Commit 15d68f80 authored by Jeff Garzik's avatar Jeff Garzik

Update 8139cp net driver to support NIC-specific statistic dumps

parent 996dec15
...@@ -100,13 +100,16 @@ MODULE_PARM_DESC (multicast_filter_limit, "8139cp maximum number of filtered mul ...@@ -100,13 +100,16 @@ MODULE_PARM_DESC (multicast_filter_limit, "8139cp maximum number of filtered mul
#define CP_DEF_MSG_ENABLE (NETIF_MSG_DRV | \ #define CP_DEF_MSG_ENABLE (NETIF_MSG_DRV | \
NETIF_MSG_PROBE | \ NETIF_MSG_PROBE | \
NETIF_MSG_LINK) NETIF_MSG_LINK)
#define CP_NUM_STATS 14 /* struct cp_dma_stats, plus one */
#define CP_STATS_SIZE 64 /* size in bytes of DMA stats block */
#define CP_REGS_SIZE (0xff + 1) #define CP_REGS_SIZE (0xff + 1)
#define CP_REGS_VER 1 /* version 1 */ #define CP_REGS_VER 1 /* version 1 */
#define CP_RX_RING_SIZE 64 #define CP_RX_RING_SIZE 64
#define CP_TX_RING_SIZE 64 #define CP_TX_RING_SIZE 64
#define CP_RING_BYTES \ #define CP_RING_BYTES \
((sizeof(struct cp_desc) * CP_RX_RING_SIZE) + \ ((sizeof(struct cp_desc) * CP_RX_RING_SIZE) + \
(sizeof(struct cp_desc) * CP_TX_RING_SIZE)) (sizeof(struct cp_desc) * CP_TX_RING_SIZE) + \
CP_STATS_SIZE)
#define NEXT_TX(N) (((N) + 1) & (CP_TX_RING_SIZE - 1)) #define NEXT_TX(N) (((N) + 1) & (CP_TX_RING_SIZE - 1))
#define NEXT_RX(N) (((N) + 1) & (CP_RX_RING_SIZE - 1)) #define NEXT_RX(N) (((N) + 1) & (CP_RX_RING_SIZE - 1))
#define TX_BUFFS_AVAIL(CP) \ #define TX_BUFFS_AVAIL(CP) \
...@@ -135,6 +138,7 @@ enum { ...@@ -135,6 +138,7 @@ enum {
/* NIC register offsets */ /* NIC register offsets */
MAC0 = 0x00, /* Ethernet hardware address. */ MAC0 = 0x00, /* Ethernet hardware address. */
MAR0 = 0x08, /* Multicast filter. */ MAR0 = 0x08, /* Multicast filter. */
StatsAddr = 0x10, /* 64-bit start addr of 64-byte DMA stats blk */
TxRingAddr = 0x20, /* 64-bit start addr of Tx ring */ TxRingAddr = 0x20, /* 64-bit start addr of Tx ring */
HiTxRingAddr = 0x28, /* 64-bit start addr of high priority Tx ring */ HiTxRingAddr = 0x28, /* 64-bit start addr of high priority Tx ring */
Cmd = 0x37, /* Command register */ Cmd = 0x37, /* Command register */
...@@ -197,6 +201,9 @@ enum { ...@@ -197,6 +201,9 @@ enum {
RxErrLong = (1 << 21), /* Rx error, packet > 4096 bytes */ RxErrLong = (1 << 21), /* Rx error, packet > 4096 bytes */
RxErrFIFO = (1 << 22), /* Rx error, FIFO overflowed, pkt bad */ RxErrFIFO = (1 << 22), /* Rx error, FIFO overflowed, pkt bad */
/* StatsAddr register */
DumpStats = (1 << 3), /* Begin stats dump */
/* RxConfig register */ /* RxConfig register */
RxCfgFIFOShift = 13, /* Shift, to get Rx FIFO thresh value */ RxCfgFIFOShift = 13, /* Shift, to get Rx FIFO thresh value */
RxCfgDMAShift = 8, /* Shift, to get Rx Max DMA value */ RxCfgDMAShift = 8, /* Shift, to get Rx Max DMA value */
...@@ -284,6 +291,22 @@ struct ring_info { ...@@ -284,6 +291,22 @@ struct ring_info {
unsigned frag; unsigned frag;
}; };
struct cp_dma_stats {
u64 tx_ok;
u64 rx_ok;
u64 tx_err;
u32 rx_err;
u16 rx_fifo;
u16 frame_align;
u32 tx_ok_1col;
u32 tx_ok_mcol;
u64 rx_ok_phys;
u64 rx_ok_bcast;
u32 rx_ok_mcast;
u16 tx_abort;
u16 tx_underrun;
} __attribute__((packed));
struct cp_extra_stats { struct cp_extra_stats {
unsigned long rx_frags; unsigned long rx_frags;
}; };
...@@ -312,6 +335,8 @@ struct cp_private { ...@@ -312,6 +335,8 @@ 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;
struct pci_dev *pdev; struct pci_dev *pdev;
u32 rx_config; u32 rx_config;
...@@ -373,6 +398,26 @@ static struct pci_device_id cp_pci_tbl[] __devinitdata = { ...@@ -373,6 +398,26 @@ static struct pci_device_id cp_pci_tbl[] __devinitdata = {
}; };
MODULE_DEVICE_TABLE(pci, cp_pci_tbl); MODULE_DEVICE_TABLE(pci, cp_pci_tbl);
static struct {
const char str[ETH_GSTRING_LEN];
} ethtool_stats_keys[] = {
{ "tx_ok" },
{ "rx_ok" },
{ "tx_err" },
{ "rx_err" },
{ "rx_fifo" },
{ "frame_align" },
{ "tx_ok_1col" },
{ "tx_ok_mcol" },
{ "rx_ok_phys" },
{ "rx_ok_bcast" },
{ "rx_ok_mcast" },
{ "tx_abort" },
{ "tx_underrun" },
{ "rx_frags" },
};
static inline void cp_set_rxbufsize (struct cp_private *cp) static inline void cp_set_rxbufsize (struct cp_private *cp)
{ {
unsigned int mtu = cp->dev->mtu; unsigned int mtu = cp->dev->mtu;
...@@ -949,9 +994,9 @@ static void cp_init_hw (struct cp_private *cp) ...@@ -949,9 +994,9 @@ static void cp_init_hw (struct cp_private *cp)
cpw32_f(HiTxRingAddr + 4, 0); cpw32_f(HiTxRingAddr + 4, 0);
cpw32_f(RxRingAddr, cp->ring_dma); cpw32_f(RxRingAddr, cp->ring_dma);
cpw32_f(RxRingAddr + 4, 0); cpw32_f(RxRingAddr + 4, 0); /* FIXME: 64-bit PCI */
cpw32_f(TxRingAddr, cp->ring_dma + (sizeof(struct cp_desc) * CP_RX_RING_SIZE)); cpw32_f(TxRingAddr, cp->ring_dma + (sizeof(struct cp_desc) * CP_RX_RING_SIZE));
cpw32_f(TxRingAddr + 4, 0); cpw32_f(TxRingAddr + 4, 0); /* FIXME: 64-bit PCI */
cpw16(MultiIntr, 0); cpw16(MultiIntr, 0);
...@@ -1010,10 +1055,19 @@ static int cp_init_rings (struct cp_private *cp) ...@@ -1010,10 +1055,19 @@ static int cp_init_rings (struct cp_private *cp)
static int cp_alloc_rings (struct cp_private *cp) static int cp_alloc_rings (struct cp_private *cp)
{ {
cp->rx_ring = pci_alloc_consistent(cp->pdev, CP_RING_BYTES, &cp->ring_dma); void *mem;
if (!cp->rx_ring)
mem = pci_alloc_consistent(cp->pdev, CP_RING_BYTES, &cp->ring_dma);
if (!mem)
return -ENOMEM; return -ENOMEM;
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);
} }
...@@ -1052,6 +1106,7 @@ static void cp_free_rings (struct cp_private *cp) ...@@ -1052,6 +1106,7 @@ 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)
...@@ -1181,6 +1236,7 @@ static int cp_ethtool_ioctl (struct cp_private *cp, void *useraddr) ...@@ -1181,6 +1236,7 @@ static int cp_ethtool_ioctl (struct cp_private *cp, void *useraddr)
strcpy (info.version, DRV_VERSION); strcpy (info.version, DRV_VERSION);
strcpy (info.bus_info, cp->pdev->slot_name); strcpy (info.bus_info, cp->pdev->slot_name);
info.regdump_len = CP_REGS_SIZE; info.regdump_len = CP_REGS_SIZE;
info.n_stats = CP_NUM_STATS;
if (copy_to_user (useraddr, &info, sizeof (info))) if (copy_to_user (useraddr, &info, sizeof (info)))
return -EFAULT; return -EFAULT;
return 0; return 0;
...@@ -1359,6 +1415,83 @@ static int cp_ethtool_ioctl (struct cp_private *cp, void *useraddr) ...@@ -1359,6 +1415,83 @@ static int cp_ethtool_ioctl (struct cp_private *cp, void *useraddr)
return 0; return 0;
} }
/* get string list(s) */
case ETHTOOL_GSTRINGS: {
struct ethtool_gstrings estr = { ETHTOOL_GSTRINGS };
if (copy_from_user(&estr, useraddr, sizeof(estr)))
return -EFAULT;
if (estr.string_set != ETH_SS_STATS)
return -EINVAL;
estr.len = CP_NUM_STATS;
if (copy_to_user(useraddr, &estr, sizeof(estr)))
return -EFAULT;
if (copy_to_user(useraddr + sizeof(estr),
&ethtool_stats_keys,
sizeof(ethtool_stats_keys)))
return -EFAULT;
return 0;
}
/* get NIC-specific statistics */
case ETHTOOL_GSTATS: {
struct ethtool_stats estats = { ETHTOOL_GSTATS };
u64 *tmp_stats;
unsigned int work = 100;
const unsigned int sz = sizeof(u64) * CP_NUM_STATS;
int i;
/* begin NIC statistics dump */
cpw32(StatsAddr + 4, 0); /* FIXME: 64-bit PCI */
cpw32(StatsAddr, cp->nic_stats_dma | DumpStats);
cpr32(StatsAddr);
estats.n_stats = CP_NUM_STATS;
if (copy_to_user(useraddr, &estats, sizeof(estats)))
return -EFAULT;
while (work-- > 0) {
if ((cpr32(StatsAddr) & DumpStats) == 0)
break;
cpu_relax();
}
if (cpr32(StatsAddr) & DumpStats)
return -EIO;
tmp_stats = kmalloc(sz, GFP_KERNEL);
if (!tmp_stats)
return -ENOMEM;
memset(tmp_stats, 0, sz);
i = 0;
tmp_stats[i++] = le64_to_cpu(cp->nic_stats->tx_ok);
tmp_stats[i++] = le64_to_cpu(cp->nic_stats->rx_ok);
tmp_stats[i++] = le64_to_cpu(cp->nic_stats->tx_err);
tmp_stats[i++] = le32_to_cpu(cp->nic_stats->rx_err);
tmp_stats[i++] = le16_to_cpu(cp->nic_stats->rx_fifo);
tmp_stats[i++] = le16_to_cpu(cp->nic_stats->frame_align);
tmp_stats[i++] = le32_to_cpu(cp->nic_stats->tx_ok_1col);
tmp_stats[i++] = le32_to_cpu(cp->nic_stats->tx_ok_mcol);
tmp_stats[i++] = le64_to_cpu(cp->nic_stats->rx_ok_phys);
tmp_stats[i++] = le64_to_cpu(cp->nic_stats->rx_ok_bcast);
tmp_stats[i++] = le32_to_cpu(cp->nic_stats->rx_ok_mcast);
tmp_stats[i++] = le16_to_cpu(cp->nic_stats->tx_abort);
tmp_stats[i++] = le16_to_cpu(cp->nic_stats->tx_underrun);
tmp_stats[i++] = cp->cp_stats.rx_frags;
if (i != CP_NUM_STATS)
BUG();
i = copy_to_user(useraddr + sizeof(estats),
tmp_stats, sz);
kfree(tmp_stats);
if (i)
return -EFAULT;
return 0;
}
default: default:
break; break;
} }
......
...@@ -39,7 +39,8 @@ struct ethtool_drvinfo { ...@@ -39,7 +39,8 @@ struct ethtool_drvinfo {
char bus_info[ETHTOOL_BUSINFO_LEN]; /* Bus info for this IF. */ char bus_info[ETHTOOL_BUSINFO_LEN]; /* Bus info for this IF. */
/* For PCI devices, use pci_dev->slot_name. */ /* For PCI devices, use pci_dev->slot_name. */
char reserved1[32]; char reserved1[32];
char reserved2[20]; char reserved2[16];
u32 n_stats; /* number of u64's from ETHTOOL_GSTATS */
u32 testinfo_len; u32 testinfo_len;
u32 eedump_len; /* Size of data from ETHTOOL_GEEPROM (bytes) */ u32 eedump_len; /* Size of data from ETHTOOL_GEEPROM (bytes) */
u32 regdump_len; /* Size of data from ETHTOOL_GREGS (bytes) */ u32 regdump_len; /* Size of data from ETHTOOL_GREGS (bytes) */
...@@ -242,6 +243,13 @@ struct ethtool_test { ...@@ -242,6 +243,13 @@ struct ethtool_test {
u64 data[0]; u64 data[0];
}; };
/* for dumping NIC-specific statistics */
struct ethtool_stats {
u32 cmd; /* ETHTOOL_GSTATS */
u32 n_stats; /* number of u64's being returned */
u64 data[0];
};
/* CMDs currently supported */ /* CMDs currently supported */
#define ETHTOOL_GSET 0x00000001 /* Get settings. */ #define ETHTOOL_GSET 0x00000001 /* Get settings. */
#define ETHTOOL_SSET 0x00000002 /* Set settings, privileged. */ #define ETHTOOL_SSET 0x00000002 /* Set settings, privileged. */
...@@ -272,6 +280,7 @@ struct ethtool_test { ...@@ -272,6 +280,7 @@ struct ethtool_test {
#define ETHTOOL_TEST 0x0000001a /* execute NIC self-test, priv. */ #define ETHTOOL_TEST 0x0000001a /* execute NIC self-test, priv. */
#define ETHTOOL_GSTRINGS 0x0000001b /* get specified string set */ #define ETHTOOL_GSTRINGS 0x0000001b /* get specified string set */
#define ETHTOOL_PHYS_ID 0x0000001c /* identify the NIC */ #define ETHTOOL_PHYS_ID 0x0000001c /* identify the NIC */
#define ETHTOOL_GSTATS 0x0000001d /* get NIC-specific statistics */
/* compatibility with older code */ /* compatibility with older code */
#define SPARC_ETH_GSET ETHTOOL_GSET #define SPARC_ETH_GSET ETHTOOL_GSET
......
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