Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

[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
Loading
Loading
Loading
Loading
+23 −23
Original line number Original line Diff line number Diff line
@@ -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)
	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)
	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,
				  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,
	}
	}
	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 = {