diff options
-rw-r--r-- | Documentation/networking/device_drivers/ethernet/meta/fbnic.rst | 13 | ||||
-rw-r--r-- | drivers/net/ethernet/meta/fbnic/fbnic_csr.h | 10 | ||||
-rw-r--r-- | drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c | 71 | ||||
-rw-r--r-- | drivers/net/ethernet/meta/fbnic/fbnic_hw_stats.c | 76 | ||||
-rw-r--r-- | drivers/net/ethernet/meta/fbnic/fbnic_hw_stats.h | 8 | ||||
-rw-r--r-- | drivers/net/ethernet/meta/fbnic/fbnic_pci.c | 2 |
6 files changed, 180 insertions, 0 deletions
diff --git a/Documentation/networking/device_drivers/ethernet/meta/fbnic.rst b/Documentation/networking/device_drivers/ethernet/meta/fbnic.rst index 14f2834d86d1..04e0595bb0a7 100644 --- a/Documentation/networking/device_drivers/ethernet/meta/fbnic.rst +++ b/Documentation/networking/device_drivers/ethernet/meta/fbnic.rst @@ -31,6 +31,19 @@ separate entry. Statistics ---------- +RPC (Rx parser) +~~~~~~~~~~~~~~~ + + - ``rpc_unkn_etype``: frames containing unknown EtherType + - ``rpc_unkn_ext_hdr``: frames containing unknown IPv6 extension header + - ``rpc_ipv4_frag``: frames containing IPv4 fragment + - ``rpc_ipv6_frag``: frames containing IPv6 fragment + - ``rpc_ipv4_esp``: frames with IPv4 ESP encapsulation + - ``rpc_ipv6_esp``: frames with IPv6 ESP encapsulation + - ``rpc_tcp_opt_err``: frames which encountered TCP option parsing error + - ``rpc_out_of_hdr_err``: frames where header was larger than parsable region + - ``ovr_size_err``: oversized frames + PCIe ~~~~ diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_csr.h b/drivers/net/ethernet/meta/fbnic/fbnic_csr.h index dac9a4879e52..02bb81b3c506 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_csr.h +++ b/drivers/net/ethernet/meta/fbnic/fbnic_csr.h @@ -638,6 +638,16 @@ enum { FBNIC_RPC_RSS_KEY_DWORD_LEN * 32 - \ FBNIC_RPC_RSS_KEY_BIT_LEN) +#define FBNIC_RPC_CNTR_TCP_OPT_ERR 0x0849e /* 0x21278 */ +#define FBNIC_RPC_CNTR_UNKN_ETYPE 0x0849f /* 0x2127c */ +#define FBNIC_RPC_CNTR_IPV4_FRAG 0x084a0 /* 0x21280 */ +#define FBNIC_RPC_CNTR_IPV6_FRAG 0x084a1 /* 0x21284 */ +#define FBNIC_RPC_CNTR_IPV4_ESP 0x084a2 /* 0x21288 */ +#define FBNIC_RPC_CNTR_IPV6_ESP 0x084a3 /* 0x2128c */ +#define FBNIC_RPC_CNTR_UNKN_EXT_HDR 0x084a4 /* 0x21290 */ +#define FBNIC_RPC_CNTR_OUT_OF_HDR_ERR 0x084a5 /* 0x21294 */ +#define FBNIC_RPC_CNTR_OVR_SIZE_ERR 0x084a6 /* 0x21298 */ + #define FBNIC_RPC_TCAM_MACDA_VALIDATE 0x0852d /* 0x214b4 */ #define FBNIC_CSR_END_RPC 0x0856b /* CSR section delimiter */ diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c b/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c index 589cc7c2ee52..cc8ca94529ca 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c @@ -9,6 +9,37 @@ #include "fbnic_netdev.h" #include "fbnic_tlv.h" +struct fbnic_stat { + u8 string[ETH_GSTRING_LEN]; + unsigned int size; + unsigned int offset; +}; + +#define FBNIC_STAT_FIELDS(type, name, stat) { \ + .string = name, \ + .size = sizeof_field(struct type, stat), \ + .offset = offsetof(struct type, stat), \ +} + +/* Hardware statistics not captured in rtnl_link_stats */ +#define FBNIC_HW_STAT(name, stat) \ + FBNIC_STAT_FIELDS(fbnic_hw_stats, name, stat) + +static const struct fbnic_stat fbnic_gstrings_hw_stats[] = { + /* RPC */ + FBNIC_HW_STAT("rpc_unkn_etype", rpc.unkn_etype), + FBNIC_HW_STAT("rpc_unkn_ext_hdr", rpc.unkn_ext_hdr), + FBNIC_HW_STAT("rpc_ipv4_frag", rpc.ipv4_frag), + FBNIC_HW_STAT("rpc_ipv6_frag", rpc.ipv6_frag), + FBNIC_HW_STAT("rpc_ipv4_esp", rpc.ipv4_esp), + FBNIC_HW_STAT("rpc_ipv6_esp", rpc.ipv6_esp), + FBNIC_HW_STAT("rpc_tcp_opt_err", rpc.tcp_opt_err), + FBNIC_HW_STAT("rpc_out_of_hdr_err", rpc.out_of_hdr_err), +}; + +#define FBNIC_HW_FIXED_STATS_LEN ARRAY_SIZE(fbnic_gstrings_hw_stats) +#define FBNIC_HW_STATS_LEN FBNIC_HW_FIXED_STATS_LEN + static int fbnic_get_ts_info(struct net_device *netdev, struct kernel_ethtool_ts_info *tsinfo) @@ -54,6 +85,43 @@ static void fbnic_set_counter(u64 *stat, struct fbnic_stat_counter *counter) *stat = counter->value; } +static void fbnic_get_strings(struct net_device *dev, u32 sset, u8 *data) +{ + int i; + + switch (sset) { + case ETH_SS_STATS: + for (i = 0; i < FBNIC_HW_STATS_LEN; i++) + ethtool_puts(&data, fbnic_gstrings_hw_stats[i].string); + break; + } +} + +static int fbnic_get_sset_count(struct net_device *dev, int sset) +{ + switch (sset) { + case ETH_SS_STATS: + return FBNIC_HW_STATS_LEN; + default: + return -EOPNOTSUPP; + } +} + +static void fbnic_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *stats, u64 *data) +{ + struct fbnic_net *fbn = netdev_priv(dev); + const struct fbnic_stat *stat; + int i; + + fbnic_get_hw_stats(fbn->fbd); + + for (i = 0; i < FBNIC_HW_STATS_LEN; i++) { + stat = &fbnic_gstrings_hw_stats[i]; + data[i] = *(u64 *)((u8 *)&fbn->fbd->hw_stats + stat->offset); + } +} + static void fbnic_get_eth_mac_stats(struct net_device *netdev, struct ethtool_eth_mac_stats *eth_mac_stats) @@ -138,6 +206,9 @@ static const struct ethtool_ops fbnic_ethtool_ops = { .get_drvinfo = fbnic_get_drvinfo, .get_regs_len = fbnic_get_regs_len, .get_regs = fbnic_get_regs, + .get_strings = fbnic_get_strings, + .get_ethtool_stats = fbnic_get_ethtool_stats, + .get_sset_count = fbnic_get_sset_count, .get_ts_info = fbnic_get_ts_info, .get_ts_stats = fbnic_get_ts_stats, .get_eth_mac_stats = fbnic_get_eth_mac_stats, diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_hw_stats.c b/drivers/net/ethernet/meta/fbnic/fbnic_hw_stats.c index c391f2155054..89ac6bc8c7fc 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_hw_stats.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_hw_stats.c @@ -3,6 +3,27 @@ #include "fbnic.h" +static void fbnic_hw_stat_rst32(struct fbnic_dev *fbd, u32 reg, + struct fbnic_stat_counter *stat) +{ + /* We do not touch the "value" field here. + * It gets zeroed out on fbd structure allocation. + * After that we want it to grow continuously + * through device resets and power state changes. + */ + stat->u.old_reg_value_32 = rd32(fbd, reg); +} + +static void fbnic_hw_stat_rd32(struct fbnic_dev *fbd, u32 reg, + struct fbnic_stat_counter *stat) +{ + u32 new_reg_value; + + new_reg_value = rd32(fbd, reg); + stat->value += new_reg_value - stat->u.old_reg_value_32; + stat->u.old_reg_value_32 = new_reg_value; +} + u64 fbnic_stat_rd64(struct fbnic_dev *fbd, u32 reg, u32 offset) { u32 prev_upper, upper, lower, diff; @@ -49,6 +70,53 @@ static void fbnic_hw_stat_rd64(struct fbnic_dev *fbd, u32 reg, s32 offset, stat->u.old_reg_value_64 = new_reg_value; } +static void fbnic_reset_rpc_stats(struct fbnic_dev *fbd, + struct fbnic_rpc_stats *rpc) +{ + fbnic_hw_stat_rst32(fbd, + FBNIC_RPC_CNTR_UNKN_ETYPE, + &rpc->unkn_etype); + fbnic_hw_stat_rst32(fbd, + FBNIC_RPC_CNTR_UNKN_EXT_HDR, + &rpc->unkn_ext_hdr); + fbnic_hw_stat_rst32(fbd, FBNIC_RPC_CNTR_IPV4_FRAG, &rpc->ipv4_frag); + fbnic_hw_stat_rst32(fbd, FBNIC_RPC_CNTR_IPV6_FRAG, &rpc->ipv6_frag); + fbnic_hw_stat_rst32(fbd, FBNIC_RPC_CNTR_IPV4_ESP, &rpc->ipv4_esp); + fbnic_hw_stat_rst32(fbd, FBNIC_RPC_CNTR_IPV6_ESP, &rpc->ipv6_esp); + fbnic_hw_stat_rst32(fbd, FBNIC_RPC_CNTR_TCP_OPT_ERR, &rpc->tcp_opt_err); + fbnic_hw_stat_rst32(fbd, + FBNIC_RPC_CNTR_OUT_OF_HDR_ERR, + &rpc->out_of_hdr_err); + fbnic_hw_stat_rst32(fbd, + FBNIC_RPC_CNTR_OVR_SIZE_ERR, + &rpc->ovr_size_err); +} + +static void fbnic_get_rpc_stats32(struct fbnic_dev *fbd, + struct fbnic_rpc_stats *rpc) +{ + fbnic_hw_stat_rd32(fbd, + FBNIC_RPC_CNTR_UNKN_ETYPE, + &rpc->unkn_etype); + fbnic_hw_stat_rd32(fbd, + FBNIC_RPC_CNTR_UNKN_EXT_HDR, + &rpc->unkn_ext_hdr); + + fbnic_hw_stat_rd32(fbd, FBNIC_RPC_CNTR_IPV4_FRAG, &rpc->ipv4_frag); + fbnic_hw_stat_rd32(fbd, FBNIC_RPC_CNTR_IPV6_FRAG, &rpc->ipv6_frag); + + fbnic_hw_stat_rd32(fbd, FBNIC_RPC_CNTR_IPV4_ESP, &rpc->ipv4_esp); + fbnic_hw_stat_rd32(fbd, FBNIC_RPC_CNTR_IPV6_ESP, &rpc->ipv6_esp); + + fbnic_hw_stat_rd32(fbd, FBNIC_RPC_CNTR_TCP_OPT_ERR, &rpc->tcp_opt_err); + fbnic_hw_stat_rd32(fbd, + FBNIC_RPC_CNTR_OUT_OF_HDR_ERR, + &rpc->out_of_hdr_err); + fbnic_hw_stat_rd32(fbd, + FBNIC_RPC_CNTR_OVR_SIZE_ERR, + &rpc->ovr_size_err); +} + static void fbnic_reset_pcie_stats_asic(struct fbnic_dev *fbd, struct fbnic_pcie_stats *pcie) { @@ -135,10 +203,18 @@ static void fbnic_get_pcie_stats_asic64(struct fbnic_dev *fbd, void fbnic_reset_hw_stats(struct fbnic_dev *fbd) { + fbnic_reset_rpc_stats(fbd, &fbd->hw_stats.rpc); fbnic_reset_pcie_stats_asic(fbd, &fbd->hw_stats.pcie); } +void fbnic_get_hw_stats32(struct fbnic_dev *fbd) +{ + fbnic_get_rpc_stats32(fbd, &fbd->hw_stats.rpc); +} + void fbnic_get_hw_stats(struct fbnic_dev *fbd) { + fbnic_get_hw_stats32(fbd); + fbnic_get_pcie_stats_asic64(fbd, &fbd->hw_stats.pcie); } diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_hw_stats.h b/drivers/net/ethernet/meta/fbnic/fbnic_hw_stats.h index b152c6b1b4ab..78df56b87745 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_hw_stats.h +++ b/drivers/net/ethernet/meta/fbnic/fbnic_hw_stats.h @@ -37,6 +37,12 @@ struct fbnic_mac_stats { struct fbnic_eth_mac_stats eth_mac; }; +struct fbnic_rpc_stats { + struct fbnic_stat_counter unkn_etype, unkn_ext_hdr; + struct fbnic_stat_counter ipv4_frag, ipv6_frag, ipv4_esp, ipv6_esp; + struct fbnic_stat_counter tcp_opt_err, out_of_hdr_err, ovr_size_err; +}; + struct fbnic_pcie_stats { struct fbnic_stat_counter ob_rd_tlp, ob_rd_dword; struct fbnic_stat_counter ob_wr_tlp, ob_wr_dword; @@ -49,12 +55,14 @@ struct fbnic_pcie_stats { struct fbnic_hw_stats { struct fbnic_mac_stats mac; + struct fbnic_rpc_stats rpc; struct fbnic_pcie_stats pcie; }; u64 fbnic_stat_rd64(struct fbnic_dev *fbd, u32 reg, u32 offset); void fbnic_reset_hw_stats(struct fbnic_dev *fbd); +void fbnic_get_hw_stats32(struct fbnic_dev *fbd); void fbnic_get_hw_stats(struct fbnic_dev *fbd); #endif /* _FBNIC_HW_STATS_H_ */ diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_pci.c b/drivers/net/ethernet/meta/fbnic/fbnic_pci.c index f913a87c78a2..e110c2ceafcf 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_pci.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_pci.c @@ -199,6 +199,8 @@ static void fbnic_service_task(struct work_struct *work) rtnl_lock(); + fbnic_get_hw_stats32(fbd); + fbnic_fw_check_heartbeat(fbd); fbnic_health_check(fbd); |