mirror of
https://github.com/torvalds/linux.git
synced 2024-11-26 06:02:05 +00:00
Merge branch 'qed-enhancements'
Manish Chopra says: ==================== qed*: enhancements This series adds below enhancements for qed/qede drivers patch 1: Improves tx timeout debug data logs. patch 2: Add ESL(Enhanced system lockdown) priv flag cap/status support. v2: * Fixed cosmetic issues in both patches * Added ESL feature description in patch #2 Please consider applying it to "net-next" ==================== Link: https://lore.kernel.org/r/20211202210157.25530-1-manishc@marvell.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
ce83278f31
@ -2399,3 +2399,25 @@ int qed_int_set_timer_res(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt,
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int qed_int_get_sb_dbg(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt,
|
||||
struct qed_sb_info *p_sb, struct qed_sb_info_dbg *p_info)
|
||||
{
|
||||
u16 sbid = p_sb->igu_sb_id;
|
||||
u32 i;
|
||||
|
||||
if (IS_VF(p_hwfn->cdev))
|
||||
return -EINVAL;
|
||||
|
||||
if (sbid >= NUM_OF_SBS(p_hwfn->cdev))
|
||||
return -EINVAL;
|
||||
|
||||
p_info->igu_prod = qed_rd(p_hwfn, p_ptt, IGU_REG_PRODUCER_MEMORY + sbid * 4);
|
||||
p_info->igu_cons = qed_rd(p_hwfn, p_ptt, IGU_REG_CONSUMER_MEM + sbid * 4);
|
||||
|
||||
for (i = 0; i < PIS_PER_SB; i++)
|
||||
p_info->pi[i] = (u16)qed_rd(p_hwfn, p_ptt,
|
||||
CAU_REG_PI_MEMORY + sbid * 4 * PIS_PER_SB + i * 4);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -185,6 +185,19 @@ void qed_int_disable_post_isr_release(struct qed_dev *cdev);
|
||||
*/
|
||||
void qed_int_attn_clr_enable(struct qed_dev *cdev, bool clr_enable);
|
||||
|
||||
/**
|
||||
* qed_int_get_sb_dbg: Read debug information regarding a given SB
|
||||
*
|
||||
* @p_hwfn: hw function pointer
|
||||
* @p_ptt: ptt resource
|
||||
* @p_sb: pointer to status block for which we want to get info
|
||||
* @p_info: pointer to struct to fill with information regarding SB
|
||||
*
|
||||
* Return: 0 with status block info filled on success, otherwise return error
|
||||
*/
|
||||
int qed_int_get_sb_dbg(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt,
|
||||
struct qed_sb_info *p_sb, struct qed_sb_info_dbg *p_info);
|
||||
|
||||
/**
|
||||
* qed_db_rec_handler(): Doorbell Recovery handler.
|
||||
* Run doorbell recovery in case of PF overflow (and flush DORQ if
|
||||
|
@ -447,7 +447,7 @@ int qed_fill_dev_info(struct qed_dev *cdev,
|
||||
dev_info->wol_support = true;
|
||||
|
||||
dev_info->smart_an = qed_mcp_is_smart_an_supported(p_hwfn);
|
||||
|
||||
dev_info->esl = qed_mcp_is_esl_supported(p_hwfn);
|
||||
dev_info->abs_pf_id = QED_LEADING_HWFN(cdev)->abs_pf_id;
|
||||
} else {
|
||||
qed_vf_get_fw_version(&cdev->hwfns[0], &dev_info->fw_major,
|
||||
@ -2936,6 +2936,30 @@ out:
|
||||
return status;
|
||||
}
|
||||
|
||||
static int
|
||||
qed_get_sb_info(struct qed_dev *cdev, struct qed_sb_info *sb,
|
||||
u16 qid, struct qed_sb_info_dbg *sb_dbg)
|
||||
{
|
||||
struct qed_hwfn *hwfn = &cdev->hwfns[qid % cdev->num_hwfns];
|
||||
struct qed_ptt *ptt;
|
||||
int rc;
|
||||
|
||||
if (IS_VF(cdev))
|
||||
return -EINVAL;
|
||||
|
||||
ptt = qed_ptt_acquire(hwfn);
|
||||
if (!ptt) {
|
||||
DP_NOTICE(hwfn, "Can't acquire PTT\n");
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
memset(sb_dbg, 0, sizeof(*sb_dbg));
|
||||
rc = qed_int_get_sb_dbg(hwfn, ptt, sb, sb_dbg);
|
||||
|
||||
qed_ptt_release(hwfn, ptt);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int qed_read_module_eeprom(struct qed_dev *cdev, char *buf,
|
||||
u8 dev_addr, u32 offset, u32 len)
|
||||
{
|
||||
@ -2978,11 +3002,54 @@ static int qed_set_grc_config(struct qed_dev *cdev, u32 cfg_id, u32 val)
|
||||
return rc;
|
||||
}
|
||||
|
||||
static __printf(2, 3) void qed_mfw_report(struct qed_dev *cdev, char *fmt, ...)
|
||||
{
|
||||
char buf[QED_MFW_REPORT_STR_SIZE];
|
||||
struct qed_hwfn *p_hwfn;
|
||||
struct qed_ptt *p_ptt;
|
||||
va_list vl;
|
||||
|
||||
va_start(vl, fmt);
|
||||
vsnprintf(buf, QED_MFW_REPORT_STR_SIZE, fmt, vl);
|
||||
va_end(vl);
|
||||
|
||||
if (IS_PF(cdev)) {
|
||||
p_hwfn = QED_LEADING_HWFN(cdev);
|
||||
p_ptt = qed_ptt_acquire(p_hwfn);
|
||||
if (p_ptt) {
|
||||
qed_mcp_send_raw_debug_data(p_hwfn, p_ptt, buf, strlen(buf));
|
||||
qed_ptt_release(p_hwfn, p_ptt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static u8 qed_get_affin_hwfn_idx(struct qed_dev *cdev)
|
||||
{
|
||||
return QED_AFFIN_HWFN_IDX(cdev);
|
||||
}
|
||||
|
||||
static int qed_get_esl_status(struct qed_dev *cdev, bool *esl_active)
|
||||
{
|
||||
struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev);
|
||||
struct qed_ptt *ptt;
|
||||
int rc = 0;
|
||||
|
||||
*esl_active = false;
|
||||
|
||||
if (IS_VF(cdev))
|
||||
return 0;
|
||||
|
||||
ptt = qed_ptt_acquire(hwfn);
|
||||
if (!ptt)
|
||||
return -EAGAIN;
|
||||
|
||||
rc = qed_mcp_get_esl_status(hwfn, ptt, esl_active);
|
||||
|
||||
qed_ptt_release(hwfn, ptt);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static struct qed_selftest_ops qed_selftest_ops_pass = {
|
||||
.selftest_memory = &qed_selftest_memory,
|
||||
.selftest_interrupt = &qed_selftest_interrupt,
|
||||
@ -3038,6 +3105,9 @@ const struct qed_common_ops qed_common_ops_pass = {
|
||||
.read_nvm_cfg = &qed_nvm_flash_cfg_read,
|
||||
.read_nvm_cfg_len = &qed_nvm_flash_cfg_len,
|
||||
.set_grc_config = &qed_set_grc_config,
|
||||
.mfw_report = &qed_mfw_report,
|
||||
.get_sb_info = &qed_get_sb_info,
|
||||
.get_esl_status = &qed_get_esl_status,
|
||||
};
|
||||
|
||||
void qed_get_protocol_stats(struct qed_dev *cdev,
|
||||
|
@ -4158,3 +4158,25 @@ qed_mcp_send_raw_debug_data(struct qed_hwfn *p_hwfn,
|
||||
return qed_mcp_send_debug_data(p_hwfn, p_ptt,
|
||||
QED_MCP_DBG_DATA_TYPE_RAW, p_buf, size);
|
||||
}
|
||||
|
||||
bool qed_mcp_is_esl_supported(struct qed_hwfn *p_hwfn)
|
||||
{
|
||||
return !!(p_hwfn->mcp_info->capabilities &
|
||||
FW_MB_PARAM_FEATURE_SUPPORT_ENHANCED_SYS_LCK);
|
||||
}
|
||||
|
||||
int qed_mcp_get_esl_status(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, bool *active)
|
||||
{
|
||||
u32 resp = 0, param = 0;
|
||||
int rc;
|
||||
|
||||
rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_GET_MANAGEMENT_STATUS, 0, &resp, ¶m);
|
||||
if (rc) {
|
||||
DP_NOTICE(p_hwfn, "Failed to send ESL command, rc = %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
*active = !!(param & FW_MB_PARAM_MANAGEMENT_STATUS_LOCKDOWN_ENABLED);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -15,6 +15,8 @@
|
||||
#include "qed_hsi.h"
|
||||
#include "qed_dev_api.h"
|
||||
|
||||
#define QED_MFW_REPORT_STR_SIZE 256
|
||||
|
||||
struct qed_mcp_link_speed_params {
|
||||
bool autoneg;
|
||||
|
||||
@ -1337,4 +1339,24 @@ int qed_mcp_nvm_get_cfg(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt,
|
||||
int qed_mcp_nvm_set_cfg(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt,
|
||||
u16 option_id, u8 entity_id, u16 flags, u8 *p_buf,
|
||||
u32 len);
|
||||
|
||||
/**
|
||||
* qed_mcp_is_esl_supported(): Return whether management firmware support ESL or not.
|
||||
*
|
||||
* @p_hwfn: hw function pointer
|
||||
*
|
||||
* Return: true if esl is supported, otherwise return false
|
||||
*/
|
||||
bool qed_mcp_is_esl_supported(struct qed_hwfn *p_hwfn);
|
||||
|
||||
/**
|
||||
* qed_mcp_get_esl_status(): Get enhanced system lockdown status
|
||||
*
|
||||
* @p_hwfn: hw function pointer
|
||||
* @p_ptt: ptt resource pointer
|
||||
* @active: ESL active status data pointer
|
||||
*
|
||||
* Return: 0 with esl status info on success, otherwise return error
|
||||
*/
|
||||
int qed_mcp_get_esl_status(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, bool *active);
|
||||
#endif
|
||||
|
@ -1191,6 +1191,7 @@ enum drv_msg_code_enum {
|
||||
DRV_MSG_CODE_CFG_VF_MSIX = DRV_MSG_CODE(0xc001),
|
||||
DRV_MSG_CODE_CFG_PF_VFS_MSIX = DRV_MSG_CODE(0xc002),
|
||||
DRV_MSG_CODE_DEBUG_DATA_SEND = DRV_MSG_CODE(0xc004),
|
||||
DRV_MSG_CODE_GET_MANAGEMENT_STATUS = DRV_MSG_CODE(0xc007),
|
||||
};
|
||||
|
||||
#define DRV_MSG_CODE_VMAC_TYPE_SHIFT 4
|
||||
|
@ -550,6 +550,8 @@
|
||||
0x1 << 1)
|
||||
#define IGU_REG_BLOCK_CONFIGURATION_PXP_TPH_INTERFACE_EN ( \
|
||||
0x1 << 0)
|
||||
#define IGU_REG_PRODUCER_MEMORY 0x182000UL
|
||||
#define IGU_REG_CONSUMER_MEM 0x183000UL
|
||||
#define IGU_REG_MAPPING_MEMORY \
|
||||
0x184000UL
|
||||
#define IGU_REG_STATISTIC_NUM_VF_MSG_SENT \
|
||||
|
@ -168,6 +168,8 @@ enum {
|
||||
QEDE_PRI_FLAG_CMT,
|
||||
QEDE_PRI_FLAG_SMART_AN_SUPPORT, /* MFW supports SmartAN */
|
||||
QEDE_PRI_FLAG_RECOVER_ON_ERROR,
|
||||
QEDE_PRI_FLAG_ESL_SUPPORT, /* MFW supports Enhanced System Lockdown */
|
||||
QEDE_PRI_FLAG_ESL_ACTIVE, /* Enhanced System Lockdown Active status */
|
||||
QEDE_PRI_FLAG_LEN,
|
||||
};
|
||||
|
||||
@ -175,6 +177,8 @@ static const char qede_private_arr[QEDE_PRI_FLAG_LEN][ETH_GSTRING_LEN] = {
|
||||
"Coupled-Function",
|
||||
"SmartAN capable",
|
||||
"Recover on error",
|
||||
"ESL capable",
|
||||
"ESL active",
|
||||
};
|
||||
|
||||
enum qede_ethtool_tests {
|
||||
@ -478,6 +482,7 @@ static int qede_get_sset_count(struct net_device *dev, int stringset)
|
||||
static u32 qede_get_priv_flags(struct net_device *dev)
|
||||
{
|
||||
struct qede_dev *edev = netdev_priv(dev);
|
||||
bool esl_active;
|
||||
u32 flags = 0;
|
||||
|
||||
if (edev->dev_info.common.num_hwfns > 1)
|
||||
@ -489,6 +494,14 @@ static u32 qede_get_priv_flags(struct net_device *dev)
|
||||
if (edev->err_flags & BIT(QEDE_ERR_IS_RECOVERABLE))
|
||||
flags |= BIT(QEDE_PRI_FLAG_RECOVER_ON_ERROR);
|
||||
|
||||
if (edev->dev_info.common.esl)
|
||||
flags |= BIT(QEDE_PRI_FLAG_ESL_SUPPORT);
|
||||
|
||||
edev->ops->common->get_esl_status(edev->cdev, &esl_active);
|
||||
|
||||
if (esl_active)
|
||||
flags |= BIT(QEDE_PRI_FLAG_ESL_ACTIVE);
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
|
@ -509,34 +509,95 @@ static int qede_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void qede_tx_log_print(struct qede_dev *edev, struct qede_tx_queue *txq)
|
||||
static void qede_fp_sb_dump(struct qede_dev *edev, struct qede_fastpath *fp)
|
||||
{
|
||||
char *p_sb = (char *)fp->sb_info->sb_virt;
|
||||
u32 sb_size, i;
|
||||
|
||||
sb_size = sizeof(struct status_block);
|
||||
|
||||
for (i = 0; i < sb_size; i += 8)
|
||||
DP_NOTICE(edev,
|
||||
"%02hhX %02hhX %02hhX %02hhX %02hhX %02hhX %02hhX %02hhX\n",
|
||||
p_sb[i], p_sb[i + 1], p_sb[i + 2], p_sb[i + 3],
|
||||
p_sb[i + 4], p_sb[i + 5], p_sb[i + 6], p_sb[i + 7]);
|
||||
}
|
||||
|
||||
static void
|
||||
qede_txq_fp_log_metadata(struct qede_dev *edev,
|
||||
struct qede_fastpath *fp, struct qede_tx_queue *txq)
|
||||
{
|
||||
struct qed_chain *p_chain = &txq->tx_pbl;
|
||||
|
||||
/* Dump txq/fp/sb ids etc. other metadata */
|
||||
DP_NOTICE(edev,
|
||||
"Txq[%d]: FW cons [host] %04x, SW cons %04x, SW prod %04x [Jiffies %lu]\n",
|
||||
txq->index, le16_to_cpu(*txq->hw_cons_ptr),
|
||||
qed_chain_get_cons_idx(&txq->tx_pbl),
|
||||
qed_chain_get_prod_idx(&txq->tx_pbl),
|
||||
jiffies);
|
||||
"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",
|
||||
fp->id, fp->sb_info->igu_sb_id, txq->index, txq->ndev_txq_id, txq->cos,
|
||||
p_chain, p_chain->capacity, p_chain->size, jiffies, HZ);
|
||||
|
||||
/* Dump all the relevant prod/cons indexes */
|
||||
DP_NOTICE(edev,
|
||||
"hw cons %04x sw_tx_prod=0x%x, sw_tx_cons=0x%x, bd_prod 0x%x bd_cons 0x%x\n",
|
||||
le16_to_cpu(*txq->hw_cons_ptr), txq->sw_tx_prod, txq->sw_tx_cons,
|
||||
qed_chain_get_prod_idx(p_chain), qed_chain_get_cons_idx(p_chain));
|
||||
}
|
||||
|
||||
static void
|
||||
qede_tx_log_print(struct qede_dev *edev, struct qede_fastpath *fp, struct qede_tx_queue *txq)
|
||||
{
|
||||
struct qed_sb_info_dbg sb_dbg;
|
||||
int rc;
|
||||
|
||||
/* sb info */
|
||||
qede_fp_sb_dump(edev, fp);
|
||||
|
||||
memset(&sb_dbg, 0, sizeof(sb_dbg));
|
||||
rc = edev->ops->common->get_sb_info(edev->cdev, fp->sb_info, (u16)fp->id, &sb_dbg);
|
||||
|
||||
DP_NOTICE(edev, "IGU: prod %08x cons %08x CAU Tx %04x\n",
|
||||
sb_dbg.igu_prod, sb_dbg.igu_cons, sb_dbg.pi[TX_PI(txq->cos)]);
|
||||
|
||||
/* report to mfw */
|
||||
edev->ops->common->mfw_report(edev->cdev,
|
||||
"Txq[%d]: FW cons [host] %04x, SW cons %04x, SW prod %04x [Jiffies %lu]\n",
|
||||
txq->index, le16_to_cpu(*txq->hw_cons_ptr),
|
||||
qed_chain_get_cons_idx(&txq->tx_pbl),
|
||||
qed_chain_get_prod_idx(&txq->tx_pbl), jiffies);
|
||||
if (!rc)
|
||||
edev->ops->common->mfw_report(edev->cdev,
|
||||
"Txq[%d]: SB[0x%04x] - IGU: prod %08x cons %08x CAU Tx %04x\n",
|
||||
txq->index, fp->sb_info->igu_sb_id,
|
||||
sb_dbg.igu_prod, sb_dbg.igu_cons,
|
||||
sb_dbg.pi[TX_PI(txq->cos)]);
|
||||
}
|
||||
|
||||
static void qede_tx_timeout(struct net_device *dev, unsigned int txqueue)
|
||||
{
|
||||
struct qede_dev *edev = netdev_priv(dev);
|
||||
struct qede_tx_queue *txq;
|
||||
int cos;
|
||||
int i;
|
||||
|
||||
netif_carrier_off(dev);
|
||||
DP_NOTICE(edev, "TX timeout on queue %u!\n", txqueue);
|
||||
|
||||
if (!(edev->fp_array[txqueue].type & QEDE_FASTPATH_TX))
|
||||
return;
|
||||
for_each_queue(i) {
|
||||
struct qede_tx_queue *txq;
|
||||
struct qede_fastpath *fp;
|
||||
int cos;
|
||||
|
||||
for_each_cos_in_txq(edev, cos) {
|
||||
txq = &edev->fp_array[txqueue].txq[cos];
|
||||
fp = &edev->fp_array[i];
|
||||
if (!(fp->type & QEDE_FASTPATH_TX))
|
||||
continue;
|
||||
|
||||
if (qed_chain_get_cons_idx(&txq->tx_pbl) !=
|
||||
qed_chain_get_prod_idx(&txq->tx_pbl))
|
||||
qede_tx_log_print(edev, txq);
|
||||
for_each_cos_in_txq(edev, cos) {
|
||||
txq = &fp->txq[cos];
|
||||
|
||||
/* Dump basic metadata for all queues */
|
||||
qede_txq_fp_log_metadata(edev, fp, txq);
|
||||
|
||||
if (qed_chain_get_cons_idx(&txq->tx_pbl) !=
|
||||
qed_chain_get_prod_idx(&txq->tx_pbl))
|
||||
qede_tx_log_print(edev, fp, txq);
|
||||
}
|
||||
}
|
||||
|
||||
if (IS_VF(edev))
|
||||
|
@ -652,6 +652,7 @@ struct qed_dev_info {
|
||||
|
||||
bool wol_support;
|
||||
bool smart_an;
|
||||
bool esl;
|
||||
|
||||
/* MBI version */
|
||||
u32 mbi_version;
|
||||
@ -807,6 +808,12 @@ struct qed_devlink {
|
||||
struct devlink_health_reporter *fw_reporter;
|
||||
};
|
||||
|
||||
struct qed_sb_info_dbg {
|
||||
u32 igu_prod;
|
||||
u32 igu_cons;
|
||||
u16 pi[PIS_PER_SB];
|
||||
};
|
||||
|
||||
struct qed_common_cb_ops {
|
||||
void (*arfs_filter_op)(void *dev, void *fltr, u8 fw_rc);
|
||||
void (*link_update)(void *dev, struct qed_link_output *link);
|
||||
@ -1194,6 +1201,13 @@ struct qed_common_ops {
|
||||
struct devlink* (*devlink_register)(struct qed_dev *cdev);
|
||||
|
||||
void (*devlink_unregister)(struct devlink *devlink);
|
||||
|
||||
__printf(2, 3) void (*mfw_report)(struct qed_dev *cdev, char *fmt, ...);
|
||||
|
||||
int (*get_sb_info)(struct qed_dev *cdev, struct qed_sb_info *sb,
|
||||
u16 qid, struct qed_sb_info_dbg *sb_dbg);
|
||||
|
||||
int (*get_esl_status)(struct qed_dev *cdev, bool *esl_active);
|
||||
};
|
||||
|
||||
#define MASK_FIELD(_name, _value) \
|
||||
|
Loading…
Reference in New Issue
Block a user