]> err.no Git - linux-2.6/blobdiff - drivers/net/r8169.c
[PATCH] parport: add NetMOS 9805 support
[linux-2.6] / drivers / net / r8169.c
index d795b31649f3087c8ae3c0b3e7dade28f205b603..f0471d102e3c61bcfc6089c483009e52b2427cfb 100644 (file)
@@ -187,6 +187,7 @@ static struct pci_device_id rtl8169_pci_tbl[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_REALTEK,     0x8169), },
        { PCI_DEVICE(PCI_VENDOR_ID_DLINK,       0x4300), },
        { PCI_DEVICE(0x16ec,                    0x0116), },
+       { PCI_VENDOR_ID_LINKSYS,                0x1032, PCI_ANY_ID, 0x0024, },
        {0,},
 };
 
@@ -201,6 +202,8 @@ static struct {
 enum RTL8169_registers {
        MAC0 = 0,               /* Ethernet hardware address. */
        MAR0 = 8,               /* Multicast filter. */
+       CounterAddrLow = 0x10,
+       CounterAddrHigh = 0x14,
        TxDescStartAddrLow = 0x20,
        TxDescStartAddrHigh = 0x24,
        TxHDescStartAddrLow = 0x28,
@@ -342,6 +345,9 @@ enum RTL8169_register_content {
 
        /* _TBICSRBit */
        TBILinkOK = 0x02000000,
+
+       /* DumpCounterCommand */
+       CounterDump = 0x8,
 };
 
 enum _DescStatusBit {
@@ -430,7 +436,7 @@ struct rtl8169_private {
        struct work_struct task;
 };
 
-MODULE_AUTHOR("Realtek and the Linux r8169 crew <netdev@oss.sgi.com>");
+MODULE_AUTHOR("Realtek and the Linux r8169 crew <netdev@vger.kernel.org>");
 MODULE_DESCRIPTION("RealTek RTL-8169 Gigabit Ethernet driver");
 module_param_array(media, int, &num_media, 0);
 MODULE_PARM_DESC(media, "force phy operation. Deprecated by ethtool (8).");
@@ -452,10 +458,10 @@ static void rtl8169_hw_start(struct net_device *dev);
 static int rtl8169_close(struct net_device *dev);
 static void rtl8169_set_rx_mode(struct net_device *dev);
 static void rtl8169_tx_timeout(struct net_device *dev);
-static struct net_device_stats *rtl8169_get_stats(struct net_device *netdev);
+static struct net_device_stats *rtl8169_get_stats(struct net_device *dev);
 static int rtl8169_rx_interrupt(struct net_device *, struct rtl8169_private *,
                                void __iomem *);
-static int rtl8169_change_mtu(struct net_device *netdev, int new_mtu);
+static int rtl8169_change_mtu(struct net_device *dev, int new_mtu);
 static void rtl8169_down(struct net_device *dev);
 
 #ifdef CONFIG_R8169_NAPI
@@ -910,6 +916,98 @@ static void rtl8169_set_msglevel(struct net_device *dev, u32 value)
        tp->msg_enable = value;
 }
 
+static const char rtl8169_gstrings[][ETH_GSTRING_LEN] = {
+       "tx_packets",
+       "rx_packets",
+       "tx_errors",
+       "rx_errors",
+       "rx_missed",
+       "align_errors",
+       "tx_single_collisions",
+       "tx_multi_collisions",
+       "unicast",
+       "broadcast",
+       "multicast",
+       "tx_aborted",
+       "tx_underrun",
+};
+
+struct rtl8169_counters {
+       u64     tx_packets;
+       u64     rx_packets;
+       u64     tx_errors;
+       u32     rx_errors;
+       u16     rx_missed;
+       u16     align_errors;
+       u32     tx_one_collision;
+       u32     tx_multi_collision;
+       u64     rx_unicast;
+       u64     rx_broadcast;
+       u32     rx_multicast;
+       u16     tx_aborted;
+       u16     tx_underun;
+};
+
+static int rtl8169_get_stats_count(struct net_device *dev)
+{
+       return ARRAY_SIZE(rtl8169_gstrings);
+}
+
+static void rtl8169_get_ethtool_stats(struct net_device *dev,
+                                     struct ethtool_stats *stats, u64 *data)
+{
+       struct rtl8169_private *tp = netdev_priv(dev);
+       void __iomem *ioaddr = tp->mmio_addr;
+       struct rtl8169_counters *counters;
+       dma_addr_t paddr;
+       u32 cmd;
+
+       ASSERT_RTNL();
+
+       counters = pci_alloc_consistent(tp->pci_dev, sizeof(*counters), &paddr);
+       if (!counters)
+               return;
+
+       RTL_W32(CounterAddrHigh, (u64)paddr >> 32);
+       cmd = (u64)paddr & DMA_32BIT_MASK;
+       RTL_W32(CounterAddrLow, cmd);
+       RTL_W32(CounterAddrLow, cmd | CounterDump);
+
+       while (RTL_R32(CounterAddrLow) & CounterDump) {
+               if (msleep_interruptible(1))
+                       break;
+       }
+
+       RTL_W32(CounterAddrLow, 0);
+       RTL_W32(CounterAddrHigh, 0);
+
+       data[0] = le64_to_cpu(counters->tx_packets);
+       data[1] = le64_to_cpu(counters->rx_packets);
+       data[2] = le64_to_cpu(counters->tx_errors);
+       data[3] = le32_to_cpu(counters->rx_errors);
+       data[4] = le16_to_cpu(counters->rx_missed);
+       data[5] = le16_to_cpu(counters->align_errors);
+       data[6] = le32_to_cpu(counters->tx_one_collision);
+       data[7] = le32_to_cpu(counters->tx_multi_collision);
+       data[8] = le64_to_cpu(counters->rx_unicast);
+       data[9] = le64_to_cpu(counters->rx_broadcast);
+       data[10] = le32_to_cpu(counters->rx_multicast);
+       data[11] = le16_to_cpu(counters->tx_aborted);
+       data[12] = le16_to_cpu(counters->tx_underun);
+
+       pci_free_consistent(tp->pci_dev, sizeof(*counters), counters, paddr);
+}
+
+static void rtl8169_get_strings(struct net_device *dev, u32 stringset, u8 *data)
+{
+       switch(stringset) {
+       case ETH_SS_STATS:
+               memcpy(data, *rtl8169_gstrings, sizeof(rtl8169_gstrings));
+               break;
+       }
+}
+
+
 static struct ethtool_ops rtl8169_ethtool_ops = {
        .get_drvinfo            = rtl8169_get_drvinfo,
        .get_regs_len           = rtl8169_get_regs_len,
@@ -927,6 +1025,9 @@ static struct ethtool_ops rtl8169_ethtool_ops = {
        .get_tso                = ethtool_op_get_tso,
        .set_tso                = ethtool_op_set_tso,
        .get_regs               = rtl8169_get_regs,
+       .get_strings            = rtl8169_get_strings,
+       .get_stats_count        = rtl8169_get_stats_count,
+       .get_ethtool_stats      = rtl8169_get_ethtool_stats,
 };
 
 static void rtl8169_write_gmii_reg_bit(void __iomem *ioaddr, int reg, int bitnum,
@@ -1776,7 +1877,7 @@ static int rtl8169_alloc_rx_skb(struct pci_dev *pdev, struct sk_buff **sk_buff,
        skb_reserve(skb, NET_IP_ALIGN);
        *sk_buff = skb;
 
-       mapping = pci_map_single(pdev, skb->tail, rx_buf_sz,
+       mapping = pci_map_single(pdev, skb->data, rx_buf_sz,
                                 PCI_DMA_FROMDEVICE);
 
        rtl8169_map_to_asic(desc, mapping, rx_buf_sz);
@@ -2236,7 +2337,7 @@ static inline int rtl8169_try_rx_copy(struct sk_buff **sk_buff, int pkt_size,
                skb = dev_alloc_skb(pkt_size + NET_IP_ALIGN);
                if (skb) {
                        skb_reserve(skb, NET_IP_ALIGN);
-                       eth_copy_and_sum(skb, sk_buff[0]->tail, pkt_size, 0);
+                       eth_copy_and_sum(skb, sk_buff[0]->data, pkt_size, 0);
                        *sk_buff = skb;
                        rtl8169_mark_to_asic(desc, rx_buf_sz);
                        ret = 0;
@@ -2260,7 +2361,7 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
        rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx;
        rx_left = rtl8169_rx_quota(rx_left, (u32) dev->quota);
 
-       while (rx_left > 0) {
+       for (; rx_left > 0; rx_left--, cur_rx++) {
                unsigned int entry = cur_rx % NUM_RX_DESC;
                struct RxDesc *desc = tp->RxDescArray + entry;
                u32 status;
@@ -2270,7 +2371,7 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
 
                if (status & DescOwn)
                        break;
-               if (status & RxRES) {
+               if (unlikely(status & RxRES)) {
                        if (netif_msg_rx_err(tp)) {
                                printk(KERN_INFO
                                       "%s: Rx ERROR. status = %08x\n",
@@ -2297,7 +2398,7 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
                                tp->stats.rx_dropped++;
                                tp->stats.rx_length_errors++;
                                rtl8169_mark_to_asic(desc, tp->rx_buf_sz);
-                               goto move_on;
+                               continue;
                        }
 
                        rtl8169_rx_csum(skb, desc);
@@ -2326,9 +2427,6 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
                        tp->stats.rx_bytes += pkt_size;
                        tp->stats.rx_packets++;
                }
-move_on:               
-               cur_rx++; 
-               rx_left--;
        }
 
        count = cur_rx - tp->cur_rx;