diff options
Diffstat (limited to 'drivers/net/3c515.c')
-rw-r--r-- | drivers/net/3c515.c | 1195 |
1 files changed, 623 insertions, 572 deletions
diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c index 5012dae6e..36f15f0cb 100644 --- a/drivers/net/3c515.c +++ b/drivers/net/3c515.c @@ -10,17 +10,22 @@ The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O Center of Excellence in Space Data and Information Sciences Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 + + Cleaned up for 2.3.x/softnet by Jeff Garzik and Alan Cox. */ -static char *version = "3c515.c:v0.99 4/7/98 becker@cesdis.gsfc.nasa.gov\n"; +static char *version = "3c515.c:v0.99-sn 2000/02/12 becker@cesdis.gsfc.nasa.gov and others\n"; + #define CORKSCREW 1 /* "Knobs" that adjust features and parameters. */ /* Set the copy breakpoint for the copy-only-tiny-frames scheme. Setting to > 1512 effectively disables this feature. */ static const int rx_copybreak = 200; + /* Allow setting MTU to a larger size, bypassing the normal ethernet setup. */ static const int mtu = 1500; + /* Maximum events (Rx packets, etc.) to handle at each interrupt. */ static int max_interrupt_work = 20; @@ -37,7 +42,7 @@ static int max_interrupt_work = 20; /* Keep the ring sizes a power of two for efficiency. */ #define TX_RING_SIZE 16 #define RX_RING_SIZE 16 -#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ +#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */ #include <linux/module.h> #include <linux/version.h> @@ -65,15 +70,10 @@ static int max_interrupt_work = 20; /* Kernel version compatibility functions. */ #define RUN_AT(x) (jiffies + (x)) -#define DEV_ALLOC_SKB(len) dev_alloc_skb(len + 2) -#define FREE_IRQ(irqnum, dev) free_irq(irqnum, dev) #define REQUEST_IRQ(i,h,f,n, instance) request_irq(i,h,f,n, instance) #define IRQ(irq, dev_id, pt_regs) (irq, dev_id, pt_regs) -#if (LINUX_VERSION_CODE < 0x20123) -#define test_and_set_bit(val, addr) set_bit(val, addr) -#elif defined(MODULE) MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>"); MODULE_DESCRIPTION("3Com 3c515 Corkscrew driver"); MODULE_PARM(debug, "i"); @@ -81,7 +81,6 @@ MODULE_PARM(options, "1-" __MODULE_STRING(8) "i"); MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i"); MODULE_PARM(rx_copybreak, "i"); MODULE_PARM(max_interrupt_work, "i"); -#endif /* "Knobs" for adjusting internal parameters. */ /* Put out somewhat more debugging messages. (0 - no msg, 1 minimal msgs). */ @@ -102,15 +101,10 @@ static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0; */ #define CORKSCREW_TOTAL_SIZE 0x20 -#ifdef HAVE_DEVLIST -struct netdev_entry tc515_drv = -{"3c515", tc515_probe, CORKSCREW_TOTAL_SIZE, NULL}; -#endif - #ifdef DRIVER_DEBUG -int vortex_debug = DRIVER_DEBUG; +int corkscrew_debug = DRIVER_DEBUG; #else -int vortex_debug = 1; +int corkscrew_debug = 1; #endif #define CORKSCREW_ID 10 @@ -149,8 +143,8 @@ correctly-sized skbuff. IIIC. Synchronization The driver runs as two independent, single-threaded flows of control. One -is the send-packet routine, which enforces single-threaded use by the -dev->tbusy flag. The other thread is the interrupt handler, which is single +is the send-packet routine, which enforces single-threaded use by the netif +layer. The other thread is the interrupt handler, which is single threaded by the hardware and other software. IV. Notes @@ -184,87 +178,98 @@ of 1.5K, but the changes to support 4.5K are minimal. can handle FDDI length frames (~4500 octets) and now parameters count 32-bit 'Dwords' rather than octets. */ -enum vortex_cmd { - TotalReset = 0<<11, SelectWindow = 1<<11, StartCoax = 2<<11, - RxDisable = 3<<11, RxEnable = 4<<11, RxReset = 5<<11, - UpStall = 6<<11, UpUnstall = (6<<11)+1, - DownStall = (6<<11)+2, DownUnstall = (6<<11)+3, - RxDiscard = 8<<11, TxEnable = 9<<11, TxDisable = 10<<11, TxReset = 11<<11, - FakeIntr = 12<<11, AckIntr = 13<<11, SetIntrEnb = 14<<11, - SetStatusEnb = 15<<11, SetRxFilter = 16<<11, SetRxThreshold = 17<<11, - SetTxThreshold = 18<<11, SetTxStart = 19<<11, - StartDMAUp = 20<<11, StartDMADown = (20<<11)+1, StatsEnable = 21<<11, - StatsDisable = 22<<11, StopCoax = 23<<11,}; +enum corkscrew_cmd { + TotalReset = 0 << 11, SelectWindow = 1 << 11, StartCoax = 2 << 11, + RxDisable = 3 << 11, RxEnable = 4 << 11, RxReset = 5 << 11, + UpStall = 6 << 11, UpUnstall = (6 << 11) + 1, + DownStall = (6 << 11) + 2, DownUnstall = (6 << 11) + 3, + RxDiscard = 8 << 11, TxEnable = 9 << 11, TxDisable = + 10 << 11, TxReset = 11 << 11, + FakeIntr = 12 << 11, AckIntr = 13 << 11, SetIntrEnb = 14 << 11, + SetStatusEnb = 15 << 11, SetRxFilter = 16 << 11, SetRxThreshold = + 17 << 11, + SetTxThreshold = 18 << 11, SetTxStart = 19 << 11, + StartDMAUp = 20 << 11, StartDMADown = (20 << 11) + 1, StatsEnable = + 21 << 11, + StatsDisable = 22 << 11, StopCoax = 23 << 11, +}; /* The SetRxFilter command accepts the following classes: */ enum RxFilter { - RxStation = 1, RxMulticast = 2, RxBroadcast = 4, RxProm = 8 }; + RxStation = 1, RxMulticast = 2, RxBroadcast = 4, RxProm = 8 +}; /* Bits in the general status register. */ -enum vortex_status { +enum corkscrew_status { IntLatch = 0x0001, AdapterFailure = 0x0002, TxComplete = 0x0004, TxAvailable = 0x0008, RxComplete = 0x0010, RxEarly = 0x0020, IntReq = 0x0040, StatsFull = 0x0080, - DMADone = 1<<8, DownComplete = 1<<9, UpComplete = 1<<10, - DMAInProgress = 1<<11, /* DMA controller is still busy.*/ - CmdInProgress = 1<<12, /* EL3_CMD is still busy.*/ + DMADone = 1 << 8, DownComplete = 1 << 9, UpComplete = 1 << 10, + DMAInProgress = 1 << 11, /* DMA controller is still busy. */ + CmdInProgress = 1 << 12, /* EL3_CMD is still busy. */ }; /* Register window 1 offsets, the window used in normal operation. On the Corkscrew this window is always mapped at offsets 0x10-0x1f. */ enum Window1 { - TX_FIFO = 0x10, RX_FIFO = 0x10, RxErrors = 0x14, - RxStatus = 0x18, Timer=0x1A, TxStatus = 0x1B, - TxFree = 0x1C, /* Remaining free bytes in Tx buffer. */ + TX_FIFO = 0x10, RX_FIFO = 0x10, RxErrors = 0x14, + RxStatus = 0x18, Timer = 0x1A, TxStatus = 0x1B, + TxFree = 0x1C, /* Remaining free bytes in Tx buffer. */ }; enum Window0 { - Wn0IRQ = 0x08, + Wn0IRQ = 0x08, #if defined(CORKSCREW) - Wn0EepromCmd = 0x200A, /* Corkscrew EEPROM command register. */ - Wn0EepromData = 0x200C, /* Corkscrew EEPROM results register. */ + Wn0EepromCmd = 0x200A, /* Corkscrew EEPROM command register. */ + Wn0EepromData = 0x200C, /* Corkscrew EEPROM results register. */ #else - Wn0EepromCmd = 10, /* Window 0: EEPROM command register. */ - Wn0EepromData = 12, /* Window 0: EEPROM results register. */ + Wn0EepromCmd = 10, /* Window 0: EEPROM command register. */ + Wn0EepromData = 12, /* Window 0: EEPROM results register. */ #endif }; enum Win0_EEPROM_bits { EEPROM_Read = 0x80, EEPROM_WRITE = 0x40, EEPROM_ERASE = 0xC0, - EEPROM_EWENB = 0x30, /* Enable erasing/writing for 10 msec. */ - EEPROM_EWDIS = 0x00, /* Disable EWENB before 10 msec timeout. */ + EEPROM_EWENB = 0x30, /* Enable erasing/writing for 10 msec. */ + EEPROM_EWDIS = 0x00, /* Disable EWENB before 10 msec timeout. */ }; + /* EEPROM locations. */ enum eeprom_offset { - PhysAddr01=0, PhysAddr23=1, PhysAddr45=2, ModelID=3, - EtherLink3ID=7, }; + PhysAddr01 = 0, PhysAddr23 = 1, PhysAddr45 = 2, ModelID = 3, + EtherLink3ID = 7, +}; enum Window3 { /* Window 3: MAC/config bits. */ - Wn3_Config=0, Wn3_MAC_Ctrl=6, Wn3_Options=8, + Wn3_Config = 0, Wn3_MAC_Ctrl = 6, Wn3_Options = 8, }; union wn3_config { int i; struct w3_config_fields { - unsigned int ram_size:3, ram_width:1, ram_speed:2, rom_size:2; + unsigned int ram_size:3, ram_width:1, ram_speed:2, + rom_size:2; int pad8:8; - unsigned int ram_split:2, pad18:2, xcvr:3, pad21:1, autoselect:1; + unsigned int ram_split:2, pad18:2, xcvr:3, pad21:1, + autoselect:1; int pad24:7; } u; }; enum Window4 { - Wn4_NetDiag = 6, Wn4_Media = 10, /* Window 4: Xcvr/media bits. */ + Wn4_NetDiag = 6, Wn4_Media = 10, /* Window 4: Xcvr/media bits. */ }; enum Win4_Media_bits { - Media_SQE = 0x0008, /* Enable SQE error counting for AUI. */ + Media_SQE = 0x0008, /* Enable SQE error counting for AUI. */ Media_10TP = 0x00C0, /* Enable link beat and jabber for 10baseT. */ - Media_Lnk = 0x0080, /* Enable just link beat for 100TX/100FX. */ + Media_Lnk = 0x0080, /* Enable just link beat for 100TX/100FX. */ Media_LnkBeat = 0x0800, }; -enum Window7 { /* Window 7: Bus Master control. */ +enum Window7 { /* Window 7: Bus Master control. */ Wn7_MasterAddr = 0, Wn7_MasterLen = 6, Wn7_MasterStatus = 12, }; + /* Boomerang-style bus master control registers. Note ISA aliases! */ enum MasterCtrl { - PktStatus = 0x400, DownListPtr = 0x404, FragAddr = 0x408, FragLen = 0x40c, + PktStatus = 0x400, DownListPtr = 0x404, FragAddr = 0x408, FragLen = + 0x40c, TxFreeThreshold = 0x40f, UpPktStatus = 0x410, UpListPtr = 0x418, }; @@ -277,9 +282,10 @@ struct boom_rx_desc { u32 addr; s32 length; }; + /* Values for the Rx status entry. */ enum rx_desc_status { - RxDComplete=0x00008000, RxDError=0x4000, + RxDComplete = 0x00008000, RxDError = 0x4000, /* See boomerang_rx() for actual error bits */ }; @@ -290,111 +296,112 @@ struct boom_tx_desc { s32 length; }; -struct vortex_private { - char devname[8]; /* "ethN" string, also for kernel debug. */ +struct corkscrew_private { + char devname[8]; /* "ethN" string, also for kernel debug. */ const char *product_name; struct net_device *next_module; /* The Rx and Tx rings are here to keep them quad-word-aligned. */ struct boom_rx_desc rx_ring[RX_RING_SIZE]; struct boom_tx_desc tx_ring[TX_RING_SIZE]; /* The addresses of transmit- and receive-in-place skbuffs. */ - struct sk_buff* rx_skbuff[RX_RING_SIZE]; - struct sk_buff* tx_skbuff[TX_RING_SIZE]; - unsigned int cur_rx, cur_tx; /* The next free ring entry */ - unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ + struct sk_buff *rx_skbuff[RX_RING_SIZE]; + struct sk_buff *tx_skbuff[TX_RING_SIZE]; + unsigned int cur_rx, cur_tx; /* The next free ring entry */ + unsigned int dirty_rx, dirty_tx;/* The ring entries to be free()ed. */ struct enet_statistics stats; - struct sk_buff *tx_skb; /* Packet being eaten by bus master ctrl. */ + struct sk_buff *tx_skb; /* Packet being eaten by bus master ctrl. */ struct timer_list timer; /* Media selection timer. */ - int capabilities; /* Adapter capabilities word. */ - int options; /* User-settable misc. driver options. */ + int capabilities ; /* Adapter capabilities word. */ + int options; /* User-settable misc. driver options. */ int last_rx_packets; /* For media autoselection. */ unsigned int available_media:8, /* From Wn3_Options */ - media_override:3, /* Passed-in media type. */ - default_media:3, /* Read from the EEPROM. */ - full_duplex:1, autoselect:1, - bus_master:1, /* Vortex can only do a fragment bus-m. */ - full_bus_master_tx:1, full_bus_master_rx:1, /* Boomerang */ - tx_full:1; + media_override:3, /* Passed-in media type. */ + default_media:3, /* Read from the EEPROM. */ + full_duplex:1, autoselect:1, bus_master:1, /* Vortex can only do a fragment bus-m. */ + full_bus_master_tx:1, full_bus_master_rx:1, /* Boomerang */ + tx_full:1; }; /* The action to take with a media selection timer tick. Note that we deviate from the 3Com order by checking 10base2 before AUI. */ enum xcvr_types { - XCVR_10baseT=0, XCVR_AUI, XCVR_10baseTOnly, XCVR_10base2, XCVR_100baseTx, - XCVR_100baseFx, XCVR_MII=6, XCVR_Default=8, + XCVR_10baseT = + 0, XCVR_AUI, XCVR_10baseTOnly, XCVR_10base2, XCVR_100baseTx, + XCVR_100baseFx, XCVR_MII = 6, XCVR_Default = 8, }; static struct media_table { - char *name; - unsigned int media_bits:16, /* Bits to set in Wn4_Media register. */ - mask:8, /* The transceiver-present bit in Wn3_Config.*/ - next:8; /* The media type to try next. */ - short wait; /* Time before we check media status. */ -} media_tbl[] = { - { "10baseT", Media_10TP,0x08, XCVR_10base2, (14*HZ)/10}, - { "10Mbs AUI", Media_SQE, 0x20, XCVR_Default, (1*HZ)/10}, - { "undefined", 0, 0x80, XCVR_10baseT, 10000}, - { "10base2", 0, 0x10, XCVR_AUI, (1*HZ)/10}, - { "100baseTX", Media_Lnk, 0x02, XCVR_100baseFx, (14*HZ)/10}, - { "100baseFX", Media_Lnk, 0x04, XCVR_MII, (14*HZ)/10}, - { "MII", 0, 0x40, XCVR_10baseT, 3*HZ }, - { "undefined", 0, 0x01, XCVR_10baseT, 10000}, - { "Default", 0, 0xFF, XCVR_10baseT, 10000}, + char *name; + unsigned int media_bits:16, /* Bits to set in Wn4_Media register. */ + mask:8, /* The transceiver-present bit in Wn3_Config. */ + next:8; /* The media type to try next. */ + short wait; /* Time before we check media status. */ +} media_tbl[] = { + { "10baseT", Media_10TP, 0x08, XCVR_10base2, (14 * HZ) / 10 }, + { "10Mbs AUI", Media_SQE, 0x20, XCVR_Default, (1 * HZ) / 10}, + { "undefined", 0, 0x80, XCVR_10baseT, 10000}, + { "10base2", 0, 0x10, XCVR_AUI, (1 * HZ) / 10}, + { "100baseTX", Media_Lnk, 0x02, XCVR_100baseFx, (14 * HZ) / 10}, + { "100baseFX", Media_Lnk, 0x04, XCVR_MII, (14 * HZ) / 10}, + { "MII", 0, 0x40, XCVR_10baseT, 3 * HZ}, + { "undefined", 0, 0x01, XCVR_10baseT, 10000}, + { "Default", 0, 0xFF, XCVR_10baseT, 10000}, }; -static int vortex_scan(struct net_device *dev); -static struct net_device *vortex_found_device(struct net_device *dev, int ioaddr, - int irq, int product_index, - int options); -static int vortex_probe1(struct net_device *dev); -static int vortex_open(struct net_device *dev); -static void vortex_timer(unsigned long arg); -static int vortex_start_xmit(struct sk_buff *skb, struct net_device *dev); -static int vortex_rx(struct net_device *dev); +static int corkscrew_scan(struct net_device *dev); +static struct net_device *corkscrew_found_device(struct net_device *dev, + int ioaddr, int irq, + int product_index, + int options); +static int corkscrew_probe1(struct net_device *dev); +static int corkscrew_open(struct net_device *dev); +static void corkscrew_timer(unsigned long arg); +static int corkscrew_start_xmit(struct sk_buff *skb, + struct net_device *dev); +static int corkscrew_rx(struct net_device *dev); +static void corkscrew_timeout(struct net_device *dev); static int boomerang_rx(struct net_device *dev); -static void vortex_interrupt IRQ(int irq, void *dev_id, struct pt_regs *regs); -static int vortex_close(struct net_device *dev); +static void corkscrew_interrupt(int irq, void *dev_id, + struct pt_regs *regs); +static int corkscrew_close(struct net_device *dev); static void update_stats(int addr, struct net_device *dev); -static struct enet_statistics *vortex_get_stats(struct net_device *dev); +static struct enet_statistics *corkscrew_get_stats(struct net_device *dev); static void set_rx_mode(struct net_device *dev); -/* Unlike the other PCI cards the 59x cards don't need a large contiguous - memory region, so making the driver a loadable module is feasible. - +/* Unfortunately maximizing the shared code between the integrated and module version of the driver results in a complicated set of initialization procedures. init_module() -- modules / tc59x_init() -- built-in - The wrappers for vortex_scan() - vortex_scan() The common routine that scans for PCI and EISA cards - vortex_found_device() Allocate a device structure when we find a card. + The wrappers for corkscrew_scan() + corkscrew_scan() The common routine that scans for PCI and EISA cards + corkscrew_found_device() Allocate a device structure when we find a card. Different versions exist for modules and built-in. - vortex_probe1() Fill in the device structure -- this is separated + corkscrew_probe1() Fill in the device structure -- this is separated so that the modules code can put it in dev->init. */ /* This driver uses 'options' to pass the media type, full-duplex flag, etc. */ /* Note: this is the only limit on the number of cards supported!! */ -static int options[8] = { -1, -1, -1, -1, -1, -1, -1, -1,}; +static int options[8] = { -1, -1, -1, -1, -1, -1, -1, -1, }; #ifdef MODULE static int debug = -1; /* A list of all installed Vortex devices, for removing the driver module. */ -static struct net_device *root_vortex_dev = NULL; +static struct net_device *root_corkscrew_dev = NULL; -int -init_module(void) +int init_module(void) { int cards_found; if (debug >= 0) - vortex_debug = debug; - if (vortex_debug) + corkscrew_debug = debug; + if (corkscrew_debug) printk(version); - root_vortex_dev = NULL; - cards_found = vortex_scan(0); + root_corkscrew_dev = NULL; + cards_found = corkscrew_scan(0); return cards_found ? 0 : -ENODEV; } @@ -403,80 +410,86 @@ int tc515_probe(struct net_device *dev) { int cards_found = 0; - cards_found = vortex_scan(dev); + cards_found = corkscrew_scan(dev); - if (vortex_debug > 0 && cards_found) + if (corkscrew_debug > 0 && cards_found) printk(version); return cards_found ? 0 : -ENODEV; } -#endif /* not MODULE */ +#endif /* not MODULE */ -static int vortex_scan(struct net_device *dev) +static int corkscrew_scan(struct net_device *dev) { int cards_found = 0; static int ioaddr = 0x100; /* Check all locations on the ISA bus -- evil! */ for (; ioaddr < 0x400; ioaddr += 0x20) { - int irq; - if (check_region(ioaddr, CORKSCREW_TOTAL_SIZE)) - continue; - /* Check the resource configuration for a matching ioaddr. */ - if ((inw(ioaddr + 0x2002) & 0x1f0) != (ioaddr & 0x1f0)) - continue; - /* Verify by reading the device ID from the EEPROM. */ - { - int timer; - outw(EEPROM_Read + 7, ioaddr + Wn0EepromCmd); - /* Pause for at least 162 us. for the read to take place. */ - for (timer = 4; timer >= 0; timer--) { - udelay(162); - if ((inw(ioaddr + Wn0EepromCmd) & 0x0200) == 0) - break; + int irq; + if (check_region(ioaddr, CORKSCREW_TOTAL_SIZE)) + continue; + /* Check the resource configuration for a matching ioaddr. */ + if ((inw(ioaddr + 0x2002) & 0x1f0) != (ioaddr & 0x1f0)) + continue; + /* Verify by reading the device ID from the EEPROM. */ + { + int timer; + outw(EEPROM_Read + 7, ioaddr + Wn0EepromCmd); + /* Pause for at least 162 us. for the read to take place. */ + for (timer = 4; timer >= 0; timer--) { + udelay(162); + if ((inw(ioaddr + Wn0EepromCmd) & 0x0200) + == 0) + break; + } + if (inw(ioaddr + Wn0EepromData) != 0x6d50) + continue; } - if (inw(ioaddr + Wn0EepromData) != 0x6d50) - continue; - } - printk("3c515 Resource configuraiton register %#4.4x, DCR %4.4x.\n", - inl(ioaddr + 0x2002), inw(ioaddr + 0x2000)); - irq = inw(ioaddr + 0x2002) & 15; - vortex_found_device(dev, ioaddr, irq, CORKSCREW_ID, dev && dev->mem_start - ? dev->mem_start : options[cards_found]); - dev = 0; - cards_found++; + printk(KERN_INFO "3c515 Resource configuraiton register %#4.4x, DCR %4.4x.\n", + inl(ioaddr + 0x2002), inw(ioaddr + 0x2000)); + irq = inw(ioaddr + 0x2002) & 15; + corkscrew_found_device(dev, ioaddr, irq, CORKSCREW_ID, dev + && dev->mem_start ? dev-> + mem_start : options[cards_found]); + dev = 0; + cards_found++; } - if (vortex_debug) - printk("%d 3c515 cards found.\n", cards_found); + if (corkscrew_debug) + printk(KERN_INFO "%d 3c515 cards found.\n", cards_found); return cards_found; } -static struct net_device *vortex_found_device(struct net_device *dev, int ioaddr, - int irq, int product_index, - int options) +static struct net_device *corkscrew_found_device(struct net_device *dev, + int ioaddr, int irq, + int product_index, + int options) { - struct vortex_private *vp; + struct corkscrew_private *vp; #ifdef MODULE /* Allocate and fill new device structure. */ int dev_size = sizeof(struct net_device) + - sizeof(struct vortex_private) + 15; /* Pad for alignment */ - + sizeof(struct corkscrew_private) + 15; /* Pad for alignment */ + dev = (struct net_device *) kmalloc(dev_size, GFP_KERNEL); memset(dev, 0, dev_size); /* Align the Rx and Tx ring entries. */ - dev->priv = (void *)(((long)dev + sizeof(struct net_device) + 15) & ~15); - vp = (struct vortex_private *)dev->priv; - dev->name = vp->devname; /* An empty string. */ + dev->priv = + (void *) (((long) dev + sizeof(struct net_device) + 15) & ~15); + vp = (struct corkscrew_private *) dev->priv; + dev->name = vp->devname; /* An empty string. */ dev->base_addr = ioaddr; dev->irq = irq; - dev->dma = (product_index == CORKSCREW_ID ? inw(ioaddr + 0x2000) & 7 : 0); - dev->init = vortex_probe1; + dev->dma = + (product_index == CORKSCREW_ID ? inw(ioaddr + 0x2000) & 7 : 0); + dev->init = corkscrew_probe1; vp->product_name = "3c515"; vp->options = options; if (options >= 0) { - vp->media_override = ((options & 7) == 2) ? 0 : options & 7; + vp->media_override = + ((options & 7) == 2) ? 0 : options & 7; vp->full_duplex = (options & 8) ? 1 : 0; vp->bus_master = (options & 16) ? 1 : 0; } else { @@ -485,25 +498,28 @@ static struct net_device *vortex_found_device(struct net_device *dev, int ioaddr vp->bus_master = 0; } ether_setup(dev); - vp->next_module = root_vortex_dev; - root_vortex_dev = dev; + vp->next_module = root_corkscrew_dev; + root_corkscrew_dev = dev; if (register_netdev(dev) != 0) return 0; -#else /* not a MODULE */ +#else /* not a MODULE */ if (dev) { /* Caution: quad-word alignment required for rings! */ - dev->priv = kmalloc(sizeof (struct vortex_private), GFP_KERNEL); - memset(dev->priv, 0, sizeof (struct vortex_private)); + dev->priv = + kmalloc(sizeof(struct corkscrew_private), GFP_KERNEL); + memset(dev->priv, 0, sizeof(struct corkscrew_private)); } - dev = init_etherdev(dev, sizeof(struct vortex_private)); + dev = init_etherdev(dev, sizeof(struct corkscrew_private)); dev->base_addr = ioaddr; dev->irq = irq; - dev->dma = (product_index == CORKSCREW_ID ? inw(ioaddr + 0x2000) & 7 : 0); - vp = (struct vortex_private *)dev->priv; + dev->dma = + (product_index == CORKSCREW_ID ? inw(ioaddr + 0x2000) & 7 : 0); + vp = (struct corkscrew_private *) dev->priv; vp->product_name = "3c515"; vp->options = options; if (options >= 0) { - vp->media_override = ((options & 7) == 2) ? 0 : options & 7; + vp->media_override = + ((options & 7) == 2) ? 0 : options & 7; vp->full_duplex = (options & 8) ? 1 : 0; vp->bus_master = (options & 16) ? 1 : 0; } else { @@ -512,25 +528,26 @@ static struct net_device *vortex_found_device(struct net_device *dev, int ioaddr vp->bus_master = 0; } - vortex_probe1(dev); -#endif /* MODULE */ + corkscrew_probe1(dev); +#endif /* MODULE */ return dev; } -static int vortex_probe1(struct net_device *dev) +static int corkscrew_probe1(struct net_device *dev) { int ioaddr = dev->base_addr; - struct vortex_private *vp = (struct vortex_private *)dev->priv; - unsigned int eeprom[0x40], checksum = 0; /* EEPROM contents */ + struct corkscrew_private *vp = + (struct corkscrew_private *) dev->priv; + unsigned int eeprom[0x40], checksum = 0; /* EEPROM contents */ int i; - printk("%s: 3Com %s at %#3x,", dev->name, - vp->product_name, ioaddr); + printk(KERN_INFO "%s: 3Com %s at %#3x,", dev->name, + vp->product_name, ioaddr); /* Read the station address from the EEPROM. */ EL3WINDOW(0); for (i = 0; i < 0x18; i++) { - short *phys_addr = (short *)dev->dev_addr; + short *phys_addr = (short *) dev->dev_addr; int timer; outw(EEPROM_Read + i, ioaddr + Wn0EepromCmd); /* Pause for at least 162 us. for the read to take place. */ @@ -549,97 +566,100 @@ static int vortex_probe1(struct net_device *dev) printk(" ***INVALID CHECKSUM %4.4x*** ", checksum); for (i = 0; i < 6; i++) printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i]); - if (eeprom[16] == 0x11c7) { /* Corkscrew */ - if (request_dma(dev->dma, "3c515")) { - printk(", DMA %d allocation failed", dev->dma); - dev->dma = 0; - } else - printk(", DMA %d", dev->dma); + if (eeprom[16] == 0x11c7) { /* Corkscrew */ + if (request_dma(dev->dma, "3c515")) { + printk(", DMA %d allocation failed", dev->dma); + dev->dma = 0; + } else + printk(", DMA %d", dev->dma); } printk(", IRQ %d\n", dev->irq); /* Tell them about an invalid IRQ. */ - if (vortex_debug && (dev->irq <= 0 || dev->irq > 15)) - printk(" *** Warning: this IRQ is unlikely to work! ***\n"); + if (corkscrew_debug && (dev->irq <= 0 || dev->irq > 15)) + printk(KERN_WARNING " *** Warning: this IRQ is unlikely to work! ***\n"); { - char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"}; + char *ram_split[] = { "5:3", "3:1", "1:1", "3:5" }; union wn3_config config; EL3WINDOW(3); vp->available_media = inw(ioaddr + Wn3_Options); config.i = inl(ioaddr + Wn3_Config); - if (vortex_debug > 1) - printk(" Internal config register is %4.4x, transceivers %#x.\n", - config.i, inw(ioaddr + Wn3_Options)); - printk(" %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n", - 8 << config.u.ram_size, - config.u.ram_width ? "word" : "byte", - ram_split[config.u.ram_split], - config.u.autoselect ? "autoselect/" : "", - media_tbl[config.u.xcvr].name); + if (corkscrew_debug > 1) + printk(KERN_INFO " Internal config register is %4.4x, transceivers %#x.\n", + config.i, inw(ioaddr + Wn3_Options)); + printk(KERN_INFO " %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n", + 8 << config.u.ram_size, + config.u.ram_width ? "word" : "byte", + ram_split[config.u.ram_split], + config.u.autoselect ? "autoselect/" : "", + media_tbl[config.u.xcvr].name); dev->if_port = config.u.xcvr; vp->default_media = config.u.xcvr; vp->autoselect = config.u.autoselect; } if (vp->media_override != 7) { - printk(" Media override to transceiver type %d (%s).\n", - vp->media_override, media_tbl[vp->media_override].name); + printk(KERN_INFO " Media override to transceiver type %d (%s).\n", + vp->media_override, + media_tbl[vp->media_override].name); dev->if_port = vp->media_override; } vp->capabilities = eeprom[16]; vp->full_bus_master_tx = (vp->capabilities & 0x20) ? 1 : 0; /* Rx is broken at 10mbps, so we always disable it. */ - /* vp->full_bus_master_rx = 0;*/ + /* vp->full_bus_master_rx = 0; */ vp->full_bus_master_rx = (vp->capabilities & 0x20) ? 1 : 0; /* We do a request_region() to register /proc/ioports info. */ request_region(ioaddr, CORKSCREW_TOTAL_SIZE, vp->product_name); - /* The 3c59x-specific entries in the device structure. */ - dev->open = &vortex_open; - dev->hard_start_xmit = &vortex_start_xmit; - dev->stop = &vortex_close; - dev->get_stats = &vortex_get_stats; + /* The 3c51x-specific entries in the device structure. */ + dev->open = &corkscrew_open; + dev->hard_start_xmit = &corkscrew_start_xmit; + dev->tx_timeout = &corkscrew_timeout; + dev->watchdog_timeo = (400 * HZ) / 1000; + dev->stop = &corkscrew_close; + dev->get_stats = &corkscrew_get_stats; dev->set_multicast_list = &set_rx_mode; return 0; } - -static int -vortex_open(struct net_device *dev) + +static int corkscrew_open(struct net_device *dev) { int ioaddr = dev->base_addr; - struct vortex_private *vp = (struct vortex_private *)dev->priv; + struct corkscrew_private *vp = + (struct corkscrew_private *) dev->priv; union wn3_config config; int i; /* Before initializing select the active media port. */ EL3WINDOW(3); if (vp->full_duplex) - outb(0x20, ioaddr + Wn3_MAC_Ctrl); /* Set the full-duplex bit. */ + outb(0x20, ioaddr + Wn3_MAC_Ctrl); /* Set the full-duplex bit. */ config.i = inl(ioaddr + Wn3_Config); if (vp->media_override != 7) { - if (vortex_debug > 1) - printk("%s: Media override to transceiver %d (%s).\n", - dev->name, vp->media_override, - media_tbl[vp->media_override].name); + if (corkscrew_debug > 1) + printk(KERN_INFO "%s: Media override to transceiver %d (%s).\n", + dev->name, vp->media_override, + media_tbl[vp->media_override].name); dev->if_port = vp->media_override; } else if (vp->autoselect) { /* Find first available media type, starting with 100baseTx. */ dev->if_port = 4; - while (! (vp->available_media & media_tbl[dev->if_port].mask)) + while (!(vp->available_media & media_tbl[dev->if_port].mask)) dev->if_port = media_tbl[dev->if_port].next; - if (vortex_debug > 1) + if (corkscrew_debug > 1) printk("%s: Initial media type %s.\n", - dev->name, media_tbl[dev->if_port].name); + dev->name, media_tbl[dev->if_port].name); init_timer(&vp->timer); vp->timer.expires = RUN_AT(media_tbl[dev->if_port].wait); - vp->timer.data = (unsigned long)dev; - vp->timer.function = &vortex_timer; /* timer handler */ + vp->timer.data = (unsigned long) dev; + vp->timer.function = &corkscrew_timer; /* timer handler */ add_timer(&vp->timer); } else dev->if_port = vp->default_media; @@ -647,63 +667,62 @@ vortex_open(struct net_device *dev) config.u.xcvr = dev->if_port; outl(config.i, ioaddr + Wn3_Config); - if (vortex_debug > 1) { - printk("%s: vortex_open() InternalConfig %8.8x.\n", - dev->name, config.i); + if (corkscrew_debug > 1) { + printk("%s: corkscrew_open() InternalConfig %8.8x.\n", + dev->name, config.i); } outw(TxReset, ioaddr + EL3_CMD); - for (i = 20; i >= 0 ; i--) - if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) + for (i = 20; i >= 0; i--) + if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress)) break; outw(RxReset, ioaddr + EL3_CMD); /* Wait a few ticks for the RxReset command to complete. */ - for (i = 20; i >= 0 ; i--) - if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) + for (i = 20; i >= 0; i--) + if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress)) break; outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD); /* Use the now-standard shared IRQ implementation. */ if (vp->capabilities == 0x11c7) { - /* Corkscrew: Cannot share ISA resources. */ - if (dev->irq == 0 - || dev->dma == 0 - || request_irq(dev->irq, &vortex_interrupt, 0, - vp->product_name, dev)) + /* Corkscrew: Cannot share ISA resources. */ + if (dev->irq == 0 + || dev->dma == 0 + || request_irq(dev->irq, &corkscrew_interrupt, 0, + vp->product_name, dev)) return -EAGAIN; + enable_dma(dev->dma); + set_dma_mode(dev->dma, DMA_MODE_CASCADE); + } else if (request_irq(dev->irq, &corkscrew_interrupt, SA_SHIRQ, + vp->product_name, dev)) { return -EAGAIN; - enable_dma(dev->dma); - set_dma_mode(dev->dma, DMA_MODE_CASCADE); - } else if (request_irq(dev->irq, &vortex_interrupt, SA_SHIRQ, - vp->product_name, dev)) { - return -EAGAIN; } - if (vortex_debug > 1) { + if (corkscrew_debug > 1) { EL3WINDOW(4); - printk("%s: vortex_open() irq %d media status %4.4x.\n", - dev->name, dev->irq, inw(ioaddr + Wn4_Media)); + printk("%s: corkscrew_open() irq %d media status %4.4x.\n", + dev->name, dev->irq, inw(ioaddr + Wn4_Media)); } /* Set the station address and mask in window 2 each time opened. */ EL3WINDOW(2); for (i = 0; i < 6; i++) outb(dev->dev_addr[i], ioaddr + i); - for (; i < 12; i+=2) + for (; i < 12; i += 2) outw(0, ioaddr + i); if (dev->if_port == 3) - /* Start the thinnet transceiver. We should really wait 50ms...*/ + /* Start the thinnet transceiver. We should really wait 50ms... */ outw(StartCoax, ioaddr + EL3_CMD); EL3WINDOW(4); - outw((inw(ioaddr + Wn4_Media) & ~(Media_10TP|Media_SQE)) | - media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media); + outw((inw(ioaddr + Wn4_Media) & ~(Media_10TP | Media_SQE)) | + media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media); /* Switch to the stats window, and clear all stats by reading. */ outw(StatsDisable, ioaddr + EL3_CMD); EL3WINDOW(6); - for (i = 0; i < 10; i++) + for (i = 0; i < 10; i++) inb(ioaddr + i); inw(ioaddr + 10); inw(ioaddr + 12); @@ -716,32 +735,34 @@ vortex_open(struct net_device *dev) /* Switch to register set 7 for normal use. */ EL3WINDOW(7); - if (vp->full_bus_master_rx) { /* Boomerang bus master. */ + if (vp->full_bus_master_rx) { /* Boomerang bus master. */ vp->cur_rx = vp->dirty_rx = 0; - if (vortex_debug > 2) - printk("%s: Filling in the Rx ring.\n", dev->name); + if (corkscrew_debug > 2) + printk("%s: Filling in the Rx ring.\n", + dev->name); for (i = 0; i < RX_RING_SIZE; i++) { struct sk_buff *skb; if (i < (RX_RING_SIZE - 1)) - vp->rx_ring[i].next = virt_to_bus(&vp->rx_ring[i+1]); + vp->rx_ring[i].next = + virt_to_bus(&vp->rx_ring[i + 1]); else - vp->rx_ring[i].next = 0; + vp->rx_ring[i].next = 0; vp->rx_ring[i].status = 0; /* Clear complete bit. */ vp->rx_ring[i].length = PKT_BUF_SZ | 0x80000000; skb = dev_alloc_skb(PKT_BUF_SZ); vp->rx_skbuff[i] = skb; if (skb == NULL) - break; /* Bad news! */ - skb->dev = dev; /* Mark as being used by this device. */ + break; /* Bad news! */ + skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ vp->rx_ring[i].addr = virt_to_bus(skb->tail); } - vp->rx_ring[i-1].next = virt_to_bus(&vp->rx_ring[0]); /* Wrap the ring. */ + vp->rx_ring[i - 1].next = virt_to_bus(&vp->rx_ring[0]); /* Wrap the ring. */ outl(virt_to_bus(&vp->rx_ring[0]), ioaddr + UpListPtr); } - if (vp->full_bus_master_tx) { /* Boomerang bus master Tx. */ + if (vp->full_bus_master_tx) { /* Boomerang bus master Tx. */ vp->cur_tx = vp->dirty_tx = 0; - outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); /* Room for a packet. */ + outb(PKT_BUF_SZ >> 8, ioaddr + TxFreeThreshold); /* Room for a packet. */ /* Clear the Tx ring. */ for (i = 0; i < TX_RING_SIZE; i++) vp->tx_skbuff[i] = 0; @@ -749,175 +770,188 @@ vortex_open(struct net_device *dev) } /* Set receiver mode: presumably accept b-case and phys addr only. */ set_rx_mode(dev); - outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */ + outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */ - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; + netif_start_queue(dev); - outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */ - outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */ + outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */ + outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */ /* Allow status bits to be seen. */ - outw(SetStatusEnb | AdapterFailure|IntReq|StatsFull | - (vp->full_bus_master_tx ? DownComplete : TxAvailable) | - (vp->full_bus_master_rx ? UpComplete : RxComplete) | - (vp->bus_master ? DMADone : 0), - ioaddr + EL3_CMD); + outw(SetStatusEnb | AdapterFailure | IntReq | StatsFull | + (vp->full_bus_master_tx ? DownComplete : TxAvailable) | + (vp->full_bus_master_rx ? UpComplete : RxComplete) | + (vp->bus_master ? DMADone : 0), ioaddr + EL3_CMD); /* Ack all pending events, and set active indicator mask. */ outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq, - ioaddr + EL3_CMD); + ioaddr + EL3_CMD); outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull - | (vp->bus_master ? DMADone : 0) | UpComplete | DownComplete, - ioaddr + EL3_CMD); + | (vp->bus_master ? DMADone : 0) | UpComplete | DownComplete, + ioaddr + EL3_CMD); MOD_INC_USE_COUNT; return 0; } -static void vortex_timer(unsigned long data) +static void corkscrew_timer(unsigned long data) { #ifdef AUTOMEDIA - struct net_device *dev = (struct net_device *)data; - struct vortex_private *vp = (struct vortex_private *)dev->priv; + struct net_device *dev = (struct net_device *) data; + struct corkscrew_private *vp = + (struct corkscrew_private *) dev->priv; int ioaddr = dev->base_addr; unsigned long flags; int ok = 0; - if (vortex_debug > 1) + if (corkscrew_debug > 1) printk("%s: Media selection timer tick happened, %s.\n", - dev->name, media_tbl[dev->if_port].name); - - save_flags(flags); cli(); { - int old_window = inw(ioaddr + EL3_CMD) >> 13; - int media_status; - EL3WINDOW(4); - media_status = inw(ioaddr + Wn4_Media); - switch (dev->if_port) { - case 0: case 4: case 5: /* 10baseT, 100baseTX, 100baseFX */ - if (media_status & Media_LnkBeat) { - ok = 1; - if (vortex_debug > 1) - printk("%s: Media %s has link beat, %x.\n", - dev->name, media_tbl[dev->if_port].name, media_status); - } else if (vortex_debug > 1) - printk("%s: Media %s is has no link beat, %x.\n", - dev->name, media_tbl[dev->if_port].name, media_status); - - break; - default: /* Other media types handled by Tx timeouts. */ - if (vortex_debug > 1) - printk("%s: Media %s is has no indication, %x.\n", - dev->name, media_tbl[dev->if_port].name, media_status); - ok = 1; - } - if ( ! ok) { - union wn3_config config; + dev->name, media_tbl[dev->if_port].name); - do { - dev->if_port = media_tbl[dev->if_port].next; - } while ( ! (vp->available_media & media_tbl[dev->if_port].mask)); - if (dev->if_port == 8) { /* Go back to default. */ - dev->if_port = vp->default_media; - if (vortex_debug > 1) - printk("%s: Media selection failing, using default %s port.\n", - dev->name, media_tbl[dev->if_port].name); - } else { - if (vortex_debug > 1) - printk("%s: Media selection failed, now trying %s port.\n", - dev->name, media_tbl[dev->if_port].name); - vp->timer.expires = RUN_AT(media_tbl[dev->if_port].wait); - add_timer(&vp->timer); + save_flags(flags); + cli(); { + int old_window = inw(ioaddr + EL3_CMD) >> 13; + int media_status; + EL3WINDOW(4); + media_status = inw(ioaddr + Wn4_Media); + switch (dev->if_port) { + case 0: + case 4: + case 5: /* 10baseT, 100baseTX, 100baseFX */ + if (media_status & Media_LnkBeat) { + ok = 1; + if (corkscrew_debug > 1) + printk("%s: Media %s has link beat, %x.\n", + dev->name, + media_tbl[dev->if_port].name, + media_status); + } else if (corkscrew_debug > 1) + printk("%s: Media %s is has no link beat, %x.\n", + dev->name, + media_tbl[dev->if_port].name, + media_status); + + break; + default: /* Other media types handled by Tx timeouts. */ + if (corkscrew_debug > 1) + printk("%s: Media %s is has no indication, %x.\n", + dev->name, + media_tbl[dev->if_port].name, + media_status); + ok = 1; } - outw((media_status & ~(Media_10TP|Media_SQE)) | - media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media); + if (!ok) { + union wn3_config config; - EL3WINDOW(3); - config.i = inl(ioaddr + Wn3_Config); - config.u.xcvr = dev->if_port; - outl(config.i, ioaddr + Wn3_Config); - - outw(dev->if_port == 3 ? StartCoax : StopCoax, ioaddr + EL3_CMD); - } - EL3WINDOW(old_window); - } restore_flags(flags); - if (vortex_debug > 1) - printk("%s: Media selection timer finished, %s.\n", - dev->name, media_tbl[dev->if_port].name); - -#endif /* AUTOMEDIA*/ + do { + dev->if_port = + media_tbl[dev->if_port].next; + } + while (!(vp->available_media & media_tbl[dev->if_port].mask)); + + if (dev->if_port == 8) { /* Go back to default. */ + dev->if_port = vp->default_media; + if (corkscrew_debug > 1) + printk("%s: Media selection failing, using default %s port.\n", + dev->name, + media_tbl[dev->if_port].name); + } else { + if (corkscrew_debug > 1) + printk("%s: Media selection failed, now trying %s port.\n", + dev->name, + media_tbl[dev->if_port].name); + vp->timer.expires = RUN_AT(media_tbl[dev->if_port].wait); + add_timer(&vp->timer); + } + outw((media_status & ~(Media_10TP | Media_SQE)) | + media_tbl[dev->if_port].media_bits, + ioaddr + Wn4_Media); + + EL3WINDOW(3); + config.i = inl(ioaddr + Wn3_Config); + config.u.xcvr = dev->if_port; + outl(config.i, ioaddr + Wn3_Config); + + outw(dev->if_port == 3 ? StartCoax : StopCoax, + ioaddr + EL3_CMD); + } + EL3WINDOW(old_window); + } + restore_flags(flags); + if (corkscrew_debug > 1) + printk("%s: Media selection timer finished, %s.\n", + dev->name, media_tbl[dev->if_port].name); + +#endif /* AUTOMEDIA */ return; } -static int -vortex_start_xmit(struct sk_buff *skb, struct net_device *dev) +static void corkscrew_timeout(struct net_device *dev) { - struct vortex_private *vp = (struct vortex_private *)dev->priv; + int i; + struct corkscrew_private *vp = + (struct corkscrew_private *) dev->priv; int ioaddr = dev->base_addr; - if (dev->tbusy) { - int tickssofar = jiffies - dev->trans_start; - int i; - - /* Min. wait before assuming a Tx failed == 400ms. */ - - if (tickssofar < 400*HZ/1000) /* We probably aren't empty. */ - return 1; - printk("%s: transmit timed out, tx_status %2.2x status %4.4x.\n", - dev->name, inb(ioaddr + TxStatus), - inw(ioaddr + EL3_STATUS)); - /* Slight code bloat to be user friendly. */ - if ((inb(ioaddr + TxStatus) & 0x88) == 0x88) - printk("%s: Transmitter encountered 16 collisions -- network" - " network cable problem?\n", dev->name); + printk(KERN_WARNING + "%s: transmit timed out, tx_status %2.2x status %4.4x.\n", + dev->name, inb(ioaddr + TxStatus), + inw(ioaddr + EL3_STATUS)); + /* Slight code bloat to be user friendly. */ + if ((inb(ioaddr + TxStatus) & 0x88) == 0x88) + printk(KERN_WARNING + "%s: Transmitter encountered 16 collisions -- network" + " network cable problem?\n", dev->name); #ifndef final_version - printk(" Flags; bus-master %d, full %d; dirty %d current %d.\n", - vp->full_bus_master_tx, vp->tx_full, vp->dirty_tx, vp->cur_tx); - printk(" Down list %8.8x vs. %p.\n", inl(ioaddr + DownListPtr), - &vp->tx_ring[0]); - for (i = 0; i < TX_RING_SIZE; i++) { - printk(" %d: %p length %8.8x status %8.8x\n", i, - &vp->tx_ring[i], - vp->tx_ring[i].length, - vp->tx_ring[i].status); - } -#endif - /* Issue TX_RESET and TX_START commands. */ - outw(TxReset, ioaddr + EL3_CMD); - for (i = 20; i >= 0 ; i--) - if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) - break; - outw(TxEnable, ioaddr + EL3_CMD); - dev->trans_start = jiffies; - /* dev->tbusy = 0;*/ - vp->stats.tx_errors++; - vp->stats.tx_dropped++; - return 0; /* Yes, silently *drop* the packet! */ + printk(" Flags; bus-master %d, full %d; dirty %d current %d.\n", + vp->full_bus_master_tx, vp->tx_full, vp->dirty_tx, + vp->cur_tx); + printk(" Down list %8.8x vs. %p.\n", inl(ioaddr + DownListPtr), + &vp->tx_ring[0]); + for (i = 0; i < TX_RING_SIZE; i++) { + printk(" %d: %p length %8.8x status %8.8x\n", i, + &vp->tx_ring[i], + vp->tx_ring[i].length, vp->tx_ring[i].status); } +#endif + /* Issue TX_RESET and TX_START commands. */ + outw(TxReset, ioaddr + EL3_CMD); + for (i = 20; i >= 0; i--) + if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress)) + break; + outw(TxEnable, ioaddr + EL3_CMD); + dev->trans_start = jiffies; + vp->stats.tx_errors++; + vp->stats.tx_dropped++; + netif_wake_queue(dev); +} - /* Block a timer-based transmit from overlapping. This could better be - done with atomic_swap(1, dev->tbusy), but set_bit() works as well. - If this ever occurs the queue layer is doing something evil! */ - if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { - printk("%s: Transmitter access conflict.\n", dev->name); - return 1; - } +static int corkscrew_start_xmit(struct sk_buff *skb, + struct net_device *dev) +{ + struct corkscrew_private *vp = + (struct corkscrew_private *) dev->priv; + int ioaddr = dev->base_addr; + + /* Block a timer-based transmit from overlapping. */ - if (vp->full_bus_master_tx) { /* BOOMERANG bus-master */ + netif_stop_queue(dev); + + if (vp->full_bus_master_tx) { /* BOOMERANG bus-master */ /* Calculate the next Tx descriptor entry. */ int entry = vp->cur_tx % TX_RING_SIZE; struct boom_tx_desc *prev_entry; unsigned long flags, i; - if (vp->tx_full) /* No room to transmit with */ - return 1; + if (vp->tx_full) /* No room to transmit with */ + return 1; if (vp->cur_tx != 0) - prev_entry = &vp->tx_ring[(vp->cur_tx-1) % TX_RING_SIZE]; + prev_entry = + &vp->tx_ring[(vp->cur_tx - 1) % TX_RING_SIZE]; else - prev_entry = NULL; - if (vortex_debug > 3) + prev_entry = NULL; + if (corkscrew_debug > 3) printk("%s: Trying to send a packet, Tx index %d.\n", - dev->name, vp->cur_tx); + dev->name, vp->cur_tx); /* vp->tx_full = 1; */ vp->tx_skbuff[entry] = skb; vp->tx_ring[entry].next = 0; @@ -929,13 +963,15 @@ vortex_start_xmit(struct sk_buff *skb, struct net_device *dev) cli(); outw(DownStall, ioaddr + EL3_CMD); /* Wait for the stall to complete. */ - for (i = 20; i >= 0 ; i--) - if ( (inw(ioaddr + EL3_STATUS) & CmdInProgress) == 0) - break; + for (i = 20; i >= 0; i--) + if ((inw(ioaddr + EL3_STATUS) & CmdInProgress) == + 0) break; if (prev_entry) - prev_entry->next = virt_to_bus(&vp->tx_ring[entry]); + prev_entry->next = + virt_to_bus(&vp->tx_ring[entry]); if (inl(ioaddr + DownListPtr) == 0) { - outl(virt_to_bus(&vp->tx_ring[entry]), ioaddr + DownListPtr); + outl(virt_to_bus(&vp->tx_ring[entry]), + ioaddr + DownListPtr); queued_packet++; } outw(DownUnstall, ioaddr + EL3_CMD); @@ -944,10 +980,10 @@ vortex_start_xmit(struct sk_buff *skb, struct net_device *dev) vp->cur_tx++; if (vp->cur_tx - vp->dirty_tx > TX_RING_SIZE - 1) vp->tx_full = 1; - else { /* Clear previous interrupt enable. */ - if (prev_entry) - prev_entry->status &= ~0x80000000; - dev->tbusy = 0; + else { /* Clear previous interrupt enable. */ + if (prev_entry) + prev_entry->status &= ~0x80000000; + netif_wake_queue(dev); } dev->trans_start = jiffies; return 0; @@ -957,31 +993,32 @@ vortex_start_xmit(struct sk_buff *skb, struct net_device *dev) #ifdef VORTEX_BUS_MASTER if (vp->bus_master) { /* Set the bus-master controller to transfer the packet. */ - outl((int)(skb->data), ioaddr + Wn7_MasterAddr); + outl((int) (skb->data), ioaddr + Wn7_MasterAddr); outw((skb->len + 3) & ~3, ioaddr + Wn7_MasterLen); vp->tx_skb = skb; outw(StartDMADown, ioaddr + EL3_CMD); - /* dev->tbusy will be cleared at the DMADone interrupt. */ + /* queue will be woken at the DMADone interrupt. */ } else { /* ... and the packet rounded to a doubleword. */ outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2); - dev_kfree_skb (skb); + dev_kfree_skb(skb); if (inw(ioaddr + TxFree) > 1536) { - dev->tbusy = 0; + netif_wake_queue(dev); } else /* Interrupt us when the FIFO has room for max-sized packet. */ - outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD); + outw(SetTxThreshold + (1536 >> 2), + ioaddr + EL3_CMD); } #else /* ... and the packet rounded to a doubleword. */ outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2); - dev_kfree_skb (skb); + dev_kfree_skb(skb); if (inw(ioaddr + TxFree) > 1536) { - dev->tbusy = 0; + netif_wake_queue(dev); } else /* Interrupt us when the FIFO has room for max-sized packet. */ - outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD); -#endif /* bus master */ + outw(SetTxThreshold + (1536 >> 2), ioaddr + EL3_CMD); +#endif /* bus master */ dev->trans_start = jiffies; @@ -990,80 +1027,79 @@ vortex_start_xmit(struct sk_buff *skb, struct net_device *dev) short tx_status; int i = 4; - while (--i > 0 && (tx_status = inb(ioaddr + TxStatus)) > 0) { - if (tx_status & 0x3C) { /* A Tx-disabling error occurred. */ - if (vortex_debug > 2) - printk("%s: Tx error, status %2.2x.\n", - dev->name, tx_status); - if (tx_status & 0x04) vp->stats.tx_fifo_errors++; - if (tx_status & 0x38) vp->stats.tx_aborted_errors++; + while (--i > 0 && (tx_status = inb(ioaddr + TxStatus)) > 0) { + if (tx_status & 0x3C) { /* A Tx-disabling error occurred. */ + if (corkscrew_debug > 2) + printk("%s: Tx error, status %2.2x.\n", + dev->name, tx_status); + if (tx_status & 0x04) + vp->stats.tx_fifo_errors++; + if (tx_status & 0x38) + vp->stats.tx_aborted_errors++; if (tx_status & 0x30) { int j; outw(TxReset, ioaddr + EL3_CMD); - for (j = 20; j >= 0 ; j--) - if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) + for (j = 20; j >= 0; j--) + if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress)) break; } outw(TxEnable, ioaddr + EL3_CMD); } - outb(0x00, ioaddr + TxStatus); /* Pop the status stack. */ + outb(0x00, ioaddr + TxStatus); /* Pop the status stack. */ } } - vp->stats.tx_bytes+=skb->len; + vp->stats.tx_bytes += skb->len; return 0; } /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */ -static void vortex_interrupt IRQ(int irq, void *dev_id, struct pt_regs *regs) + +static void corkscrew_interrupt(int irq, void *dev_id, + struct pt_regs *regs) { /* Use the now-standard shared IRQ implementation. */ struct net_device *dev = dev_id; - struct vortex_private *lp; + struct corkscrew_private *lp; int ioaddr, status; int latency; int i = max_interrupt_work; - if (test_and_set_bit(0, (void*)&dev->interrupt)) { - printk("%s: Re-entering the interrupt handler.\n", dev->name); - return; - } - ioaddr = dev->base_addr; latency = inb(ioaddr + Timer); - lp = (struct vortex_private *)dev->priv; + lp = (struct corkscrew_private *) dev->priv; status = inw(ioaddr + EL3_STATUS); - if (vortex_debug > 4) - printk("%s: interrupt, status %4.4x, timer %d.\n", dev->name, - status, latency); + if (corkscrew_debug > 4) + printk("%s: interrupt, status %4.4x, timer %d.\n", + dev->name, status, latency); if ((status & 0xE000) != 0xE000) { - static int donedidthis=0; + static int donedidthis = 0; /* Some interrupt controllers store a bogus interrupt from boot-time. Ignore a single early interrupt, but don't hang the machine for other interrupt problems. */ if (donedidthis++ > 100) { - printk("%s: Bogus interrupt, bailing. Status %4.4x, start=%d.\n", - dev->name, status, dev->start); - FREE_IRQ(dev->irq, dev); + printk(KERN_ERR "%s: Bogus interrupt, bailing. Status %4.4x, start=%d.\n", + dev->name, status, netif_running(dev)); + free_irq(dev->irq, dev); } } do { - if (vortex_debug > 5) - printk("%s: In interrupt loop, status %4.4x.\n", - dev->name, status); + if (corkscrew_debug > 5) + printk("%s: In interrupt loop, status %4.4x.\n", + dev->name, status); if (status & RxComplete) - vortex_rx(dev); + corkscrew_rx(dev); if (status & TxAvailable) { - if (vortex_debug > 5) - printk(" TX room bit was handled.\n"); + if (corkscrew_debug > 5) + printk + (" TX room bit was handled.\n"); /* There's room in the FIFO for a full-sized packet. */ outw(AckIntr | TxAvailable, ioaddr + EL3_CMD); - dev->tbusy = 0; - mark_bh(NET_BH); + netif_wake_queue(dev); } if (status & DownComplete) { unsigned int dirty_tx = lp->dirty_tx; @@ -1071,28 +1107,29 @@ static void vortex_interrupt IRQ(int irq, void *dev_id, struct pt_regs *regs) while (lp->cur_tx - dirty_tx > 0) { int entry = dirty_tx % TX_RING_SIZE; if (inl(ioaddr + DownListPtr) == - virt_to_bus(&lp->tx_ring[entry])) - break; /* It still hasn't been processed. */ + virt_to_bus(&lp->tx_ring[entry])) + break; /* It still hasn't been processed. */ if (lp->tx_skbuff[entry]) { - dev_kfree_skb(lp->tx_skbuff[entry]); + dev_kfree_skb_irq(lp-> + tx_skbuff + [entry]); lp->tx_skbuff[entry] = 0; } dirty_tx++; } lp->dirty_tx = dirty_tx; outw(AckIntr | DownComplete, ioaddr + EL3_CMD); - if (lp->tx_full && (lp->cur_tx - dirty_tx <= TX_RING_SIZE - 1)) { - lp->tx_full= 0; - dev->tbusy = 0; - mark_bh(NET_BH); + if (lp->tx_full + && (lp->cur_tx - dirty_tx <= TX_RING_SIZE - 1)) { + lp->tx_full = 0; + netif_wake_queue(dev); } } #ifdef VORTEX_BUS_MASTER if (status & DMADone) { - outw(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */ - dev->tbusy = 0; - dev_kfree_skb (lp->tx_skb); /* Release the transfered buffer */ - mark_bh(NET_BH); + outw(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */ + dev_kfree_skb_irq(lp->tx_skb); /* Release the transfered buffer */ + netif_wake_queue(dev); } #endif if (status & UpComplete) { @@ -1101,32 +1138,36 @@ static void vortex_interrupt IRQ(int irq, void *dev_id, struct pt_regs *regs) } if (status & (AdapterFailure | RxEarly | StatsFull)) { /* Handle all uncommon interrupts at once. */ - if (status & RxEarly) { /* Rx early is unused. */ - vortex_rx(dev); + if (status & RxEarly) { /* Rx early is unused. */ + corkscrew_rx(dev); outw(AckIntr | RxEarly, ioaddr + EL3_CMD); } - if (status & StatsFull) { /* Empty statistics. */ + if (status & StatsFull) { /* Empty statistics. */ static int DoneDidThat = 0; - if (vortex_debug > 4) - printk("%s: Updating stats.\n", dev->name); + if (corkscrew_debug > 4) + printk("%s: Updating stats.\n", + dev->name); update_stats(ioaddr, dev); /* DEBUG HACK: Disable statistics as an interrupt source. */ /* This occurs when we have the wrong media type! */ - if (DoneDidThat == 0 && - inw(ioaddr + EL3_STATUS) & StatsFull) { + if (DoneDidThat == 0 && + inw(ioaddr + EL3_STATUS) & StatsFull) { int win, reg; printk("%s: Updating stats failed, disabling stats as an" - " interrupt source.\n", dev->name); + " interrupt source.\n", + dev->name); for (win = 0; win < 8; win++) { EL3WINDOW(win); printk("\n Vortex window %d:", win); for (reg = 0; reg < 16; reg++) - printk(" %2.2x", inb(ioaddr+reg)); + printk(" %2.2x", + inb(ioaddr + reg)); } EL3WINDOW(7); - outw(SetIntrEnb | TxAvailable | RxComplete | AdapterFailure - | UpComplete | DownComplete | TxComplete, - ioaddr + EL3_CMD); + outw(SetIntrEnb | TxAvailable | + RxComplete | AdapterFailure | + UpComplete | DownComplete | + TxComplete, ioaddr + EL3_CMD); DoneDidThat++; } } @@ -1135,139 +1176,150 @@ static void vortex_interrupt IRQ(int irq, void *dev_id, struct pt_regs *regs) outw(RxReset, ioaddr + EL3_CMD); /* Set the Rx filter to the current state. */ set_rx_mode(dev); - outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */ - outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD); + outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */ + outw(AckIntr | AdapterFailure, + ioaddr + EL3_CMD); } } if (--i < 0) { - printk("%s: Too much work in interrupt, status %4.4x. " - "Disabling functions (%4.4x).\n", - dev->name, status, SetStatusEnb | ((~status) & 0x7FE)); + printk(KERN_ERR "%s: Too much work in interrupt, status %4.4x. " + "Disabling functions (%4.4x).\n", dev->name, + status, SetStatusEnb | ((~status) & 0x7FE)); /* Disable all pending interrupts. */ - outw(SetStatusEnb | ((~status) & 0x7FE), ioaddr + EL3_CMD); + outw(SetStatusEnb | ((~status) & 0x7FE), + ioaddr + EL3_CMD); outw(AckIntr | 0x7FF, ioaddr + EL3_CMD); break; } /* Acknowledge the IRQ. */ outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD); - } while ((status = inw(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete)); + } while ((status = inw(ioaddr + EL3_STATUS)) & + (IntLatch | RxComplete)); - if (vortex_debug > 4) - printk("%s: exiting interrupt, status %4.4x.\n", dev->name, status); - - dev->interrupt = 0; - return; + if (corkscrew_debug > 4) + printk("%s: exiting interrupt, status %4.4x.\n", dev->name, + status); } -static int -vortex_rx(struct net_device *dev) +static int corkscrew_rx(struct net_device *dev) { - struct vortex_private *vp = (struct vortex_private *)dev->priv; + struct corkscrew_private *vp = (struct corkscrew_private *) dev->priv; int ioaddr = dev->base_addr; int i; short rx_status; - if (vortex_debug > 5) + if (corkscrew_debug > 5) printk(" In rx_packet(), status %4.4x, rx_status %4.4x.\n", - inw(ioaddr+EL3_STATUS), inw(ioaddr+RxStatus)); + inw(ioaddr + EL3_STATUS), inw(ioaddr + RxStatus)); while ((rx_status = inw(ioaddr + RxStatus)) > 0) { - if (rx_status & 0x4000) { /* Error, update stats. */ + if (rx_status & 0x4000) { /* Error, update stats. */ unsigned char rx_error = inb(ioaddr + RxErrors); - if (vortex_debug > 2) - printk(" Rx error: status %2.2x.\n", rx_error); + if (corkscrew_debug > 2) + printk(" Rx error: status %2.2x.\n", + rx_error); vp->stats.rx_errors++; - if (rx_error & 0x01) vp->stats.rx_over_errors++; - if (rx_error & 0x02) vp->stats.rx_length_errors++; - if (rx_error & 0x04) vp->stats.rx_frame_errors++; - if (rx_error & 0x08) vp->stats.rx_crc_errors++; - if (rx_error & 0x10) vp->stats.rx_length_errors++; + if (rx_error & 0x01) + vp->stats.rx_over_errors++; + if (rx_error & 0x02) + vp->stats.rx_length_errors++; + if (rx_error & 0x04) + vp->stats.rx_frame_errors++; + if (rx_error & 0x08) + vp->stats.rx_crc_errors++; + if (rx_error & 0x10) + vp->stats.rx_length_errors++; } else { /* The packet length: up to 4.5K!. */ short pkt_len = rx_status & 0x1fff; struct sk_buff *skb; - skb = DEV_ALLOC_SKB(pkt_len + 5); - if (vortex_debug > 4) + skb = dev_alloc_skb(pkt_len + 5 + 2); + if (corkscrew_debug > 4) printk("Receiving packet size %d status %4.4x.\n", - pkt_len, rx_status); + pkt_len, rx_status); if (skb != NULL) { skb->dev = dev; skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ /* 'skb_put()' points to the start of sk_buff data area. */ - insl(ioaddr + RX_FIFO, skb_put(skb, pkt_len), - (pkt_len + 3) >> 2); - outw(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */ + insl(ioaddr + RX_FIFO, + skb_put(skb, pkt_len), + (pkt_len + 3) >> 2); + outw(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */ skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); dev->last_rx = jiffies; vp->stats.rx_packets++; - vp->stats.rx_bytes+=skb->len; + vp->stats.rx_bytes += skb->len; /* Wait a limited time to go to next packet. */ for (i = 200; i >= 0; i--) - if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) + if (! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) break; continue; - } else if (vortex_debug) - printk("%s: Couldn't allocate a sk_buff of size %d.\n", - dev->name, pkt_len); + } else if (corkscrew_debug) + printk("%s: Couldn't allocate a sk_buff of size %d.\n", dev->name, pkt_len); } outw(RxDiscard, ioaddr + EL3_CMD); vp->stats.rx_dropped++; /* Wait a limited time to skip this packet. */ for (i = 200; i >= 0; i--) - if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) + if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress)) break; } - return 0; } -static int -boomerang_rx(struct net_device *dev) +static int boomerang_rx(struct net_device *dev) { - struct vortex_private *vp = (struct vortex_private *)dev->priv; + struct corkscrew_private *vp = + (struct corkscrew_private *) dev->priv; int entry = vp->cur_rx % RX_RING_SIZE; int ioaddr = dev->base_addr; int rx_status; - if (vortex_debug > 5) + if (corkscrew_debug > 5) printk(" In boomerang_rx(), status %4.4x, rx_status %4.4x.\n", - inw(ioaddr+EL3_STATUS), inw(ioaddr+RxStatus)); + inw(ioaddr + EL3_STATUS), inw(ioaddr + RxStatus)); while ((rx_status = vp->rx_ring[entry].status) & RxDComplete) { - if (rx_status & RxDError) { /* Error, update stats. */ + if (rx_status & RxDError) { /* Error, update stats. */ unsigned char rx_error = rx_status >> 16; - if (vortex_debug > 2) - printk(" Rx error: status %2.2x.\n", rx_error); + if (corkscrew_debug > 2) + printk(" Rx error: status %2.2x.\n", + rx_error); vp->stats.rx_errors++; - if (rx_error & 0x01) vp->stats.rx_over_errors++; - if (rx_error & 0x02) vp->stats.rx_length_errors++; - if (rx_error & 0x04) vp->stats.rx_frame_errors++; - if (rx_error & 0x08) vp->stats.rx_crc_errors++; - if (rx_error & 0x10) vp->stats.rx_length_errors++; + if (rx_error & 0x01) + vp->stats.rx_over_errors++; + if (rx_error & 0x02) + vp->stats.rx_length_errors++; + if (rx_error & 0x04) + vp->stats.rx_frame_errors++; + if (rx_error & 0x08) + vp->stats.rx_crc_errors++; + if (rx_error & 0x10) + vp->stats.rx_length_errors++; } else { /* The packet length: up to 4.5K!. */ short pkt_len = rx_status & 0x1fff; struct sk_buff *skb; - vp->stats.rx_bytes+=pkt_len; - if (vortex_debug > 4) + vp->stats.rx_bytes += pkt_len; + if (corkscrew_debug > 4) printk("Receiving packet size %d status %4.4x.\n", - pkt_len, rx_status); + pkt_len, rx_status); /* Check if the packet is long enough to just accept without copying to a properly sized skbuff. */ if (pkt_len < rx_copybreak - && (skb = DEV_ALLOC_SKB(pkt_len + 2)) != 0) { + && (skb = dev_alloc_skb(pkt_len + 4)) != 0) { skb->dev = dev; skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ /* 'skb_put()' points to the start of sk_buff data area. */ memcpy(skb_put(skb, pkt_len), - bus_to_virt(vp->rx_ring[entry].addr), - pkt_len); + bus_to_virt(vp->rx_ring[entry]. + addr), pkt_len); rx_copy++; - } else{ + } else { void *temp; /* Pass up the skbuff already on the Rx ring. */ skb = vp->rx_skbuff[entry]; @@ -1275,10 +1327,13 @@ boomerang_rx(struct net_device *dev) temp = skb_put(skb, pkt_len); /* Remove this checking code for final release. */ if (bus_to_virt(vp->rx_ring[entry].addr) != temp) - printk("%s: Warning -- the skbuff addresses do not match" - " in boomerang_rx: %p vs. %p / %p.\n", dev->name, - bus_to_virt(vp->rx_ring[entry].addr), - skb->head, temp); + printk("%s: Warning -- the skbuff addresses do not match" + " in boomerang_rx: %p vs. %p / %p.\n", + dev->name, + bus_to_virt(vp-> + rx_ring[entry]. + addr), skb->head, + temp); rx_nocopy++; } skb->protocol = eth_type_trans(skb, dev); @@ -1295,8 +1350,8 @@ boomerang_rx(struct net_device *dev) if (vp->rx_skbuff[entry] == NULL) { skb = dev_alloc_skb(PKT_BUF_SZ); if (skb == NULL) - break; /* Bad news! */ - skb->dev = dev; /* Mark as being used by this device. */ + break; /* Bad news! */ + skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ vp->rx_ring[entry].addr = virt_to_bus(skb->tail); vp->rx_skbuff[entry] = skb; @@ -1306,22 +1361,22 @@ boomerang_rx(struct net_device *dev) return 0; } -static int -vortex_close(struct net_device *dev) +static int corkscrew_close(struct net_device *dev) { - struct vortex_private *vp = (struct vortex_private *)dev->priv; + struct corkscrew_private *vp = + (struct corkscrew_private *) dev->priv; int ioaddr = dev->base_addr; int i; - dev->start = 0; - dev->tbusy = 1; + netif_stop_queue(dev); - if (vortex_debug > 1) { - printk("%s: vortex_close() status %4.4x, Tx status %2.2x.\n", - dev->name, inw(ioaddr + EL3_STATUS), inb(ioaddr + TxStatus)); - printk("%s: vortex close stats: rx_nocopy %d rx_copy %d" - " tx_queued %d.\n", - dev->name, rx_nocopy, rx_copy, queued_packet); + if (corkscrew_debug > 1) { + printk("%s: corkscrew_close() status %4.4x, Tx status %2.2x.\n", + dev->name, inw(ioaddr + EL3_STATUS), + inb(ioaddr + TxStatus)); + printk("%s: corkscrew close stats: rx_nocopy %d rx_copy %d" + " tx_queued %d.\n", dev->name, rx_nocopy, rx_copy, + queued_packet); } del_timer(&vp->timer); @@ -1337,28 +1392,20 @@ vortex_close(struct net_device *dev) /* Turn off thinnet power. Green! */ outw(StopCoax, ioaddr + EL3_CMD); -#ifdef SA_SHIRQ free_irq(dev->irq, dev); -#else - free_irq(dev->irq); - irq2dev_map[dev->irq] = 0; -#endif outw(SetIntrEnb | 0x0000, ioaddr + EL3_CMD); update_stats(ioaddr, dev); - if (vp->full_bus_master_rx) { /* Free Boomerang bus master Rx buffers. */ + if (vp->full_bus_master_rx) { /* Free Boomerang bus master Rx buffers. */ outl(0, ioaddr + UpListPtr); for (i = 0; i < RX_RING_SIZE; i++) if (vp->rx_skbuff[i]) { -#if LINUX_VERSION_CODE < 0x20100 - vp->rx_skbuff[i]->free = 1; -#endif - dev_kfree_skb (vp->rx_skbuff[i]); + dev_kfree_skb(vp->rx_skbuff[i]); vp->rx_skbuff[i] = 0; } } - if (vp->full_bus_master_tx) { /* Free Boomerang bus master Tx buffers. */ + if (vp->full_bus_master_tx) { /* Free Boomerang bus master Tx buffers. */ outl(0, ioaddr + DownListPtr); for (i = 0; i < TX_RING_SIZE; i++) if (vp->tx_skbuff[i]) { @@ -1372,13 +1419,13 @@ vortex_close(struct net_device *dev) return 0; } -static struct enet_statistics * -vortex_get_stats(struct net_device *dev) +static struct enet_statistics *corkscrew_get_stats(struct net_device *dev) { - struct vortex_private *vp = (struct vortex_private *)dev->priv; + struct corkscrew_private *vp = + (struct corkscrew_private *) dev->priv; unsigned long flags; - if (dev->start) { + if (netif_running(dev)) { save_flags(flags); cli(); update_stats(dev->base_addr, dev); @@ -1396,21 +1443,23 @@ vortex_get_stats(struct net_device *dev) */ static void update_stats(int ioaddr, struct net_device *dev) { - struct vortex_private *vp = (struct vortex_private *)dev->priv; + struct corkscrew_private *vp = + (struct corkscrew_private *) dev->priv; /* Unlike the 3c5x9 we need not turn off stats updates while reading. */ /* Switch to the stats window, and read everything. */ EL3WINDOW(6); - vp->stats.tx_carrier_errors += inb(ioaddr + 0); - vp->stats.tx_heartbeat_errors += inb(ioaddr + 1); - /* Multiple collisions. */ inb(ioaddr + 2); - vp->stats.collisions += inb(ioaddr + 3); - vp->stats.tx_window_errors += inb(ioaddr + 4); - vp->stats.rx_fifo_errors += inb(ioaddr + 5); - vp->stats.tx_packets += inb(ioaddr + 6); - vp->stats.tx_packets += (inb(ioaddr + 9)&0x30) << 4; - /* Rx packets */ inb(ioaddr + 7); /* Must read to clear */ - /* Tx deferrals */ inb(ioaddr + 8); + vp->stats.tx_carrier_errors += inb(ioaddr + 0); + vp->stats.tx_heartbeat_errors += inb(ioaddr + 1); + /* Multiple collisions. */ inb(ioaddr + 2); + vp->stats.collisions += inb(ioaddr + 3); + vp->stats.tx_window_errors += inb(ioaddr + 4); + vp->stats.rx_fifo_errors += inb(ioaddr + 5); + vp->stats.tx_packets += inb(ioaddr + 6); + vp->stats.tx_packets += (inb(ioaddr + 9) & 0x30) << 4; + /* Rx packets */ inb(ioaddr + 7); + /* Must read to clear */ + /* Tx deferrals */ inb(ioaddr + 8); /* Don't bother with register 9, an extension of registers 6&7. If we do use the 6&7 values the atomic update assumption above is invalid. */ @@ -1429,18 +1478,18 @@ static void update_stats(int ioaddr, struct net_device *dev) The Vortex chip has no documented multicast filter, so the only multicast setting is to receive all multicast frames. At least the chip has a very clean way to set the mode, unlike many others. */ -static void -set_rx_mode(struct net_device *dev) +static void set_rx_mode(struct net_device *dev) { int ioaddr = dev->base_addr; short new_mode; if (dev->flags & IFF_PROMISC) { - if (vortex_debug > 3) - printk("%s: Setting promiscuous mode.\n", dev->name); - new_mode = SetRxFilter|RxStation|RxMulticast|RxBroadcast|RxProm; - } else if ((dev->mc_list) || (dev->flags & IFF_ALLMULTI)) { - new_mode = SetRxFilter|RxStation|RxMulticast|RxBroadcast; + if (corkscrew_debug > 3) + printk("%s: Setting promiscuous mode.\n", + dev->name); + new_mode = SetRxFilter | RxStation | RxMulticast | RxBroadcast | RxProm; + } else if ((dev->mc_list) || (dev->flags & IFF_ALLMULTI)) { + new_mode = SetRxFilter | RxStation | RxMulticast | RxBroadcast; } else new_mode = SetRxFilter | RxStation | RxBroadcast; @@ -1448,24 +1497,26 @@ set_rx_mode(struct net_device *dev) } #ifdef MODULE -void -cleanup_module(void) +void cleanup_module(void) { struct net_device *next_dev; /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ - while (root_vortex_dev) { - next_dev = ((struct vortex_private *)root_vortex_dev->priv)->next_module; - if (root_vortex_dev->dma) - free_dma(root_vortex_dev->dma); - unregister_netdev(root_vortex_dev); - outw(TotalReset, root_vortex_dev->base_addr + EL3_CMD); - release_region(root_vortex_dev->base_addr, CORKSCREW_TOTAL_SIZE); - kfree(root_vortex_dev); - root_vortex_dev = next_dev; + while (root_corkscrew_dev) { + next_dev = + ((struct corkscrew_private *) root_corkscrew_dev-> + priv)->next_module; + if (root_corkscrew_dev->dma) + free_dma(root_corkscrew_dev->dma); + unregister_netdev(root_corkscrew_dev); + outw(TotalReset, root_corkscrew_dev->base_addr + EL3_CMD); + release_region(root_corkscrew_dev->base_addr, + CORKSCREW_TOTAL_SIZE); + kfree(root_corkscrew_dev); + root_corkscrew_dev = next_dev; } } -#endif /* MODULE */ +#endif /* MODULE */ /* * Local variables: |