|
@@ -284,6 +284,7 @@ static const struct bcm_sysport_stats bcm_sysport_gstrings_stats[] = {
|
|
|
STAT_MIB_SOFT("alloc_rx_buff_failed", mib.alloc_rx_buff_failed),
|
|
|
STAT_MIB_SOFT("rx_dma_failed", mib.rx_dma_failed),
|
|
|
STAT_MIB_SOFT("tx_dma_failed", mib.tx_dma_failed),
|
|
|
+ /* Per TX-queue statistics are dynamically appended */
|
|
|
};
|
|
|
|
|
|
#define BCM_SYSPORT_STATS_LEN ARRAY_SIZE(bcm_sysport_gstrings_stats)
|
|
@@ -338,7 +339,8 @@ static int bcm_sysport_get_sset_count(struct net_device *dev, int string_set)
|
|
|
continue;
|
|
|
j++;
|
|
|
}
|
|
|
- return j;
|
|
|
+ /* Include per-queue statistics */
|
|
|
+ return j + dev->num_tx_queues * NUM_SYSPORT_TXQ_STAT;
|
|
|
default:
|
|
|
return -EOPNOTSUPP;
|
|
|
}
|
|
@@ -349,6 +351,7 @@ static void bcm_sysport_get_strings(struct net_device *dev,
|
|
|
{
|
|
|
struct bcm_sysport_priv *priv = netdev_priv(dev);
|
|
|
const struct bcm_sysport_stats *s;
|
|
|
+ char buf[128];
|
|
|
int i, j;
|
|
|
|
|
|
switch (stringset) {
|
|
@@ -363,6 +366,18 @@ static void bcm_sysport_get_strings(struct net_device *dev,
|
|
|
ETH_GSTRING_LEN);
|
|
|
j++;
|
|
|
}
|
|
|
+
|
|
|
+ for (i = 0; i < dev->num_tx_queues; i++) {
|
|
|
+ snprintf(buf, sizeof(buf), "txq%d_packets", i);
|
|
|
+ memcpy(data + j * ETH_GSTRING_LEN, buf,
|
|
|
+ ETH_GSTRING_LEN);
|
|
|
+ j++;
|
|
|
+
|
|
|
+ snprintf(buf, sizeof(buf), "txq%d_bytes", i);
|
|
|
+ memcpy(data + j * ETH_GSTRING_LEN, buf,
|
|
|
+ ETH_GSTRING_LEN);
|
|
|
+ j++;
|
|
|
+ }
|
|
|
break;
|
|
|
default:
|
|
|
break;
|
|
@@ -418,6 +433,7 @@ static void bcm_sysport_get_stats(struct net_device *dev,
|
|
|
struct ethtool_stats *stats, u64 *data)
|
|
|
{
|
|
|
struct bcm_sysport_priv *priv = netdev_priv(dev);
|
|
|
+ struct bcm_sysport_tx_ring *ring;
|
|
|
int i, j;
|
|
|
|
|
|
if (netif_running(dev))
|
|
@@ -436,6 +452,22 @@ static void bcm_sysport_get_stats(struct net_device *dev,
|
|
|
data[j] = *(unsigned long *)p;
|
|
|
j++;
|
|
|
}
|
|
|
+
|
|
|
+ /* For SYSTEMPORT Lite since we have holes in our statistics, j would
|
|
|
+ * be equal to BCM_SYSPORT_STATS_LEN at the end of the loop, but it
|
|
|
+ * needs to point to how many total statistics we have minus the
|
|
|
+ * number of per TX queue statistics
|
|
|
+ */
|
|
|
+ j = bcm_sysport_get_sset_count(dev, ETH_SS_STATS) -
|
|
|
+ dev->num_tx_queues * NUM_SYSPORT_TXQ_STAT;
|
|
|
+
|
|
|
+ for (i = 0; i < dev->num_tx_queues; i++) {
|
|
|
+ ring = &priv->tx_rings[i];
|
|
|
+ data[j] = ring->packets;
|
|
|
+ j++;
|
|
|
+ data[j] = ring->bytes;
|
|
|
+ j++;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
static void bcm_sysport_get_wol(struct net_device *dev,
|
|
@@ -637,6 +669,9 @@ static unsigned int bcm_sysport_desc_rx(struct bcm_sysport_priv *priv,
|
|
|
u16 len, status;
|
|
|
struct bcm_rsb *rsb;
|
|
|
|
|
|
+ /* Clear status before servicing to reduce spurious interrupts */
|
|
|
+ intrl2_0_writel(priv, INTRL2_0_RDMA_MBDONE, INTRL2_CPU_CLEAR);
|
|
|
+
|
|
|
/* Determine how much we should process since last call, SYSTEMPORT Lite
|
|
|
* groups the producer and consumer indexes into the same 32-bit
|
|
|
* which we access using RDMA_CONS_INDEX
|
|
@@ -647,11 +682,7 @@ static unsigned int bcm_sysport_desc_rx(struct bcm_sysport_priv *priv,
|
|
|
p_index = rdma_readl(priv, RDMA_CONS_INDEX);
|
|
|
p_index &= RDMA_PROD_INDEX_MASK;
|
|
|
|
|
|
- if (p_index < priv->rx_c_index)
|
|
|
- to_process = (RDMA_CONS_INDEX_MASK + 1) -
|
|
|
- priv->rx_c_index + p_index;
|
|
|
- else
|
|
|
- to_process = p_index - priv->rx_c_index;
|
|
|
+ to_process = (p_index - priv->rx_c_index) & RDMA_CONS_INDEX_MASK;
|
|
|
|
|
|
netif_dbg(priv, rx_status, ndev,
|
|
|
"p_index=%d rx_c_index=%d to_process=%d\n",
|
|
@@ -746,26 +777,26 @@ next:
|
|
|
return processed;
|
|
|
}
|
|
|
|
|
|
-static void bcm_sysport_tx_reclaim_one(struct bcm_sysport_priv *priv,
|
|
|
+static void bcm_sysport_tx_reclaim_one(struct bcm_sysport_tx_ring *ring,
|
|
|
struct bcm_sysport_cb *cb,
|
|
|
unsigned int *bytes_compl,
|
|
|
unsigned int *pkts_compl)
|
|
|
{
|
|
|
+ struct bcm_sysport_priv *priv = ring->priv;
|
|
|
struct device *kdev = &priv->pdev->dev;
|
|
|
- struct net_device *ndev = priv->netdev;
|
|
|
|
|
|
if (cb->skb) {
|
|
|
- ndev->stats.tx_bytes += cb->skb->len;
|
|
|
+ ring->bytes += cb->skb->len;
|
|
|
*bytes_compl += cb->skb->len;
|
|
|
dma_unmap_single(kdev, dma_unmap_addr(cb, dma_addr),
|
|
|
dma_unmap_len(cb, dma_len),
|
|
|
DMA_TO_DEVICE);
|
|
|
- ndev->stats.tx_packets++;
|
|
|
+ ring->packets++;
|
|
|
(*pkts_compl)++;
|
|
|
bcm_sysport_free_cb(cb);
|
|
|
/* SKB fragment */
|
|
|
} else if (dma_unmap_addr(cb, dma_addr)) {
|
|
|
- ndev->stats.tx_bytes += dma_unmap_len(cb, dma_len);
|
|
|
+ ring->bytes += dma_unmap_len(cb, dma_len);
|
|
|
dma_unmap_page(kdev, dma_unmap_addr(cb, dma_addr),
|
|
|
dma_unmap_len(cb, dma_len), DMA_TO_DEVICE);
|
|
|
dma_unmap_addr_set(cb, dma_addr, 0);
|
|
@@ -782,6 +813,13 @@ static unsigned int __bcm_sysport_tx_reclaim(struct bcm_sysport_priv *priv,
|
|
|
struct bcm_sysport_cb *cb;
|
|
|
u32 hw_ind;
|
|
|
|
|
|
+ /* Clear status before servicing to reduce spurious interrupts */
|
|
|
+ if (!ring->priv->is_lite)
|
|
|
+ intrl2_1_writel(ring->priv, BIT(ring->index), INTRL2_CPU_CLEAR);
|
|
|
+ else
|
|
|
+ intrl2_0_writel(ring->priv, BIT(ring->index +
|
|
|
+ INTRL2_0_TDMA_MBDONE_SHIFT), INTRL2_CPU_CLEAR);
|
|
|
+
|
|
|
/* Compute how many descriptors have been processed since last call */
|
|
|
hw_ind = tdma_readl(priv, TDMA_DESC_RING_PROD_CONS_INDEX(ring->index));
|
|
|
c_index = (hw_ind >> RING_CONS_INDEX_SHIFT) & RING_CONS_INDEX_MASK;
|
|
@@ -803,7 +841,7 @@ static unsigned int __bcm_sysport_tx_reclaim(struct bcm_sysport_priv *priv,
|
|
|
|
|
|
while (last_tx_cn-- > 0) {
|
|
|
cb = ring->cbs + last_c_index;
|
|
|
- bcm_sysport_tx_reclaim_one(priv, cb, &bytes_compl, &pkts_compl);
|
|
|
+ bcm_sysport_tx_reclaim_one(ring, cb, &bytes_compl, &pkts_compl);
|
|
|
|
|
|
ring->desc_count++;
|
|
|
last_c_index++;
|
|
@@ -1632,6 +1670,24 @@ static int bcm_sysport_change_mac(struct net_device *dev, void *p)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static struct net_device_stats *bcm_sysport_get_nstats(struct net_device *dev)
|
|
|
+{
|
|
|
+ struct bcm_sysport_priv *priv = netdev_priv(dev);
|
|
|
+ unsigned long tx_bytes = 0, tx_packets = 0;
|
|
|
+ struct bcm_sysport_tx_ring *ring;
|
|
|
+ unsigned int q;
|
|
|
+
|
|
|
+ for (q = 0; q < dev->num_tx_queues; q++) {
|
|
|
+ ring = &priv->tx_rings[q];
|
|
|
+ tx_bytes += ring->bytes;
|
|
|
+ tx_packets += ring->packets;
|
|
|
+ }
|
|
|
+
|
|
|
+ dev->stats.tx_bytes = tx_bytes;
|
|
|
+ dev->stats.tx_packets = tx_packets;
|
|
|
+ return &dev->stats;
|
|
|
+}
|
|
|
+
|
|
|
static void bcm_sysport_netif_start(struct net_device *dev)
|
|
|
{
|
|
|
struct bcm_sysport_priv *priv = netdev_priv(dev);
|
|
@@ -1893,6 +1949,7 @@ static const struct net_device_ops bcm_sysport_netdev_ops = {
|
|
|
#ifdef CONFIG_NET_POLL_CONTROLLER
|
|
|
.ndo_poll_controller = bcm_sysport_poll_controller,
|
|
|
#endif
|
|
|
+ .ndo_get_stats = bcm_sysport_get_nstats,
|
|
|
};
|
|
|
|
|
|
#define REV_FMT "v%2x.%02x"
|