diff options
Diffstat (limited to 'drivers/net/ethernet/meta/fbnic')
18 files changed, 1040 insertions, 230 deletions
diff --git a/drivers/net/ethernet/meta/fbnic/Makefile b/drivers/net/ethernet/meta/fbnic/Makefile index 0dbc634adb4b..15e8ff649615 100644 --- a/drivers/net/ethernet/meta/fbnic/Makefile +++ b/drivers/net/ethernet/meta/fbnic/Makefile @@ -12,6 +12,7 @@ fbnic-y := fbnic_csr.o \ fbnic_devlink.o \ fbnic_ethtool.o \ fbnic_fw.o \ + fbnic_fw_log.o \ fbnic_hw_stats.o \ fbnic_hwmon.o \ fbnic_irq.o \ diff --git a/drivers/net/ethernet/meta/fbnic/fbnic.h b/drivers/net/ethernet/meta/fbnic/fbnic.h index 65815d4f379e..c376e06880c9 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic.h +++ b/drivers/net/ethernet/meta/fbnic/fbnic.h @@ -12,6 +12,7 @@ #include "fbnic_csr.h" #include "fbnic_fw.h" +#include "fbnic_fw_log.h" #include "fbnic_hw_stats.h" #include "fbnic_mac.h" #include "fbnic_rpc.h" @@ -85,6 +86,8 @@ struct fbnic_dev { /* Lock protecting access to hw_stats */ spinlock_t hw_stats_lock; + + struct fbnic_fw_log fw_log; }; /* Reserve entry 0 in the MSI-X "others" array until we have filled all diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_csr.h b/drivers/net/ethernet/meta/fbnic/fbnic_csr.h index 36393a17d92d..a81db842aa53 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_csr.h +++ b/drivers/net/ethernet/meta/fbnic/fbnic_csr.h @@ -12,13 +12,28 @@ #define DESC_BIT(nr) BIT_ULL(nr) #define DESC_GENMASK(h, l) GENMASK_ULL(h, l) +#define FW_VER_CODE(_major, _minor, _patch, _build) ( \ + FIELD_PREP(FBNIC_FW_CAP_RESP_VERSION_MAJOR, _major) | \ + FIELD_PREP(FBNIC_FW_CAP_RESP_VERSION_MINOR, _minor) | \ + FIELD_PREP(FBNIC_FW_CAP_RESP_VERSION_PATCH, _patch) | \ + FIELD_PREP(FBNIC_FW_CAP_RESP_VERSION_BUILD, _build)) + /* Defines the minimum firmware version required by the driver */ -#define MIN_FW_MAJOR_VERSION 0 -#define MIN_FW_MINOR_VERSION 10 -#define MIN_FW_BUILD_VERSION 6 -#define MIN_FW_VERSION_CODE (MIN_FW_MAJOR_VERSION * (1u << 24) + \ - MIN_FW_MINOR_VERSION * (1u << 16) + \ - MIN_FW_BUILD_VERSION) +#define MIN_FW_VER_CODE FW_VER_CODE(0, 10, 6, 0) + +/* Defines the minimum firmware version required for firmware logs */ +#define MIN_FW_VER_CODE_LOG FW_VER_CODE(0, 12, 9, 0) + +/* Driver can request that firmware sends all cached logs in bulk. This + * feature was enabled on older firmware however firmware has a bug + * which attempted to send 30 messages per mbx message which caused an + * overflow flooding the mailbox. This results in a kernel warning + * related to corrupt mailbox messages. + * + * If firmware is new enough only request sending historical logs when + * the log buffer is empty to prevent duplicate logs. + */ +#define MIN_FW_VER_CODE_HIST FW_VER_CODE(25, 5, 7, 0) #define PCI_DEVICE_ID_META_FBNIC_ASIC 0x0013 @@ -446,6 +461,26 @@ enum { #define FBNIC_TMI_ILLEGAL_PTP_REQS 0x04409 /* 0x11024 */ #define FBNIC_TMI_GOOD_PTP_TS 0x0440a /* 0x11028 */ #define FBNIC_TMI_BAD_PTP_TS 0x0440b /* 0x1102c */ +#define FBNIC_TMI_STAT_TX_PACKET_1519_2047_BYTES_L \ + 0x04433 /* 0x110cc */ +#define FBNIC_TMI_STAT_TX_PACKET_1519_2047_BYTES_H \ + 0x04434 /* 0x110d0 */ +#define FBNIC_TMI_STAT_TX_PACKET_2048_4095_BYTES_L \ + 0x04435 /* 0x110d4 */ +#define FBNIC_TMI_STAT_TX_PACKET_2048_4095_BYTES_H \ + 0x04436 /* 0x110d8 */ +#define FBNIC_TMI_STAT_TX_PACKET_4096_8191_BYTES_L \ + 0x04437 /* 0x110dc */ +#define FBNIC_TMI_STAT_TX_PACKET_4096_8191_BYTES_H \ + 0x04438 /* 0x110e0 */ +#define FBNIC_TMI_STAT_TX_PACKET_8192_9216_BYTES_L \ + 0x04439 /* 0x110e4 */ +#define FBNIC_TMI_STAT_TX_PACKET_8192_9216_BYTES_H \ + 0x0443a /* 0x110e8 */ +#define FBNIC_TMI_STAT_TX_PACKET_9217_MAX_BYTES_L \ + 0x0443b /* 0x110ec */ +#define FBNIC_TMI_STAT_TX_PACKET_9217_MAX_BYTES_H \ + 0x0443c /* 0x110f0 */ #define FBNIC_CSR_END_TMI 0x0443f /* CSR section delimiter */ /* Precision Time Protocol Registers */ @@ -473,7 +508,7 @@ enum { #define FBNIC_PTP_ADD_VAL_NS 0x04806 /* 0x12018 */ #define FBNIC_PTP_ADD_VAL_NS_MASK CSR_GENMASK(15, 0) -#define FBNIC_PTP_ADD_VAL_SUBNS 0x04807 /* 0x1201c */ +#define FBNIC_PTP_ADD_VAL_SUBNS 0x04807 /* 0x1201c */ #define FBNIC_PTP_CTR_VAL_HI 0x04808 /* 0x12020 */ #define FBNIC_PTP_CTR_VAL_LO 0x04809 /* 0x12024 */ @@ -674,6 +709,26 @@ enum { #define FBNIC_RPC_CNTR_OVR_SIZE_ERR 0x084a6 /* 0x21298 */ #define FBNIC_RPC_TCAM_MACDA_VALIDATE 0x0852d /* 0x214b4 */ +#define FBNIC_RPC_STAT_RX_PACKET_1519_2047_BYTES_L \ + 0x0855f /* 0x2157c */ +#define FBNIC_RPC_STAT_RX_PACKET_1519_2047_BYTES_H \ + 0x08560 /* 0x21580 */ +#define FBNIC_RPC_STAT_RX_PACKET_2048_4095_BYTES_L \ + 0x08561 /* 0x21584 */ +#define FBNIC_RPC_STAT_RX_PACKET_2048_4095_BYTES_H \ + 0x08562 /* 0x21588 */ +#define FBNIC_RPC_STAT_RX_PACKET_4096_8191_BYTES_L \ + 0x08563 /* 0x2158c */ +#define FBNIC_RPC_STAT_RX_PACKET_4096_8191_BYTES_H \ + 0x08564 /* 0x21590 */ +#define FBNIC_RPC_STAT_RX_PACKET_8192_9216_BYTES_L \ + 0x08565 /* 0x21594 */ +#define FBNIC_RPC_STAT_RX_PACKET_8192_9216_BYTES_H \ + 0x08566 /* 0x21598 */ +#define FBNIC_RPC_STAT_RX_PACKET_9217_MAX_BYTES_L \ + 0x08567 /* 0x2159c */ +#define FBNIC_RPC_STAT_RX_PACKET_9217_MAX_BYTES_H \ + 0x08568 /* 0x215a0 */ #define FBNIC_CSR_END_RPC 0x0856b /* CSR section delimiter */ /* RPC RAM Registers */ @@ -776,16 +831,12 @@ enum { #define FBNIC_CSR_START_MAC_STAT 0x11a00 #define FBNIC_MAC_STAT_RX_BYTE_COUNT_L 0x11a08 /* 0x46820 */ #define FBNIC_MAC_STAT_RX_BYTE_COUNT_H 0x11a09 /* 0x46824 */ -#define FBNIC_MAC_STAT_RX_ALIGN_ERROR_L \ - 0x11a0a /* 0x46828 */ -#define FBNIC_MAC_STAT_RX_ALIGN_ERROR_H \ - 0x11a0b /* 0x4682c */ +#define FBNIC_MAC_STAT_RX_ALIGN_ERROR_L 0x11a0a /* 0x46828 */ +#define FBNIC_MAC_STAT_RX_ALIGN_ERROR_H 0x11a0b /* 0x4682c */ #define FBNIC_MAC_STAT_RX_TOOLONG_L 0x11a0e /* 0x46838 */ #define FBNIC_MAC_STAT_RX_TOOLONG_H 0x11a0f /* 0x4683c */ -#define FBNIC_MAC_STAT_RX_RECEIVED_OK_L \ - 0x11a12 /* 0x46848 */ -#define FBNIC_MAC_STAT_RX_RECEIVED_OK_H \ - 0x11a13 /* 0x4684c */ +#define FBNIC_MAC_STAT_RX_RECEIVED_OK_L 0x11a12 /* 0x46848 */ +#define FBNIC_MAC_STAT_RX_RECEIVED_OK_H 0x11a13 /* 0x4684c */ #define FBNIC_MAC_STAT_RX_PACKET_BAD_FCS_L \ 0x11a14 /* 0x46850 */ #define FBNIC_MAC_STAT_RX_PACKET_BAD_FCS_H \ @@ -796,20 +847,90 @@ enum { #define FBNIC_MAC_STAT_RX_MULTICAST_H 0x11a1d /* 0x46874 */ #define FBNIC_MAC_STAT_RX_BROADCAST_L 0x11a1e /* 0x46878 */ #define FBNIC_MAC_STAT_RX_BROADCAST_H 0x11a1f /* 0x4687c */ +#define FBNIC_MAC_STAT_RX_UNDERSIZE_L 0x11a24 /* 0x46890 */ +#define FBNIC_MAC_STAT_RX_UNDERSIZE_H 0x11a25 /* 0x46894 */ +#define FBNIC_MAC_STAT_RX_PACKET_64_BYTES_L \ + 0x11a26 /* 0x46898 */ +#define FBNIC_MAC_STAT_RX_PACKET_64_BYTES_H \ + 0x11a27 /* 0x4689c */ +#define FBNIC_MAC_STAT_RX_PACKET_65_127_BYTES_L \ + 0x11a28 /* 0x468a0 */ +#define FBNIC_MAC_STAT_RX_PACKET_65_127_BYTES_H \ + 0x11a29 /* 0x468a4 */ +#define FBNIC_MAC_STAT_RX_PACKET_128_255_BYTES_L \ + 0x11a2a /* 0x468a8 */ +#define FBNIC_MAC_STAT_RX_PACKET_128_255_BYTES_H \ + 0x11a2b /* 0x468ac */ +#define FBNIC_MAC_STAT_RX_PACKET_256_511_BYTES_L \ + 0x11a2c /* 0x468b0 */ +#define FBNIC_MAC_STAT_RX_PACKET_256_511_BYTES_H \ + 0x11a2d /* 0x468b4 */ +#define FBNIC_MAC_STAT_RX_PACKET_512_1023_BYTES_L \ + 0x11a2e /* 0x468b8 */ +#define FBNIC_MAC_STAT_RX_PACKET_512_1023_BYTES_H \ + 0x11a2f /* 0x468bc */ +#define FBNIC_MAC_STAT_RX_PACKET_1024_1518_BYTES_L \ + 0x11a30 /* 0x468c0 */ +#define FBNIC_MAC_STAT_RX_PACKET_1024_1518_BYTES_H \ + 0x11a31 /* 0x468c4 */ +#define FBNIC_MAC_STAT_RX_PACKET_1519_MAX_BYTES_L \ + 0x11a32 /* 0x468c8 */ +#define FBNIC_MAC_STAT_RX_PACKET_1519_MAX_BYTES_H \ + 0x11a33 /* 0x468cc */ +#define FBNIC_MAC_STAT_RX_OVERSIZE_L 0x11a34 /* 0x468d0 */ +#define FBNIC_MAC_STAT_RX_OVERSSIZE_H 0x11a35 /* 0x468d4 */ +#define FBNIC_MAC_STAT_RX_JABBER_L 0x11a36 /* 0x468d8 */ +#define FBNIC_MAC_STAT_RX_JABBER_H 0x11a37 /* 0x468dc */ +#define FBNIC_MAC_STAT_RX_FRAGMENT_L 0x11a38 /* 0x468e0 */ +#define FBNIC_MAC_STAT_RX_FRAGMENT_H 0x11a39 /* 0x468e4 */ +#define FBNIC_MAC_STAT_RX_CONTROL_FRAMES_L \ + 0x11a3c /* 0x468f0 */ +#define FBNIC_MAC_STAT_RX_CONTROL_FRAMES_H \ + 0x11a3d /* 0x468f4 */ #define FBNIC_MAC_STAT_TX_BYTE_COUNT_L 0x11a3e /* 0x468f8 */ #define FBNIC_MAC_STAT_TX_BYTE_COUNT_H 0x11a3f /* 0x468fc */ #define FBNIC_MAC_STAT_TX_TRANSMITTED_OK_L \ 0x11a42 /* 0x46908 */ #define FBNIC_MAC_STAT_TX_TRANSMITTED_OK_H \ 0x11a43 /* 0x4690c */ -#define FBNIC_MAC_STAT_TX_IFOUTERRORS_L \ - 0x11a46 /* 0x46918 */ -#define FBNIC_MAC_STAT_TX_IFOUTERRORS_H \ - 0x11a47 /* 0x4691c */ +#define FBNIC_MAC_STAT_TX_IFOUTERRORS_L 0x11a46 /* 0x46918 */ +#define FBNIC_MAC_STAT_TX_IFOUTERRORS_H 0x11a47 /* 0x4691c */ #define FBNIC_MAC_STAT_TX_MULTICAST_L 0x11a4a /* 0x46928 */ #define FBNIC_MAC_STAT_TX_MULTICAST_H 0x11a4b /* 0x4692c */ #define FBNIC_MAC_STAT_TX_BROADCAST_L 0x11a4c /* 0x46930 */ #define FBNIC_MAC_STAT_TX_BROADCAST_H 0x11a4d /* 0x46934 */ +#define FBNIC_MAC_STAT_TX_PACKET_64_BYTES_L \ + 0x11a4e /* 0x46938 */ +#define FBNIC_MAC_STAT_TX_PACKET_64_BYTES_H \ + 0x11a4f /* 0x4693c */ +#define FBNIC_MAC_STAT_TX_PACKET_65_127_BYTES_L \ + 0x11a50 /* 0x46940 */ +#define FBNIC_MAC_STAT_TX_PACKET_65_127_BYTES_H \ + 0x11a51 /* 0x46944 */ +#define FBNIC_MAC_STAT_TX_PACKET_128_255_BYTES_L \ + 0x11a52 /* 0x46948 */ +#define FBNIC_MAC_STAT_TX_PACKET_128_255_BYTES_H \ + 0x11a53 /* 0x4694c */ +#define FBNIC_MAC_STAT_TX_PACKET_256_511_BYTES_L \ + 0x11a54 /* 0x46950 */ +#define FBNIC_MAC_STAT_TX_PACKET_256_511_BYTES_H \ + 0x11a55 /* 0x46954 */ +#define FBNIC_MAC_STAT_TX_PACKET_512_1023_BYTES_L \ + 0x11a56 /* 0x46958 */ +#define FBNIC_MAC_STAT_TX_PACKET_512_1023_BYTES_H \ + 0x11a57 /* 0x4695c */ +#define FBNIC_MAC_STAT_TX_PACKET_1024_1518_BYTES_L \ + 0x11a58 /* 0x46960 */ +#define FBNIC_MAC_STAT_TX_PACKET_1024_1518_BYTES_H \ + 0x11a59 /* 0x46964 */ +#define FBNIC_MAC_STAT_TX_PACKET_1519_MAX_BYTES_L \ + 0x11a5a /* 0x46968 */ +#define FBNIC_MAC_STAT_TX_PACKET_1519_MAX_BYTES_H \ + 0x11a5b /* 0x4696c */ +#define FBNIC_MAC_STAT_TX_CONTROL_FRAMES_L \ + 0x11a5e /* 0x46978 */ +#define FBNIC_MAC_STAT_TX_CONTROL_FRAMES_H \ + 0x11a5f /* 0x4697c */ /* PCIE Comphy Registers */ #define FBNIC_CSR_START_PCIE_SS_COMPHY 0x2442e /* CSR section delimiter */ @@ -857,7 +978,7 @@ enum { 0x3107e /* 0xc41f8 */ #define FBNIC_PUL_USER_OB_RD_DBG_CNT_NP_CRED_63_32 \ 0x3107f /* 0xc41fc */ -#define FBNIC_CSR_END_PUL_USER 0x310ea /* CSR section delimiter */ +#define FBNIC_CSR_END_PUL_USER 0x310ea /* CSR section delimiter */ /* Queue Registers * diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_debugfs.c b/drivers/net/ethernet/meta/fbnic/fbnic_debugfs.c index e8f2d7f2d962..b7238dd967fe 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_debugfs.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_debugfs.c @@ -170,6 +170,33 @@ static int fbnic_dbg_ipo_dst_show(struct seq_file *s, void *v) } DEFINE_SHOW_ATTRIBUTE(fbnic_dbg_ipo_dst); +static int fbnic_dbg_fw_log_show(struct seq_file *s, void *v) +{ + struct fbnic_dev *fbd = s->private; + struct fbnic_fw_log_entry *entry; + unsigned long flags; + + if (!fbnic_fw_log_ready(fbd)) + return -ENXIO; + + spin_lock_irqsave(&fbd->fw_log.lock, flags); + + list_for_each_entry_reverse(entry, &fbd->fw_log.entries, list) { + seq_printf(s, FBNIC_FW_LOG_FMT, entry->index, + (entry->timestamp / (MSEC_PER_SEC * 60 * 60 * 24)), + (entry->timestamp / (MSEC_PER_SEC * 60 * 60)) % 24, + ((entry->timestamp / (MSEC_PER_SEC * 60) % 60)), + ((entry->timestamp / MSEC_PER_SEC) % 60), + (entry->timestamp % MSEC_PER_SEC), + entry->msg); + } + + spin_unlock_irqrestore(&fbd->fw_log.lock, flags); + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(fbnic_dbg_fw_log); + static int fbnic_dbg_pcie_stats_show(struct seq_file *s, void *v) { struct fbnic_dev *fbd = s->private; @@ -222,6 +249,8 @@ void fbnic_dbg_fbd_init(struct fbnic_dev *fbd) &fbnic_dbg_ipo_src_fops); debugfs_create_file("ipo_dst", 0400, fbd->dbg_fbd, fbd, &fbnic_dbg_ipo_dst_fops); + debugfs_create_file("fw_log", 0400, fbd->dbg_fbd, fbd, + &fbnic_dbg_fw_log_fops); } void fbnic_dbg_fbd_exit(struct fbnic_dev *fbd) diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_devlink.c b/drivers/net/ethernet/meta/fbnic/fbnic_devlink.c index 4c4938eedd7b..c5f81f139e7e 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_devlink.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_devlink.c @@ -182,7 +182,7 @@ fbnic_flash_start(struct fbnic_dev *fbd, struct pldmfw_component *component) else err = -ETIMEDOUT; - fbnic_fw_clear_cmpl(fbd, cmpl); + fbnic_mbx_clear_cmpl(fbd, cmpl); cmpl_free: fbnic_fw_put_cmpl(cmpl); @@ -300,7 +300,7 @@ err_no_msg: component_name, 0, 0); } - fbnic_fw_clear_cmpl(fbd, cmpl); + fbnic_mbx_clear_cmpl(fbd, cmpl); cmpl_free: fbnic_fw_put_cmpl(cmpl); diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c b/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c index 5c7556c8c4c5..dc7ba8d5fc43 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c @@ -531,20 +531,6 @@ static int fbnic_get_rss_hash_idx(u32 flow_type) return -1; } -static int -fbnic_get_rss_hash_opts(struct fbnic_net *fbn, struct ethtool_rxnfc *cmd) -{ - int hash_opt_idx = fbnic_get_rss_hash_idx(cmd->flow_type); - - if (hash_opt_idx < 0) - return -EINVAL; - - /* Report options from rss_en table in fbn */ - cmd->data = fbn->rss_flow_hash[hash_opt_idx]; - - return 0; -} - static int fbnic_get_cls_rule_all(struct fbnic_net *fbn, struct ethtool_rxnfc *cmd, u32 *rule_locs) @@ -779,9 +765,6 @@ static int fbnic_get_rxnfc(struct net_device *netdev, cmd->data = fbn->num_rx_queues; ret = 0; break; - case ETHTOOL_GRXFH: - ret = fbnic_get_rss_hash_opts(fbn, cmd); - break; case ETHTOOL_GRXCLSRULE: ret = fbnic_get_cls_rule(fbn, cmd); break; @@ -803,41 +786,6 @@ static int fbnic_get_rxnfc(struct net_device *netdev, return ret; } -#define FBNIC_L2_HASH_OPTIONS \ - (RXH_L2DA | RXH_DISCARD) -#define FBNIC_L3_HASH_OPTIONS \ - (FBNIC_L2_HASH_OPTIONS | RXH_IP_SRC | RXH_IP_DST) -#define FBNIC_L4_HASH_OPTIONS \ - (FBNIC_L3_HASH_OPTIONS | RXH_L4_B_0_1 | RXH_L4_B_2_3) - -static int -fbnic_set_rss_hash_opts(struct fbnic_net *fbn, const struct ethtool_rxnfc *cmd) -{ - int hash_opt_idx; - - /* Verify the type requested is correct */ - hash_opt_idx = fbnic_get_rss_hash_idx(cmd->flow_type); - if (hash_opt_idx < 0) - return -EINVAL; - - /* Verify the fields asked for can actually be assigned based on type */ - if (cmd->data & ~FBNIC_L4_HASH_OPTIONS || - (hash_opt_idx > FBNIC_L4_HASH_OPT && - cmd->data & ~FBNIC_L3_HASH_OPTIONS) || - (hash_opt_idx > FBNIC_IP_HASH_OPT && - cmd->data & ~FBNIC_L2_HASH_OPTIONS)) - return -EINVAL; - - fbn->rss_flow_hash[hash_opt_idx] = cmd->data; - - if (netif_running(fbn->netdev)) { - fbnic_rss_reinit(fbn->fbd, fbn); - fbnic_write_rules(fbn->fbd); - } - - return 0; -} - static int fbnic_cls_rule_any_loc(struct fbnic_dev *fbd) { int i; @@ -1244,9 +1192,6 @@ static int fbnic_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd) int ret = -EOPNOTSUPP; switch (cmd->cmd) { - case ETHTOOL_SRXFH: - ret = fbnic_set_rss_hash_opts(fbn, cmd); - break; case ETHTOOL_SRXCLSRLINS: ret = fbnic_set_cls_rule_ins(fbn, cmd); break; @@ -1347,6 +1292,60 @@ fbnic_set_rxfh(struct net_device *netdev, struct ethtool_rxfh_param *rxfh, } static int +fbnic_get_rss_hash_opts(struct net_device *netdev, + struct ethtool_rxfh_fields *cmd) +{ + int hash_opt_idx = fbnic_get_rss_hash_idx(cmd->flow_type); + struct fbnic_net *fbn = netdev_priv(netdev); + + if (hash_opt_idx < 0) + return -EINVAL; + + /* Report options from rss_en table in fbn */ + cmd->data = fbn->rss_flow_hash[hash_opt_idx]; + + return 0; +} + +#define FBNIC_L2_HASH_OPTIONS \ + (RXH_L2DA | RXH_DISCARD) +#define FBNIC_L3_HASH_OPTIONS \ + (FBNIC_L2_HASH_OPTIONS | RXH_IP_SRC | RXH_IP_DST) +#define FBNIC_L4_HASH_OPTIONS \ + (FBNIC_L3_HASH_OPTIONS | RXH_L4_B_0_1 | RXH_L4_B_2_3) + +static int +fbnic_set_rss_hash_opts(struct net_device *netdev, + const struct ethtool_rxfh_fields *cmd, + struct netlink_ext_ack *extack) +{ + struct fbnic_net *fbn = netdev_priv(netdev); + int hash_opt_idx; + + /* Verify the type requested is correct */ + hash_opt_idx = fbnic_get_rss_hash_idx(cmd->flow_type); + if (hash_opt_idx < 0) + return -EINVAL; + + /* Verify the fields asked for can actually be assigned based on type */ + if (cmd->data & ~FBNIC_L4_HASH_OPTIONS || + (hash_opt_idx > FBNIC_L4_HASH_OPT && + cmd->data & ~FBNIC_L3_HASH_OPTIONS) || + (hash_opt_idx > FBNIC_IP_HASH_OPT && + cmd->data & ~FBNIC_L2_HASH_OPTIONS)) + return -EINVAL; + + fbn->rss_flow_hash[hash_opt_idx] = cmd->data; + + if (netif_running(fbn->netdev)) { + fbnic_rss_reinit(fbn->fbd, fbn); + fbnic_write_rules(fbn->fbd); + } + + return 0; +} + +static int fbnic_modify_rxfh_context(struct net_device *netdev, struct ethtool_rxfh_context *ctx, const struct ethtool_rxfh_param *rxfh, @@ -1446,7 +1445,7 @@ static int fbnic_set_channels(struct net_device *netdev, standalone = ch->rx_count + ch->tx_count; /* Limits for standalone queues: - * - each queue has it's own NAPI (num_napi >= rx + tx + combined) + * - each queue has its own NAPI (num_napi >= rx + tx + combined) * - combining queues (combined not 0, rx or tx must be 0) */ if ((ch->rx_count && ch->tx_count && ch->combined_count) || @@ -1612,35 +1611,107 @@ fbnic_get_eth_mac_stats(struct net_device *netdev, &mac_stats->eth_mac.FrameTooLongErrors); } +static void +fbnic_get_eth_ctrl_stats(struct net_device *netdev, + struct ethtool_eth_ctrl_stats *eth_ctrl_stats) +{ + struct fbnic_net *fbn = netdev_priv(netdev); + struct fbnic_mac_stats *mac_stats; + struct fbnic_dev *fbd = fbn->fbd; + + mac_stats = &fbd->hw_stats.mac; + + fbd->mac->get_eth_ctrl_stats(fbd, false, &mac_stats->eth_ctrl); + + eth_ctrl_stats->MACControlFramesReceived = + mac_stats->eth_ctrl.MACControlFramesReceived.value; + eth_ctrl_stats->MACControlFramesTransmitted = + mac_stats->eth_ctrl.MACControlFramesTransmitted.value; +} + +static const struct ethtool_rmon_hist_range fbnic_rmon_ranges[] = { + { 0, 64 }, + { 65, 127 }, + { 128, 255 }, + { 256, 511 }, + { 512, 1023 }, + { 1024, 1518 }, + { 1519, 2047 }, + { 2048, 4095 }, + { 4096, 8191 }, + { 8192, 9216 }, + { 9217, FBNIC_MAX_JUMBO_FRAME_SIZE }, + {} +}; + +static void +fbnic_get_rmon_stats(struct net_device *netdev, + struct ethtool_rmon_stats *rmon_stats, + const struct ethtool_rmon_hist_range **ranges) +{ + struct fbnic_net *fbn = netdev_priv(netdev); + struct fbnic_mac_stats *mac_stats; + struct fbnic_dev *fbd = fbn->fbd; + int i; + + mac_stats = &fbd->hw_stats.mac; + + fbd->mac->get_rmon_stats(fbd, false, &mac_stats->rmon); + + rmon_stats->undersize_pkts = + mac_stats->rmon.undersize_pkts.value; + rmon_stats->oversize_pkts = + mac_stats->rmon.oversize_pkts.value; + rmon_stats->fragments = + mac_stats->rmon.fragments.value; + rmon_stats->jabbers = + mac_stats->rmon.jabbers.value; + + for (i = 0; fbnic_rmon_ranges[i].high; i++) { + rmon_stats->hist[i] = mac_stats->rmon.hist[i].value; + rmon_stats->hist_tx[i] = mac_stats->rmon.hist_tx[i].value; + } + + *ranges = fbnic_rmon_ranges; +} + static const struct ethtool_ops fbnic_ethtool_ops = { - .supported_coalesce_params = - ETHTOOL_COALESCE_USECS | - ETHTOOL_COALESCE_RX_MAX_FRAMES, - .rxfh_max_num_contexts = FBNIC_RPC_RSS_TBL_COUNT, - .get_drvinfo = fbnic_get_drvinfo, - .get_regs_len = fbnic_get_regs_len, - .get_regs = fbnic_get_regs, - .get_coalesce = fbnic_get_coalesce, - .set_coalesce = fbnic_set_coalesce, - .get_ringparam = fbnic_get_ringparam, - .set_ringparam = fbnic_set_ringparam, - .get_strings = fbnic_get_strings, - .get_ethtool_stats = fbnic_get_ethtool_stats, - .get_sset_count = fbnic_get_sset_count, - .get_rxnfc = fbnic_get_rxnfc, - .set_rxnfc = fbnic_set_rxnfc, - .get_rxfh_key_size = fbnic_get_rxfh_key_size, - .get_rxfh_indir_size = fbnic_get_rxfh_indir_size, - .get_rxfh = fbnic_get_rxfh, - .set_rxfh = fbnic_set_rxfh, - .create_rxfh_context = fbnic_create_rxfh_context, - .modify_rxfh_context = fbnic_modify_rxfh_context, - .remove_rxfh_context = fbnic_remove_rxfh_context, - .get_channels = fbnic_get_channels, - .set_channels = fbnic_set_channels, - .get_ts_info = fbnic_get_ts_info, - .get_ts_stats = fbnic_get_ts_stats, - .get_eth_mac_stats = fbnic_get_eth_mac_stats, + .supported_coalesce_params = ETHTOOL_COALESCE_USECS | + ETHTOOL_COALESCE_RX_MAX_FRAMES, + .rxfh_max_num_contexts = FBNIC_RPC_RSS_TBL_COUNT, + .get_drvinfo = fbnic_get_drvinfo, + .get_regs_len = fbnic_get_regs_len, + .get_regs = fbnic_get_regs, + .get_link = ethtool_op_get_link, + .get_coalesce = fbnic_get_coalesce, + .set_coalesce = fbnic_set_coalesce, + .get_ringparam = fbnic_get_ringparam, + .set_ringparam = fbnic_set_ringparam, + .get_pauseparam = fbnic_phylink_get_pauseparam, + .set_pauseparam = fbnic_phylink_set_pauseparam, + .get_strings = fbnic_get_strings, + .get_ethtool_stats = fbnic_get_ethtool_stats, + .get_sset_count = fbnic_get_sset_count, + .get_rxnfc = fbnic_get_rxnfc, + .set_rxnfc = fbnic_set_rxnfc, + .get_rxfh_key_size = fbnic_get_rxfh_key_size, + .get_rxfh_indir_size = fbnic_get_rxfh_indir_size, + .get_rxfh = fbnic_get_rxfh, + .set_rxfh = fbnic_set_rxfh, + .get_rxfh_fields = fbnic_get_rss_hash_opts, + .set_rxfh_fields = fbnic_set_rss_hash_opts, + .create_rxfh_context = fbnic_create_rxfh_context, + .modify_rxfh_context = fbnic_modify_rxfh_context, + .remove_rxfh_context = fbnic_remove_rxfh_context, + .get_channels = fbnic_get_channels, + .set_channels = fbnic_set_channels, + .get_ts_info = fbnic_get_ts_info, + .get_ts_stats = fbnic_get_ts_stats, + .get_link_ksettings = fbnic_phylink_ethtool_ksettings_get, + .get_fecparam = fbnic_phylink_get_fecparam, + .get_eth_mac_stats = fbnic_get_eth_mac_stats, + .get_eth_ctrl_stats = fbnic_get_eth_ctrl_stats, + .get_rmon_stats = fbnic_get_rmon_stats, }; void fbnic_set_ethtool_ops(struct net_device *dev) diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_fw.c b/drivers/net/ethernet/meta/fbnic/fbnic_fw.c index 4521d0483d18..0c55be7d2547 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_fw.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_fw.c @@ -95,6 +95,9 @@ void fbnic_mbx_init(struct fbnic_dev *fbd) /* Initialize lock to protect Tx ring */ spin_lock_init(&fbd->fw_tx_lock); + /* Reset FW Capabilities */ + memset(&fbd->fw_cap, 0, sizeof(fbd->fw_cap)); + /* Reinitialize mailbox memory */ for (i = 0; i < FBNIC_IPC_MBX_INDICES; i++) memset(&fbd->mbx[i], 0, sizeof(struct fbnic_fw_mbx)); @@ -335,6 +338,16 @@ unlock_mbx: return err; } +void fbnic_mbx_clear_cmpl(struct fbnic_dev *fbd, + struct fbnic_fw_completion *fw_cmpl) +{ + unsigned long flags; + + spin_lock_irqsave(&fbd->fw_tx_lock, flags); + fbnic_mbx_clear_cmpl_slot(fbd, fw_cmpl); + spin_unlock_irqrestore(&fbd->fw_tx_lock, flags); +} + static void fbnic_fw_release_cmpl_data(struct kref *kref) { struct fbnic_fw_completion *cmpl_data; @@ -373,11 +386,11 @@ fbnic_fw_get_cmpl_by_type(struct fbnic_dev *fbd, u32 msg_type) * * Return: * One the following values: - * -EOPNOTSUPP: Is not ASIC so mailbox is not supported - * -ENODEV: Device I/O error - * -ENOMEM: Failed to allocate message - * -EBUSY: No space in mailbox - * -ENOSPC: DMA mapping failed + * -EOPNOTSUPP: Is not ASIC so mailbox is not supported + * -ENODEV: Device I/O error + * -ENOMEM: Failed to allocate message + * -EBUSY: No space in mailbox + * -ENOSPC: DMA mapping failed * * This function sends a single TLV header indicating the host wants to take * some action. However there are no other side effects which means that any @@ -560,16 +573,15 @@ static int fbnic_fw_parse_cap_resp(void *opaque, struct fbnic_tlv_msg **results) if (!fbd->fw_cap.running.mgmt.version) return -EINVAL; - if (fbd->fw_cap.running.mgmt.version < MIN_FW_VERSION_CODE) { + if (fbd->fw_cap.running.mgmt.version < MIN_FW_VER_CODE) { + char required_ver[FBNIC_FW_VER_MAX_SIZE]; char running_ver[FBNIC_FW_VER_MAX_SIZE]; fbnic_mk_fw_ver_str(fbd->fw_cap.running.mgmt.version, running_ver); - dev_err(fbd->dev, "Device firmware version(%s) is older than minimum required version(%02d.%02d.%02d)\n", - running_ver, - MIN_FW_MAJOR_VERSION, - MIN_FW_MINOR_VERSION, - MIN_FW_BUILD_VERSION); + fbnic_mk_fw_ver_str(MIN_FW_VER_CODE, required_ver); + dev_err(fbd->dev, "Device firmware version(%s) is older than minimum required version(%s)\n", + running_ver, required_ver); /* Disable TX mailbox to prevent card use until firmware is * updated. */ @@ -1022,6 +1034,169 @@ msg_err: return err; } +static const struct fbnic_tlv_index fbnic_fw_log_req_index[] = { + FBNIC_TLV_ATTR_U32(FBNIC_FW_LOG_MSEC), + FBNIC_TLV_ATTR_U64(FBNIC_FW_LOG_INDEX), + FBNIC_TLV_ATTR_STRING(FBNIC_FW_LOG_MSG, FBNIC_FW_LOG_MAX_SIZE), + FBNIC_TLV_ATTR_U32(FBNIC_FW_LOG_LENGTH), + FBNIC_TLV_ATTR_ARRAY(FBNIC_FW_LOG_MSEC_ARRAY), + FBNIC_TLV_ATTR_ARRAY(FBNIC_FW_LOG_INDEX_ARRAY), + FBNIC_TLV_ATTR_ARRAY(FBNIC_FW_LOG_MSG_ARRAY), + FBNIC_TLV_ATTR_LAST +}; + +static int fbnic_fw_process_log_array(struct fbnic_tlv_msg **results, + u16 length, u16 arr_type_idx, + u16 attr_type_idx, + struct fbnic_tlv_msg **tlv_array_out) +{ + struct fbnic_tlv_msg *attr; + int attr_len; + int err; + + if (!results[attr_type_idx]) + return -EINVAL; + + tlv_array_out[0] = results[attr_type_idx]; + + if (!length) + return 0; + + if (!results[arr_type_idx]) + return -EINVAL; + + attr = results[arr_type_idx]; + attr_len = le16_to_cpu(attr->hdr.len) / sizeof(u32) - 1; + err = fbnic_tlv_attr_parse_array(&attr[1], attr_len, &tlv_array_out[1], + fbnic_fw_log_req_index, + attr_type_idx, + length); + if (err) + return err; + + return 0; +} + +static int fbnic_fw_parse_logs(struct fbnic_dev *fbd, + struct fbnic_tlv_msg **msec_tlv, + struct fbnic_tlv_msg **index_tlv, + struct fbnic_tlv_msg **log_tlv, + int count) +{ + int i; + + for (i = 0; i < count; i++) { + char log[FBNIC_FW_LOG_MAX_SIZE]; + ssize_t len; + u64 index; + u32 msec; + int err; + + if (!msec_tlv[i] || !index_tlv[i] || !log_tlv[i]) { + dev_warn(fbd->dev, "Received log message with missing attributes!\n"); + return -EINVAL; + } + + index = fbnic_tlv_attr_get_signed(index_tlv[i], 0); + msec = fbnic_tlv_attr_get_signed(msec_tlv[i], 0); + len = fbnic_tlv_attr_get_string(log_tlv[i], log, + FBNIC_FW_LOG_MAX_SIZE); + if (len < 0) + return len; + + err = fbnic_fw_log_write(fbd, index, msec, log); + if (err) + return err; + } + + return 0; +} + +static int fbnic_fw_parse_log_req(void *opaque, + struct fbnic_tlv_msg **results) +{ + struct fbnic_tlv_msg *index_tlv[FBNIC_FW_MAX_LOG_HISTORY]; + struct fbnic_tlv_msg *msec_tlv[FBNIC_FW_MAX_LOG_HISTORY]; + struct fbnic_tlv_msg *log_tlv[FBNIC_FW_MAX_LOG_HISTORY]; + struct fbnic_dev *fbd = opaque; + u16 length; + int err; + + length = fta_get_uint(results, FBNIC_FW_LOG_LENGTH); + if (length >= FBNIC_FW_MAX_LOG_HISTORY) + return -E2BIG; + + err = fbnic_fw_process_log_array(results, length, + FBNIC_FW_LOG_MSEC_ARRAY, + FBNIC_FW_LOG_MSEC, msec_tlv); + if (err) + return err; + + err = fbnic_fw_process_log_array(results, length, + FBNIC_FW_LOG_INDEX_ARRAY, + FBNIC_FW_LOG_INDEX, index_tlv); + if (err) + return err; + + err = fbnic_fw_process_log_array(results, length, + FBNIC_FW_LOG_MSG_ARRAY, + FBNIC_FW_LOG_MSG, log_tlv); + if (err) + return err; + + err = fbnic_fw_parse_logs(fbd, msec_tlv, index_tlv, log_tlv, + length + 1); + if (err) + return err; + + return 0; +} + +int fbnic_fw_xmit_send_logs(struct fbnic_dev *fbd, bool enable, + bool send_log_history) +{ + struct fbnic_tlv_msg *msg; + int err; + + if (fbd->fw_cap.running.mgmt.version < MIN_FW_VER_CODE_LOG) { + dev_warn(fbd->dev, "Firmware version is too old to support firmware logs!\n"); + return -EOPNOTSUPP; + } + + msg = fbnic_tlv_msg_alloc(FBNIC_TLV_MSG_ID_LOG_SEND_LOGS_REQ); + if (!msg) + return -ENOMEM; + + if (enable) { + err = fbnic_tlv_attr_put_flag(msg, FBNIC_SEND_LOGS); + if (err) + goto free_message; + + /* Report request for version 1 of logs */ + err = fbnic_tlv_attr_put_int(msg, FBNIC_SEND_LOGS_VERSION, + FBNIC_FW_LOG_VERSION); + if (err) + goto free_message; + + if (send_log_history) { + err = fbnic_tlv_attr_put_flag(msg, + FBNIC_SEND_LOGS_HISTORY); + if (err) + goto free_message; + } + } + + err = fbnic_mbx_map_tlv_msg(fbd, msg); + if (err) + goto free_message; + + return 0; + +free_message: + free_page((unsigned long)msg); + return err; +} + static const struct fbnic_tlv_parser fbnic_fw_tlv_parser[] = { FBNIC_TLV_PARSER(FW_CAP_RESP, fbnic_fw_cap_resp_index, fbnic_fw_parse_cap_resp), @@ -1041,6 +1216,9 @@ static const struct fbnic_tlv_parser fbnic_fw_tlv_parser[] = { FBNIC_TLV_PARSER(TSENE_READ_RESP, fbnic_tsene_read_resp_index, fbnic_fw_parse_tsene_read_resp), + FBNIC_TLV_PARSER(LOG_MSG_REQ, + fbnic_fw_log_req_index, + fbnic_fw_parse_log_req), FBNIC_TLV_MSG_ERROR }; @@ -1117,6 +1295,7 @@ void fbnic_mbx_poll(struct fbnic_dev *fbd) int fbnic_mbx_poll_tx_ready(struct fbnic_dev *fbd) { + struct fbnic_fw_mbx *tx_mbx = &fbd->mbx[FBNIC_IPC_MBX_TX_IDX]; unsigned long timeout = jiffies + 10 * HZ + 1; int err, i; @@ -1149,8 +1328,23 @@ int fbnic_mbx_poll_tx_ready(struct fbnic_dev *fbd) if (err) goto clean_mbx; - /* Use "1" to indicate we entered the state waiting for a response */ - fbd->fw_cap.running.mgmt.version = 1; + /* Poll until we get a current management firmware version, use "1" + * to indicate we entered the polling state waiting for a response + */ + for (fbd->fw_cap.running.mgmt.version = 1; + fbd->fw_cap.running.mgmt.version < MIN_FW_VER_CODE;) { + if (!tx_mbx->ready) + err = -ENODEV; + if (err) + goto clean_mbx; + + msleep(20); + fbnic_mbx_poll(fbd); + + /* set err, but wait till mgmt.version check to report it */ + if (!time_is_after_jiffies(timeout)) + err = -ETIMEDOUT; + } return 0; clean_mbx: @@ -1244,16 +1438,6 @@ struct fbnic_fw_completion *fbnic_fw_alloc_cmpl(u32 msg_type) return cmpl; } -void fbnic_fw_clear_cmpl(struct fbnic_dev *fbd, - struct fbnic_fw_completion *fw_cmpl) -{ - unsigned long flags; - - spin_lock_irqsave(&fbd->fw_tx_lock, flags); - fbnic_mbx_clear_cmpl_slot(fbd, fw_cmpl); - spin_unlock_irqrestore(&fbd->fw_tx_lock, flags); -} - void fbnic_fw_put_cmpl(struct fbnic_fw_completion *fw_cmpl) { kref_put(&fw_cmpl->ref_count, fbnic_fw_release_cmpl_data); diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_fw.h b/drivers/net/ethernet/meta/fbnic/fbnic_fw.h index 08bc4b918de7..fde331696fdd 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_fw.h +++ b/drivers/net/ethernet/meta/fbnic/fbnic_fw.h @@ -19,10 +19,23 @@ struct fbnic_fw_mbx { }; // FW_VER_MAX_SIZE must match ETHTOOL_FWVERS_LEN -#define FBNIC_FW_VER_MAX_SIZE 32 +#define FBNIC_FW_VER_MAX_SIZE 32 // Formatted version is in the format XX.YY.ZZ_RRR_COMMIT #define FBNIC_FW_CAP_RESP_COMMIT_MAX_SIZE (FBNIC_FW_VER_MAX_SIZE - 13) -#define FBNIC_FW_LOG_MAX_SIZE 256 +#define FBNIC_FW_LOG_VERSION 1 +#define FBNIC_FW_LOG_MAX_SIZE 256 +/* + * The max amount of logs which can fit in a single mailbox message. Firmware + * assumes each mailbox message is 4096B. The amount of messages supported is + * calculated as 4096 minus headers for message, arrays, and length minus the + * size of length divided by headers for each array plus the maximum LOG size, + * and the size of MSEC and INDEX. Put another way: + * + * MAX_LOG_HISTORY = ((4096 - TLV_HDR_SZ * 5 - LENGTH_SZ) + * / (FBNIC_FW_LOG_MAX_SIZE + TLV_HDR_SZ * 3 + MSEC_SZ + * + INDEX_SZ)) + */ +#define FBNIC_FW_MAX_LOG_HISTORY 14 struct fbnic_fw_ver { u32 version; @@ -66,6 +79,8 @@ void fbnic_mbx_init(struct fbnic_dev *fbd); void fbnic_mbx_clean(struct fbnic_dev *fbd); int fbnic_mbx_set_cmpl(struct fbnic_dev *fbd, struct fbnic_fw_completion *cmpl_data); +void fbnic_mbx_clear_cmpl(struct fbnic_dev *fbd, + struct fbnic_fw_completion *cmpl_data); void fbnic_mbx_poll(struct fbnic_dev *fbd); int fbnic_mbx_poll_tx_ready(struct fbnic_dev *fbd); void fbnic_mbx_flush_tx(struct fbnic_dev *fbd); @@ -80,9 +95,9 @@ int fbnic_fw_xmit_fw_write_chunk(struct fbnic_dev *fbd, int cancel_error); int fbnic_fw_xmit_tsene_read_msg(struct fbnic_dev *fbd, struct fbnic_fw_completion *cmpl_data); +int fbnic_fw_xmit_send_logs(struct fbnic_dev *fbd, bool enable, + bool send_log_history); struct fbnic_fw_completion *fbnic_fw_alloc_cmpl(u32 msg_type); -void fbnic_fw_clear_cmpl(struct fbnic_dev *fbd, - struct fbnic_fw_completion *cmpl_data); void fbnic_fw_put_cmpl(struct fbnic_fw_completion *cmpl_data); #define fbnic_mk_full_fw_ver_str(_rev_id, _delim, _commit, _str, _str_sz) \ @@ -125,6 +140,9 @@ enum { FBNIC_TLV_MSG_ID_FW_FINISH_UPGRADE_RESP = 0x29, FBNIC_TLV_MSG_ID_TSENE_READ_REQ = 0x3C, FBNIC_TLV_MSG_ID_TSENE_READ_RESP = 0x3D, + FBNIC_TLV_MSG_ID_LOG_SEND_LOGS_REQ = 0x43, + FBNIC_TLV_MSG_ID_LOG_MSG_REQ = 0x44, + FBNIC_TLV_MSG_ID_LOG_MSG_RESP = 0x45, }; #define FBNIC_FW_CAP_RESP_VERSION_MAJOR CSR_GENMASK(31, 24) @@ -155,10 +173,10 @@ enum { }; enum { - FBNIC_FW_LINK_SPEED_25R1 = 1, - FBNIC_FW_LINK_SPEED_50R2 = 2, - FBNIC_FW_LINK_SPEED_50R1 = 3, - FBNIC_FW_LINK_SPEED_100R2 = 4, + FBNIC_FW_LINK_MODE_25CR = 1, + FBNIC_FW_LINK_MODE_50CR2 = 2, + FBNIC_FW_LINK_MODE_50CR = 3, + FBNIC_FW_LINK_MODE_100CR2 = 4, }; enum { @@ -199,4 +217,22 @@ enum { FBNIC_FW_FINISH_UPGRADE_MSG_MAX }; +enum { + FBNIC_SEND_LOGS = 0x0, + FBNIC_SEND_LOGS_VERSION = 0x1, + FBNIC_SEND_LOGS_HISTORY = 0x2, + FBNIC_SEND_LOGS_MSG_MAX +}; + +enum { + FBNIC_FW_LOG_MSEC = 0x0, + FBNIC_FW_LOG_INDEX = 0x1, + FBNIC_FW_LOG_MSG = 0x2, + FBNIC_FW_LOG_LENGTH = 0x3, + FBNIC_FW_LOG_MSEC_ARRAY = 0x4, + FBNIC_FW_LOG_INDEX_ARRAY = 0x5, + FBNIC_FW_LOG_MSG_ARRAY = 0x6, + FBNIC_FW_LOG_MSG_MAX +}; + #endif /* _FBNIC_FW_H_ */ diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_fw_log.c b/drivers/net/ethernet/meta/fbnic/fbnic_fw_log.c new file mode 100644 index 000000000000..c1663f042245 --- /dev/null +++ b/drivers/net/ethernet/meta/fbnic/fbnic_fw_log.c @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) Meta Platforms, Inc. and affiliates. */ + +#include <linux/spinlock.h> +#include <linux/vmalloc.h> + +#include "fbnic.h" +#include "fbnic_fw.h" +#include "fbnic_fw_log.h" + +void fbnic_fw_log_enable(struct fbnic_dev *fbd, bool send_hist) +{ + int err; + + if (!fbnic_fw_log_ready(fbd)) + return; + + if (fbd->fw_cap.running.mgmt.version < MIN_FW_VER_CODE_HIST) + send_hist = false; + + err = fbnic_fw_xmit_send_logs(fbd, true, send_hist); + if (err && err != -EOPNOTSUPP) + dev_warn(fbd->dev, "Unable to enable firmware logs: %d\n", err); +} + +void fbnic_fw_log_disable(struct fbnic_dev *fbd) +{ + int err; + + err = fbnic_fw_xmit_send_logs(fbd, false, false); + if (err && err != -EOPNOTSUPP) + dev_warn(fbd->dev, "Unable to disable firmware logs: %d\n", + err); +} + +int fbnic_fw_log_init(struct fbnic_dev *fbd) +{ + struct fbnic_fw_log *log = &fbd->fw_log; + void *data; + + if (WARN_ON_ONCE(fbnic_fw_log_ready(fbd))) + return -EEXIST; + + data = vmalloc(FBNIC_FW_LOG_SIZE); + if (!data) + return -ENOMEM; + + spin_lock_init(&fbd->fw_log.lock); + INIT_LIST_HEAD(&log->entries); + log->size = FBNIC_FW_LOG_SIZE; + log->data_start = data; + log->data_end = data + FBNIC_FW_LOG_SIZE; + + fbnic_fw_log_enable(fbd, true); + + return 0; +} + +void fbnic_fw_log_free(struct fbnic_dev *fbd) +{ + struct fbnic_fw_log *log = &fbd->fw_log; + + if (!fbnic_fw_log_ready(fbd)) + return; + + fbnic_fw_log_disable(fbd); + INIT_LIST_HEAD(&log->entries); + log->size = 0; + vfree(log->data_start); + log->data_start = NULL; + log->data_end = NULL; +} + +int fbnic_fw_log_write(struct fbnic_dev *fbd, u64 index, u32 timestamp, + char *msg) +{ + struct fbnic_fw_log_entry *entry, *head, *tail, *next; + struct fbnic_fw_log *log = &fbd->fw_log; + size_t msg_len = strlen(msg) + 1; + unsigned long flags; + void *entry_end; + + if (!fbnic_fw_log_ready(fbd)) { + dev_err(fbd->dev, "Firmware sent log entry without being requested!\n"); + return -ENOSPC; + } + + spin_lock_irqsave(&log->lock, flags); + + if (list_empty(&log->entries)) { + entry = log->data_start; + } else { + head = list_first_entry(&log->entries, typeof(*head), list); + entry_end = head->msg + head->len + 1; + entry = PTR_ALIGN(entry_end, 8); + } + + entry_end = entry->msg + msg_len + 1; + + /* We've reached the end of the buffer, wrap around */ + if (entry_end > log->data_end) { + entry = log->data_start; + entry_end = entry->msg + msg_len + 1; + } + + /* Make room for entry by removing from tail. */ + list_for_each_entry_safe_reverse(tail, next, &log->entries, list) { + if (entry <= tail && entry_end > (void *)tail) + list_del(&tail->list); + else + break; + } + + entry->index = index; + entry->timestamp = timestamp; + entry->len = msg_len; + strscpy(entry->msg, msg, entry->len); + list_add(&entry->list, &log->entries); + + spin_unlock_irqrestore(&log->lock, flags); + + return 0; +} diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_fw_log.h b/drivers/net/ethernet/meta/fbnic/fbnic_fw_log.h new file mode 100644 index 000000000000..cb6555f40a24 --- /dev/null +++ b/drivers/net/ethernet/meta/fbnic/fbnic_fw_log.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) Meta Platforms, Inc. and affiliates. */ + +#ifndef _FBNIC_FW_LOG_H_ +#define _FBNIC_FW_LOG_H_ + +#include <linux/spinlock.h> +#include <linux/types.h> + +/* A 512K log buffer was chosen fairly arbitrarily */ +#define FBNIC_FW_LOG_SIZE (512 * 1024) /* bytes */ + +/* Firmware log output is prepended with log index followed by a timestamp. + * The timestamp is similar to Zephyr's format DD:HH:MM:SS.MMM + */ +#define FBNIC_FW_LOG_FMT "[%5lld] [%02ld:%02ld:%02ld:%02ld.%03ld] %s\n" + +struct fbnic_dev; + +struct fbnic_fw_log_entry { + struct list_head list; + u64 index; + u32 timestamp; + u16 len; + char msg[] __counted_by(len); +}; + +struct fbnic_fw_log { + void *data_start; + void *data_end; + size_t size; + struct list_head entries; + /* Spin lock for accessing or modifying entries */ + spinlock_t lock; +}; + +#define fbnic_fw_log_ready(_fbd) (!!(_fbd)->fw_log.data_start) + +void fbnic_fw_log_enable(struct fbnic_dev *fbd, bool send_hist); +void fbnic_fw_log_disable(struct fbnic_dev *fbd); +int fbnic_fw_log_init(struct fbnic_dev *fbd); +void fbnic_fw_log_free(struct fbnic_dev *fbd); +int fbnic_fw_log_write(struct fbnic_dev *fbd, u64 index, u32 timestamp, + char *msg); +#endif /* _FBNIC_FW_LOG_H_ */ diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_hw_stats.h b/drivers/net/ethernet/meta/fbnic/fbnic_hw_stats.h index 07e54bb75bf3..4fe239717497 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_hw_stats.h +++ b/drivers/net/ethernet/meta/fbnic/fbnic_hw_stats.h @@ -22,6 +22,23 @@ struct fbnic_hw_stat { struct fbnic_stat_counter bytes; }; +/* Note: not updated by fbnic_get_hw_stats() */ +struct fbnic_eth_ctrl_stats { + struct fbnic_stat_counter MACControlFramesTransmitted; + struct fbnic_stat_counter MACControlFramesReceived; +}; + +/* Note: not updated by fbnic_get_hw_stats() */ +struct fbnic_rmon_stats { + struct fbnic_stat_counter undersize_pkts; + struct fbnic_stat_counter oversize_pkts; + struct fbnic_stat_counter fragments; + struct fbnic_stat_counter jabbers; + + struct fbnic_stat_counter hist[ETHTOOL_RMON_HIST_MAX]; + struct fbnic_stat_counter hist_tx[ETHTOOL_RMON_HIST_MAX]; +}; + struct fbnic_eth_mac_stats { struct fbnic_stat_counter FramesTransmittedOK; struct fbnic_stat_counter FramesReceivedOK; @@ -40,6 +57,8 @@ struct fbnic_eth_mac_stats { struct fbnic_mac_stats { struct fbnic_eth_mac_stats eth_mac; + struct fbnic_eth_ctrl_stats eth_ctrl; + struct fbnic_rmon_stats rmon; }; struct fbnic_tmi_stats { diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_mac.c b/drivers/net/ethernet/meta/fbnic/fbnic_mac.c index 10e108c1fcd0..fd8d67f9048e 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_mac.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_mac.c @@ -452,7 +452,7 @@ static u32 __fbnic_mac_cmd_config_asic(struct fbnic_dev *fbd, command_config |= FBNIC_MAC_COMMAND_CONFIG_RX_PAUSE_DIS; /* Disable fault handling if no FEC is requested */ - if ((fbn->fec & FBNIC_FEC_MODE_MASK) == FBNIC_FEC_OFF) + if (fbn->fec == FBNIC_FEC_OFF) command_config |= FBNIC_MAC_COMMAND_CONFIG_FLT_HDL_DIS; return command_config; @@ -468,15 +468,15 @@ static bool fbnic_mac_get_pcs_link_status(struct fbnic_dev *fbd) return false; /* Define the expected lane mask for the status bits we need to check */ - switch (fbn->link_mode & FBNIC_LINK_MODE_MASK) { - case FBNIC_LINK_100R2: + switch (fbn->aui) { + case FBNIC_AUI_100GAUI2: lane_mask = 0xf; break; - case FBNIC_LINK_50R1: + case FBNIC_AUI_50GAUI1: lane_mask = 3; break; - case FBNIC_LINK_50R2: - switch (fbn->fec & FBNIC_FEC_MODE_MASK) { + case FBNIC_AUI_LAUI2: + switch (fbn->fec) { case FBNIC_FEC_OFF: lane_mask = 0x63; break; @@ -488,13 +488,13 @@ static bool fbnic_mac_get_pcs_link_status(struct fbnic_dev *fbd) break; } break; - case FBNIC_LINK_25R1: + case FBNIC_AUI_25GAUI: lane_mask = 1; break; } /* Use an XOR to remove the bits we expect to see set */ - switch (fbn->fec & FBNIC_FEC_MODE_MASK) { + switch (fbn->fec) { case FBNIC_FEC_OFF: lane_mask ^= FIELD_GET(FBNIC_SIG_PCS_OUT0_BLOCK_LOCK, pcs_status); @@ -540,53 +540,41 @@ static bool fbnic_pcs_get_link_asic(struct fbnic_dev *fbd) return link; } -static void fbnic_pcs_get_fw_settings(struct fbnic_dev *fbd) +void fbnic_mac_get_fw_settings(struct fbnic_dev *fbd, u8 *aui, u8 *fec) { - struct fbnic_net *fbn = netdev_priv(fbd->netdev); - u8 link_mode = fbn->link_mode; - u8 fec = fbn->fec; - - /* Update FEC first to reflect FW current mode */ - if (fbn->fec & FBNIC_FEC_AUTO) { - switch (fbd->fw_cap.link_fec) { - case FBNIC_FW_LINK_FEC_NONE: - fec = FBNIC_FEC_OFF; - break; - case FBNIC_FW_LINK_FEC_RS: - fec = FBNIC_FEC_RS; - break; - case FBNIC_FW_LINK_FEC_BASER: - fec = FBNIC_FEC_BASER; - break; - default: - return; - } - - fbn->fec = fec; + /* Retrieve default speed from FW */ + switch (fbd->fw_cap.link_speed) { + case FBNIC_FW_LINK_MODE_25CR: + *aui = FBNIC_AUI_25GAUI; + break; + case FBNIC_FW_LINK_MODE_50CR2: + *aui = FBNIC_AUI_LAUI2; + break; + case FBNIC_FW_LINK_MODE_50CR: + *aui = FBNIC_AUI_50GAUI1; + *fec = FBNIC_FEC_RS; + return; + case FBNIC_FW_LINK_MODE_100CR2: + *aui = FBNIC_AUI_100GAUI2; + *fec = FBNIC_FEC_RS; + return; + default: + *aui = FBNIC_AUI_UNKNOWN; + return; } - /* Do nothing if AUTO mode is not engaged */ - if (fbn->link_mode & FBNIC_LINK_AUTO) { - switch (fbd->fw_cap.link_speed) { - case FBNIC_FW_LINK_SPEED_25R1: - link_mode = FBNIC_LINK_25R1; - break; - case FBNIC_FW_LINK_SPEED_50R2: - link_mode = FBNIC_LINK_50R2; - break; - case FBNIC_FW_LINK_SPEED_50R1: - link_mode = FBNIC_LINK_50R1; - fec = FBNIC_FEC_RS; - break; - case FBNIC_FW_LINK_SPEED_100R2: - link_mode = FBNIC_LINK_100R2; - fec = FBNIC_FEC_RS; - break; - default: - return; - } - - fbn->link_mode = link_mode; + /* Update FEC first to reflect FW current mode */ + switch (fbd->fw_cap.link_fec) { + case FBNIC_FW_LINK_FEC_NONE: + *fec = FBNIC_FEC_OFF; + break; + case FBNIC_FW_LINK_FEC_RS: + default: + *fec = FBNIC_FEC_RS; + break; + case FBNIC_FW_LINK_FEC_BASER: + *fec = FBNIC_FEC_BASER; + break; } } @@ -596,9 +584,6 @@ static int fbnic_pcs_enable_asic(struct fbnic_dev *fbd) wr32(fbd, FBNIC_SIG_PCS_INTR_MASK, ~0); wr32(fbd, FBNIC_SIG_PCS_INTR_STS, ~0); - /* Pull in settings from FW */ - fbnic_pcs_get_fw_settings(fbd); - return 0; } @@ -680,6 +665,76 @@ fbnic_mac_get_eth_mac_stats(struct fbnic_dev *fbd, bool reset, MAC_STAT_TX_BROADCAST); } +static void +fbnic_mac_get_eth_ctrl_stats(struct fbnic_dev *fbd, bool reset, + struct fbnic_eth_ctrl_stats *ctrl_stats) +{ + fbnic_mac_stat_rd64(fbd, reset, ctrl_stats->MACControlFramesReceived, + MAC_STAT_RX_CONTROL_FRAMES); + fbnic_mac_stat_rd64(fbd, reset, ctrl_stats->MACControlFramesTransmitted, + MAC_STAT_TX_CONTROL_FRAMES); +} + +static void +fbnic_mac_get_rmon_stats(struct fbnic_dev *fbd, bool reset, + struct fbnic_rmon_stats *rmon_stats) +{ + fbnic_mac_stat_rd64(fbd, reset, rmon_stats->undersize_pkts, + MAC_STAT_RX_UNDERSIZE); + fbnic_mac_stat_rd64(fbd, reset, rmon_stats->oversize_pkts, + MAC_STAT_RX_OVERSIZE); + fbnic_mac_stat_rd64(fbd, reset, rmon_stats->fragments, + MAC_STAT_RX_FRAGMENT); + fbnic_mac_stat_rd64(fbd, reset, rmon_stats->jabbers, + MAC_STAT_RX_JABBER); + + fbnic_mac_stat_rd64(fbd, reset, rmon_stats->hist[0], + MAC_STAT_RX_PACKET_64_BYTES); + fbnic_mac_stat_rd64(fbd, reset, rmon_stats->hist[1], + MAC_STAT_RX_PACKET_65_127_BYTES); + fbnic_mac_stat_rd64(fbd, reset, rmon_stats->hist[2], + MAC_STAT_RX_PACKET_128_255_BYTES); + fbnic_mac_stat_rd64(fbd, reset, rmon_stats->hist[3], + MAC_STAT_RX_PACKET_256_511_BYTES); + fbnic_mac_stat_rd64(fbd, reset, rmon_stats->hist[4], + MAC_STAT_RX_PACKET_512_1023_BYTES); + fbnic_mac_stat_rd64(fbd, reset, rmon_stats->hist[5], + MAC_STAT_RX_PACKET_1024_1518_BYTES); + fbnic_mac_stat_rd64(fbd, reset, rmon_stats->hist[6], + RPC_STAT_RX_PACKET_1519_2047_BYTES); + fbnic_mac_stat_rd64(fbd, reset, rmon_stats->hist[7], + RPC_STAT_RX_PACKET_2048_4095_BYTES); + fbnic_mac_stat_rd64(fbd, reset, rmon_stats->hist[8], + RPC_STAT_RX_PACKET_4096_8191_BYTES); + fbnic_mac_stat_rd64(fbd, reset, rmon_stats->hist[9], + RPC_STAT_RX_PACKET_8192_9216_BYTES); + fbnic_mac_stat_rd64(fbd, reset, rmon_stats->hist[10], + RPC_STAT_RX_PACKET_9217_MAX_BYTES); + + fbnic_mac_stat_rd64(fbd, reset, rmon_stats->hist_tx[0], + MAC_STAT_TX_PACKET_64_BYTES); + fbnic_mac_stat_rd64(fbd, reset, rmon_stats->hist_tx[1], + MAC_STAT_TX_PACKET_65_127_BYTES); + fbnic_mac_stat_rd64(fbd, reset, rmon_stats->hist_tx[2], + MAC_STAT_TX_PACKET_128_255_BYTES); + fbnic_mac_stat_rd64(fbd, reset, rmon_stats->hist_tx[3], + MAC_STAT_TX_PACKET_256_511_BYTES); + fbnic_mac_stat_rd64(fbd, reset, rmon_stats->hist_tx[4], + MAC_STAT_TX_PACKET_512_1023_BYTES); + fbnic_mac_stat_rd64(fbd, reset, rmon_stats->hist_tx[5], + MAC_STAT_TX_PACKET_1024_1518_BYTES); + fbnic_mac_stat_rd64(fbd, reset, rmon_stats->hist_tx[6], + TMI_STAT_TX_PACKET_1519_2047_BYTES); + fbnic_mac_stat_rd64(fbd, reset, rmon_stats->hist_tx[7], + TMI_STAT_TX_PACKET_2048_4095_BYTES); + fbnic_mac_stat_rd64(fbd, reset, rmon_stats->hist_tx[8], + TMI_STAT_TX_PACKET_4096_8191_BYTES); + fbnic_mac_stat_rd64(fbd, reset, rmon_stats->hist_tx[9], + TMI_STAT_TX_PACKET_8192_9216_BYTES); + fbnic_mac_stat_rd64(fbd, reset, rmon_stats->hist_tx[10], + TMI_STAT_TX_PACKET_9217_MAX_BYTES); +} + static int fbnic_mac_get_sensor_asic(struct fbnic_dev *fbd, int id, long *val) { @@ -741,7 +796,7 @@ static int fbnic_mac_get_sensor_asic(struct fbnic_dev *fbd, int id, *val = *sensor; exit_cleanup: - fbnic_fw_clear_cmpl(fbd, fw_cmpl); + fbnic_mbx_clear_cmpl(fbd, fw_cmpl); exit_free: fbnic_fw_put_cmpl(fw_cmpl); @@ -755,6 +810,8 @@ static const struct fbnic_mac fbnic_mac_asic = { .pcs_get_link = fbnic_pcs_get_link_asic, .pcs_get_link_event = fbnic_pcs_get_link_event_asic, .get_eth_mac_stats = fbnic_mac_get_eth_mac_stats, + .get_eth_ctrl_stats = fbnic_mac_get_eth_ctrl_stats, + .get_rmon_stats = fbnic_mac_get_rmon_stats, .link_down = fbnic_mac_link_down_asic, .link_up = fbnic_mac_link_up_asic, .get_sensor = fbnic_mac_get_sensor_asic, diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_mac.h b/drivers/net/ethernet/meta/fbnic/fbnic_mac.h index 05a591653e09..86fa06da2b3e 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_mac.h +++ b/drivers/net/ethernet/meta/fbnic/fbnic_mac.h @@ -25,27 +25,23 @@ enum { FBNIC_FEC_OFF = 0, FBNIC_FEC_RS = 1, FBNIC_FEC_BASER = 2, - FBNIC_FEC_AUTO = 4, }; -#define FBNIC_FEC_MODE_MASK (FBNIC_FEC_AUTO - 1) - -/* Treat the link modes as a set of modulation/lanes bitmask: +/* Treat the AUI modes as a modulation/lanes bitmask: * Bit 0: Lane Count, 0 = R1, 1 = R2 * Bit 1: Modulation, 0 = NRZ, 1 = PAM4 - * Bit 2: Retrieve link mode from FW + * Bit 2: Unknown Modulation/Lane Configuration */ enum { - FBNIC_LINK_25R1 = 0, - FBNIC_LINK_50R2 = 1, - FBNIC_LINK_50R1 = 2, - FBNIC_LINK_100R2 = 3, - FBNIC_LINK_AUTO = 4, + FBNIC_AUI_25GAUI = 0, /* 25.7812GBd 25.78125 * 1 */ + FBNIC_AUI_LAUI2 = 1, /* 51.5625GBd 25.78128 * 2 */ + FBNIC_AUI_50GAUI1 = 2, /* 53.125GBd 53.125 * 1 */ + FBNIC_AUI_100GAUI2 = 3, /* 106.25GBd 53.125 * 2 */ + FBNIC_AUI_UNKNOWN = 4, }; -#define FBNIC_LINK_MODE_R2 (FBNIC_LINK_50R2) -#define FBNIC_LINK_MODE_PAM4 (FBNIC_LINK_50R1) -#define FBNIC_LINK_MODE_MASK (FBNIC_LINK_AUTO - 1) +#define FBNIC_AUI_MODE_R2 (FBNIC_AUI_LAUI2) +#define FBNIC_AUI_MODE_PAM4 (FBNIC_AUI_50GAUI1) enum fbnic_sensor_id { FBNIC_SENSOR_TEMP, /* Temp in millidegrees Centigrade */ @@ -85,6 +81,10 @@ struct fbnic_mac { void (*get_eth_mac_stats)(struct fbnic_dev *fbd, bool reset, struct fbnic_eth_mac_stats *mac_stats); + void (*get_eth_ctrl_stats)(struct fbnic_dev *fbd, bool reset, + struct fbnic_eth_ctrl_stats *ctrl_stats); + void (*get_rmon_stats)(struct fbnic_dev *fbd, bool reset, + struct fbnic_rmon_stats *rmon_stats); void (*link_down)(struct fbnic_dev *fbd); void (*link_up)(struct fbnic_dev *fbd, bool tx_pause, bool rx_pause); @@ -93,4 +93,5 @@ struct fbnic_mac { }; int fbnic_mac_init(struct fbnic_dev *fbd); +void fbnic_mac_get_fw_settings(struct fbnic_dev *fbd, u8 *aui, u8 *fec); #endif /* _FBNIC_MAC_H_ */ diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c index aa812c63d5af..7bd7812d9c06 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c @@ -736,8 +736,6 @@ struct net_device *fbnic_netdev_alloc(struct fbnic_dev *fbd) */ netdev->ethtool->wol_enabled = true; - fbn->fec = FBNIC_FEC_AUTO | FBNIC_FEC_RS; - fbn->link_mode = FBNIC_LINK_AUTO | FBNIC_LINK_50R2; netif_carrier_off(netdev); netif_tx_stop_all_queues(netdev); diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.h b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.h index 561837e80ec8..86576ae04262 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.h +++ b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.h @@ -4,8 +4,8 @@ #ifndef _FBNIC_NETDEV_H_ #define _FBNIC_NETDEV_H_ -#include <linux/types.h> #include <linux/phylink.h> +#include <linux/types.h> #include "fbnic_csr.h" #include "fbnic_rpc.h" @@ -42,9 +42,8 @@ struct fbnic_net { struct phylink_config phylink_config; struct phylink_pcs phylink_pcs; - /* TBD: Remove these when phylink supports FEC and lane config */ + u8 aui; u8 fec; - u8 link_mode; /* Cached top bits of the HW time counter for 40b -> 64b conversion */ u32 time_high; @@ -67,7 +66,7 @@ struct fbnic_net { struct fbnic_queue_stats rx_stats; u64 link_down_events; - /* Time stampinn filter config */ + /* Time stamping filter config */ struct kernel_hwtstamp_config hwtstamp_config; }; @@ -82,6 +81,7 @@ int fbnic_netdev_register(struct net_device *netdev); void fbnic_netdev_unregister(struct net_device *netdev); void fbnic_reset_queues(struct fbnic_net *fbn, unsigned int tx, unsigned int rx); + void fbnic_set_ethtool_ops(struct net_device *dev); int fbnic_ptp_setup(struct fbnic_dev *fbd); @@ -93,5 +93,13 @@ void fbnic_time_stop(struct fbnic_net *fbn); void __fbnic_set_rx_mode(struct net_device *netdev); void fbnic_clear_rx_mode(struct net_device *netdev); +void fbnic_phylink_get_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *pause); +int fbnic_phylink_set_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *pause); +int fbnic_phylink_ethtool_ksettings_get(struct net_device *netdev, + struct ethtool_link_ksettings *cmd); +int fbnic_phylink_get_fecparam(struct net_device *netdev, + struct ethtool_fecparam *fecparam); int fbnic_phylink_init(struct net_device *netdev); #endif /* _FBNIC_NETDEV_H_ */ diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_pci.c b/drivers/net/ethernet/meta/fbnic/fbnic_pci.c index 249d3ef862d5..b70e4cadb37b 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_pci.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_pci.c @@ -291,6 +291,17 @@ static int fbnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto free_irqs; } + /* Send the request to enable the FW logging to host. Note if this + * fails we ignore the error and just display a message as it is + * possible the FW is just too old to support the logging and needs + * to be updated. + */ + err = fbnic_fw_log_init(fbd); + if (err) + dev_warn(fbd->dev, + "Unable to initialize firmware log buffer: %d\n", + err); + fbnic_devlink_register(fbd); fbnic_dbg_fbd_init(fbd); spin_lock_init(&fbd->hw_stats_lock); @@ -365,6 +376,7 @@ static void fbnic_remove(struct pci_dev *pdev) fbnic_hwmon_unregister(fbd); fbnic_dbg_fbd_exit(fbd); fbnic_devlink_unregister(fbd); + fbnic_fw_log_free(fbd); fbnic_fw_free_mbx(fbd); fbnic_free_irqs(fbd); @@ -389,6 +401,8 @@ static int fbnic_pm_suspend(struct device *dev) rtnl_unlock(); null_uc_addr: + fbnic_fw_log_disable(fbd); + devl_lock(priv_to_devlink(fbd)); fbnic_fw_free_mbx(fbd); @@ -434,6 +448,11 @@ static int __fbnic_pm_resume(struct device *dev) devl_unlock(priv_to_devlink(fbd)); + /* Only send log history if log buffer is empty to prevent duplicate + * log entries. + */ + fbnic_fw_log_enable(fbd, list_empty(&fbd->fw_log.entries)); + /* No netdev means there isn't a network interface to bring up */ if (fbnic_init_failure(fbd)) return 0; @@ -455,6 +474,8 @@ static int __fbnic_pm_resume(struct device *dev) return 0; err_free_mbx: + fbnic_fw_log_disable(fbd); + rtnl_unlock(); fbnic_fw_free_mbx(fbd); err_free_irqs: diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_phylink.c b/drivers/net/ethernet/meta/fbnic/fbnic_phylink.c index 860b02b22c15..7ce3fdd25282 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_phylink.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_phylink.c @@ -8,6 +8,99 @@ #include "fbnic_mac.h" #include "fbnic_netdev.h" +static phy_interface_t fbnic_phylink_select_interface(u8 aui) +{ + switch (aui) { + case FBNIC_AUI_100GAUI2: + return PHY_INTERFACE_MODE_100GBASEP; + case FBNIC_AUI_50GAUI1: + return PHY_INTERFACE_MODE_50GBASER; + case FBNIC_AUI_LAUI2: + return PHY_INTERFACE_MODE_LAUI; + case FBNIC_AUI_25GAUI: + return PHY_INTERFACE_MODE_25GBASER; + } + + return PHY_INTERFACE_MODE_NA; +} + +void fbnic_phylink_get_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *pause) +{ + struct fbnic_net *fbn = netdev_priv(netdev); + + phylink_ethtool_get_pauseparam(fbn->phylink, pause); +} + +int fbnic_phylink_set_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *pause) +{ + struct fbnic_net *fbn = netdev_priv(netdev); + + return phylink_ethtool_set_pauseparam(fbn->phylink, pause); +} + +static void +fbnic_phylink_get_supported_fec_modes(unsigned long *supported) +{ + /* The NIC can support up to 8 possible combinations. + * Either 50G-CR, or 100G-CR2 + * This is with RS FEC mode only + * Either 25G-CR, or 50G-CR2 + * This is with No FEC, RS, or Base-R + */ + if (phylink_test(supported, 100000baseCR2_Full) || + phylink_test(supported, 50000baseCR_Full)) + phylink_set(supported, FEC_RS); + if (phylink_test(supported, 50000baseCR2_Full) || + phylink_test(supported, 25000baseCR_Full)) { + phylink_set(supported, FEC_BASER); + phylink_set(supported, FEC_NONE); + phylink_set(supported, FEC_RS); + } +} + +int fbnic_phylink_ethtool_ksettings_get(struct net_device *netdev, + struct ethtool_link_ksettings *cmd) +{ + struct fbnic_net *fbn = netdev_priv(netdev); + int err; + + err = phylink_ethtool_ksettings_get(fbn->phylink, cmd); + if (!err) { + unsigned long *supp = cmd->link_modes.supported; + + cmd->base.port = PORT_DA; + cmd->lanes = (fbn->aui & FBNIC_AUI_MODE_R2) ? 2 : 1; + + fbnic_phylink_get_supported_fec_modes(supp); + } + + return err; +} + +int fbnic_phylink_get_fecparam(struct net_device *netdev, + struct ethtool_fecparam *fecparam) +{ + struct fbnic_net *fbn = netdev_priv(netdev); + + if (fbn->fec & FBNIC_FEC_RS) { + fecparam->active_fec = ETHTOOL_FEC_RS; + fecparam->fec = ETHTOOL_FEC_RS; + } else if (fbn->fec & FBNIC_FEC_BASER) { + fecparam->active_fec = ETHTOOL_FEC_BASER; + fecparam->fec = ETHTOOL_FEC_BASER; + } else { + fecparam->active_fec = ETHTOOL_FEC_OFF; + fecparam->fec = ETHTOOL_FEC_OFF; + } + + if (fbn->aui & FBNIC_AUI_MODE_PAM4) + fecparam->fec |= ETHTOOL_FEC_AUTO; + + return 0; +} + static struct fbnic_net * fbnic_pcs_to_net(struct phylink_pcs *pcs) { @@ -21,23 +114,20 @@ fbnic_phylink_pcs_get_state(struct phylink_pcs *pcs, unsigned int neg_mode, struct fbnic_net *fbn = fbnic_pcs_to_net(pcs); struct fbnic_dev *fbd = fbn->fbd; - /* For now we use hard-coded defaults and FW config to determine - * the current values. In future patches we will add support for - * reconfiguring these values and changing link settings. - */ - switch (fbd->fw_cap.link_speed) { - case FBNIC_FW_LINK_SPEED_25R1: + switch (fbn->aui) { + case FBNIC_AUI_25GAUI: state->speed = SPEED_25000; break; - case FBNIC_FW_LINK_SPEED_50R2: + case FBNIC_AUI_LAUI2: + case FBNIC_AUI_50GAUI1: state->speed = SPEED_50000; break; - case FBNIC_FW_LINK_SPEED_100R2: + case FBNIC_AUI_100GAUI2: state->speed = SPEED_100000; break; default: - state->speed = SPEED_UNKNOWN; - break; + state->link = 0; + return; } state->duplex = DUPLEX_FULL; @@ -131,6 +221,7 @@ static const struct phylink_mac_ops fbnic_phylink_mac_ops = { int fbnic_phylink_init(struct net_device *netdev) { struct fbnic_net *fbn = netdev_priv(netdev); + struct fbnic_dev *fbd = fbn->fbd; struct phylink *phylink; fbn->phylink_pcs.ops = &fbnic_phylink_pcs_ops; @@ -138,18 +229,23 @@ int fbnic_phylink_init(struct net_device *netdev) fbn->phylink_config.dev = &netdev->dev; fbn->phylink_config.type = PHYLINK_NETDEV; fbn->phylink_config.mac_capabilities = MAC_SYM_PAUSE | MAC_ASYM_PAUSE | - MAC_10000FD | MAC_25000FD | - MAC_40000FD | MAC_50000FD | + MAC_25000FD | MAC_50000FD | MAC_100000FD; fbn->phylink_config.default_an_inband = true; - __set_bit(PHY_INTERFACE_MODE_XGMII, + __set_bit(PHY_INTERFACE_MODE_100GBASEP, + fbn->phylink_config.supported_interfaces); + __set_bit(PHY_INTERFACE_MODE_50GBASER, fbn->phylink_config.supported_interfaces); - __set_bit(PHY_INTERFACE_MODE_XLGMII, + __set_bit(PHY_INTERFACE_MODE_LAUI, fbn->phylink_config.supported_interfaces); + __set_bit(PHY_INTERFACE_MODE_25GBASER, + fbn->phylink_config.supported_interfaces); + + fbnic_mac_get_fw_settings(fbd, &fbn->aui, &fbn->fec); phylink = phylink_create(&fbn->phylink_config, NULL, - PHY_INTERFACE_MODE_XLGMII, + fbnic_phylink_select_interface(fbn->aui), &fbnic_phylink_mac_ops); if (IS_ERR(phylink)) return PTR_ERR(phylink); diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h index f46616af41ea..2e361d6f03ff 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h +++ b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h @@ -141,9 +141,6 @@ struct fbnic_napi_vector { struct fbnic_q_triad qt[]; }; -#define FBNIC_MAX_TXQS 128u -#define FBNIC_MAX_RXQS 128u - netdev_tx_t fbnic_xmit_frame(struct sk_buff *skb, struct net_device *dev); netdev_features_t fbnic_features_check(struct sk_buff *skb, struct net_device *dev, |