Commit | Line | Data |
---|---|---|
fe56b9e6 YM |
1 | /* QLogic qed NIC Driver |
2 | * Copyright (c) 2015 QLogic Corporation | |
3 | * | |
4 | * This software is available under the terms of the GNU General Public License | |
5 | * (GPL) Version 2, available from the file COPYING in the main directory of | |
6 | * this source tree. | |
7 | */ | |
8 | ||
9 | #include <linux/stddef.h> | |
10 | #include <linux/pci.h> | |
11 | #include <linux/kernel.h> | |
12 | #include <linux/slab.h> | |
13 | #include <linux/version.h> | |
14 | #include <linux/delay.h> | |
15 | #include <asm/byteorder.h> | |
16 | #include <linux/dma-mapping.h> | |
17 | #include <linux/string.h> | |
18 | #include <linux/module.h> | |
19 | #include <linux/interrupt.h> | |
20 | #include <linux/workqueue.h> | |
21 | #include <linux/ethtool.h> | |
22 | #include <linux/etherdevice.h> | |
23 | #include <linux/vmalloc.h> | |
24 | #include <linux/qed/qed_if.h> | |
25 | ||
26 | #include "qed.h" | |
37bff2b9 | 27 | #include "qed_sriov.h" |
fe56b9e6 YM |
28 | #include "qed_sp.h" |
29 | #include "qed_dev_api.h" | |
30 | #include "qed_mcp.h" | |
31 | #include "qed_hw.h" | |
03dc76ca | 32 | #include "qed_selftest.h" |
fe56b9e6 | 33 | |
5abd7e92 YM |
34 | static char version[] = |
35 | "QLogic FastLinQ 4xxxx Core Module qed " DRV_MODULE_VERSION "\n"; | |
fe56b9e6 | 36 | |
5abd7e92 | 37 | MODULE_DESCRIPTION("QLogic FastLinQ 4xxxx Core Module"); |
fe56b9e6 YM |
38 | MODULE_LICENSE("GPL"); |
39 | MODULE_VERSION(DRV_MODULE_VERSION); | |
40 | ||
41 | #define FW_FILE_VERSION \ | |
42 | __stringify(FW_MAJOR_VERSION) "." \ | |
43 | __stringify(FW_MINOR_VERSION) "." \ | |
44 | __stringify(FW_REVISION_VERSION) "." \ | |
45 | __stringify(FW_ENGINEERING_VERSION) | |
46 | ||
47 | #define QED_FW_FILE_NAME \ | |
48 | "qed/qed_init_values_zipped-" FW_FILE_VERSION ".bin" | |
49 | ||
d43d3f0f YM |
50 | MODULE_FIRMWARE(QED_FW_FILE_NAME); |
51 | ||
fe56b9e6 YM |
52 | static int __init qed_init(void) |
53 | { | |
fe56b9e6 YM |
54 | pr_info("%s", version); |
55 | ||
56 | return 0; | |
57 | } | |
58 | ||
59 | static void __exit qed_cleanup(void) | |
60 | { | |
61 | pr_notice("qed_cleanup called\n"); | |
62 | } | |
63 | ||
64 | module_init(qed_init); | |
65 | module_exit(qed_cleanup); | |
66 | ||
67 | /* Check if the DMA controller on the machine can properly handle the DMA | |
68 | * addressing required by the device. | |
69 | */ | |
70 | static int qed_set_coherency_mask(struct qed_dev *cdev) | |
71 | { | |
72 | struct device *dev = &cdev->pdev->dev; | |
73 | ||
74 | if (dma_set_mask(dev, DMA_BIT_MASK(64)) == 0) { | |
75 | if (dma_set_coherent_mask(dev, DMA_BIT_MASK(64)) != 0) { | |
76 | DP_NOTICE(cdev, | |
77 | "Can't request 64-bit consistent allocations\n"); | |
78 | return -EIO; | |
79 | } | |
80 | } else if (dma_set_mask(dev, DMA_BIT_MASK(32)) != 0) { | |
81 | DP_NOTICE(cdev, "Can't request 64b/32b DMA addresses\n"); | |
82 | return -EIO; | |
83 | } | |
84 | ||
85 | return 0; | |
86 | } | |
87 | ||
88 | static void qed_free_pci(struct qed_dev *cdev) | |
89 | { | |
90 | struct pci_dev *pdev = cdev->pdev; | |
91 | ||
92 | if (cdev->doorbells) | |
93 | iounmap(cdev->doorbells); | |
94 | if (cdev->regview) | |
95 | iounmap(cdev->regview); | |
96 | if (atomic_read(&pdev->enable_cnt) == 1) | |
97 | pci_release_regions(pdev); | |
98 | ||
99 | pci_disable_device(pdev); | |
100 | } | |
101 | ||
0dfaba6d YM |
102 | #define PCI_REVISION_ID_ERROR_VAL 0xff |
103 | ||
fe56b9e6 YM |
104 | /* Performs PCI initializations as well as initializing PCI-related parameters |
105 | * in the device structrue. Returns 0 in case of success. | |
106 | */ | |
1a635e48 | 107 | static int qed_init_pci(struct qed_dev *cdev, struct pci_dev *pdev) |
fe56b9e6 | 108 | { |
0dfaba6d | 109 | u8 rev_id; |
fe56b9e6 YM |
110 | int rc; |
111 | ||
112 | cdev->pdev = pdev; | |
113 | ||
114 | rc = pci_enable_device(pdev); | |
115 | if (rc) { | |
116 | DP_NOTICE(cdev, "Cannot enable PCI device\n"); | |
117 | goto err0; | |
118 | } | |
119 | ||
120 | if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { | |
121 | DP_NOTICE(cdev, "No memory region found in bar #0\n"); | |
122 | rc = -EIO; | |
123 | goto err1; | |
124 | } | |
125 | ||
1408cc1f | 126 | if (IS_PF(cdev) && !(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) { |
fe56b9e6 YM |
127 | DP_NOTICE(cdev, "No memory region found in bar #2\n"); |
128 | rc = -EIO; | |
129 | goto err1; | |
130 | } | |
131 | ||
132 | if (atomic_read(&pdev->enable_cnt) == 1) { | |
133 | rc = pci_request_regions(pdev, "qed"); | |
134 | if (rc) { | |
135 | DP_NOTICE(cdev, | |
136 | "Failed to request PCI memory resources\n"); | |
137 | goto err1; | |
138 | } | |
139 | pci_set_master(pdev); | |
140 | pci_save_state(pdev); | |
141 | } | |
142 | ||
0dfaba6d YM |
143 | pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id); |
144 | if (rev_id == PCI_REVISION_ID_ERROR_VAL) { | |
145 | DP_NOTICE(cdev, | |
146 | "Detected PCI device error [rev_id 0x%x]. Probably due to prior indication. Aborting.\n", | |
147 | rev_id); | |
148 | rc = -ENODEV; | |
149 | goto err2; | |
150 | } | |
fe56b9e6 YM |
151 | if (!pci_is_pcie(pdev)) { |
152 | DP_NOTICE(cdev, "The bus is not PCI Express\n"); | |
153 | rc = -EIO; | |
154 | goto err2; | |
155 | } | |
156 | ||
157 | cdev->pci_params.pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM); | |
416cdf06 | 158 | if (IS_PF(cdev) && !cdev->pci_params.pm_cap) |
fe56b9e6 YM |
159 | DP_NOTICE(cdev, "Cannot find power management capability\n"); |
160 | ||
161 | rc = qed_set_coherency_mask(cdev); | |
162 | if (rc) | |
163 | goto err2; | |
164 | ||
165 | cdev->pci_params.mem_start = pci_resource_start(pdev, 0); | |
166 | cdev->pci_params.mem_end = pci_resource_end(pdev, 0); | |
167 | cdev->pci_params.irq = pdev->irq; | |
168 | ||
169 | cdev->regview = pci_ioremap_bar(pdev, 0); | |
170 | if (!cdev->regview) { | |
171 | DP_NOTICE(cdev, "Cannot map register space, aborting\n"); | |
172 | rc = -ENOMEM; | |
173 | goto err2; | |
174 | } | |
175 | ||
1408cc1f | 176 | if (IS_PF(cdev)) { |
f82731b4 | 177 | cdev->db_phys_addr = pci_resource_start(cdev->pdev, 2); |
1408cc1f YM |
178 | cdev->db_size = pci_resource_len(cdev->pdev, 2); |
179 | cdev->doorbells = ioremap_wc(cdev->db_phys_addr, cdev->db_size); | |
180 | if (!cdev->doorbells) { | |
181 | DP_NOTICE(cdev, "Cannot map doorbell space\n"); | |
182 | return -ENOMEM; | |
183 | } | |
fe56b9e6 YM |
184 | } |
185 | ||
186 | return 0; | |
187 | ||
188 | err2: | |
189 | pci_release_regions(pdev); | |
190 | err1: | |
191 | pci_disable_device(pdev); | |
192 | err0: | |
193 | return rc; | |
194 | } | |
195 | ||
196 | int qed_fill_dev_info(struct qed_dev *cdev, | |
197 | struct qed_dev_info *dev_info) | |
198 | { | |
cee4d264 MC |
199 | struct qed_ptt *ptt; |
200 | ||
fe56b9e6 YM |
201 | memset(dev_info, 0, sizeof(struct qed_dev_info)); |
202 | ||
203 | dev_info->num_hwfns = cdev->num_hwfns; | |
204 | dev_info->pci_mem_start = cdev->pci_params.mem_start; | |
205 | dev_info->pci_mem_end = cdev->pci_params.mem_end; | |
206 | dev_info->pci_irq = cdev->pci_params.irq; | |
c5ac9319 YM |
207 | dev_info->rdma_supported = |
208 | (cdev->hwfns[0].hw_info.personality == QED_PCI_ETH_ROCE); | |
fc48b7a6 | 209 | dev_info->is_mf_default = IS_MF_DEFAULT(&cdev->hwfns[0]); |
fe56b9e6 YM |
210 | ether_addr_copy(dev_info->hw_mac, cdev->hwfns[0].hw_info.hw_mac_addr); |
211 | ||
1408cc1f YM |
212 | if (IS_PF(cdev)) { |
213 | dev_info->fw_major = FW_MAJOR_VERSION; | |
214 | dev_info->fw_minor = FW_MINOR_VERSION; | |
215 | dev_info->fw_rev = FW_REVISION_VERSION; | |
216 | dev_info->fw_eng = FW_ENGINEERING_VERSION; | |
217 | dev_info->mf_mode = cdev->mf_mode; | |
831bfb0e | 218 | dev_info->tx_switching = true; |
1408cc1f YM |
219 | } else { |
220 | qed_vf_get_fw_version(&cdev->hwfns[0], &dev_info->fw_major, | |
221 | &dev_info->fw_minor, &dev_info->fw_rev, | |
222 | &dev_info->fw_eng); | |
223 | } | |
fe56b9e6 | 224 | |
1408cc1f YM |
225 | if (IS_PF(cdev)) { |
226 | ptt = qed_ptt_acquire(QED_LEADING_HWFN(cdev)); | |
227 | if (ptt) { | |
228 | qed_mcp_get_mfw_ver(QED_LEADING_HWFN(cdev), ptt, | |
229 | &dev_info->mfw_rev, NULL); | |
fe56b9e6 | 230 | |
1408cc1f YM |
231 | qed_mcp_get_flash_size(QED_LEADING_HWFN(cdev), ptt, |
232 | &dev_info->flash_size); | |
cee4d264 | 233 | |
1408cc1f YM |
234 | qed_ptt_release(QED_LEADING_HWFN(cdev), ptt); |
235 | } | |
236 | } else { | |
237 | qed_mcp_get_mfw_ver(QED_LEADING_HWFN(cdev), NULL, | |
238 | &dev_info->mfw_rev, NULL); | |
cee4d264 MC |
239 | } |
240 | ||
fe56b9e6 YM |
241 | return 0; |
242 | } | |
243 | ||
244 | static void qed_free_cdev(struct qed_dev *cdev) | |
245 | { | |
246 | kfree((void *)cdev); | |
247 | } | |
248 | ||
249 | static struct qed_dev *qed_alloc_cdev(struct pci_dev *pdev) | |
250 | { | |
251 | struct qed_dev *cdev; | |
252 | ||
253 | cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); | |
254 | if (!cdev) | |
255 | return cdev; | |
256 | ||
257 | qed_init_struct(cdev); | |
258 | ||
259 | return cdev; | |
260 | } | |
261 | ||
262 | /* Sets the requested power state */ | |
1a635e48 | 263 | static int qed_set_power_state(struct qed_dev *cdev, pci_power_t state) |
fe56b9e6 YM |
264 | { |
265 | if (!cdev) | |
266 | return -ENODEV; | |
267 | ||
268 | DP_VERBOSE(cdev, NETIF_MSG_DRV, "Omitting Power state change\n"); | |
269 | return 0; | |
270 | } | |
271 | ||
272 | /* probing */ | |
273 | static struct qed_dev *qed_probe(struct pci_dev *pdev, | |
1408cc1f | 274 | struct qed_probe_params *params) |
fe56b9e6 YM |
275 | { |
276 | struct qed_dev *cdev; | |
277 | int rc; | |
278 | ||
279 | cdev = qed_alloc_cdev(pdev); | |
280 | if (!cdev) | |
281 | goto err0; | |
282 | ||
1408cc1f | 283 | cdev->protocol = params->protocol; |
fe56b9e6 | 284 | |
1408cc1f YM |
285 | if (params->is_vf) |
286 | cdev->b_is_vf = true; | |
287 | ||
288 | qed_init_dp(cdev, params->dp_module, params->dp_level); | |
fe56b9e6 YM |
289 | |
290 | rc = qed_init_pci(cdev, pdev); | |
291 | if (rc) { | |
292 | DP_ERR(cdev, "init pci failed\n"); | |
293 | goto err1; | |
294 | } | |
295 | DP_INFO(cdev, "PCI init completed successfully\n"); | |
296 | ||
297 | rc = qed_hw_prepare(cdev, QED_PCI_DEFAULT); | |
298 | if (rc) { | |
299 | DP_ERR(cdev, "hw prepare failed\n"); | |
300 | goto err2; | |
301 | } | |
302 | ||
303 | DP_INFO(cdev, "qed_probe completed successffuly\n"); | |
304 | ||
305 | return cdev; | |
306 | ||
307 | err2: | |
308 | qed_free_pci(cdev); | |
309 | err1: | |
310 | qed_free_cdev(cdev); | |
311 | err0: | |
312 | return NULL; | |
313 | } | |
314 | ||
315 | static void qed_remove(struct qed_dev *cdev) | |
316 | { | |
317 | if (!cdev) | |
318 | return; | |
319 | ||
320 | qed_hw_remove(cdev); | |
321 | ||
322 | qed_free_pci(cdev); | |
323 | ||
324 | qed_set_power_state(cdev, PCI_D3hot); | |
325 | ||
326 | qed_free_cdev(cdev); | |
327 | } | |
328 | ||
329 | static void qed_disable_msix(struct qed_dev *cdev) | |
330 | { | |
331 | if (cdev->int_params.out.int_mode == QED_INT_MODE_MSIX) { | |
332 | pci_disable_msix(cdev->pdev); | |
333 | kfree(cdev->int_params.msix_table); | |
334 | } else if (cdev->int_params.out.int_mode == QED_INT_MODE_MSI) { | |
335 | pci_disable_msi(cdev->pdev); | |
336 | } | |
337 | ||
338 | memset(&cdev->int_params.out, 0, sizeof(struct qed_int_param)); | |
339 | } | |
340 | ||
341 | static int qed_enable_msix(struct qed_dev *cdev, | |
342 | struct qed_int_params *int_params) | |
343 | { | |
344 | int i, rc, cnt; | |
345 | ||
346 | cnt = int_params->in.num_vectors; | |
347 | ||
348 | for (i = 0; i < cnt; i++) | |
349 | int_params->msix_table[i].entry = i; | |
350 | ||
351 | rc = pci_enable_msix_range(cdev->pdev, int_params->msix_table, | |
352 | int_params->in.min_msix_cnt, cnt); | |
353 | if (rc < cnt && rc >= int_params->in.min_msix_cnt && | |
354 | (rc % cdev->num_hwfns)) { | |
355 | pci_disable_msix(cdev->pdev); | |
356 | ||
357 | /* If fastpath is initialized, we need at least one interrupt | |
358 | * per hwfn [and the slow path interrupts]. New requested number | |
359 | * should be a multiple of the number of hwfns. | |
360 | */ | |
361 | cnt = (rc / cdev->num_hwfns) * cdev->num_hwfns; | |
362 | DP_NOTICE(cdev, | |
363 | "Trying to enable MSI-X with less vectors (%d out of %d)\n", | |
364 | cnt, int_params->in.num_vectors); | |
1a635e48 YM |
365 | rc = pci_enable_msix_exact(cdev->pdev, int_params->msix_table, |
366 | cnt); | |
fe56b9e6 YM |
367 | if (!rc) |
368 | rc = cnt; | |
369 | } | |
370 | ||
371 | if (rc > 0) { | |
372 | /* MSI-x configuration was achieved */ | |
373 | int_params->out.int_mode = QED_INT_MODE_MSIX; | |
374 | int_params->out.num_vectors = rc; | |
375 | rc = 0; | |
376 | } else { | |
377 | DP_NOTICE(cdev, | |
378 | "Failed to enable MSI-X [Requested %d vectors][rc %d]\n", | |
379 | cnt, rc); | |
380 | } | |
381 | ||
382 | return rc; | |
383 | } | |
384 | ||
385 | /* This function outputs the int mode and the number of enabled msix vector */ | |
386 | static int qed_set_int_mode(struct qed_dev *cdev, bool force_mode) | |
387 | { | |
388 | struct qed_int_params *int_params = &cdev->int_params; | |
389 | struct msix_entry *tbl; | |
390 | int rc = 0, cnt; | |
391 | ||
392 | switch (int_params->in.int_mode) { | |
393 | case QED_INT_MODE_MSIX: | |
394 | /* Allocate MSIX table */ | |
395 | cnt = int_params->in.num_vectors; | |
396 | int_params->msix_table = kcalloc(cnt, sizeof(*tbl), GFP_KERNEL); | |
397 | if (!int_params->msix_table) { | |
398 | rc = -ENOMEM; | |
399 | goto out; | |
400 | } | |
401 | ||
402 | /* Enable MSIX */ | |
403 | rc = qed_enable_msix(cdev, int_params); | |
404 | if (!rc) | |
405 | goto out; | |
406 | ||
407 | DP_NOTICE(cdev, "Failed to enable MSI-X\n"); | |
408 | kfree(int_params->msix_table); | |
409 | if (force_mode) | |
410 | goto out; | |
411 | /* Fallthrough */ | |
412 | ||
413 | case QED_INT_MODE_MSI: | |
bb13ace7 SRK |
414 | if (cdev->num_hwfns == 1) { |
415 | rc = pci_enable_msi(cdev->pdev); | |
416 | if (!rc) { | |
417 | int_params->out.int_mode = QED_INT_MODE_MSI; | |
418 | goto out; | |
419 | } | |
420 | ||
421 | DP_NOTICE(cdev, "Failed to enable MSI\n"); | |
422 | if (force_mode) | |
423 | goto out; | |
fe56b9e6 | 424 | } |
fe56b9e6 YM |
425 | /* Fallthrough */ |
426 | ||
427 | case QED_INT_MODE_INTA: | |
428 | int_params->out.int_mode = QED_INT_MODE_INTA; | |
429 | rc = 0; | |
430 | goto out; | |
431 | default: | |
432 | DP_NOTICE(cdev, "Unknown int_mode value %d\n", | |
433 | int_params->in.int_mode); | |
434 | rc = -EINVAL; | |
435 | } | |
436 | ||
437 | out: | |
525ef5c0 YM |
438 | if (!rc) |
439 | DP_INFO(cdev, "Using %s interrupts\n", | |
440 | int_params->out.int_mode == QED_INT_MODE_INTA ? | |
441 | "INTa" : int_params->out.int_mode == QED_INT_MODE_MSI ? | |
442 | "MSI" : "MSIX"); | |
fe56b9e6 YM |
443 | cdev->int_coalescing_mode = QED_COAL_MODE_ENABLE; |
444 | ||
445 | return rc; | |
446 | } | |
447 | ||
448 | static void qed_simd_handler_config(struct qed_dev *cdev, void *token, | |
449 | int index, void(*handler)(void *)) | |
450 | { | |
451 | struct qed_hwfn *hwfn = &cdev->hwfns[index % cdev->num_hwfns]; | |
452 | int relative_idx = index / cdev->num_hwfns; | |
453 | ||
454 | hwfn->simd_proto_handler[relative_idx].func = handler; | |
455 | hwfn->simd_proto_handler[relative_idx].token = token; | |
456 | } | |
457 | ||
458 | static void qed_simd_handler_clean(struct qed_dev *cdev, int index) | |
459 | { | |
460 | struct qed_hwfn *hwfn = &cdev->hwfns[index % cdev->num_hwfns]; | |
461 | int relative_idx = index / cdev->num_hwfns; | |
462 | ||
463 | memset(&hwfn->simd_proto_handler[relative_idx], 0, | |
464 | sizeof(struct qed_simd_fp_handler)); | |
465 | } | |
466 | ||
467 | static irqreturn_t qed_msix_sp_int(int irq, void *tasklet) | |
468 | { | |
469 | tasklet_schedule((struct tasklet_struct *)tasklet); | |
470 | return IRQ_HANDLED; | |
471 | } | |
472 | ||
473 | static irqreturn_t qed_single_int(int irq, void *dev_instance) | |
474 | { | |
475 | struct qed_dev *cdev = (struct qed_dev *)dev_instance; | |
476 | struct qed_hwfn *hwfn; | |
477 | irqreturn_t rc = IRQ_NONE; | |
478 | u64 status; | |
479 | int i, j; | |
480 | ||
481 | for (i = 0; i < cdev->num_hwfns; i++) { | |
482 | status = qed_int_igu_read_sisr_reg(&cdev->hwfns[i]); | |
483 | ||
484 | if (!status) | |
485 | continue; | |
486 | ||
487 | hwfn = &cdev->hwfns[i]; | |
488 | ||
489 | /* Slowpath interrupt */ | |
490 | if (unlikely(status & 0x1)) { | |
491 | tasklet_schedule(hwfn->sp_dpc); | |
492 | status &= ~0x1; | |
493 | rc = IRQ_HANDLED; | |
494 | } | |
495 | ||
496 | /* Fastpath interrupts */ | |
497 | for (j = 0; j < 64; j++) { | |
498 | if ((0x2ULL << j) & status) { | |
499 | hwfn->simd_proto_handler[j].func( | |
500 | hwfn->simd_proto_handler[j].token); | |
501 | status &= ~(0x2ULL << j); | |
502 | rc = IRQ_HANDLED; | |
503 | } | |
504 | } | |
505 | ||
506 | if (unlikely(status)) | |
507 | DP_VERBOSE(hwfn, NETIF_MSG_INTR, | |
508 | "got an unknown interrupt status 0x%llx\n", | |
509 | status); | |
510 | } | |
511 | ||
512 | return rc; | |
513 | } | |
514 | ||
8f16bc97 | 515 | int qed_slowpath_irq_req(struct qed_hwfn *hwfn) |
fe56b9e6 | 516 | { |
8f16bc97 | 517 | struct qed_dev *cdev = hwfn->cdev; |
525ef5c0 | 518 | u32 int_mode; |
8f16bc97 SK |
519 | int rc = 0; |
520 | u8 id; | |
fe56b9e6 | 521 | |
525ef5c0 YM |
522 | int_mode = cdev->int_params.out.int_mode; |
523 | if (int_mode == QED_INT_MODE_MSIX) { | |
8f16bc97 SK |
524 | id = hwfn->my_id; |
525 | snprintf(hwfn->name, NAME_SIZE, "sp-%d-%02x:%02x.%02x", | |
526 | id, cdev->pdev->bus->number, | |
527 | PCI_SLOT(cdev->pdev->devfn), hwfn->abs_pf_id); | |
528 | rc = request_irq(cdev->int_params.msix_table[id].vector, | |
529 | qed_msix_sp_int, 0, hwfn->name, hwfn->sp_dpc); | |
fe56b9e6 YM |
530 | } else { |
531 | unsigned long flags = 0; | |
532 | ||
533 | snprintf(cdev->name, NAME_SIZE, "%02x:%02x.%02x", | |
534 | cdev->pdev->bus->number, PCI_SLOT(cdev->pdev->devfn), | |
535 | PCI_FUNC(cdev->pdev->devfn)); | |
536 | ||
537 | if (cdev->int_params.out.int_mode == QED_INT_MODE_INTA) | |
538 | flags |= IRQF_SHARED; | |
539 | ||
540 | rc = request_irq(cdev->pdev->irq, qed_single_int, | |
541 | flags, cdev->name, cdev); | |
542 | } | |
543 | ||
525ef5c0 YM |
544 | if (rc) |
545 | DP_NOTICE(cdev, "request_irq failed, rc = %d\n", rc); | |
546 | else | |
547 | DP_VERBOSE(hwfn, (NETIF_MSG_INTR | QED_MSG_SP), | |
548 | "Requested slowpath %s\n", | |
549 | (int_mode == QED_INT_MODE_MSIX) ? "MSI-X" : "IRQ"); | |
550 | ||
fe56b9e6 YM |
551 | return rc; |
552 | } | |
553 | ||
554 | static void qed_slowpath_irq_free(struct qed_dev *cdev) | |
555 | { | |
556 | int i; | |
557 | ||
558 | if (cdev->int_params.out.int_mode == QED_INT_MODE_MSIX) { | |
559 | for_each_hwfn(cdev, i) { | |
8f16bc97 SK |
560 | if (!cdev->hwfns[i].b_int_requested) |
561 | break; | |
fe56b9e6 YM |
562 | synchronize_irq(cdev->int_params.msix_table[i].vector); |
563 | free_irq(cdev->int_params.msix_table[i].vector, | |
564 | cdev->hwfns[i].sp_dpc); | |
565 | } | |
566 | } else { | |
8f16bc97 SK |
567 | if (QED_LEADING_HWFN(cdev)->b_int_requested) |
568 | free_irq(cdev->pdev->irq, cdev); | |
fe56b9e6 | 569 | } |
8f16bc97 | 570 | qed_int_disable_post_isr_release(cdev); |
fe56b9e6 YM |
571 | } |
572 | ||
573 | static int qed_nic_stop(struct qed_dev *cdev) | |
574 | { | |
575 | int i, rc; | |
576 | ||
577 | rc = qed_hw_stop(cdev); | |
578 | ||
579 | for (i = 0; i < cdev->num_hwfns; i++) { | |
580 | struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; | |
581 | ||
582 | if (p_hwfn->b_sp_dpc_enabled) { | |
583 | tasklet_disable(p_hwfn->sp_dpc); | |
584 | p_hwfn->b_sp_dpc_enabled = false; | |
585 | DP_VERBOSE(cdev, NETIF_MSG_IFDOWN, | |
586 | "Disabled sp taskelt [hwfn %d] at %p\n", | |
587 | i, p_hwfn->sp_dpc); | |
588 | } | |
589 | } | |
590 | ||
c965db44 TT |
591 | qed_dbg_pf_exit(cdev); |
592 | ||
fe56b9e6 YM |
593 | return rc; |
594 | } | |
595 | ||
596 | static int qed_nic_reset(struct qed_dev *cdev) | |
597 | { | |
598 | int rc; | |
599 | ||
600 | rc = qed_hw_reset(cdev); | |
601 | if (rc) | |
602 | return rc; | |
603 | ||
604 | qed_resc_free(cdev); | |
605 | ||
606 | return 0; | |
607 | } | |
608 | ||
609 | static int qed_nic_setup(struct qed_dev *cdev) | |
610 | { | |
611 | int rc; | |
612 | ||
613 | rc = qed_resc_alloc(cdev); | |
614 | if (rc) | |
615 | return rc; | |
616 | ||
617 | DP_INFO(cdev, "Allocated qed resources\n"); | |
618 | ||
619 | qed_resc_setup(cdev); | |
620 | ||
621 | return rc; | |
622 | } | |
623 | ||
624 | static int qed_set_int_fp(struct qed_dev *cdev, u16 cnt) | |
625 | { | |
626 | int limit = 0; | |
627 | ||
628 | /* Mark the fastpath as free/used */ | |
629 | cdev->int_params.fp_initialized = cnt ? true : false; | |
630 | ||
631 | if (cdev->int_params.out.int_mode != QED_INT_MODE_MSIX) | |
632 | limit = cdev->num_hwfns * 63; | |
633 | else if (cdev->int_params.fp_msix_cnt) | |
634 | limit = cdev->int_params.fp_msix_cnt; | |
635 | ||
636 | if (!limit) | |
637 | return -ENOMEM; | |
638 | ||
639 | return min_t(int, cnt, limit); | |
640 | } | |
641 | ||
642 | static int qed_get_int_fp(struct qed_dev *cdev, struct qed_int_info *info) | |
643 | { | |
644 | memset(info, 0, sizeof(struct qed_int_info)); | |
645 | ||
646 | if (!cdev->int_params.fp_initialized) { | |
647 | DP_INFO(cdev, | |
648 | "Protocol driver requested interrupt information, but its support is not yet configured\n"); | |
649 | return -EINVAL; | |
650 | } | |
651 | ||
652 | /* Need to expose only MSI-X information; Single IRQ is handled solely | |
653 | * by qed. | |
654 | */ | |
655 | if (cdev->int_params.out.int_mode == QED_INT_MODE_MSIX) { | |
656 | int msix_base = cdev->int_params.fp_msix_base; | |
657 | ||
658 | info->msix_cnt = cdev->int_params.fp_msix_cnt; | |
659 | info->msix = &cdev->int_params.msix_table[msix_base]; | |
660 | } | |
661 | ||
662 | return 0; | |
663 | } | |
664 | ||
665 | static int qed_slowpath_setup_int(struct qed_dev *cdev, | |
666 | enum qed_int_mode int_mode) | |
667 | { | |
4ac801b7 YM |
668 | struct qed_sb_cnt_info sb_cnt_info; |
669 | int rc; | |
670 | int i; | |
fe56b9e6 | 671 | |
1d2c2024 SRK |
672 | if ((int_mode == QED_INT_MODE_MSI) && (cdev->num_hwfns > 1)) { |
673 | DP_NOTICE(cdev, "MSI mode is not supported for CMT devices\n"); | |
674 | return -EINVAL; | |
675 | } | |
676 | ||
677 | memset(&cdev->int_params, 0, sizeof(struct qed_int_params)); | |
fe56b9e6 | 678 | cdev->int_params.in.int_mode = int_mode; |
4ac801b7 YM |
679 | for_each_hwfn(cdev, i) { |
680 | memset(&sb_cnt_info, 0, sizeof(sb_cnt_info)); | |
681 | qed_int_get_num_sbs(&cdev->hwfns[i], &sb_cnt_info); | |
682 | cdev->int_params.in.num_vectors += sb_cnt_info.sb_cnt; | |
683 | cdev->int_params.in.num_vectors++; /* slowpath */ | |
684 | } | |
fe56b9e6 YM |
685 | |
686 | /* We want a minimum of one slowpath and one fastpath vector per hwfn */ | |
687 | cdev->int_params.in.min_msix_cnt = cdev->num_hwfns * 2; | |
688 | ||
689 | rc = qed_set_int_mode(cdev, false); | |
690 | if (rc) { | |
691 | DP_ERR(cdev, "qed_slowpath_setup_int ERR\n"); | |
692 | return rc; | |
693 | } | |
694 | ||
695 | cdev->int_params.fp_msix_base = cdev->num_hwfns; | |
696 | cdev->int_params.fp_msix_cnt = cdev->int_params.out.num_vectors - | |
697 | cdev->num_hwfns; | |
698 | ||
699 | return 0; | |
700 | } | |
701 | ||
1408cc1f YM |
702 | static int qed_slowpath_vf_setup_int(struct qed_dev *cdev) |
703 | { | |
704 | int rc; | |
705 | ||
706 | memset(&cdev->int_params, 0, sizeof(struct qed_int_params)); | |
707 | cdev->int_params.in.int_mode = QED_INT_MODE_MSIX; | |
708 | ||
709 | qed_vf_get_num_rxqs(QED_LEADING_HWFN(cdev), | |
710 | &cdev->int_params.in.num_vectors); | |
711 | if (cdev->num_hwfns > 1) { | |
712 | u8 vectors = 0; | |
713 | ||
714 | qed_vf_get_num_rxqs(&cdev->hwfns[1], &vectors); | |
715 | cdev->int_params.in.num_vectors += vectors; | |
716 | } | |
717 | ||
718 | /* We want a minimum of one fastpath vector per vf hwfn */ | |
719 | cdev->int_params.in.min_msix_cnt = cdev->num_hwfns; | |
720 | ||
721 | rc = qed_set_int_mode(cdev, true); | |
722 | if (rc) | |
723 | return rc; | |
724 | ||
725 | cdev->int_params.fp_msix_base = 0; | |
726 | cdev->int_params.fp_msix_cnt = cdev->int_params.out.num_vectors; | |
727 | ||
728 | return 0; | |
729 | } | |
730 | ||
fe56b9e6 YM |
731 | u32 qed_unzip_data(struct qed_hwfn *p_hwfn, u32 input_len, |
732 | u8 *input_buf, u32 max_size, u8 *unzip_buf) | |
733 | { | |
734 | int rc; | |
735 | ||
736 | p_hwfn->stream->next_in = input_buf; | |
737 | p_hwfn->stream->avail_in = input_len; | |
738 | p_hwfn->stream->next_out = unzip_buf; | |
739 | p_hwfn->stream->avail_out = max_size; | |
740 | ||
741 | rc = zlib_inflateInit2(p_hwfn->stream, MAX_WBITS); | |
742 | ||
743 | if (rc != Z_OK) { | |
744 | DP_VERBOSE(p_hwfn, NETIF_MSG_DRV, "zlib init failed, rc = %d\n", | |
745 | rc); | |
746 | return 0; | |
747 | } | |
748 | ||
749 | rc = zlib_inflate(p_hwfn->stream, Z_FINISH); | |
750 | zlib_inflateEnd(p_hwfn->stream); | |
751 | ||
752 | if (rc != Z_OK && rc != Z_STREAM_END) { | |
753 | DP_VERBOSE(p_hwfn, NETIF_MSG_DRV, "FW unzip error: %s, rc=%d\n", | |
754 | p_hwfn->stream->msg, rc); | |
755 | return 0; | |
756 | } | |
757 | ||
758 | return p_hwfn->stream->total_out / 4; | |
759 | } | |
760 | ||
761 | static int qed_alloc_stream_mem(struct qed_dev *cdev) | |
762 | { | |
763 | int i; | |
764 | void *workspace; | |
765 | ||
766 | for_each_hwfn(cdev, i) { | |
767 | struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; | |
768 | ||
769 | p_hwfn->stream = kzalloc(sizeof(*p_hwfn->stream), GFP_KERNEL); | |
770 | if (!p_hwfn->stream) | |
771 | return -ENOMEM; | |
772 | ||
773 | workspace = vzalloc(zlib_inflate_workspacesize()); | |
774 | if (!workspace) | |
775 | return -ENOMEM; | |
776 | p_hwfn->stream->workspace = workspace; | |
777 | } | |
778 | ||
779 | return 0; | |
780 | } | |
781 | ||
782 | static void qed_free_stream_mem(struct qed_dev *cdev) | |
783 | { | |
784 | int i; | |
785 | ||
786 | for_each_hwfn(cdev, i) { | |
787 | struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; | |
788 | ||
789 | if (!p_hwfn->stream) | |
790 | return; | |
791 | ||
792 | vfree(p_hwfn->stream->workspace); | |
793 | kfree(p_hwfn->stream); | |
794 | } | |
795 | } | |
796 | ||
797 | static void qed_update_pf_params(struct qed_dev *cdev, | |
798 | struct qed_pf_params *params) | |
799 | { | |
800 | int i; | |
801 | ||
802 | for (i = 0; i < cdev->num_hwfns; i++) { | |
803 | struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; | |
804 | ||
805 | p_hwfn->pf_params = *params; | |
806 | } | |
807 | } | |
808 | ||
809 | static int qed_slowpath_start(struct qed_dev *cdev, | |
810 | struct qed_slowpath_params *params) | |
811 | { | |
b18e170c | 812 | struct qed_tunn_start_params tunn_info; |
fe56b9e6 YM |
813 | struct qed_mcp_drv_version drv_version; |
814 | const u8 *data = NULL; | |
815 | struct qed_hwfn *hwfn; | |
37bff2b9 YM |
816 | int rc = -EINVAL; |
817 | ||
818 | if (qed_iov_wq_start(cdev)) | |
819 | goto err; | |
fe56b9e6 | 820 | |
1408cc1f YM |
821 | if (IS_PF(cdev)) { |
822 | rc = request_firmware(&cdev->firmware, QED_FW_FILE_NAME, | |
823 | &cdev->pdev->dev); | |
824 | if (rc) { | |
825 | DP_NOTICE(cdev, | |
826 | "Failed to find fw file - /lib/firmware/%s\n", | |
827 | QED_FW_FILE_NAME); | |
828 | goto err; | |
829 | } | |
fe56b9e6 YM |
830 | } |
831 | ||
832 | rc = qed_nic_setup(cdev); | |
833 | if (rc) | |
834 | goto err; | |
835 | ||
1408cc1f YM |
836 | if (IS_PF(cdev)) |
837 | rc = qed_slowpath_setup_int(cdev, params->int_mode); | |
838 | else | |
839 | rc = qed_slowpath_vf_setup_int(cdev); | |
fe56b9e6 YM |
840 | if (rc) |
841 | goto err1; | |
842 | ||
1408cc1f YM |
843 | if (IS_PF(cdev)) { |
844 | /* Allocate stream for unzipping */ | |
845 | rc = qed_alloc_stream_mem(cdev); | |
2591c280 | 846 | if (rc) |
1408cc1f | 847 | goto err2; |
fe56b9e6 | 848 | |
351a4ded YM |
849 | /* First Dword used to diffrentiate between various sources */ |
850 | data = cdev->firmware->data + sizeof(u32); | |
c965db44 TT |
851 | |
852 | qed_dbg_pf_init(cdev); | |
1408cc1f | 853 | } |
fe56b9e6 | 854 | |
b18e170c | 855 | memset(&tunn_info, 0, sizeof(tunn_info)); |
9a109dd0 | 856 | tunn_info.tunn_mode |= 1 << QED_MODE_VXLAN_TUNN | |
f7985869 MC |
857 | 1 << QED_MODE_L2GRE_TUNN | |
858 | 1 << QED_MODE_IPGRE_TUNN | | |
9a109dd0 MC |
859 | 1 << QED_MODE_L2GENEVE_TUNN | |
860 | 1 << QED_MODE_IPGENEVE_TUNN; | |
861 | ||
b18e170c | 862 | tunn_info.tunn_clss_vxlan = QED_TUNN_CLSS_MAC_VLAN; |
f7985869 MC |
863 | tunn_info.tunn_clss_l2gre = QED_TUNN_CLSS_MAC_VLAN; |
864 | tunn_info.tunn_clss_ipgre = QED_TUNN_CLSS_MAC_VLAN; | |
b18e170c | 865 | |
1408cc1f | 866 | /* Start the slowpath */ |
b18e170c MC |
867 | rc = qed_hw_init(cdev, &tunn_info, true, |
868 | cdev->int_params.out.int_mode, | |
fe56b9e6 YM |
869 | true, data); |
870 | if (rc) | |
8c925c44 | 871 | goto err2; |
fe56b9e6 YM |
872 | |
873 | DP_INFO(cdev, | |
874 | "HW initialization and function start completed successfully\n"); | |
875 | ||
1408cc1f YM |
876 | if (IS_PF(cdev)) { |
877 | hwfn = QED_LEADING_HWFN(cdev); | |
878 | drv_version.version = (params->drv_major << 24) | | |
879 | (params->drv_minor << 16) | | |
880 | (params->drv_rev << 8) | | |
881 | (params->drv_eng); | |
882 | strlcpy(drv_version.name, params->name, | |
883 | MCP_DRV_VER_STR_SIZE - 4); | |
884 | rc = qed_mcp_send_drv_version(hwfn, hwfn->p_main_ptt, | |
885 | &drv_version); | |
886 | if (rc) { | |
887 | DP_NOTICE(cdev, "Failed sending drv version command\n"); | |
888 | return rc; | |
889 | } | |
fe56b9e6 YM |
890 | } |
891 | ||
8c925c44 YM |
892 | qed_reset_vport_stats(cdev); |
893 | ||
fe56b9e6 YM |
894 | return 0; |
895 | ||
fe56b9e6 | 896 | err2: |
8c925c44 | 897 | qed_hw_timers_stop_all(cdev); |
1408cc1f YM |
898 | if (IS_PF(cdev)) |
899 | qed_slowpath_irq_free(cdev); | |
8c925c44 | 900 | qed_free_stream_mem(cdev); |
fe56b9e6 YM |
901 | qed_disable_msix(cdev); |
902 | err1: | |
903 | qed_resc_free(cdev); | |
904 | err: | |
1408cc1f YM |
905 | if (IS_PF(cdev)) |
906 | release_firmware(cdev->firmware); | |
fe56b9e6 | 907 | |
37bff2b9 YM |
908 | qed_iov_wq_stop(cdev, false); |
909 | ||
fe56b9e6 YM |
910 | return rc; |
911 | } | |
912 | ||
913 | static int qed_slowpath_stop(struct qed_dev *cdev) | |
914 | { | |
915 | if (!cdev) | |
916 | return -ENODEV; | |
917 | ||
1408cc1f YM |
918 | if (IS_PF(cdev)) { |
919 | qed_free_stream_mem(cdev); | |
c5ac9319 YM |
920 | if (IS_QED_ETH_IF(cdev)) |
921 | qed_sriov_disable(cdev, true); | |
fe56b9e6 | 922 | |
1408cc1f YM |
923 | qed_nic_stop(cdev); |
924 | qed_slowpath_irq_free(cdev); | |
925 | } | |
fe56b9e6 YM |
926 | |
927 | qed_disable_msix(cdev); | |
928 | qed_nic_reset(cdev); | |
929 | ||
37bff2b9 YM |
930 | qed_iov_wq_stop(cdev, true); |
931 | ||
1408cc1f YM |
932 | if (IS_PF(cdev)) |
933 | release_firmware(cdev->firmware); | |
fe56b9e6 YM |
934 | |
935 | return 0; | |
936 | } | |
937 | ||
938 | static void qed_set_id(struct qed_dev *cdev, char name[NAME_SIZE], | |
939 | char ver_str[VER_SIZE]) | |
940 | { | |
941 | int i; | |
942 | ||
943 | memcpy(cdev->name, name, NAME_SIZE); | |
944 | for_each_hwfn(cdev, i) | |
945 | snprintf(cdev->hwfns[i].name, NAME_SIZE, "%s-%d", name, i); | |
946 | ||
947 | memcpy(cdev->ver_str, ver_str, VER_SIZE); | |
948 | cdev->drv_type = DRV_ID_DRV_TYPE_LINUX; | |
949 | } | |
950 | ||
951 | static u32 qed_sb_init(struct qed_dev *cdev, | |
952 | struct qed_sb_info *sb_info, | |
953 | void *sb_virt_addr, | |
954 | dma_addr_t sb_phy_addr, u16 sb_id, | |
955 | enum qed_sb_type type) | |
956 | { | |
957 | struct qed_hwfn *p_hwfn; | |
958 | int hwfn_index; | |
959 | u16 rel_sb_id; | |
960 | u8 n_hwfns; | |
961 | u32 rc; | |
962 | ||
963 | /* RoCE uses single engine and CMT uses two engines. When using both | |
964 | * we force only a single engine. Storage uses only engine 0 too. | |
965 | */ | |
966 | if (type == QED_SB_TYPE_L2_QUEUE) | |
967 | n_hwfns = cdev->num_hwfns; | |
968 | else | |
969 | n_hwfns = 1; | |
970 | ||
971 | hwfn_index = sb_id % n_hwfns; | |
972 | p_hwfn = &cdev->hwfns[hwfn_index]; | |
973 | rel_sb_id = sb_id / n_hwfns; | |
974 | ||
975 | DP_VERBOSE(cdev, NETIF_MSG_INTR, | |
976 | "hwfn [%d] <--[init]-- SB %04x [0x%04x upper]\n", | |
977 | hwfn_index, rel_sb_id, sb_id); | |
978 | ||
979 | rc = qed_int_sb_init(p_hwfn, p_hwfn->p_main_ptt, sb_info, | |
980 | sb_virt_addr, sb_phy_addr, rel_sb_id); | |
981 | ||
982 | return rc; | |
983 | } | |
984 | ||
985 | static u32 qed_sb_release(struct qed_dev *cdev, | |
1a635e48 | 986 | struct qed_sb_info *sb_info, u16 sb_id) |
fe56b9e6 YM |
987 | { |
988 | struct qed_hwfn *p_hwfn; | |
989 | int hwfn_index; | |
990 | u16 rel_sb_id; | |
991 | u32 rc; | |
992 | ||
993 | hwfn_index = sb_id % cdev->num_hwfns; | |
994 | p_hwfn = &cdev->hwfns[hwfn_index]; | |
995 | rel_sb_id = sb_id / cdev->num_hwfns; | |
996 | ||
997 | DP_VERBOSE(cdev, NETIF_MSG_INTR, | |
998 | "hwfn [%d] <--[init]-- SB %04x [0x%04x upper]\n", | |
999 | hwfn_index, rel_sb_id, sb_id); | |
1000 | ||
1001 | rc = qed_int_sb_release(p_hwfn, sb_info, rel_sb_id); | |
1002 | ||
1003 | return rc; | |
1004 | } | |
1005 | ||
fe7cd2bf YM |
1006 | static bool qed_can_link_change(struct qed_dev *cdev) |
1007 | { | |
1008 | return true; | |
1009 | } | |
1010 | ||
351a4ded | 1011 | static int qed_set_link(struct qed_dev *cdev, struct qed_link_params *params) |
cc875c2e YM |
1012 | { |
1013 | struct qed_hwfn *hwfn; | |
1014 | struct qed_mcp_link_params *link_params; | |
1015 | struct qed_ptt *ptt; | |
1016 | int rc; | |
1017 | ||
1018 | if (!cdev) | |
1019 | return -ENODEV; | |
1020 | ||
1408cc1f YM |
1021 | if (IS_VF(cdev)) |
1022 | return 0; | |
1023 | ||
cc875c2e YM |
1024 | /* The link should be set only once per PF */ |
1025 | hwfn = &cdev->hwfns[0]; | |
1026 | ||
1027 | ptt = qed_ptt_acquire(hwfn); | |
1028 | if (!ptt) | |
1029 | return -EBUSY; | |
1030 | ||
1031 | link_params = qed_mcp_get_link_params(hwfn); | |
1032 | if (params->override_flags & QED_LINK_OVERRIDE_SPEED_AUTONEG) | |
1033 | link_params->speed.autoneg = params->autoneg; | |
1034 | if (params->override_flags & QED_LINK_OVERRIDE_SPEED_ADV_SPEEDS) { | |
1035 | link_params->speed.advertised_speeds = 0; | |
054c67d1 SRK |
1036 | if ((params->adv_speeds & QED_LM_1000baseT_Half_BIT) || |
1037 | (params->adv_speeds & QED_LM_1000baseT_Full_BIT)) | |
cc875c2e | 1038 | link_params->speed.advertised_speeds |= |
054c67d1 SRK |
1039 | NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G; |
1040 | if (params->adv_speeds & QED_LM_10000baseKR_Full_BIT) | |
cc875c2e | 1041 | link_params->speed.advertised_speeds |= |
054c67d1 SRK |
1042 | NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G; |
1043 | if (params->adv_speeds & QED_LM_25000baseKR_Full_BIT) | |
cc875c2e | 1044 | link_params->speed.advertised_speeds |= |
054c67d1 SRK |
1045 | NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G; |
1046 | if (params->adv_speeds & QED_LM_40000baseLR4_Full_BIT) | |
cc875c2e | 1047 | link_params->speed.advertised_speeds |= |
054c67d1 SRK |
1048 | NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G; |
1049 | if (params->adv_speeds & QED_LM_50000baseKR2_Full_BIT) | |
1050 | link_params->speed.advertised_speeds |= | |
1051 | NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G; | |
1052 | if (params->adv_speeds & QED_LM_100000baseKR4_Full_BIT) | |
cc875c2e | 1053 | link_params->speed.advertised_speeds |= |
351a4ded | 1054 | NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G; |
cc875c2e YM |
1055 | } |
1056 | if (params->override_flags & QED_LINK_OVERRIDE_SPEED_FORCED_SPEED) | |
1057 | link_params->speed.forced_speed = params->forced_speed; | |
a43f235f SRK |
1058 | if (params->override_flags & QED_LINK_OVERRIDE_PAUSE_CONFIG) { |
1059 | if (params->pause_config & QED_LINK_PAUSE_AUTONEG_ENABLE) | |
1060 | link_params->pause.autoneg = true; | |
1061 | else | |
1062 | link_params->pause.autoneg = false; | |
1063 | if (params->pause_config & QED_LINK_PAUSE_RX_ENABLE) | |
1064 | link_params->pause.forced_rx = true; | |
1065 | else | |
1066 | link_params->pause.forced_rx = false; | |
1067 | if (params->pause_config & QED_LINK_PAUSE_TX_ENABLE) | |
1068 | link_params->pause.forced_tx = true; | |
1069 | else | |
1070 | link_params->pause.forced_tx = false; | |
1071 | } | |
03dc76ca SRK |
1072 | if (params->override_flags & QED_LINK_OVERRIDE_LOOPBACK_MODE) { |
1073 | switch (params->loopback_mode) { | |
1074 | case QED_LINK_LOOPBACK_INT_PHY: | |
351a4ded | 1075 | link_params->loopback_mode = ETH_LOOPBACK_INT_PHY; |
03dc76ca SRK |
1076 | break; |
1077 | case QED_LINK_LOOPBACK_EXT_PHY: | |
351a4ded | 1078 | link_params->loopback_mode = ETH_LOOPBACK_EXT_PHY; |
03dc76ca SRK |
1079 | break; |
1080 | case QED_LINK_LOOPBACK_EXT: | |
351a4ded | 1081 | link_params->loopback_mode = ETH_LOOPBACK_EXT; |
03dc76ca SRK |
1082 | break; |
1083 | case QED_LINK_LOOPBACK_MAC: | |
351a4ded | 1084 | link_params->loopback_mode = ETH_LOOPBACK_MAC; |
03dc76ca SRK |
1085 | break; |
1086 | default: | |
351a4ded | 1087 | link_params->loopback_mode = ETH_LOOPBACK_NONE; |
03dc76ca SRK |
1088 | break; |
1089 | } | |
1090 | } | |
cc875c2e YM |
1091 | |
1092 | rc = qed_mcp_set_link(hwfn, ptt, params->link_up); | |
1093 | ||
1094 | qed_ptt_release(hwfn, ptt); | |
1095 | ||
1096 | return rc; | |
1097 | } | |
1098 | ||
1099 | static int qed_get_port_type(u32 media_type) | |
1100 | { | |
1101 | int port_type; | |
1102 | ||
1103 | switch (media_type) { | |
1104 | case MEDIA_SFPP_10G_FIBER: | |
1105 | case MEDIA_SFP_1G_FIBER: | |
1106 | case MEDIA_XFP_FIBER: | |
b639f197 | 1107 | case MEDIA_MODULE_FIBER: |
cc875c2e YM |
1108 | case MEDIA_KR: |
1109 | port_type = PORT_FIBRE; | |
1110 | break; | |
1111 | case MEDIA_DA_TWINAX: | |
1112 | port_type = PORT_DA; | |
1113 | break; | |
1114 | case MEDIA_BASE_T: | |
1115 | port_type = PORT_TP; | |
1116 | break; | |
1117 | case MEDIA_NOT_PRESENT: | |
1118 | port_type = PORT_NONE; | |
1119 | break; | |
1120 | case MEDIA_UNSPECIFIED: | |
1121 | default: | |
1122 | port_type = PORT_OTHER; | |
1123 | break; | |
1124 | } | |
1125 | return port_type; | |
1126 | } | |
1127 | ||
14b84e86 AB |
1128 | static int qed_get_link_data(struct qed_hwfn *hwfn, |
1129 | struct qed_mcp_link_params *params, | |
1130 | struct qed_mcp_link_state *link, | |
1131 | struct qed_mcp_link_capabilities *link_caps) | |
1132 | { | |
1133 | void *p; | |
1134 | ||
1135 | if (!IS_PF(hwfn->cdev)) { | |
1136 | qed_vf_get_link_params(hwfn, params); | |
1137 | qed_vf_get_link_state(hwfn, link); | |
1138 | qed_vf_get_link_caps(hwfn, link_caps); | |
1139 | ||
1140 | return 0; | |
1141 | } | |
1142 | ||
1143 | p = qed_mcp_get_link_params(hwfn); | |
1144 | if (!p) | |
1145 | return -ENXIO; | |
1146 | memcpy(params, p, sizeof(*params)); | |
1147 | ||
1148 | p = qed_mcp_get_link_state(hwfn); | |
1149 | if (!p) | |
1150 | return -ENXIO; | |
1151 | memcpy(link, p, sizeof(*link)); | |
1152 | ||
1153 | p = qed_mcp_get_link_capabilities(hwfn); | |
1154 | if (!p) | |
1155 | return -ENXIO; | |
1156 | memcpy(link_caps, p, sizeof(*link_caps)); | |
1157 | ||
1158 | return 0; | |
1159 | } | |
1160 | ||
cc875c2e YM |
1161 | static void qed_fill_link(struct qed_hwfn *hwfn, |
1162 | struct qed_link_output *if_link) | |
1163 | { | |
1164 | struct qed_mcp_link_params params; | |
1165 | struct qed_mcp_link_state link; | |
1166 | struct qed_mcp_link_capabilities link_caps; | |
1167 | u32 media_type; | |
1168 | ||
1169 | memset(if_link, 0, sizeof(*if_link)); | |
1170 | ||
1171 | /* Prepare source inputs */ | |
14b84e86 AB |
1172 | if (qed_get_link_data(hwfn, ¶ms, &link, &link_caps)) { |
1173 | dev_warn(&hwfn->cdev->pdev->dev, "no link data available\n"); | |
1174 | return; | |
1408cc1f | 1175 | } |
cc875c2e YM |
1176 | |
1177 | /* Set the link parameters to pass to protocol driver */ | |
1178 | if (link.link_up) | |
1179 | if_link->link_up = true; | |
1180 | ||
1181 | /* TODO - at the moment assume supported and advertised speed equal */ | |
054c67d1 | 1182 | if_link->supported_caps = QED_LM_FIBRE_BIT; |
cc875c2e | 1183 | if (params.speed.autoneg) |
054c67d1 | 1184 | if_link->supported_caps |= QED_LM_Autoneg_BIT; |
cc875c2e YM |
1185 | if (params.pause.autoneg || |
1186 | (params.pause.forced_rx && params.pause.forced_tx)) | |
054c67d1 | 1187 | if_link->supported_caps |= QED_LM_Asym_Pause_BIT; |
cc875c2e YM |
1188 | if (params.pause.autoneg || params.pause.forced_rx || |
1189 | params.pause.forced_tx) | |
054c67d1 | 1190 | if_link->supported_caps |= QED_LM_Pause_BIT; |
cc875c2e YM |
1191 | |
1192 | if_link->advertised_caps = if_link->supported_caps; | |
1193 | if (params.speed.advertised_speeds & | |
1194 | NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G) | |
054c67d1 SRK |
1195 | if_link->advertised_caps |= QED_LM_1000baseT_Half_BIT | |
1196 | QED_LM_1000baseT_Full_BIT; | |
cc875c2e YM |
1197 | if (params.speed.advertised_speeds & |
1198 | NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G) | |
054c67d1 SRK |
1199 | if_link->advertised_caps |= QED_LM_10000baseKR_Full_BIT; |
1200 | if (params.speed.advertised_speeds & | |
1201 | NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G) | |
1202 | if_link->advertised_caps |= QED_LM_25000baseKR_Full_BIT; | |
cc875c2e | 1203 | if (params.speed.advertised_speeds & |
054c67d1 SRK |
1204 | NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G) |
1205 | if_link->advertised_caps |= QED_LM_40000baseLR4_Full_BIT; | |
cc875c2e | 1206 | if (params.speed.advertised_speeds & |
054c67d1 SRK |
1207 | NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G) |
1208 | if_link->advertised_caps |= QED_LM_50000baseKR2_Full_BIT; | |
cc875c2e | 1209 | if (params.speed.advertised_speeds & |
351a4ded | 1210 | NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G) |
054c67d1 | 1211 | if_link->advertised_caps |= QED_LM_100000baseKR4_Full_BIT; |
cc875c2e YM |
1212 | |
1213 | if (link_caps.speed_capabilities & | |
1214 | NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G) | |
054c67d1 SRK |
1215 | if_link->supported_caps |= QED_LM_1000baseT_Half_BIT | |
1216 | QED_LM_1000baseT_Full_BIT; | |
cc875c2e YM |
1217 | if (link_caps.speed_capabilities & |
1218 | NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G) | |
054c67d1 SRK |
1219 | if_link->supported_caps |= QED_LM_10000baseKR_Full_BIT; |
1220 | if (link_caps.speed_capabilities & | |
1221 | NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G) | |
1222 | if_link->supported_caps |= QED_LM_25000baseKR_Full_BIT; | |
cc875c2e | 1223 | if (link_caps.speed_capabilities & |
054c67d1 SRK |
1224 | NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G) |
1225 | if_link->supported_caps |= QED_LM_40000baseLR4_Full_BIT; | |
cc875c2e | 1226 | if (link_caps.speed_capabilities & |
054c67d1 SRK |
1227 | NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G) |
1228 | if_link->supported_caps |= QED_LM_50000baseKR2_Full_BIT; | |
cc875c2e | 1229 | if (link_caps.speed_capabilities & |
351a4ded | 1230 | NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G) |
054c67d1 | 1231 | if_link->supported_caps |= QED_LM_100000baseKR4_Full_BIT; |
cc875c2e YM |
1232 | |
1233 | if (link.link_up) | |
1234 | if_link->speed = link.speed; | |
1235 | ||
1236 | /* TODO - fill duplex properly */ | |
1237 | if_link->duplex = DUPLEX_FULL; | |
1238 | qed_mcp_get_media_type(hwfn->cdev, &media_type); | |
1239 | if_link->port = qed_get_port_type(media_type); | |
1240 | ||
1241 | if_link->autoneg = params.speed.autoneg; | |
1242 | ||
1243 | if (params.pause.autoneg) | |
1244 | if_link->pause_config |= QED_LINK_PAUSE_AUTONEG_ENABLE; | |
1245 | if (params.pause.forced_rx) | |
1246 | if_link->pause_config |= QED_LINK_PAUSE_RX_ENABLE; | |
1247 | if (params.pause.forced_tx) | |
1248 | if_link->pause_config |= QED_LINK_PAUSE_TX_ENABLE; | |
1249 | ||
1250 | /* Link partner capabilities */ | |
054c67d1 SRK |
1251 | if (link.partner_adv_speed & QED_LINK_PARTNER_SPEED_1G_HD) |
1252 | if_link->lp_caps |= QED_LM_1000baseT_Half_BIT; | |
1253 | if (link.partner_adv_speed & QED_LINK_PARTNER_SPEED_1G_FD) | |
1254 | if_link->lp_caps |= QED_LM_1000baseT_Full_BIT; | |
1255 | if (link.partner_adv_speed & QED_LINK_PARTNER_SPEED_10G) | |
1256 | if_link->lp_caps |= QED_LM_10000baseKR_Full_BIT; | |
1257 | if (link.partner_adv_speed & QED_LINK_PARTNER_SPEED_25G) | |
1258 | if_link->lp_caps |= QED_LM_25000baseKR_Full_BIT; | |
1259 | if (link.partner_adv_speed & QED_LINK_PARTNER_SPEED_40G) | |
1260 | if_link->lp_caps |= QED_LM_40000baseLR4_Full_BIT; | |
1261 | if (link.partner_adv_speed & QED_LINK_PARTNER_SPEED_50G) | |
1262 | if_link->lp_caps |= QED_LM_50000baseKR2_Full_BIT; | |
1263 | if (link.partner_adv_speed & QED_LINK_PARTNER_SPEED_100G) | |
1264 | if_link->lp_caps |= QED_LM_100000baseKR4_Full_BIT; | |
cc875c2e YM |
1265 | |
1266 | if (link.an_complete) | |
054c67d1 | 1267 | if_link->lp_caps |= QED_LM_Autoneg_BIT; |
cc875c2e YM |
1268 | |
1269 | if (link.partner_adv_pause) | |
054c67d1 | 1270 | if_link->lp_caps |= QED_LM_Pause_BIT; |
cc875c2e YM |
1271 | if (link.partner_adv_pause == QED_LINK_PARTNER_ASYMMETRIC_PAUSE || |
1272 | link.partner_adv_pause == QED_LINK_PARTNER_BOTH_PAUSE) | |
054c67d1 | 1273 | if_link->lp_caps |= QED_LM_Asym_Pause_BIT; |
cc875c2e YM |
1274 | } |
1275 | ||
1276 | static void qed_get_current_link(struct qed_dev *cdev, | |
1277 | struct qed_link_output *if_link) | |
1278 | { | |
36558c3d YM |
1279 | int i; |
1280 | ||
cc875c2e | 1281 | qed_fill_link(&cdev->hwfns[0], if_link); |
36558c3d YM |
1282 | |
1283 | for_each_hwfn(cdev, i) | |
1284 | qed_inform_vf_link_state(&cdev->hwfns[i]); | |
cc875c2e YM |
1285 | } |
1286 | ||
1287 | void qed_link_update(struct qed_hwfn *hwfn) | |
1288 | { | |
1289 | void *cookie = hwfn->cdev->ops_cookie; | |
1290 | struct qed_common_cb_ops *op = hwfn->cdev->protocol_ops.common; | |
1291 | struct qed_link_output if_link; | |
1292 | ||
1293 | qed_fill_link(hwfn, &if_link); | |
36558c3d | 1294 | qed_inform_vf_link_state(hwfn); |
cc875c2e YM |
1295 | |
1296 | if (IS_LEAD_HWFN(hwfn) && cookie) | |
1297 | op->link_update(cookie, &if_link); | |
1298 | } | |
1299 | ||
fe56b9e6 YM |
1300 | static int qed_drain(struct qed_dev *cdev) |
1301 | { | |
1302 | struct qed_hwfn *hwfn; | |
1303 | struct qed_ptt *ptt; | |
1304 | int i, rc; | |
1305 | ||
1408cc1f YM |
1306 | if (IS_VF(cdev)) |
1307 | return 0; | |
1308 | ||
fe56b9e6 YM |
1309 | for_each_hwfn(cdev, i) { |
1310 | hwfn = &cdev->hwfns[i]; | |
1311 | ptt = qed_ptt_acquire(hwfn); | |
1312 | if (!ptt) { | |
1313 | DP_NOTICE(hwfn, "Failed to drain NIG; No PTT\n"); | |
1314 | return -EBUSY; | |
1315 | } | |
1316 | rc = qed_mcp_drain(hwfn, ptt); | |
1317 | if (rc) | |
1318 | return rc; | |
1319 | qed_ptt_release(hwfn, ptt); | |
1320 | } | |
1321 | ||
1322 | return 0; | |
1323 | } | |
1324 | ||
722003ac SRK |
1325 | static void qed_get_coalesce(struct qed_dev *cdev, u16 *rx_coal, u16 *tx_coal) |
1326 | { | |
1327 | *rx_coal = cdev->rx_coalesce_usecs; | |
1328 | *tx_coal = cdev->tx_coalesce_usecs; | |
1329 | } | |
1330 | ||
1331 | static int qed_set_coalesce(struct qed_dev *cdev, u16 rx_coal, u16 tx_coal, | |
1332 | u8 qid, u16 sb_id) | |
1333 | { | |
1334 | struct qed_hwfn *hwfn; | |
1335 | struct qed_ptt *ptt; | |
1336 | int hwfn_index; | |
1337 | int status = 0; | |
1338 | ||
1339 | hwfn_index = qid % cdev->num_hwfns; | |
1340 | hwfn = &cdev->hwfns[hwfn_index]; | |
1341 | ptt = qed_ptt_acquire(hwfn); | |
1342 | if (!ptt) | |
1343 | return -EAGAIN; | |
1344 | ||
1345 | status = qed_set_rxq_coalesce(hwfn, ptt, rx_coal, | |
1346 | qid / cdev->num_hwfns, sb_id); | |
1347 | if (status) | |
1348 | goto out; | |
1349 | status = qed_set_txq_coalesce(hwfn, ptt, tx_coal, | |
1350 | qid / cdev->num_hwfns, sb_id); | |
1351 | out: | |
1352 | qed_ptt_release(hwfn, ptt); | |
1353 | ||
1354 | return status; | |
1355 | } | |
1356 | ||
91420b83 SK |
1357 | static int qed_set_led(struct qed_dev *cdev, enum qed_led_mode mode) |
1358 | { | |
1359 | struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); | |
1360 | struct qed_ptt *ptt; | |
1361 | int status = 0; | |
1362 | ||
1363 | ptt = qed_ptt_acquire(hwfn); | |
1364 | if (!ptt) | |
1365 | return -EAGAIN; | |
1366 | ||
1367 | status = qed_mcp_set_led(hwfn, ptt, mode); | |
1368 | ||
1369 | qed_ptt_release(hwfn, ptt); | |
1370 | ||
1371 | return status; | |
1372 | } | |
1373 | ||
03dc76ca SRK |
1374 | struct qed_selftest_ops qed_selftest_ops_pass = { |
1375 | .selftest_memory = &qed_selftest_memory, | |
1376 | .selftest_interrupt = &qed_selftest_interrupt, | |
1377 | .selftest_register = &qed_selftest_register, | |
1378 | .selftest_clock = &qed_selftest_clock, | |
1379 | }; | |
1380 | ||
fe56b9e6 | 1381 | const struct qed_common_ops qed_common_ops_pass = { |
03dc76ca | 1382 | .selftest = &qed_selftest_ops_pass, |
fe56b9e6 YM |
1383 | .probe = &qed_probe, |
1384 | .remove = &qed_remove, | |
1385 | .set_power_state = &qed_set_power_state, | |
1386 | .set_id = &qed_set_id, | |
1387 | .update_pf_params = &qed_update_pf_params, | |
1388 | .slowpath_start = &qed_slowpath_start, | |
1389 | .slowpath_stop = &qed_slowpath_stop, | |
1390 | .set_fp_int = &qed_set_int_fp, | |
1391 | .get_fp_int = &qed_get_int_fp, | |
1392 | .sb_init = &qed_sb_init, | |
1393 | .sb_release = &qed_sb_release, | |
1394 | .simd_handler_config = &qed_simd_handler_config, | |
1395 | .simd_handler_clean = &qed_simd_handler_clean, | |
fe7cd2bf | 1396 | .can_link_change = &qed_can_link_change, |
cc875c2e YM |
1397 | .set_link = &qed_set_link, |
1398 | .get_link = &qed_get_current_link, | |
fe56b9e6 YM |
1399 | .drain = &qed_drain, |
1400 | .update_msglvl = &qed_init_dp, | |
e0971c83 TT |
1401 | .dbg_all_data = &qed_dbg_all_data, |
1402 | .dbg_all_data_size = &qed_dbg_all_data_size, | |
fe56b9e6 YM |
1403 | .chain_alloc = &qed_chain_alloc, |
1404 | .chain_free = &qed_chain_free, | |
722003ac SRK |
1405 | .get_coalesce = &qed_get_coalesce, |
1406 | .set_coalesce = &qed_set_coalesce, | |
91420b83 | 1407 | .set_led = &qed_set_led, |
fe56b9e6 | 1408 | }; |
6c754246 SRK |
1409 | |
1410 | void qed_get_protocol_stats(struct qed_dev *cdev, | |
1411 | enum qed_mcp_protocol_type type, | |
1412 | union qed_mcp_protocol_stats *stats) | |
1413 | { | |
1414 | struct qed_eth_stats eth_stats; | |
1415 | ||
1416 | memset(stats, 0, sizeof(*stats)); | |
1417 | ||
1418 | switch (type) { | |
1419 | case QED_MCP_LAN_STATS: | |
1420 | qed_get_vport_stats(cdev, ð_stats); | |
1421 | stats->lan_stats.ucast_rx_pkts = eth_stats.rx_ucast_pkts; | |
1422 | stats->lan_stats.ucast_tx_pkts = eth_stats.tx_ucast_pkts; | |
1423 | stats->lan_stats.fcs_err = -1; | |
1424 | break; | |
1425 | default: | |
1426 | DP_ERR(cdev, "Invalid protocol type = %d\n", type); | |
1427 | return; | |
1428 | } | |
1429 | } |