]>
Commit | Line | Data |
---|---|---|
f67539c2 TL |
1 | /* SPDX-License-Identifier: BSD-3-Clause |
2 | * Copyright(c) 2017 Huawei Technologies Co., Ltd | |
3 | */ | |
4 | ||
5 | #include<rte_ethdev_driver.h> | |
6 | #include <rte_bus_pci.h> | |
7 | #include <rte_hash.h> | |
8 | #include <rte_jhash.h> | |
9 | ||
10 | #include "hinic_compat.h" | |
11 | #include "hinic_csr.h" | |
12 | #include "hinic_pmd_hwdev.h" | |
13 | #include "hinic_pmd_hwif.h" | |
14 | #include "hinic_pmd_wq.h" | |
15 | #include "hinic_pmd_cmdq.h" | |
16 | #include "hinic_pmd_mgmt.h" | |
17 | #include "hinic_pmd_niccfg.h" | |
18 | #include "hinic_pmd_mbox.h" | |
19 | ||
20 | #define HINIC_DEAULT_EQ_MSIX_PENDING_LIMIT 0 | |
21 | #define HINIC_DEAULT_EQ_MSIX_COALESC_TIMER_CFG 0xFF | |
22 | #define HINIC_DEAULT_EQ_MSIX_RESEND_TIMER_CFG 7 | |
23 | ||
24 | #define HINIC_FLR_TIMEOUT 1000 | |
25 | ||
26 | #define FFM_RECORD_NUM_MAX 32 | |
27 | ||
28 | #define HINIC_DMA_ATTR_ENTRY_ST_SHIFT 0 | |
29 | #define HINIC_DMA_ATTR_ENTRY_AT_SHIFT 8 | |
30 | #define HINIC_DMA_ATTR_ENTRY_PH_SHIFT 10 | |
31 | #define HINIC_DMA_ATTR_ENTRY_NO_SNOOPING_SHIFT 12 | |
32 | #define HINIC_DMA_ATTR_ENTRY_TPH_EN_SHIFT 13 | |
33 | ||
34 | #define HINIC_DMA_ATTR_ENTRY_ST_MASK 0xFF | |
35 | #define HINIC_DMA_ATTR_ENTRY_AT_MASK 0x3 | |
36 | #define HINIC_DMA_ATTR_ENTRY_PH_MASK 0x3 | |
37 | #define HINIC_DMA_ATTR_ENTRY_NO_SNOOPING_MASK 0x1 | |
38 | #define HINIC_DMA_ATTR_ENTRY_TPH_EN_MASK 0x1 | |
39 | ||
40 | #define HINIC_DMA_ATTR_ENTRY_SET(val, member) \ | |
41 | (((u32)(val) & HINIC_DMA_ATTR_ENTRY_##member##_MASK) << \ | |
42 | HINIC_DMA_ATTR_ENTRY_##member##_SHIFT) | |
43 | ||
44 | #define HINIC_DMA_ATTR_ENTRY_CLEAR(val, member) \ | |
45 | ((val) & (~(HINIC_DMA_ATTR_ENTRY_##member##_MASK \ | |
46 | << HINIC_DMA_ATTR_ENTRY_##member##_SHIFT))) | |
47 | ||
48 | #define HINIC_PCIE_ST_DISABLE 0 | |
49 | #define HINIC_PCIE_AT_DISABLE 0 | |
50 | #define HINIC_PCIE_PH_DISABLE 0 | |
51 | #define PCIE_MSIX_ATTR_ENTRY 0 | |
52 | ||
53 | #define HINIC_HASH_FUNC rte_jhash | |
54 | #define HINIC_HASH_KEY_LEN (sizeof(dma_addr_t)) | |
55 | #define HINIC_HASH_FUNC_INIT_VAL 0 | |
56 | ||
57 | static const char *__hw_to_char_fec[HILINK_FEC_MAX_TYPE] = { | |
58 | "RS-FEC", "BASE-FEC", "NO-FEC"}; | |
59 | ||
60 | static const char *__hw_to_char_port_type[LINK_PORT_MAX_TYPE] = { | |
61 | "Unknown", "Fibre", "Electric", "Direct Attach Copper", "AOC", | |
62 | "Back plane", "BaseT" | |
63 | }; | |
64 | ||
65 | static const char *hinic_module_link_err[LINK_ERR_NUM] = { | |
66 | "Unrecognized module", | |
67 | }; | |
68 | ||
69 | struct hinic_vf_dma_attr_table { | |
70 | struct hinic_mgmt_msg_head mgmt_msg_head; | |
71 | ||
72 | u16 func_idx; | |
73 | u8 func_dma_entry_num; | |
74 | u8 entry_idx; | |
75 | u8 st; | |
76 | u8 at; | |
77 | u8 ph; | |
78 | u8 no_snooping; | |
79 | u8 tph_en; | |
80 | u8 resv1[3]; | |
81 | }; | |
82 | ||
83 | /** | |
84 | * hinic_cpu_to_be32 - convert data to big endian 32 bit format | |
85 | * @data: the data to convert | |
86 | * @len: length of data to convert, must be Multiple of 4B | |
87 | */ | |
88 | void hinic_cpu_to_be32(void *data, u32 len) | |
89 | { | |
90 | u32 i; | |
91 | u32 *mem = (u32 *)data; | |
92 | ||
93 | for (i = 0; i < (len >> 2); i++) { | |
94 | *mem = cpu_to_be32(*mem); | |
95 | mem++; | |
96 | } | |
97 | } | |
98 | ||
99 | /** | |
100 | * hinic_be32_to_cpu - convert data from big endian 32 bit format | |
101 | * @data: the data to convert | |
102 | * @len: length of data to convert, must be Multiple of 4B | |
103 | */ | |
104 | void hinic_be32_to_cpu(void *data, u32 len) | |
105 | { | |
106 | u32 i; | |
107 | u32 *mem = (u32 *)data; | |
108 | ||
109 | for (i = 0; i < (len >> 2); i++) { | |
110 | *mem = be32_to_cpu(*mem); | |
111 | mem++; | |
112 | } | |
113 | } | |
114 | ||
115 | static void *hinic_dma_mem_zalloc(struct hinic_hwdev *hwdev, size_t size, | |
116 | dma_addr_t *dma_handle, unsigned int align, | |
117 | unsigned int socket_id) | |
118 | { | |
119 | int rc, alloc_cnt; | |
120 | const struct rte_memzone *mz; | |
121 | char z_name[RTE_MEMZONE_NAMESIZE]; | |
122 | hash_sig_t sig; | |
123 | rte_iova_t iova; | |
124 | ||
125 | if (dma_handle == NULL || 0 == size) | |
126 | return NULL; | |
127 | ||
128 | alloc_cnt = rte_atomic32_add_return(&hwdev->os_dep.dma_alloc_cnt, 1); | |
129 | snprintf(z_name, sizeof(z_name), "%s_%d", | |
130 | hwdev->pcidev_hdl->name, alloc_cnt); | |
131 | ||
132 | mz = rte_memzone_reserve_aligned(z_name, size, socket_id, | |
133 | RTE_MEMZONE_IOVA_CONTIG, align); | |
134 | if (!mz) { | |
135 | PMD_DRV_LOG(ERR, "Alloc dma able memory failed, errno: %d, ma_name: %s, size: 0x%zx", | |
136 | rte_errno, z_name, size); | |
137 | return NULL; | |
138 | } | |
139 | ||
140 | iova = mz->iova; | |
141 | ||
142 | /* check if phys_addr already exist */ | |
143 | sig = HINIC_HASH_FUNC(&iova, HINIC_HASH_KEY_LEN, | |
144 | HINIC_HASH_FUNC_INIT_VAL); | |
145 | rc = rte_hash_lookup_with_hash(hwdev->os_dep.dma_addr_hash, | |
146 | &iova, sig); | |
147 | if (rc >= 0) { | |
148 | PMD_DRV_LOG(ERR, "Dma addr: %p already in hash table, error: %d, mz_name: %s", | |
149 | (void *)iova, rc, z_name); | |
150 | goto phys_addr_hash_err; | |
151 | } | |
152 | ||
153 | /* record paddr in hash table */ | |
154 | rte_spinlock_lock(&hwdev->os_dep.dma_hash_lock); | |
155 | rc = rte_hash_add_key_with_hash_data(hwdev->os_dep.dma_addr_hash, | |
156 | &iova, sig, | |
157 | (void *)(u64)mz); | |
158 | rte_spinlock_unlock(&hwdev->os_dep.dma_hash_lock); | |
159 | if (rc) { | |
160 | PMD_DRV_LOG(ERR, "Insert dma addr: %p hash failed, error: %d, mz_name: %s", | |
161 | (void *)iova, rc, z_name); | |
162 | goto phys_addr_hash_err; | |
163 | } | |
164 | *dma_handle = iova; | |
165 | memset(mz->addr, 0, size); | |
166 | ||
167 | return mz->addr; | |
168 | ||
169 | phys_addr_hash_err: | |
170 | (void)rte_memzone_free(mz); | |
171 | ||
172 | return NULL; | |
173 | } | |
174 | ||
175 | static void | |
176 | hinic_dma_mem_free(struct hinic_hwdev *hwdev, size_t size, | |
177 | void *virt, dma_addr_t phys) | |
178 | { | |
179 | int rc; | |
180 | struct rte_memzone *mz = NULL; | |
181 | struct rte_hash *hash; | |
182 | hash_sig_t sig; | |
183 | ||
184 | if (virt == NULL || phys == 0) | |
185 | return; | |
186 | ||
187 | hash = hwdev->os_dep.dma_addr_hash; | |
188 | sig = HINIC_HASH_FUNC(&phys, HINIC_HASH_KEY_LEN, | |
189 | HINIC_HASH_FUNC_INIT_VAL); | |
190 | rc = rte_hash_lookup_with_hash_data(hash, &phys, sig, (void **)&mz); | |
191 | if (rc < 0) { | |
192 | PMD_DRV_LOG(ERR, "Can not find phys_addr: %p, error: %d", | |
193 | (void *)phys, rc); | |
194 | return; | |
195 | } | |
196 | ||
197 | if (virt != mz->addr || size > mz->len) { | |
198 | PMD_DRV_LOG(ERR, "Match mz_info failed: " | |
199 | "mz.name: %s, mz.phys: %p, mz.virt: %p, mz.len: %zu, " | |
200 | "phys: %p, virt: %p, size: %zu", | |
201 | mz->name, (void *)mz->iova, mz->addr, mz->len, | |
202 | (void *)phys, virt, size); | |
203 | } | |
204 | ||
205 | rte_spinlock_lock(&hwdev->os_dep.dma_hash_lock); | |
206 | (void)rte_hash_del_key_with_hash(hash, &phys, sig); | |
207 | rte_spinlock_unlock(&hwdev->os_dep.dma_hash_lock); | |
208 | ||
209 | (void)rte_memzone_free(mz); | |
210 | } | |
211 | ||
212 | void *dma_zalloc_coherent(void *hwdev, size_t size, dma_addr_t *dma_handle, | |
213 | unsigned int socket_id) | |
214 | { | |
215 | return hinic_dma_mem_zalloc(hwdev, size, dma_handle, | |
216 | RTE_CACHE_LINE_SIZE, socket_id); | |
217 | } | |
218 | ||
219 | void *dma_zalloc_coherent_aligned(void *hwdev, size_t size, | |
220 | dma_addr_t *dma_handle, unsigned int socket_id) | |
221 | { | |
222 | return hinic_dma_mem_zalloc(hwdev, size, dma_handle, HINIC_PAGE_SIZE, | |
223 | socket_id); | |
224 | } | |
225 | ||
226 | void *dma_zalloc_coherent_aligned256k(void *hwdev, size_t size, | |
227 | dma_addr_t *dma_handle, | |
228 | unsigned int socket_id) | |
229 | { | |
230 | return hinic_dma_mem_zalloc(hwdev, size, dma_handle, | |
231 | HINIC_PAGE_SIZE * 64, socket_id); | |
232 | } | |
233 | ||
234 | void dma_free_coherent(void *hwdev, size_t size, void *virt, dma_addr_t phys) | |
235 | { | |
236 | hinic_dma_mem_free(hwdev, size, virt, phys); | |
237 | } | |
238 | ||
239 | void dma_free_coherent_volatile(void *hwdev, size_t size, | |
240 | volatile void *virt, dma_addr_t phys) | |
241 | { | |
242 | int rc; | |
243 | struct rte_memzone *mz = NULL; | |
244 | struct hinic_hwdev *dev = hwdev; | |
245 | struct rte_hash *hash; | |
246 | hash_sig_t sig; | |
247 | ||
248 | if (virt == NULL || phys == 0) | |
249 | return; | |
250 | ||
251 | hash = dev->os_dep.dma_addr_hash; | |
252 | sig = HINIC_HASH_FUNC(&phys, HINIC_HASH_KEY_LEN, | |
253 | HINIC_HASH_FUNC_INIT_VAL); | |
254 | rc = rte_hash_lookup_with_hash_data(hash, &phys, sig, (void **)&mz); | |
255 | if (rc < 0) { | |
256 | PMD_DRV_LOG(ERR, "Can not find phys_addr: %p, error: %d", | |
257 | (void *)phys, rc); | |
258 | return; | |
259 | } | |
260 | ||
261 | if (virt != mz->addr || size > mz->len) { | |
262 | PMD_DRV_LOG(ERR, "Match mz_info failed: " | |
263 | "mz.name:%s, mz.phys:%p, mz.virt:%p, mz.len:%zu, " | |
264 | "phys:%p, virt:%p, size:%zu", | |
265 | mz->name, (void *)mz->iova, mz->addr, mz->len, | |
266 | (void *)phys, virt, size); | |
267 | } | |
268 | ||
269 | rte_spinlock_lock(&dev->os_dep.dma_hash_lock); | |
270 | (void)rte_hash_del_key_with_hash(hash, &phys, sig); | |
271 | rte_spinlock_unlock(&dev->os_dep.dma_hash_lock); | |
272 | ||
273 | (void)rte_memzone_free(mz); | |
274 | } | |
275 | ||
276 | struct dma_pool *dma_pool_create(const char *name, void *dev, | |
277 | size_t size, size_t align, size_t boundary) | |
278 | { | |
279 | struct pci_pool *pool; | |
280 | ||
281 | pool = rte_zmalloc(NULL, sizeof(*pool), HINIC_MEM_ALLOC_ALIGN_MIN); | |
282 | if (!pool) | |
283 | return NULL; | |
284 | ||
285 | rte_atomic32_set(&pool->inuse, 0); | |
286 | pool->elem_size = size; | |
287 | pool->align = align; | |
288 | pool->boundary = boundary; | |
289 | pool->hwdev = dev; | |
290 | strncpy(pool->name, name, (sizeof(pool->name) - 1)); | |
291 | ||
292 | return pool; | |
293 | } | |
294 | ||
295 | void dma_pool_destroy(struct dma_pool *pool) | |
296 | { | |
297 | if (!pool) | |
298 | return; | |
299 | ||
300 | if (rte_atomic32_read(&pool->inuse) != 0) { | |
301 | PMD_DRV_LOG(ERR, "Leak memory, dma_pool: %s, inuse_count: %d", | |
302 | pool->name, rte_atomic32_read(&pool->inuse)); | |
303 | } | |
304 | ||
305 | rte_free(pool); | |
306 | } | |
307 | ||
308 | void *dma_pool_alloc(struct pci_pool *pool, dma_addr_t *dma_addr) | |
309 | { | |
310 | void *buf; | |
311 | ||
312 | buf = hinic_dma_mem_zalloc(pool->hwdev, pool->elem_size, dma_addr, | |
313 | (u32)pool->align, SOCKET_ID_ANY); | |
314 | if (buf) | |
315 | rte_atomic32_inc(&pool->inuse); | |
316 | ||
317 | return buf; | |
318 | } | |
319 | ||
320 | void dma_pool_free(struct pci_pool *pool, void *vaddr, dma_addr_t dma) | |
321 | { | |
322 | rte_atomic32_dec(&pool->inuse); | |
323 | hinic_dma_mem_free(pool->hwdev, pool->elem_size, vaddr, dma); | |
324 | } | |
325 | ||
326 | #define HINIC_MAX_DMA_ENTRIES 8192 | |
327 | int hinic_osdep_init(struct hinic_hwdev *hwdev) | |
328 | { | |
329 | struct rte_hash_parameters dh_params = { 0 }; | |
330 | struct rte_hash *paddr_hash = NULL; | |
331 | ||
332 | rte_atomic32_set(&hwdev->os_dep.dma_alloc_cnt, 0); | |
333 | rte_spinlock_init(&hwdev->os_dep.dma_hash_lock); | |
334 | ||
335 | dh_params.name = hwdev->pcidev_hdl->name; | |
336 | dh_params.entries = HINIC_MAX_DMA_ENTRIES; | |
337 | dh_params.key_len = HINIC_HASH_KEY_LEN; | |
338 | dh_params.hash_func = HINIC_HASH_FUNC; | |
339 | dh_params.hash_func_init_val = HINIC_HASH_FUNC_INIT_VAL; | |
340 | dh_params.socket_id = SOCKET_ID_ANY; | |
341 | ||
342 | paddr_hash = rte_hash_find_existing(dh_params.name); | |
343 | if (paddr_hash == NULL) { | |
344 | paddr_hash = rte_hash_create(&dh_params); | |
345 | if (paddr_hash == NULL) { | |
346 | PMD_DRV_LOG(ERR, "Create nic_dev phys_addr hash table failed"); | |
347 | return -ENOMEM; | |
348 | } | |
349 | } else { | |
350 | PMD_DRV_LOG(INFO, "Using existing dma hash table %s", | |
351 | dh_params.name); | |
352 | } | |
353 | hwdev->os_dep.dma_addr_hash = paddr_hash; | |
354 | ||
355 | return 0; | |
356 | } | |
357 | ||
358 | void hinic_osdep_deinit(struct hinic_hwdev *hwdev) | |
359 | { | |
360 | uint32_t iter = 0; | |
361 | dma_addr_t key_pa; | |
362 | struct rte_memzone *data_mz = NULL; | |
363 | struct rte_hash *paddr_hash = hwdev->os_dep.dma_addr_hash; | |
364 | ||
365 | if (paddr_hash) { | |
366 | /* iterate through the hash table */ | |
367 | while (rte_hash_iterate(paddr_hash, (const void **)&key_pa, | |
368 | (void **)&data_mz, &iter) >= 0) { | |
369 | if (data_mz) { | |
370 | PMD_DRV_LOG(WARNING, "Free leaked dma_addr: %p, mz: %s", | |
371 | (void *)key_pa, data_mz->name); | |
372 | (void)rte_memzone_free(data_mz); | |
373 | } | |
374 | } | |
375 | ||
376 | /* free phys_addr hash table */ | |
377 | rte_hash_free(paddr_hash); | |
378 | } | |
379 | } | |
380 | ||
381 | /** | |
382 | * hinic_set_ci_table - set ci attribute table | |
383 | * @hwdev: the hardware interface of a nic device | |
384 | * @q_id: Queue id of SQ | |
385 | * @attr: Point to SQ CI attribute table | |
386 | * @return | |
387 | * 0 on success and ci attribute table is filled, | |
388 | * negative error value otherwise. | |
389 | */ | |
390 | int hinic_set_ci_table(void *hwdev, u16 q_id, struct hinic_sq_attr *attr) | |
391 | { | |
392 | struct hinic_cons_idx_attr cons_idx_attr; | |
393 | ||
394 | memset(&cons_idx_attr, 0, sizeof(cons_idx_attr)); | |
395 | cons_idx_attr.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1; | |
396 | cons_idx_attr.func_idx = hinic_global_func_id(hwdev); | |
397 | cons_idx_attr.dma_attr_off = attr->dma_attr_off; | |
398 | cons_idx_attr.pending_limit = attr->pending_limit; | |
399 | cons_idx_attr.coalescing_time = attr->coalescing_time; | |
400 | if (attr->intr_en) { | |
401 | cons_idx_attr.intr_en = attr->intr_en; | |
402 | cons_idx_attr.intr_idx = attr->intr_idx; | |
403 | } | |
404 | ||
405 | cons_idx_attr.l2nic_sqn = attr->l2nic_sqn; | |
406 | cons_idx_attr.sq_id = q_id; | |
407 | cons_idx_attr.ci_addr = attr->ci_dma_base; | |
408 | ||
409 | return hinic_msg_to_mgmt_sync(hwdev, HINIC_MOD_COMM, | |
410 | HINIC_MGMT_CMD_L2NIC_SQ_CI_ATTR_SET, | |
411 | &cons_idx_attr, sizeof(cons_idx_attr), | |
412 | NULL, NULL, 0); | |
413 | } | |
414 | ||
415 | /** | |
416 | * hinic_set_pagesize - set page size to vat table | |
417 | * @hwdev: the hardware interface of a nic device | |
418 | * @page_size: vat page size | |
419 | * @return | |
420 | * 0 on success, | |
421 | * negative error value otherwise. | |
422 | */ | |
423 | int hinic_set_pagesize(void *hwdev, u8 page_size) | |
424 | { | |
425 | struct hinic_page_size cmd; | |
426 | ||
427 | if (page_size > HINIC_PAGE_SIZE_MAX) { | |
428 | PMD_DRV_LOG(ERR, "Invalid page_size %u, bigger than %u", | |
429 | page_size, HINIC_PAGE_SIZE_MAX); | |
430 | return -EINVAL; | |
431 | } | |
432 | ||
433 | memset(&cmd, 0, sizeof(cmd)); | |
434 | cmd.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1; | |
435 | cmd.func_idx = hinic_global_func_id(hwdev); | |
436 | cmd.ppf_idx = hinic_ppf_idx(hwdev); | |
437 | cmd.page_size = page_size; | |
438 | ||
439 | return hinic_msg_to_mgmt_sync(hwdev, HINIC_MOD_COMM, | |
440 | HINIC_MGMT_CMD_PAGESIZE_SET, | |
441 | &cmd, sizeof(cmd), | |
442 | NULL, NULL, 0); | |
443 | } | |
444 | ||
445 | static int wait_for_flr_finish(struct hinic_hwif *hwif) | |
446 | { | |
447 | unsigned long end; | |
448 | enum hinic_pf_status status; | |
449 | ||
450 | end = jiffies + msecs_to_jiffies(HINIC_FLR_TIMEOUT); | |
451 | do { | |
452 | status = hinic_get_pf_status(hwif); | |
453 | if (status == HINIC_PF_STATUS_FLR_FINISH_FLAG) { | |
454 | return 0; | |
455 | } | |
456 | ||
457 | rte_delay_ms(10); | |
458 | } while (time_before(jiffies, end)); | |
459 | ||
460 | return -EFAULT; | |
461 | } | |
462 | ||
463 | #define HINIC_WAIT_CMDQ_IDLE_TIMEOUT 1000 | |
464 | ||
465 | static int wait_cmdq_stop(struct hinic_hwdev *hwdev) | |
466 | { | |
467 | enum hinic_cmdq_type cmdq_type; | |
468 | struct hinic_cmdqs *cmdqs = hwdev->cmdqs; | |
469 | unsigned long end; | |
470 | int err = 0; | |
471 | ||
472 | if (!(cmdqs->status & HINIC_CMDQ_ENABLE)) | |
473 | return 0; | |
474 | ||
475 | cmdqs->status &= ~HINIC_CMDQ_ENABLE; | |
476 | ||
477 | end = jiffies + msecs_to_jiffies(HINIC_WAIT_CMDQ_IDLE_TIMEOUT); | |
478 | do { | |
479 | err = 0; | |
480 | cmdq_type = HINIC_CMDQ_SYNC; | |
481 | for (; cmdq_type < HINIC_MAX_CMDQ_TYPES; cmdq_type++) { | |
482 | if (!hinic_cmdq_idle(&cmdqs->cmdq[cmdq_type])) { | |
483 | err = -EBUSY; | |
484 | break; | |
485 | } | |
486 | } | |
487 | ||
488 | if (!err) | |
489 | return 0; | |
490 | ||
491 | rte_delay_ms(1); | |
492 | } while (time_before(jiffies, end)); | |
493 | ||
494 | cmdqs->status |= HINIC_CMDQ_ENABLE; | |
495 | ||
496 | return err; | |
497 | } | |
498 | ||
499 | static int hinic_vf_rx_tx_flush(struct hinic_hwdev *hwdev) | |
500 | { | |
501 | struct hinic_clear_resource clr_res; | |
502 | int err; | |
503 | ||
504 | err = wait_cmdq_stop(hwdev); | |
505 | if (err) { | |
506 | PMD_DRV_LOG(WARNING, "Cmdq is still working"); | |
507 | return err; | |
508 | } | |
509 | ||
510 | memset(&clr_res, 0, sizeof(clr_res)); | |
511 | clr_res.func_idx = HINIC_HWIF_GLOBAL_IDX(hwdev->hwif); | |
512 | clr_res.ppf_idx = HINIC_HWIF_PPF_IDX(hwdev->hwif); | |
513 | err = hinic_mbox_to_pf_no_ack(hwdev, HINIC_MOD_COMM, | |
514 | HINIC_MGMT_CMD_START_FLR, &clr_res, sizeof(clr_res)); | |
515 | if (err) | |
516 | PMD_DRV_LOG(WARNING, "Notice flush message failed"); | |
517 | ||
518 | /* | |
519 | * PF firstly set VF doorbell flush csr to be disabled. After PF finish | |
520 | * VF resources flush, PF will set VF doorbell flush csr to be enabled. | |
521 | */ | |
522 | err = wait_until_doorbell_flush_states(hwdev->hwif, DISABLE_DOORBELL); | |
523 | if (err) | |
524 | PMD_DRV_LOG(WARNING, "Wait doorbell flush disable timeout"); | |
525 | ||
526 | err = wait_until_doorbell_flush_states(hwdev->hwif, ENABLE_DOORBELL); | |
527 | if (err) | |
528 | PMD_DRV_LOG(WARNING, "Wait doorbell flush enable timeout"); | |
529 | ||
530 | err = hinic_reinit_cmdq_ctxts(hwdev); | |
531 | if (err) | |
532 | PMD_DRV_LOG(WARNING, "Reinit cmdq failed when vf flush"); | |
533 | ||
534 | return err; | |
535 | } | |
536 | ||
537 | /** | |
538 | * hinic_pf_rx_tx_flush - clean up hardware resource | |
539 | * @hwdev: the hardware interface of a nic device | |
540 | * @return | |
541 | * 0 on success, | |
542 | * negative error value otherwise. | |
543 | */ | |
544 | static int hinic_pf_rx_tx_flush(struct hinic_hwdev *hwdev) | |
545 | { | |
546 | struct hinic_hwif *hwif = hwdev->hwif; | |
547 | struct hinic_clear_doorbell clear_db; | |
548 | struct hinic_clear_resource clr_res; | |
549 | int err; | |
550 | ||
551 | rte_delay_ms(100); | |
552 | ||
553 | err = wait_cmdq_stop(hwdev); | |
554 | if (err) { | |
555 | PMD_DRV_LOG(ERR, "Cmdq is still working"); | |
556 | return err; | |
557 | } | |
558 | ||
559 | hinic_disable_doorbell(hwif); | |
560 | memset(&clear_db, 0, sizeof(clear_db)); | |
561 | clear_db.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1; | |
562 | clear_db.func_idx = HINIC_HWIF_GLOBAL_IDX(hwif); | |
563 | clear_db.ppf_idx = HINIC_HWIF_PPF_IDX(hwif); | |
564 | err = hinic_msg_to_mgmt_sync(hwdev, HINIC_MOD_COMM, | |
565 | HINIC_MGMT_CMD_FLUSH_DOORBELL, &clear_db, | |
566 | sizeof(clear_db), NULL, NULL, 0); | |
567 | if (err) | |
568 | PMD_DRV_LOG(WARNING, "Flush doorbell failed"); | |
569 | ||
570 | hinic_set_pf_status(hwif, HINIC_PF_STATUS_FLR_START_FLAG); | |
571 | memset(&clr_res, 0, sizeof(clr_res)); | |
572 | clr_res.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1; | |
573 | clr_res.func_idx = HINIC_HWIF_GLOBAL_IDX(hwif); | |
574 | clr_res.ppf_idx = HINIC_HWIF_PPF_IDX(hwif); | |
575 | ||
576 | err = hinic_msg_to_mgmt_no_ack(hwdev, HINIC_MOD_COMM, | |
577 | HINIC_MGMT_CMD_START_FLR, &clr_res, | |
578 | sizeof(clr_res), NULL, NULL); | |
579 | if (err) | |
580 | PMD_DRV_LOG(WARNING, "Notice flush message failed"); | |
581 | ||
582 | err = wait_for_flr_finish(hwif); | |
583 | if (err) | |
584 | PMD_DRV_LOG(WARNING, "Wait firmware FLR timeout"); | |
585 | ||
586 | hinic_enable_doorbell(hwif); | |
587 | ||
588 | err = hinic_reinit_cmdq_ctxts(hwdev); | |
589 | if (err) | |
590 | PMD_DRV_LOG(WARNING, "Reinit cmdq failed when pf flush"); | |
591 | ||
592 | return 0; | |
593 | } | |
594 | ||
595 | int hinic_func_rx_tx_flush(struct hinic_hwdev *hwdev) | |
596 | { | |
597 | if (HINIC_FUNC_TYPE(hwdev) == TYPE_VF) | |
598 | return hinic_vf_rx_tx_flush(hwdev); | |
599 | else | |
600 | return hinic_pf_rx_tx_flush(hwdev); | |
601 | } | |
602 | ||
603 | /** | |
604 | * hinic_get_interrupt_cfg - get interrupt configuration from NIC | |
605 | * @hwdev: the hardware interface of a nic device | |
606 | * @interrupt_info: Information of Interrupt aggregation | |
607 | * Return: 0 on success, negative error value otherwise. | |
608 | */ | |
609 | static int hinic_get_interrupt_cfg(struct hinic_hwdev *hwdev, | |
610 | struct nic_interrupt_info *interrupt_info) | |
611 | { | |
612 | struct hinic_msix_config msix_cfg; | |
613 | u16 out_size = sizeof(msix_cfg); | |
614 | int err; | |
615 | ||
616 | memset(&msix_cfg, 0, sizeof(msix_cfg)); | |
617 | msix_cfg.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1; | |
618 | msix_cfg.func_id = hinic_global_func_id(hwdev); | |
619 | msix_cfg.msix_index = interrupt_info->msix_index; | |
620 | ||
621 | err = hinic_msg_to_mgmt_sync(hwdev, HINIC_MOD_COMM, | |
622 | HINIC_MGMT_CMD_MSI_CTRL_REG_RD_BY_UP, | |
623 | &msix_cfg, sizeof(msix_cfg), | |
624 | &msix_cfg, &out_size, 0); | |
625 | if (err || !out_size || msix_cfg.mgmt_msg_head.status) { | |
626 | PMD_DRV_LOG(ERR, "Get interrupt config failed, ret: %d", | |
627 | msix_cfg.mgmt_msg_head.status); | |
628 | return -EINVAL; | |
629 | } | |
630 | ||
631 | interrupt_info->lli_credit_limit = msix_cfg.lli_credit_cnt; | |
632 | interrupt_info->lli_timer_cfg = msix_cfg.lli_tmier_cnt; | |
633 | interrupt_info->pending_limt = msix_cfg.pending_cnt; | |
634 | interrupt_info->coalesc_timer_cfg = msix_cfg.coalesct_timer_cnt; | |
635 | interrupt_info->resend_timer_cfg = msix_cfg.resend_timer_cnt; | |
636 | return 0; | |
637 | } | |
638 | ||
639 | /** | |
640 | * hinic_set_interrupt_cfg - set interrupt configuration to NIC | |
641 | * @hwdev: the hardware interface of a nic device | |
642 | * @interrupt_info: Information of Interrupt aggregation | |
643 | * Return: 0 on success, negative error value otherwise. | |
644 | */ | |
645 | int hinic_set_interrupt_cfg(struct hinic_hwdev *hwdev, | |
646 | struct nic_interrupt_info interrupt_info) | |
647 | { | |
648 | struct hinic_msix_config msix_cfg; | |
649 | struct nic_interrupt_info temp_info; | |
650 | u16 out_size = sizeof(msix_cfg); | |
651 | int err; | |
652 | ||
653 | memset(&msix_cfg, 0, sizeof(msix_cfg)); | |
654 | msix_cfg.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1; | |
655 | msix_cfg.func_id = hinic_global_func_id(hwdev); | |
656 | msix_cfg.msix_index = (u16)interrupt_info.msix_index; | |
657 | ||
658 | temp_info.msix_index = interrupt_info.msix_index; | |
659 | ||
660 | err = hinic_get_interrupt_cfg(hwdev, &temp_info); | |
661 | if (err) | |
662 | return -EINVAL; | |
663 | ||
664 | msix_cfg.lli_credit_cnt = temp_info.lli_credit_limit; | |
665 | msix_cfg.lli_tmier_cnt = temp_info.lli_timer_cfg; | |
666 | msix_cfg.pending_cnt = temp_info.pending_limt; | |
667 | msix_cfg.coalesct_timer_cnt = temp_info.coalesc_timer_cfg; | |
668 | msix_cfg.resend_timer_cnt = temp_info.resend_timer_cfg; | |
669 | ||
670 | if (interrupt_info.lli_set) { | |
671 | msix_cfg.lli_credit_cnt = interrupt_info.lli_credit_limit; | |
672 | msix_cfg.lli_tmier_cnt = interrupt_info.lli_timer_cfg; | |
673 | } | |
674 | ||
675 | if (interrupt_info.interrupt_coalesc_set) { | |
676 | msix_cfg.pending_cnt = interrupt_info.pending_limt; | |
677 | msix_cfg.coalesct_timer_cnt = interrupt_info.coalesc_timer_cfg; | |
678 | msix_cfg.resend_timer_cnt = interrupt_info.resend_timer_cfg; | |
679 | } | |
680 | ||
681 | err = hinic_msg_to_mgmt_sync(hwdev, HINIC_MOD_COMM, | |
682 | HINIC_MGMT_CMD_MSI_CTRL_REG_WR_BY_UP, | |
683 | &msix_cfg, sizeof(msix_cfg), | |
684 | &msix_cfg, &out_size, 0); | |
685 | if (err || !out_size || msix_cfg.mgmt_msg_head.status) { | |
686 | PMD_DRV_LOG(ERR, "Set interrupt config failed, ret: %d", | |
687 | msix_cfg.mgmt_msg_head.status); | |
688 | return -EINVAL; | |
689 | } | |
690 | ||
691 | return 0; | |
692 | } | |
693 | ||
694 | /** | |
695 | * init_aeqs_msix_attr - Init interrupt attributes of aeq | |
696 | * @hwdev: the hardware interface of a nic device | |
697 | * @return | |
698 | * 0 on success, | |
699 | * negative error value otherwise. | |
700 | */ | |
701 | int init_aeqs_msix_attr(void *hwdev) | |
702 | { | |
703 | struct hinic_hwdev *nic_hwdev = hwdev; | |
704 | struct hinic_aeqs *aeqs = nic_hwdev->aeqs; | |
705 | struct nic_interrupt_info info = {0}; | |
706 | struct hinic_eq *eq; | |
707 | u16 q_id; | |
708 | int err; | |
709 | ||
710 | info.lli_set = 0; | |
711 | info.interrupt_coalesc_set = 1; | |
712 | info.pending_limt = HINIC_DEAULT_EQ_MSIX_PENDING_LIMIT; | |
713 | info.coalesc_timer_cfg = HINIC_DEAULT_EQ_MSIX_COALESC_TIMER_CFG; | |
714 | info.resend_timer_cfg = HINIC_DEAULT_EQ_MSIX_RESEND_TIMER_CFG; | |
715 | ||
716 | for (q_id = 0; q_id < aeqs->num_aeqs; q_id++) { | |
717 | eq = &aeqs->aeq[q_id]; | |
718 | info.msix_index = eq->eq_irq.msix_entry_idx; | |
719 | err = hinic_set_interrupt_cfg(hwdev, info); | |
720 | if (err) { | |
721 | PMD_DRV_LOG(ERR, "Set msix attr for aeq %d failed", | |
722 | q_id); | |
723 | return -EFAULT; | |
724 | } | |
725 | } | |
726 | ||
727 | return 0; | |
728 | } | |
729 | ||
730 | /** | |
731 | * set_pf_dma_attr_entry - set the dma attributes for entry | |
732 | * @hwdev: the pointer to the private hardware device object | |
733 | * @entry_idx: the entry index in the dma table | |
734 | * @st: PCIE TLP steering tag | |
735 | * @at: PCIE TLP AT field | |
736 | * @ph: PCIE TLP Processing Hint field | |
737 | * @no_snooping: PCIE TLP No snooping | |
738 | * @tph_en: PCIE TLP Processing Hint Enable | |
739 | */ | |
740 | static void set_pf_dma_attr_entry(struct hinic_hwdev *hwdev, u32 entry_idx, | |
741 | u8 st, u8 at, u8 ph, | |
742 | enum hinic_pcie_nosnoop no_snooping, | |
743 | enum hinic_pcie_tph tph_en) | |
744 | { | |
745 | u32 addr, val, dma_attr_entry; | |
746 | ||
747 | /* Read Modify Write */ | |
748 | addr = HINIC_CSR_DMA_ATTR_TBL_ADDR(entry_idx); | |
749 | ||
750 | val = hinic_hwif_read_reg(hwdev->hwif, addr); | |
751 | val = HINIC_DMA_ATTR_ENTRY_CLEAR(val, ST) & | |
752 | HINIC_DMA_ATTR_ENTRY_CLEAR(val, AT) & | |
753 | HINIC_DMA_ATTR_ENTRY_CLEAR(val, PH) & | |
754 | HINIC_DMA_ATTR_ENTRY_CLEAR(val, NO_SNOOPING) & | |
755 | HINIC_DMA_ATTR_ENTRY_CLEAR(val, TPH_EN); | |
756 | ||
757 | dma_attr_entry = HINIC_DMA_ATTR_ENTRY_SET(st, ST) | | |
758 | HINIC_DMA_ATTR_ENTRY_SET(at, AT) | | |
759 | HINIC_DMA_ATTR_ENTRY_SET(ph, PH) | | |
760 | HINIC_DMA_ATTR_ENTRY_SET(no_snooping, NO_SNOOPING) | | |
761 | HINIC_DMA_ATTR_ENTRY_SET(tph_en, TPH_EN); | |
762 | ||
763 | val |= dma_attr_entry; | |
764 | hinic_hwif_write_reg(hwdev->hwif, addr, val); | |
765 | } | |
766 | ||
767 | static int set_vf_dma_attr_entry(struct hinic_hwdev *hwdev, u8 entry_idx, | |
768 | u8 st, u8 at, u8 ph, | |
769 | enum hinic_pcie_nosnoop no_snooping, | |
770 | enum hinic_pcie_tph tph_en) | |
771 | { | |
772 | struct hinic_vf_dma_attr_table attr; | |
773 | ||
774 | memset(&attr, 0, sizeof(attr)); | |
775 | attr.func_idx = hinic_global_func_id(hwdev); | |
776 | attr.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1; | |
777 | attr.func_dma_entry_num = hinic_dma_attr_entry_num(hwdev); | |
778 | attr.entry_idx = entry_idx; | |
779 | attr.st = st; | |
780 | attr.at = at; | |
781 | attr.ph = ph; | |
782 | attr.no_snooping = no_snooping; | |
783 | attr.tph_en = tph_en; | |
784 | ||
785 | return hinic_msg_to_mgmt_sync(hwdev, HINIC_MOD_COMM, | |
786 | HINIC_MGMT_CMD_DMA_ATTR_SET, | |
787 | &attr, sizeof(attr), NULL, NULL, 0); | |
788 | } | |
789 | ||
790 | /** | |
791 | * dma_attr_table_init - initialize the the default dma attributes | |
792 | * @hwdev: the pointer to the private hardware device object | |
793 | */ | |
794 | static int dma_attr_table_init(struct hinic_hwdev *hwdev) | |
795 | { | |
796 | int err = 0; | |
797 | ||
798 | if (HINIC_IS_VF(hwdev)) | |
799 | err = set_vf_dma_attr_entry(hwdev, PCIE_MSIX_ATTR_ENTRY, | |
800 | HINIC_PCIE_ST_DISABLE, HINIC_PCIE_AT_DISABLE, | |
801 | HINIC_PCIE_PH_DISABLE, HINIC_PCIE_SNOOP, | |
802 | HINIC_PCIE_TPH_DISABLE); | |
803 | else | |
804 | set_pf_dma_attr_entry(hwdev, PCIE_MSIX_ATTR_ENTRY, | |
805 | HINIC_PCIE_ST_DISABLE, HINIC_PCIE_AT_DISABLE, | |
806 | HINIC_PCIE_PH_DISABLE, HINIC_PCIE_SNOOP, | |
807 | HINIC_PCIE_TPH_DISABLE); | |
808 | ||
809 | return err; | |
810 | } | |
811 | ||
812 | /** | |
813 | * hinic_init_attr_table - init dma and aeq msix attribute table | |
814 | * @hwdev: the pointer to the private hardware device object | |
815 | */ | |
816 | int hinic_init_attr_table(struct hinic_hwdev *hwdev) | |
817 | { | |
818 | int err; | |
819 | ||
820 | err = dma_attr_table_init(hwdev); | |
821 | if (err) { | |
822 | PMD_DRV_LOG(ERR, "Initialize dma attribute table failed, err: %d", | |
823 | err); | |
824 | return err; | |
825 | } | |
826 | ||
827 | err = init_aeqs_msix_attr(hwdev); | |
828 | if (err) { | |
829 | PMD_DRV_LOG(ERR, "Initialize aeqs msix attribute failed, err: %d", | |
830 | err); | |
831 | return err; | |
832 | } | |
833 | ||
834 | return 0; | |
835 | } | |
836 | ||
837 | #define FAULT_SHOW_STR_LEN 16 | |
838 | static void fault_report_show(struct hinic_hwdev *hwdev, | |
839 | struct hinic_fault_event *event) | |
840 | { | |
841 | char fault_type[FAULT_TYPE_MAX][FAULT_SHOW_STR_LEN + 1] = { | |
842 | "chip", "ucode", "mem rd timeout", "mem wr timeout", | |
843 | "reg rd timeout", "reg wr timeout"}; | |
844 | char fault_level[FAULT_LEVEL_MAX][FAULT_SHOW_STR_LEN + 1] = { | |
845 | "fatal", "reset", "flr", "general", "suggestion"}; | |
846 | char type_str[FAULT_SHOW_STR_LEN + 1] = { 0 }; | |
847 | char level_str[FAULT_SHOW_STR_LEN + 1] = { 0 }; | |
848 | u8 err_level; | |
849 | ||
850 | PMD_DRV_LOG(WARNING, "Fault event report received, func_id: %d", | |
851 | hinic_global_func_id(hwdev)); | |
852 | ||
853 | if (event->type < FAULT_TYPE_MAX) | |
854 | strncpy(type_str, fault_type[event->type], FAULT_SHOW_STR_LEN); | |
855 | else | |
856 | strncpy(type_str, "unknown", FAULT_SHOW_STR_LEN); | |
857 | PMD_DRV_LOG(WARNING, "fault type: %d [%s]", | |
858 | event->type, type_str); | |
859 | PMD_DRV_LOG(WARNING, "fault val[0]: 0x%08x", | |
860 | event->event.val[0]); | |
861 | PMD_DRV_LOG(WARNING, "fault val[1]: 0x%08x", | |
862 | event->event.val[1]); | |
863 | PMD_DRV_LOG(WARNING, "fault val[2]: 0x%08x", | |
864 | event->event.val[2]); | |
865 | PMD_DRV_LOG(WARNING, "fault val[3]: 0x%08x", | |
866 | event->event.val[3]); | |
867 | ||
868 | switch (event->type) { | |
869 | case FAULT_TYPE_CHIP: | |
870 | err_level = event->event.chip.err_level; | |
871 | if (err_level < FAULT_LEVEL_MAX) | |
872 | strncpy(level_str, fault_level[err_level], | |
873 | FAULT_SHOW_STR_LEN); | |
874 | else | |
875 | strncpy(level_str, "unknown", | |
876 | FAULT_SHOW_STR_LEN); | |
877 | ||
878 | PMD_DRV_LOG(WARNING, "err_level: %d [%s]", | |
879 | err_level, level_str); | |
880 | ||
881 | if (err_level == FAULT_LEVEL_SERIOUS_FLR) { | |
882 | PMD_DRV_LOG(WARNING, "flr func_id: %d", | |
883 | event->event.chip.func_id); | |
884 | } else { | |
885 | PMD_DRV_LOG(WARNING, "node_id: %d", | |
886 | event->event.chip.node_id); | |
887 | PMD_DRV_LOG(WARNING, "err_type: %d", | |
888 | event->event.chip.err_type); | |
889 | PMD_DRV_LOG(WARNING, "err_csr_addr: %d", | |
890 | event->event.chip.err_csr_addr); | |
891 | PMD_DRV_LOG(WARNING, "err_csr_value: %d", | |
892 | event->event.chip.err_csr_value); | |
893 | } | |
894 | break; | |
895 | case FAULT_TYPE_UCODE: | |
896 | PMD_DRV_LOG(WARNING, "cause_id: %d", | |
897 | event->event.ucode.cause_id); | |
898 | PMD_DRV_LOG(WARNING, "core_id: %d", | |
899 | event->event.ucode.core_id); | |
900 | PMD_DRV_LOG(WARNING, "c_id: %d", | |
901 | event->event.ucode.c_id); | |
902 | PMD_DRV_LOG(WARNING, "epc: %d", | |
903 | event->event.ucode.epc); | |
904 | break; | |
905 | case FAULT_TYPE_MEM_RD_TIMEOUT: | |
906 | case FAULT_TYPE_MEM_WR_TIMEOUT: | |
907 | PMD_DRV_LOG(WARNING, "err_csr_ctrl: %d", | |
908 | event->event.mem_timeout.err_csr_ctrl); | |
909 | PMD_DRV_LOG(WARNING, "err_csr_data: %d", | |
910 | event->event.mem_timeout.err_csr_data); | |
911 | PMD_DRV_LOG(WARNING, "ctrl_tab: %d", | |
912 | event->event.mem_timeout.ctrl_tab); | |
913 | PMD_DRV_LOG(WARNING, "mem_index: %d", | |
914 | event->event.mem_timeout.mem_index); | |
915 | break; | |
916 | case FAULT_TYPE_REG_RD_TIMEOUT: | |
917 | case FAULT_TYPE_REG_WR_TIMEOUT: | |
918 | PMD_DRV_LOG(WARNING, "err_csr: %d", | |
919 | event->event.reg_timeout.err_csr); | |
920 | break; | |
921 | default: | |
922 | break; | |
923 | } | |
924 | } | |
925 | ||
926 | static int resources_state_set(struct hinic_hwdev *hwdev, | |
927 | enum hinic_res_state state) | |
928 | { | |
929 | struct hinic_hwif *hwif = hwdev->hwif; | |
930 | struct hinic_cmd_set_res_state res_state; | |
931 | ||
932 | memset(&res_state, 0, sizeof(res_state)); | |
933 | res_state.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1; | |
934 | res_state.func_idx = HINIC_HWIF_GLOBAL_IDX(hwif); | |
935 | res_state.state = state; | |
936 | ||
937 | return hinic_msg_to_mgmt_sync(hwdev, HINIC_MOD_COMM, | |
938 | HINIC_MGMT_CMD_RES_STATE_SET, | |
939 | &res_state, sizeof(res_state), NULL, NULL, 0); | |
940 | } | |
941 | ||
942 | /** | |
943 | * hinic_activate_hwdev_state - Active host nic state and notify mgmt channel | |
944 | * that host nic is ready. | |
945 | * @hwdev: the hardware interface of a nic device | |
946 | * @return | |
947 | * 0 on success, | |
948 | * negative error value otherwise. | |
949 | */ | |
950 | int hinic_activate_hwdev_state(struct hinic_hwdev *hwdev) | |
951 | { | |
952 | int rc = HINIC_OK; | |
953 | ||
954 | if (!hwdev) | |
955 | return -EINVAL; | |
956 | ||
957 | hinic_set_pf_status(hwdev->hwif, HINIC_PF_STATUS_ACTIVE_FLAG); | |
958 | ||
959 | rc = resources_state_set(hwdev, HINIC_RES_ACTIVE); | |
960 | if (rc) { | |
961 | PMD_DRV_LOG(ERR, "Initialize resources state failed"); | |
962 | return rc; | |
963 | } | |
964 | ||
965 | return 0; | |
966 | } | |
967 | ||
968 | /** | |
969 | * hinic_deactivate_hwdev_state - Deactivate host nic state and notify mgmt | |
970 | * channel that host nic is not ready. | |
971 | * @hwdev: the pointer to the private hardware device object | |
972 | */ | |
973 | void hinic_deactivate_hwdev_state(struct hinic_hwdev *hwdev) | |
974 | { | |
975 | int rc = HINIC_OK; | |
976 | ||
977 | if (!hwdev) | |
978 | return; | |
979 | ||
980 | rc = resources_state_set(hwdev, HINIC_RES_CLEAN); | |
981 | if (rc) | |
982 | PMD_DRV_LOG(ERR, "Deinit resources state failed"); | |
983 | ||
984 | hinic_set_pf_status(hwdev->hwif, HINIC_PF_STATUS_INIT); | |
985 | } | |
986 | ||
987 | int hinic_get_board_info(void *hwdev, struct hinic_board_info *info) | |
988 | { | |
989 | struct hinic_comm_board_info board_info; | |
990 | u16 out_size = sizeof(board_info); | |
991 | int err; | |
992 | ||
993 | if (!hwdev || !info) | |
994 | return -EINVAL; | |
995 | ||
996 | memset(&board_info, 0, sizeof(board_info)); | |
997 | board_info.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1; | |
998 | err = hinic_msg_to_mgmt_sync(hwdev, HINIC_MOD_COMM, | |
999 | HINIC_MGMT_CMD_GET_BOARD_INFO, | |
1000 | &board_info, sizeof(board_info), | |
1001 | &board_info, &out_size, 0); | |
1002 | if (err || board_info.mgmt_msg_head.status || !out_size) { | |
1003 | PMD_DRV_LOG(ERR, "Failed to get board info, err: %d, status: 0x%x, out size: 0x%x", | |
1004 | err, board_info.mgmt_msg_head.status, out_size); | |
1005 | return -EFAULT; | |
1006 | } | |
1007 | ||
1008 | memcpy(info, &board_info.info, sizeof(*info)); | |
1009 | return 0; | |
1010 | } | |
1011 | ||
1012 | /** | |
1013 | * hinic_l2nic_reset - Restore the initial state of NIC | |
1014 | * @hwdev: the hardware interface of a nic device | |
1015 | * @return | |
1016 | * 0 on success, | |
1017 | * negative error value otherwise. | |
1018 | */ | |
1019 | int hinic_l2nic_reset(struct hinic_hwdev *hwdev) | |
1020 | { | |
1021 | struct hinic_hwif *hwif = hwdev->hwif; | |
1022 | struct hinic_l2nic_reset l2nic_reset; | |
1023 | int err = 0; | |
1024 | ||
1025 | err = hinic_set_vport_enable(hwdev, false); | |
1026 | if (err) { | |
1027 | PMD_DRV_LOG(ERR, "Set vport disable failed"); | |
1028 | return err; | |
1029 | } | |
1030 | ||
1031 | rte_delay_ms(100); | |
1032 | ||
1033 | memset(&l2nic_reset, 0, sizeof(l2nic_reset)); | |
1034 | l2nic_reset.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1; | |
1035 | l2nic_reset.func_id = HINIC_HWIF_GLOBAL_IDX(hwif); | |
1036 | err = hinic_msg_to_mgmt_sync(hwdev, HINIC_MOD_COMM, | |
1037 | HINIC_MGMT_CMD_L2NIC_RESET, | |
1038 | &l2nic_reset, sizeof(l2nic_reset), | |
1039 | NULL, NULL, 0); | |
1040 | if (err || l2nic_reset.mgmt_msg_head.status) { | |
1041 | PMD_DRV_LOG(ERR, "Reset L2NIC resources failed"); | |
1042 | return -EFAULT; | |
1043 | } | |
1044 | ||
1045 | return 0; | |
1046 | } | |
1047 | ||
1048 | static void | |
1049 | hinic_show_sw_watchdog_timeout_info(void *buf_in, u16 in_size, | |
1050 | void *buf_out, u16 *out_size) | |
1051 | { | |
1052 | struct hinic_mgmt_watchdog_info *watchdog_info; | |
1053 | u32 *dump_addr, *reg, stack_len, i, j; | |
1054 | ||
1055 | if (in_size != sizeof(*watchdog_info)) { | |
1056 | PMD_DRV_LOG(ERR, "Invalid mgmt watchdog report, length: %d, should be %zu", | |
1057 | in_size, sizeof(*watchdog_info)); | |
1058 | return; | |
1059 | } | |
1060 | ||
1061 | watchdog_info = (struct hinic_mgmt_watchdog_info *)buf_in; | |
1062 | ||
1063 | PMD_DRV_LOG(ERR, "Mgmt deadloop time: 0x%x 0x%x, task id: 0x%x, sp: 0x%x", | |
1064 | watchdog_info->curr_time_h, watchdog_info->curr_time_l, | |
1065 | watchdog_info->task_id, watchdog_info->sp); | |
1066 | PMD_DRV_LOG(ERR, "Stack current used: 0x%x, peak used: 0x%x, overflow flag: 0x%x, top: 0x%x, bottom: 0x%x", | |
1067 | watchdog_info->curr_used, watchdog_info->peak_used, | |
1068 | watchdog_info->is_overflow, watchdog_info->stack_top, | |
1069 | watchdog_info->stack_bottom); | |
1070 | ||
1071 | PMD_DRV_LOG(ERR, "Mgmt pc: 0x%08x, lr: 0x%08x, cpsr: 0x%08x", | |
1072 | watchdog_info->pc, watchdog_info->lr, watchdog_info->cpsr); | |
1073 | ||
1074 | PMD_DRV_LOG(ERR, "Mgmt register info"); | |
1075 | ||
1076 | for (i = 0; i < 3; i++) { | |
1077 | reg = watchdog_info->reg + (u64)(u32)(4 * i); | |
1078 | PMD_DRV_LOG(ERR, "0x%08x 0x%08x 0x%08x 0x%08x", | |
1079 | *(reg), *(reg + 1), *(reg + 2), *(reg + 3)); | |
1080 | } | |
1081 | ||
1082 | PMD_DRV_LOG(ERR, "0x%08x", watchdog_info->reg[12]); | |
1083 | ||
1084 | if (watchdog_info->stack_actlen <= 1024) { | |
1085 | stack_len = watchdog_info->stack_actlen; | |
1086 | } else { | |
1087 | PMD_DRV_LOG(ERR, "Oops stack length: 0x%x is wrong", | |
1088 | watchdog_info->stack_actlen); | |
1089 | stack_len = 1024; | |
1090 | } | |
1091 | ||
1092 | PMD_DRV_LOG(ERR, "Mgmt dump stack, 16Bytes per line(start from sp)"); | |
1093 | for (i = 0; i < (stack_len / 16); i++) { | |
1094 | dump_addr = (u32 *)(watchdog_info->data + ((u64)(u32)(i * 16))); | |
1095 | PMD_DRV_LOG(ERR, "0x%08x 0x%08x 0x%08x 0x%08x", | |
1096 | *dump_addr, *(dump_addr + 1), *(dump_addr + 2), | |
1097 | *(dump_addr + 3)); | |
1098 | } | |
1099 | ||
1100 | for (j = 0; j < ((stack_len % 16) / 4); j++) { | |
1101 | dump_addr = (u32 *)(watchdog_info->data + | |
1102 | ((u64)(u32)(i * 16 + j * 4))); | |
1103 | PMD_DRV_LOG(ERR, "0x%08x", *dump_addr); | |
1104 | } | |
1105 | ||
1106 | *out_size = sizeof(*watchdog_info); | |
1107 | watchdog_info = (struct hinic_mgmt_watchdog_info *)buf_out; | |
1108 | watchdog_info->mgmt_msg_head.status = 0; | |
1109 | } | |
1110 | ||
1111 | static void hinic_show_pcie_dfx_info(struct hinic_hwdev *hwdev, | |
1112 | void *buf_in, u16 in_size, | |
1113 | void *buf_out, u16 *out_size) | |
1114 | { | |
1115 | struct hinic_pcie_dfx_ntc *notice_info = | |
1116 | (struct hinic_pcie_dfx_ntc *)buf_in; | |
1117 | struct hinic_pcie_dfx_info dfx_info; | |
1118 | u16 size = 0; | |
1119 | u16 cnt = 0; | |
1120 | u32 num = 0; | |
1121 | u32 i, j; | |
1122 | int err; | |
1123 | u32 *reg; | |
1124 | ||
1125 | if (in_size != sizeof(*notice_info)) { | |
1126 | PMD_DRV_LOG(ERR, "Invalid pcie dfx notice info, length: %d, should be %zu.", | |
1127 | in_size, sizeof(*notice_info)); | |
1128 | return; | |
1129 | } | |
1130 | ||
1131 | ((struct hinic_pcie_dfx_ntc *)buf_out)->mgmt_msg_head.status = 0; | |
1132 | *out_size = sizeof(*notice_info); | |
1133 | memset(&dfx_info, 0, sizeof(dfx_info)); | |
1134 | num = (u32)(notice_info->len / 1024); | |
1135 | PMD_DRV_LOG(INFO, "INFO LEN: %d", notice_info->len); | |
1136 | PMD_DRV_LOG(INFO, "PCIE DFX:"); | |
1137 | dfx_info.host_id = 0; | |
1138 | dfx_info.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1; | |
1139 | for (i = 0; i < num; i++) { | |
1140 | dfx_info.offset = i * MAX_PCIE_DFX_BUF_SIZE; | |
1141 | if (i == (num - 1)) | |
1142 | dfx_info.last = 1; | |
1143 | size = sizeof(dfx_info); | |
1144 | err = hinic_msg_to_mgmt_sync(hwdev, HINIC_MOD_COMM, | |
1145 | HINIC_MGMT_CMD_PCIE_DFX_GET, | |
1146 | &dfx_info, sizeof(dfx_info), | |
1147 | &dfx_info, &size, 0); | |
1148 | if (err || dfx_info.mgmt_msg_head.status || !size) { | |
1149 | PMD_DRV_LOG(ERR, "Failed to get pcie dfx info, err: %d, status: 0x%x, out size: 0x%x", | |
1150 | err, dfx_info.mgmt_msg_head.status, size); | |
1151 | return; | |
1152 | } | |
1153 | ||
1154 | reg = (u32 *)dfx_info.data; | |
1155 | for (j = 0; j < 256; j = j + 8) { | |
1156 | PMD_DRV_LOG(ERR, "0x%04x: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x", | |
1157 | cnt, reg[j], reg[(u32)(j + 1)], | |
1158 | reg[(u32)(j + 2)], reg[(u32)(j + 3)], | |
1159 | reg[(u32)(j + 4)], reg[(u32)(j + 5)], | |
1160 | reg[(u32)(j + 6)], reg[(u32)(j + 7)]); | |
1161 | cnt = cnt + 32; | |
1162 | } | |
1163 | memset(dfx_info.data, 0, MAX_PCIE_DFX_BUF_SIZE); | |
1164 | } | |
1165 | } | |
1166 | ||
1167 | static void | |
1168 | hinic_show_ffm_info(struct hinic_hwdev *hwdev, void *buf_in, u16 in_size) | |
1169 | { | |
1170 | struct ffm_intr_info *intr; | |
1171 | ||
1172 | if (in_size != sizeof(struct ffm_intr_info)) { | |
1173 | PMD_DRV_LOG(ERR, "Invalid input buffer len, length: %d, should be %zu.", | |
1174 | in_size, sizeof(struct ffm_intr_info)); | |
1175 | return; | |
1176 | } | |
1177 | ||
1178 | if (hwdev->ffm_num < FFM_RECORD_NUM_MAX) { | |
1179 | hwdev->ffm_num++; | |
1180 | intr = (struct ffm_intr_info *)buf_in; | |
1181 | PMD_DRV_LOG(WARNING, "node_id(%d),err_csr_addr(0x%x),err_csr_val(0x%x),err_level(0x%x),err_type(0x%x)", | |
1182 | intr->node_id, | |
1183 | intr->err_csr_addr, | |
1184 | intr->err_csr_value, | |
1185 | intr->err_level, | |
1186 | intr->err_type); | |
1187 | } | |
1188 | } | |
1189 | ||
1190 | void hinic_comm_async_event_handle(struct hinic_hwdev *hwdev, u8 cmd, | |
1191 | void *buf_in, u16 in_size, | |
1192 | void *buf_out, u16 *out_size) | |
1193 | { | |
1194 | struct hinic_cmd_fault_event *fault_event, *ret_fault_event; | |
1195 | ||
1196 | if (!hwdev) | |
1197 | return; | |
1198 | ||
1199 | *out_size = 0; | |
1200 | ||
1201 | switch (cmd) { | |
1202 | case HINIC_MGMT_CMD_FAULT_REPORT: | |
1203 | if (in_size != sizeof(*fault_event)) { | |
1204 | PMD_DRV_LOG(ERR, "Invalid fault event report, length: %d, should be %zu", | |
1205 | in_size, sizeof(*fault_event)); | |
1206 | return; | |
1207 | } | |
1208 | ||
1209 | fault_event = (struct hinic_cmd_fault_event *)buf_in; | |
1210 | fault_report_show(hwdev, &fault_event->event); | |
1211 | ||
1212 | if (hinic_func_type(hwdev) != TYPE_VF) { | |
1213 | ret_fault_event = | |
1214 | (struct hinic_cmd_fault_event *)buf_out; | |
1215 | ret_fault_event->mgmt_msg_head.status = 0; | |
1216 | *out_size = sizeof(*ret_fault_event); | |
1217 | } | |
1218 | break; | |
1219 | ||
1220 | case HINIC_MGMT_CMD_WATCHDOG_INFO: | |
1221 | hinic_show_sw_watchdog_timeout_info(buf_in, in_size, | |
1222 | buf_out, out_size); | |
1223 | break; | |
1224 | ||
1225 | case HINIC_MGMT_CMD_PCIE_DFX_NTC: | |
1226 | hinic_show_pcie_dfx_info(hwdev, buf_in, in_size, | |
1227 | buf_out, out_size); | |
1228 | break; | |
1229 | ||
1230 | case HINIC_MGMT_CMD_FFM_SET: | |
1231 | hinic_show_ffm_info(hwdev, buf_in, in_size); | |
1232 | break; | |
1233 | ||
1234 | default: | |
1235 | break; | |
1236 | } | |
1237 | } | |
1238 | ||
1239 | static void | |
1240 | hinic_cable_status_event(u8 cmd, void *buf_in, __rte_unused u16 in_size, | |
1241 | void *buf_out, u16 *out_size) | |
1242 | { | |
1243 | struct hinic_cable_plug_event *plug_event; | |
1244 | struct hinic_link_err_event *link_err; | |
1245 | ||
1246 | if (cmd == HINIC_PORT_CMD_CABLE_PLUG_EVENT) { | |
1247 | plug_event = (struct hinic_cable_plug_event *)buf_in; | |
1248 | PMD_DRV_LOG(INFO, "Port module event: Cable %s", | |
1249 | plug_event->plugged ? "plugged" : "unplugged"); | |
1250 | ||
1251 | *out_size = sizeof(*plug_event); | |
1252 | plug_event = (struct hinic_cable_plug_event *)buf_out; | |
1253 | plug_event->mgmt_msg_head.status = 0; | |
1254 | } else if (cmd == HINIC_PORT_CMD_LINK_ERR_EVENT) { | |
1255 | link_err = (struct hinic_link_err_event *)buf_in; | |
1256 | if (link_err->err_type >= LINK_ERR_NUM) { | |
1257 | PMD_DRV_LOG(ERR, "Link failed, Unknown type: 0x%x", | |
1258 | link_err->err_type); | |
1259 | } else { | |
1260 | PMD_DRV_LOG(INFO, "Link failed, type: 0x%x: %s", | |
1261 | link_err->err_type, | |
1262 | hinic_module_link_err[link_err->err_type]); | |
1263 | } | |
1264 | ||
1265 | *out_size = sizeof(*link_err); | |
1266 | link_err = (struct hinic_link_err_event *)buf_out; | |
1267 | link_err->mgmt_msg_head.status = 0; | |
1268 | } | |
1269 | } | |
1270 | ||
1271 | static int hinic_link_event_process(struct hinic_hwdev *hwdev, | |
1272 | struct rte_eth_dev *eth_dev, u8 status) | |
1273 | { | |
1274 | uint32_t port_speed[LINK_SPEED_MAX] = {ETH_SPEED_NUM_10M, | |
1275 | ETH_SPEED_NUM_100M, ETH_SPEED_NUM_1G, | |
1276 | ETH_SPEED_NUM_10G, ETH_SPEED_NUM_25G, | |
1277 | ETH_SPEED_NUM_40G, ETH_SPEED_NUM_100G}; | |
1278 | struct nic_port_info port_info; | |
1279 | struct rte_eth_link link; | |
1280 | int rc = HINIC_OK; | |
1281 | ||
1282 | if (!status) { | |
1283 | link.link_status = ETH_LINK_DOWN; | |
1284 | link.link_speed = 0; | |
1285 | link.link_duplex = ETH_LINK_HALF_DUPLEX; | |
1286 | link.link_autoneg = ETH_LINK_FIXED; | |
1287 | } else { | |
1288 | link.link_status = ETH_LINK_UP; | |
1289 | ||
1290 | memset(&port_info, 0, sizeof(port_info)); | |
1291 | rc = hinic_get_port_info(hwdev, &port_info); | |
1292 | if (rc) { | |
1293 | link.link_speed = ETH_SPEED_NUM_NONE; | |
1294 | link.link_duplex = ETH_LINK_FULL_DUPLEX; | |
1295 | link.link_autoneg = ETH_LINK_FIXED; | |
1296 | } else { | |
1297 | link.link_speed = port_speed[port_info.speed % | |
1298 | LINK_SPEED_MAX]; | |
1299 | link.link_duplex = port_info.duplex; | |
1300 | link.link_autoneg = port_info.autoneg_state; | |
1301 | } | |
1302 | } | |
1303 | (void)rte_eth_linkstatus_set(eth_dev, &link); | |
1304 | ||
1305 | return rc; | |
1306 | } | |
1307 | ||
1308 | static void hinic_lsc_process(struct hinic_hwdev *hwdev, | |
1309 | struct rte_eth_dev *rte_dev, u8 status) | |
1310 | { | |
1311 | int ret; | |
1312 | ||
1313 | ret = hinic_link_event_process(hwdev, rte_dev, status); | |
1314 | /* check if link has changed, notify callback */ | |
1315 | if (ret == 0) | |
1316 | _rte_eth_dev_callback_process(rte_dev, | |
1317 | RTE_ETH_EVENT_INTR_LSC, | |
1318 | NULL); | |
1319 | } | |
1320 | ||
1321 | void hinic_l2nic_async_event_handle(struct hinic_hwdev *hwdev, | |
1322 | void *param, u8 cmd, | |
1323 | void *buf_in, u16 in_size, | |
1324 | void *buf_out, u16 *out_size) | |
1325 | { | |
1326 | struct hinic_port_link_status *in_link; | |
1327 | struct rte_eth_dev *eth_dev; | |
1328 | ||
1329 | if (!hwdev) | |
1330 | return; | |
1331 | ||
1332 | *out_size = 0; | |
1333 | ||
1334 | switch (cmd) { | |
1335 | case HINIC_PORT_CMD_LINK_STATUS_REPORT: | |
1336 | eth_dev = param; | |
1337 | in_link = (struct hinic_port_link_status *)buf_in; | |
1338 | PMD_DRV_LOG(INFO, "Link status event report, dev_name: %s, port_id: %d, link_status: %s", | |
1339 | eth_dev->data->name, eth_dev->data->port_id, | |
1340 | in_link->link ? "UP" : "DOWN"); | |
1341 | ||
1342 | hinic_lsc_process(hwdev, eth_dev, in_link->link); | |
1343 | break; | |
1344 | ||
1345 | case HINIC_PORT_CMD_CABLE_PLUG_EVENT: | |
1346 | case HINIC_PORT_CMD_LINK_ERR_EVENT: | |
1347 | hinic_cable_status_event(cmd, buf_in, in_size, | |
1348 | buf_out, out_size); | |
1349 | break; | |
1350 | ||
1351 | case HINIC_PORT_CMD_MGMT_RESET: | |
1352 | PMD_DRV_LOG(WARNING, "Mgmt is reset"); | |
1353 | break; | |
1354 | ||
1355 | default: | |
1356 | PMD_DRV_LOG(ERR, "Unsupported event %d to process", | |
1357 | cmd); | |
1358 | break; | |
1359 | } | |
1360 | } | |
1361 | ||
1362 | static void print_cable_info(struct hinic_link_info *info) | |
1363 | { | |
1364 | char tmp_str[512] = {0}; | |
1365 | char tmp_vendor[17] = {0}; | |
1366 | const char *port_type = "Unknown port type"; | |
1367 | int i; | |
1368 | ||
1369 | if (info->cable_absent) { | |
1370 | PMD_DRV_LOG(INFO, "Cable unpresent"); | |
1371 | return; | |
1372 | } | |
1373 | ||
1374 | if (info->port_type < LINK_PORT_MAX_TYPE) | |
1375 | port_type = __hw_to_char_port_type[info->port_type]; | |
1376 | else | |
1377 | PMD_DRV_LOG(INFO, "Unknown port type: %u", | |
1378 | info->port_type); | |
1379 | if (info->port_type == LINK_PORT_FIBRE) { | |
1380 | if (info->port_sub_type == FIBRE_SUBTYPE_SR) | |
1381 | port_type = "Fibre-SR"; | |
1382 | else if (info->port_sub_type == FIBRE_SUBTYPE_LR) | |
1383 | port_type = "Fibre-LR"; | |
1384 | } | |
1385 | ||
1386 | for (i = sizeof(info->vendor_name) - 1; i >= 0; i--) { | |
1387 | if (info->vendor_name[i] == ' ') | |
1388 | info->vendor_name[i] = '\0'; | |
1389 | else | |
1390 | break; | |
1391 | } | |
1392 | ||
1393 | memcpy(tmp_vendor, info->vendor_name, sizeof(info->vendor_name)); | |
1394 | snprintf(tmp_str, sizeof(tmp_str), | |
1395 | "Vendor: %s, %s, %s, length: %um, max_speed: %uGbps", | |
1396 | tmp_vendor, info->sfp_type ? "SFP" : "QSFP", port_type, | |
1397 | info->cable_length, info->cable_max_speed); | |
1398 | if (info->port_type != LINK_PORT_COPPER) | |
1399 | snprintf(tmp_str + strlen(tmp_str), | |
1400 | sizeof(tmp_str) - strlen(tmp_str), | |
1401 | ", Temperature: %u", info->cable_temp); | |
1402 | ||
1403 | PMD_DRV_LOG(INFO, "Cable information: %s", tmp_str); | |
1404 | } | |
1405 | ||
1406 | static void print_hi30_status(struct hinic_link_info *info) | |
1407 | { | |
1408 | struct hi30_ffe_data *ffe_data; | |
1409 | struct hi30_ctle_data *ctle_data; | |
1410 | ||
1411 | ffe_data = (struct hi30_ffe_data *)info->hi30_ffe; | |
1412 | ctle_data = (struct hi30_ctle_data *)info->hi30_ctle; | |
1413 | ||
1414 | PMD_DRV_LOG(INFO, "TX_FFE: PRE2=%s%d; PRE1=%s%d; MAIN=%d; POST1=%s%d; POST1X=%s%d", | |
1415 | (ffe_data->PRE1 & 0x10) ? "-" : "", | |
1416 | (int)(ffe_data->PRE1 & 0xf), | |
1417 | (ffe_data->PRE2 & 0x10) ? "-" : "", | |
1418 | (int)(ffe_data->PRE2 & 0xf), | |
1419 | (int)ffe_data->MAIN, | |
1420 | (ffe_data->POST1 & 0x10) ? "-" : "", | |
1421 | (int)(ffe_data->POST1 & 0xf), | |
1422 | (ffe_data->POST2 & 0x10) ? "-" : "", | |
1423 | (int)(ffe_data->POST2 & 0xf)); | |
1424 | PMD_DRV_LOG(INFO, "RX_CTLE: Gain1~3=%u %u %u; Boost1~3=%u %u %u; Zero1~3=%u %u %u; Squelch1~3=%u %u %u", | |
1425 | ctle_data->ctlebst[0], ctle_data->ctlebst[1], | |
1426 | ctle_data->ctlebst[2], ctle_data->ctlecmband[0], | |
1427 | ctle_data->ctlecmband[1], ctle_data->ctlecmband[2], | |
1428 | ctle_data->ctlermband[0], ctle_data->ctlermband[1], | |
1429 | ctle_data->ctlermband[2], ctle_data->ctleza[0], | |
1430 | ctle_data->ctleza[1], ctle_data->ctleza[2]); | |
1431 | } | |
1432 | ||
1433 | static void print_link_info(struct hinic_link_info *info, | |
1434 | enum hilink_info_print_event type) | |
1435 | { | |
1436 | const char *fec = "None"; | |
1437 | ||
1438 | if (info->fec < HILINK_FEC_MAX_TYPE) | |
1439 | fec = __hw_to_char_fec[info->fec]; | |
1440 | else | |
1441 | PMD_DRV_LOG(INFO, "Unknown fec type: %u", | |
1442 | info->fec); | |
1443 | ||
1444 | if (type == HILINK_EVENT_LINK_UP || !info->an_state) { | |
1445 | PMD_DRV_LOG(INFO, "Link information: speed %dGbps, %s, autoneg %s", | |
1446 | info->speed, fec, info->an_state ? "on" : "off"); | |
1447 | } else { | |
1448 | PMD_DRV_LOG(INFO, "Link information: antoneg: %s", | |
1449 | info->an_state ? "on" : "off"); | |
1450 | } | |
1451 | } | |
1452 | ||
1453 | static const char *hilink_info_report_type[HILINK_EVENT_MAX_TYPE] = { | |
1454 | "", "link up", "link down", "cable plugged" | |
1455 | }; | |
1456 | ||
1457 | static void hinic_print_hilink_info(void *buf_in, u16 in_size, | |
1458 | void *buf_out, u16 *out_size) | |
1459 | { | |
1460 | struct hinic_hilink_link_info *hilink_info = | |
1461 | (struct hinic_hilink_link_info *)buf_in; | |
1462 | struct hinic_link_info *info; | |
1463 | enum hilink_info_print_event type; | |
1464 | ||
1465 | if (in_size != sizeof(*hilink_info)) { | |
1466 | PMD_DRV_LOG(ERR, "Invalid hilink info message size %d, should be %zu", | |
1467 | in_size, sizeof(*hilink_info)); | |
1468 | return; | |
1469 | } | |
1470 | ||
1471 | ((struct hinic_hilink_link_info *)buf_out)->mgmt_msg_head.status = 0; | |
1472 | *out_size = sizeof(*hilink_info); | |
1473 | ||
1474 | info = &hilink_info->info; | |
1475 | type = hilink_info->info_type; | |
1476 | ||
1477 | if (type < HILINK_EVENT_LINK_UP || type >= HILINK_EVENT_MAX_TYPE) { | |
1478 | PMD_DRV_LOG(INFO, "Invalid hilink info report, type: %d", | |
1479 | type); | |
1480 | return; | |
1481 | } | |
1482 | ||
1483 | PMD_DRV_LOG(INFO, "Hilink info report after %s", | |
1484 | hilink_info_report_type[type]); | |
1485 | ||
1486 | print_cable_info(info); | |
1487 | ||
1488 | print_link_info(info, type); | |
1489 | ||
1490 | print_hi30_status(info); | |
1491 | ||
1492 | if (type == HILINK_EVENT_LINK_UP) | |
1493 | return; | |
1494 | ||
1495 | if (type == HILINK_EVENT_CABLE_PLUGGED) { | |
1496 | PMD_DRV_LOG(INFO, "alos: %u, rx_los: %u", | |
1497 | info->alos, info->rx_los); | |
1498 | return; | |
1499 | } | |
1500 | ||
1501 | PMD_DRV_LOG(INFO, "PMA ctrl: %s, MAC tx %s, MAC rx %s, PMA debug inforeg: 0x%x, PMA signal ok reg: 0x%x, RF/LF status reg: 0x%x", | |
1502 | info->pma_status ? "on" : "off", | |
1503 | info->mac_tx_en ? "enable" : "disable", | |
1504 | info->mac_rx_en ? "enable" : "disable", info->pma_dbg_info_reg, | |
1505 | info->pma_signal_ok_reg, info->rf_lf_status_reg); | |
1506 | PMD_DRV_LOG(INFO, "alos: %u, rx_los: %u, PCS block counter reg: 0x%x,PCS link: 0x%x, MAC link: 0x%x PCS_err_cnt: 0x%x", | |
1507 | info->alos, info->rx_los, info->pcs_err_blk_cnt_reg, | |
1508 | info->pcs_link_reg, info->mac_link_reg, info->pcs_err_cnt); | |
1509 | } | |
1510 | ||
1511 | void hinic_hilink_async_event_handle(struct hinic_hwdev *hwdev, u8 cmd, | |
1512 | void *buf_in, u16 in_size, | |
1513 | void *buf_out, u16 *out_size) | |
1514 | { | |
1515 | if (!hwdev) | |
1516 | return; | |
1517 | ||
1518 | *out_size = 0; | |
1519 | ||
1520 | switch (cmd) { | |
1521 | case HINIC_HILINK_CMD_GET_LINK_INFO: | |
1522 | hinic_print_hilink_info(buf_in, in_size, buf_out, | |
1523 | out_size); | |
1524 | break; | |
1525 | ||
1526 | default: | |
1527 | PMD_DRV_LOG(ERR, "Unsupported event %d to process", | |
1528 | cmd); | |
1529 | break; | |
1530 | } | |
1531 | } |