Commit 8b512927 authored by Stephen Hemminger's avatar Stephen Hemminger Committed by Jeff Garzik

[PATCH] 8139cp: allocate statistics space only when needed

Don't crash if ethtool statistics are requested and device is down.
Fix is to allocate pci space for statistics only when needed.
Signed-off-by: default avatarStephen Hemminger <shemminger@osdl.org>
Signed-off-by: default avatarJeff Garzik <jgarzik@pobox.com>
parent ed4b9f80
...@@ -353,8 +353,6 @@ struct cp_private { ...@@ -353,8 +353,6 @@ struct cp_private {
struct net_device_stats net_stats; struct net_device_stats net_stats;
struct cp_extra_stats cp_stats; struct cp_extra_stats cp_stats;
struct cp_dma_stats *nic_stats;
dma_addr_t nic_stats_dma;
unsigned rx_tail ____cacheline_aligned; unsigned rx_tail ____cacheline_aligned;
struct cp_desc *rx_ring; struct cp_desc *rx_ring;
...@@ -1143,10 +1141,6 @@ static int cp_alloc_rings (struct cp_private *cp) ...@@ -1143,10 +1141,6 @@ static int cp_alloc_rings (struct cp_private *cp)
cp->rx_ring = mem; cp->rx_ring = mem;
cp->tx_ring = &cp->rx_ring[CP_RX_RING_SIZE]; cp->tx_ring = &cp->rx_ring[CP_RX_RING_SIZE];
mem += (CP_RING_BYTES - CP_STATS_SIZE);
cp->nic_stats = mem;
cp->nic_stats_dma = cp->ring_dma + (CP_RING_BYTES - CP_STATS_SIZE);
return cp_init_rings(cp); return cp_init_rings(cp);
} }
...@@ -1187,7 +1181,6 @@ static void cp_free_rings (struct cp_private *cp) ...@@ -1187,7 +1181,6 @@ static void cp_free_rings (struct cp_private *cp)
pci_free_consistent(cp->pdev, CP_RING_BYTES, cp->rx_ring, cp->ring_dma); pci_free_consistent(cp->pdev, CP_RING_BYTES, cp->rx_ring, cp->ring_dma);
cp->rx_ring = NULL; cp->rx_ring = NULL;
cp->tx_ring = NULL; cp->tx_ring = NULL;
cp->nic_stats = NULL;
} }
static int cp_open (struct net_device *dev) static int cp_open (struct net_device *dev)
...@@ -1516,13 +1509,17 @@ static void cp_get_ethtool_stats (struct net_device *dev, ...@@ -1516,13 +1509,17 @@ static void cp_get_ethtool_stats (struct net_device *dev,
struct ethtool_stats *estats, u64 *tmp_stats) struct ethtool_stats *estats, u64 *tmp_stats)
{ {
struct cp_private *cp = netdev_priv(dev); struct cp_private *cp = netdev_priv(dev);
struct cp_dma_stats *nic_stats;
dma_addr_t dma;
int i; int i;
memset(cp->nic_stats, 0, sizeof(struct cp_dma_stats)); nic_stats = pci_alloc_consistent(cp->pdev, sizeof(*nic_stats), &dma);
if (!nic_stats)
return;
/* begin NIC statistics dump */ /* begin NIC statistics dump */
cpw32(StatsAddr + 4, (cp->nic_stats_dma >> 16) >> 16); cpw32(StatsAddr + 4, (u64)dma >> 32);
cpw32(StatsAddr, (cp->nic_stats_dma & 0xffffffff) | DumpStats); cpw32(StatsAddr, ((u64)dma & DMA_32BIT_MASK) | DumpStats);
cpr32(StatsAddr); cpr32(StatsAddr);
for (i = 0; i < 1000; i++) { for (i = 0; i < 1000; i++) {
...@@ -1532,24 +1529,27 @@ static void cp_get_ethtool_stats (struct net_device *dev, ...@@ -1532,24 +1529,27 @@ static void cp_get_ethtool_stats (struct net_device *dev,
} }
cpw32(StatsAddr, 0); cpw32(StatsAddr, 0);
cpw32(StatsAddr + 4, 0); cpw32(StatsAddr + 4, 0);
cpr32(StatsAddr);
i = 0; i = 0;
tmp_stats[i++] = le64_to_cpu(cp->nic_stats->tx_ok); tmp_stats[i++] = le64_to_cpu(nic_stats->tx_ok);
tmp_stats[i++] = le64_to_cpu(cp->nic_stats->rx_ok); tmp_stats[i++] = le64_to_cpu(nic_stats->rx_ok);
tmp_stats[i++] = le64_to_cpu(cp->nic_stats->tx_err); tmp_stats[i++] = le64_to_cpu(nic_stats->tx_err);
tmp_stats[i++] = le32_to_cpu(cp->nic_stats->rx_err); tmp_stats[i++] = le32_to_cpu(nic_stats->rx_err);
tmp_stats[i++] = le16_to_cpu(cp->nic_stats->rx_fifo); tmp_stats[i++] = le16_to_cpu(nic_stats->rx_fifo);
tmp_stats[i++] = le16_to_cpu(cp->nic_stats->frame_align); tmp_stats[i++] = le16_to_cpu(nic_stats->frame_align);
tmp_stats[i++] = le32_to_cpu(cp->nic_stats->tx_ok_1col); tmp_stats[i++] = le32_to_cpu(nic_stats->tx_ok_1col);
tmp_stats[i++] = le32_to_cpu(cp->nic_stats->tx_ok_mcol); tmp_stats[i++] = le32_to_cpu(nic_stats->tx_ok_mcol);
tmp_stats[i++] = le64_to_cpu(cp->nic_stats->rx_ok_phys); tmp_stats[i++] = le64_to_cpu(nic_stats->rx_ok_phys);
tmp_stats[i++] = le64_to_cpu(cp->nic_stats->rx_ok_bcast); tmp_stats[i++] = le64_to_cpu(nic_stats->rx_ok_bcast);
tmp_stats[i++] = le32_to_cpu(cp->nic_stats->rx_ok_mcast); tmp_stats[i++] = le32_to_cpu(nic_stats->rx_ok_mcast);
tmp_stats[i++] = le16_to_cpu(cp->nic_stats->tx_abort); tmp_stats[i++] = le16_to_cpu(nic_stats->tx_abort);
tmp_stats[i++] = le16_to_cpu(cp->nic_stats->tx_underrun); tmp_stats[i++] = le16_to_cpu(nic_stats->tx_underrun);
tmp_stats[i++] = cp->cp_stats.rx_frags; tmp_stats[i++] = cp->cp_stats.rx_frags;
if (i != CP_NUM_STATS) if (i != CP_NUM_STATS)
BUG(); BUG();
pci_free_consistent(cp->pdev, sizeof(*nic_stats), nic_stats, dma);
} }
static struct ethtool_ops cp_ethtool_ops = { static struct ethtool_ops cp_ethtool_ops = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment