Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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: Stephen Hemminger <shemminger@osdl.org>
Signed-off-by: Jeff Garzik <jgarzik@pobox.com>

authored by

Stephen Hemminger and committed by
Jeff Garzik
8b512927 ed4b9f80

+23 -23
+23 -23
drivers/net/8139cp.c
··· 353 353 354 354 struct net_device_stats net_stats; 355 355 struct cp_extra_stats cp_stats; 356 - struct cp_dma_stats *nic_stats; 357 - dma_addr_t nic_stats_dma; 358 356 359 357 unsigned rx_tail ____cacheline_aligned; 360 358 struct cp_desc *rx_ring; ··· 1141 1143 cp->rx_ring = mem; 1142 1144 cp->tx_ring = &cp->rx_ring[CP_RX_RING_SIZE]; 1143 1145 1144 - mem += (CP_RING_BYTES - CP_STATS_SIZE); 1145 - cp->nic_stats = mem; 1146 - cp->nic_stats_dma = cp->ring_dma + (CP_RING_BYTES - CP_STATS_SIZE); 1147 - 1148 1146 return cp_init_rings(cp); 1149 1147 } 1150 1148 ··· 1181 1187 pci_free_consistent(cp->pdev, CP_RING_BYTES, cp->rx_ring, cp->ring_dma); 1182 1188 cp->rx_ring = NULL; 1183 1189 cp->tx_ring = NULL; 1184 - cp->nic_stats = NULL; 1185 1190 } 1186 1191 1187 1192 static int cp_open (struct net_device *dev) ··· 1509 1516 struct ethtool_stats *estats, u64 *tmp_stats) 1510 1517 { 1511 1518 struct cp_private *cp = netdev_priv(dev); 1519 + struct cp_dma_stats *nic_stats; 1520 + dma_addr_t dma; 1512 1521 int i; 1513 1522 1514 - memset(cp->nic_stats, 0, sizeof(struct cp_dma_stats)); 1523 + nic_stats = pci_alloc_consistent(cp->pdev, sizeof(*nic_stats), &dma); 1524 + if (!nic_stats) 1525 + return; 1515 1526 1516 1527 /* begin NIC statistics dump */ 1517 - cpw32(StatsAddr + 4, (cp->nic_stats_dma >> 16) >> 16); 1518 - cpw32(StatsAddr, (cp->nic_stats_dma & 0xffffffff) | DumpStats); 1528 + cpw32(StatsAddr + 4, (u64)dma >> 32); 1529 + cpw32(StatsAddr, ((u64)dma & DMA_32BIT_MASK) | DumpStats); 1519 1530 cpr32(StatsAddr); 1520 1531 1521 1532 for (i = 0; i < 1000; i++) { ··· 1529 1532 } 1530 1533 cpw32(StatsAddr, 0); 1531 1534 cpw32(StatsAddr + 4, 0); 1535 + cpr32(StatsAddr); 1532 1536 1533 1537 i = 0; 1534 - tmp_stats[i++] = le64_to_cpu(cp->nic_stats->tx_ok); 1535 - tmp_stats[i++] = le64_to_cpu(cp->nic_stats->rx_ok); 1536 - tmp_stats[i++] = le64_to_cpu(cp->nic_stats->tx_err); 1537 - tmp_stats[i++] = le32_to_cpu(cp->nic_stats->rx_err); 1538 - tmp_stats[i++] = le16_to_cpu(cp->nic_stats->rx_fifo); 1539 - tmp_stats[i++] = le16_to_cpu(cp->nic_stats->frame_align); 1540 - tmp_stats[i++] = le32_to_cpu(cp->nic_stats->tx_ok_1col); 1541 - tmp_stats[i++] = le32_to_cpu(cp->nic_stats->tx_ok_mcol); 1542 - tmp_stats[i++] = le64_to_cpu(cp->nic_stats->rx_ok_phys); 1543 - tmp_stats[i++] = le64_to_cpu(cp->nic_stats->rx_ok_bcast); 1544 - tmp_stats[i++] = le32_to_cpu(cp->nic_stats->rx_ok_mcast); 1545 - tmp_stats[i++] = le16_to_cpu(cp->nic_stats->tx_abort); 1546 - tmp_stats[i++] = le16_to_cpu(cp->nic_stats->tx_underrun); 1538 + tmp_stats[i++] = le64_to_cpu(nic_stats->tx_ok); 1539 + tmp_stats[i++] = le64_to_cpu(nic_stats->rx_ok); 1540 + tmp_stats[i++] = le64_to_cpu(nic_stats->tx_err); 1541 + tmp_stats[i++] = le32_to_cpu(nic_stats->rx_err); 1542 + tmp_stats[i++] = le16_to_cpu(nic_stats->rx_fifo); 1543 + tmp_stats[i++] = le16_to_cpu(nic_stats->frame_align); 1544 + tmp_stats[i++] = le32_to_cpu(nic_stats->tx_ok_1col); 1545 + tmp_stats[i++] = le32_to_cpu(nic_stats->tx_ok_mcol); 1546 + tmp_stats[i++] = le64_to_cpu(nic_stats->rx_ok_phys); 1547 + tmp_stats[i++] = le64_to_cpu(nic_stats->rx_ok_bcast); 1548 + tmp_stats[i++] = le32_to_cpu(nic_stats->rx_ok_mcast); 1549 + tmp_stats[i++] = le16_to_cpu(nic_stats->tx_abort); 1550 + tmp_stats[i++] = le16_to_cpu(nic_stats->tx_underrun); 1547 1551 tmp_stats[i++] = cp->cp_stats.rx_frags; 1548 1552 if (i != CP_NUM_STATS) 1549 1553 BUG(); 1554 + 1555 + pci_free_consistent(cp->pdev, sizeof(*nic_stats), nic_stats, dma); 1550 1556 } 1551 1557 1552 1558 static struct ethtool_ops cp_ethtool_ops = {