Loading drivers/net/ethernet/3com/3c589_cs.c +584 −543 Original line number Original line Diff line number Diff line /* ====================================================================== /* ====================================================================== * A PCMCIA ethernet driver for the 3com 3c589 card. * A PCMCIA ethernet driver for the 3com 3c589 card. * Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net * Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net * 3c589_cs.c 1.162 2001/10/13 00:08:50 * 3c589_cs.c 1.162 2001/10/13 00:08:50 * The network driver code is based on Donald Becker's 3c589 code: * The network driver code is based on Donald Becker's 3c589 code: * Written 1994 by Donald Becker. * Written 1994 by Donald Becker. Copyright 1993 United States Government as represented by the * Copyright 1993 United States Government as represented by the Director, National Security Agency. This software may be used and * Director, National Security Agency. This software may be used and distributed according to the terms of the GNU General Public License, * distributed according to the terms of the GNU General Public License, incorporated herein by reference. * incorporated herein by reference. Donald Becker may be reached at becker@scyld.com * Donald Becker may be reached at becker@scyld.com * Updated for 2.5.x by Alan Cox <alan@lxorguk.ukuu.org.uk> * Updated for 2.5.x by Alan Cox <alan@lxorguk.ukuu.org.uk> * ======================================================================*/ * ====================================================================== */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt Loading @@ -41,18 +42,20 @@ #include <linux/ioport.h> #include <linux/ioport.h> #include <linux/bitops.h> #include <linux/bitops.h> #include <linux/jiffies.h> #include <linux/jiffies.h> #include <linux/uaccess.h> #include <linux/io.h> #include <pcmcia/cistpl.h> #include <pcmcia/cistpl.h> #include <pcmcia/cisreg.h> #include <pcmcia/cisreg.h> #include <pcmcia/ciscode.h> #include <pcmcia/ciscode.h> #include <pcmcia/ds.h> #include <pcmcia/ds.h> #include <asm/uaccess.h> #include <asm/io.h> /* To minimize the size of the driver source I only define operating /* To minimize the size of the driver source I only define operating constants if they are used several times. You'll need the manual * constants if they are used several times. You'll need the manual if you want to understand driver details. */ * if you want to understand driver details. */ /* Offsets from base I/O address. */ /* Offsets from base I/O address. */ #define EL3_DATA 0x00 #define EL3_DATA 0x00 #define EL3_TIMER 0x0a #define EL3_TIMER 0x0a Loading @@ -65,7 +68,9 @@ #define EL3WINDOW(win_num) outw(SelectWindow + (win_num), ioaddr + EL3_CMD) #define EL3WINDOW(win_num) outw(SelectWindow + (win_num), ioaddr + EL3_CMD) /* The top five bits written to EL3_CMD are a command, the lower /* The top five bits written to EL3_CMD are a command, the lower 11 bits are the parameter, if applicable. */ * 11 bits are the parameter, if applicable. */ enum c509cmd { enum c509cmd { TotalReset = 0<<11, TotalReset = 0<<11, SelectWindow = 1<<11, SelectWindow = 1<<11, Loading Loading @@ -253,7 +258,8 @@ static int tc589_config(struct pcmcia_device *link) /* For the 3c562, the base address must be xx00-xx7f */ /* For the 3c562, the base address must be xx00-xx7f */ for (i = j = 0; j < 0x400; j += 0x10) { for (i = j = 0; j < 0x400; j += 0x10) { if (multi && (j & 0x80)) continue; if (multi && (j & 0x80)) continue; link->resource[0]->start = j ^ 0x300; link->resource[0]->start = j ^ 0x300; i = pcmcia_request_io(link); i = pcmcia_request_io(link); if (i == 0) if (i == 0) Loading @@ -276,7 +282,8 @@ static int tc589_config(struct pcmcia_device *link) EL3WINDOW(0); EL3WINDOW(0); /* The 3c589 has an extra EEPROM for configuration info, including /* The 3c589 has an extra EEPROM for configuration info, including the hardware address. The 3c562 puts the address in the CIS. */ * the hardware address. The 3c562 puts the address in the CIS. */ len = pcmcia_get_tuple(link, 0x88, &buf); len = pcmcia_get_tuple(link, 0x88, &buf); if (buf && len >= 6) { if (buf && len >= 6) { for (i = 0; i < 3; i++) for (i = 0; i < 3; i++) Loading @@ -294,7 +301,9 @@ static int tc589_config(struct pcmcia_device *link) } } /* The address and resource configuration register aren't loaded from /* The address and resource configuration register aren't loaded from the EEPROM and *must* be set to 0 and IRQ3 for the PCMCIA version. */ * the EEPROM and *must* be set to 0 and IRQ3 for the PCMCIA version. */ outw(0x3f00, ioaddr + 8); outw(0x3f00, ioaddr + 8); fifo = inl(ioaddr); fifo = inl(ioaddr); Loading Loading @@ -353,23 +362,23 @@ static int tc589_resume(struct pcmcia_device *link) /*====================================================================*/ /*====================================================================*/ /* /* Use this for commands that may take time to finish */ Use this for commands that may take time to finish */ static void tc589_wait_for_completion(struct net_device *dev, int cmd) static void tc589_wait_for_completion(struct net_device *dev, int cmd) { { int i = 100; int i = 100; outw(cmd, dev->base_addr + EL3_CMD); outw(cmd, dev->base_addr + EL3_CMD); while (--i > 0) while (--i > 0) if (!(inw(dev->base_addr + EL3_STATUS) & 0x1000)) break; if (!(inw(dev->base_addr + EL3_STATUS) & 0x1000)) break; if (i == 0) if (i == 0) netdev_warn(dev, "command 0x%04x did not complete!\n", cmd); netdev_warn(dev, "command 0x%04x did not complete!\n", cmd); } } /* /* Read a word from the EEPROM using the regular EEPROM access register. Read a word from the EEPROM using the regular EEPROM access register. * Assume that we are in register window zero. Assume that we are in register window zero. */ */ static u16 read_eeprom(unsigned int ioaddr, int index) static u16 read_eeprom(unsigned int ioaddr, int index) { { int i; int i; Loading @@ -381,10 +390,10 @@ static u16 read_eeprom(unsigned int ioaddr, int index) return inw(ioaddr + 12); return inw(ioaddr + 12); } } /* /* Set transceiver type, perhaps to something other than what the user Set transceiver type, perhaps to something other than what the user * specified in dev->if_port. specified in dev->if_port. */ */ static void tc589_set_xcvr(struct net_device *dev, int if_port) static void tc589_set_xcvr(struct net_device *dev, int if_port) { { struct el3_private *lp = netdev_priv(dev); struct el3_private *lp = netdev_priv(dev); Loading @@ -392,9 +401,16 @@ static void tc589_set_xcvr(struct net_device *dev, int if_port) EL3WINDOW(0); EL3WINDOW(0); switch (if_port) { switch (if_port) { case 0: case 1: outw(0, ioaddr + 6); break; case 0: case 2: outw(3<<14, ioaddr + 6); break; case 1: case 3: outw(1<<14, ioaddr + 6); break; outw(0, ioaddr + 6); break; case 2: outw(3<<14, ioaddr + 6); break; case 3: outw(1<<14, ioaddr + 6); break; } } /* On PCMCIA, this just turns on the LED */ /* On PCMCIA, this just turns on the LED */ outw((if_port == 2) ? StartCoax : StopCoax, ioaddr + EL3_CMD); outw((if_port == 2) ? StartCoax : StopCoax, ioaddr + EL3_CMD); Loading Loading @@ -483,9 +499,10 @@ static int el3_config(struct net_device *dev, struct ifmap *map) dev->if_port = map->port; dev->if_port = map->port; netdev_info(dev, "switched to %s port\n", if_names[dev->if_port]); netdev_info(dev, "switched to %s port\n", if_names[dev->if_port]); tc589_set_xcvr(dev, dev->if_port); tc589_set_xcvr(dev, dev->if_port); } else } else { return -EINVAL; return -EINVAL; } } } return 0; return 0; } } Loading Loading @@ -535,7 +552,8 @@ static void pop_tx_status(struct net_device *dev) /* Clear the Tx status stack. */ /* Clear the Tx status stack. */ for (i = 32; i > 0; i--) { for (i = 32; i > 0; i--) { u_char tx_status = inb(ioaddr + TX_STATUS); u_char tx_status = inb(ioaddr + TX_STATUS); if (!(tx_status & 0x84)) break; if (!(tx_status & 0x84)) break; /* reset transmitter on jabber error or underrun */ /* reset transmitter on jabber error or underrun */ if (tx_status & 0x30) if (tx_status & 0x30) tc589_wait_for_completion(dev, TxReset); tc589_wait_for_completion(dev, TxReset); Loading Loading @@ -619,7 +637,8 @@ static irqreturn_t el3_interrupt(int irq, void *dev_id) /* Handle all uncommon interrupts. */ /* Handle all uncommon interrupts. */ if (status & StatsFull) /* Empty statistics. */ if (status & StatsFull) /* Empty statistics. */ update_stats(dev); update_stats(dev); if (status & RxEarly) { /* Rx early is unused. */ if (status & RxEarly) { /* Rx early is unused. */ el3_rx(dev); el3_rx(dev); outw(AckIntr | RxEarly, ioaddr + EL3_CMD); outw(AckIntr | RxEarly, ioaddr + EL3_CMD); } } Loading Loading @@ -669,10 +688,12 @@ static void media_check(unsigned long arg) u16 media, errs; u16 media, errs; unsigned long flags; unsigned long flags; if (!netif_device_present(dev)) goto reschedule; if (!netif_device_present(dev)) goto reschedule; /* Check for pending interrupt with expired latency timer: with /* Check for pending interrupt with expired latency timer: with this, we can limp along even if the interrupt is blocked */ * this, we can limp along even if the interrupt is blocked */ if ((inw(ioaddr + EL3_STATUS) & IntLatch) && if ((inw(ioaddr + EL3_STATUS) & IntLatch) && (inb(ioaddr + EL3_TIMER) == 0xff)) { (inb(ioaddr + EL3_TIMER) == 0xff)) { if (!lp->fast_poll) if (!lp->fast_poll) Loading @@ -692,7 +713,9 @@ static void media_check(unsigned long arg) } } /* lp->lock guards the EL3 window. Window should always be 1 except /* lp->lock guards the EL3 window. Window should always be 1 except when the lock is held */ * when the lock is held */ spin_lock_irqsave(&lp->lock, flags); spin_lock_irqsave(&lp->lock, flags); EL3WINDOW(4); EL3WINDOW(4); media = inw(ioaddr+WN4_MEDIA) & 0xc810; media = inw(ioaddr+WN4_MEDIA) & 0xc810; Loading @@ -707,7 +730,8 @@ static void media_check(unsigned long arg) errs = inb(ioaddr + 0); errs = inb(ioaddr + 0); outw(StatsEnable, ioaddr + EL3_CMD); outw(StatsEnable, ioaddr + EL3_CMD); dev->stats.tx_carrier_errors += errs; dev->stats.tx_carrier_errors += errs; if (errs || (lp->media_status & 0x0010)) media |= 0x0010; if (errs || (lp->media_status & 0x0010)) media |= 0x0010; } } if (media != lp->media_status) { if (media != lp->media_status) { Loading Loading @@ -757,14 +781,14 @@ static struct net_device_stats *el3_get_stats(struct net_device *dev) return &dev->stats; return &dev->stats; } } /* /* Update statistics. We change to register window 6, so this should be run Update statistics. We change to register window 6, so this should be run * single-threaded if the device is active. This is expected to be a rare single-threaded if the device is active. This is expected to be a rare * operation, and it's simpler for the rest of the driver to assume that operation, and it's simpler for the rest of the driver to assume that * window 1 is always valid rather than use a special window-state variable. window 1 is always valid rather than use a special window-state variable. * * Caller must hold the lock for this Caller must hold the lock for this */ */ static void update_stats(struct net_device *dev) static void update_stats(struct net_device *dev) { { unsigned int ioaddr = dev->base_addr; unsigned int ioaddr = dev->base_addr; Loading @@ -776,15 +800,20 @@ static void update_stats(struct net_device *dev) EL3WINDOW(6); EL3WINDOW(6); dev->stats.tx_carrier_errors += inb(ioaddr + 0); dev->stats.tx_carrier_errors += inb(ioaddr + 0); dev->stats.tx_heartbeat_errors += inb(ioaddr + 1); dev->stats.tx_heartbeat_errors += inb(ioaddr + 1); /* Multiple collisions. */ inb(ioaddr + 2); /* Multiple collisions. */ inb(ioaddr + 2); dev->stats.collisions += inb(ioaddr + 3); dev->stats.collisions += inb(ioaddr + 3); dev->stats.tx_window_errors += inb(ioaddr + 4); dev->stats.tx_window_errors += inb(ioaddr + 4); dev->stats.rx_fifo_errors += inb(ioaddr + 5); dev->stats.rx_fifo_errors += inb(ioaddr + 5); dev->stats.tx_packets += inb(ioaddr + 6); dev->stats.tx_packets += inb(ioaddr + 6); /* Rx packets */ inb(ioaddr + 7); /* Rx packets */ /* Tx deferrals */ inb(ioaddr + 8); inb(ioaddr + 7); /* Rx octets */ inw(ioaddr + 10); /* Tx deferrals */ /* Tx octets */ inw(ioaddr + 12); inb(ioaddr + 8); /* Rx octets */ inw(ioaddr + 10); /* Tx octets */ inw(ioaddr + 12); /* Back to window 1, and turn statistics back on. */ /* Back to window 1, and turn statistics back on. */ EL3WINDOW(1); EL3WINDOW(1); Loading @@ -806,12 +835,24 @@ static int el3_rx(struct net_device *dev) short error = rx_status & 0x3800; short error = rx_status & 0x3800; dev->stats.rx_errors++; dev->stats.rx_errors++; switch (error) { switch (error) { case 0x0000: dev->stats.rx_over_errors++; break; case 0x0000: case 0x0800: dev->stats.rx_length_errors++; break; dev->stats.rx_over_errors++; case 0x1000: dev->stats.rx_frame_errors++; break; break; case 0x1800: dev->stats.rx_length_errors++; break; case 0x0800: case 0x2000: dev->stats.rx_frame_errors++; break; dev->stats.rx_length_errors++; case 0x2800: dev->stats.rx_crc_errors++; break; break; case 0x1000: dev->stats.rx_frame_errors++; break; case 0x1800: dev->stats.rx_length_errors++; break; case 0x2000: dev->stats.rx_frame_errors++; break; case 0x2800: dev->stats.rx_crc_errors++; break; } } } else { } else { short pkt_len = rx_status & 0x7ff; short pkt_len = rx_status & 0x7ff; Loading Loading
drivers/net/ethernet/3com/3c589_cs.c +584 −543 Original line number Original line Diff line number Diff line /* ====================================================================== /* ====================================================================== * A PCMCIA ethernet driver for the 3com 3c589 card. * A PCMCIA ethernet driver for the 3com 3c589 card. * Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net * Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net * 3c589_cs.c 1.162 2001/10/13 00:08:50 * 3c589_cs.c 1.162 2001/10/13 00:08:50 * The network driver code is based on Donald Becker's 3c589 code: * The network driver code is based on Donald Becker's 3c589 code: * Written 1994 by Donald Becker. * Written 1994 by Donald Becker. Copyright 1993 United States Government as represented by the * Copyright 1993 United States Government as represented by the Director, National Security Agency. This software may be used and * Director, National Security Agency. This software may be used and distributed according to the terms of the GNU General Public License, * distributed according to the terms of the GNU General Public License, incorporated herein by reference. * incorporated herein by reference. Donald Becker may be reached at becker@scyld.com * Donald Becker may be reached at becker@scyld.com * Updated for 2.5.x by Alan Cox <alan@lxorguk.ukuu.org.uk> * Updated for 2.5.x by Alan Cox <alan@lxorguk.ukuu.org.uk> * ======================================================================*/ * ====================================================================== */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt Loading @@ -41,18 +42,20 @@ #include <linux/ioport.h> #include <linux/ioport.h> #include <linux/bitops.h> #include <linux/bitops.h> #include <linux/jiffies.h> #include <linux/jiffies.h> #include <linux/uaccess.h> #include <linux/io.h> #include <pcmcia/cistpl.h> #include <pcmcia/cistpl.h> #include <pcmcia/cisreg.h> #include <pcmcia/cisreg.h> #include <pcmcia/ciscode.h> #include <pcmcia/ciscode.h> #include <pcmcia/ds.h> #include <pcmcia/ds.h> #include <asm/uaccess.h> #include <asm/io.h> /* To minimize the size of the driver source I only define operating /* To minimize the size of the driver source I only define operating constants if they are used several times. You'll need the manual * constants if they are used several times. You'll need the manual if you want to understand driver details. */ * if you want to understand driver details. */ /* Offsets from base I/O address. */ /* Offsets from base I/O address. */ #define EL3_DATA 0x00 #define EL3_DATA 0x00 #define EL3_TIMER 0x0a #define EL3_TIMER 0x0a Loading @@ -65,7 +68,9 @@ #define EL3WINDOW(win_num) outw(SelectWindow + (win_num), ioaddr + EL3_CMD) #define EL3WINDOW(win_num) outw(SelectWindow + (win_num), ioaddr + EL3_CMD) /* The top five bits written to EL3_CMD are a command, the lower /* The top five bits written to EL3_CMD are a command, the lower 11 bits are the parameter, if applicable. */ * 11 bits are the parameter, if applicable. */ enum c509cmd { enum c509cmd { TotalReset = 0<<11, TotalReset = 0<<11, SelectWindow = 1<<11, SelectWindow = 1<<11, Loading Loading @@ -253,7 +258,8 @@ static int tc589_config(struct pcmcia_device *link) /* For the 3c562, the base address must be xx00-xx7f */ /* For the 3c562, the base address must be xx00-xx7f */ for (i = j = 0; j < 0x400; j += 0x10) { for (i = j = 0; j < 0x400; j += 0x10) { if (multi && (j & 0x80)) continue; if (multi && (j & 0x80)) continue; link->resource[0]->start = j ^ 0x300; link->resource[0]->start = j ^ 0x300; i = pcmcia_request_io(link); i = pcmcia_request_io(link); if (i == 0) if (i == 0) Loading @@ -276,7 +282,8 @@ static int tc589_config(struct pcmcia_device *link) EL3WINDOW(0); EL3WINDOW(0); /* The 3c589 has an extra EEPROM for configuration info, including /* The 3c589 has an extra EEPROM for configuration info, including the hardware address. The 3c562 puts the address in the CIS. */ * the hardware address. The 3c562 puts the address in the CIS. */ len = pcmcia_get_tuple(link, 0x88, &buf); len = pcmcia_get_tuple(link, 0x88, &buf); if (buf && len >= 6) { if (buf && len >= 6) { for (i = 0; i < 3; i++) for (i = 0; i < 3; i++) Loading @@ -294,7 +301,9 @@ static int tc589_config(struct pcmcia_device *link) } } /* The address and resource configuration register aren't loaded from /* The address and resource configuration register aren't loaded from the EEPROM and *must* be set to 0 and IRQ3 for the PCMCIA version. */ * the EEPROM and *must* be set to 0 and IRQ3 for the PCMCIA version. */ outw(0x3f00, ioaddr + 8); outw(0x3f00, ioaddr + 8); fifo = inl(ioaddr); fifo = inl(ioaddr); Loading Loading @@ -353,23 +362,23 @@ static int tc589_resume(struct pcmcia_device *link) /*====================================================================*/ /*====================================================================*/ /* /* Use this for commands that may take time to finish */ Use this for commands that may take time to finish */ static void tc589_wait_for_completion(struct net_device *dev, int cmd) static void tc589_wait_for_completion(struct net_device *dev, int cmd) { { int i = 100; int i = 100; outw(cmd, dev->base_addr + EL3_CMD); outw(cmd, dev->base_addr + EL3_CMD); while (--i > 0) while (--i > 0) if (!(inw(dev->base_addr + EL3_STATUS) & 0x1000)) break; if (!(inw(dev->base_addr + EL3_STATUS) & 0x1000)) break; if (i == 0) if (i == 0) netdev_warn(dev, "command 0x%04x did not complete!\n", cmd); netdev_warn(dev, "command 0x%04x did not complete!\n", cmd); } } /* /* Read a word from the EEPROM using the regular EEPROM access register. Read a word from the EEPROM using the regular EEPROM access register. * Assume that we are in register window zero. Assume that we are in register window zero. */ */ static u16 read_eeprom(unsigned int ioaddr, int index) static u16 read_eeprom(unsigned int ioaddr, int index) { { int i; int i; Loading @@ -381,10 +390,10 @@ static u16 read_eeprom(unsigned int ioaddr, int index) return inw(ioaddr + 12); return inw(ioaddr + 12); } } /* /* Set transceiver type, perhaps to something other than what the user Set transceiver type, perhaps to something other than what the user * specified in dev->if_port. specified in dev->if_port. */ */ static void tc589_set_xcvr(struct net_device *dev, int if_port) static void tc589_set_xcvr(struct net_device *dev, int if_port) { { struct el3_private *lp = netdev_priv(dev); struct el3_private *lp = netdev_priv(dev); Loading @@ -392,9 +401,16 @@ static void tc589_set_xcvr(struct net_device *dev, int if_port) EL3WINDOW(0); EL3WINDOW(0); switch (if_port) { switch (if_port) { case 0: case 1: outw(0, ioaddr + 6); break; case 0: case 2: outw(3<<14, ioaddr + 6); break; case 1: case 3: outw(1<<14, ioaddr + 6); break; outw(0, ioaddr + 6); break; case 2: outw(3<<14, ioaddr + 6); break; case 3: outw(1<<14, ioaddr + 6); break; } } /* On PCMCIA, this just turns on the LED */ /* On PCMCIA, this just turns on the LED */ outw((if_port == 2) ? StartCoax : StopCoax, ioaddr + EL3_CMD); outw((if_port == 2) ? StartCoax : StopCoax, ioaddr + EL3_CMD); Loading Loading @@ -483,9 +499,10 @@ static int el3_config(struct net_device *dev, struct ifmap *map) dev->if_port = map->port; dev->if_port = map->port; netdev_info(dev, "switched to %s port\n", if_names[dev->if_port]); netdev_info(dev, "switched to %s port\n", if_names[dev->if_port]); tc589_set_xcvr(dev, dev->if_port); tc589_set_xcvr(dev, dev->if_port); } else } else { return -EINVAL; return -EINVAL; } } } return 0; return 0; } } Loading Loading @@ -535,7 +552,8 @@ static void pop_tx_status(struct net_device *dev) /* Clear the Tx status stack. */ /* Clear the Tx status stack. */ for (i = 32; i > 0; i--) { for (i = 32; i > 0; i--) { u_char tx_status = inb(ioaddr + TX_STATUS); u_char tx_status = inb(ioaddr + TX_STATUS); if (!(tx_status & 0x84)) break; if (!(tx_status & 0x84)) break; /* reset transmitter on jabber error or underrun */ /* reset transmitter on jabber error or underrun */ if (tx_status & 0x30) if (tx_status & 0x30) tc589_wait_for_completion(dev, TxReset); tc589_wait_for_completion(dev, TxReset); Loading Loading @@ -619,7 +637,8 @@ static irqreturn_t el3_interrupt(int irq, void *dev_id) /* Handle all uncommon interrupts. */ /* Handle all uncommon interrupts. */ if (status & StatsFull) /* Empty statistics. */ if (status & StatsFull) /* Empty statistics. */ update_stats(dev); update_stats(dev); if (status & RxEarly) { /* Rx early is unused. */ if (status & RxEarly) { /* Rx early is unused. */ el3_rx(dev); el3_rx(dev); outw(AckIntr | RxEarly, ioaddr + EL3_CMD); outw(AckIntr | RxEarly, ioaddr + EL3_CMD); } } Loading Loading @@ -669,10 +688,12 @@ static void media_check(unsigned long arg) u16 media, errs; u16 media, errs; unsigned long flags; unsigned long flags; if (!netif_device_present(dev)) goto reschedule; if (!netif_device_present(dev)) goto reschedule; /* Check for pending interrupt with expired latency timer: with /* Check for pending interrupt with expired latency timer: with this, we can limp along even if the interrupt is blocked */ * this, we can limp along even if the interrupt is blocked */ if ((inw(ioaddr + EL3_STATUS) & IntLatch) && if ((inw(ioaddr + EL3_STATUS) & IntLatch) && (inb(ioaddr + EL3_TIMER) == 0xff)) { (inb(ioaddr + EL3_TIMER) == 0xff)) { if (!lp->fast_poll) if (!lp->fast_poll) Loading @@ -692,7 +713,9 @@ static void media_check(unsigned long arg) } } /* lp->lock guards the EL3 window. Window should always be 1 except /* lp->lock guards the EL3 window. Window should always be 1 except when the lock is held */ * when the lock is held */ spin_lock_irqsave(&lp->lock, flags); spin_lock_irqsave(&lp->lock, flags); EL3WINDOW(4); EL3WINDOW(4); media = inw(ioaddr+WN4_MEDIA) & 0xc810; media = inw(ioaddr+WN4_MEDIA) & 0xc810; Loading @@ -707,7 +730,8 @@ static void media_check(unsigned long arg) errs = inb(ioaddr + 0); errs = inb(ioaddr + 0); outw(StatsEnable, ioaddr + EL3_CMD); outw(StatsEnable, ioaddr + EL3_CMD); dev->stats.tx_carrier_errors += errs; dev->stats.tx_carrier_errors += errs; if (errs || (lp->media_status & 0x0010)) media |= 0x0010; if (errs || (lp->media_status & 0x0010)) media |= 0x0010; } } if (media != lp->media_status) { if (media != lp->media_status) { Loading Loading @@ -757,14 +781,14 @@ static struct net_device_stats *el3_get_stats(struct net_device *dev) return &dev->stats; return &dev->stats; } } /* /* Update statistics. We change to register window 6, so this should be run Update statistics. We change to register window 6, so this should be run * single-threaded if the device is active. This is expected to be a rare single-threaded if the device is active. This is expected to be a rare * operation, and it's simpler for the rest of the driver to assume that operation, and it's simpler for the rest of the driver to assume that * window 1 is always valid rather than use a special window-state variable. window 1 is always valid rather than use a special window-state variable. * * Caller must hold the lock for this Caller must hold the lock for this */ */ static void update_stats(struct net_device *dev) static void update_stats(struct net_device *dev) { { unsigned int ioaddr = dev->base_addr; unsigned int ioaddr = dev->base_addr; Loading @@ -776,15 +800,20 @@ static void update_stats(struct net_device *dev) EL3WINDOW(6); EL3WINDOW(6); dev->stats.tx_carrier_errors += inb(ioaddr + 0); dev->stats.tx_carrier_errors += inb(ioaddr + 0); dev->stats.tx_heartbeat_errors += inb(ioaddr + 1); dev->stats.tx_heartbeat_errors += inb(ioaddr + 1); /* Multiple collisions. */ inb(ioaddr + 2); /* Multiple collisions. */ inb(ioaddr + 2); dev->stats.collisions += inb(ioaddr + 3); dev->stats.collisions += inb(ioaddr + 3); dev->stats.tx_window_errors += inb(ioaddr + 4); dev->stats.tx_window_errors += inb(ioaddr + 4); dev->stats.rx_fifo_errors += inb(ioaddr + 5); dev->stats.rx_fifo_errors += inb(ioaddr + 5); dev->stats.tx_packets += inb(ioaddr + 6); dev->stats.tx_packets += inb(ioaddr + 6); /* Rx packets */ inb(ioaddr + 7); /* Rx packets */ /* Tx deferrals */ inb(ioaddr + 8); inb(ioaddr + 7); /* Rx octets */ inw(ioaddr + 10); /* Tx deferrals */ /* Tx octets */ inw(ioaddr + 12); inb(ioaddr + 8); /* Rx octets */ inw(ioaddr + 10); /* Tx octets */ inw(ioaddr + 12); /* Back to window 1, and turn statistics back on. */ /* Back to window 1, and turn statistics back on. */ EL3WINDOW(1); EL3WINDOW(1); Loading @@ -806,12 +835,24 @@ static int el3_rx(struct net_device *dev) short error = rx_status & 0x3800; short error = rx_status & 0x3800; dev->stats.rx_errors++; dev->stats.rx_errors++; switch (error) { switch (error) { case 0x0000: dev->stats.rx_over_errors++; break; case 0x0000: case 0x0800: dev->stats.rx_length_errors++; break; dev->stats.rx_over_errors++; case 0x1000: dev->stats.rx_frame_errors++; break; break; case 0x1800: dev->stats.rx_length_errors++; break; case 0x0800: case 0x2000: dev->stats.rx_frame_errors++; break; dev->stats.rx_length_errors++; case 0x2800: dev->stats.rx_crc_errors++; break; break; case 0x1000: dev->stats.rx_frame_errors++; break; case 0x1800: dev->stats.rx_length_errors++; break; case 0x2000: dev->stats.rx_frame_errors++; break; case 0x2800: dev->stats.rx_crc_errors++; break; } } } else { } else { short pkt_len = rx_status & 0x7ff; short pkt_len = rx_status & 0x7ff; Loading