bnxt_en: Add support for 'ethtool -d'
authorVasundhara Volam <vasundhara-v.volam@broadcom.com>
Mon, 27 Jul 2020 09:40:45 +0000 (05:40 -0400)
committerDavid S. Miller <davem@davemloft.net>
Mon, 27 Jul 2020 18:47:33 +0000 (11:47 -0700)
Add support to dump PXP registers and PCIe statistics.

Signed-off-by: Vasundhara Volam <vasundhara-v.volam@broadcom.com>
Signed-off-by: Michael Chan <michael.chan@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/broadcom/bnxt/bnxt.c
drivers/net/ethernet/broadcom/bnxt/bnxt.h
drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.h

index 1fc263b..2622d3c 100644 (file)
@@ -10228,6 +10228,38 @@ static int bnxt_set_features(struct net_device *dev, netdev_features_t features)
        return rc;
 }
 
+int bnxt_dbg_hwrm_rd_reg(struct bnxt *bp, u32 reg_off, u16 num_words,
+                        u32 *reg_buf)
+{
+       struct hwrm_dbg_read_direct_output *resp = bp->hwrm_cmd_resp_addr;
+       struct hwrm_dbg_read_direct_input req = {0};
+       __le32 *dbg_reg_buf;
+       dma_addr_t mapping;
+       int rc, i;
+
+       dbg_reg_buf = dma_alloc_coherent(&bp->pdev->dev, num_words * 4,
+                                        &mapping, GFP_KERNEL);
+       if (!dbg_reg_buf)
+               return -ENOMEM;
+       bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_DBG_READ_DIRECT, -1, -1);
+       req.host_dest_addr = cpu_to_le64(mapping);
+       req.read_addr = cpu_to_le32(reg_off + CHIMP_REG_VIEW_ADDR);
+       req.read_len32 = cpu_to_le32(num_words);
+       mutex_lock(&bp->hwrm_cmd_lock);
+       rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
+       if (rc || resp->error_code) {
+               rc = -EIO;
+               goto dbg_rd_reg_exit;
+       }
+       for (i = 0; i < num_words; i++)
+               reg_buf[i] = le32_to_cpu(dbg_reg_buf[i]);
+
+dbg_rd_reg_exit:
+       mutex_unlock(&bp->hwrm_cmd_lock);
+       dma_free_coherent(&bp->pdev->dev, num_words * 4, dbg_reg_buf, mapping);
+       return rc;
+}
+
 static int bnxt_dbg_hwrm_ring_info_get(struct bnxt *bp, u8 ring_type,
                                       u32 ring_id, u32 *prod, u32 *cons)
 {
index 0c9b79b..5a13eb6 100644 (file)
@@ -1304,6 +1304,9 @@ struct bnxt_test_info {
        char string[BNXT_MAX_TEST][ETH_GSTRING_LEN];
 };
 
+#define CHIMP_REG_VIEW_ADDR                            \
+       ((bp->flags & BNXT_FLAG_CHIP_P5) ? 0x80000000 : 0xb1000000)
+
 #define BNXT_GRCPF_REG_CHIMP_COMM              0x0
 #define BNXT_GRCPF_REG_CHIMP_COMM_TRIGGER      0x100
 #define BNXT_GRCPF_REG_WINDOW_BASE_OUT         0x400
@@ -2117,6 +2120,8 @@ int bnxt_open_nic(struct bnxt *, bool, bool);
 int bnxt_half_open_nic(struct bnxt *bp);
 void bnxt_half_close_nic(struct bnxt *bp);
 int bnxt_close_nic(struct bnxt *, bool, bool);
+int bnxt_dbg_hwrm_rd_reg(struct bnxt *bp, u32 reg_off, u16 num_words,
+                        u32 *reg_buf);
 void bnxt_fw_exception(struct bnxt *bp);
 void bnxt_fw_reset(struct bnxt *bp);
 int bnxt_check_rings(struct bnxt *bp, int tx, int rx, bool sh, int tcs,
index 5fd3e92..64da654 100644 (file)
@@ -1324,6 +1324,59 @@ static void bnxt_get_drvinfo(struct net_device *dev,
        info->regdump_len = 0;
 }
 
+static int bnxt_get_regs_len(struct net_device *dev)
+{
+       struct bnxt *bp = netdev_priv(dev);
+       int reg_len;
+
+       reg_len = BNXT_PXP_REG_LEN;
+
+       if (bp->fw_cap & BNXT_FW_CAP_PCIE_STATS_SUPPORTED)
+               reg_len += sizeof(struct pcie_ctx_hw_stats);
+
+       return reg_len;
+}
+
+static void bnxt_get_regs(struct net_device *dev, struct ethtool_regs *regs,
+                         void *_p)
+{
+       struct pcie_ctx_hw_stats *hw_pcie_stats;
+       struct hwrm_pcie_qstats_input req = {0};
+       struct bnxt *bp = netdev_priv(dev);
+       dma_addr_t hw_pcie_stats_addr;
+       int rc;
+
+       regs->version = 0;
+       bnxt_dbg_hwrm_rd_reg(bp, 0, BNXT_PXP_REG_LEN / 4, _p);
+
+       if (!(bp->fw_cap & BNXT_FW_CAP_PCIE_STATS_SUPPORTED))
+               return;
+
+       hw_pcie_stats = dma_alloc_coherent(&bp->pdev->dev,
+                                          sizeof(*hw_pcie_stats),
+                                          &hw_pcie_stats_addr, GFP_KERNEL);
+       if (!hw_pcie_stats)
+               return;
+
+       regs->version = 1;
+       bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_PCIE_QSTATS, -1, -1);
+       req.pcie_stat_size = cpu_to_le16(sizeof(*hw_pcie_stats));
+       req.pcie_stat_host_addr = cpu_to_le64(hw_pcie_stats_addr);
+       mutex_lock(&bp->hwrm_cmd_lock);
+       rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
+       if (!rc) {
+               __le64 *src = (__le64 *)hw_pcie_stats;
+               u64 *dst = (u64 *)(_p + BNXT_PXP_REG_LEN);
+               int i;
+
+               for (i = 0; i < sizeof(*hw_pcie_stats) / sizeof(__le64); i++)
+                       dst[i] = le64_to_cpu(src[i]);
+       }
+       mutex_unlock(&bp->hwrm_cmd_lock);
+       dma_free_coherent(&bp->pdev->dev, sizeof(*hw_pcie_stats), hw_pcie_stats,
+                         hw_pcie_stats_addr);
+}
+
 static void bnxt_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 {
        struct bnxt *bp = netdev_priv(dev);
@@ -3599,6 +3652,8 @@ const struct ethtool_ops bnxt_ethtool_ops = {
        .get_pauseparam         = bnxt_get_pauseparam,
        .set_pauseparam         = bnxt_set_pauseparam,
        .get_drvinfo            = bnxt_get_drvinfo,
+       .get_regs_len           = bnxt_get_regs_len,
+       .get_regs               = bnxt_get_regs,
        .get_wol                = bnxt_get_wol,
        .set_wol                = bnxt_set_wol,
        .get_coalesce           = bnxt_get_coalesce,
index dddbca1..34f44dd 100644 (file)
@@ -84,6 +84,8 @@ struct hwrm_dbg_cmn_output {
                                  ETH_RESET_PHY | ETH_RESET_RAM)        \
                                 << ETH_RESET_SHARED_SHIFT)
 
+#define BNXT_PXP_REG_LEN       0x3110
+
 extern const struct ethtool_ops bnxt_ethtool_ops;
 
 u32 bnxt_get_rxfh_indir_size(struct net_device *dev);