Merge branch 'bng_en-add-link-management-and-statistics-support'

Bhargava Marreddy says:

====================
bng_en: add link management and statistics support

This series enhances the bng_en driver by adding:
1. Link/PHY support
   a. Link query
   b. Async Link events
   c. Ethtool link set/get functionality
2. Hardware statistics reporting via ethtool -S

This version incorporates feedback received prior to splitting the
original series into two parts.
====================

Link: https://patch.msgid.link/20260406180420.279470-1-bhargava.marreddy@broadcom.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2026-04-12 11:09:39 -07:00
commit 5acd07df86
11 changed files with 3229 additions and 19 deletions

View File

@ -11,4 +11,5 @@ bng_en-y := bnge_core.o \
bnge_netdev.o \
bnge_ethtool.o \
bnge_auxr.o \
bnge_txrx.o
bnge_txrx.o \
bnge_link.o

View File

@ -94,6 +94,11 @@ struct bnge_queue_info {
u8 queue_profile;
};
#define BNGE_PHY_FLAGS2_SHIFT 8
#define BNGE_PHY_FL_NO_FCS PORT_PHY_QCAPS_RESP_FLAGS_NO_FCS
#define BNGE_PHY_FL_NO_PAUSE \
(PORT_PHY_QCAPS_RESP_FLAGS2_PAUSE_UNSUPPORTED << 8)
struct bnge_dev {
struct device *dev;
struct pci_dev *pdev;
@ -207,6 +212,11 @@ struct bnge_dev {
struct bnge_auxr_priv *aux_priv;
struct bnge_auxr_dev *auxr_dev;
struct bnge_link_info link_info;
/* Copied from flags and flags2 in hwrm_port_phy_qcaps_output */
u32 phy_flags;
};
static inline bool bnge_is_roce_en(struct bnge_dev *bd)

View File

@ -10,6 +10,7 @@
#include "bnge_devlink.h"
#include "bnge_hwrm.h"
#include "bnge_hwrm_lib.h"
#include "bnge_link.h"
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION(DRV_SUMMARY);

View File

@ -11,6 +11,294 @@
#include "bnge.h"
#include "bnge_ethtool.h"
#include "bnge_hwrm_lib.h"
static int bnge_nway_reset(struct net_device *dev)
{
struct bnge_net *bn = netdev_priv(dev);
struct bnge_dev *bd = bn->bd;
bool set_pause = false;
int rc = 0;
if (!BNGE_PHY_CFG_ABLE(bd))
return -EOPNOTSUPP;
if (!(bn->eth_link_info.autoneg & BNGE_AUTONEG_SPEED))
return -EINVAL;
if (!(bd->phy_flags & BNGE_PHY_FL_NO_PAUSE))
set_pause = true;
if (netif_running(dev))
rc = bnge_hwrm_set_link_setting(bn, set_pause);
return rc;
}
static const char * const bnge_ring_q_stats_str[] = {
"ucast_packets",
"mcast_packets",
"bcast_packets",
"ucast_bytes",
"mcast_bytes",
"bcast_bytes",
};
static const char * const bnge_ring_tpa2_stats_str[] = {
"tpa_eligible_pkt",
"tpa_eligible_bytes",
"tpa_pkt",
"tpa_bytes",
"tpa_errors",
"tpa_events",
};
#define BNGE_RX_PORT_STATS_ENTRY(suffix) \
{ BNGE_RX_STATS_OFFSET(rx_##suffix), "rxp_" __stringify(suffix) }
#define BNGE_TX_PORT_STATS_ENTRY(suffix) \
{ BNGE_TX_STATS_OFFSET(tx_##suffix), "txp_" __stringify(suffix) }
#define BNGE_RX_STATS_EXT_ENTRY(counter) \
{ BNGE_RX_STATS_EXT_OFFSET(counter), __stringify(counter) }
#define BNGE_TX_STATS_EXT_ENTRY(counter) \
{ BNGE_TX_STATS_EXT_OFFSET(counter), __stringify(counter) }
#define BNGE_RX_STATS_EXT_PFC_ENTRY(n) \
BNGE_RX_STATS_EXT_ENTRY(pfc_pri##n##_rx_duration_us), \
BNGE_RX_STATS_EXT_ENTRY(pfc_pri##n##_rx_transitions)
#define BNGE_TX_STATS_EXT_PFC_ENTRY(n) \
BNGE_TX_STATS_EXT_ENTRY(pfc_pri##n##_tx_duration_us), \
BNGE_TX_STATS_EXT_ENTRY(pfc_pri##n##_tx_transitions)
#define BNGE_RX_STATS_EXT_PFC_ENTRIES \
BNGE_RX_STATS_EXT_PFC_ENTRY(0), \
BNGE_RX_STATS_EXT_PFC_ENTRY(1), \
BNGE_RX_STATS_EXT_PFC_ENTRY(2), \
BNGE_RX_STATS_EXT_PFC_ENTRY(3), \
BNGE_RX_STATS_EXT_PFC_ENTRY(4), \
BNGE_RX_STATS_EXT_PFC_ENTRY(5), \
BNGE_RX_STATS_EXT_PFC_ENTRY(6), \
BNGE_RX_STATS_EXT_PFC_ENTRY(7)
#define BNGE_TX_STATS_EXT_PFC_ENTRIES \
BNGE_TX_STATS_EXT_PFC_ENTRY(0), \
BNGE_TX_STATS_EXT_PFC_ENTRY(1), \
BNGE_TX_STATS_EXT_PFC_ENTRY(2), \
BNGE_TX_STATS_EXT_PFC_ENTRY(3), \
BNGE_TX_STATS_EXT_PFC_ENTRY(4), \
BNGE_TX_STATS_EXT_PFC_ENTRY(5), \
BNGE_TX_STATS_EXT_PFC_ENTRY(6), \
BNGE_TX_STATS_EXT_PFC_ENTRY(7)
#define BNGE_RX_STATS_EXT_COS_ENTRY(n) \
BNGE_RX_STATS_EXT_ENTRY(rx_bytes_cos##n), \
BNGE_RX_STATS_EXT_ENTRY(rx_packets_cos##n)
#define BNGE_TX_STATS_EXT_COS_ENTRY(n) \
BNGE_TX_STATS_EXT_ENTRY(tx_bytes_cos##n), \
BNGE_TX_STATS_EXT_ENTRY(tx_packets_cos##n)
#define BNGE_RX_STATS_EXT_COS_ENTRIES \
BNGE_RX_STATS_EXT_COS_ENTRY(0), \
BNGE_RX_STATS_EXT_COS_ENTRY(1), \
BNGE_RX_STATS_EXT_COS_ENTRY(2), \
BNGE_RX_STATS_EXT_COS_ENTRY(3), \
BNGE_RX_STATS_EXT_COS_ENTRY(4), \
BNGE_RX_STATS_EXT_COS_ENTRY(5), \
BNGE_RX_STATS_EXT_COS_ENTRY(6), \
BNGE_RX_STATS_EXT_COS_ENTRY(7) \
#define BNGE_TX_STATS_EXT_COS_ENTRIES \
BNGE_TX_STATS_EXT_COS_ENTRY(0), \
BNGE_TX_STATS_EXT_COS_ENTRY(1), \
BNGE_TX_STATS_EXT_COS_ENTRY(2), \
BNGE_TX_STATS_EXT_COS_ENTRY(3), \
BNGE_TX_STATS_EXT_COS_ENTRY(4), \
BNGE_TX_STATS_EXT_COS_ENTRY(5), \
BNGE_TX_STATS_EXT_COS_ENTRY(6), \
BNGE_TX_STATS_EXT_COS_ENTRY(7) \
#define BNGE_RX_STATS_EXT_DISCARD_COS_ENTRY(n) \
BNGE_RX_STATS_EXT_ENTRY(rx_discard_bytes_cos##n), \
BNGE_RX_STATS_EXT_ENTRY(rx_discard_packets_cos##n)
#define BNGE_RX_STATS_EXT_DISCARD_COS_ENTRIES \
BNGE_RX_STATS_EXT_DISCARD_COS_ENTRY(0), \
BNGE_RX_STATS_EXT_DISCARD_COS_ENTRY(1), \
BNGE_RX_STATS_EXT_DISCARD_COS_ENTRY(2), \
BNGE_RX_STATS_EXT_DISCARD_COS_ENTRY(3), \
BNGE_RX_STATS_EXT_DISCARD_COS_ENTRY(4), \
BNGE_RX_STATS_EXT_DISCARD_COS_ENTRY(5), \
BNGE_RX_STATS_EXT_DISCARD_COS_ENTRY(6), \
BNGE_RX_STATS_EXT_DISCARD_COS_ENTRY(7)
#define BNGE_RX_STATS_PRI_ENTRY(counter, n) \
{ BNGE_RX_STATS_EXT_OFFSET(counter##_cos0), \
__stringify(counter##_pri##n) }
#define BNGE_TX_STATS_PRI_ENTRY(counter, n) \
{ BNGE_TX_STATS_EXT_OFFSET(counter##_cos0), \
__stringify(counter##_pri##n) }
#define BNGE_RX_STATS_PRI_ENTRIES(counter) \
BNGE_RX_STATS_PRI_ENTRY(counter, 0), \
BNGE_RX_STATS_PRI_ENTRY(counter, 1), \
BNGE_RX_STATS_PRI_ENTRY(counter, 2), \
BNGE_RX_STATS_PRI_ENTRY(counter, 3), \
BNGE_RX_STATS_PRI_ENTRY(counter, 4), \
BNGE_RX_STATS_PRI_ENTRY(counter, 5), \
BNGE_RX_STATS_PRI_ENTRY(counter, 6), \
BNGE_RX_STATS_PRI_ENTRY(counter, 7)
#define BNGE_TX_STATS_PRI_ENTRIES(counter) \
BNGE_TX_STATS_PRI_ENTRY(counter, 0), \
BNGE_TX_STATS_PRI_ENTRY(counter, 1), \
BNGE_TX_STATS_PRI_ENTRY(counter, 2), \
BNGE_TX_STATS_PRI_ENTRY(counter, 3), \
BNGE_TX_STATS_PRI_ENTRY(counter, 4), \
BNGE_TX_STATS_PRI_ENTRY(counter, 5), \
BNGE_TX_STATS_PRI_ENTRY(counter, 6), \
BNGE_TX_STATS_PRI_ENTRY(counter, 7)
#define NUM_RING_Q_HW_STATS ARRAY_SIZE(bnge_ring_q_stats_str)
static const struct {
long offset;
char string[ETH_GSTRING_LEN];
} bnge_tx_port_stats_ext_arr[] = {
BNGE_TX_STATS_EXT_COS_ENTRIES,
BNGE_TX_STATS_EXT_PFC_ENTRIES,
};
static const struct {
long base_off;
char string[ETH_GSTRING_LEN];
} bnge_rx_bytes_pri_arr[] = {
BNGE_RX_STATS_PRI_ENTRIES(rx_bytes),
};
static const struct {
long base_off;
char string[ETH_GSTRING_LEN];
} bnge_rx_pkts_pri_arr[] = {
BNGE_RX_STATS_PRI_ENTRIES(rx_packets),
};
static const struct {
long base_off;
char string[ETH_GSTRING_LEN];
} bnge_tx_bytes_pri_arr[] = {
BNGE_TX_STATS_PRI_ENTRIES(tx_bytes),
};
static const struct {
long base_off;
char string[ETH_GSTRING_LEN];
} bnge_tx_pkts_pri_arr[] = {
BNGE_TX_STATS_PRI_ENTRIES(tx_packets),
};
static const struct {
long offset;
char string[ETH_GSTRING_LEN];
} bnge_port_stats_arr[] = {
BNGE_RX_PORT_STATS_ENTRY(good_vlan_frames),
BNGE_RX_PORT_STATS_ENTRY(mtu_err_frames),
BNGE_RX_PORT_STATS_ENTRY(tagged_frames),
BNGE_RX_PORT_STATS_ENTRY(double_tagged_frames),
BNGE_RX_PORT_STATS_ENTRY(pfc_ena_frames_pri0),
BNGE_RX_PORT_STATS_ENTRY(pfc_ena_frames_pri1),
BNGE_RX_PORT_STATS_ENTRY(pfc_ena_frames_pri2),
BNGE_RX_PORT_STATS_ENTRY(pfc_ena_frames_pri3),
BNGE_RX_PORT_STATS_ENTRY(pfc_ena_frames_pri4),
BNGE_RX_PORT_STATS_ENTRY(pfc_ena_frames_pri5),
BNGE_RX_PORT_STATS_ENTRY(pfc_ena_frames_pri6),
BNGE_RX_PORT_STATS_ENTRY(pfc_ena_frames_pri7),
BNGE_RX_PORT_STATS_ENTRY(eee_lpi_events),
BNGE_RX_PORT_STATS_ENTRY(eee_lpi_duration),
BNGE_RX_PORT_STATS_ENTRY(runt_bytes),
BNGE_RX_PORT_STATS_ENTRY(runt_frames),
BNGE_TX_PORT_STATS_ENTRY(good_vlan_frames),
BNGE_TX_PORT_STATS_ENTRY(jabber_frames),
BNGE_TX_PORT_STATS_ENTRY(fcs_err_frames),
BNGE_TX_PORT_STATS_ENTRY(pfc_ena_frames_pri0),
BNGE_TX_PORT_STATS_ENTRY(pfc_ena_frames_pri1),
BNGE_TX_PORT_STATS_ENTRY(pfc_ena_frames_pri2),
BNGE_TX_PORT_STATS_ENTRY(pfc_ena_frames_pri3),
BNGE_TX_PORT_STATS_ENTRY(pfc_ena_frames_pri4),
BNGE_TX_PORT_STATS_ENTRY(pfc_ena_frames_pri5),
BNGE_TX_PORT_STATS_ENTRY(pfc_ena_frames_pri6),
BNGE_TX_PORT_STATS_ENTRY(pfc_ena_frames_pri7),
BNGE_TX_PORT_STATS_ENTRY(eee_lpi_events),
BNGE_TX_PORT_STATS_ENTRY(eee_lpi_duration),
BNGE_TX_PORT_STATS_ENTRY(xthol_frames),
};
static const struct {
long offset;
char string[ETH_GSTRING_LEN];
} bnge_port_stats_ext_arr[] = {
BNGE_RX_STATS_EXT_ENTRY(continuous_pause_events),
BNGE_RX_STATS_EXT_ENTRY(resume_pause_events),
BNGE_RX_STATS_EXT_ENTRY(continuous_roce_pause_events),
BNGE_RX_STATS_EXT_ENTRY(resume_roce_pause_events),
BNGE_RX_STATS_EXT_COS_ENTRIES,
BNGE_RX_STATS_EXT_PFC_ENTRIES,
BNGE_RX_STATS_EXT_ENTRY(rx_bits),
BNGE_RX_STATS_EXT_ENTRY(rx_buffer_passed_threshold),
BNGE_RX_STATS_EXT_DISCARD_COS_ENTRIES,
BNGE_RX_STATS_EXT_ENTRY(rx_filter_miss),
};
static int bnge_get_num_tpa_ring_stats(struct bnge_dev *bd)
{
if (BNGE_SUPPORTS_TPA(bd))
return BNGE_NUM_TPA_RING_STATS;
return 0;
}
#define BNGE_NUM_PORT_STATS ARRAY_SIZE(bnge_port_stats_arr)
#define BNGE_NUM_STATS_PRI \
(ARRAY_SIZE(bnge_rx_bytes_pri_arr) + \
ARRAY_SIZE(bnge_rx_pkts_pri_arr) + \
ARRAY_SIZE(bnge_tx_bytes_pri_arr) + \
ARRAY_SIZE(bnge_tx_pkts_pri_arr))
static int bnge_get_num_ring_stats(struct bnge_dev *bd)
{
int rx, tx;
rx = NUM_RING_Q_HW_STATS + bnge_get_num_tpa_ring_stats(bd);
tx = NUM_RING_Q_HW_STATS;
return rx * bd->rx_nr_rings +
tx * bd->tx_nr_rings_per_tc;
}
static u32 bnge_get_num_stats(struct bnge_net *bn)
{
u32 num_stats = bnge_get_num_ring_stats(bn->bd);
u32 len;
if (bn->flags & BNGE_FLAG_PORT_STATS)
num_stats += BNGE_NUM_PORT_STATS;
if (bn->flags & BNGE_FLAG_PORT_STATS_EXT) {
len = min_t(u32, bn->fw_rx_stats_ext_size,
ARRAY_SIZE(bnge_port_stats_ext_arr));
num_stats += len;
len = min_t(u32, bn->fw_tx_stats_ext_size,
ARRAY_SIZE(bnge_tx_port_stats_ext_arr));
num_stats += len;
if (bn->pri2cos_valid)
num_stats += BNGE_NUM_STATS_PRI;
}
return num_stats;
}
static void bnge_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
@ -23,8 +311,452 @@ static void bnge_get_drvinfo(struct net_device *dev,
strscpy(info->bus_info, pci_name(bd->pdev), sizeof(info->bus_info));
}
static int bnge_get_sset_count(struct net_device *dev, int sset)
{
struct bnge_net *bn = netdev_priv(dev);
switch (sset) {
case ETH_SS_STATS:
return bnge_get_num_stats(bn);
default:
return -EOPNOTSUPP;
}
}
static bool is_rx_ring(struct bnge_dev *bd, u16 ring_num)
{
return ring_num < bd->rx_nr_rings;
}
static bool is_tx_ring(struct bnge_dev *bd, u16 ring_num)
{
u16 tx_base = 0;
if (!(bd->flags & BNGE_EN_SHARED_CHNL))
tx_base = bd->rx_nr_rings;
return ring_num >= tx_base && ring_num < (tx_base + bd->tx_nr_rings_per_tc);
}
static void bnge_get_ethtool_stats(struct net_device *dev,
struct ethtool_stats *stats, u64 *buf)
{
struct bnge_net *bn = netdev_priv(dev);
struct bnge_dev *bd = bn->bd;
u32 tpa_stats;
u32 i, j = 0;
if (!bn->bnapi) {
j += bnge_get_num_ring_stats(bd);
goto skip_ring_stats;
}
tpa_stats = bnge_get_num_tpa_ring_stats(bd);
for (i = 0; i < bd->nq_nr_rings; i++) {
struct bnge_napi *bnapi = bn->bnapi[i];
struct bnge_nq_ring_info *nqr;
u64 *sw_stats;
int k;
nqr = &bnapi->nq_ring;
sw_stats = nqr->stats.sw_stats;
if (is_rx_ring(bd, i)) {
buf[j++] = BNGE_GET_RING_STATS64(sw_stats, rx_ucast_pkts);
buf[j++] = BNGE_GET_RING_STATS64(sw_stats, rx_mcast_pkts);
buf[j++] = BNGE_GET_RING_STATS64(sw_stats, rx_bcast_pkts);
buf[j++] = BNGE_GET_RING_STATS64(sw_stats, rx_ucast_bytes);
buf[j++] = BNGE_GET_RING_STATS64(sw_stats, rx_mcast_bytes);
buf[j++] = BNGE_GET_RING_STATS64(sw_stats, rx_bcast_bytes);
}
if (is_tx_ring(bd, i)) {
buf[j++] = BNGE_GET_RING_STATS64(sw_stats, tx_ucast_pkts);
buf[j++] = BNGE_GET_RING_STATS64(sw_stats, tx_mcast_pkts);
buf[j++] = BNGE_GET_RING_STATS64(sw_stats, tx_bcast_pkts);
buf[j++] = BNGE_GET_RING_STATS64(sw_stats, tx_ucast_bytes);
buf[j++] = BNGE_GET_RING_STATS64(sw_stats, tx_mcast_bytes);
buf[j++] = BNGE_GET_RING_STATS64(sw_stats, tx_bcast_bytes);
}
if (!tpa_stats || !is_rx_ring(bd, i))
continue;
k = BNGE_NUM_RX_RING_STATS + BNGE_NUM_TX_RING_STATS;
for (; k < BNGE_NUM_RX_RING_STATS + BNGE_NUM_TX_RING_STATS +
tpa_stats; j++, k++)
buf[j] = sw_stats[k];
}
skip_ring_stats:
if (bn->flags & BNGE_FLAG_PORT_STATS) {
u64 *port_stats = bn->port_stats.sw_stats;
for (i = 0; i < BNGE_NUM_PORT_STATS; i++, j++)
buf[j] = *(port_stats + bnge_port_stats_arr[i].offset);
}
if (bn->flags & BNGE_FLAG_PORT_STATS_EXT) {
u64 *rx_port_stats_ext = bn->rx_port_stats_ext.sw_stats;
u64 *tx_port_stats_ext = bn->tx_port_stats_ext.sw_stats;
u32 len;
len = min_t(u32, bn->fw_rx_stats_ext_size,
ARRAY_SIZE(bnge_port_stats_ext_arr));
for (i = 0; i < len; i++, j++) {
buf[j] = *(rx_port_stats_ext +
bnge_port_stats_ext_arr[i].offset);
}
len = min_t(u32, bn->fw_tx_stats_ext_size,
ARRAY_SIZE(bnge_tx_port_stats_ext_arr));
for (i = 0; i < len; i++, j++) {
buf[j] = *(tx_port_stats_ext +
bnge_tx_port_stats_ext_arr[i].offset);
}
if (bn->pri2cos_valid) {
for (i = 0; i < 8; i++, j++) {
long n = bnge_rx_bytes_pri_arr[i].base_off +
bn->pri2cos_idx[i];
buf[j] = *(rx_port_stats_ext + n);
}
for (i = 0; i < 8; i++, j++) {
long n = bnge_rx_pkts_pri_arr[i].base_off +
bn->pri2cos_idx[i];
buf[j] = *(rx_port_stats_ext + n);
}
for (i = 0; i < 8; i++, j++) {
long n = bnge_tx_bytes_pri_arr[i].base_off +
bn->pri2cos_idx[i];
buf[j] = *(tx_port_stats_ext + n);
}
for (i = 0; i < 8; i++, j++) {
long n = bnge_tx_pkts_pri_arr[i].base_off +
bn->pri2cos_idx[i];
buf[j] = *(tx_port_stats_ext + n);
}
}
}
}
static void bnge_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
{
struct bnge_net *bn = netdev_priv(dev);
struct bnge_dev *bd = bn->bd;
u32 i, j, num_str;
const char *str;
switch (stringset) {
case ETH_SS_STATS:
for (i = 0; i < bd->nq_nr_rings; i++) {
if (is_rx_ring(bd, i))
for (j = 0; j < NUM_RING_Q_HW_STATS; j++) {
str = bnge_ring_q_stats_str[j];
ethtool_sprintf(&buf, "rxq%d_%s", i,
str);
}
if (is_tx_ring(bd, i))
for (j = 0; j < NUM_RING_Q_HW_STATS; j++) {
str = bnge_ring_q_stats_str[j];
ethtool_sprintf(&buf, "txq%d_%s", i,
str);
}
num_str = bnge_get_num_tpa_ring_stats(bd);
if (!num_str || !is_rx_ring(bd, i))
continue;
for (j = 0; j < num_str; j++) {
str = bnge_ring_tpa2_stats_str[j];
ethtool_sprintf(&buf, "rxq%d_%s", i, str);
}
}
if (bn->flags & BNGE_FLAG_PORT_STATS)
for (i = 0; i < BNGE_NUM_PORT_STATS; i++) {
str = bnge_port_stats_arr[i].string;
ethtool_puts(&buf, str);
}
if (bn->flags & BNGE_FLAG_PORT_STATS_EXT) {
u32 len;
len = min_t(u32, bn->fw_rx_stats_ext_size,
ARRAY_SIZE(bnge_port_stats_ext_arr));
for (i = 0; i < len; i++) {
str = bnge_port_stats_ext_arr[i].string;
ethtool_puts(&buf, str);
}
len = min_t(u32, bn->fw_tx_stats_ext_size,
ARRAY_SIZE(bnge_tx_port_stats_ext_arr));
for (i = 0; i < len; i++) {
str = bnge_tx_port_stats_ext_arr[i].string;
ethtool_puts(&buf, str);
}
if (bn->pri2cos_valid) {
for (i = 0; i < 8; i++) {
str = bnge_rx_bytes_pri_arr[i].string;
ethtool_puts(&buf, str);
}
for (i = 0; i < 8; i++) {
str = bnge_rx_pkts_pri_arr[i].string;
ethtool_puts(&buf, str);
}
for (i = 0; i < 8; i++) {
str = bnge_tx_bytes_pri_arr[i].string;
ethtool_puts(&buf, str);
}
for (i = 0; i < 8; i++) {
str = bnge_tx_pkts_pri_arr[i].string;
ethtool_puts(&buf, str);
}
}
}
break;
default:
netdev_err(bd->netdev, "%s invalid request %x\n",
__func__, stringset);
break;
}
}
static void bnge_get_eth_phy_stats(struct net_device *dev,
struct ethtool_eth_phy_stats *phy_stats)
{
struct bnge_net *bn = netdev_priv(dev);
u64 *rx;
if (!(bn->flags & BNGE_FLAG_PORT_STATS_EXT))
return;
rx = bn->rx_port_stats_ext.sw_stats;
phy_stats->SymbolErrorDuringCarrier =
*(rx + BNGE_RX_STATS_EXT_OFFSET(rx_pcs_symbol_err));
}
static void bnge_get_eth_mac_stats(struct net_device *dev,
struct ethtool_eth_mac_stats *mac_stats)
{
struct bnge_net *bn = netdev_priv(dev);
u64 *rx, *tx;
if (!(bn->flags & BNGE_FLAG_PORT_STATS))
return;
rx = bn->port_stats.sw_stats;
tx = bn->port_stats.sw_stats + BNGE_TX_PORT_STATS_BYTE_OFFSET / 8;
mac_stats->FramesReceivedOK =
BNGE_GET_RX_PORT_STATS64(rx, rx_good_frames);
mac_stats->FramesTransmittedOK =
BNGE_GET_TX_PORT_STATS64(tx, tx_good_frames);
mac_stats->FrameCheckSequenceErrors =
BNGE_GET_RX_PORT_STATS64(rx, rx_fcs_err_frames);
mac_stats->AlignmentErrors =
BNGE_GET_RX_PORT_STATS64(rx, rx_align_err_frames);
mac_stats->OutOfRangeLengthField =
BNGE_GET_RX_PORT_STATS64(rx, rx_oor_len_frames);
mac_stats->OctetsReceivedOK = BNGE_GET_RX_PORT_STATS64(rx, rx_bytes);
mac_stats->OctetsTransmittedOK = BNGE_GET_TX_PORT_STATS64(tx, tx_bytes);
mac_stats->MulticastFramesReceivedOK =
BNGE_GET_RX_PORT_STATS64(rx, rx_mcast_frames);
mac_stats->BroadcastFramesReceivedOK =
BNGE_GET_RX_PORT_STATS64(rx, rx_bcast_frames);
mac_stats->MulticastFramesXmittedOK =
BNGE_GET_TX_PORT_STATS64(tx, tx_mcast_frames);
mac_stats->BroadcastFramesXmittedOK =
BNGE_GET_TX_PORT_STATS64(tx, tx_bcast_frames);
mac_stats->FrameTooLongErrors =
BNGE_GET_RX_PORT_STATS64(rx, rx_ovrsz_frames);
}
static void bnge_get_eth_ctrl_stats(struct net_device *dev,
struct ethtool_eth_ctrl_stats *ctrl_stats)
{
struct bnge_net *bn = netdev_priv(dev);
u64 *rx;
if (!(bn->flags & BNGE_FLAG_PORT_STATS))
return;
rx = bn->port_stats.sw_stats;
ctrl_stats->MACControlFramesReceived =
BNGE_GET_RX_PORT_STATS64(rx, rx_ctrl_frames);
}
static void bnge_get_pause_stats(struct net_device *dev,
struct ethtool_pause_stats *pause_stats)
{
struct bnge_net *bn = netdev_priv(dev);
u64 *rx, *tx;
if (!(bn->flags & BNGE_FLAG_PORT_STATS))
return;
rx = bn->port_stats.sw_stats;
tx = bn->port_stats.sw_stats + BNGE_TX_PORT_STATS_BYTE_OFFSET / 8;
pause_stats->rx_pause_frames =
BNGE_GET_RX_PORT_STATS64(rx, rx_pause_frames);
pause_stats->tx_pause_frames =
BNGE_GET_TX_PORT_STATS64(tx, tx_pause_frames);
}
static const struct ethtool_rmon_hist_range bnge_rmon_ranges[] = {
{ 0, 64 },
{ 65, 127 },
{ 128, 255 },
{ 256, 511 },
{ 512, 1023 },
{ 1024, 1518 },
{ 1519, 2047 },
{ 2048, 4095 },
{ 4096, 9216 },
{ 9217, 16383 },
{}
};
static void bnge_get_rmon_stats(struct net_device *dev,
struct ethtool_rmon_stats *rmon_stats,
const struct ethtool_rmon_hist_range **ranges)
{
struct bnge_net *bn = netdev_priv(dev);
u64 *rx, *tx;
if (!(bn->flags & BNGE_FLAG_PORT_STATS))
return;
rx = bn->port_stats.sw_stats;
tx = bn->port_stats.sw_stats + BNGE_TX_PORT_STATS_BYTE_OFFSET / 8;
rmon_stats->jabbers = BNGE_GET_RX_PORT_STATS64(rx, rx_jbr_frames);
rmon_stats->oversize_pkts =
BNGE_GET_RX_PORT_STATS64(rx, rx_ovrsz_frames);
rmon_stats->undersize_pkts =
BNGE_GET_RX_PORT_STATS64(rx, rx_undrsz_frames);
rmon_stats->hist[0] = BNGE_GET_RX_PORT_STATS64(rx, rx_64b_frames);
rmon_stats->hist[1] = BNGE_GET_RX_PORT_STATS64(rx, rx_65b_127b_frames);
rmon_stats->hist[2] = BNGE_GET_RX_PORT_STATS64(rx, rx_128b_255b_frames);
rmon_stats->hist[3] = BNGE_GET_RX_PORT_STATS64(rx, rx_256b_511b_frames);
rmon_stats->hist[4] =
BNGE_GET_RX_PORT_STATS64(rx, rx_512b_1023b_frames);
rmon_stats->hist[5] =
BNGE_GET_RX_PORT_STATS64(rx, rx_1024b_1518b_frames);
rmon_stats->hist[6] =
BNGE_GET_RX_PORT_STATS64(rx, rx_1519b_2047b_frames);
rmon_stats->hist[7] =
BNGE_GET_RX_PORT_STATS64(rx, rx_2048b_4095b_frames);
rmon_stats->hist[8] =
BNGE_GET_RX_PORT_STATS64(rx, rx_4096b_9216b_frames);
rmon_stats->hist[9] =
BNGE_GET_RX_PORT_STATS64(rx, rx_9217b_16383b_frames);
rmon_stats->hist_tx[0] = BNGE_GET_TX_PORT_STATS64(tx, tx_64b_frames);
rmon_stats->hist_tx[1] =
BNGE_GET_TX_PORT_STATS64(tx, tx_65b_127b_frames);
rmon_stats->hist_tx[2] =
BNGE_GET_TX_PORT_STATS64(tx, tx_128b_255b_frames);
rmon_stats->hist_tx[3] =
BNGE_GET_TX_PORT_STATS64(tx, tx_256b_511b_frames);
rmon_stats->hist_tx[4] =
BNGE_GET_TX_PORT_STATS64(tx, tx_512b_1023b_frames);
rmon_stats->hist_tx[5] =
BNGE_GET_TX_PORT_STATS64(tx, tx_1024b_1518b_frames);
rmon_stats->hist_tx[6] =
BNGE_GET_TX_PORT_STATS64(tx, tx_1519b_2047b_frames);
rmon_stats->hist_tx[7] =
BNGE_GET_TX_PORT_STATS64(tx, tx_2048b_4095b_frames);
rmon_stats->hist_tx[8] =
BNGE_GET_TX_PORT_STATS64(tx, tx_4096b_9216b_frames);
rmon_stats->hist_tx[9] =
BNGE_GET_TX_PORT_STATS64(tx, tx_9217b_16383b_frames);
*ranges = bnge_rmon_ranges;
}
static void bnge_get_pauseparam(struct net_device *dev,
struct ethtool_pauseparam *epause)
{
struct bnge_net *bn = netdev_priv(dev);
struct bnge_dev *bd = bn->bd;
if (bd->phy_flags & BNGE_PHY_FL_NO_PAUSE) {
epause->autoneg = 0;
epause->rx_pause = 0;
epause->tx_pause = 0;
return;
}
epause->autoneg = !!(bn->eth_link_info.autoneg &
BNGE_AUTONEG_FLOW_CTRL);
epause->rx_pause = !!(bn->eth_link_info.req_flow_ctrl &
BNGE_LINK_PAUSE_RX);
epause->tx_pause = !!(bn->eth_link_info.req_flow_ctrl &
BNGE_LINK_PAUSE_TX);
}
static int bnge_set_pauseparam(struct net_device *dev,
struct ethtool_pauseparam *epause)
{
struct bnge_ethtool_link_info old_elink_info, *elink_info;
struct bnge_net *bn = netdev_priv(dev);
struct bnge_dev *bd = bn->bd;
int rc = 0;
if (!BNGE_PHY_CFG_ABLE(bd) || (bd->phy_flags & BNGE_PHY_FL_NO_PAUSE))
return -EOPNOTSUPP;
elink_info = &bn->eth_link_info;
old_elink_info = *elink_info;
if (epause->autoneg) {
if (!(elink_info->autoneg & BNGE_AUTONEG_SPEED))
return -EINVAL;
elink_info->autoneg |= BNGE_AUTONEG_FLOW_CTRL;
} else {
if (elink_info->autoneg & BNGE_AUTONEG_FLOW_CTRL)
elink_info->force_link_chng = true;
elink_info->autoneg &= ~BNGE_AUTONEG_FLOW_CTRL;
}
elink_info->req_flow_ctrl = 0;
if (epause->rx_pause)
elink_info->req_flow_ctrl |= BNGE_LINK_PAUSE_RX;
if (epause->tx_pause)
elink_info->req_flow_ctrl |= BNGE_LINK_PAUSE_TX;
if (netif_running(dev)) {
rc = bnge_hwrm_set_pause(bn);
if (rc)
*elink_info = old_elink_info;
}
return rc;
}
static const struct ethtool_ops bnge_ethtool_ops = {
.cap_link_lanes_supported = 1,
.get_link_ksettings = bnge_get_link_ksettings,
.set_link_ksettings = bnge_set_link_ksettings,
.get_drvinfo = bnge_get_drvinfo,
.get_link = bnge_get_link,
.nway_reset = bnge_nway_reset,
.get_pauseparam = bnge_get_pauseparam,
.set_pauseparam = bnge_set_pauseparam,
.get_sset_count = bnge_get_sset_count,
.get_strings = bnge_get_strings,
.get_ethtool_stats = bnge_get_ethtool_stats,
.get_eth_phy_stats = bnge_get_eth_phy_stats,
.get_eth_mac_stats = bnge_get_eth_mac_stats,
.get_eth_ctrl_stats = bnge_get_eth_ctrl_stats,
.get_pause_stats = bnge_get_pause_stats,
.get_rmon_stats = bnge_get_rmon_stats,
};
void bnge_set_ethtool_ops(struct net_device *dev)

View File

@ -14,6 +14,14 @@
#include "bnge_hwrm_lib.h"
#include "bnge_rmem.h"
#include "bnge_resc.h"
#include "bnge_netdev.h"
static const u16 bnge_async_events_arr[] = {
ASYNC_EVENT_CMPL_EVENT_ID_LINK_STATUS_CHANGE,
ASYNC_EVENT_CMPL_EVENT_ID_LINK_SPEED_CHANGE,
ASYNC_EVENT_CMPL_EVENT_ID_LINK_SPEED_CFG_CHANGE,
ASYNC_EVENT_CMPL_EVENT_ID_PORT_PHY_CFG_CHANGE,
};
int bnge_hwrm_ver_get(struct bnge_dev *bd)
{
@ -166,10 +174,12 @@ int bnge_hwrm_fw_set_time(struct bnge_dev *bd)
int bnge_hwrm_func_drv_rgtr(struct bnge_dev *bd)
{
DECLARE_BITMAP(async_events_bmap, 256);
struct hwrm_func_drv_rgtr_output *resp;
struct hwrm_func_drv_rgtr_input *req;
u32 events[8];
u32 flags;
int rc;
int rc, i;
rc = bnge_hwrm_req_init(bd, req, HWRM_FUNC_DRV_RGTR);
if (rc)
@ -190,6 +200,14 @@ int bnge_hwrm_func_drv_rgtr(struct bnge_dev *bd)
req->ver_min = cpu_to_le16(DRV_VER_MIN);
req->ver_upd = cpu_to_le16(DRV_VER_UPD);
memset(async_events_bmap, 0, sizeof(async_events_bmap));
for (i = 0; i < ARRAY_SIZE(bnge_async_events_arr); i++)
__set_bit(bnge_async_events_arr[i], async_events_bmap);
bitmap_to_arr32(events, async_events_bmap, 256);
for (i = 0; i < ARRAY_SIZE(req->async_event_fwd); i++)
req->async_event_fwd[i] |= cpu_to_le32(events[i]);
resp = bnge_hwrm_req_hold(bd, req);
rc = bnge_hwrm_req_send(bd, req);
if (!rc) {
@ -577,7 +595,7 @@ int bnge_hwrm_func_qcaps(struct bnge_dev *bd)
struct hwrm_func_qcaps_output *resp;
struct hwrm_func_qcaps_input *req;
struct bnge_pf_info *pf = &bd->pf;
u32 flags;
u32 flags, flags_ext;
int rc;
rc = bnge_hwrm_req_init(bd, req, HWRM_FUNC_QCAPS);
@ -595,6 +613,12 @@ int bnge_hwrm_func_qcaps(struct bnge_dev *bd)
bd->flags |= BNGE_EN_ROCE_V1;
if (flags & FUNC_QCAPS_RESP_FLAGS_ROCE_V2_SUPPORTED)
bd->flags |= BNGE_EN_ROCE_V2;
if (flags & FUNC_QCAPS_RESP_FLAGS_EXT_STATS_SUPPORTED)
bd->fw_cap |= BNGE_FW_CAP_EXT_STATS_SUPPORTED;
flags_ext = le32_to_cpu(resp->flags_ext);
if (flags_ext & FUNC_QCAPS_RESP_FLAGS_EXT_EXT_HW_STATS_SUPPORTED)
bd->fw_cap |= BNGE_FW_CAP_EXT_HW_STATS_SUPPORTED;
pf->fw_fid = le16_to_cpu(resp->fid);
pf->port_id = le16_to_cpu(resp->port_id);
@ -981,6 +1005,220 @@ void bnge_hwrm_vnic_ctx_free_one(struct bnge_dev *bd,
vnic->fw_rss_cos_lb_ctx[ctx_idx] = INVALID_HW_RING_ID;
}
static bool bnge_phy_qcaps_no_speed(struct hwrm_port_phy_qcaps_output *resp)
{
return !resp->supported_speeds2_auto_mode &&
!resp->supported_speeds2_force_mode;
}
int bnge_hwrm_phy_qcaps(struct bnge_dev *bd)
{
struct bnge_link_info *link_info = &bd->link_info;
struct hwrm_port_phy_qcaps_output *resp;
struct hwrm_port_phy_qcaps_input *req;
int rc;
rc = bnge_hwrm_req_init(bd, req, HWRM_PORT_PHY_QCAPS);
if (rc)
return rc;
resp = bnge_hwrm_req_hold(bd, req);
rc = bnge_hwrm_req_send(bd, req);
if (rc)
goto hwrm_phy_qcaps_exit;
bd->phy_flags = resp->flags |
(le16_to_cpu(resp->flags2) << BNGE_PHY_FLAGS2_SHIFT);
if (bnge_phy_qcaps_no_speed(resp)) {
link_info->phy_enabled = false;
netdev_warn(bd->netdev, "Ethernet link disabled\n");
} else if (!link_info->phy_enabled) {
link_info->phy_enabled = true;
netdev_info(bd->netdev, "Ethernet link enabled\n");
/* Phy re-enabled, reprobe the speeds */
link_info->support_auto_speeds2 = 0;
}
/* Firmware may report 0 for autoneg supported speeds when no
* SFP module is present. Skip the update to preserve the
* current supported speeds -- storing 0 would cause autoneg
* default fallback to advertise nothing.
*/
if (resp->supported_speeds2_auto_mode)
link_info->support_auto_speeds2 =
le16_to_cpu(resp->supported_speeds2_auto_mode);
bd->port_count = resp->port_cnt;
hwrm_phy_qcaps_exit:
bnge_hwrm_req_drop(bd, req);
return rc;
}
int bnge_hwrm_set_link_setting(struct bnge_net *bn, bool set_pause)
{
struct hwrm_port_phy_cfg_input *req;
struct bnge_dev *bd = bn->bd;
int rc;
rc = bnge_hwrm_req_init(bd, req, HWRM_PORT_PHY_CFG);
if (rc)
return rc;
if (set_pause)
bnge_hwrm_set_pause_common(bn, req);
bnge_hwrm_set_link_common(bn, req);
rc = bnge_hwrm_req_send(bd, req);
if (!rc)
bn->eth_link_info.force_link_chng = false;
return rc;
}
int bnge_update_link(struct bnge_net *bn, bool chng_link_state)
{
struct hwrm_port_phy_qcfg_output *resp;
struct hwrm_port_phy_qcfg_input *req;
struct bnge_link_info *link_info;
struct bnge_dev *bd = bn->bd;
bool support_changed;
u8 link_state;
int rc;
link_info = &bd->link_info;
link_state = link_info->link_state;
rc = bnge_hwrm_req_init(bd, req, HWRM_PORT_PHY_QCFG);
if (rc)
return rc;
resp = bnge_hwrm_req_hold(bd, req);
rc = bnge_hwrm_req_send(bd, req);
if (rc) {
bnge_hwrm_req_drop(bd, req);
return rc;
}
memcpy(&link_info->phy_qcfg_resp, resp, sizeof(*resp));
link_info->phy_link_status = resp->link;
link_info->duplex = resp->duplex_state;
link_info->pause = resp->pause;
link_info->auto_mode = resp->auto_mode;
link_info->auto_pause_setting = resp->auto_pause;
link_info->lp_pause = resp->link_partner_adv_pause;
link_info->force_pause_setting = resp->force_pause;
link_info->duplex_setting = resp->duplex_cfg;
if (link_info->phy_link_status == BNGE_LINK_LINK) {
link_info->link_speed = le16_to_cpu(resp->link_speed);
link_info->active_lanes = resp->active_lanes;
} else {
link_info->link_speed = 0;
link_info->active_lanes = 0;
}
link_info->force_link_speed2 = le16_to_cpu(resp->force_link_speeds2);
link_info->support_speeds2 = le16_to_cpu(resp->support_speeds2);
link_info->auto_link_speeds2 = le16_to_cpu(resp->auto_link_speeds2);
link_info->lp_auto_link_speeds =
le16_to_cpu(resp->link_partner_adv_speeds);
link_info->media_type = resp->media_type;
link_info->phy_type = resp->phy_type;
link_info->phy_addr = resp->eee_config_phy_addr &
PORT_PHY_QCFG_RESP_PHY_ADDR_MASK;
link_info->module_status = resp->module_status;
link_info->fec_cfg = le16_to_cpu(resp->fec_cfg);
link_info->active_fec_sig_mode = resp->active_fec_signal_mode;
if (chng_link_state) {
if (link_info->phy_link_status == BNGE_LINK_LINK)
link_info->link_state = BNGE_LINK_STATE_UP;
else
link_info->link_state = BNGE_LINK_STATE_DOWN;
if (link_state != link_info->link_state)
bnge_report_link(bd);
} else {
/* always link down if not required to update link state */
link_info->link_state = BNGE_LINK_STATE_DOWN;
}
bnge_hwrm_req_drop(bd, req);
if (!BNGE_PHY_CFG_ABLE(bd))
return 0;
support_changed = bnge_support_speed_dropped(bn);
if (support_changed && (bn->eth_link_info.autoneg & BNGE_AUTONEG_SPEED))
rc = bnge_hwrm_set_link_setting(bn, true);
return rc;
}
int bnge_hwrm_set_pause(struct bnge_net *bn)
{
struct bnge_ethtool_link_info *elink_info = &bn->eth_link_info;
struct hwrm_port_phy_cfg_input *req;
struct bnge_dev *bd = bn->bd;
bool pause_autoneg;
int rc;
rc = bnge_hwrm_req_init(bd, req, HWRM_PORT_PHY_CFG);
if (rc)
return rc;
pause_autoneg = !!(elink_info->autoneg & BNGE_AUTONEG_FLOW_CTRL);
/* Prepare PHY pause-advertisement or forced-pause settings. */
bnge_hwrm_set_pause_common(bn, req);
/* Prepare speed/autoneg settings */
if (pause_autoneg || elink_info->force_link_chng)
bnge_hwrm_set_link_common(bn, req);
rc = bnge_hwrm_req_send(bd, req);
if (!rc && !pause_autoneg) {
/* Since changing of pause setting, with pause autoneg off,
* doesn't trigger any link change event, the driver needs to
* update the current MAC pause upon successful return of the
* phy_cfg command.
*/
bd->link_info.force_pause_setting =
bd->link_info.pause = elink_info->req_flow_ctrl;
bd->link_info.auto_pause_setting = 0;
if (!elink_info->force_link_chng)
bnge_report_link(bd);
}
if (!rc)
elink_info->force_link_chng = false;
return rc;
}
int bnge_hwrm_shutdown_link(struct bnge_dev *bd)
{
struct hwrm_port_phy_cfg_input *req;
int rc;
if (!BNGE_PHY_CFG_ABLE(bd))
return 0;
rc = bnge_hwrm_req_init(bd, req, HWRM_PORT_PHY_CFG);
if (rc)
return rc;
req->flags = cpu_to_le32(PORT_PHY_CFG_REQ_FLAGS_FORCE_LINK_DWN);
rc = bnge_hwrm_req_send(bd, req);
if (!rc) {
/* Device is not obliged to link down in certain scenarios,
* even when forced. Setting the state unknown is consistent
* with driver startup and will force link state to be
* reported during subsequent open based on PORT_PHY_QCFG.
*/
bd->link_info.link_state = BNGE_LINK_STATE_UNKNOWN;
}
return rc;
}
void bnge_hwrm_stat_ctx_free(struct bnge_net *bn)
{
struct hwrm_stat_ctx_free_input *req;
@ -1248,3 +1486,145 @@ int bnge_hwrm_vnic_set_tpa(struct bnge_dev *bd, struct bnge_vnic_info *vnic,
return bnge_hwrm_req_send(bd, req);
}
int bnge_hwrm_func_qstat_ext(struct bnge_dev *bd, struct bnge_stats_mem *stats)
{
struct hwrm_func_qstats_ext_output *resp;
struct hwrm_func_qstats_ext_input *req;
__le64 *hw_masks;
int rc;
if (!(bd->fw_cap & BNGE_FW_CAP_EXT_HW_STATS_SUPPORTED))
return -EOPNOTSUPP;
rc = bnge_hwrm_req_init(bd, req, HWRM_FUNC_QSTATS_EXT);
if (rc)
return rc;
req->fid = cpu_to_le16(0xffff);
req->flags = FUNC_QSTATS_EXT_REQ_FLAGS_COUNTER_MASK;
resp = bnge_hwrm_req_hold(bd, req);
rc = bnge_hwrm_req_send(bd, req);
if (!rc) {
hw_masks = &resp->rx_ucast_pkts;
bnge_copy_hw_masks(stats->hw_masks, hw_masks, stats->len / 8);
}
bnge_hwrm_req_drop(bd, req);
return rc;
}
int bnge_hwrm_port_qstats_ext(struct bnge_dev *bd, u8 flags)
{
struct hwrm_queue_pri2cos_qcfg_output *resp_qc;
struct bnge_net *bn = netdev_priv(bd->netdev);
struct hwrm_queue_pri2cos_qcfg_input *req_qc;
struct hwrm_port_qstats_ext_output *resp_qs;
struct hwrm_port_qstats_ext_input *req_qs;
struct bnge_pf_info *pf = &bd->pf;
u32 tx_stat_size;
int rc;
if (!(bn->flags & BNGE_FLAG_PORT_STATS_EXT))
return 0;
if (flags && !(bd->fw_cap & BNGE_FW_CAP_EXT_HW_STATS_SUPPORTED))
return -EOPNOTSUPP;
rc = bnge_hwrm_req_init(bd, req_qs, HWRM_PORT_QSTATS_EXT);
if (rc)
return rc;
req_qs->flags = flags;
req_qs->port_id = cpu_to_le16(pf->port_id);
req_qs->rx_stat_size = cpu_to_le16(sizeof(struct rx_port_stats_ext));
req_qs->rx_stat_host_addr =
cpu_to_le64(bn->rx_port_stats_ext.hw_stats_map);
tx_stat_size = bn->tx_port_stats_ext.hw_stats ?
sizeof(struct tx_port_stats_ext) : 0;
req_qs->tx_stat_size = cpu_to_le16(tx_stat_size);
req_qs->tx_stat_host_addr =
cpu_to_le64(bn->tx_port_stats_ext.hw_stats_map);
resp_qs = bnge_hwrm_req_hold(bd, req_qs);
rc = bnge_hwrm_req_send(bd, req_qs);
if (!rc) {
bn->fw_rx_stats_ext_size =
le16_to_cpu(resp_qs->rx_stat_size) / 8;
bn->fw_tx_stats_ext_size = tx_stat_size ?
le16_to_cpu(resp_qs->tx_stat_size) / 8 : 0;
} else {
bn->fw_rx_stats_ext_size = 0;
bn->fw_tx_stats_ext_size = 0;
}
bnge_hwrm_req_drop(bd, req_qs);
if (flags)
return rc;
if (bn->fw_tx_stats_ext_size <=
offsetof(struct tx_port_stats_ext, pfc_pri0_tx_duration_us) / 8) {
bn->pri2cos_valid = false;
return rc;
}
rc = bnge_hwrm_req_init(bd, req_qc, HWRM_QUEUE_PRI2COS_QCFG);
if (rc)
return rc;
req_qc->flags = cpu_to_le32(QUEUE_PRI2COS_QCFG_REQ_FLAGS_IVLAN);
resp_qc = bnge_hwrm_req_hold(bd, req_qc);
rc = bnge_hwrm_req_send(bd, req_qc);
if (!rc) {
u8 *pri2cos;
int i, j;
pri2cos = &resp_qc->pri0_cos_queue_id;
for (i = 0; i < 8; i++) {
u8 queue_id = pri2cos[i];
u8 queue_idx;
/* Per port queue IDs start from 0, 10, 20, etc */
queue_idx = queue_id % 10;
if (queue_idx >= BNGE_MAX_QUEUE) {
bn->pri2cos_valid = false;
rc = -EINVAL;
goto drop_req;
}
for (j = 0; j < bd->max_q; j++) {
if (bd->q_ids[j] == queue_id)
bn->pri2cos_idx[i] = queue_idx;
}
}
bn->pri2cos_valid = true;
}
drop_req:
bnge_hwrm_req_drop(bd, req_qc);
return rc;
}
int bnge_hwrm_port_qstats(struct bnge_dev *bd, u8 flags)
{
struct bnge_net *bn = netdev_priv(bd->netdev);
struct hwrm_port_qstats_input *req;
struct bnge_pf_info *pf = &bd->pf;
int rc;
if (!(bn->flags & BNGE_FLAG_PORT_STATS))
return 0;
if (flags && !(bd->fw_cap & BNGE_FW_CAP_EXT_HW_STATS_SUPPORTED))
return -EOPNOTSUPP;
rc = bnge_hwrm_req_init(bd, req, HWRM_PORT_QSTATS);
if (rc)
return rc;
req->flags = flags;
req->port_id = cpu_to_le16(pf->port_id);
req->tx_stat_host_addr = cpu_to_le64(bn->port_stats.hw_stats_map +
BNGE_TX_PORT_STATS_BYTE_OFFSET);
req->rx_stat_host_addr = cpu_to_le64(bn->port_stats.hw_stats_map);
return bnge_hwrm_req_send(bd, req);
}

View File

@ -57,4 +57,12 @@ int hwrm_ring_alloc_send_msg(struct bnge_net *bn,
int bnge_hwrm_set_async_event_cr(struct bnge_dev *bd, int idx);
int bnge_hwrm_vnic_set_tpa(struct bnge_dev *bd, struct bnge_vnic_info *vnic,
u32 tpa_flags);
int bnge_update_link(struct bnge_net *bn, bool chng_link_state);
int bnge_hwrm_phy_qcaps(struct bnge_dev *bd);
int bnge_hwrm_set_link_setting(struct bnge_net *bn, bool set_pause);
int bnge_hwrm_set_pause(struct bnge_net *bn);
int bnge_hwrm_shutdown_link(struct bnge_dev *bd);
int bnge_hwrm_port_qstats(struct bnge_dev *bd, u8 flags);
int bnge_hwrm_port_qstats_ext(struct bnge_dev *bd, u8 flags);
int bnge_hwrm_func_qstat_ext(struct bnge_dev *bd, struct bnge_stats_mem *stats);
#endif /* _BNGE_HWRM_LIB_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,173 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2026 Broadcom */
#ifndef _BNGE_LINK_H_
#define _BNGE_LINK_H_
#include <linux/ethtool.h>
#define BNGE_PHY_CFG_ABLE(bd) \
((bd)->link_info.phy_enabled)
#define BNGE_PHY_AUTO_SPEEDS2_MASK \
PORT_PHY_CFG_REQ_ENABLES_AUTO_LINK_SPEEDS2_MASK
#define BNGE_PHY_FLAGS_RESTART_AUTO \
PORT_PHY_CFG_REQ_FLAGS_RESTART_AUTONEG
#define BNGE_PHY_FLAGS_ENA_FORCE_SPEEDS2 \
PORT_PHY_CFG_REQ_ENABLES_FORCE_LINK_SPEEDS2
#define BNGE_LINK_LINK PORT_PHY_QCFG_RESP_LINK_LINK
enum bnge_link_state {
BNGE_LINK_STATE_UNKNOWN,
BNGE_LINK_STATE_DOWN,
BNGE_LINK_STATE_UP,
};
#define BNGE_LINK_IS_UP(bd) \
((bd)->link_info.link_state == BNGE_LINK_STATE_UP)
#define BNGE_LINK_DUPLEX_FULL PORT_PHY_QCFG_RESP_DUPLEX_STATE_FULL
#define BNGE_LINK_PAUSE_TX PORT_PHY_QCFG_RESP_PAUSE_TX
#define BNGE_LINK_PAUSE_RX PORT_PHY_QCFG_RESP_PAUSE_RX
#define BNGE_LINK_PAUSE_BOTH (PORT_PHY_QCFG_RESP_PAUSE_RX | \
PORT_PHY_QCFG_RESP_PAUSE_TX)
#define BNGE_LINK_AUTO_NONE PORT_PHY_QCFG_RESP_AUTO_MODE_NONE
#define BNGE_LINK_AUTO_MSK PORT_PHY_QCFG_RESP_AUTO_MODE_SPEED_MASK
#define BNGE_AUTO_MODE(mode) ((mode) > BNGE_LINK_AUTO_NONE && \
(mode) <= BNGE_LINK_AUTO_MSK)
#define BNGE_LINK_SPEED_50GB PORT_PHY_QCFG_RESP_LINK_SPEED_50GB
#define BNGE_LINK_SPEED_100GB PORT_PHY_QCFG_RESP_LINK_SPEED_100GB
#define BNGE_LINK_SPEED_200GB PORT_PHY_QCFG_RESP_LINK_SPEED_200GB
#define BNGE_LINK_SPEED_400GB PORT_PHY_QCFG_RESP_LINK_SPEED_400GB
#define BNGE_LINK_SPEED_800GB PORT_PHY_QCFG_RESP_LINK_SPEED_800GB
#define BNGE_LINK_SPEEDS2_MSK_50GB PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_50GB
#define BNGE_LINK_SPEEDS2_MSK_100GB PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_100GB
#define BNGE_LINK_SPEEDS2_MSK_50GB_PAM4 \
PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_50GB_PAM4_56
#define BNGE_LINK_SPEEDS2_MSK_100GB_PAM4 \
PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_100GB_PAM4_56
#define BNGE_LINK_SPEEDS2_MSK_200GB_PAM4 \
PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_200GB_PAM4_56
#define BNGE_LINK_SPEEDS2_MSK_400GB_PAM4 \
PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_400GB_PAM4_56
#define BNGE_LINK_SPEEDS2_MSK_100GB_PAM4_112 \
PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_100GB_PAM4_112
#define BNGE_LINK_SPEEDS2_MSK_200GB_PAM4_112 \
PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_200GB_PAM4_112
#define BNGE_LINK_SPEEDS2_MSK_400GB_PAM4_112 \
PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_400GB_PAM4_112
#define BNGE_LINK_SPEEDS2_MSK_800GB_PAM4_112 \
PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_800GB_PAM4_112
#define BNGE_LINK_SPEED_50GB_PAM4 \
PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_50GB_PAM4_56
#define BNGE_LINK_SPEED_100GB_PAM4 \
PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_100GB_PAM4_56
#define BNGE_LINK_SPEED_200GB_PAM4 \
PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_200GB_PAM4_56
#define BNGE_LINK_SPEED_400GB_PAM4 \
PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_400GB_PAM4_56
#define BNGE_LINK_SPEED_100GB_PAM4_112 \
PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_100GB_PAM4_112
#define BNGE_LINK_SPEED_200GB_PAM4_112 \
PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_200GB_PAM4_112
#define BNGE_LINK_SPEED_400GB_PAM4_112 \
PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_400GB_PAM4_112
#define BNGE_LINK_SPEED_800GB_PAM4_112 \
PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_800GB_PAM4_112
#define BNGE_FEC_NONE PORT_PHY_QCFG_RESP_FEC_CFG_FEC_NONE_SUPPORTED
#define BNGE_FEC_AUTONEG PORT_PHY_QCFG_RESP_FEC_CFG_FEC_AUTONEG_ENABLED
#define BNGE_FEC_ENC_BASE_R_CAP \
PORT_PHY_QCFG_RESP_FEC_CFG_FEC_CLAUSE74_SUPPORTED
#define BNGE_FEC_ENC_BASE_R PORT_PHY_QCFG_RESP_FEC_CFG_FEC_CLAUSE74_ENABLED
#define BNGE_FEC_ENC_RS_CAP \
PORT_PHY_QCFG_RESP_FEC_CFG_FEC_CLAUSE91_SUPPORTED
#define BNGE_FEC_ENC_LLRS_CAP \
(PORT_PHY_QCFG_RESP_FEC_CFG_FEC_RS272_1XN_SUPPORTED | \
PORT_PHY_QCFG_RESP_FEC_CFG_FEC_RS272_IEEE_SUPPORTED)
#define BNGE_FEC_ENC_RS \
(PORT_PHY_QCFG_RESP_FEC_CFG_FEC_CLAUSE91_ENABLED | \
PORT_PHY_QCFG_RESP_FEC_CFG_FEC_RS544_1XN_ENABLED | \
PORT_PHY_QCFG_RESP_FEC_CFG_FEC_RS544_IEEE_ENABLED)
#define BNGE_FEC_ENC_LLRS \
(PORT_PHY_QCFG_RESP_FEC_CFG_FEC_RS272_1XN_ENABLED | \
PORT_PHY_QCFG_RESP_FEC_CFG_FEC_RS272_IEEE_ENABLED)
struct bnge_link_info {
u8 phy_type;
u8 media_type;
u8 phy_addr;
u8 phy_link_status;
bool phy_enabled;
u8 link_state;
u8 active_lanes;
u8 duplex;
u8 pause;
u8 lp_pause;
u8 auto_pause_setting;
u8 force_pause_setting;
u8 duplex_setting;
u8 auto_mode;
u16 link_speed;
u16 support_speeds2;
u16 auto_link_speeds2;
u16 support_auto_speeds2;
u16 lp_auto_link_speeds;
u16 force_link_speed2;
u8 module_status;
u8 active_fec_sig_mode;
u16 fec_cfg;
/* A copy of phy_qcfg output used to report link
* info to VF
*/
struct hwrm_port_phy_qcfg_output phy_qcfg_resp;
bool phy_retry;
unsigned long phy_retry_expires;
};
#define BNGE_AUTONEG_SPEED 1
#define BNGE_AUTONEG_FLOW_CTRL 2
#define BNGE_SIG_MODE_NRZ PORT_PHY_QCFG_RESP_SIGNAL_MODE_NRZ
#define BNGE_SIG_MODE_PAM4 PORT_PHY_QCFG_RESP_SIGNAL_MODE_PAM4
#define BNGE_SIG_MODE_PAM4_112 PORT_PHY_QCFG_RESP_SIGNAL_MODE_PAM4_112
#define BNGE_SIG_MODE_MAX (PORT_PHY_QCFG_RESP_SIGNAL_MODE_LAST + 1)
struct bnge_ethtool_link_info {
/* copy of requested setting from ethtool cmd */
u8 autoneg;
u8 req_signal_mode;
u8 req_duplex;
u8 req_flow_ctrl;
u16 req_link_speed;
u16 advertising; /* user adv setting */
bool force_link_chng;
};
void bnge_hwrm_set_link_common(struct bnge_net *bn,
struct hwrm_port_phy_cfg_input *req);
void bnge_hwrm_set_pause_common(struct bnge_net *bn,
struct hwrm_port_phy_cfg_input *req);
int bnge_update_phy_setting(struct bnge_net *bn);
void bnge_get_port_module_status(struct bnge_net *bn);
void bnge_report_link(struct bnge_dev *bd);
bool bnge_support_speed_dropped(struct bnge_net *bn);
void bnge_init_ethtool_link_settings(struct bnge_net *bn);
int bnge_probe_phy(struct bnge_net *bn, bool fw_dflt);
int bnge_set_link_ksettings(struct net_device *dev,
const struct ethtool_link_ksettings *lk_ksettings);
int bnge_get_link_ksettings(struct net_device *dev,
struct ethtool_link_ksettings *lk_ksettings);
u32 bnge_get_link(struct net_device *dev);
void bnge_link_async_event_process(struct bnge_net *bn, u16 event_id);
#endif /* _BNGE_LINK_H_ */

View File

@ -39,6 +39,10 @@ static void bnge_free_stats_mem(struct bnge_net *bn,
{
struct bnge_dev *bd = bn->bd;
kfree(stats->hw_masks);
stats->hw_masks = NULL;
kfree(stats->sw_stats);
stats->sw_stats = NULL;
if (stats->hw_stats) {
dma_free_coherent(bd->dev, stats->len, stats->hw_stats,
stats->hw_stats_map);
@ -47,7 +51,7 @@ static void bnge_free_stats_mem(struct bnge_net *bn,
}
static int bnge_alloc_stats_mem(struct bnge_net *bn,
struct bnge_stats_mem *stats)
struct bnge_stats_mem *stats, bool alloc_masks)
{
struct bnge_dev *bd = bn->bd;
@ -56,7 +60,23 @@ static int bnge_alloc_stats_mem(struct bnge_net *bn,
if (!stats->hw_stats)
return -ENOMEM;
stats->sw_stats = kzalloc(stats->len, GFP_KERNEL);
if (!stats->sw_stats)
goto stats_mem_err;
if (alloc_masks) {
stats->hw_masks = kzalloc(stats->len, GFP_KERNEL);
if (!stats->hw_masks)
goto stats_mem_err;
}
u64_stats_init(&stats->syncp);
return 0;
stats_mem_err:
bnge_free_stats_mem(bn, stats);
return -ENOMEM;
}
static void bnge_free_ring_stats(struct bnge_net *bn)
@ -75,6 +95,107 @@ static void bnge_free_ring_stats(struct bnge_net *bn)
}
}
static void bnge_fill_masks(u64 *mask_arr, u64 mask, int count)
{
int i;
for (i = 0; i < count; i++)
mask_arr[i] = mask;
}
void bnge_copy_hw_masks(u64 *mask_arr, __le64 *hw_mask_arr, int count)
{
int i;
for (i = 0; i < count; i++)
mask_arr[i] = le64_to_cpu(hw_mask_arr[i]);
}
static void bnge_init_stats(struct bnge_net *bn)
{
struct bnge_napi *bnapi = bn->bnapi[0];
struct bnge_nq_ring_info *nqr;
struct bnge_stats_mem *stats;
struct bnge_dev *bd = bn->bd;
__le64 *rx_stats, *tx_stats;
int rc, rx_count, tx_count;
u64 *rx_masks, *tx_masks;
u8 flags;
nqr = &bnapi->nq_ring;
stats = &nqr->stats;
rc = bnge_hwrm_func_qstat_ext(bd, stats);
if (rc) {
u64 mask = (1ULL << 48) - 1;
bnge_fill_masks(stats->hw_masks, mask, stats->len / 8);
}
if (bn->flags & BNGE_FLAG_PORT_STATS) {
stats = &bn->port_stats;
rx_stats = stats->hw_stats;
rx_masks = stats->hw_masks;
rx_count = sizeof(struct rx_port_stats) / 8;
tx_stats = rx_stats + BNGE_TX_PORT_STATS_BYTE_OFFSET / 8;
tx_masks = rx_masks + BNGE_TX_PORT_STATS_BYTE_OFFSET / 8;
tx_count = sizeof(struct tx_port_stats) / 8;
flags = PORT_QSTATS_REQ_FLAGS_COUNTER_MASK;
rc = bnge_hwrm_port_qstats(bd, flags);
if (rc) {
u64 mask = (1ULL << 40) - 1;
bnge_fill_masks(rx_masks, mask, rx_count);
bnge_fill_masks(tx_masks, mask, tx_count);
} else {
bnge_copy_hw_masks(rx_masks, rx_stats, rx_count);
bnge_copy_hw_masks(tx_masks, tx_stats, tx_count);
}
bnge_hwrm_port_qstats(bd, 0);
}
if (bn->flags & BNGE_FLAG_PORT_STATS_EXT) {
stats = &bn->rx_port_stats_ext;
rx_stats = stats->hw_stats;
rx_masks = stats->hw_masks;
rx_count = sizeof(struct rx_port_stats_ext) / 8;
stats = &bn->tx_port_stats_ext;
tx_stats = stats->hw_stats;
tx_masks = stats->hw_masks;
tx_count = sizeof(struct tx_port_stats_ext) / 8;
flags = PORT_QSTATS_EXT_REQ_FLAGS_COUNTER_MASK;
rc = bnge_hwrm_port_qstats_ext(bd, flags);
if (rc) {
u64 mask = (1ULL << 40) - 1;
bnge_fill_masks(rx_masks, mask, rx_count);
if (tx_stats)
bnge_fill_masks(tx_masks, mask, tx_count);
} else {
bnge_copy_hw_masks(rx_masks, rx_stats, rx_count);
if (tx_stats)
bnge_copy_hw_masks(tx_masks, tx_stats,
tx_count);
}
bnge_hwrm_port_qstats_ext(bd, 0);
}
}
static void bnge_free_port_ext_stats(struct bnge_net *bn)
{
bn->flags &= ~BNGE_FLAG_PORT_STATS_EXT;
bnge_free_stats_mem(bn, &bn->rx_port_stats_ext);
bnge_free_stats_mem(bn, &bn->tx_port_stats_ext);
}
static void bnge_free_port_stats(struct bnge_net *bn)
{
bn->flags &= ~BNGE_FLAG_PORT_STATS;
bnge_free_stats_mem(bn, &bn->port_stats);
bnge_free_port_ext_stats(bn);
}
static int bnge_alloc_ring_stats(struct bnge_net *bn)
{
struct bnge_dev *bd = bn->bd;
@ -88,12 +209,13 @@ static int bnge_alloc_ring_stats(struct bnge_net *bn)
struct bnge_nq_ring_info *nqr = &bnapi->nq_ring;
nqr->stats.len = size;
rc = bnge_alloc_stats_mem(bn, &nqr->stats);
rc = bnge_alloc_stats_mem(bn, &nqr->stats, !i);
if (rc)
goto err_free_ring_stats;
nqr->hw_stats_ctx_id = INVALID_STATS_CTX_ID;
}
return 0;
err_free_ring_stats:
@ -101,6 +223,227 @@ static int bnge_alloc_ring_stats(struct bnge_net *bn)
return rc;
}
static void bnge_alloc_port_ext_stats(struct bnge_net *bn)
{
struct bnge_dev *bd = bn->bd;
int rc;
if (!(bd->fw_cap & BNGE_FW_CAP_EXT_STATS_SUPPORTED))
return;
if (!bn->rx_port_stats_ext.hw_stats) {
bn->rx_port_stats_ext.len = sizeof(struct rx_port_stats_ext);
rc = bnge_alloc_stats_mem(bn, &bn->rx_port_stats_ext, true);
/* Extended stats are optional */
if (rc)
return;
}
if (!bn->tx_port_stats_ext.hw_stats) {
bn->tx_port_stats_ext.len = sizeof(struct tx_port_stats_ext);
rc = bnge_alloc_stats_mem(bn, &bn->tx_port_stats_ext, true);
/* Extended stats are optional */
if (rc) {
bnge_free_port_ext_stats(bn);
return;
}
}
bn->flags |= BNGE_FLAG_PORT_STATS_EXT;
}
static int bnge_alloc_port_stats(struct bnge_net *bn)
{
int rc;
if (!bn->port_stats.hw_stats) {
bn->port_stats.len = BNGE_PORT_STATS_SIZE;
rc = bnge_alloc_stats_mem(bn, &bn->port_stats, true);
if (rc)
return rc;
bn->flags |= BNGE_FLAG_PORT_STATS;
}
bnge_alloc_port_ext_stats(bn);
return 0;
}
void __bnge_queue_sp_work(struct bnge_net *bn)
{
queue_work(bn->bnge_pf_wq, &bn->sp_task);
}
static void bnge_queue_sp_work(struct bnge_net *bn, unsigned int event)
{
set_bit(event, &bn->sp_event);
__bnge_queue_sp_work(bn);
}
static void bnge_timer(struct timer_list *t)
{
struct bnge_net *bn = timer_container_of(bn, t, timer);
struct bnge_dev *bd = bn->bd;
if (!netif_running(bn->netdev) ||
!test_bit(BNGE_STATE_OPEN, &bd->state))
return;
if (READ_ONCE(bd->link_info.phy_retry)) {
if (time_after(jiffies, READ_ONCE(bd->link_info.phy_retry_expires))) {
WRITE_ONCE(bd->link_info.phy_retry, false);
netdev_warn(bn->netdev, "failed to update PHY settings after maximum retries.\n");
} else {
bnge_queue_sp_work(bn, BNGE_UPDATE_PHY_SP_EVENT);
}
}
if (BNGE_LINK_IS_UP(bd) && bn->stats_coal_ticks)
bnge_queue_sp_work(bn, BNGE_PERIODIC_STATS_SP_EVENT);
mod_timer(&bn->timer, jiffies + bn->current_interval);
}
static void bnge_add_one_ctr(u64 hw, u64 *sw, u64 mask)
{
u64 sw_tmp, sw_val;
hw &= mask;
sw_val = READ_ONCE(*sw);
sw_tmp = (sw_val & ~mask) | hw;
if (hw < (sw_val & mask))
sw_tmp += mask + 1;
WRITE_ONCE(*sw, sw_tmp);
}
static void __bnge_accumulate_stats(__le64 *hw_stats, u64 *sw_stats, u64 *masks,
int count, struct u64_stats_sync *syncp)
{
unsigned long flags;
int i;
flags = u64_stats_update_begin_irqsave(syncp);
for (i = 0; i < count; i++) {
u64 hw = le64_to_cpu(READ_ONCE(hw_stats[i]));
if (masks[i] == -1ULL)
WRITE_ONCE(sw_stats[i], hw);
else
bnge_add_one_ctr(hw, &sw_stats[i], masks[i]);
}
u64_stats_update_end_irqrestore(syncp, flags);
}
static void bnge_accumulate_stats(struct bnge_stats_mem *stats)
{
if (!stats->hw_stats)
return;
__bnge_accumulate_stats(stats->hw_stats, stats->sw_stats,
stats->hw_masks, stats->len / 8, &stats->syncp);
}
static void bnge_accumulate_all_stats(struct bnge_dev *bd)
{
struct bnge_net *bn = netdev_priv(bd->netdev);
struct bnge_stats_mem *ring0_stats = NULL;
int i;
for (i = 0; i < bd->nq_nr_rings; i++) {
struct bnge_napi *bnapi = bn->bnapi[i];
struct bnge_nq_ring_info *nqr;
struct bnge_stats_mem *stats;
nqr = &bnapi->nq_ring;
stats = &nqr->stats;
if (!ring0_stats)
ring0_stats = &bn->bnapi[0]->nq_ring.stats;
__bnge_accumulate_stats(stats->hw_stats, stats->sw_stats,
ring0_stats->hw_masks,
ring0_stats->len / 8, &stats->syncp);
}
if (bn->flags & BNGE_FLAG_PORT_STATS) {
struct bnge_stats_mem *stats = &bn->port_stats;
__le64 *hw_stats = stats->hw_stats;
u64 *sw_stats = stats->sw_stats;
u64 *masks = stats->hw_masks;
u16 cnt;
cnt = sizeof(struct rx_port_stats) / 8;
__bnge_accumulate_stats(hw_stats, sw_stats, masks, cnt,
&stats->syncp);
hw_stats += BNGE_TX_PORT_STATS_BYTE_OFFSET / 8;
sw_stats += BNGE_TX_PORT_STATS_BYTE_OFFSET / 8;
masks += BNGE_TX_PORT_STATS_BYTE_OFFSET / 8;
cnt = sizeof(struct tx_port_stats) / 8;
__bnge_accumulate_stats(hw_stats, sw_stats, masks, cnt,
&stats->syncp);
}
if (bn->flags & BNGE_FLAG_PORT_STATS_EXT) {
bnge_accumulate_stats(&bn->rx_port_stats_ext);
bnge_accumulate_stats(&bn->tx_port_stats_ext);
}
}
static void bnge_sp_task(struct work_struct *work)
{
struct bnge_net *bn = container_of(work, struct bnge_net, sp_task);
bool speed_chng, cfg_chng, link_chng;
struct bnge_dev *bd = bn->bd;
netdev_lock(bn->netdev);
if (!test_bit(BNGE_STATE_OPEN, &bd->state)) {
netdev_unlock(bn->netdev);
return;
}
if (test_and_clear_bit(BNGE_PERIODIC_STATS_SP_EVENT, &bn->sp_event)) {
bnge_hwrm_port_qstats(bd, 0);
bnge_hwrm_port_qstats_ext(bd, 0);
bnge_accumulate_all_stats(bd);
}
if (test_and_clear_bit(BNGE_UPDATE_PHY_SP_EVENT, &bn->sp_event)) {
int rc;
rc = bnge_update_phy_setting(bn);
if (rc) {
netdev_warn(bn->netdev, "update PHY settings retry failed\n");
} else {
WRITE_ONCE(bd->link_info.phy_retry, false);
netdev_info(bn->netdev, "update PHY settings retry succeeded\n");
}
}
speed_chng = test_and_clear_bit(BNGE_LINK_SPEED_CHNG_SP_EVENT,
&bn->sp_event);
cfg_chng = test_and_clear_bit(BNGE_LINK_CFG_CHANGE_SP_EVENT,
&bn->sp_event);
link_chng = test_and_clear_bit(BNGE_LINK_CHNG_SP_EVENT,
&bn->sp_event);
if (speed_chng || cfg_chng || link_chng) {
int rc;
if (speed_chng)
bnge_hwrm_phy_qcaps(bd);
rc = bnge_update_link(bn, true);
if (rc)
netdev_err(bn->netdev, "SP task cannot update link (rc: %d)\n",
rc);
if (speed_chng || cfg_chng)
bnge_init_ethtool_link_settings(bn);
}
netdev_unlock(bn->netdev);
}
static void bnge_free_nq_desc_arr(struct bnge_nq_ring_info *nqr)
{
struct bnge_ring_struct *ring = &nqr->ring_struct;
@ -947,6 +1290,8 @@ static int bnge_alloc_core(struct bnge_net *bn)
if (rc)
goto err_free_core;
bnge_init_stats(bn);
rc = bnge_alloc_vnics(bn);
if (rc)
goto err_free_core;
@ -2466,6 +2811,8 @@ static void bnge_tx_enable(struct bnge_net *bn)
/* Make sure napi polls see @dev_state change */
synchronize_net();
netif_tx_wake_all_queues(bn->netdev);
if (BNGE_LINK_IS_UP(bn->bd))
netif_carrier_on(bn->netdev);
}
static int bnge_open_core(struct bnge_net *bn)
@ -2502,11 +2849,28 @@ static int bnge_open_core(struct bnge_net *bn)
bnge_enable_napi(bn);
rc = bnge_update_phy_setting(bn);
if (rc) {
netdev_warn(bn->netdev, "failed to update PHY settings (rc: %d)\n",
rc);
WRITE_ONCE(bd->link_info.phy_retry_expires, jiffies + 5 * HZ);
WRITE_ONCE(bd->link_info.phy_retry, true);
} else {
WRITE_ONCE(bd->link_info.phy_retry, false);
}
set_bit(BNGE_STATE_OPEN, &bd->state);
set_bit(BNGE_STATE_STATS_ENABLE, &bn->state);
bnge_enable_int(bn);
bnge_tx_enable(bn);
mod_timer(&bn->timer, jiffies + bn->current_interval);
/* Poll link status and check for SFP+ module status */
bnge_get_port_module_status(bn);
return 0;
err_free_irq:
@ -2535,6 +2899,184 @@ static int bnge_shutdown_nic(struct bnge_net *bn)
return 0;
}
static void bnge_add_prev_ring_stats64(struct bnge_net *bn,
struct rtnl_link_stats64 *stats)
{
struct netdev_queue_stats_rx *rx_save = &bn->rxq_prv_stats;
struct netdev_queue_stats_tx *tx_save = &bn->txq_prv_stats;
struct rtnl_link_stats64 *stats64_save = &bn->prv_stats64;
stats->rx_packets += rx_save->packets;
stats->tx_packets += tx_save->packets;
stats->rx_bytes += rx_save->bytes;
stats->tx_bytes += tx_save->bytes;
stats->rx_missed_errors += rx_save->hw_drop_overruns;
stats->tx_dropped += tx_save->hw_drop_errors;
stats->multicast += stats64_save->multicast;
}
static void bnge_get_ring_stats64(struct bnge_dev *bd,
struct rtnl_link_stats64 *stats)
{
struct bnge_net *bn = netdev_priv(bd->netdev);
int i;
for (i = 0; i < bd->nq_nr_rings; i++) {
struct bnge_napi *bnapi = bn->bnapi[i];
u64 tx_bytes, tx_packets, tx_dropped;
u64 multicast, rx_missed_errors;
struct bnge_nq_ring_info *nqr;
u64 rx_bytes, rx_packets;
unsigned int start;
u64 *sw;
nqr = &bnapi->nq_ring;
sw = nqr->stats.sw_stats;
do {
start = u64_stats_fetch_begin(&nqr->stats.syncp);
rx_packets = BNGE_GET_RING_STATS64(sw, rx_ucast_pkts);
rx_packets += BNGE_GET_RING_STATS64(sw, rx_mcast_pkts);
rx_packets += BNGE_GET_RING_STATS64(sw, rx_bcast_pkts);
tx_packets = BNGE_GET_RING_STATS64(sw, tx_ucast_pkts);
tx_packets += BNGE_GET_RING_STATS64(sw, tx_mcast_pkts);
tx_packets += BNGE_GET_RING_STATS64(sw, tx_bcast_pkts);
rx_bytes = BNGE_GET_RING_STATS64(sw, rx_ucast_bytes);
rx_bytes += BNGE_GET_RING_STATS64(sw, rx_mcast_bytes);
rx_bytes += BNGE_GET_RING_STATS64(sw, rx_bcast_bytes);
tx_bytes = BNGE_GET_RING_STATS64(sw, tx_ucast_bytes);
tx_bytes += BNGE_GET_RING_STATS64(sw, tx_mcast_bytes);
tx_bytes += BNGE_GET_RING_STATS64(sw, tx_bcast_bytes);
multicast = BNGE_GET_RING_STATS64(sw, rx_mcast_pkts);
rx_missed_errors =
BNGE_GET_RING_STATS64(sw, rx_discard_pkts);
tx_dropped =
BNGE_GET_RING_STATS64(sw, tx_error_pkts);
} while (u64_stats_fetch_retry(&nqr->stats.syncp, start));
stats->rx_packets += rx_packets;
stats->tx_packets += tx_packets;
stats->rx_bytes += rx_bytes;
stats->tx_bytes += tx_bytes;
stats->multicast += multicast;
stats->rx_missed_errors += rx_missed_errors;
stats->tx_dropped += tx_dropped;
}
}
static void bnge_get_port_stats64(struct bnge_net *bn,
struct rtnl_link_stats64 *stats)
{
unsigned int start;
u64 *tx, *rx;
rx = bn->port_stats.sw_stats;
tx = bn->port_stats.sw_stats + BNGE_TX_PORT_STATS_BYTE_OFFSET / 8;
do {
start = u64_stats_fetch_begin(&bn->port_stats.syncp);
stats->rx_crc_errors =
BNGE_GET_RX_PORT_STATS64(rx, rx_fcs_err_frames);
stats->rx_frame_errors =
BNGE_GET_RX_PORT_STATS64(rx, rx_align_err_frames);
stats->rx_length_errors =
BNGE_GET_RX_PORT_STATS64(rx, rx_undrsz_frames) +
BNGE_GET_RX_PORT_STATS64(rx, rx_ovrsz_frames) +
BNGE_GET_RX_PORT_STATS64(rx, rx_runt_frames);
stats->rx_errors =
BNGE_GET_RX_PORT_STATS64(rx, rx_false_carrier_frames) +
BNGE_GET_RX_PORT_STATS64(rx, rx_jbr_frames);
stats->collisions =
BNGE_GET_TX_PORT_STATS64(tx, tx_total_collisions);
stats->tx_fifo_errors =
BNGE_GET_TX_PORT_STATS64(tx, tx_fifo_underruns);
stats->tx_errors = BNGE_GET_TX_PORT_STATS64(tx, tx_err);
} while (u64_stats_fetch_retry(&bn->port_stats.syncp, start));
}
static void bnge_fill_prev_stats64(struct bnge_net *bn,
struct rtnl_link_stats64 *stats)
{
struct netdev_queue_stats_rx *rx_save = &bn->rxq_prv_stats;
struct netdev_queue_stats_tx *tx_save = &bn->txq_prv_stats;
struct rtnl_link_stats64 *stats64_save = &bn->prv_stats64;
stats->rx_packets = rx_save->packets;
stats->tx_packets = tx_save->packets;
stats->rx_bytes = rx_save->bytes;
stats->tx_bytes = tx_save->bytes;
stats->rx_missed_errors = rx_save->hw_drop_overruns;
stats->tx_dropped = tx_save->hw_drop_errors;
stats->multicast = stats64_save->multicast;
}
static void bnge_get_stats64(struct net_device *dev,
struct rtnl_link_stats64 *stats)
{
struct bnge_net *bn = netdev_priv(dev);
if (bn->flags & BNGE_FLAG_PORT_STATS)
bnge_get_port_stats64(bn, stats);
spin_lock_bh(&bn->stats_lock);
if (!test_bit(BNGE_STATE_STATS_ENABLE, &bn->state)) {
bnge_fill_prev_stats64(bn, stats);
spin_unlock_bh(&bn->stats_lock);
return;
}
bnge_get_ring_stats64(bn->bd, stats);
bnge_add_prev_ring_stats64(bn, stats);
spin_unlock_bh(&bn->stats_lock);
}
static void bnge_save_ring_stats(struct bnge_net *bn)
{
struct netdev_queue_stats_rx *rx_save = &bn->rxq_prv_stats;
struct netdev_queue_stats_tx *tx_save = &bn->txq_prv_stats;
struct rtnl_link_stats64 *stats64_save = &bn->prv_stats64;
int i;
for (i = 0; i < bn->bd->nq_nr_rings; i++) {
struct bnge_napi *bnapi = bn->bnapi[i];
struct bnge_nq_ring_info *nqr;
u64 *sw;
nqr = &bnapi->nq_ring;
sw = nqr->stats.sw_stats;
rx_save->packets += BNGE_GET_RING_STATS64(sw, rx_ucast_pkts);
rx_save->packets += BNGE_GET_RING_STATS64(sw, rx_mcast_pkts);
rx_save->packets += BNGE_GET_RING_STATS64(sw, rx_bcast_pkts);
rx_save->bytes += BNGE_GET_RING_STATS64(sw, rx_ucast_bytes);
rx_save->bytes += BNGE_GET_RING_STATS64(sw, rx_mcast_bytes);
rx_save->bytes += BNGE_GET_RING_STATS64(sw, rx_bcast_bytes);
rx_save->hw_drop_overruns += BNGE_GET_RING_STATS64(sw, rx_discard_pkts);
rx_save->hw_drops += BNGE_GET_RING_STATS64(sw, rx_error_pkts) +
BNGE_GET_RING_STATS64(sw, rx_discard_pkts);
tx_save->packets += BNGE_GET_RING_STATS64(sw, tx_ucast_pkts);
tx_save->packets += BNGE_GET_RING_STATS64(sw, tx_mcast_pkts);
tx_save->packets += BNGE_GET_RING_STATS64(sw, tx_bcast_pkts);
tx_save->bytes += BNGE_GET_RING_STATS64(sw, tx_ucast_bytes);
tx_save->bytes += BNGE_GET_RING_STATS64(sw, tx_mcast_bytes);
tx_save->bytes += BNGE_GET_RING_STATS64(sw, tx_bcast_bytes);
tx_save->hw_drop_errors += BNGE_GET_RING_STATS64(sw, tx_error_pkts);
tx_save->hw_drops += BNGE_GET_RING_STATS64(sw, tx_discard_pkts) +
BNGE_GET_RING_STATS64(sw, tx_error_pkts);
stats64_save->multicast +=
BNGE_GET_RING_STATS64(sw, rx_mcast_pkts);
}
}
static void bnge_close_core(struct bnge_net *bn)
{
struct bnge_dev *bd = bn->bd;
@ -2542,8 +3084,17 @@ static void bnge_close_core(struct bnge_net *bn)
bnge_tx_disable(bn);
clear_bit(BNGE_STATE_OPEN, &bd->state);
timer_delete_sync(&bn->timer);
bnge_shutdown_nic(bn);
bnge_disable_napi(bn);
/* Save ring stats before shutdown */
spin_lock_bh(&bn->stats_lock);
bnge_save_ring_stats(bn);
clear_bit(BNGE_STATE_STATS_ENABLE, &bn->state);
spin_unlock_bh(&bn->stats_lock);
bnge_free_all_rings_bufs(bn);
bnge_free_irq(bn);
bnge_del_napi(bn);
@ -2556,14 +3107,96 @@ static int bnge_close(struct net_device *dev)
struct bnge_net *bn = netdev_priv(dev);
bnge_close_core(bn);
bnge_hwrm_shutdown_link(bn->bd);
bn->sp_event = 0;
return 0;
}
static void bnge_get_queue_stats_rx(struct net_device *dev, int i,
struct netdev_queue_stats_rx *stats)
{
struct bnge_net *bn = netdev_priv(dev);
struct bnge_nq_ring_info *nqr;
u64 *sw;
if (!bn->bnapi)
return;
nqr = &bn->bnapi[i]->nq_ring;
sw = nqr->stats.sw_stats;
stats->packets = 0;
stats->packets += BNGE_GET_RING_STATS64(sw, rx_ucast_pkts);
stats->packets += BNGE_GET_RING_STATS64(sw, rx_mcast_pkts);
stats->packets += BNGE_GET_RING_STATS64(sw, rx_bcast_pkts);
stats->bytes = 0;
stats->bytes += BNGE_GET_RING_STATS64(sw, rx_ucast_bytes);
stats->bytes += BNGE_GET_RING_STATS64(sw, rx_mcast_bytes);
stats->bytes += BNGE_GET_RING_STATS64(sw, rx_bcast_bytes);
stats->hw_drop_overruns = BNGE_GET_RING_STATS64(sw, rx_discard_pkts);
stats->hw_drops = BNGE_GET_RING_STATS64(sw, rx_error_pkts) +
stats->hw_drop_overruns;
}
static void bnge_get_queue_stats_tx(struct net_device *dev, int i,
struct netdev_queue_stats_tx *stats)
{
struct bnge_net *bn = netdev_priv(dev);
struct bnge_napi *bnapi;
u64 *sw;
if (!bn->tx_ring)
return;
bnapi = bn->tx_ring[bn->tx_ring_map[i]].bnapi;
sw = bnapi->nq_ring.stats.sw_stats;
stats->packets = 0;
stats->packets += BNGE_GET_RING_STATS64(sw, tx_ucast_pkts);
stats->packets += BNGE_GET_RING_STATS64(sw, tx_mcast_pkts);
stats->packets += BNGE_GET_RING_STATS64(sw, tx_bcast_pkts);
stats->bytes = 0;
stats->bytes += BNGE_GET_RING_STATS64(sw, tx_ucast_bytes);
stats->bytes += BNGE_GET_RING_STATS64(sw, tx_mcast_bytes);
stats->bytes += BNGE_GET_RING_STATS64(sw, tx_bcast_bytes);
stats->hw_drop_errors = BNGE_GET_RING_STATS64(sw, tx_error_pkts);
stats->hw_drops = BNGE_GET_RING_STATS64(sw, tx_discard_pkts) +
stats->hw_drop_errors;
}
static void bnge_get_base_stats(struct net_device *dev,
struct netdev_queue_stats_rx *rx,
struct netdev_queue_stats_tx *tx)
{
struct bnge_net *bn = netdev_priv(dev);
rx->packets = bn->rxq_prv_stats.packets;
rx->bytes = bn->rxq_prv_stats.bytes;
rx->hw_drops = bn->rxq_prv_stats.hw_drops;
rx->hw_drop_overruns = bn->rxq_prv_stats.hw_drop_overruns;
tx->packets = bn->txq_prv_stats.packets;
tx->bytes = bn->txq_prv_stats.bytes;
tx->hw_drops = bn->txq_prv_stats.hw_drops;
tx->hw_drop_errors = bn->txq_prv_stats.hw_drop_errors;
}
static const struct netdev_stat_ops bnge_stat_ops = {
.get_queue_stats_rx = bnge_get_queue_stats_rx,
.get_queue_stats_tx = bnge_get_queue_stats_tx,
.get_base_stats = bnge_get_base_stats,
};
static const struct net_device_ops bnge_netdev_ops = {
.ndo_open = bnge_open,
.ndo_stop = bnge_close,
.ndo_start_xmit = bnge_start_xmit,
.ndo_get_stats64 = bnge_get_stats64,
.ndo_features_check = bnge_features_check,
};
@ -2705,6 +3338,7 @@ int bnge_netdev_alloc(struct bnge_dev *bd, int max_irqs)
bd->netdev = netdev;
netdev->netdev_ops = &bnge_netdev_ops;
netdev->stat_ops = &bnge_stat_ops;
bnge_set_ethtool_ops(netdev);
@ -2774,6 +3408,18 @@ int bnge_netdev_alloc(struct bnge_dev *bd, int max_irqs)
if (bd->tso_max_segs)
netif_set_tso_max_segs(netdev, bd->tso_max_segs);
INIT_WORK(&bn->sp_task, bnge_sp_task);
timer_setup(&bn->timer, bnge_timer, 0);
bn->current_interval = BNGE_TIMER_INTERVAL;
bn->bnge_pf_wq = alloc_ordered_workqueue("bnge_pf_wq-%s", 0,
dev_name(bd->dev));
if (!bn->bnge_pf_wq) {
netdev_err(netdev, "Unable to create workqueue.\n");
rc = -ENOMEM;
goto err_netdev;
}
bn->rx_ring_size = BNGE_DEFAULT_RX_RING_SIZE;
bn->tx_ring_size = BNGE_DEFAULT_TX_RING_SIZE;
bn->rx_dir = DMA_FROM_DEVICE;
@ -2785,15 +3431,28 @@ int bnge_netdev_alloc(struct bnge_dev *bd, int max_irqs)
bnge_init_l2_fltr_tbl(bn);
bnge_init_mac_addr(bd);
rc = bnge_probe_phy(bn, true);
if (rc)
goto err_free_workq;
rc = bnge_alloc_port_stats(bn);
if (rc)
goto err_free_workq;
spin_lock_init(&bn->stats_lock);
netdev->request_ops_lock = true;
rc = register_netdev(netdev);
if (rc) {
dev_err(bd->dev, "Register netdev failed rc: %d\n", rc);
goto err_netdev;
goto err_free_port_stats;
}
return 0;
err_free_port_stats:
bnge_free_port_stats(bn);
err_free_workq:
destroy_workqueue(bn->bnge_pf_wq);
err_netdev:
free_netdev(netdev);
return rc;
@ -2802,8 +3461,19 @@ int bnge_netdev_alloc(struct bnge_dev *bd, int max_irqs)
void bnge_netdev_free(struct bnge_dev *bd)
{
struct net_device *netdev = bd->netdev;
struct bnge_net *bn;
bn = netdev_priv(netdev);
unregister_netdev(netdev);
timer_shutdown_sync(&bn->timer);
cancel_work_sync(&bn->sp_task);
bn->sp_event = 0;
destroy_workqueue(bn->bnge_pf_wq);
bnge_free_port_stats(bn);
free_netdev(netdev);
bd->netdev = NULL;
}

View File

@ -7,8 +7,11 @@
#include <linux/bnge/hsi.h>
#include <linux/io-64-nonatomic-lo-hi.h>
#include <linux/refcount.h>
#include <linux/u64_stats_sync.h>
#include <net/netdev_queues.h>
#include "bnge_db.h"
#include "bnge_hw_def.h"
#include "bnge_link.h"
struct tx_bd {
__le32 tx_bd_len_flags_type;
@ -223,6 +226,62 @@ struct bnge_tpa_info {
#define BNGE_NQ_HDL_IDX(hdl) ((hdl) & BNGE_NQ_HDL_IDX_MASK)
#define BNGE_NQ_HDL_TYPE(hdl) (((hdl) & BNGE_NQ_HDL_TYPE_MASK) >> \
BNGE_NQ_HDL_TYPE_SHIFT)
#define BNGE_GET_RING_STATS64(sw, counter) \
(*((sw) + offsetof(struct ctx_hw_stats, counter) / 8))
#define BNGE_GET_RX_PORT_STATS64(sw, counter) \
(*((sw) + offsetof(struct rx_port_stats, counter) / 8))
#define BNGE_GET_TX_PORT_STATS64(sw, counter) \
(*((sw) + offsetof(struct tx_port_stats, counter) / 8))
#define BNGE_PORT_STATS_SIZE \
(sizeof(struct rx_port_stats) + sizeof(struct tx_port_stats) + 1024)
#define BNGE_TX_PORT_STATS_BYTE_OFFSET \
(sizeof(struct rx_port_stats) + 512)
#define BNGE_RX_STATS_OFFSET(counter) \
(offsetof(struct rx_port_stats, counter) / 8)
#define BNGE_TX_STATS_OFFSET(counter) \
((offsetof(struct tx_port_stats, counter) + \
BNGE_TX_PORT_STATS_BYTE_OFFSET) / 8)
#define BNGE_RX_STATS_EXT_OFFSET(counter) \
(offsetof(struct rx_port_stats_ext, counter) / 8)
#define BNGE_TX_STATS_EXT_OFFSET(counter) \
(offsetof(struct tx_port_stats_ext, counter) / 8)
struct bnge_stats_mem {
u64 *sw_stats;
u64 *hw_masks;
void *hw_stats;
dma_addr_t hw_stats_map;
u32 len;
struct u64_stats_sync syncp;
};
enum bnge_net_state {
BNGE_STATE_NAPI_DISABLED,
BNGE_STATE_STATS_ENABLE,
};
#define BNGE_TIMER_INTERVAL HZ
enum bnge_net_flag {
BNGE_FLAG_PORT_STATS = BIT(0),
BNGE_FLAG_PORT_STATS_EXT = BIT(1),
};
enum bnge_sp_event {
BNGE_LINK_CHNG_SP_EVENT,
BNGE_LINK_SPEED_CHNG_SP_EVENT,
BNGE_LINK_CFG_CHANGE_SP_EVENT,
BNGE_UPDATE_PHY_SP_EVENT,
BNGE_PERIODIC_STATS_SP_EVENT,
};
struct bnge_net {
struct bnge_dev *bd;
@ -281,13 +340,36 @@ struct bnge_net {
u32 stats_coal_ticks;
unsigned long state;
#define BNGE_STATE_NAPI_DISABLED 0
u32 msg_enable;
u16 max_tpa;
__be16 vxlan_port;
__be16 nge_port;
__be16 vxlan_gpe_port;
unsigned int current_interval;
struct timer_list timer;
struct workqueue_struct *bnge_pf_wq;
struct work_struct sp_task;
unsigned long sp_event;
struct bnge_ethtool_link_info eth_link_info;
u64 flags;
struct bnge_stats_mem port_stats;
struct bnge_stats_mem rx_port_stats_ext;
struct bnge_stats_mem tx_port_stats_ext;
u16 fw_rx_stats_ext_size;
u16 fw_tx_stats_ext_size;
struct netdev_queue_stats_rx rxq_prv_stats;
struct netdev_queue_stats_tx txq_prv_stats;
struct rtnl_link_stats64 prv_stats64;
spinlock_t stats_lock;
u8 pri2cos_idx[8];
bool pri2cos_valid;
};
#define BNGE_DEFAULT_RX_RING_SIZE 511
@ -353,14 +435,6 @@ void bnge_set_ring_params(struct bnge_dev *bd);
bnge_writeq(bd, (db)->db_key64 | DBR_TYPE_NQ_ARM | \
DB_RING_IDX(db, idx), (db)->doorbell)
struct bnge_stats_mem {
u64 *sw_stats;
u64 *hw_masks;
void *hw_stats;
dma_addr_t hw_stats_map;
int len;
};
struct nqe_cn {
__le16 type;
#define NQ_CN_TYPE_MASK 0x3fUL
@ -566,4 +640,6 @@ u8 *__bnge_alloc_rx_frag(struct bnge_net *bn, dma_addr_t *mapping,
struct bnge_rx_ring_info *rxr, gfp_t gfp);
int bnge_alloc_rx_netmem(struct bnge_net *bn, struct bnge_rx_ring_info *rxr,
u16 prod, gfp_t gfp);
void __bnge_queue_sp_work(struct bnge_net *bn);
void bnge_copy_hw_masks(u64 *mask_arr, __le64 *hw_mask_arr, int count);
#endif /* _BNGE_NETDEV_H_ */

View File

@ -1128,6 +1128,29 @@ static void __bnge_poll_work_done(struct bnge_net *bn, struct bnge_napi *bnapi,
}
}
static void bnge_async_event_process(struct bnge_net *bn,
struct hwrm_async_event_cmpl *cmpl)
{
u16 event_id = le16_to_cpu(cmpl->event_id);
u32 data1 = le32_to_cpu(cmpl->event_data1);
u32 data2 = le32_to_cpu(cmpl->event_data2);
netdev_dbg(bn->netdev, "hwrm event 0x%x {0x%x, 0x%x}\n",
event_id, data1, data2);
switch (event_id) {
case ASYNC_EVENT_CMPL_EVENT_ID_LINK_SPEED_CFG_CHANGE:
case ASYNC_EVENT_CMPL_EVENT_ID_LINK_SPEED_CHANGE:
case ASYNC_EVENT_CMPL_EVENT_ID_PORT_PHY_CFG_CHANGE:
case ASYNC_EVENT_CMPL_EVENT_ID_LINK_STATUS_CHANGE:
bnge_link_async_event_process(bn, event_id);
break;
default:
return;
}
__bnge_queue_sp_work(bn);
}
static void
bnge_hwrm_update_token(struct bnge_dev *bd, u16 seq_id,
enum bnge_hwrm_wait_state state)
@ -1146,7 +1169,7 @@ bnge_hwrm_update_token(struct bnge_dev *bd, u16 seq_id,
dev_err(bd->dev, "Invalid hwrm seq id %d\n", seq_id);
}
static int bnge_hwrm_handler(struct bnge_dev *bd, struct tx_cmp *txcmp)
static int bnge_hwrm_handler(struct bnge_net *bn, struct tx_cmp *txcmp)
{
struct hwrm_cmpl *h_cmpl = (struct hwrm_cmpl *)txcmp;
u16 cmpl_type = TX_CMP_TYPE(txcmp), seq_id;
@ -1154,10 +1177,14 @@ static int bnge_hwrm_handler(struct bnge_dev *bd, struct tx_cmp *txcmp)
switch (cmpl_type) {
case CMPL_BASE_TYPE_HWRM_DONE:
seq_id = le16_to_cpu(h_cmpl->sequence_id);
bnge_hwrm_update_token(bd, seq_id, BNGE_HWRM_COMPLETE);
bnge_hwrm_update_token(bn->bd, seq_id, BNGE_HWRM_COMPLETE);
break;
case CMPL_BASE_TYPE_HWRM_ASYNC_EVENT:
bnge_async_event_process(bn,
(struct hwrm_async_event_cmpl *)txcmp);
break;
default:
break;
}
@ -1235,7 +1262,7 @@ static int __bnge_poll_work(struct bnge_net *bn, struct bnge_cp_ring_info *cpr,
} else if (unlikely(cmp_type == CMPL_BASE_TYPE_HWRM_DONE ||
cmp_type == CMPL_BASE_TYPE_HWRM_FWD_REQ ||
cmp_type == CMPL_BA_TY_HWRM_ASY_EVT)) {
bnge_hwrm_handler(bn->bd, txcmp);
bnge_hwrm_handler(bn, txcmp);
}
raw_cons = NEXT_RAW_CMP(raw_cons);
@ -1355,7 +1382,7 @@ int bnge_napi_poll(struct napi_struct *napi, int budget)
budget - work_done);
nqr->has_more_work |= cpr->has_more_work;
} else {
bnge_hwrm_handler(bn->bd, (struct tx_cmp *)nqcmp);
bnge_hwrm_handler(bn, (struct tx_cmp *)nqcmp);
}
raw_cons = NEXT_RAW_CMP(raw_cons);
}