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