Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

qed*: enhance tx timeout debug info

This patch add some new qed APIs to query status block
info and report various data to MFW on tx timeout event

Along with that it enhances qede to dump more debug logs
(not just specific to the queue which was reported by stack)
on tx timeout which includes various other basic metadata about
all tx queues and other info (like status block etc.)

Signed-off-by: Manish Chopra <manishc@marvell.com>
Signed-off-by: Prabhakar Kushwaha <pkushwaha@marvell.com>
Signed-off-by: Alok Prasad <palok@marvell.com>
Signed-off-by: Ariel Elior <aelior@marvell.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Manish Chopra and committed by
Jakub Kicinski
0cc3a801 bb14bfc7

+173 -15
+22
drivers/net/ethernet/qlogic/qed/qed_int.c
··· 2399 2399 2400 2400 return rc; 2401 2401 } 2402 + 2403 + int qed_int_get_sb_dbg(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, 2404 + struct qed_sb_info *p_sb, struct qed_sb_info_dbg *p_info) 2405 + { 2406 + u16 sbid = p_sb->igu_sb_id; 2407 + u32 i; 2408 + 2409 + if (IS_VF(p_hwfn->cdev)) 2410 + return -EINVAL; 2411 + 2412 + if (sbid >= NUM_OF_SBS(p_hwfn->cdev)) 2413 + return -EINVAL; 2414 + 2415 + p_info->igu_prod = qed_rd(p_hwfn, p_ptt, IGU_REG_PRODUCER_MEMORY + sbid * 4); 2416 + p_info->igu_cons = qed_rd(p_hwfn, p_ptt, IGU_REG_CONSUMER_MEM + sbid * 4); 2417 + 2418 + for (i = 0; i < PIS_PER_SB; i++) 2419 + p_info->pi[i] = (u16)qed_rd(p_hwfn, p_ptt, 2420 + CAU_REG_PI_MEMORY + sbid * 4 * PIS_PER_SB + i * 4); 2421 + 2422 + return 0; 2423 + }
+13
drivers/net/ethernet/qlogic/qed/qed_int.h
··· 186 186 void qed_int_attn_clr_enable(struct qed_dev *cdev, bool clr_enable); 187 187 188 188 /** 189 + * qed_int_get_sb_dbg: Read debug information regarding a given SB 190 + * 191 + * @p_hwfn: hw function pointer 192 + * @p_ptt: ptt resource 193 + * @p_sb: pointer to status block for which we want to get info 194 + * @p_info: pointer to struct to fill with information regarding SB 195 + * 196 + * Return: 0 with status block info filled on success, otherwise return error 197 + */ 198 + int qed_int_get_sb_dbg(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, 199 + struct qed_sb_info *p_sb, struct qed_sb_info_dbg *p_info); 200 + 201 + /** 189 202 * qed_db_rec_handler(): Doorbell Recovery handler. 190 203 * Run doorbell recovery in case of PF overflow (and flush DORQ if 191 204 * needed).
+47
drivers/net/ethernet/qlogic/qed/qed_main.c
··· 2936 2936 return status; 2937 2937 } 2938 2938 2939 + static int 2940 + qed_get_sb_info(struct qed_dev *cdev, struct qed_sb_info *sb, 2941 + u16 qid, struct qed_sb_info_dbg *sb_dbg) 2942 + { 2943 + struct qed_hwfn *hwfn = &cdev->hwfns[qid % cdev->num_hwfns]; 2944 + struct qed_ptt *ptt; 2945 + int rc; 2946 + 2947 + if (IS_VF(cdev)) 2948 + return -EINVAL; 2949 + 2950 + ptt = qed_ptt_acquire(hwfn); 2951 + if (!ptt) { 2952 + DP_NOTICE(hwfn, "Can't acquire PTT\n"); 2953 + return -EAGAIN; 2954 + } 2955 + 2956 + memset(sb_dbg, 0, sizeof(*sb_dbg)); 2957 + rc = qed_int_get_sb_dbg(hwfn, ptt, sb, sb_dbg); 2958 + 2959 + qed_ptt_release(hwfn, ptt); 2960 + return rc; 2961 + } 2962 + 2939 2963 static int qed_read_module_eeprom(struct qed_dev *cdev, char *buf, 2940 2964 u8 dev_addr, u32 offset, u32 len) 2941 2965 { ··· 3000 2976 qed_ptt_release(hwfn, ptt); 3001 2977 3002 2978 return rc; 2979 + } 2980 + 2981 + static __printf(2, 3) void qed_mfw_report(struct qed_dev *cdev, char *fmt, ...) 2982 + { 2983 + char buf[QED_MFW_REPORT_STR_SIZE]; 2984 + struct qed_hwfn *p_hwfn; 2985 + struct qed_ptt *p_ptt; 2986 + va_list vl; 2987 + 2988 + va_start(vl, fmt); 2989 + vsnprintf(buf, QED_MFW_REPORT_STR_SIZE, fmt, vl); 2990 + va_end(vl); 2991 + 2992 + if (IS_PF(cdev)) { 2993 + p_hwfn = QED_LEADING_HWFN(cdev); 2994 + p_ptt = qed_ptt_acquire(p_hwfn); 2995 + if (p_ptt) { 2996 + qed_mcp_send_raw_debug_data(p_hwfn, p_ptt, buf, strlen(buf)); 2997 + qed_ptt_release(p_hwfn, p_ptt); 2998 + } 2999 + } 3003 3000 } 3004 3001 3005 3002 static u8 qed_get_affin_hwfn_idx(struct qed_dev *cdev) ··· 3083 3038 .read_nvm_cfg = &qed_nvm_flash_cfg_read, 3084 3039 .read_nvm_cfg_len = &qed_nvm_flash_cfg_len, 3085 3040 .set_grc_config = &qed_set_grc_config, 3041 + .mfw_report = &qed_mfw_report, 3042 + .get_sb_info = &qed_get_sb_info, 3086 3043 }; 3087 3044 3088 3045 void qed_get_protocol_stats(struct qed_dev *cdev,
+2
drivers/net/ethernet/qlogic/qed/qed_mcp.h
··· 15 15 #include "qed_hsi.h" 16 16 #include "qed_dev_api.h" 17 17 18 + #define QED_MFW_REPORT_STR_SIZE 256 19 + 18 20 struct qed_mcp_link_speed_params { 19 21 bool autoneg; 20 22
+2
drivers/net/ethernet/qlogic/qed/qed_reg_addr.h
··· 550 550 0x1 << 1) 551 551 #define IGU_REG_BLOCK_CONFIGURATION_PXP_TPH_INTERFACE_EN ( \ 552 552 0x1 << 0) 553 + #define IGU_REG_PRODUCER_MEMORY 0x182000UL 554 + #define IGU_REG_CONSUMER_MEM 0x183000UL 553 555 #define IGU_REG_MAPPING_MEMORY \ 554 556 0x184000UL 555 557 #define IGU_REG_STATISTIC_NUM_VF_MSG_SENT \
+76 -15
drivers/net/ethernet/qlogic/qede/qede_main.c
··· 509 509 return 0; 510 510 } 511 511 512 - static void qede_tx_log_print(struct qede_dev *edev, struct qede_tx_queue *txq) 512 + static void qede_fp_sb_dump(struct qede_dev *edev, struct qede_fastpath *fp) 513 513 { 514 + char *p_sb = (char *)fp->sb_info->sb_virt; 515 + u32 sb_size, i; 516 + 517 + sb_size = sizeof(struct status_block); 518 + 519 + for (i = 0; i < sb_size; i += 8) 520 + DP_NOTICE(edev, 521 + "%02hhX %02hhX %02hhX %02hhX %02hhX %02hhX %02hhX %02hhX\n", 522 + p_sb[i], p_sb[i + 1], p_sb[i + 2], p_sb[i + 3], 523 + p_sb[i + 4], p_sb[i + 5], p_sb[i + 6], p_sb[i + 7]); 524 + } 525 + 526 + static void 527 + qede_txq_fp_log_metadata(struct qede_dev *edev, 528 + struct qede_fastpath *fp, struct qede_tx_queue *txq) 529 + { 530 + struct qed_chain *p_chain = &txq->tx_pbl; 531 + 532 + /* Dump txq/fp/sb ids etc. other metadata */ 514 533 DP_NOTICE(edev, 515 - "Txq[%d]: FW cons [host] %04x, SW cons %04x, SW prod %04x [Jiffies %lu]\n", 516 - txq->index, le16_to_cpu(*txq->hw_cons_ptr), 517 - qed_chain_get_cons_idx(&txq->tx_pbl), 518 - qed_chain_get_prod_idx(&txq->tx_pbl), 519 - jiffies); 534 + "fpid 0x%x sbid 0x%x txqid [0x%x] ndev_qid [0x%x] cos [0x%x] p_chain %p cap %d size %d jiffies %lu HZ 0x%x\n", 535 + fp->id, fp->sb_info->igu_sb_id, txq->index, txq->ndev_txq_id, txq->cos, 536 + p_chain, p_chain->capacity, p_chain->size, jiffies, HZ); 537 + 538 + /* Dump all the relevant prod/cons indexes */ 539 + DP_NOTICE(edev, 540 + "hw cons %04x sw_tx_prod=0x%x, sw_tx_cons=0x%x, bd_prod 0x%x bd_cons 0x%x\n", 541 + le16_to_cpu(*txq->hw_cons_ptr), txq->sw_tx_prod, txq->sw_tx_cons, 542 + qed_chain_get_prod_idx(p_chain), qed_chain_get_cons_idx(p_chain)); 543 + } 544 + 545 + static void 546 + qede_tx_log_print(struct qede_dev *edev, struct qede_fastpath *fp, struct qede_tx_queue *txq) 547 + { 548 + struct qed_sb_info_dbg sb_dbg; 549 + int rc; 550 + 551 + /* sb info */ 552 + qede_fp_sb_dump(edev, fp); 553 + 554 + memset(&sb_dbg, 0, sizeof(sb_dbg)); 555 + rc = edev->ops->common->get_sb_info(edev->cdev, fp->sb_info, (u16)fp->id, &sb_dbg); 556 + 557 + DP_NOTICE(edev, "IGU: prod %08x cons %08x CAU Tx %04x\n", 558 + sb_dbg.igu_prod, sb_dbg.igu_cons, sb_dbg.pi[TX_PI(txq->cos)]); 559 + 560 + /* report to mfw */ 561 + edev->ops->common->mfw_report(edev->cdev, 562 + "Txq[%d]: FW cons [host] %04x, SW cons %04x, SW prod %04x [Jiffies %lu]\n", 563 + txq->index, le16_to_cpu(*txq->hw_cons_ptr), 564 + qed_chain_get_cons_idx(&txq->tx_pbl), 565 + qed_chain_get_prod_idx(&txq->tx_pbl), jiffies); 566 + if (!rc) 567 + edev->ops->common->mfw_report(edev->cdev, 568 + "Txq[%d]: SB[0x%04x] - IGU: prod %08x cons %08x CAU Tx %04x\n", 569 + txq->index, fp->sb_info->igu_sb_id, 570 + sb_dbg.igu_prod, sb_dbg.igu_cons, 571 + sb_dbg.pi[TX_PI(txq->cos)]); 520 572 } 521 573 522 574 static void qede_tx_timeout(struct net_device *dev, unsigned int txqueue) 523 575 { 524 576 struct qede_dev *edev = netdev_priv(dev); 525 - struct qede_tx_queue *txq; 526 - int cos; 577 + int i; 527 578 528 579 netif_carrier_off(dev); 529 580 DP_NOTICE(edev, "TX timeout on queue %u!\n", txqueue); 530 581 531 - if (!(edev->fp_array[txqueue].type & QEDE_FASTPATH_TX)) 532 - return; 582 + for_each_queue(i) { 583 + struct qede_tx_queue *txq; 584 + struct qede_fastpath *fp; 585 + int cos; 533 586 534 - for_each_cos_in_txq(edev, cos) { 535 - txq = &edev->fp_array[txqueue].txq[cos]; 587 + fp = &edev->fp_array[i]; 588 + if (!(fp->type & QEDE_FASTPATH_TX)) 589 + continue; 536 590 537 - if (qed_chain_get_cons_idx(&txq->tx_pbl) != 538 - qed_chain_get_prod_idx(&txq->tx_pbl)) 539 - qede_tx_log_print(edev, txq); 591 + for_each_cos_in_txq(edev, cos) { 592 + txq = &fp->txq[cos]; 593 + 594 + /* Dump basic metadata for all queues */ 595 + qede_txq_fp_log_metadata(edev, fp, txq); 596 + 597 + if (qed_chain_get_cons_idx(&txq->tx_pbl) != 598 + qed_chain_get_prod_idx(&txq->tx_pbl)) 599 + qede_tx_log_print(edev, fp, txq); 600 + } 540 601 } 541 602 542 603 if (IS_VF(edev))
+11
include/linux/qed/qed_if.h
··· 807 807 struct devlink_health_reporter *fw_reporter; 808 808 }; 809 809 810 + struct qed_sb_info_dbg { 811 + u32 igu_prod; 812 + u32 igu_cons; 813 + u16 pi[PIS_PER_SB]; 814 + }; 815 + 810 816 struct qed_common_cb_ops { 811 817 void (*arfs_filter_op)(void *dev, void *fltr, u8 fw_rc); 812 818 void (*link_update)(void *dev, struct qed_link_output *link); ··· 1200 1194 struct devlink* (*devlink_register)(struct qed_dev *cdev); 1201 1195 1202 1196 void (*devlink_unregister)(struct devlink *devlink); 1197 + 1198 + __printf(2, 3) void (*mfw_report)(struct qed_dev *cdev, char *fmt, ...); 1199 + 1200 + int (*get_sb_info)(struct qed_dev *cdev, struct qed_sb_info *sb, 1201 + u16 qid, struct qed_sb_info_dbg *sb_dbg); 1203 1202 }; 1204 1203 1205 1204 #define MASK_FIELD(_name, _value) \