airoha_fe_set(eth, REG_GDM_FWD_CFG(AIROHA_GDM3_IDX), GDM_PAD_EN_MASK);
airoha_fe_set(eth, REG_GDM_FWD_CFG(AIROHA_GDM4_IDX), GDM_PAD_EN_MASK);
+ /* Enable split for MIB counters for GDM3 and GDM4 */
+ airoha_fe_set(eth, REG_FE_GDM_MIB_CFG(AIROHA_GDM3_IDX),
+ FE_GDM_TX_MIB_SPLIT_EN_MASK |
+ FE_GDM_RX_MIB_SPLIT_EN_MASK);
+ airoha_fe_set(eth, REG_FE_GDM_MIB_CFG(AIROHA_GDM4_IDX),
+ FE_GDM_TX_MIB_SPLIT_EN_MASK |
+ FE_GDM_RX_MIB_SPLIT_EN_MASK);
+
airoha_fe_crsn_qsel_init(eth);
airoha_fe_clear(eth, REG_FE_CPORT_CFG, FE_CPORT_QUEUE_XFC_MASK);
}
}
-static void airoha_update_hw_stats(struct airoha_gdm_dev *dev)
+static void airoha_dev_get_hw_stats(struct airoha_gdm_dev *dev)
{
struct airoha_gdm_port *port = dev->port;
struct airoha_eth *eth = dev->eth;
u32 val, i = 0;
- spin_lock(&port->stats.lock);
- u64_stats_update_begin(&port->stats.syncp);
+ /* Read relevant MIB for GDM with multiple port attached */
+ if (port->id == AIROHA_GDM3_IDX || port->id == AIROHA_GDM4_IDX)
+ airoha_fe_rmw(eth, REG_FE_GDM_MIB_CFG(port->id),
+ FE_TX_MIB_ID_MASK | FE_RX_MIB_ID_MASK,
+ FIELD_PREP(FE_TX_MIB_ID_MASK, dev->nbq) |
+ FIELD_PREP(FE_RX_MIB_ID_MASK, dev->nbq));
+
+ u64_stats_update_begin(&dev->stats.syncp);
/* TX */
val = airoha_fe_rr(eth, REG_FE_GDM_TX_OK_PKT_CNT_H(port->id));
- port->stats.tx_ok_pkts += ((u64)val << 32);
+ dev->stats.tx_ok_pkts += ((u64)val << 32);
val = airoha_fe_rr(eth, REG_FE_GDM_TX_OK_PKT_CNT_L(port->id));
- port->stats.tx_ok_pkts += val;
+ dev->stats.tx_ok_pkts += val;
val = airoha_fe_rr(eth, REG_FE_GDM_TX_OK_BYTE_CNT_H(port->id));
- port->stats.tx_ok_bytes += ((u64)val << 32);
+ dev->stats.tx_ok_bytes += ((u64)val << 32);
val = airoha_fe_rr(eth, REG_FE_GDM_TX_OK_BYTE_CNT_L(port->id));
- port->stats.tx_ok_bytes += val;
+ dev->stats.tx_ok_bytes += val;
val = airoha_fe_rr(eth, REG_FE_GDM_TX_ETH_DROP_CNT(port->id));
- port->stats.tx_drops += val;
+ dev->stats.tx_drops += val;
val = airoha_fe_rr(eth, REG_FE_GDM_TX_ETH_BC_CNT(port->id));
- port->stats.tx_broadcast += val;
+ dev->stats.tx_broadcast += val;
val = airoha_fe_rr(eth, REG_FE_GDM_TX_ETH_MC_CNT(port->id));
- port->stats.tx_multicast += val;
+ dev->stats.tx_multicast += val;
val = airoha_fe_rr(eth, REG_FE_GDM_TX_ETH_RUNT_CNT(port->id));
- port->stats.tx_len[i] += val;
+ dev->stats.tx_len[i] += val;
val = airoha_fe_rr(eth, REG_FE_GDM_TX_ETH_E64_CNT_H(port->id));
- port->stats.tx_len[i] += ((u64)val << 32);
+ dev->stats.tx_len[i] += ((u64)val << 32);
val = airoha_fe_rr(eth, REG_FE_GDM_TX_ETH_E64_CNT_L(port->id));
- port->stats.tx_len[i++] += val;
+ dev->stats.tx_len[i++] += val;
val = airoha_fe_rr(eth, REG_FE_GDM_TX_ETH_L64_CNT_H(port->id));
- port->stats.tx_len[i] += ((u64)val << 32);
+ dev->stats.tx_len[i] += ((u64)val << 32);
val = airoha_fe_rr(eth, REG_FE_GDM_TX_ETH_L64_CNT_L(port->id));
- port->stats.tx_len[i++] += val;
+ dev->stats.tx_len[i++] += val;
val = airoha_fe_rr(eth, REG_FE_GDM_TX_ETH_L127_CNT_H(port->id));
- port->stats.tx_len[i] += ((u64)val << 32);
+ dev->stats.tx_len[i] += ((u64)val << 32);
val = airoha_fe_rr(eth, REG_FE_GDM_TX_ETH_L127_CNT_L(port->id));
- port->stats.tx_len[i++] += val;
+ dev->stats.tx_len[i++] += val;
val = airoha_fe_rr(eth, REG_FE_GDM_TX_ETH_L255_CNT_H(port->id));
- port->stats.tx_len[i] += ((u64)val << 32);
+ dev->stats.tx_len[i] += ((u64)val << 32);
val = airoha_fe_rr(eth, REG_FE_GDM_TX_ETH_L255_CNT_L(port->id));
- port->stats.tx_len[i++] += val;
+ dev->stats.tx_len[i++] += val;
val = airoha_fe_rr(eth, REG_FE_GDM_TX_ETH_L511_CNT_H(port->id));
- port->stats.tx_len[i] += ((u64)val << 32);
+ dev->stats.tx_len[i] += ((u64)val << 32);
val = airoha_fe_rr(eth, REG_FE_GDM_TX_ETH_L511_CNT_L(port->id));
- port->stats.tx_len[i++] += val;
+ dev->stats.tx_len[i++] += val;
val = airoha_fe_rr(eth, REG_FE_GDM_TX_ETH_L1023_CNT_H(port->id));
- port->stats.tx_len[i] += ((u64)val << 32);
+ dev->stats.tx_len[i] += ((u64)val << 32);
val = airoha_fe_rr(eth, REG_FE_GDM_TX_ETH_L1023_CNT_L(port->id));
- port->stats.tx_len[i++] += val;
+ dev->stats.tx_len[i++] += val;
val = airoha_fe_rr(eth, REG_FE_GDM_TX_ETH_LONG_CNT(port->id));
- port->stats.tx_len[i++] += val;
+ dev->stats.tx_len[i++] += val;
/* RX */
val = airoha_fe_rr(eth, REG_FE_GDM_RX_OK_PKT_CNT_H(port->id));
- port->stats.rx_ok_pkts += ((u64)val << 32);
+ dev->stats.rx_ok_pkts += ((u64)val << 32);
val = airoha_fe_rr(eth, REG_FE_GDM_RX_OK_PKT_CNT_L(port->id));
- port->stats.rx_ok_pkts += val;
+ dev->stats.rx_ok_pkts += val;
val = airoha_fe_rr(eth, REG_FE_GDM_RX_OK_BYTE_CNT_H(port->id));
- port->stats.rx_ok_bytes += ((u64)val << 32);
+ dev->stats.rx_ok_bytes += ((u64)val << 32);
val = airoha_fe_rr(eth, REG_FE_GDM_RX_OK_BYTE_CNT_L(port->id));
- port->stats.rx_ok_bytes += val;
+ dev->stats.rx_ok_bytes += val;
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_DROP_CNT(port->id));
- port->stats.rx_drops += val;
+ dev->stats.rx_drops += val;
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_BC_CNT(port->id));
- port->stats.rx_broadcast += val;
+ dev->stats.rx_broadcast += val;
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_MC_CNT(port->id));
- port->stats.rx_multicast += val;
+ dev->stats.rx_multicast += val;
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ERROR_DROP_CNT(port->id));
- port->stats.rx_errors += val;
+ dev->stats.rx_errors += val;
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_CRC_ERR_CNT(port->id));
- port->stats.rx_crc_error += val;
+ dev->stats.rx_crc_error += val;
val = airoha_fe_rr(eth, REG_FE_GDM_RX_OVERFLOW_DROP_CNT(port->id));
- port->stats.rx_over_errors += val;
+ dev->stats.rx_over_errors += val;
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_FRAG_CNT(port->id));
- port->stats.rx_fragment += val;
+ dev->stats.rx_fragment += val;
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_JABBER_CNT(port->id));
- port->stats.rx_jabber += val;
+ dev->stats.rx_jabber += val;
i = 0;
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_RUNT_CNT(port->id));
- port->stats.rx_len[i] += val;
+ dev->stats.rx_len[i] += val;
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_E64_CNT_H(port->id));
- port->stats.rx_len[i] += ((u64)val << 32);
+ dev->stats.rx_len[i] += ((u64)val << 32);
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_E64_CNT_L(port->id));
- port->stats.rx_len[i++] += val;
+ dev->stats.rx_len[i++] += val;
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_L64_CNT_H(port->id));
- port->stats.rx_len[i] += ((u64)val << 32);
+ dev->stats.rx_len[i] += ((u64)val << 32);
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_L64_CNT_L(port->id));
- port->stats.rx_len[i++] += val;
+ dev->stats.rx_len[i++] += val;
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_L127_CNT_H(port->id));
- port->stats.rx_len[i] += ((u64)val << 32);
+ dev->stats.rx_len[i] += ((u64)val << 32);
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_L127_CNT_L(port->id));
- port->stats.rx_len[i++] += val;
+ dev->stats.rx_len[i++] += val;
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_L255_CNT_H(port->id));
- port->stats.rx_len[i] += ((u64)val << 32);
+ dev->stats.rx_len[i] += ((u64)val << 32);
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_L255_CNT_L(port->id));
- port->stats.rx_len[i++] += val;
+ dev->stats.rx_len[i++] += val;
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_L511_CNT_H(port->id));
- port->stats.rx_len[i] += ((u64)val << 32);
+ dev->stats.rx_len[i] += ((u64)val << 32);
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_L511_CNT_L(port->id));
- port->stats.rx_len[i++] += val;
+ dev->stats.rx_len[i++] += val;
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_L1023_CNT_H(port->id));
- port->stats.rx_len[i] += ((u64)val << 32);
+ dev->stats.rx_len[i] += ((u64)val << 32);
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_L1023_CNT_L(port->id));
- port->stats.rx_len[i++] += val;
+ dev->stats.rx_len[i++] += val;
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_LONG_CNT(port->id));
- port->stats.rx_len[i++] += val;
+ dev->stats.rx_len[i++] += val;
+
+ u64_stats_update_end(&dev->stats.syncp);
+}
- /* reset mib counters */
- airoha_fe_set(eth, REG_FE_GDM_MIB_CLEAR(port->id),
+static void airoha_update_hw_stats(struct airoha_gdm_dev *dev)
+{
+ struct airoha_gdm_port *port = dev->port;
+ int i;
+
+ spin_lock(&port->stats_lock);
+
+ for (i = 0; i < ARRAY_SIZE(port->devs); i++) {
+ if (port->devs[i])
+ airoha_dev_get_hw_stats(port->devs[i]);
+ }
+
+ /* Reset MIB counters */
+ airoha_fe_set(dev->eth, REG_FE_GDM_MIB_CLEAR(port->id),
FE_GDM_MIB_RX_CLEAR_MASK | FE_GDM_MIB_TX_CLEAR_MASK);
- u64_stats_update_end(&port->stats.syncp);
- spin_unlock(&port->stats.lock);
+ spin_unlock(&port->stats_lock);
}
static int airoha_dev_open(struct net_device *netdev)
struct rtnl_link_stats64 *storage)
{
struct airoha_gdm_dev *dev = netdev_priv(netdev);
- struct airoha_gdm_port *port = dev->port;
unsigned int start;
airoha_update_hw_stats(dev);
do {
- start = u64_stats_fetch_begin(&port->stats.syncp);
- storage->rx_packets = port->stats.rx_ok_pkts;
- storage->tx_packets = port->stats.tx_ok_pkts;
- storage->rx_bytes = port->stats.rx_ok_bytes;
- storage->tx_bytes = port->stats.tx_ok_bytes;
- storage->multicast = port->stats.rx_multicast;
- storage->rx_errors = port->stats.rx_errors;
- storage->rx_dropped = port->stats.rx_drops;
- storage->tx_dropped = port->stats.tx_drops;
- storage->rx_crc_errors = port->stats.rx_crc_error;
- storage->rx_over_errors = port->stats.rx_over_errors;
- } while (u64_stats_fetch_retry(&port->stats.syncp, start));
+ start = u64_stats_fetch_begin(&dev->stats.syncp);
+ storage->rx_packets = dev->stats.rx_ok_pkts;
+ storage->tx_packets = dev->stats.tx_ok_pkts;
+ storage->rx_bytes = dev->stats.rx_ok_bytes;
+ storage->tx_bytes = dev->stats.tx_ok_bytes;
+ storage->multicast = dev->stats.rx_multicast;
+ storage->rx_errors = dev->stats.rx_errors;
+ storage->rx_dropped = dev->stats.rx_drops;
+ storage->tx_dropped = dev->stats.tx_drops;
+ storage->rx_crc_errors = dev->stats.rx_crc_error;
+ storage->rx_over_errors = dev->stats.rx_over_errors;
+ } while (u64_stats_fetch_retry(&dev->stats.syncp, start));
}
static int airoha_dev_change_mtu(struct net_device *netdev, int mtu)
struct ethtool_eth_mac_stats *stats)
{
struct airoha_gdm_dev *dev = netdev_priv(netdev);
- struct airoha_gdm_port *port = dev->port;
unsigned int start;
airoha_update_hw_stats(dev);
do {
- start = u64_stats_fetch_begin(&port->stats.syncp);
- stats->FramesTransmittedOK = port->stats.tx_ok_pkts;
- stats->OctetsTransmittedOK = port->stats.tx_ok_bytes;
- stats->MulticastFramesXmittedOK = port->stats.tx_multicast;
- stats->BroadcastFramesXmittedOK = port->stats.tx_broadcast;
- stats->FramesReceivedOK = port->stats.rx_ok_pkts;
- stats->OctetsReceivedOK = port->stats.rx_ok_bytes;
- stats->BroadcastFramesReceivedOK = port->stats.rx_broadcast;
- } while (u64_stats_fetch_retry(&port->stats.syncp, start));
+ start = u64_stats_fetch_begin(&dev->stats.syncp);
+ stats->FramesTransmittedOK = dev->stats.tx_ok_pkts;
+ stats->OctetsTransmittedOK = dev->stats.tx_ok_bytes;
+ stats->MulticastFramesXmittedOK = dev->stats.tx_multicast;
+ stats->BroadcastFramesXmittedOK = dev->stats.tx_broadcast;
+ stats->FramesReceivedOK = dev->stats.rx_ok_pkts;
+ stats->OctetsReceivedOK = dev->stats.rx_ok_bytes;
+ stats->BroadcastFramesReceivedOK = dev->stats.rx_broadcast;
+ } while (u64_stats_fetch_retry(&dev->stats.syncp, start));
}
static const struct ethtool_rmon_hist_range airoha_ethtool_rmon_ranges[] = {
const struct ethtool_rmon_hist_range **ranges)
{
struct airoha_gdm_dev *dev = netdev_priv(netdev);
- struct airoha_gdm_port *port = dev->port;
- struct airoha_hw_stats *hw_stats = &port->stats;
+ struct airoha_hw_stats *hw_stats = &dev->stats;
unsigned int start;
BUILD_BUG_ON(ARRAY_SIZE(airoha_ethtool_rmon_ranges) !=
do {
int i;
- start = u64_stats_fetch_begin(&port->stats.syncp);
+ start = u64_stats_fetch_begin(&dev->stats.syncp);
stats->fragments = hw_stats->rx_fragment;
stats->jabbers = hw_stats->rx_jabber;
for (i = 0; i < ARRAY_SIZE(airoha_ethtool_rmon_ranges) - 1;
stats->hist[i] = hw_stats->rx_len[i];
stats->hist_tx[i] = hw_stats->tx_len[i];
}
- } while (u64_stats_fetch_retry(&port->stats.syncp, start));
+ } while (u64_stats_fetch_retry(&dev->stats.syncp, start));
}
static int airoha_qdma_set_chan_tx_sched(struct net_device *netdev,
netdev->dev.of_node = of_node_get(np);
dev = netdev_priv(netdev);
+ u64_stats_init(&dev->stats.syncp);
dev->port = port;
dev->eth = eth;
dev->nbq = nbq;
if (!port)
return -ENOMEM;
- u64_stats_init(&port->stats.syncp);
- spin_lock_init(&port->stats.lock);
port->id = id;
+ spin_lock_init(&port->stats_lock);
eth->ports[p] = port;
err = airoha_metadata_dst_alloc(port);