Commit | Line | Data |
---|---|---|
fe56b9e6 | 1 | /* QLogic qed NIC Driver |
e8f1cb50 | 2 | * Copyright (c) 2015-2017 QLogic Corporation |
fe56b9e6 | 3 | * |
e8f1cb50 MY |
4 | * This software is available to you under a choice of one of two |
5 | * licenses. You may choose to be licensed under the terms of the GNU | |
6 | * General Public License (GPL) Version 2, available from the file | |
7 | * COPYING in the main directory of this source tree, or the | |
8 | * OpenIB.org BSD license below: | |
9 | * | |
10 | * Redistribution and use in source and binary forms, with or | |
11 | * without modification, are permitted provided that the following | |
12 | * conditions are met: | |
13 | * | |
14 | * - Redistributions of source code must retain the above | |
15 | * copyright notice, this list of conditions and the following | |
16 | * disclaimer. | |
17 | * | |
18 | * - Redistributions in binary form must reproduce the above | |
19 | * copyright notice, this list of conditions and the following | |
20 | * disclaimer in the documentation and /or other materials | |
21 | * provided with the distribution. | |
22 | * | |
23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
24 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
25 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
26 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | |
27 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | |
28 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
29 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
30 | * SOFTWARE. | |
fe56b9e6 YM |
31 | */ |
32 | ||
33 | #include <linux/stddef.h> | |
34 | #include <linux/pci.h> | |
35 | #include <linux/kernel.h> | |
36 | #include <linux/slab.h> | |
37 | #include <linux/version.h> | |
38 | #include <linux/delay.h> | |
39 | #include <asm/byteorder.h> | |
40 | #include <linux/dma-mapping.h> | |
41 | #include <linux/string.h> | |
42 | #include <linux/module.h> | |
43 | #include <linux/interrupt.h> | |
44 | #include <linux/workqueue.h> | |
45 | #include <linux/ethtool.h> | |
46 | #include <linux/etherdevice.h> | |
47 | #include <linux/vmalloc.h> | |
5d24bcf1 | 48 | #include <linux/crash_dump.h> |
fe56b9e6 | 49 | #include <linux/qed/qed_if.h> |
0a7fb11c | 50 | #include <linux/qed/qed_ll2_if.h> |
fe56b9e6 YM |
51 | |
52 | #include "qed.h" | |
37bff2b9 | 53 | #include "qed_sriov.h" |
fe56b9e6 YM |
54 | #include "qed_sp.h" |
55 | #include "qed_dev_api.h" | |
0a7fb11c | 56 | #include "qed_ll2.h" |
1e128c81 | 57 | #include "qed_fcoe.h" |
2f2b2614 MY |
58 | #include "qed_iscsi.h" |
59 | ||
fe56b9e6 YM |
60 | #include "qed_mcp.h" |
61 | #include "qed_hw.h" | |
03dc76ca | 62 | #include "qed_selftest.h" |
1e128c81 | 63 | #include "qed_debug.h" |
fe56b9e6 | 64 | |
51ff1725 RA |
65 | #define QED_ROCE_QPS (8192) |
66 | #define QED_ROCE_DPIS (8) | |
51ff1725 | 67 | |
5abd7e92 YM |
68 | static char version[] = |
69 | "QLogic FastLinQ 4xxxx Core Module qed " DRV_MODULE_VERSION "\n"; | |
fe56b9e6 | 70 | |
5abd7e92 | 71 | MODULE_DESCRIPTION("QLogic FastLinQ 4xxxx Core Module"); |
fe56b9e6 YM |
72 | MODULE_LICENSE("GPL"); |
73 | MODULE_VERSION(DRV_MODULE_VERSION); | |
74 | ||
75 | #define FW_FILE_VERSION \ | |
76 | __stringify(FW_MAJOR_VERSION) "." \ | |
77 | __stringify(FW_MINOR_VERSION) "." \ | |
78 | __stringify(FW_REVISION_VERSION) "." \ | |
79 | __stringify(FW_ENGINEERING_VERSION) | |
80 | ||
81 | #define QED_FW_FILE_NAME \ | |
82 | "qed/qed_init_values_zipped-" FW_FILE_VERSION ".bin" | |
83 | ||
d43d3f0f YM |
84 | MODULE_FIRMWARE(QED_FW_FILE_NAME); |
85 | ||
fe56b9e6 YM |
86 | static int __init qed_init(void) |
87 | { | |
fe56b9e6 YM |
88 | pr_info("%s", version); |
89 | ||
90 | return 0; | |
91 | } | |
92 | ||
93 | static void __exit qed_cleanup(void) | |
94 | { | |
95 | pr_notice("qed_cleanup called\n"); | |
96 | } | |
97 | ||
98 | module_init(qed_init); | |
99 | module_exit(qed_cleanup); | |
100 | ||
101 | /* Check if the DMA controller on the machine can properly handle the DMA | |
102 | * addressing required by the device. | |
103 | */ | |
104 | static int qed_set_coherency_mask(struct qed_dev *cdev) | |
105 | { | |
106 | struct device *dev = &cdev->pdev->dev; | |
107 | ||
108 | if (dma_set_mask(dev, DMA_BIT_MASK(64)) == 0) { | |
109 | if (dma_set_coherent_mask(dev, DMA_BIT_MASK(64)) != 0) { | |
110 | DP_NOTICE(cdev, | |
111 | "Can't request 64-bit consistent allocations\n"); | |
112 | return -EIO; | |
113 | } | |
114 | } else if (dma_set_mask(dev, DMA_BIT_MASK(32)) != 0) { | |
115 | DP_NOTICE(cdev, "Can't request 64b/32b DMA addresses\n"); | |
116 | return -EIO; | |
117 | } | |
118 | ||
119 | return 0; | |
120 | } | |
121 | ||
122 | static void qed_free_pci(struct qed_dev *cdev) | |
123 | { | |
124 | struct pci_dev *pdev = cdev->pdev; | |
125 | ||
126 | if (cdev->doorbells) | |
127 | iounmap(cdev->doorbells); | |
128 | if (cdev->regview) | |
129 | iounmap(cdev->regview); | |
130 | if (atomic_read(&pdev->enable_cnt) == 1) | |
131 | pci_release_regions(pdev); | |
132 | ||
133 | pci_disable_device(pdev); | |
134 | } | |
135 | ||
0dfaba6d YM |
136 | #define PCI_REVISION_ID_ERROR_VAL 0xff |
137 | ||
fe56b9e6 YM |
138 | /* Performs PCI initializations as well as initializing PCI-related parameters |
139 | * in the device structrue. Returns 0 in case of success. | |
140 | */ | |
1a635e48 | 141 | static int qed_init_pci(struct qed_dev *cdev, struct pci_dev *pdev) |
fe56b9e6 | 142 | { |
0dfaba6d | 143 | u8 rev_id; |
fe56b9e6 YM |
144 | int rc; |
145 | ||
146 | cdev->pdev = pdev; | |
147 | ||
148 | rc = pci_enable_device(pdev); | |
149 | if (rc) { | |
150 | DP_NOTICE(cdev, "Cannot enable PCI device\n"); | |
151 | goto err0; | |
152 | } | |
153 | ||
154 | if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { | |
155 | DP_NOTICE(cdev, "No memory region found in bar #0\n"); | |
156 | rc = -EIO; | |
157 | goto err1; | |
158 | } | |
159 | ||
1408cc1f | 160 | if (IS_PF(cdev) && !(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) { |
fe56b9e6 YM |
161 | DP_NOTICE(cdev, "No memory region found in bar #2\n"); |
162 | rc = -EIO; | |
163 | goto err1; | |
164 | } | |
165 | ||
166 | if (atomic_read(&pdev->enable_cnt) == 1) { | |
167 | rc = pci_request_regions(pdev, "qed"); | |
168 | if (rc) { | |
169 | DP_NOTICE(cdev, | |
170 | "Failed to request PCI memory resources\n"); | |
171 | goto err1; | |
172 | } | |
173 | pci_set_master(pdev); | |
174 | pci_save_state(pdev); | |
175 | } | |
176 | ||
0dfaba6d YM |
177 | pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id); |
178 | if (rev_id == PCI_REVISION_ID_ERROR_VAL) { | |
179 | DP_NOTICE(cdev, | |
180 | "Detected PCI device error [rev_id 0x%x]. Probably due to prior indication. Aborting.\n", | |
181 | rev_id); | |
182 | rc = -ENODEV; | |
183 | goto err2; | |
184 | } | |
fe56b9e6 YM |
185 | if (!pci_is_pcie(pdev)) { |
186 | DP_NOTICE(cdev, "The bus is not PCI Express\n"); | |
187 | rc = -EIO; | |
188 | goto err2; | |
189 | } | |
190 | ||
191 | cdev->pci_params.pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM); | |
416cdf06 | 192 | if (IS_PF(cdev) && !cdev->pci_params.pm_cap) |
fe56b9e6 YM |
193 | DP_NOTICE(cdev, "Cannot find power management capability\n"); |
194 | ||
195 | rc = qed_set_coherency_mask(cdev); | |
196 | if (rc) | |
197 | goto err2; | |
198 | ||
199 | cdev->pci_params.mem_start = pci_resource_start(pdev, 0); | |
200 | cdev->pci_params.mem_end = pci_resource_end(pdev, 0); | |
201 | cdev->pci_params.irq = pdev->irq; | |
202 | ||
203 | cdev->regview = pci_ioremap_bar(pdev, 0); | |
204 | if (!cdev->regview) { | |
205 | DP_NOTICE(cdev, "Cannot map register space, aborting\n"); | |
206 | rc = -ENOMEM; | |
207 | goto err2; | |
208 | } | |
209 | ||
1408cc1f | 210 | if (IS_PF(cdev)) { |
f82731b4 | 211 | cdev->db_phys_addr = pci_resource_start(cdev->pdev, 2); |
1408cc1f YM |
212 | cdev->db_size = pci_resource_len(cdev->pdev, 2); |
213 | cdev->doorbells = ioremap_wc(cdev->db_phys_addr, cdev->db_size); | |
214 | if (!cdev->doorbells) { | |
215 | DP_NOTICE(cdev, "Cannot map doorbell space\n"); | |
216 | return -ENOMEM; | |
217 | } | |
fe56b9e6 YM |
218 | } |
219 | ||
220 | return 0; | |
221 | ||
222 | err2: | |
223 | pci_release_regions(pdev); | |
224 | err1: | |
225 | pci_disable_device(pdev); | |
226 | err0: | |
227 | return rc; | |
228 | } | |
229 | ||
230 | int qed_fill_dev_info(struct qed_dev *cdev, | |
231 | struct qed_dev_info *dev_info) | |
232 | { | |
19489c7f | 233 | struct qed_tunnel_info *tun = &cdev->tunnel; |
cee4d264 MC |
234 | struct qed_ptt *ptt; |
235 | ||
fe56b9e6 YM |
236 | memset(dev_info, 0, sizeof(struct qed_dev_info)); |
237 | ||
19489c7f CM |
238 | if (tun->vxlan.tun_cls == QED_TUNN_CLSS_MAC_VLAN && |
239 | tun->vxlan.b_mode_enabled) | |
240 | dev_info->vxlan_enable = true; | |
241 | ||
242 | if (tun->l2_gre.b_mode_enabled && tun->ip_gre.b_mode_enabled && | |
243 | tun->l2_gre.tun_cls == QED_TUNN_CLSS_MAC_VLAN && | |
244 | tun->ip_gre.tun_cls == QED_TUNN_CLSS_MAC_VLAN) | |
245 | dev_info->gre_enable = true; | |
246 | ||
247 | if (tun->l2_geneve.b_mode_enabled && tun->ip_geneve.b_mode_enabled && | |
248 | tun->l2_geneve.tun_cls == QED_TUNN_CLSS_MAC_VLAN && | |
249 | tun->ip_geneve.tun_cls == QED_TUNN_CLSS_MAC_VLAN) | |
250 | dev_info->geneve_enable = true; | |
251 | ||
fe56b9e6 YM |
252 | dev_info->num_hwfns = cdev->num_hwfns; |
253 | dev_info->pci_mem_start = cdev->pci_params.mem_start; | |
254 | dev_info->pci_mem_end = cdev->pci_params.mem_end; | |
255 | dev_info->pci_irq = cdev->pci_params.irq; | |
51ff1725 RA |
256 | dev_info->rdma_supported = (cdev->hwfns[0].hw_info.personality == |
257 | QED_PCI_ETH_ROCE); | |
fc48b7a6 | 258 | dev_info->is_mf_default = IS_MF_DEFAULT(&cdev->hwfns[0]); |
9c79ddaa | 259 | dev_info->dev_type = cdev->type; |
fe56b9e6 YM |
260 | ether_addr_copy(dev_info->hw_mac, cdev->hwfns[0].hw_info.hw_mac_addr); |
261 | ||
1408cc1f YM |
262 | if (IS_PF(cdev)) { |
263 | dev_info->fw_major = FW_MAJOR_VERSION; | |
264 | dev_info->fw_minor = FW_MINOR_VERSION; | |
265 | dev_info->fw_rev = FW_REVISION_VERSION; | |
266 | dev_info->fw_eng = FW_ENGINEERING_VERSION; | |
267 | dev_info->mf_mode = cdev->mf_mode; | |
831bfb0e | 268 | dev_info->tx_switching = true; |
14d39648 MY |
269 | |
270 | if (QED_LEADING_HWFN(cdev)->hw_info.b_wol_support == | |
271 | QED_WOL_SUPPORT_PME) | |
272 | dev_info->wol_support = true; | |
1408cc1f YM |
273 | } else { |
274 | qed_vf_get_fw_version(&cdev->hwfns[0], &dev_info->fw_major, | |
275 | &dev_info->fw_minor, &dev_info->fw_rev, | |
276 | &dev_info->fw_eng); | |
277 | } | |
fe56b9e6 | 278 | |
1408cc1f YM |
279 | if (IS_PF(cdev)) { |
280 | ptt = qed_ptt_acquire(QED_LEADING_HWFN(cdev)); | |
281 | if (ptt) { | |
282 | qed_mcp_get_mfw_ver(QED_LEADING_HWFN(cdev), ptt, | |
283 | &dev_info->mfw_rev, NULL); | |
fe56b9e6 | 284 | |
1408cc1f YM |
285 | qed_mcp_get_flash_size(QED_LEADING_HWFN(cdev), ptt, |
286 | &dev_info->flash_size); | |
cee4d264 | 287 | |
1408cc1f YM |
288 | qed_ptt_release(QED_LEADING_HWFN(cdev), ptt); |
289 | } | |
290 | } else { | |
291 | qed_mcp_get_mfw_ver(QED_LEADING_HWFN(cdev), NULL, | |
292 | &dev_info->mfw_rev, NULL); | |
cee4d264 MC |
293 | } |
294 | ||
0fefbfba SK |
295 | dev_info->mtu = QED_LEADING_HWFN(cdev)->hw_info.mtu; |
296 | ||
fe56b9e6 YM |
297 | return 0; |
298 | } | |
299 | ||
300 | static void qed_free_cdev(struct qed_dev *cdev) | |
301 | { | |
302 | kfree((void *)cdev); | |
303 | } | |
304 | ||
305 | static struct qed_dev *qed_alloc_cdev(struct pci_dev *pdev) | |
306 | { | |
307 | struct qed_dev *cdev; | |
308 | ||
309 | cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); | |
310 | if (!cdev) | |
311 | return cdev; | |
312 | ||
313 | qed_init_struct(cdev); | |
314 | ||
315 | return cdev; | |
316 | } | |
317 | ||
318 | /* Sets the requested power state */ | |
1a635e48 | 319 | static int qed_set_power_state(struct qed_dev *cdev, pci_power_t state) |
fe56b9e6 YM |
320 | { |
321 | if (!cdev) | |
322 | return -ENODEV; | |
323 | ||
324 | DP_VERBOSE(cdev, NETIF_MSG_DRV, "Omitting Power state change\n"); | |
325 | return 0; | |
326 | } | |
327 | ||
328 | /* probing */ | |
329 | static struct qed_dev *qed_probe(struct pci_dev *pdev, | |
1408cc1f | 330 | struct qed_probe_params *params) |
fe56b9e6 YM |
331 | { |
332 | struct qed_dev *cdev; | |
333 | int rc; | |
334 | ||
335 | cdev = qed_alloc_cdev(pdev); | |
336 | if (!cdev) | |
337 | goto err0; | |
338 | ||
1408cc1f | 339 | cdev->protocol = params->protocol; |
fe56b9e6 | 340 | |
1408cc1f YM |
341 | if (params->is_vf) |
342 | cdev->b_is_vf = true; | |
343 | ||
344 | qed_init_dp(cdev, params->dp_module, params->dp_level); | |
fe56b9e6 YM |
345 | |
346 | rc = qed_init_pci(cdev, pdev); | |
347 | if (rc) { | |
348 | DP_ERR(cdev, "init pci failed\n"); | |
349 | goto err1; | |
350 | } | |
351 | DP_INFO(cdev, "PCI init completed successfully\n"); | |
352 | ||
353 | rc = qed_hw_prepare(cdev, QED_PCI_DEFAULT); | |
354 | if (rc) { | |
355 | DP_ERR(cdev, "hw prepare failed\n"); | |
356 | goto err2; | |
357 | } | |
358 | ||
359 | DP_INFO(cdev, "qed_probe completed successffuly\n"); | |
360 | ||
361 | return cdev; | |
362 | ||
363 | err2: | |
364 | qed_free_pci(cdev); | |
365 | err1: | |
366 | qed_free_cdev(cdev); | |
367 | err0: | |
368 | return NULL; | |
369 | } | |
370 | ||
371 | static void qed_remove(struct qed_dev *cdev) | |
372 | { | |
373 | if (!cdev) | |
374 | return; | |
375 | ||
376 | qed_hw_remove(cdev); | |
377 | ||
378 | qed_free_pci(cdev); | |
379 | ||
380 | qed_set_power_state(cdev, PCI_D3hot); | |
381 | ||
382 | qed_free_cdev(cdev); | |
383 | } | |
384 | ||
385 | static void qed_disable_msix(struct qed_dev *cdev) | |
386 | { | |
387 | if (cdev->int_params.out.int_mode == QED_INT_MODE_MSIX) { | |
388 | pci_disable_msix(cdev->pdev); | |
389 | kfree(cdev->int_params.msix_table); | |
390 | } else if (cdev->int_params.out.int_mode == QED_INT_MODE_MSI) { | |
391 | pci_disable_msi(cdev->pdev); | |
392 | } | |
393 | ||
394 | memset(&cdev->int_params.out, 0, sizeof(struct qed_int_param)); | |
395 | } | |
396 | ||
397 | static int qed_enable_msix(struct qed_dev *cdev, | |
398 | struct qed_int_params *int_params) | |
399 | { | |
400 | int i, rc, cnt; | |
401 | ||
402 | cnt = int_params->in.num_vectors; | |
403 | ||
404 | for (i = 0; i < cnt; i++) | |
405 | int_params->msix_table[i].entry = i; | |
406 | ||
407 | rc = pci_enable_msix_range(cdev->pdev, int_params->msix_table, | |
408 | int_params->in.min_msix_cnt, cnt); | |
409 | if (rc < cnt && rc >= int_params->in.min_msix_cnt && | |
410 | (rc % cdev->num_hwfns)) { | |
411 | pci_disable_msix(cdev->pdev); | |
412 | ||
413 | /* If fastpath is initialized, we need at least one interrupt | |
414 | * per hwfn [and the slow path interrupts]. New requested number | |
415 | * should be a multiple of the number of hwfns. | |
416 | */ | |
417 | cnt = (rc / cdev->num_hwfns) * cdev->num_hwfns; | |
418 | DP_NOTICE(cdev, | |
419 | "Trying to enable MSI-X with less vectors (%d out of %d)\n", | |
420 | cnt, int_params->in.num_vectors); | |
1a635e48 YM |
421 | rc = pci_enable_msix_exact(cdev->pdev, int_params->msix_table, |
422 | cnt); | |
fe56b9e6 YM |
423 | if (!rc) |
424 | rc = cnt; | |
425 | } | |
426 | ||
427 | if (rc > 0) { | |
428 | /* MSI-x configuration was achieved */ | |
429 | int_params->out.int_mode = QED_INT_MODE_MSIX; | |
430 | int_params->out.num_vectors = rc; | |
431 | rc = 0; | |
432 | } else { | |
433 | DP_NOTICE(cdev, | |
434 | "Failed to enable MSI-X [Requested %d vectors][rc %d]\n", | |
435 | cnt, rc); | |
436 | } | |
437 | ||
438 | return rc; | |
439 | } | |
440 | ||
441 | /* This function outputs the int mode and the number of enabled msix vector */ | |
442 | static int qed_set_int_mode(struct qed_dev *cdev, bool force_mode) | |
443 | { | |
444 | struct qed_int_params *int_params = &cdev->int_params; | |
445 | struct msix_entry *tbl; | |
446 | int rc = 0, cnt; | |
447 | ||
448 | switch (int_params->in.int_mode) { | |
449 | case QED_INT_MODE_MSIX: | |
450 | /* Allocate MSIX table */ | |
451 | cnt = int_params->in.num_vectors; | |
452 | int_params->msix_table = kcalloc(cnt, sizeof(*tbl), GFP_KERNEL); | |
453 | if (!int_params->msix_table) { | |
454 | rc = -ENOMEM; | |
455 | goto out; | |
456 | } | |
457 | ||
458 | /* Enable MSIX */ | |
459 | rc = qed_enable_msix(cdev, int_params); | |
460 | if (!rc) | |
461 | goto out; | |
462 | ||
463 | DP_NOTICE(cdev, "Failed to enable MSI-X\n"); | |
464 | kfree(int_params->msix_table); | |
465 | if (force_mode) | |
466 | goto out; | |
467 | /* Fallthrough */ | |
468 | ||
469 | case QED_INT_MODE_MSI: | |
bb13ace7 SRK |
470 | if (cdev->num_hwfns == 1) { |
471 | rc = pci_enable_msi(cdev->pdev); | |
472 | if (!rc) { | |
473 | int_params->out.int_mode = QED_INT_MODE_MSI; | |
474 | goto out; | |
475 | } | |
476 | ||
477 | DP_NOTICE(cdev, "Failed to enable MSI\n"); | |
478 | if (force_mode) | |
479 | goto out; | |
fe56b9e6 | 480 | } |
fe56b9e6 YM |
481 | /* Fallthrough */ |
482 | ||
483 | case QED_INT_MODE_INTA: | |
484 | int_params->out.int_mode = QED_INT_MODE_INTA; | |
485 | rc = 0; | |
486 | goto out; | |
487 | default: | |
488 | DP_NOTICE(cdev, "Unknown int_mode value %d\n", | |
489 | int_params->in.int_mode); | |
490 | rc = -EINVAL; | |
491 | } | |
492 | ||
493 | out: | |
525ef5c0 YM |
494 | if (!rc) |
495 | DP_INFO(cdev, "Using %s interrupts\n", | |
496 | int_params->out.int_mode == QED_INT_MODE_INTA ? | |
497 | "INTa" : int_params->out.int_mode == QED_INT_MODE_MSI ? | |
498 | "MSI" : "MSIX"); | |
fe56b9e6 YM |
499 | cdev->int_coalescing_mode = QED_COAL_MODE_ENABLE; |
500 | ||
501 | return rc; | |
502 | } | |
503 | ||
504 | static void qed_simd_handler_config(struct qed_dev *cdev, void *token, | |
505 | int index, void(*handler)(void *)) | |
506 | { | |
507 | struct qed_hwfn *hwfn = &cdev->hwfns[index % cdev->num_hwfns]; | |
508 | int relative_idx = index / cdev->num_hwfns; | |
509 | ||
510 | hwfn->simd_proto_handler[relative_idx].func = handler; | |
511 | hwfn->simd_proto_handler[relative_idx].token = token; | |
512 | } | |
513 | ||
514 | static void qed_simd_handler_clean(struct qed_dev *cdev, int index) | |
515 | { | |
516 | struct qed_hwfn *hwfn = &cdev->hwfns[index % cdev->num_hwfns]; | |
517 | int relative_idx = index / cdev->num_hwfns; | |
518 | ||
519 | memset(&hwfn->simd_proto_handler[relative_idx], 0, | |
520 | sizeof(struct qed_simd_fp_handler)); | |
521 | } | |
522 | ||
523 | static irqreturn_t qed_msix_sp_int(int irq, void *tasklet) | |
524 | { | |
525 | tasklet_schedule((struct tasklet_struct *)tasklet); | |
526 | return IRQ_HANDLED; | |
527 | } | |
528 | ||
529 | static irqreturn_t qed_single_int(int irq, void *dev_instance) | |
530 | { | |
531 | struct qed_dev *cdev = (struct qed_dev *)dev_instance; | |
532 | struct qed_hwfn *hwfn; | |
533 | irqreturn_t rc = IRQ_NONE; | |
534 | u64 status; | |
535 | int i, j; | |
536 | ||
537 | for (i = 0; i < cdev->num_hwfns; i++) { | |
538 | status = qed_int_igu_read_sisr_reg(&cdev->hwfns[i]); | |
539 | ||
540 | if (!status) | |
541 | continue; | |
542 | ||
543 | hwfn = &cdev->hwfns[i]; | |
544 | ||
545 | /* Slowpath interrupt */ | |
546 | if (unlikely(status & 0x1)) { | |
547 | tasklet_schedule(hwfn->sp_dpc); | |
548 | status &= ~0x1; | |
549 | rc = IRQ_HANDLED; | |
550 | } | |
551 | ||
552 | /* Fastpath interrupts */ | |
553 | for (j = 0; j < 64; j++) { | |
554 | if ((0x2ULL << j) & status) { | |
555 | hwfn->simd_proto_handler[j].func( | |
556 | hwfn->simd_proto_handler[j].token); | |
557 | status &= ~(0x2ULL << j); | |
558 | rc = IRQ_HANDLED; | |
559 | } | |
560 | } | |
561 | ||
562 | if (unlikely(status)) | |
563 | DP_VERBOSE(hwfn, NETIF_MSG_INTR, | |
564 | "got an unknown interrupt status 0x%llx\n", | |
565 | status); | |
566 | } | |
567 | ||
568 | return rc; | |
569 | } | |
570 | ||
8f16bc97 | 571 | int qed_slowpath_irq_req(struct qed_hwfn *hwfn) |
fe56b9e6 | 572 | { |
8f16bc97 | 573 | struct qed_dev *cdev = hwfn->cdev; |
525ef5c0 | 574 | u32 int_mode; |
8f16bc97 SK |
575 | int rc = 0; |
576 | u8 id; | |
fe56b9e6 | 577 | |
525ef5c0 YM |
578 | int_mode = cdev->int_params.out.int_mode; |
579 | if (int_mode == QED_INT_MODE_MSIX) { | |
8f16bc97 SK |
580 | id = hwfn->my_id; |
581 | snprintf(hwfn->name, NAME_SIZE, "sp-%d-%02x:%02x.%02x", | |
582 | id, cdev->pdev->bus->number, | |
583 | PCI_SLOT(cdev->pdev->devfn), hwfn->abs_pf_id); | |
584 | rc = request_irq(cdev->int_params.msix_table[id].vector, | |
585 | qed_msix_sp_int, 0, hwfn->name, hwfn->sp_dpc); | |
fe56b9e6 YM |
586 | } else { |
587 | unsigned long flags = 0; | |
588 | ||
589 | snprintf(cdev->name, NAME_SIZE, "%02x:%02x.%02x", | |
590 | cdev->pdev->bus->number, PCI_SLOT(cdev->pdev->devfn), | |
591 | PCI_FUNC(cdev->pdev->devfn)); | |
592 | ||
593 | if (cdev->int_params.out.int_mode == QED_INT_MODE_INTA) | |
594 | flags |= IRQF_SHARED; | |
595 | ||
596 | rc = request_irq(cdev->pdev->irq, qed_single_int, | |
597 | flags, cdev->name, cdev); | |
598 | } | |
599 | ||
525ef5c0 YM |
600 | if (rc) |
601 | DP_NOTICE(cdev, "request_irq failed, rc = %d\n", rc); | |
602 | else | |
603 | DP_VERBOSE(hwfn, (NETIF_MSG_INTR | QED_MSG_SP), | |
604 | "Requested slowpath %s\n", | |
605 | (int_mode == QED_INT_MODE_MSIX) ? "MSI-X" : "IRQ"); | |
606 | ||
fe56b9e6 YM |
607 | return rc; |
608 | } | |
609 | ||
1226337a TT |
610 | void qed_slowpath_irq_sync(struct qed_hwfn *p_hwfn) |
611 | { | |
612 | struct qed_dev *cdev = p_hwfn->cdev; | |
613 | u8 id = p_hwfn->my_id; | |
614 | u32 int_mode; | |
615 | ||
616 | int_mode = cdev->int_params.out.int_mode; | |
617 | if (int_mode == QED_INT_MODE_MSIX) | |
618 | synchronize_irq(cdev->int_params.msix_table[id].vector); | |
619 | else | |
620 | synchronize_irq(cdev->pdev->irq); | |
621 | } | |
622 | ||
fe56b9e6 YM |
623 | static void qed_slowpath_irq_free(struct qed_dev *cdev) |
624 | { | |
625 | int i; | |
626 | ||
627 | if (cdev->int_params.out.int_mode == QED_INT_MODE_MSIX) { | |
628 | for_each_hwfn(cdev, i) { | |
8f16bc97 SK |
629 | if (!cdev->hwfns[i].b_int_requested) |
630 | break; | |
fe56b9e6 YM |
631 | synchronize_irq(cdev->int_params.msix_table[i].vector); |
632 | free_irq(cdev->int_params.msix_table[i].vector, | |
633 | cdev->hwfns[i].sp_dpc); | |
634 | } | |
635 | } else { | |
8f16bc97 SK |
636 | if (QED_LEADING_HWFN(cdev)->b_int_requested) |
637 | free_irq(cdev->pdev->irq, cdev); | |
fe56b9e6 | 638 | } |
8f16bc97 | 639 | qed_int_disable_post_isr_release(cdev); |
fe56b9e6 YM |
640 | } |
641 | ||
642 | static int qed_nic_stop(struct qed_dev *cdev) | |
643 | { | |
644 | int i, rc; | |
645 | ||
646 | rc = qed_hw_stop(cdev); | |
647 | ||
648 | for (i = 0; i < cdev->num_hwfns; i++) { | |
649 | struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; | |
650 | ||
651 | if (p_hwfn->b_sp_dpc_enabled) { | |
652 | tasklet_disable(p_hwfn->sp_dpc); | |
653 | p_hwfn->b_sp_dpc_enabled = false; | |
654 | DP_VERBOSE(cdev, NETIF_MSG_IFDOWN, | |
655 | "Disabled sp taskelt [hwfn %d] at %p\n", | |
656 | i, p_hwfn->sp_dpc); | |
657 | } | |
658 | } | |
659 | ||
c965db44 TT |
660 | qed_dbg_pf_exit(cdev); |
661 | ||
fe56b9e6 YM |
662 | return rc; |
663 | } | |
664 | ||
fe56b9e6 YM |
665 | static int qed_nic_setup(struct qed_dev *cdev) |
666 | { | |
0a7fb11c YM |
667 | int rc, i; |
668 | ||
669 | /* Determine if interface is going to require LL2 */ | |
670 | if (QED_LEADING_HWFN(cdev)->hw_info.personality != QED_PCI_ETH) { | |
671 | for (i = 0; i < cdev->num_hwfns; i++) { | |
672 | struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; | |
673 | ||
674 | p_hwfn->using_ll2 = true; | |
675 | } | |
676 | } | |
fe56b9e6 YM |
677 | |
678 | rc = qed_resc_alloc(cdev); | |
679 | if (rc) | |
680 | return rc; | |
681 | ||
682 | DP_INFO(cdev, "Allocated qed resources\n"); | |
683 | ||
684 | qed_resc_setup(cdev); | |
685 | ||
686 | return rc; | |
687 | } | |
688 | ||
689 | static int qed_set_int_fp(struct qed_dev *cdev, u16 cnt) | |
690 | { | |
691 | int limit = 0; | |
692 | ||
693 | /* Mark the fastpath as free/used */ | |
694 | cdev->int_params.fp_initialized = cnt ? true : false; | |
695 | ||
696 | if (cdev->int_params.out.int_mode != QED_INT_MODE_MSIX) | |
697 | limit = cdev->num_hwfns * 63; | |
698 | else if (cdev->int_params.fp_msix_cnt) | |
699 | limit = cdev->int_params.fp_msix_cnt; | |
700 | ||
701 | if (!limit) | |
702 | return -ENOMEM; | |
703 | ||
704 | return min_t(int, cnt, limit); | |
705 | } | |
706 | ||
707 | static int qed_get_int_fp(struct qed_dev *cdev, struct qed_int_info *info) | |
708 | { | |
709 | memset(info, 0, sizeof(struct qed_int_info)); | |
710 | ||
711 | if (!cdev->int_params.fp_initialized) { | |
712 | DP_INFO(cdev, | |
713 | "Protocol driver requested interrupt information, but its support is not yet configured\n"); | |
714 | return -EINVAL; | |
715 | } | |
716 | ||
717 | /* Need to expose only MSI-X information; Single IRQ is handled solely | |
718 | * by qed. | |
719 | */ | |
720 | if (cdev->int_params.out.int_mode == QED_INT_MODE_MSIX) { | |
721 | int msix_base = cdev->int_params.fp_msix_base; | |
722 | ||
723 | info->msix_cnt = cdev->int_params.fp_msix_cnt; | |
724 | info->msix = &cdev->int_params.msix_table[msix_base]; | |
725 | } | |
726 | ||
727 | return 0; | |
728 | } | |
729 | ||
730 | static int qed_slowpath_setup_int(struct qed_dev *cdev, | |
731 | enum qed_int_mode int_mode) | |
732 | { | |
4ac801b7 | 733 | struct qed_sb_cnt_info sb_cnt_info; |
0189efb8 | 734 | int num_l2_queues = 0; |
4ac801b7 YM |
735 | int rc; |
736 | int i; | |
fe56b9e6 | 737 | |
1d2c2024 SRK |
738 | if ((int_mode == QED_INT_MODE_MSI) && (cdev->num_hwfns > 1)) { |
739 | DP_NOTICE(cdev, "MSI mode is not supported for CMT devices\n"); | |
740 | return -EINVAL; | |
741 | } | |
742 | ||
743 | memset(&cdev->int_params, 0, sizeof(struct qed_int_params)); | |
fe56b9e6 | 744 | cdev->int_params.in.int_mode = int_mode; |
4ac801b7 YM |
745 | for_each_hwfn(cdev, i) { |
746 | memset(&sb_cnt_info, 0, sizeof(sb_cnt_info)); | |
747 | qed_int_get_num_sbs(&cdev->hwfns[i], &sb_cnt_info); | |
748 | cdev->int_params.in.num_vectors += sb_cnt_info.sb_cnt; | |
749 | cdev->int_params.in.num_vectors++; /* slowpath */ | |
750 | } | |
fe56b9e6 YM |
751 | |
752 | /* We want a minimum of one slowpath and one fastpath vector per hwfn */ | |
753 | cdev->int_params.in.min_msix_cnt = cdev->num_hwfns * 2; | |
754 | ||
755 | rc = qed_set_int_mode(cdev, false); | |
756 | if (rc) { | |
757 | DP_ERR(cdev, "qed_slowpath_setup_int ERR\n"); | |
758 | return rc; | |
759 | } | |
760 | ||
761 | cdev->int_params.fp_msix_base = cdev->num_hwfns; | |
762 | cdev->int_params.fp_msix_cnt = cdev->int_params.out.num_vectors - | |
763 | cdev->num_hwfns; | |
764 | ||
2f782278 MY |
765 | if (!IS_ENABLED(CONFIG_QED_RDMA) || |
766 | QED_LEADING_HWFN(cdev)->hw_info.personality != QED_PCI_ETH_ROCE) | |
0189efb8 YM |
767 | return 0; |
768 | ||
51ff1725 RA |
769 | for_each_hwfn(cdev, i) |
770 | num_l2_queues += FEAT_NUM(&cdev->hwfns[i], QED_PF_L2_QUE); | |
771 | ||
772 | DP_VERBOSE(cdev, QED_MSG_RDMA, | |
773 | "cdev->int_params.fp_msix_cnt=%d num_l2_queues=%d\n", | |
774 | cdev->int_params.fp_msix_cnt, num_l2_queues); | |
775 | ||
776 | if (cdev->int_params.fp_msix_cnt > num_l2_queues) { | |
777 | cdev->int_params.rdma_msix_cnt = | |
778 | (cdev->int_params.fp_msix_cnt - num_l2_queues) | |
779 | / cdev->num_hwfns; | |
780 | cdev->int_params.rdma_msix_base = | |
781 | cdev->int_params.fp_msix_base + num_l2_queues; | |
782 | cdev->int_params.fp_msix_cnt = num_l2_queues; | |
783 | } else { | |
784 | cdev->int_params.rdma_msix_cnt = 0; | |
785 | } | |
786 | ||
787 | DP_VERBOSE(cdev, QED_MSG_RDMA, "roce_msix_cnt=%d roce_msix_base=%d\n", | |
788 | cdev->int_params.rdma_msix_cnt, | |
789 | cdev->int_params.rdma_msix_base); | |
51ff1725 | 790 | |
fe56b9e6 YM |
791 | return 0; |
792 | } | |
793 | ||
1408cc1f YM |
794 | static int qed_slowpath_vf_setup_int(struct qed_dev *cdev) |
795 | { | |
796 | int rc; | |
797 | ||
798 | memset(&cdev->int_params, 0, sizeof(struct qed_int_params)); | |
799 | cdev->int_params.in.int_mode = QED_INT_MODE_MSIX; | |
800 | ||
801 | qed_vf_get_num_rxqs(QED_LEADING_HWFN(cdev), | |
802 | &cdev->int_params.in.num_vectors); | |
803 | if (cdev->num_hwfns > 1) { | |
804 | u8 vectors = 0; | |
805 | ||
806 | qed_vf_get_num_rxqs(&cdev->hwfns[1], &vectors); | |
807 | cdev->int_params.in.num_vectors += vectors; | |
808 | } | |
809 | ||
810 | /* We want a minimum of one fastpath vector per vf hwfn */ | |
811 | cdev->int_params.in.min_msix_cnt = cdev->num_hwfns; | |
812 | ||
813 | rc = qed_set_int_mode(cdev, true); | |
814 | if (rc) | |
815 | return rc; | |
816 | ||
817 | cdev->int_params.fp_msix_base = 0; | |
818 | cdev->int_params.fp_msix_cnt = cdev->int_params.out.num_vectors; | |
819 | ||
820 | return 0; | |
821 | } | |
822 | ||
fe56b9e6 YM |
823 | u32 qed_unzip_data(struct qed_hwfn *p_hwfn, u32 input_len, |
824 | u8 *input_buf, u32 max_size, u8 *unzip_buf) | |
825 | { | |
826 | int rc; | |
827 | ||
828 | p_hwfn->stream->next_in = input_buf; | |
829 | p_hwfn->stream->avail_in = input_len; | |
830 | p_hwfn->stream->next_out = unzip_buf; | |
831 | p_hwfn->stream->avail_out = max_size; | |
832 | ||
833 | rc = zlib_inflateInit2(p_hwfn->stream, MAX_WBITS); | |
834 | ||
835 | if (rc != Z_OK) { | |
836 | DP_VERBOSE(p_hwfn, NETIF_MSG_DRV, "zlib init failed, rc = %d\n", | |
837 | rc); | |
838 | return 0; | |
839 | } | |
840 | ||
841 | rc = zlib_inflate(p_hwfn->stream, Z_FINISH); | |
842 | zlib_inflateEnd(p_hwfn->stream); | |
843 | ||
844 | if (rc != Z_OK && rc != Z_STREAM_END) { | |
845 | DP_VERBOSE(p_hwfn, NETIF_MSG_DRV, "FW unzip error: %s, rc=%d\n", | |
846 | p_hwfn->stream->msg, rc); | |
847 | return 0; | |
848 | } | |
849 | ||
850 | return p_hwfn->stream->total_out / 4; | |
851 | } | |
852 | ||
853 | static int qed_alloc_stream_mem(struct qed_dev *cdev) | |
854 | { | |
855 | int i; | |
856 | void *workspace; | |
857 | ||
858 | for_each_hwfn(cdev, i) { | |
859 | struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; | |
860 | ||
861 | p_hwfn->stream = kzalloc(sizeof(*p_hwfn->stream), GFP_KERNEL); | |
862 | if (!p_hwfn->stream) | |
863 | return -ENOMEM; | |
864 | ||
865 | workspace = vzalloc(zlib_inflate_workspacesize()); | |
866 | if (!workspace) | |
867 | return -ENOMEM; | |
868 | p_hwfn->stream->workspace = workspace; | |
869 | } | |
870 | ||
871 | return 0; | |
872 | } | |
873 | ||
874 | static void qed_free_stream_mem(struct qed_dev *cdev) | |
875 | { | |
876 | int i; | |
877 | ||
878 | for_each_hwfn(cdev, i) { | |
879 | struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; | |
880 | ||
881 | if (!p_hwfn->stream) | |
882 | return; | |
883 | ||
884 | vfree(p_hwfn->stream->workspace); | |
885 | kfree(p_hwfn->stream); | |
886 | } | |
887 | } | |
888 | ||
889 | static void qed_update_pf_params(struct qed_dev *cdev, | |
890 | struct qed_pf_params *params) | |
891 | { | |
892 | int i; | |
893 | ||
5c5f2609 RA |
894 | if (IS_ENABLED(CONFIG_QED_RDMA)) { |
895 | params->rdma_pf_params.num_qps = QED_ROCE_QPS; | |
896 | params->rdma_pf_params.min_dpis = QED_ROCE_DPIS; | |
897 | /* divide by 3 the MRs to avoid MF ILT overflow */ | |
5c5f2609 RA |
898 | params->rdma_pf_params.gl_pi = QED_ROCE_PROTOCOL_INDEX; |
899 | } | |
900 | ||
d51e4af5 CM |
901 | if (cdev->num_hwfns > 1 || IS_VF(cdev)) |
902 | params->eth_pf_params.num_arfs_filters = 0; | |
903 | ||
e1d32acb MY |
904 | /* In case we might support RDMA, don't allow qede to be greedy |
905 | * with the L2 contexts. Allow for 64 queues [rx, tx, xdp] per hwfn. | |
906 | */ | |
907 | if (QED_LEADING_HWFN(cdev)->hw_info.personality == | |
908 | QED_PCI_ETH_ROCE) { | |
909 | u16 *num_cons; | |
910 | ||
911 | num_cons = ¶ms->eth_pf_params.num_cons; | |
912 | *num_cons = min_t(u16, *num_cons, 192); | |
913 | } | |
914 | ||
fe56b9e6 YM |
915 | for (i = 0; i < cdev->num_hwfns; i++) { |
916 | struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; | |
917 | ||
918 | p_hwfn->pf_params = *params; | |
919 | } | |
920 | } | |
921 | ||
922 | static int qed_slowpath_start(struct qed_dev *cdev, | |
923 | struct qed_slowpath_params *params) | |
924 | { | |
5d24bcf1 | 925 | struct qed_drv_load_params drv_load_params; |
c0c2d0b4 | 926 | struct qed_hw_init_params hw_init_params; |
fe56b9e6 | 927 | struct qed_mcp_drv_version drv_version; |
19968430 | 928 | struct qed_tunnel_info tunn_info; |
fe56b9e6 YM |
929 | const u8 *data = NULL; |
930 | struct qed_hwfn *hwfn; | |
07ff2ed0 | 931 | #ifdef CONFIG_RFS_ACCEL |
c78c70fa | 932 | struct qed_ptt *p_ptt; |
07ff2ed0 | 933 | #endif |
37bff2b9 YM |
934 | int rc = -EINVAL; |
935 | ||
936 | if (qed_iov_wq_start(cdev)) | |
937 | goto err; | |
fe56b9e6 | 938 | |
1408cc1f YM |
939 | if (IS_PF(cdev)) { |
940 | rc = request_firmware(&cdev->firmware, QED_FW_FILE_NAME, | |
941 | &cdev->pdev->dev); | |
942 | if (rc) { | |
943 | DP_NOTICE(cdev, | |
944 | "Failed to find fw file - /lib/firmware/%s\n", | |
945 | QED_FW_FILE_NAME); | |
946 | goto err; | |
947 | } | |
c78c70fa | 948 | |
d51e4af5 CM |
949 | #ifdef CONFIG_RFS_ACCEL |
950 | if (cdev->num_hwfns == 1) { | |
951 | p_ptt = qed_ptt_acquire(QED_LEADING_HWFN(cdev)); | |
952 | if (p_ptt) { | |
953 | QED_LEADING_HWFN(cdev)->p_arfs_ptt = p_ptt; | |
954 | } else { | |
955 | DP_NOTICE(cdev, | |
956 | "Failed to acquire PTT for aRFS\n"); | |
957 | goto err; | |
958 | } | |
959 | } | |
960 | #endif | |
fe56b9e6 YM |
961 | } |
962 | ||
0e191827 | 963 | cdev->rx_coalesce_usecs = QED_DEFAULT_RX_USECS; |
fe56b9e6 YM |
964 | rc = qed_nic_setup(cdev); |
965 | if (rc) | |
966 | goto err; | |
967 | ||
1408cc1f YM |
968 | if (IS_PF(cdev)) |
969 | rc = qed_slowpath_setup_int(cdev, params->int_mode); | |
970 | else | |
971 | rc = qed_slowpath_vf_setup_int(cdev); | |
fe56b9e6 YM |
972 | if (rc) |
973 | goto err1; | |
974 | ||
1408cc1f YM |
975 | if (IS_PF(cdev)) { |
976 | /* Allocate stream for unzipping */ | |
977 | rc = qed_alloc_stream_mem(cdev); | |
2591c280 | 978 | if (rc) |
1408cc1f | 979 | goto err2; |
fe56b9e6 | 980 | |
8ac1ed79 | 981 | /* First Dword used to differentiate between various sources */ |
351a4ded | 982 | data = cdev->firmware->data + sizeof(u32); |
c965db44 TT |
983 | |
984 | qed_dbg_pf_init(cdev); | |
1408cc1f | 985 | } |
fe56b9e6 | 986 | |
1408cc1f | 987 | /* Start the slowpath */ |
c0c2d0b4 | 988 | memset(&hw_init_params, 0, sizeof(hw_init_params)); |
19968430 CM |
989 | memset(&tunn_info, 0, sizeof(tunn_info)); |
990 | tunn_info.vxlan.b_mode_enabled = true; | |
991 | tunn_info.l2_gre.b_mode_enabled = true; | |
992 | tunn_info.ip_gre.b_mode_enabled = true; | |
993 | tunn_info.l2_geneve.b_mode_enabled = true; | |
994 | tunn_info.ip_geneve.b_mode_enabled = true; | |
995 | tunn_info.vxlan.tun_cls = QED_TUNN_CLSS_MAC_VLAN; | |
996 | tunn_info.l2_gre.tun_cls = QED_TUNN_CLSS_MAC_VLAN; | |
997 | tunn_info.ip_gre.tun_cls = QED_TUNN_CLSS_MAC_VLAN; | |
998 | tunn_info.l2_geneve.tun_cls = QED_TUNN_CLSS_MAC_VLAN; | |
999 | tunn_info.ip_geneve.tun_cls = QED_TUNN_CLSS_MAC_VLAN; | |
c0c2d0b4 MY |
1000 | hw_init_params.p_tunn = &tunn_info; |
1001 | hw_init_params.b_hw_start = true; | |
1002 | hw_init_params.int_mode = cdev->int_params.out.int_mode; | |
1003 | hw_init_params.allow_npar_tx_switch = true; | |
1004 | hw_init_params.bin_fw_data = data; | |
1005 | ||
5d24bcf1 TT |
1006 | memset(&drv_load_params, 0, sizeof(drv_load_params)); |
1007 | drv_load_params.is_crash_kernel = is_kdump_kernel(); | |
1008 | drv_load_params.mfw_timeout_val = QED_LOAD_REQ_LOCK_TO_DEFAULT; | |
1009 | drv_load_params.avoid_eng_reset = false; | |
1010 | drv_load_params.override_force_load = QED_OVERRIDE_FORCE_LOAD_NONE; | |
1011 | hw_init_params.p_drv_load_params = &drv_load_params; | |
1012 | ||
c0c2d0b4 | 1013 | rc = qed_hw_init(cdev, &hw_init_params); |
fe56b9e6 | 1014 | if (rc) |
8c925c44 | 1015 | goto err2; |
fe56b9e6 YM |
1016 | |
1017 | DP_INFO(cdev, | |
1018 | "HW initialization and function start completed successfully\n"); | |
1019 | ||
eaf3c0c6 CM |
1020 | if (IS_PF(cdev)) { |
1021 | cdev->tunn_feature_mask = (BIT(QED_MODE_VXLAN_TUNN) | | |
1022 | BIT(QED_MODE_L2GENEVE_TUNN) | | |
1023 | BIT(QED_MODE_IPGENEVE_TUNN) | | |
1024 | BIT(QED_MODE_L2GRE_TUNN) | | |
1025 | BIT(QED_MODE_IPGRE_TUNN)); | |
1026 | } | |
1027 | ||
0a7fb11c YM |
1028 | /* Allocate LL2 interface if needed */ |
1029 | if (QED_LEADING_HWFN(cdev)->using_ll2) { | |
1030 | rc = qed_ll2_alloc_if(cdev); | |
1031 | if (rc) | |
1032 | goto err3; | |
1033 | } | |
1408cc1f YM |
1034 | if (IS_PF(cdev)) { |
1035 | hwfn = QED_LEADING_HWFN(cdev); | |
1036 | drv_version.version = (params->drv_major << 24) | | |
1037 | (params->drv_minor << 16) | | |
1038 | (params->drv_rev << 8) | | |
1039 | (params->drv_eng); | |
1040 | strlcpy(drv_version.name, params->name, | |
1041 | MCP_DRV_VER_STR_SIZE - 4); | |
1042 | rc = qed_mcp_send_drv_version(hwfn, hwfn->p_main_ptt, | |
1043 | &drv_version); | |
1044 | if (rc) { | |
1045 | DP_NOTICE(cdev, "Failed sending drv version command\n"); | |
1046 | return rc; | |
1047 | } | |
fe56b9e6 YM |
1048 | } |
1049 | ||
8c925c44 YM |
1050 | qed_reset_vport_stats(cdev); |
1051 | ||
fe56b9e6 YM |
1052 | return 0; |
1053 | ||
0a7fb11c YM |
1054 | err3: |
1055 | qed_hw_stop(cdev); | |
fe56b9e6 | 1056 | err2: |
8c925c44 | 1057 | qed_hw_timers_stop_all(cdev); |
1408cc1f YM |
1058 | if (IS_PF(cdev)) |
1059 | qed_slowpath_irq_free(cdev); | |
8c925c44 | 1060 | qed_free_stream_mem(cdev); |
fe56b9e6 YM |
1061 | qed_disable_msix(cdev); |
1062 | err1: | |
1063 | qed_resc_free(cdev); | |
1064 | err: | |
1408cc1f YM |
1065 | if (IS_PF(cdev)) |
1066 | release_firmware(cdev->firmware); | |
fe56b9e6 | 1067 | |
d51e4af5 CM |
1068 | #ifdef CONFIG_RFS_ACCEL |
1069 | if (IS_PF(cdev) && (cdev->num_hwfns == 1) && | |
1070 | QED_LEADING_HWFN(cdev)->p_arfs_ptt) | |
1071 | qed_ptt_release(QED_LEADING_HWFN(cdev), | |
1072 | QED_LEADING_HWFN(cdev)->p_arfs_ptt); | |
1073 | #endif | |
c78c70fa | 1074 | |
37bff2b9 YM |
1075 | qed_iov_wq_stop(cdev, false); |
1076 | ||
fe56b9e6 YM |
1077 | return rc; |
1078 | } | |
1079 | ||
1080 | static int qed_slowpath_stop(struct qed_dev *cdev) | |
1081 | { | |
1082 | if (!cdev) | |
1083 | return -ENODEV; | |
1084 | ||
0a7fb11c YM |
1085 | qed_ll2_dealloc_if(cdev); |
1086 | ||
1408cc1f | 1087 | if (IS_PF(cdev)) { |
d51e4af5 CM |
1088 | #ifdef CONFIG_RFS_ACCEL |
1089 | if (cdev->num_hwfns == 1) | |
1090 | qed_ptt_release(QED_LEADING_HWFN(cdev), | |
1091 | QED_LEADING_HWFN(cdev)->p_arfs_ptt); | |
1092 | #endif | |
1408cc1f | 1093 | qed_free_stream_mem(cdev); |
c5ac9319 YM |
1094 | if (IS_QED_ETH_IF(cdev)) |
1095 | qed_sriov_disable(cdev, true); | |
5f027d7a MY |
1096 | } |
1097 | ||
1098 | qed_nic_stop(cdev); | |
fe56b9e6 | 1099 | |
5f027d7a | 1100 | if (IS_PF(cdev)) |
1408cc1f | 1101 | qed_slowpath_irq_free(cdev); |
fe56b9e6 YM |
1102 | |
1103 | qed_disable_msix(cdev); | |
1226337a TT |
1104 | |
1105 | qed_resc_free(cdev); | |
fe56b9e6 | 1106 | |
37bff2b9 YM |
1107 | qed_iov_wq_stop(cdev, true); |
1108 | ||
1408cc1f YM |
1109 | if (IS_PF(cdev)) |
1110 | release_firmware(cdev->firmware); | |
fe56b9e6 YM |
1111 | |
1112 | return 0; | |
1113 | } | |
1114 | ||
1115 | static void qed_set_id(struct qed_dev *cdev, char name[NAME_SIZE], | |
1116 | char ver_str[VER_SIZE]) | |
1117 | { | |
1118 | int i; | |
1119 | ||
1120 | memcpy(cdev->name, name, NAME_SIZE); | |
1121 | for_each_hwfn(cdev, i) | |
1122 | snprintf(cdev->hwfns[i].name, NAME_SIZE, "%s-%d", name, i); | |
1123 | ||
1124 | memcpy(cdev->ver_str, ver_str, VER_SIZE); | |
1125 | cdev->drv_type = DRV_ID_DRV_TYPE_LINUX; | |
1126 | } | |
1127 | ||
1128 | static u32 qed_sb_init(struct qed_dev *cdev, | |
1129 | struct qed_sb_info *sb_info, | |
1130 | void *sb_virt_addr, | |
1131 | dma_addr_t sb_phy_addr, u16 sb_id, | |
1132 | enum qed_sb_type type) | |
1133 | { | |
1134 | struct qed_hwfn *p_hwfn; | |
85750d74 | 1135 | struct qed_ptt *p_ptt; |
fe56b9e6 YM |
1136 | int hwfn_index; |
1137 | u16 rel_sb_id; | |
1138 | u8 n_hwfns; | |
1139 | u32 rc; | |
1140 | ||
1141 | /* RoCE uses single engine and CMT uses two engines. When using both | |
1142 | * we force only a single engine. Storage uses only engine 0 too. | |
1143 | */ | |
1144 | if (type == QED_SB_TYPE_L2_QUEUE) | |
1145 | n_hwfns = cdev->num_hwfns; | |
1146 | else | |
1147 | n_hwfns = 1; | |
1148 | ||
1149 | hwfn_index = sb_id % n_hwfns; | |
1150 | p_hwfn = &cdev->hwfns[hwfn_index]; | |
1151 | rel_sb_id = sb_id / n_hwfns; | |
1152 | ||
1153 | DP_VERBOSE(cdev, NETIF_MSG_INTR, | |
1154 | "hwfn [%d] <--[init]-- SB %04x [0x%04x upper]\n", | |
1155 | hwfn_index, rel_sb_id, sb_id); | |
1156 | ||
85750d74 MY |
1157 | if (IS_PF(p_hwfn->cdev)) { |
1158 | p_ptt = qed_ptt_acquire(p_hwfn); | |
1159 | if (!p_ptt) | |
1160 | return -EBUSY; | |
1161 | ||
1162 | rc = qed_int_sb_init(p_hwfn, p_ptt, sb_info, sb_virt_addr, | |
1163 | sb_phy_addr, rel_sb_id); | |
1164 | qed_ptt_release(p_hwfn, p_ptt); | |
1165 | } else { | |
1166 | rc = qed_int_sb_init(p_hwfn, NULL, sb_info, sb_virt_addr, | |
1167 | sb_phy_addr, rel_sb_id); | |
1168 | } | |
fe56b9e6 YM |
1169 | |
1170 | return rc; | |
1171 | } | |
1172 | ||
1173 | static u32 qed_sb_release(struct qed_dev *cdev, | |
1a635e48 | 1174 | struct qed_sb_info *sb_info, u16 sb_id) |
fe56b9e6 YM |
1175 | { |
1176 | struct qed_hwfn *p_hwfn; | |
1177 | int hwfn_index; | |
1178 | u16 rel_sb_id; | |
1179 | u32 rc; | |
1180 | ||
1181 | hwfn_index = sb_id % cdev->num_hwfns; | |
1182 | p_hwfn = &cdev->hwfns[hwfn_index]; | |
1183 | rel_sb_id = sb_id / cdev->num_hwfns; | |
1184 | ||
1185 | DP_VERBOSE(cdev, NETIF_MSG_INTR, | |
1186 | "hwfn [%d] <--[init]-- SB %04x [0x%04x upper]\n", | |
1187 | hwfn_index, rel_sb_id, sb_id); | |
1188 | ||
1189 | rc = qed_int_sb_release(p_hwfn, sb_info, rel_sb_id); | |
1190 | ||
1191 | return rc; | |
1192 | } | |
1193 | ||
fe7cd2bf YM |
1194 | static bool qed_can_link_change(struct qed_dev *cdev) |
1195 | { | |
1196 | return true; | |
1197 | } | |
1198 | ||
351a4ded | 1199 | static int qed_set_link(struct qed_dev *cdev, struct qed_link_params *params) |
cc875c2e YM |
1200 | { |
1201 | struct qed_hwfn *hwfn; | |
1202 | struct qed_mcp_link_params *link_params; | |
1203 | struct qed_ptt *ptt; | |
1204 | int rc; | |
1205 | ||
1206 | if (!cdev) | |
1207 | return -ENODEV; | |
1208 | ||
1209 | /* The link should be set only once per PF */ | |
1210 | hwfn = &cdev->hwfns[0]; | |
1211 | ||
65ed2ffd MY |
1212 | /* When VF wants to set link, force it to read the bulletin instead. |
1213 | * This mimics the PF behavior, where a noitification [both immediate | |
1214 | * and possible later] would be generated when changing properties. | |
1215 | */ | |
1216 | if (IS_VF(cdev)) { | |
1217 | qed_schedule_iov(hwfn, QED_IOV_WQ_VF_FORCE_LINK_QUERY_FLAG); | |
1218 | return 0; | |
1219 | } | |
1220 | ||
cc875c2e YM |
1221 | ptt = qed_ptt_acquire(hwfn); |
1222 | if (!ptt) | |
1223 | return -EBUSY; | |
1224 | ||
1225 | link_params = qed_mcp_get_link_params(hwfn); | |
1226 | if (params->override_flags & QED_LINK_OVERRIDE_SPEED_AUTONEG) | |
1227 | link_params->speed.autoneg = params->autoneg; | |
1228 | if (params->override_flags & QED_LINK_OVERRIDE_SPEED_ADV_SPEEDS) { | |
1229 | link_params->speed.advertised_speeds = 0; | |
054c67d1 SRK |
1230 | if ((params->adv_speeds & QED_LM_1000baseT_Half_BIT) || |
1231 | (params->adv_speeds & QED_LM_1000baseT_Full_BIT)) | |
cc875c2e | 1232 | link_params->speed.advertised_speeds |= |
054c67d1 SRK |
1233 | NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G; |
1234 | if (params->adv_speeds & QED_LM_10000baseKR_Full_BIT) | |
cc875c2e | 1235 | link_params->speed.advertised_speeds |= |
054c67d1 SRK |
1236 | NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G; |
1237 | if (params->adv_speeds & QED_LM_25000baseKR_Full_BIT) | |
cc875c2e | 1238 | link_params->speed.advertised_speeds |= |
054c67d1 SRK |
1239 | NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G; |
1240 | if (params->adv_speeds & QED_LM_40000baseLR4_Full_BIT) | |
cc875c2e | 1241 | link_params->speed.advertised_speeds |= |
054c67d1 SRK |
1242 | NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G; |
1243 | if (params->adv_speeds & QED_LM_50000baseKR2_Full_BIT) | |
1244 | link_params->speed.advertised_speeds |= | |
1245 | NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G; | |
1246 | if (params->adv_speeds & QED_LM_100000baseKR4_Full_BIT) | |
cc875c2e | 1247 | link_params->speed.advertised_speeds |= |
351a4ded | 1248 | NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G; |
cc875c2e YM |
1249 | } |
1250 | if (params->override_flags & QED_LINK_OVERRIDE_SPEED_FORCED_SPEED) | |
1251 | link_params->speed.forced_speed = params->forced_speed; | |
a43f235f SRK |
1252 | if (params->override_flags & QED_LINK_OVERRIDE_PAUSE_CONFIG) { |
1253 | if (params->pause_config & QED_LINK_PAUSE_AUTONEG_ENABLE) | |
1254 | link_params->pause.autoneg = true; | |
1255 | else | |
1256 | link_params->pause.autoneg = false; | |
1257 | if (params->pause_config & QED_LINK_PAUSE_RX_ENABLE) | |
1258 | link_params->pause.forced_rx = true; | |
1259 | else | |
1260 | link_params->pause.forced_rx = false; | |
1261 | if (params->pause_config & QED_LINK_PAUSE_TX_ENABLE) | |
1262 | link_params->pause.forced_tx = true; | |
1263 | else | |
1264 | link_params->pause.forced_tx = false; | |
1265 | } | |
03dc76ca SRK |
1266 | if (params->override_flags & QED_LINK_OVERRIDE_LOOPBACK_MODE) { |
1267 | switch (params->loopback_mode) { | |
1268 | case QED_LINK_LOOPBACK_INT_PHY: | |
351a4ded | 1269 | link_params->loopback_mode = ETH_LOOPBACK_INT_PHY; |
03dc76ca SRK |
1270 | break; |
1271 | case QED_LINK_LOOPBACK_EXT_PHY: | |
351a4ded | 1272 | link_params->loopback_mode = ETH_LOOPBACK_EXT_PHY; |
03dc76ca SRK |
1273 | break; |
1274 | case QED_LINK_LOOPBACK_EXT: | |
351a4ded | 1275 | link_params->loopback_mode = ETH_LOOPBACK_EXT; |
03dc76ca SRK |
1276 | break; |
1277 | case QED_LINK_LOOPBACK_MAC: | |
351a4ded | 1278 | link_params->loopback_mode = ETH_LOOPBACK_MAC; |
03dc76ca SRK |
1279 | break; |
1280 | default: | |
351a4ded | 1281 | link_params->loopback_mode = ETH_LOOPBACK_NONE; |
03dc76ca SRK |
1282 | break; |
1283 | } | |
1284 | } | |
cc875c2e YM |
1285 | |
1286 | rc = qed_mcp_set_link(hwfn, ptt, params->link_up); | |
1287 | ||
1288 | qed_ptt_release(hwfn, ptt); | |
1289 | ||
1290 | return rc; | |
1291 | } | |
1292 | ||
1293 | static int qed_get_port_type(u32 media_type) | |
1294 | { | |
1295 | int port_type; | |
1296 | ||
1297 | switch (media_type) { | |
1298 | case MEDIA_SFPP_10G_FIBER: | |
1299 | case MEDIA_SFP_1G_FIBER: | |
1300 | case MEDIA_XFP_FIBER: | |
b639f197 | 1301 | case MEDIA_MODULE_FIBER: |
cc875c2e YM |
1302 | case MEDIA_KR: |
1303 | port_type = PORT_FIBRE; | |
1304 | break; | |
1305 | case MEDIA_DA_TWINAX: | |
1306 | port_type = PORT_DA; | |
1307 | break; | |
1308 | case MEDIA_BASE_T: | |
1309 | port_type = PORT_TP; | |
1310 | break; | |
1311 | case MEDIA_NOT_PRESENT: | |
1312 | port_type = PORT_NONE; | |
1313 | break; | |
1314 | case MEDIA_UNSPECIFIED: | |
1315 | default: | |
1316 | port_type = PORT_OTHER; | |
1317 | break; | |
1318 | } | |
1319 | return port_type; | |
1320 | } | |
1321 | ||
14b84e86 AB |
1322 | static int qed_get_link_data(struct qed_hwfn *hwfn, |
1323 | struct qed_mcp_link_params *params, | |
1324 | struct qed_mcp_link_state *link, | |
1325 | struct qed_mcp_link_capabilities *link_caps) | |
1326 | { | |
1327 | void *p; | |
1328 | ||
1329 | if (!IS_PF(hwfn->cdev)) { | |
1330 | qed_vf_get_link_params(hwfn, params); | |
1331 | qed_vf_get_link_state(hwfn, link); | |
1332 | qed_vf_get_link_caps(hwfn, link_caps); | |
1333 | ||
1334 | return 0; | |
1335 | } | |
1336 | ||
1337 | p = qed_mcp_get_link_params(hwfn); | |
1338 | if (!p) | |
1339 | return -ENXIO; | |
1340 | memcpy(params, p, sizeof(*params)); | |
1341 | ||
1342 | p = qed_mcp_get_link_state(hwfn); | |
1343 | if (!p) | |
1344 | return -ENXIO; | |
1345 | memcpy(link, p, sizeof(*link)); | |
1346 | ||
1347 | p = qed_mcp_get_link_capabilities(hwfn); | |
1348 | if (!p) | |
1349 | return -ENXIO; | |
1350 | memcpy(link_caps, p, sizeof(*link_caps)); | |
1351 | ||
1352 | return 0; | |
1353 | } | |
1354 | ||
cc875c2e YM |
1355 | static void qed_fill_link(struct qed_hwfn *hwfn, |
1356 | struct qed_link_output *if_link) | |
1357 | { | |
1358 | struct qed_mcp_link_params params; | |
1359 | struct qed_mcp_link_state link; | |
1360 | struct qed_mcp_link_capabilities link_caps; | |
1361 | u32 media_type; | |
1362 | ||
1363 | memset(if_link, 0, sizeof(*if_link)); | |
1364 | ||
1365 | /* Prepare source inputs */ | |
14b84e86 AB |
1366 | if (qed_get_link_data(hwfn, ¶ms, &link, &link_caps)) { |
1367 | dev_warn(&hwfn->cdev->pdev->dev, "no link data available\n"); | |
1368 | return; | |
1408cc1f | 1369 | } |
cc875c2e YM |
1370 | |
1371 | /* Set the link parameters to pass to protocol driver */ | |
1372 | if (link.link_up) | |
1373 | if_link->link_up = true; | |
1374 | ||
1375 | /* TODO - at the moment assume supported and advertised speed equal */ | |
054c67d1 | 1376 | if_link->supported_caps = QED_LM_FIBRE_BIT; |
34f9199c | 1377 | if (link_caps.default_speed_autoneg) |
054c67d1 | 1378 | if_link->supported_caps |= QED_LM_Autoneg_BIT; |
cc875c2e YM |
1379 | if (params.pause.autoneg || |
1380 | (params.pause.forced_rx && params.pause.forced_tx)) | |
054c67d1 | 1381 | if_link->supported_caps |= QED_LM_Asym_Pause_BIT; |
cc875c2e YM |
1382 | if (params.pause.autoneg || params.pause.forced_rx || |
1383 | params.pause.forced_tx) | |
054c67d1 | 1384 | if_link->supported_caps |= QED_LM_Pause_BIT; |
cc875c2e YM |
1385 | |
1386 | if_link->advertised_caps = if_link->supported_caps; | |
34f9199c | 1387 | if (params.speed.autoneg) |
1388 | if_link->advertised_caps |= QED_LM_Autoneg_BIT; | |
1389 | else | |
1390 | if_link->advertised_caps &= ~QED_LM_Autoneg_BIT; | |
cc875c2e YM |
1391 | if (params.speed.advertised_speeds & |
1392 | NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G) | |
054c67d1 SRK |
1393 | if_link->advertised_caps |= QED_LM_1000baseT_Half_BIT | |
1394 | QED_LM_1000baseT_Full_BIT; | |
cc875c2e YM |
1395 | if (params.speed.advertised_speeds & |
1396 | NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G) | |
054c67d1 SRK |
1397 | if_link->advertised_caps |= QED_LM_10000baseKR_Full_BIT; |
1398 | if (params.speed.advertised_speeds & | |
1399 | NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G) | |
1400 | if_link->advertised_caps |= QED_LM_25000baseKR_Full_BIT; | |
cc875c2e | 1401 | if (params.speed.advertised_speeds & |
054c67d1 SRK |
1402 | NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G) |
1403 | if_link->advertised_caps |= QED_LM_40000baseLR4_Full_BIT; | |
cc875c2e | 1404 | if (params.speed.advertised_speeds & |
054c67d1 SRK |
1405 | NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G) |
1406 | if_link->advertised_caps |= QED_LM_50000baseKR2_Full_BIT; | |
cc875c2e | 1407 | if (params.speed.advertised_speeds & |
351a4ded | 1408 | NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G) |
054c67d1 | 1409 | if_link->advertised_caps |= QED_LM_100000baseKR4_Full_BIT; |
cc875c2e YM |
1410 | |
1411 | if (link_caps.speed_capabilities & | |
1412 | NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G) | |
054c67d1 SRK |
1413 | if_link->supported_caps |= QED_LM_1000baseT_Half_BIT | |
1414 | QED_LM_1000baseT_Full_BIT; | |
cc875c2e YM |
1415 | if (link_caps.speed_capabilities & |
1416 | NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G) | |
054c67d1 SRK |
1417 | if_link->supported_caps |= QED_LM_10000baseKR_Full_BIT; |
1418 | if (link_caps.speed_capabilities & | |
1419 | NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G) | |
1420 | if_link->supported_caps |= QED_LM_25000baseKR_Full_BIT; | |
cc875c2e | 1421 | if (link_caps.speed_capabilities & |
054c67d1 SRK |
1422 | NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G) |
1423 | if_link->supported_caps |= QED_LM_40000baseLR4_Full_BIT; | |
cc875c2e | 1424 | if (link_caps.speed_capabilities & |
054c67d1 SRK |
1425 | NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G) |
1426 | if_link->supported_caps |= QED_LM_50000baseKR2_Full_BIT; | |
cc875c2e | 1427 | if (link_caps.speed_capabilities & |
351a4ded | 1428 | NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G) |
054c67d1 | 1429 | if_link->supported_caps |= QED_LM_100000baseKR4_Full_BIT; |
cc875c2e YM |
1430 | |
1431 | if (link.link_up) | |
1432 | if_link->speed = link.speed; | |
1433 | ||
1434 | /* TODO - fill duplex properly */ | |
1435 | if_link->duplex = DUPLEX_FULL; | |
1436 | qed_mcp_get_media_type(hwfn->cdev, &media_type); | |
1437 | if_link->port = qed_get_port_type(media_type); | |
1438 | ||
1439 | if_link->autoneg = params.speed.autoneg; | |
1440 | ||
1441 | if (params.pause.autoneg) | |
1442 | if_link->pause_config |= QED_LINK_PAUSE_AUTONEG_ENABLE; | |
1443 | if (params.pause.forced_rx) | |
1444 | if_link->pause_config |= QED_LINK_PAUSE_RX_ENABLE; | |
1445 | if (params.pause.forced_tx) | |
1446 | if_link->pause_config |= QED_LINK_PAUSE_TX_ENABLE; | |
1447 | ||
1448 | /* Link partner capabilities */ | |
054c67d1 SRK |
1449 | if (link.partner_adv_speed & QED_LINK_PARTNER_SPEED_1G_HD) |
1450 | if_link->lp_caps |= QED_LM_1000baseT_Half_BIT; | |
1451 | if (link.partner_adv_speed & QED_LINK_PARTNER_SPEED_1G_FD) | |
1452 | if_link->lp_caps |= QED_LM_1000baseT_Full_BIT; | |
1453 | if (link.partner_adv_speed & QED_LINK_PARTNER_SPEED_10G) | |
1454 | if_link->lp_caps |= QED_LM_10000baseKR_Full_BIT; | |
1455 | if (link.partner_adv_speed & QED_LINK_PARTNER_SPEED_25G) | |
1456 | if_link->lp_caps |= QED_LM_25000baseKR_Full_BIT; | |
1457 | if (link.partner_adv_speed & QED_LINK_PARTNER_SPEED_40G) | |
1458 | if_link->lp_caps |= QED_LM_40000baseLR4_Full_BIT; | |
1459 | if (link.partner_adv_speed & QED_LINK_PARTNER_SPEED_50G) | |
1460 | if_link->lp_caps |= QED_LM_50000baseKR2_Full_BIT; | |
1461 | if (link.partner_adv_speed & QED_LINK_PARTNER_SPEED_100G) | |
1462 | if_link->lp_caps |= QED_LM_100000baseKR4_Full_BIT; | |
cc875c2e YM |
1463 | |
1464 | if (link.an_complete) | |
054c67d1 | 1465 | if_link->lp_caps |= QED_LM_Autoneg_BIT; |
cc875c2e YM |
1466 | |
1467 | if (link.partner_adv_pause) | |
054c67d1 | 1468 | if_link->lp_caps |= QED_LM_Pause_BIT; |
cc875c2e YM |
1469 | if (link.partner_adv_pause == QED_LINK_PARTNER_ASYMMETRIC_PAUSE || |
1470 | link.partner_adv_pause == QED_LINK_PARTNER_BOTH_PAUSE) | |
054c67d1 | 1471 | if_link->lp_caps |= QED_LM_Asym_Pause_BIT; |
cc875c2e YM |
1472 | } |
1473 | ||
1474 | static void qed_get_current_link(struct qed_dev *cdev, | |
1475 | struct qed_link_output *if_link) | |
1476 | { | |
36558c3d YM |
1477 | int i; |
1478 | ||
cc875c2e | 1479 | qed_fill_link(&cdev->hwfns[0], if_link); |
36558c3d YM |
1480 | |
1481 | for_each_hwfn(cdev, i) | |
1482 | qed_inform_vf_link_state(&cdev->hwfns[i]); | |
cc875c2e YM |
1483 | } |
1484 | ||
1485 | void qed_link_update(struct qed_hwfn *hwfn) | |
1486 | { | |
1487 | void *cookie = hwfn->cdev->ops_cookie; | |
1488 | struct qed_common_cb_ops *op = hwfn->cdev->protocol_ops.common; | |
1489 | struct qed_link_output if_link; | |
1490 | ||
1491 | qed_fill_link(hwfn, &if_link); | |
36558c3d | 1492 | qed_inform_vf_link_state(hwfn); |
cc875c2e YM |
1493 | |
1494 | if (IS_LEAD_HWFN(hwfn) && cookie) | |
1495 | op->link_update(cookie, &if_link); | |
1496 | } | |
1497 | ||
fe56b9e6 YM |
1498 | static int qed_drain(struct qed_dev *cdev) |
1499 | { | |
1500 | struct qed_hwfn *hwfn; | |
1501 | struct qed_ptt *ptt; | |
1502 | int i, rc; | |
1503 | ||
1408cc1f YM |
1504 | if (IS_VF(cdev)) |
1505 | return 0; | |
1506 | ||
fe56b9e6 YM |
1507 | for_each_hwfn(cdev, i) { |
1508 | hwfn = &cdev->hwfns[i]; | |
1509 | ptt = qed_ptt_acquire(hwfn); | |
1510 | if (!ptt) { | |
1511 | DP_NOTICE(hwfn, "Failed to drain NIG; No PTT\n"); | |
1512 | return -EBUSY; | |
1513 | } | |
1514 | rc = qed_mcp_drain(hwfn, ptt); | |
1515 | if (rc) | |
1516 | return rc; | |
1517 | qed_ptt_release(hwfn, ptt); | |
1518 | } | |
1519 | ||
1520 | return 0; | |
1521 | } | |
1522 | ||
722003ac SRK |
1523 | static void qed_get_coalesce(struct qed_dev *cdev, u16 *rx_coal, u16 *tx_coal) |
1524 | { | |
1525 | *rx_coal = cdev->rx_coalesce_usecs; | |
1526 | *tx_coal = cdev->tx_coalesce_usecs; | |
1527 | } | |
1528 | ||
1529 | static int qed_set_coalesce(struct qed_dev *cdev, u16 rx_coal, u16 tx_coal, | |
f870a3c6 | 1530 | u16 qid, u16 sb_id) |
722003ac SRK |
1531 | { |
1532 | struct qed_hwfn *hwfn; | |
1533 | struct qed_ptt *ptt; | |
1534 | int hwfn_index; | |
1535 | int status = 0; | |
1536 | ||
1537 | hwfn_index = qid % cdev->num_hwfns; | |
1538 | hwfn = &cdev->hwfns[hwfn_index]; | |
1539 | ptt = qed_ptt_acquire(hwfn); | |
1540 | if (!ptt) | |
1541 | return -EAGAIN; | |
1542 | ||
1543 | status = qed_set_rxq_coalesce(hwfn, ptt, rx_coal, | |
1544 | qid / cdev->num_hwfns, sb_id); | |
1545 | if (status) | |
1546 | goto out; | |
1547 | status = qed_set_txq_coalesce(hwfn, ptt, tx_coal, | |
1548 | qid / cdev->num_hwfns, sb_id); | |
1549 | out: | |
1550 | qed_ptt_release(hwfn, ptt); | |
1551 | ||
1552 | return status; | |
1553 | } | |
1554 | ||
91420b83 SK |
1555 | static int qed_set_led(struct qed_dev *cdev, enum qed_led_mode mode) |
1556 | { | |
1557 | struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); | |
1558 | struct qed_ptt *ptt; | |
1559 | int status = 0; | |
1560 | ||
1561 | ptt = qed_ptt_acquire(hwfn); | |
1562 | if (!ptt) | |
1563 | return -EAGAIN; | |
1564 | ||
1565 | status = qed_mcp_set_led(hwfn, ptt, mode); | |
1566 | ||
1567 | qed_ptt_release(hwfn, ptt); | |
1568 | ||
1569 | return status; | |
1570 | } | |
1571 | ||
14d39648 MY |
1572 | static int qed_update_wol(struct qed_dev *cdev, bool enabled) |
1573 | { | |
1574 | struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); | |
1575 | struct qed_ptt *ptt; | |
1576 | int rc = 0; | |
1577 | ||
1578 | if (IS_VF(cdev)) | |
1579 | return 0; | |
1580 | ||
1581 | ptt = qed_ptt_acquire(hwfn); | |
1582 | if (!ptt) | |
1583 | return -EAGAIN; | |
1584 | ||
1585 | rc = qed_mcp_ov_update_wol(hwfn, ptt, enabled ? QED_OV_WOL_ENABLED | |
1586 | : QED_OV_WOL_DISABLED); | |
1587 | if (rc) | |
1588 | goto out; | |
1589 | rc = qed_mcp_ov_update_current_config(hwfn, ptt, QED_OV_CLIENT_DRV); | |
1590 | ||
1591 | out: | |
1592 | qed_ptt_release(hwfn, ptt); | |
1593 | return rc; | |
1594 | } | |
1595 | ||
0fefbfba SK |
1596 | static int qed_update_drv_state(struct qed_dev *cdev, bool active) |
1597 | { | |
1598 | struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); | |
1599 | struct qed_ptt *ptt; | |
1600 | int status = 0; | |
1601 | ||
1602 | if (IS_VF(cdev)) | |
1603 | return 0; | |
1604 | ||
1605 | ptt = qed_ptt_acquire(hwfn); | |
1606 | if (!ptt) | |
1607 | return -EAGAIN; | |
1608 | ||
1609 | status = qed_mcp_ov_update_driver_state(hwfn, ptt, active ? | |
1610 | QED_OV_DRIVER_STATE_ACTIVE : | |
1611 | QED_OV_DRIVER_STATE_DISABLED); | |
1612 | ||
1613 | qed_ptt_release(hwfn, ptt); | |
1614 | ||
1615 | return status; | |
1616 | } | |
1617 | ||
1618 | static int qed_update_mac(struct qed_dev *cdev, u8 *mac) | |
1619 | { | |
1620 | struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); | |
1621 | struct qed_ptt *ptt; | |
1622 | int status = 0; | |
1623 | ||
1624 | if (IS_VF(cdev)) | |
1625 | return 0; | |
1626 | ||
1627 | ptt = qed_ptt_acquire(hwfn); | |
1628 | if (!ptt) | |
1629 | return -EAGAIN; | |
1630 | ||
1631 | status = qed_mcp_ov_update_mac(hwfn, ptt, mac); | |
1632 | if (status) | |
1633 | goto out; | |
1634 | ||
1635 | status = qed_mcp_ov_update_current_config(hwfn, ptt, QED_OV_CLIENT_DRV); | |
1636 | ||
1637 | out: | |
1638 | qed_ptt_release(hwfn, ptt); | |
1639 | return status; | |
1640 | } | |
1641 | ||
1642 | static int qed_update_mtu(struct qed_dev *cdev, u16 mtu) | |
1643 | { | |
1644 | struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); | |
1645 | struct qed_ptt *ptt; | |
1646 | int status = 0; | |
1647 | ||
1648 | if (IS_VF(cdev)) | |
1649 | return 0; | |
1650 | ||
1651 | ptt = qed_ptt_acquire(hwfn); | |
1652 | if (!ptt) | |
1653 | return -EAGAIN; | |
1654 | ||
1655 | status = qed_mcp_ov_update_mtu(hwfn, ptt, mtu); | |
1656 | if (status) | |
1657 | goto out; | |
1658 | ||
1659 | status = qed_mcp_ov_update_current_config(hwfn, ptt, QED_OV_CLIENT_DRV); | |
1660 | ||
1661 | out: | |
1662 | qed_ptt_release(hwfn, ptt); | |
1663 | return status; | |
1664 | } | |
1665 | ||
8c93beaf | 1666 | static struct qed_selftest_ops qed_selftest_ops_pass = { |
03dc76ca SRK |
1667 | .selftest_memory = &qed_selftest_memory, |
1668 | .selftest_interrupt = &qed_selftest_interrupt, | |
1669 | .selftest_register = &qed_selftest_register, | |
1670 | .selftest_clock = &qed_selftest_clock, | |
7a4b21b7 | 1671 | .selftest_nvram = &qed_selftest_nvram, |
03dc76ca SRK |
1672 | }; |
1673 | ||
fe56b9e6 | 1674 | const struct qed_common_ops qed_common_ops_pass = { |
03dc76ca | 1675 | .selftest = &qed_selftest_ops_pass, |
fe56b9e6 YM |
1676 | .probe = &qed_probe, |
1677 | .remove = &qed_remove, | |
1678 | .set_power_state = &qed_set_power_state, | |
1679 | .set_id = &qed_set_id, | |
1680 | .update_pf_params = &qed_update_pf_params, | |
1681 | .slowpath_start = &qed_slowpath_start, | |
1682 | .slowpath_stop = &qed_slowpath_stop, | |
1683 | .set_fp_int = &qed_set_int_fp, | |
1684 | .get_fp_int = &qed_get_int_fp, | |
1685 | .sb_init = &qed_sb_init, | |
1686 | .sb_release = &qed_sb_release, | |
1687 | .simd_handler_config = &qed_simd_handler_config, | |
1688 | .simd_handler_clean = &qed_simd_handler_clean, | |
1e128c81 AE |
1689 | .dbg_grc = &qed_dbg_grc, |
1690 | .dbg_grc_size = &qed_dbg_grc_size, | |
fe7cd2bf | 1691 | .can_link_change = &qed_can_link_change, |
cc875c2e YM |
1692 | .set_link = &qed_set_link, |
1693 | .get_link = &qed_get_current_link, | |
fe56b9e6 YM |
1694 | .drain = &qed_drain, |
1695 | .update_msglvl = &qed_init_dp, | |
e0971c83 TT |
1696 | .dbg_all_data = &qed_dbg_all_data, |
1697 | .dbg_all_data_size = &qed_dbg_all_data_size, | |
fe56b9e6 YM |
1698 | .chain_alloc = &qed_chain_alloc, |
1699 | .chain_free = &qed_chain_free, | |
722003ac SRK |
1700 | .get_coalesce = &qed_get_coalesce, |
1701 | .set_coalesce = &qed_set_coalesce, | |
91420b83 | 1702 | .set_led = &qed_set_led, |
0fefbfba SK |
1703 | .update_drv_state = &qed_update_drv_state, |
1704 | .update_mac = &qed_update_mac, | |
1705 | .update_mtu = &qed_update_mtu, | |
14d39648 | 1706 | .update_wol = &qed_update_wol, |
fe56b9e6 | 1707 | }; |
6c754246 SRK |
1708 | |
1709 | void qed_get_protocol_stats(struct qed_dev *cdev, | |
1710 | enum qed_mcp_protocol_type type, | |
1711 | union qed_mcp_protocol_stats *stats) | |
1712 | { | |
1713 | struct qed_eth_stats eth_stats; | |
1714 | ||
1715 | memset(stats, 0, sizeof(*stats)); | |
1716 | ||
1717 | switch (type) { | |
1718 | case QED_MCP_LAN_STATS: | |
1719 | qed_get_vport_stats(cdev, ð_stats); | |
9c79ddaa MY |
1720 | stats->lan_stats.ucast_rx_pkts = |
1721 | eth_stats.common.rx_ucast_pkts; | |
1722 | stats->lan_stats.ucast_tx_pkts = | |
1723 | eth_stats.common.tx_ucast_pkts; | |
6c754246 SRK |
1724 | stats->lan_stats.fcs_err = -1; |
1725 | break; | |
1e128c81 AE |
1726 | case QED_MCP_FCOE_STATS: |
1727 | qed_get_protocol_stats_fcoe(cdev, &stats->fcoe_stats); | |
1728 | break; | |
2f2b2614 MY |
1729 | case QED_MCP_ISCSI_STATS: |
1730 | qed_get_protocol_stats_iscsi(cdev, &stats->iscsi_stats); | |
1731 | break; | |
6c754246 | 1732 | default: |
512c7840 MY |
1733 | DP_VERBOSE(cdev, QED_MSG_SP, |
1734 | "Invalid protocol type = %d\n", type); | |
6c754246 SRK |
1735 | return; |
1736 | } | |
1737 | } |