diff options
Diffstat (limited to 'drivers/net')
180 files changed, 18046 insertions, 5508 deletions
diff --git a/drivers/net/3c503.c b/drivers/net/3c503.c index 0fd5ace88..61ad42513 100644 --- a/drivers/net/3c503.c +++ b/drivers/net/3c503.c @@ -53,8 +53,8 @@ static const char *version = #define WRD_COUNT 4 int el2_probe(struct net_device *dev); -int el2_pio_probe(struct net_device *dev); -int el2_probe1(struct net_device *dev, int ioaddr); +static int el2_pio_probe(struct net_device *dev); +static int el2_probe1(struct net_device *dev, int ioaddr); /* A zero-terminated list of I/O addresses to be probed in PIO mode. */ static unsigned int netcard_portlist[] __initdata = @@ -115,7 +115,7 @@ el2_probe(struct net_device *dev) /* Try all of the locations that aren't obviously empty. This touches a lot of locations, and is much riskier than the code above. */ -int __init +static int __init el2_pio_probe(struct net_device *dev) { int i; @@ -136,13 +136,14 @@ el2_pio_probe(struct net_device *dev) /* Probe for the Etherlink II card at I/O port base IOADDR, returning non-zero on success. If found, set the station address and memory parameters in DEVICE. */ -int __init +static int __init el2_probe1(struct net_device *dev, int ioaddr) { int i, iobase_reg, membase_reg, saved_406, wordlength, retval; static unsigned version_printed; unsigned long vendor_id; + /* FIXME: code reads ioaddr + 0x400, we request ioaddr + 16 */ if (!request_region(ioaddr, EL2_IO_EXTENT, dev->name)) return -EBUSY; @@ -250,7 +251,8 @@ el2_probe1(struct net_device *dev, int ioaddr) } #endif /* EL2MEMTEST */ - dev->mem_end = dev->rmem_end = dev->mem_start + EL2_MEMSIZE; + if (dev->mem_start) + dev->mem_end = dev->rmem_end = dev->mem_start + EL2_MEMSIZE; if (wordlength) { /* No Tx pages to skip over to get to Rx */ dev->rmem_start = dev->mem_start; diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c index e86b37d11..d838bb4f6 100644 --- a/drivers/net/3c505.c +++ b/drivers/net/3c505.c @@ -601,15 +601,16 @@ static void receive_packet(struct net_device *dev, int len) printk("%s: memory squeeze, dropping packet\n", dev->name); target = adapter->dma_buffer; adapter->current_dma.target = NULL; + return; + } + + skb_reserve(skb, 2); + target = skb_put(skb, rlen); + if (virt_to_bus(target + rlen) >= MAX_DMA_ADDRESS) { + adapter->current_dma.target = target; + target = adapter->dma_buffer; } else { - skb_reserve(skb, 2); - target = skb_put(skb, rlen); - if (virt_to_bus(target + rlen) >= MAX_DMA_ADDRESS) { - adapter->current_dma.target = target; - target = adapter->dma_buffer; - } else { - adapter->current_dma.target = NULL; - } + adapter->current_dma.target = NULL; } /* if this happens, we die */ diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index d8c40f537..db58e8b57 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -1,8 +1,8 @@ /* 3c509.c: A 3c509 EtherLink3 ethernet driver for linux. */ /* - Written 1993-1998 by Donald Becker. + Written 1993-2000 by Donald Becker. - Copyright 1994-1998 by Donald Becker. + Copyright 1994-2000 by Donald Becker. Copyright 1993 United States Government as represented by the Director, National Security Agency. This software may be used and distributed according to the terms of the GNU General Public License, @@ -39,9 +39,11 @@ v1.14 10/15/97 Avoided waiting..discard message for fast machines -djb v1.15 1/31/98 Faster recovery for Tx errors. -djb v1.16 2/3/98 Different ID port handling to avoid sound cards. -djb + v1.18 12Mar2001 Andrew Morton <andrewm@uow.edu.au> + - Avoid bogus detect of 3c590's (Andrzej Krzysztofowicz) + - Reviewed against 1.18 from scyld.com */ -static char *version = "3c509.c:1.16 (2.2) 2/3/98 becker@cesdis.gsfc.nasa.gov.\n"; /* A few values that may be tweaked. */ /* Time in jiffies before concluding the transmitter is hung. */ @@ -61,6 +63,7 @@ static int max_interrupt_work = 10; #include <linux/in.h> #include <linux/slab.h> #include <linux/ioport.h> +#include <linux/init.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/skbuff.h> @@ -71,10 +74,13 @@ static int max_interrupt_work = 10; #include <asm/io.h> #include <asm/irq.h> +static char versionA[] __initdata = "3c509.c:1.18 12Mar2001 becker@scyld.com\n"; +static char versionB[] __initdata = "http://www.scyld.com/network/3c509.html\n"; + #ifdef EL3_DEBUG -int el3_debug = EL3_DEBUG; +static int el3_debug = EL3_DEBUG; #else -int el3_debug = 2; +static int el3_debug = 2; #endif /* To minimize the size of the driver source I only define operating @@ -137,7 +143,7 @@ struct el3_private { struct sk_buff *queue[SKB_QUEUE_SIZE]; char mca_slot; }; -static int id_port = 0x110; /* Start with 0x110 to avoid new sound cards.*/ +static int id_port __initdata = 0x110; /* Start with 0x110 to avoid new sound cards.*/ static struct net_device *el3_root_dev = NULL; static ushort id_read_eeprom(int index); @@ -158,7 +164,7 @@ struct el3_mca_adapters_struct { int id; }; -struct el3_mca_adapters_struct el3_mca_adapters[] = { +static struct el3_mca_adapters_struct el3_mca_adapters[] __initdata = { { "3Com 3c529 EtherLink III (10base2)", 0x627c }, { "3Com 3c529 EtherLink III (10baseT)", 0x627d }, { "3Com 3c529 EtherLink III (test mode)", 0x62db }, @@ -166,29 +172,38 @@ struct el3_mca_adapters_struct el3_mca_adapters[] = { { "3Com 3c529 EtherLink III (TP)", 0x62f7 }, { NULL, 0 }, }; -#endif +#endif /* CONFIG_MCA */ -#ifdef __ISAPNP__ -struct el3_isapnp_adapters_struct { - unsigned short vendor, function; - char *name; -}; -static struct el3_isapnp_adapters_struct el3_isapnp_adapters[] = { - {ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5090), "3Com Etherlink III (TP)"}, - {ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5091), "3Com Etherlink III"}, - {ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5094), "3Com Etherlink III (combo)"}, - {ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5095), "3Com Etherlink III (TPO)"}, - {ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5098), "3Com Etherlink III (TPC)"}, - {ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_FUNCTION(0x80f8), "3Com Etherlink III compatible"}, - {0, } +#ifdef CONFIG_ISAPNP +static struct isapnp_device_id el3_isapnp_adapters[] __initdata = { + { ISAPNP_ANY_ID, ISAPNP_ANY_ID, + ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5090), + (long) "3Com Etherlink III (TP)" }, + { ISAPNP_ANY_ID, ISAPNP_ANY_ID, + ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5091), + (long) "3Com Etherlink III" }, + { ISAPNP_ANY_ID, ISAPNP_ANY_ID, + ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5094), + (long) "3Com Etherlink III (combo)" }, + { ISAPNP_ANY_ID, ISAPNP_ANY_ID, + ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5095), + (long) "3Com Etherlink III (TPO)" }, + { ISAPNP_ANY_ID, ISAPNP_ANY_ID, + ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5098), + (long) "3Com Etherlink III (TPC)" }, + { ISAPNP_ANY_ID, ISAPNP_ANY_ID, + ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_FUNCTION(0x80f8), + (long) "3Com Etherlink III compatible" }, + { } /* terminate list */ }; + +MODULE_DEVICE_TABLE(isapnp, el3_isapnp_adapters); + static u16 el3_isapnp_phys_addr[8][3]; -#endif /* CONFIG_ISAPNP */ -#ifdef __ISAPNP__ static int nopnp; -#endif +#endif /* CONFIG_ISAPNP */ -int el3_probe(struct net_device *dev) +int __init el3_probe(struct net_device *dev) { struct el3_private *lp; short lrs_state = 0xff, i; @@ -196,9 +211,9 @@ int el3_probe(struct net_device *dev) u16 phys_addr[3]; static int current_tag = 0; int mca_slot = -1; -#ifdef __ISAPNP__ +#ifdef CONFIG_ISAPNP static int pnp_cards = 0; -#endif /* __ISAPNP__ */ +#endif /* CONFIG_ISAPNP */ if (dev) SET_MODULE_OWNER(dev); @@ -207,6 +222,8 @@ int el3_probe(struct net_device *dev) if (EISA_bus) { static int eisa_addr = 0x1000; while (eisa_addr < 0x9000) { + int device_id; + ioaddr = eisa_addr; eisa_addr += 0x1000; @@ -214,6 +231,12 @@ int el3_probe(struct net_device *dev) if (inw(ioaddr + 0xC80) != 0x6d50) continue; + /* Avoid conflict with 3c590, 3c592, 3c597, etc */ + device_id = (inb(ioaddr + 0xC82)<<8) + inb(ioaddr + 0xC83); + if ((device_id & 0xFF00) == 0x5900) { + continue; + } + /* Change the register set to the configuration window 0. */ outw(SelectWindow | 0, ioaddr + 0xC80 + EL3_CMD); @@ -294,7 +317,7 @@ int el3_probe(struct net_device *dev) } #endif /* CONFIG_MCA */ -#ifdef __ISAPNP__ +#ifdef CONFIG_ISAPNP if (nopnp == 1) goto no_pnp; @@ -318,7 +341,7 @@ int el3_probe(struct net_device *dev) irq = idev->irq_resource[0].start; if (el3_debug > 3) printk ("ISAPnP reports %s at i/o 0x%x, irq %d\n", - el3_isapnp_adapters[i].name, ioaddr, irq); + (char*) el3_isapnp_adapters[i].driver_data, ioaddr, irq); EL3WINDOW(0); for (j = 0; j < 3; j++) el3_isapnp_phys_addr[pnp_cards][j] = @@ -330,7 +353,7 @@ int el3_probe(struct net_device *dev) } } no_pnp: -#endif /* __ISAPNP__ */ +#endif /* CONFIG_ISAPNP */ /* Select an open I/O location at 0x1*0 to do contention select. */ for ( ; id_port < 0x200; id_port += 0x10) { @@ -376,7 +399,7 @@ no_pnp: phys_addr[i] = htons(id_read_eeprom(i)); } -#ifdef __ISAPNP__ +#ifdef CONFIG_ISAPNP if (nopnp == 0) { /* The ISA PnP 3c509 cards respond to the ID sequence. This check is needed in order not to register them twice. */ @@ -396,7 +419,7 @@ no_pnp: } } } -#endif /* __ISAPNP__ */ +#endif /* CONFIG_ISAPNP */ { unsigned int iobase = id_read_eeprom(8); @@ -451,7 +474,7 @@ no_pnp: { const char *if_names[] = {"10baseT", "AUI", "undefined", "BNC"}; - printk("%s: 3c509 at %#3.3lx, %s port, address ", + printk("%s: 3c5x9 at %#3.3lx, %s port, address ", dev->name, dev->base_addr, if_names[dev->if_port]); } @@ -474,7 +497,7 @@ no_pnp: el3_root_dev = dev; if (el3_debug > 0) - printk(version); + printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB); /* The EL3-specific entries in the device structure. */ dev->open = &el3_open; @@ -493,7 +516,7 @@ no_pnp: /* Read a word from the EEPROM using the regular EEPROM access register. Assume that we are in register window zero. */ -static ushort read_eeprom(int ioaddr, int index) +static ushort __init read_eeprom(int ioaddr, int index) { outw(EEPROM_READ + index, ioaddr + 10); /* Pause for at least 162 us. for the read to take place. */ @@ -502,7 +525,7 @@ static ushort read_eeprom(int ioaddr, int index) } /* Read a word from the EEPROM when in the ISA ID probe state. */ -static ushort id_read_eeprom(int index) +static ushort __init id_read_eeprom(int index) { int bit, word = 0; @@ -984,7 +1007,7 @@ MODULE_PARM(debug,"i"); MODULE_PARM(irq,"1-8i"); MODULE_PARM(xcvr,"1-8i"); MODULE_PARM(max_interrupt_work, "i"); -#ifdef __ISAPNP__ +#ifdef CONFIG_ISAPNP MODULE_PARM(nopnp, "i"); #endif diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c index 1ce778c9b..cb517e169 100644 --- a/drivers/net/3c515.c +++ b/drivers/net/3c515.c @@ -46,6 +46,7 @@ static int max_interrupt_work = 20; #define RX_RING_SIZE 16 #define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */ +#include <linux/config.h> #include <linux/module.h> #include <linux/version.h> #include <linux/isapnp.h> @@ -105,9 +106,9 @@ static int rx_nocopy, rx_copy, queued_packet; #define CORKSCREW_TOTAL_SIZE 0x20 #ifdef DRIVER_DEBUG -int corkscrew_debug = DRIVER_DEBUG; +static int corkscrew_debug = DRIVER_DEBUG; #else -int corkscrew_debug = 1; +static int corkscrew_debug = 1; #endif #define CORKSCREW_ID 10 @@ -351,21 +352,20 @@ static struct media_table { { "Default", 0, 0xFF, XCVR_10baseT, 10000}, }; -#ifdef __ISAPNP__ -struct corkscrew_isapnp_adapters_struct { - unsigned short vendor, function; - char *name; -}; -struct corkscrew_isapnp_adapters_struct corkscrew_isapnp_adapters[] = { - {ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5051), "3Com Fast EtherLink ISA"}, - {0, } -}; -int corkscrew_isapnp_phys_addr[3] = { - 0, 0, 0 +#ifdef CONFIG_ISAPNP +static struct isapnp_device_id corkscrew_isapnp_adapters[] = { + { ISAPNP_ANY_ID, ISAPNP_ANY_ID, + ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5051), + (long) "3Com Fast EtherLink ISA" }, + { } /* terminate list */ }; +MODULE_DEVICE_TABLE(isapnp, corkscrew_isapnp_adapters); + +static int corkscrew_isapnp_phys_addr[3]; + static int nopnp; -#endif +#endif /* CONFIG_ISAPNP */ static int corkscrew_scan(struct net_device *dev); static struct net_device *corkscrew_found_device(struct net_device *dev, @@ -419,7 +419,7 @@ int init_module(void) printk(version); root_corkscrew_dev = NULL; - cards_found = corkscrew_scan(0); + cards_found = corkscrew_scan(NULL); return cards_found ? 0 : -ENODEV; } @@ -443,12 +443,12 @@ static int corkscrew_scan(struct net_device *dev) { int cards_found = 0; static int ioaddr; -#ifdef __ISAPNP__ +#ifdef CONFIG_ISAPNP short i; static int pnp_cards = 0; #endif -#ifdef __ISAPNP__ +#ifdef CONFIG_ISAPNP if(nopnp == 1) goto no_pnp; for(i=0; corkscrew_isapnp_adapters[i].vendor != 0; i++) { @@ -475,7 +475,7 @@ static int corkscrew_scan(struct net_device *dev) irq = idev->irq_resource[0].start; if(corkscrew_debug) printk ("ISAPNP reports %s at i/o 0x%x, irq %d\n", - corkscrew_isapnp_adapters[i].name,ioaddr, irq); + (char*) corkscrew_isapnp_adapters[i].driver_data, ioaddr, irq); if ((inw(ioaddr + 0x2002) & 0x1f0) != (ioaddr & 0x1f0)) continue; @@ -506,17 +506,17 @@ static int corkscrew_scan(struct net_device *dev) } } no_pnp: -#endif /* not __ISAPNP__ */ +#endif /* CONFIG_ISAPNP */ /* Check all locations on the ISA bus -- evil! */ for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x20) { int irq; -#ifdef __ISAPNP__ +#ifdef CONFIG_ISAPNP /* Make sure this was not already picked up by isapnp */ if(ioaddr == corkscrew_isapnp_phys_addr[0]) continue; if(ioaddr == corkscrew_isapnp_phys_addr[1]) continue; if(ioaddr == corkscrew_isapnp_phys_addr[2]) continue; -#endif +#endif /* CONFIG_ISAPNP */ if (check_region(ioaddr, CORKSCREW_TOTAL_SIZE)) continue; /* Check the resource configuration for a matching ioaddr. */ @@ -590,11 +590,11 @@ static struct net_device *corkscrew_found_device(struct net_device *dev, ether_setup(dev); vp->next_module = root_corkscrew_dev; root_corkscrew_dev = dev; + SET_MODULE_OWNER(dev); if (register_netdev(dev) != 0) { kfree(dev); return NULL; } - SET_MODULE_OWNER(dev); #else /* not a MODULE */ /* Caution: quad-word alignment required for rings! */ dev->priv = @@ -1219,7 +1219,7 @@ static void corkscrew_interrupt(int irq, void *dev_id, #ifdef VORTEX_BUS_MASTER if (status & DMADone) { outw(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */ - dev_kfree_skb_irq(lp->tx_skb); /* Release the transfered buffer */ + dev_kfree_skb_irq(lp->tx_skb); /* Release the transferred buffer */ netif_wake_queue(dev); } #endif diff --git a/drivers/net/3c523.h b/drivers/net/3c523.h index aa67b871d..7292f88b4 100644 --- a/drivers/net/3c523.h +++ b/drivers/net/3c523.h @@ -60,7 +60,7 @@ struct scb_struct unsigned short cbl_offset; /* pointeroffset, command block list */ unsigned short rfa_offset; /* pointeroffset, receive frame area */ unsigned short crc_errs; /* CRC-Error counter */ - unsigned short aln_errs; /* allignmenterror counter */ + unsigned short aln_errs; /* alignmenterror counter */ unsigned short rsc_errs; /* Resourceerror counter */ unsigned short ovrn_errs; /* OVerrunerror counter */ }; diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c index 45a6a1a72..14973ed0f 100644 --- a/drivers/net/3c527.c +++ b/drivers/net/3c527.c @@ -1,8 +1,9 @@ -/* 3c527.c: 3Com Etherlink/MC32 driver for Linux +/* 3c527.c: 3Com Etherlink/MC32 driver for Linux 2.4 * * (c) Copyright 1998 Red Hat Software Inc - * Written by Alan Cox. + * Written by Alan Cox. * Further debugging by Carl Drougge. + * Modified by Richard Procter (rnp@netlink.co.nz) * * Based on skeleton.c written 1993-94 by Donald Becker and ne2.c * (for the MCA stuff) written by Wim Dumon. @@ -16,7 +17,7 @@ */ static const char *version = - "3c527.c:v0.08 2000/02/22 Alan Cox (alan@redhat.com)\n"; + "3c527.c:v0.6 2001/03/03 Richard Proctor (rnp@netlink.co.nz)\n"; /** * DOC: Traps for the unwary @@ -24,6 +25,13 @@ static const char *version = * The diagram (Figure 1-1) and the POS summary disagree with the * "Interrupt Level" section in the manual. * + * The manual contradicts itself when describing the minimum number + * buffers in the 'configure lists' command. + * My card accepts a buffer config of 4/4. + * + * Setting the SAV BP bit does not save bad packets, but + * only enables RX on-card stats collection. + * * The documentation in places seems to miss things. In actual fact * I've always eventually found everything is documented, it just * requires careful study. @@ -35,25 +43,39 @@ static const char *version = * Intel NIC. For performance we want to keep the transmit queue deep * as the card can transmit packets while fetching others from main * memory by bus master DMA. Transmission and reception are driven by - * ring buffers. When updating the ring we are required to do some - * housekeeping work using the mailboxes and the command register. - * - * The mailboxes provide a method for sending control requests to the - * card. The transmit mail box is used to update the transmit ring - * pointers and the receive mail box to update the receive ring - * pointers. The exec mailbox allows a variety of commands to be - * executed. Each command must complete before the next is executed. - * Primarily we use the exec mailbox for controlling the multicast lists. - * We have to do a certain amount of interesting hoop jumping as the - * multicast list changes can occur in interrupt state when the card - * has an exec command pending. We defer such events until the command - * completion interrupt. - * - * The control register is used to pass status information. It tells us - * the transmit and receive status for packets and allows us to control - * the card operation mode. You must stop the card when emptying the - * receive ring, or you will race with the ring buffer and lose packets. - */ + * circular buffer queues. + * + * The mailboxes can be used for controlling how the card traverses + * its buffer rings, but are used only for inital setup in this + * implementation. The exec mailbox allows a variety of commands to + * be executed. Each command must complete before the next is + * executed. Primarily we use the exec mailbox for controlling the + * multicast lists. We have to do a certain amount of interesting + * hoop jumping as the multicast list changes can occur in interrupt + * state when the card has an exec command pending. We defer such + * events until the command completion interrupt. + * + * A copy break scheme (taken from 3c59x.c) is employed whereby + * received frames exceeding a configurable length are passed + * directly to the higher networking layers without incuring a copy, + * in what amounts to a time/space trade-off. + * + * The card also keeps a large amount of statistical information + * on-board. In a perfect world, these could be used safely at no + * cost. However, lacking information to the contrary, processing + * them without races would involve so much extra complexity as to + * make it unworthwhile to do so. In the end, a hybrid SW/HW + * implementation was made necessary --- see mc32_update_stats(). + * + * DOC: Notes + * + * It should be possible to use two or more cards, but at this stage + * only by loading two copies of the same module. + * + * The on-board 82586 NIC has trouble receiving multiple + * back-to-back frames and so is likely to drop packets from fast + * senders. +**/ #include <linux/module.h> @@ -78,6 +100,7 @@ static const char *version = #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/skbuff.h> +#include <linux/if_ether.h> #include "3c527.h" @@ -91,23 +114,37 @@ static const char* cardname = "3c527"; #ifndef NET_DEBUG #define NET_DEBUG 2 #endif + +#undef DEBUG_IRQ + static unsigned int mc32_debug = NET_DEBUG; /* The number of low I/O ports used by the ethercard. */ -#define NETCARD_IO_EXTENT 8 +#define MC32_IO_EXTENT 8 + +/* As implemented, values must be a power-of-2 -- 4/8/16/32 */ +#define TX_RING_LEN 32 /* Typically the card supports 37 */ +#define RX_RING_LEN 8 /* " " " */ + +/* Copy break point, see above for details. + * Setting to > 1512 effectively disables this feature. */ +#define RX_COPYBREAK 200 /* Value from 3c59x.c */ +/* Issue the 82586 workaround command - this is for "busy lans", but + * basically means for all lans now days - has a performance (latency) + * cost, but best set. */ +static const int WORKAROUND_82586=1; -struct mc32_mailbox +/* Pointers to buffers and their on-card records */ + +struct mc32_ring_desc { - u16 mbox __attribute((packed)); - u16 data[1] __attribute((packed)); + volatile struct skb_header *p; + struct sk_buff *skb; }; -/* Information that need to be kept for each board. */ - -#define TX_RING_MAX 16 /* Typically the card supports 37 */ -#define RX_RING_MAX 32 /* " " " */ +/* Information that needs to be kept for each board. */ struct mc32_local { struct net_device_stats net_stats; @@ -115,25 +152,28 @@ struct mc32_local volatile struct mc32_mailbox *rx_box; volatile struct mc32_mailbox *tx_box; volatile struct mc32_mailbox *exec_box; - volatile u16 *stats; - u16 tx_chain; - u16 rx_chain; - u16 tx_len; - u16 rx_len; + volatile struct mc32_stats *stats; /* Start of on-card statistics */ + u16 tx_chain; /* Transmit list start offset */ + u16 rx_chain; /* Receive list start offset */ + u16 tx_len; /* Transmit list count */ + u16 rx_len; /* Receive list count */ + u32 base; - u16 rx_halted; - u16 tx_halted; - u16 rx_pending; u16 exec_pending; u16 mc_reload_wait; /* a multicast load request is pending */ - atomic_t tx_count; /* buffers left */ + u32 mc_list_valid; /* True when the mclist is set */ + u16 xceiver_state; /* Current transceiver state. bitmapped */ + u16 desired_state; /* The state we want the transceiver to be in */ + atomic_t tx_count; /* buffers left */ wait_queue_head_t event; - struct sk_buff *tx_skb[TX_RING_MAX]; /* Transmit ring */ - u16 tx_skb_top; - u16 tx_skb_end; - struct sk_buff *rx_skb[RX_RING_MAX]; /* Receive ring */ - void *rx_ptr[RX_RING_MAX]; /* Data pointers */ - u32 mc_list_valid; /* True when the mclist is set */ + + struct mc32_ring_desc tx_ring[TX_RING_LEN]; /* Host Transmit ring */ + struct mc32_ring_desc rx_ring[RX_RING_LEN]; /* Host Receive ring */ + + u16 tx_ring_tail; /* index to tx de-queue end */ + u16 tx_ring_head; /* index to tx en-queue end */ + + u16 rx_ring_tail; /* index to rx de-queue end */ }; /* The station (ethernet) address prefix, used for a sanity check. */ @@ -146,18 +186,25 @@ struct mca_adapters_t { char *name; }; -static struct mca_adapters_t mc32_adapters[] __initdata = { +const struct mca_adapters_t mc32_adapters[] = { { 0x0041, "3COM EtherLink MC/32" }, { 0x8EF5, "IBM High Performance Lan Adapter" }, { 0x0000, NULL } }; -/* Index to functions, as function prototypes. */ +/* Macros for ring index manipulations */ +static inline u16 next_rx(u16 rx) { return (rx+1)&(RX_RING_LEN-1); }; +static inline u16 prev_rx(u16 rx) { return (rx-1)&(RX_RING_LEN-1); }; + +static inline u16 next_tx(u16 tx) { return (tx+1)&(TX_RING_LEN-1); }; + +/* Index to functions, as function prototypes. */ extern int mc32_probe(struct net_device *dev); static int mc32_probe1(struct net_device *dev, int ioaddr); +static int mc32_command(struct net_device *dev, u16 cmd, void *data, int len); static int mc32_open(struct net_device *dev); static void mc32_timeout(struct net_device *dev); static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev); @@ -167,9 +214,8 @@ static struct net_device_stats *mc32_get_stats(struct net_device *dev); static void mc32_set_multicast_list(struct net_device *dev); static void mc32_reset_multicast_list(struct net_device *dev); - /** - * mc32_probe: + * mc32_probe - Search for supported boards * @dev: device to probe * * Because MCA bus is a real bus and we can scan for cards we could do a @@ -212,7 +258,7 @@ int __init mc32_probe(struct net_device *dev) } /** - * mc32_probe1: + * mc32_probe1 - Check a given slot for a board and test the card * @dev: Device structure to fill in * @slot: The MCA bus slot being used by this card * @@ -221,11 +267,11 @@ int __init mc32_probe(struct net_device *dev) * in firmware so we have to wait for it to return and post us either a * failure case or some addresses we use to find the board internals. */ - + static int __init mc32_probe1(struct net_device *dev, int slot) { static unsigned version_printed = 0; - int i; + int i, err; u8 POS; u32 base; struct mc32_local *lp; @@ -258,7 +304,7 @@ static int __init mc32_probe1(struct net_device *dev, int slot) "82586 initialisation failure", "Adapter list configuration error" }; - + /* Time to play MCA games */ if (mc32_debug && version_printed++ == 0) @@ -301,6 +347,12 @@ static int __init mc32_probe1(struct net_device *dev, int slot) dev->irq = ((POS>>2)&3)+9; + if(!request_region(dev->base_addr, MC32_IO_EXTENT, cardname)) + { + printk("io 0x%3lX, which is busy.\n", dev->base_addr); + return -EBUSY; + } + printk("io 0x%3lX irq %d mem 0x%lX (%dK)\n", dev->base_addr, dev->irq, dev->mem_start, i/1024); @@ -349,18 +401,20 @@ static int __init mc32_probe1(struct net_device *dev, int slot) * Grab the IRQ */ - i = request_irq(dev->irq, &mc32_interrupt, 0, dev->name, dev); + i = request_irq(dev->irq, &mc32_interrupt, SA_SHIRQ, dev->name, dev); if (i) { - printk("%s: unable to get IRQ %d.\n", dev->name, dev->irq); + release_region(dev->base_addr, MC32_IO_EXTENT); + printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, dev->irq); return i; } + /* Initialize the device structure. */ dev->priv = kmalloc(sizeof(struct mc32_local), GFP_KERNEL); if (dev->priv == NULL) { - free_irq(dev->irq, dev); - return -ENOMEM; + err = -ENOMEM; + goto err_exit_irq; } memset(dev->priv, 0, sizeof(struct mc32_local)); @@ -371,14 +425,14 @@ static int __init mc32_probe1(struct net_device *dev, int slot) base = inb(dev->base_addr); - while(base==0xFF) + while(base == 0xFF) { i++; - if(i==1000) + if(i == 1000) { - printk("%s: failed to boot adapter.\n", dev->name); - free_irq(dev->irq, dev); - return -ENODEV; + printk(KERN_ERR "%s: failed to boot adapter.\n", dev->name); + err = -ENODEV; + goto err_exit_free; } udelay(1000); if(inb(dev->base_addr+2)&(1<<5)) @@ -388,12 +442,12 @@ static int __init mc32_probe1(struct net_device *dev, int slot) if(base>0) { if(base < 0x0C) - printk("%s: %s%s.\n", dev->name, failures[base-1], + printk(KERN_ERR "%s: %s%s.\n", dev->name, failures[base-1], base<0x0A?" test failure":""); else - printk("%s: unknown failure %d.\n", dev->name, base); - free_irq(dev->irq, dev); - return -ENODEV; + printk(KERN_ERR "%s: unknown failure %d.\n", dev->name, base); + err = -ENODEV; + goto err_exit_free; } base=0; @@ -408,8 +462,8 @@ static int __init mc32_probe1(struct net_device *dev, int slot) if(n>100) { printk(KERN_ERR "%s: mailbox read fail (%d).\n", dev->name, i); - free_irq(dev->irq, dev); - return -ENODEV; + err = -ENODEV; + goto err_exit_free; } } @@ -418,11 +472,11 @@ static int __init mc32_probe1(struct net_device *dev, int slot) lp->exec_box=bus_to_virt(dev->mem_start+base); - base=lp->exec_box->data[1]<<16|lp->exec_box->data[0]; + base=lp->exec_box->data[1]<<16|lp->exec_box->data[0]; lp->base = dev->mem_start+base; - lp->rx_box=bus_to_virt(lp->base + lp->exec_box->data[2]); + lp->rx_box=bus_to_virt(lp->base + lp->exec_box->data[2]); lp->tx_box=bus_to_virt(lp->base + lp->exec_box->data[3]); lp->stats = bus_to_virt(lp->base + lp->exec_box->data[5]); @@ -431,18 +485,16 @@ static int __init mc32_probe1(struct net_device *dev, int slot) * Descriptor chains (card relative) */ - lp->tx_chain = lp->exec_box->data[8]; - lp->rx_chain = lp->exec_box->data[10]; - lp->tx_len = lp->exec_box->data[9]; - lp->rx_len = lp->exec_box->data[11]; + lp->tx_chain = lp->exec_box->data[8]; /* Transmit list start offset */ + lp->rx_chain = lp->exec_box->data[10]; /* Receive list start offset */ + lp->tx_len = lp->exec_box->data[9]; /* Transmit list count */ + lp->rx_len = lp->exec_box->data[11]; /* Receive list count */ + init_waitqueue_head(&lp->event); - printk("%s: %d RX buffers, %d TX buffers. Base of 0x%08X.\n", - dev->name, lp->rx_len, lp->tx_len, lp->base); - - if(lp->tx_len > TX_RING_MAX) - lp->tx_len = TX_RING_MAX; - + printk("%s: Firmware Rev %d. %d RX buffers, %d TX buffers. Base of 0x%08X.\n", + dev->name, lp->exec_box->data[12], lp->rx_len, lp->tx_len, lp->base); + dev->open = mc32_open; dev->stop = mc32_close; dev->hard_start_xmit = mc32_send_packet; @@ -450,57 +502,65 @@ static int __init mc32_probe1(struct net_device *dev, int slot) dev->set_multicast_list = mc32_set_multicast_list; dev->tx_timeout = mc32_timeout; dev->watchdog_timeo = HZ*5; /* Board does all the work */ + + + lp->xceiver_state = HALTED; - lp->rx_halted = 1; - lp->tx_halted = 1; - lp->rx_pending = 0; + lp->tx_ring_tail=lp->tx_ring_head=0; /* Fill in the fields of the device structure with ethernet values. */ ether_setup(dev); + return 0; + +err_exit_free: + kfree(dev->priv); +err_exit_irq: + free_irq(dev->irq, dev); + release_region(dev->base_addr, MC32_IO_EXTENT); + return err; } /** - * mc32_ring_poll: + * mc32_ready_poll - wait until we can feed it a command * @dev: The device to wait for * - * Wait until a command we issues to the control register is completed. - * This actually takes very little time at all, which is fortunate as - * we often have to busy wait it. + * Wait until the card becomes ready to accept a command via the + * command register. This tells us nothing about the completion + * status of any pending commands and takes very little time at all. */ -static void mc32_ring_poll(struct net_device *dev) +static void mc32_ready_poll(struct net_device *dev) { int ioaddr = dev->base_addr; while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); } - /** - * mc32_command_nowait: + * mc32_command_nowait - send a command non blocking * @dev: The 3c527 to issue the command to * @cmd: The command word to write to the mailbox * @data: A data block if the command expects one * @len: Length of the data block * - * Send a command from interrupt state. If there is a command currently - * being executed then we return an error of -1. It simply isnt viable - * to wait around as commands may be slow. Providing we get in then - * we send the command and busy wait for the board to acknowledge that - * a command request is pending. We do not wait for the command to - * complete, just for the card to admit to noticing it. + * Send a command from interrupt state. If there is a command + * currently being executed then we return an error of -1. It simply + * isn't viable to wait around as commands may be slow. Providing we + * get in, we busy wait for the board to become ready to accept the + * command and issue it. We do not wait for the command to complete + * --- the card will interrupt us when it's done. */ static int mc32_command_nowait(struct net_device *dev, u16 cmd, void *data, int len) { struct mc32_local *lp = (struct mc32_local *)dev->priv; int ioaddr = dev->base_addr; - + if(lp->exec_pending) return -1; - + lp->exec_pending=3; lp->exec_box->mbox=0; lp->exec_box->mbox=cmd; @@ -515,7 +575,7 @@ static int mc32_command_nowait(struct net_device *dev, u16 cmd, void *data, int /** - * mc32_command: + * mc32_command - send a command and sleep until completion * @dev: The 3c527 card to issue the command to * @cmd: The command word to write to the mailbox * @data: A data block if the command expects one @@ -543,8 +603,6 @@ static int mc32_command_nowait(struct net_device *dev, u16 cmd, void *data, int * 3 - command issued, trash reply. In which case the irq * takes it back to state 0 * - * Send command and block for results. On completion spot and reissue - * multicasts */ static int mc32_command(struct net_device *dev, u16 cmd, void *data, int len) @@ -580,251 +638,287 @@ static int mc32_command(struct net_device *dev, u16 cmd, void *data, int len) /* Send the command */ while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); outb(1<<6, ioaddr+HOST_CMD); - + save_flags(flags); cli(); + while(lp->exec_pending!=2) sleep_on(&lp->event); lp->exec_pending=0; restore_flags(flags); - - if(lp->exec_box->data[0]&(1<<13)) + if(lp->exec_box->mbox&(1<<13)) ret = -1; + /* * A multicast set got blocked - do it now */ if(lp->mc_reload_wait) + { mc32_reset_multicast_list(dev); + } return ret; } /** - * mc32_rx_abort: - * @dev: 3c527 to abort + * mc32_start_transceiver - tell board to restart tx/rx + * @dev: The 3c527 card to issue the command to * - * Peforms a receive abort sequence on the card. In fact after some - * experimenting we now simply tell the card to suspend reception. When - * issuing aborts occasionally odd things happened. - */ - -static void mc32_rx_abort(struct net_device *dev) -{ - struct mc32_local *lp = (struct mc32_local *)dev->priv; - int ioaddr = dev->base_addr; + * This may be called from the interrupt state, where it is used + * to restart the rx ring if the card runs out of rx buffers. + * + * First, we check if it's ok to start the transceiver. We then show + * the card where to start in the rx ring and issue the + * commands to start reception and transmission. We don't wait + * around for these to complete. + */ - while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); - - lp->rx_box->mbox=0; - outb(3<<3, ioaddr+HOST_CMD); /* Suspend reception */ -} +static void mc32_start_transceiver(struct net_device *dev) { - -/** - * mc32_rx_begin: - * @dev: 3c527 to enable - * - * We wait for any pending command to complete and then issue - * a start reception command to the board itself. At this point - * receive handling continues as it was before. - */ - -static void mc32_rx_begin(struct net_device *dev) -{ struct mc32_local *lp = (struct mc32_local *)dev->priv; int ioaddr = dev->base_addr; - - while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); - - lp->rx_box->mbox=0; - outb(1<<3, ioaddr+HOST_CMD); /* GO */ - mc32_ring_poll(dev); - - lp->rx_halted=0; - lp->rx_pending=0; -} -/** - * mc32_tx_abort: - * @dev: 3c527 to abort - * - * Peforms a receive abort sequence on the card. In fact after some - * experimenting we now simply tell the card to suspend transmits . When - * issuing aborts occasionally odd things happened. In theory we want - * an abort to be sure we can recycle our buffers. As it happens we - * just have to be careful to shut the card down on close, and - * boot it carefully from scratch on setup. - */ - -static void mc32_tx_abort(struct net_device *dev) -{ - struct mc32_local *lp = (struct mc32_local *)dev->priv; - int ioaddr = dev->base_addr; - - while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); - + /* Ignore RX overflow on device closure */ + if (lp->desired_state==HALTED) + return; + + mc32_ready_poll(dev); + lp->tx_box->mbox=0; - outb(3, ioaddr+HOST_CMD); /* Suspend */ - - /* Ring empty */ - - atomic_set(&lp->tx_count, lp->tx_len); + lp->rx_box->mbox=0; + + /* Give the card the offset to the post-EOL-bit RX descriptor */ + lp->rx_box->data[0]=lp->rx_ring[prev_rx(lp->rx_ring_tail)].p->next; + + outb(HOST_CMD_START_RX, ioaddr+HOST_CMD); + + mc32_ready_poll(dev); + outb(HOST_CMD_RESTRT_TX, ioaddr+HOST_CMD); /* card ignores this on RX restart */ - /* Flush */ - if(lp->tx_skb_top!=lp->tx_skb_end) - { - int i; - if(lp->tx_skb_top<=lp->tx_skb_end) - { - for(i=lp->tx_skb_top;i<lp->tx_skb_end;i++) - { - dev_kfree_skb(lp->tx_skb[i]); - lp->tx_skb[i]=NULL; - } - } - else - { - for(i=lp->tx_skb_end;i<TX_RING_MAX;i++) - { - dev_kfree_skb(lp->tx_skb[i]); - lp->tx_skb[i]=NULL; - } - for(i=0;i<lp->tx_skb_top;i++) - { - dev_kfree_skb(lp->tx_skb[i]); - lp->tx_skb[i]=NULL; - } - } - } - lp->tx_skb_top=lp->tx_skb_end=0; + /* We are not interrupted on start completion */ + lp->xceiver_state=RUNNING; } + /** - * mc32_tx_begin: - * @dev: 3c527 to enable - * - * We wait for any pending command to complete and then issue - * a start transmit command to the board itself. At this point - * transmit handling continues as it was before. The ring must - * be setup before you do this and must have an end marker in it. - * It turns out we can avoid issuing this specific command when - * doing our setup so we avoid it. - */ - -static void mc32_tx_begin(struct net_device *dev) + * mc32_halt_transceiver - tell board to stop tx/rx + * @dev: The 3c527 card to issue the command to + * + * We issue the commands to halt the card's transceiver. In fact, + * after some experimenting we now simply tell the card to + * suspend. When issuing aborts occasionally odd things happened. + * + * We then sleep until the card has notified us that both rx and + * tx have been suspended. + */ + +static void mc32_halt_transceiver(struct net_device *dev) { struct mc32_local *lp = (struct mc32_local *)dev->priv; int ioaddr = dev->base_addr; - - while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); - + unsigned long flags; + + mc32_ready_poll(dev); + lp->tx_box->mbox=0; -#if 0 - outb(5, ioaddr+HOST_CMD); /* GO */ - printk("TX=>5\n"); - mc32_ring_poll(dev); - if(lp->tx_box->mbox&(1<<13)) - printk("TX begin error!\n"); -#endif - lp->tx_halted=0; -} + lp->rx_box->mbox=0; + + outb(HOST_CMD_SUSPND_RX, ioaddr+HOST_CMD); + mc32_ready_poll(dev); + outb(HOST_CMD_SUSPND_TX, ioaddr+HOST_CMD); + + save_flags(flags); + cli(); + + while(lp->xceiver_state!=HALTED) + sleep_on(&lp->event); + + restore_flags(flags); +} + - /** - * mc32_load_rx_ring: + * mc32_load_rx_ring - load the ring of receive buffers * @dev: 3c527 to build the ring for * - * The card setups up the receive ring for us. We are required to - * use the ring it provides although we can change the size of the - * ring. + * This initalises the on-card and driver datastructures to + * the point where mc32_start_transceiver() can be called. + * + * The card sets up the receive ring for us. We are required to use the + * ring it provides although we can change the size of the ring. * - * We allocate an sk_buff for each ring entry in turn and set the entry - * up for a single non s/g buffer. The first buffer we mark with the - * end marker bits. Finally we clear the rx mailbox. + * We allocate an sk_buff for each ring entry in turn and + * initalise its house-keeping info. At the same time, we read + * each 'next' pointer in our rx_ring array. This reduces slow + * shared-memory reads and makes it easy to access predecessor + * descriptors. + * + * We then set the end-of-list bit for the last entry so that the + * card will know when it has run out of buffers. */ - + static int mc32_load_rx_ring(struct net_device *dev) { struct mc32_local *lp = (struct mc32_local *)dev->priv; int i; - u16 base; + u16 rx_base; volatile struct skb_header *p; - base = lp->rx_box->data[0]; - - /* Fix me - should use card size - also fix flush ! */ + rx_base=lp->rx_chain; - for(i=0;i<RX_RING_MAX;i++) + for(i=0;i<RX_RING_LEN;i++) { - lp->rx_skb[i]=alloc_skb(1532, GFP_KERNEL); - if(lp->rx_skb[i]==NULL) + lp->rx_ring[i].skb=alloc_skb(1532, GFP_KERNEL); + skb_reserve(lp->rx_ring[i].skb, 18); + + if(lp->rx_ring[i].skb==NULL) { for(;i>=0;i--) - kfree_skb(lp->rx_skb[i]); + kfree_skb(lp->rx_ring[i].skb); return -ENOBUFS; } - lp->rx_ptr[i]=lp->rx_skb[i]->data+18; - p=bus_to_virt(lp->base+base); + p=bus_to_virt(lp->base+rx_base); + p->control=0; - p->data = virt_to_bus(lp->rx_ptr[i]); + p->data=virt_to_bus(lp->rx_ring[i].skb->data); p->status=0; - p->length = 1532; - base = p->next; + p->length=1532; + + lp->rx_ring[i].p=p; + rx_base=p->next; } - p->control = (1<<6); - lp->rx_box->mbox = 0; + + lp->rx_ring[i-1].p->control |= CONTROL_EOL; + + lp->rx_ring_tail=0; + return 0; } + /** - * mc32_flush_rx_ring: + * mc32_flush_rx_ring - free the ring of receive buffers * @lp: Local data of 3c527 to flush the rx ring of * - * Free the buffer for each ring slot. Because of the receive - * algorithm we use the ring will always be loaded will a full set - * of buffers. + * Free the buffer for each ring slot. This may be called + * before mc32_load_rx_ring(), eg. on error in mc32_open(). */ -static void mc32_flush_rx_ring(struct mc32_local *lp) +static void mc32_flush_rx_ring(struct net_device *dev) { - int i; - for(i=0;i<RX_RING_MAX;i++) - kfree_skb(lp->rx_skb[i]); + struct mc32_local *lp = (struct mc32_local *)dev->priv; + + struct sk_buff *skb; + int i; + + for(i=0; i < RX_RING_LEN; i++) + { + skb = lp->rx_ring[i].skb; + if (skb!=NULL) { + kfree_skb(skb); + skb=NULL; + } + lp->rx_ring[i].p=NULL; + } } + +/** + * mc32_load_tx_ring - load transmit ring + * @dev: The 3c527 card to issue the command to + * + * This sets up the host transmit data-structures. + * + * First, we obtain from the card it's current postion in the tx + * ring, so that we will know where to begin transmitting + * packets. + * + * Then, we read the 'next' pointers from the on-card tx ring into + * our tx_ring array to reduce slow shared-mem reads. Finally, we + * intitalise the tx house keeping variables. + * + */ + +static void mc32_load_tx_ring(struct net_device *dev) +{ + struct mc32_local *lp = (struct mc32_local *)dev->priv; + volatile struct skb_header *p; + int i; + u16 tx_base; + + tx_base=lp->tx_box->data[0]; + + for(i=0;i<lp->tx_len;i++) + { + p=bus_to_virt(lp->base+tx_base); + lp->tx_ring[i].p=p; + lp->tx_ring[i].skb=NULL; + + tx_base=p->next; + } + + /* -1 so that tx_ring_head cannot "lap" tx_ring_tail, */ + /* which would be bad news for mc32_tx_ring as cur. implemented */ + + atomic_set(&lp->tx_count, TX_RING_LEN-1); + lp->tx_ring_head=lp->tx_ring_tail=0; +} + + /** - * mc32_flush_tx_ring: + * mc32_flush_tx_ring - free transmit ring * @lp: Local data of 3c527 to flush the tx ring of * * We have to consider two cases here. We want to free the pending * buffers only. If the ring buffer head is past the start then the - * ring segment we wish to free wraps through zero. + * ring segment we wish to free wraps through zero. The tx ring + * house-keeping variables are then reset. */ -static void mc32_flush_tx_ring(struct mc32_local *lp) +static void mc32_flush_tx_ring(struct net_device *dev) { - int i; + struct mc32_local *lp = (struct mc32_local *)dev->priv; - if(lp->tx_skb_top <= lp->tx_skb_end) - { - for(i=lp->tx_skb_top;i<lp->tx_skb_end;i++) - dev_kfree_skb(lp->tx_skb[i]); - } - else + if(lp->tx_ring_tail!=lp->tx_ring_head) { - for(i=0;i<lp->tx_skb_end;i++) - dev_kfree_skb(lp->tx_skb[i]); - for(i=lp->tx_skb_top;i<TX_RING_MAX;i++) - dev_kfree_skb(lp->tx_skb[i]); + int i; + if(lp->tx_ring_tail < lp->tx_ring_head) + { + for(i=lp->tx_ring_tail;i<lp->tx_ring_head;i++) + { + dev_kfree_skb(lp->tx_ring[i].skb); + lp->tx_ring[i].skb=NULL; + lp->tx_ring[i].p=NULL; + } + } + else + { + for(i=lp->tx_ring_tail; i<TX_RING_LEN; i++) + { + dev_kfree_skb(lp->tx_ring[i].skb); + lp->tx_ring[i].skb=NULL; + lp->tx_ring[i].p=NULL; + } + for(i=0; i<lp->tx_ring_head; i++) + { + dev_kfree_skb(lp->tx_ring[i].skb); + lp->tx_ring[i].skb=NULL; + lp->tx_ring[i].p=NULL; + } + } } + + atomic_set(&lp->tx_count, 0); + lp->tx_ring_tail=lp->tx_ring_head=0; } + /** - * mc32_open + * mc32_open - handle 'up' of card * @dev: device to open * * The user is trying to bring the card into ready state. This requires @@ -832,9 +926,10 @@ static void mc32_flush_tx_ring(struct mc32_local *lp) * 'indications'. Without these enabled the card doesn't bother telling * us what it has done. This had me puzzled for a week. * - * We then load the network address and multicast filters. Turn on the - * workaround mode. This works around a bug in the 82586 - it asks the - * firmware to do so. It has a performance hit but is needed on busy + * We configure the number of card descriptors, then load the network + * address and multicast filters. Turn on the workaround mode. This + * works around a bug in the 82586 - it asks the firmware to do + * so. It has a performance (latency) hit but is needed on busy * [read most] lans. We load the ring with buffers then we kick it * all off. */ @@ -842,10 +937,11 @@ static void mc32_flush_tx_ring(struct mc32_local *lp) static int mc32_open(struct net_device *dev) { int ioaddr = dev->base_addr; - u16 zero_word=0; + struct mc32_local *lp = (struct mc32_local *)dev->priv; u8 one=1; u8 regs; - + u16 descnumbuffs[2] = {TX_RING_LEN, RX_RING_LEN}; + /* * Interrupts enabled */ @@ -861,46 +957,64 @@ static int mc32_open(struct net_device *dev) mc32_command(dev, 4, &one, 2); - /* - * Send the command sequence "abort, resume" for RX and TX. - * The abort cleans up the buffer chains if needed. + * Poke it to make sure it's really dead. */ - mc32_rx_abort(dev); - mc32_tx_abort(dev); + mc32_halt_transceiver(dev); + mc32_flush_tx_ring(dev); + + /* + * Ask card to set up on-card descriptors to our spec + */ + + if(mc32_command(dev, 8, descnumbuffs, 4)) { + printk("%s: %s rejected our buffer configuration!\n", + dev->name, cardname); + mc32_close(dev); + return -ENOBUFS; + } + /* Report new configuration */ + mc32_command(dev, 6, NULL, 0); + + lp->tx_chain = lp->exec_box->data[8]; /* Transmit list start offset */ + lp->rx_chain = lp->exec_box->data[10]; /* Receive list start offset */ + lp->tx_len = lp->exec_box->data[9]; /* Transmit list count */ + lp->rx_len = lp->exec_box->data[11]; /* Receive list count */ + /* Set Network Address */ mc32_command(dev, 1, dev->dev_addr, 6); /* Set the filters */ mc32_set_multicast_list(dev); + + if (WORKAROUND_82586) { + u16 zero_word=0; + mc32_command(dev, 0x0D, &zero_word, 2); /* 82586 bug workaround on */ + } + + mc32_load_tx_ring(dev); - /* Issue the 82586 workaround command - this is for "busy lans", - but basically means for all lans now days - has a performance - cost but best set */ - - mc32_command(dev, 0x0D, &zero_word, 2); /* 82586 bug workaround on */ - - /* Load the ring we just initialised */ - - if(mc32_load_rx_ring(dev)) + if(mc32_load_rx_ring(dev)) { mc32_close(dev); return -ENOBUFS; } + + lp->desired_state = RUNNING; - /* And the resume command goes last */ - - mc32_rx_begin(dev); - mc32_tx_begin(dev); + /* And finally, set the ball rolling... */ + mc32_start_transceiver(dev); + + netif_start_queue(dev); - netif_start_queue(dev); return 0; } + /** - * mc32_timeout: + * mc32_timeout - handle a timeout from the network layer * @dev: 3c527 that timed out * * Handle a timeout on transmit from the 3c527. This normally means @@ -915,9 +1029,10 @@ static void mc32_timeout(struct net_device *dev) /* Try to restart the adaptor. */ netif_wake_queue(dev); } - + + /** - * mc32_send_packet: + * mc32_send_packet - queue a frame for transmit * @skb: buffer to transmit * @dev: 3c527 to send it out of * @@ -931,18 +1046,16 @@ static void mc32_timeout(struct net_device *dev) * MCA machine I don't plan to change it. It is probably the top * performance hit for this driver on SMP however. */ - + static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev) { struct mc32_local *lp = (struct mc32_local *)dev->priv; - int ioaddr = dev->base_addr; unsigned long flags; - - u16 tx_head; + volatile struct skb_header *p, *np; netif_stop_queue(dev); - + save_flags(flags); cli(); @@ -952,204 +1065,303 @@ static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev) return 1; } - tx_head = lp->tx_box->data[0]; - atomic_dec(&lp->tx_count); - /* We will need this to flush the buffer out */ - - lp->tx_skb[lp->tx_skb_end] = skb; - lp->tx_skb_end++; - lp->tx_skb_end&=(TX_RING_MAX-1); - - /* TX suspend - shouldnt be needed but apparently is. - This is a research item ... */ - - while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); - lp->tx_box->mbox=0; - outb(3, ioaddr+HOST_CMD); - - /* Transmit now stopped */ + atomic_dec(&lp->tx_count); /* P is the last sending/sent buffer as a pointer */ - p=(struct skb_header *)bus_to_virt(lp->base+tx_head); - - /* NP is the buffer we will be loading */ - np=(struct skb_header *)bus_to_virt(lp->base+p->next); + p=lp->tx_ring[lp->tx_ring_head].p; - np->control |= (1<<6); /* EOL */ - wmb(); - - np->length = skb->len; - - if(np->length < 60) - np->length = 60; + lp->tx_ring_head=next_tx(lp->tx_ring_head); + + /* NP is the buffer we will be loading */ + np=lp->tx_ring[lp->tx_ring_head].p; + + /* We will need this to flush the buffer out */ + lp->tx_ring[lp->tx_ring_head].skb=skb; + + np->length = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len; np->data = virt_to_bus(skb->data); np->status = 0; - np->control = (1<<7)|(1<<6); /* EOP EOL */ + np->control = CONTROL_EOP | CONTROL_EOL; wmb(); - p->status = 0; - p->control &= ~(1<<6); + p->control &= ~CONTROL_EOL; /* Clear EOL on p */ - while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); - lp->tx_box->mbox=0; - outb(5, ioaddr+HOST_CMD); /* Restart TX */ restore_flags(flags); - + netif_wake_queue(dev); return 0; } + /** - * mc32_update_stats: + * mc32_update_stats - pull off the on board statistics * @dev: 3c527 to service * - * When the board signals us that its statistics need attention we - * should query the table and clear it. In actual fact we currently - * track all our statistics in software and I haven't implemented it yet. + * + * Query and reset the on-card stats. There's the small possibility + * of a race here, which would result in an underestimation of + * actual errors. As such, we'd prefer to keep all our stats + * collection in software. As a rule, we do. However it can't be + * used for rx errors and collisions as, by default, the card discards + * bad rx packets. + * + * Setting the SAV BP in the rx filter command supposedly + * stops this behaviour. However, testing shows that it only seems to + * enable the collation of on-card rx statistics --- the driver + * never sees an RX descriptor with an error status set. + * */ - + static void mc32_update_stats(struct net_device *dev) { -} + struct mc32_local *lp = (struct mc32_local *)dev->priv; + volatile struct mc32_stats *st = lp->stats; + + u32 rx_errors=0; + + rx_errors+=lp->net_stats.rx_crc_errors +=st->rx_crc_errors; + st->rx_crc_errors=0; + rx_errors+=lp->net_stats.rx_fifo_errors +=st->rx_overrun_errors; + st->rx_overrun_errors=0; + rx_errors+=lp->net_stats.rx_frame_errors +=st->rx_alignment_errors; + st->rx_alignment_errors=0; + rx_errors+=lp->net_stats.rx_length_errors+=st->rx_tooshort_errors; + st->rx_tooshort_errors=0; + rx_errors+=lp->net_stats.rx_missed_errors+=st->rx_outofresource_errors; + st->rx_outofresource_errors=0; + lp->net_stats.rx_errors=rx_errors; + + /* Number of packets which saw one collision */ + lp->net_stats.collisions+=st->dataC[10]; + st->dataC[10]=0; + + /* Number of packets which saw 2--15 collisions */ + lp->net_stats.collisions+=st->dataC[11]; + st->dataC[11]=0; +} + /** - * mc32_rx_ring: + * mc32_rx_ring - process the receive ring * @dev: 3c527 that needs its receive ring processing * - * We have received one or more indications from the card that - * a receive has completed. The ring buffer thus contains dirty - * entries. Firstly we tell the card to stop receiving, then We walk - * the ring from the first filled entry, which is pointed to by the - * card rx mailbox and for each completed packet we will either copy - * it and pass it up the stack or if the packet is near MTU sized we - * allocate another buffer and flip the old one up the stack. * + * We have received one or more indications from the card that a + * receive has completed. The buffer ring thus contains dirty + * entries. We walk the ring by iterating over the circular rx_ring + * array, starting at the next dirty buffer (which happens to be the + * one we finished up at last time around). + * + * For each completed packet, we will either copy it and pass it up + * the stack or, if the packet is near MTU sized, we allocate + * another buffer and flip the old one up the stack. + * * We must succeed in keeping a buffer on the ring. If neccessary we - * will toss a received packet rather than lose a ring entry. Once the - * first packet that is unused is found we reload the mailbox with the - * buffer so that the card knows it can use the buffers again. Finally - * we set it receiving again. - * - * We must stop reception during the ring walk. I thought it would be - * neat to avoid it by clever tricks, but it turns out the event order - * on the card means you have to play by the manual. + * will toss a received packet rather than lose a ring entry. Once + * the first uncompleted descriptor is found, we move the + * End-Of-List bit to include the buffers just processed. + * */ - + static void mc32_rx_ring(struct net_device *dev) { - struct mc32_local *lp=dev->priv; - int ioaddr = dev->base_addr; - int x=0; + struct mc32_local *lp=dev->priv; volatile struct skb_header *p; - u16 base; - u16 top; + u16 rx_ring_tail = lp->rx_ring_tail; + u16 rx_old_tail = rx_ring_tail; - /* Halt RX before walking the ring */ - - while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); - outb(3<<3, ioaddr+HOST_CMD); - while(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR); + int x=0; - top = base = lp->rx_box->data[0]; do - { - p=(struct skb_header *)bus_to_virt(base+lp->base); - if(!(p->status & (1<<7))) + { + p=lp->rx_ring[rx_ring_tail].p; + + if(!(p->status & (1<<7))) { /* Not COMPLETED */ break; - if(p->status & (1<<6)) - { - u16 length = p->length; - struct sk_buff *skb=dev_alloc_skb(length+2); - if(skb!=NULL) + } + if(p->status & (1<<6)) /* COMPLETED_OK */ + { + + u16 length=p->length; + struct sk_buff *skb; + struct sk_buff *newskb; + + /* Try to save time by avoiding a copy on big frames */ + + if ((length > RX_COPYBREAK) + && ((newskb=dev_alloc_skb(1532)) != NULL)) + { + skb=lp->rx_ring[rx_ring_tail].skb; + skb_put(skb, length); + + skb_reserve(newskb,18); + lp->rx_ring[rx_ring_tail].skb=newskb; + p->data=virt_to_bus(newskb->data); + } + else { + skb=dev_alloc_skb(length+2); + + if(skb==NULL) { + lp->net_stats.rx_dropped++; + goto dropped; + } + skb_reserve(skb,2); - /*printk("Frame at %p\n", bus_to_virt(p->data)); */ memcpy(skb_put(skb, length), - bus_to_virt(p->data), length); - skb->protocol=eth_type_trans(skb,dev); - skb->dev=dev; - netif_rx(skb); - dev->last_rx = jiffies; - lp->net_stats.rx_packets++; - lp->net_stats.rx_bytes += length; + lp->rx_ring[rx_ring_tail].skb->data, length); } - else - lp->net_stats.rx_dropped++; + + skb->protocol=eth_type_trans(skb,dev); + skb->dev=dev; + dev->last_rx = jiffies; + lp->net_stats.rx_packets++; + lp->net_stats.rx_bytes += length; + netif_rx(skb); } - else + + dropped: + p->length = 1532; + p->status = 0; + + rx_ring_tail=next_rx(rx_ring_tail); + } + while(x++<48); + + /* If there was actually a frame to be processed, place the EOL bit */ + /* at the descriptor prior to the one to be filled next */ + + if (rx_ring_tail != rx_old_tail) + { + lp->rx_ring[prev_rx(rx_ring_tail)].p->control |= CONTROL_EOL; + lp->rx_ring[prev_rx(rx_old_tail)].p->control &= ~CONTROL_EOL; + + lp->rx_ring_tail=rx_ring_tail; + } +} + + +/** + * mc32_tx_ring - process completed transmits + * @dev: 3c527 that needs its transmit ring processing + * + * + * This operates in a similar fashion to mc32_rx_ring. We iterate + * over the transmit ring. For each descriptor which has been + * processed by the card, we free its associated buffer and note + * any errors. This continues until the transmit ring is emptied + * or we reach a descriptor that hasn't yet been processed by the + * card. + * + */ + +static void mc32_tx_ring(struct net_device *dev) +{ + struct mc32_local *lp=(struct mc32_local *)dev->priv; + volatile struct skb_header *np; + + /* NB: lp->tx_count=TX_RING_LEN-1 so that tx_ring_head cannot "lap" tail here */ + + while (lp->tx_ring_tail != lp->tx_ring_head) + { + u16 t; + + t=next_tx(lp->tx_ring_tail); + np=lp->tx_ring[t].p; + + if(!(np->status & (1<<7))) { - lp->net_stats.rx_errors++; - switch(p->status&0x0F) + /* Not COMPLETED */ + break; + } + lp->net_stats.tx_packets++; + if(!(np->status & (1<<6))) /* Not COMPLETED_OK */ + { + lp->net_stats.tx_errors++; + + switch(np->status&0x0F) { case 1: - lp->net_stats.rx_crc_errors++;break; + lp->net_stats.tx_aborted_errors++; + break; /* Max collisions */ case 2: - lp->net_stats.rx_fifo_errors++;break; + lp->net_stats.tx_fifo_errors++; + break; case 3: - lp->net_stats.rx_frame_errors++;break; + lp->net_stats.tx_carrier_errors++; + break; case 4: - lp->net_stats.rx_missed_errors++;break; + lp->net_stats.tx_window_errors++; + break; /* CTS Lost */ case 5: - lp->net_stats.rx_length_errors++;break; + lp->net_stats.tx_aborted_errors++; + break; /* Transmit timeout */ } } - p->length = 1532; - p->control &= ~(1<<6); - p->status = 0; - base = p->next; + /* Packets are sent in order - this is + basically a FIFO queue of buffers matching + the card ring */ + lp->net_stats.tx_bytes+=lp->tx_ring[t].skb->len; + dev_kfree_skb_irq(lp->tx_ring[t].skb); + lp->tx_ring[t].skb=NULL; + atomic_inc(&lp->tx_count); + netif_wake_queue(dev); + + lp->tx_ring_tail=t; } - while(x++<48); - /* - * Restart ring processing - */ - - while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); - lp->rx_box->mbox=0; - lp->rx_box->data[0] = top; - outb(1<<3, ioaddr+HOST_CMD); - lp->rx_halted=0; -} +} /** - * mc32_interrupt: + * mc32_interrupt - handle an interrupt from a 3c527 * @irq: Interrupt number * @dev_id: 3c527 that requires servicing * @regs: Registers (unused) * - * The 3c527 interrupts us for four reasons. The command register - * contains the message it wishes to send us packed into a single - * byte field. We keep reading status entries until we have processed - * all the transmit and control items, but simply count receive - * reports. When the receive reports are in we can call the mc32_rx_ring - * and empty the ring. This saves the overhead of multiple command requests + * + * An interrupt is raised whenever the 3c527 writes to the command + * register. This register contains the message it wishes to send us + * packed into a single byte field. We keep reading status entries + * until we have processed all the control items, but simply count + * transmit and receive reports. When all reports are in we empty the + * transceiver rings as appropriate. This saves the overhead of + * multiple command requests. + * + * Because MCA is level-triggered, we shouldn't miss indications. + * Therefore, we needn't ask the card to suspend interrupts within + * this handler. The card receives an implicit acknowledgment of the + * current interrupt when we read the command register. + * */ - + static void mc32_interrupt(int irq, void *dev_id, struct pt_regs * regs) { struct net_device *dev = dev_id; struct mc32_local *lp; int ioaddr, status, boguscount = 0; + int rx_event = 0; + int tx_event = 0; if (dev == NULL) { printk(KERN_WARNING "%s: irq %d for unknown device.\n", cardname, irq); return; } + ioaddr = dev->base_addr; lp = (struct mc32_local *)dev->priv; /* See whats cooking */ - - while((inb(ioaddr+2)&(1<<5)) && boguscount++<2000) + + while((inb(ioaddr+HOST_STATUS)&HOST_STATUS_CWR) && boguscount++<2000) { status=inb(ioaddr+HOST_CMD); #ifdef DEBUG_IRQ - printk("Status TX%d RX%d EX%d OV%d\n", + printk("Status TX%d RX%d EX%d OV%d BC%d\n", (status&7), (status>>3)&7, (status>>6)&1, - (status>>7)&1); + (status>>7)&1, boguscount); #endif switch(status&7) @@ -1157,32 +1369,16 @@ static void mc32_interrupt(int irq, void *dev_id, struct pt_regs * regs) case 0: break; case 6: /* TX fail */ - lp->net_stats.tx_errors++; case 2: /* TX ok */ - lp->net_stats.tx_packets++; - /* Packets are sent in order - this is - basically a FIFO queue of buffers matching - the card ring */ - lp->net_stats.tx_bytes+=lp->tx_skb[lp->tx_skb_top]->len; - dev_kfree_skb_irq(lp->tx_skb[lp->tx_skb_top]); - lp->tx_skb[lp->tx_skb_top]=NULL; - lp->tx_skb_top++; - lp->tx_skb_top&=(TX_RING_MAX-1); - atomic_inc(&lp->tx_count); - netif_wake_queue(dev); + tx_event = 1; break; case 3: /* Halt */ case 4: /* Abort */ - lp->tx_halted=1; - wake_up(&lp->event); - break; - case 5: - lp->tx_halted=0; + lp->xceiver_state |= TX_HALTED; wake_up(&lp->event); break; default: - printk("%s: strange tx ack %d\n", - dev->name, status&7); + printk("%s: strange tx ack %d\n", dev->name, status&7); } status>>=3; switch(status&7) @@ -1190,87 +1386,87 @@ static void mc32_interrupt(int irq, void *dev_id, struct pt_regs * regs) case 0: break; case 2: /* RX */ - lp->rx_pending=1; - if(!lp->rx_halted) - { - /* - * Halt ring receive - */ - while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); - outb(3<<3, ioaddr+HOST_CMD); - } + rx_event=1; break; - case 3: - case 4: - lp->rx_halted=1; - wake_up(&lp->event); - break; - case 5: - lp->rx_halted=0; + case 3: /* Halt */ + case 4: /* Abort */ + lp->xceiver_state |= RX_HALTED; wake_up(&lp->event); break; case 6: /* Out of RX buffers stat */ + /* Must restart rx */ lp->net_stats.rx_dropped++; - lp->rx_pending=1; - /* Must restart */ - lp->rx_halted=1; + mc32_rx_ring(dev); + mc32_start_transceiver(dev); break; default: printk("%s: strange rx ack %d\n", - dev->name, status&7); - + dev->name, status&7); } status>>=3; if(status&1) { + /* 0=no 1=yes 2=replied, get cmd, 3 = wait reply & dump it */ - if(lp->exec_pending!=3) + + if(lp->exec_pending!=3) { lp->exec_pending=2; - else - lp->exec_pending=0; - wake_up(&lp->event); + wake_up(&lp->event); + } + else + { + lp->exec_pending=0; + + /* A new multicast set may have been + blocked while the old one was + running. If so, do it now. */ + + if (lp->mc_reload_wait) + mc32_reset_multicast_list(dev); + else + wake_up(&lp->event); + } } if(status&2) { /* - * Update the stats as soon as - * we have it flagged and can - * send an immediate reply (CRR set) + * We get interrupted once per + * counter that is about to overflow. */ - - if(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR) - { - mc32_update_stats(dev); - outb(0, ioaddr+HOST_CMD); - } + + mc32_update_stats(dev); } } - + + /* - * Process and restart the receive ring. This has some state - * as we must halt the ring to process it and halting the ring - * might not occur in the same IRQ handling loop as we issue - * the halt. - */ + * Process the transmit and receive rings + */ + + if(tx_event) + mc32_tx_ring(dev); - if(lp->rx_pending && lp->rx_halted) - { + if(rx_event) mc32_rx_ring(dev); - lp->rx_pending = 0; - } + return; } /** - * mc32_close: + * mc32_close - user configuring the 3c527 down * @dev: 3c527 card to shut down * * The 3c527 is a bus mastering device. We must be careful how we * shut it down. It may also be running shared interrupt so we have * to be sure to silence it properly * + * We indicate that the card is closing to the rest of the + * driver. Otherwise, it is possible that the card may run out + * of receive buffers and restart the transceiver while we're + * trying to close it. + * * We abort any receive and transmits going on and then wait until * any pending exec commands have completed in other code threads. * In theory we can't get here while that is true, in practice I am @@ -1279,93 +1475,104 @@ static void mc32_interrupt(int irq, void *dev_id, struct pt_regs * regs) * We turn off the interrupt enable for the board to be sure it can't * intefere with other devices. */ - + static int mc32_close(struct net_device *dev) { struct mc32_local *lp = (struct mc32_local *)dev->priv; + int ioaddr = dev->base_addr; u8 regs; u16 one=1; - - netif_stop_queue(dev); + lp->desired_state = HALTED; + netif_stop_queue(dev); + /* * Send the indications on command (handy debug check) */ mc32_command(dev, 4, &one, 2); - /* Abort RX and Abort TX */ - - mc32_rx_abort(dev); - mc32_tx_abort(dev); + /* Shut down the transceiver */ + + mc32_halt_transceiver(dev); /* Catch any waiting commands */ while(lp->exec_pending==1) sleep_on(&lp->event); - + /* Ok the card is now stopping */ regs=inb(ioaddr+HOST_CTRL); regs&=~HOST_CTRL_INTE; outb(regs, ioaddr+HOST_CTRL); - mc32_flush_rx_ring(lp); - mc32_flush_tx_ring(lp); - - /* Update the statistics here. */ + mc32_flush_rx_ring(dev); + mc32_flush_tx_ring(dev); + + mc32_update_stats(dev); return 0; - } + /** - * mc32_get_stats: + * mc32_get_stats - hand back stats to network layer * @dev: The 3c527 card to handle * - * As we currently handle our statistics in software this one is - * easy to handle. With hardware statistics it will get messy - * as the get_stats call will need to send exec mailbox messages and - * need to lock out the multicast reloads. + * We've collected all the stats we can in software already. Now + * it's time to update those kept on-card and return the lot. + * */ static struct net_device_stats *mc32_get_stats(struct net_device *dev) { - struct mc32_local *lp = (struct mc32_local *)dev->priv; + struct mc32_local *lp; + + mc32_update_stats(dev); + + lp = (struct mc32_local *)dev->priv; + return &lp->net_stats; } + /** - * do_mc32_set_multicast_list: + * do_mc32_set_multicast_list - attempt to update multicasts * @dev: 3c527 device to load the list on * @retry: indicates this is not the first call. * - * Actually set or clear the multicast filter for this adaptor. The locking - * issues are handled by this routine. We have to track state as it may take - * multiple calls to get the command sequence completed. We just keep trying - * to schedule the loads until we manage to process them all. * - * num_addrs == -1 Promiscuous mode, receive all packets + * Actually set or clear the multicast filter for this adaptor. The + * locking issues are handled by this routine. We have to track + * state as it may take multiple calls to get the command sequence + * completed. We just keep trying to schedule the loads until we + * manage to process them all. + * + * num_addrs == -1 Promiscuous mode, receive all packets + * + * num_addrs == 0 Normal mode, clear multicast list + * + * num_addrs > 0 Multicast mode, receive normal and MC packets, + * and do best-effort filtering. * - * num_addrs == 0 Normal mode, clear multicast list + * See mc32_update_stats() regards setting the SAV BP bit. * - * num_addrs > 0 Multicast mode, receive normal and MC packets, - * and do best-effort filtering. */ static void do_mc32_set_multicast_list(struct net_device *dev, int retry) { struct mc32_local *lp = (struct mc32_local *)dev->priv; - u16 filt; + u16 filt = (1<<2); /* Save Bad Packets, for stats purposes */ if (dev->flags&IFF_PROMISC) /* Enable promiscuous mode */ - filt = 1; + filt |= 1; else if((dev->flags&IFF_ALLMULTI) || dev->mc_count > 10) { dev->flags|=IFF_PROMISC; - filt = 1; + filt |= 1; } else if(dev->mc_count) { @@ -1374,9 +1581,7 @@ static void do_mc32_set_multicast_list(struct net_device *dev, int retry) struct dev_mc_list *dmc=dev->mc_list; int i; - - filt = 0; - + if(retry==0) lp->mc_list_valid = 0; if(!lp->mc_list_valid) @@ -1399,39 +1604,40 @@ static void do_mc32_set_multicast_list(struct net_device *dev, int retry) lp->mc_list_valid=1; } } - else - { - filt = 0; - } - if(mc32_command_nowait(dev, 0, &filt, 2)==-1) + + if(mc32_command_nowait(dev, 0, &filt, 2)==-1) { lp->mc_reload_wait = 1; + } + else { + lp->mc_reload_wait = 0; } } + /** - * mc32_set_multicast_list: + * mc32_set_multicast_list - queue multicast list update * @dev: The 3c527 to use * * Commence loading the multicast list. This is called when the kernel * changes the lists. It will override any pending list we are trying to * load. */ - + static void mc32_set_multicast_list(struct net_device *dev) { do_mc32_set_multicast_list(dev,0); } + /** - * mc32_reset_multicast_list: + * mc32_reset_multicast_list - reset multicast list * @dev: The 3c527 to use * * Attempt the next step in loading the multicast lists. If this attempt * fails to complete then it will be scheduled and this function called * again later from elsewhere. */ - static void mc32_reset_multicast_list(struct net_device *dev) { @@ -1442,19 +1648,18 @@ static void mc32_reset_multicast_list(struct net_device *dev) static struct net_device this_device; - /** - * init_module: + * init_module - entry point * * Probe and locate a 3c527 card. This really should probe and locate * all the 3c527 cards in the machine not just one of them. Yes you can - * insmod multiple modules for now but its a hack. + * insmod multiple modules for now but it's a hack. */ - + int init_module(void) { int result; - + this_device.init = mc32_probe; if ((result = register_netdev(&this_device)) != 0) return result; @@ -1463,7 +1668,7 @@ int init_module(void) } /** - * cleanup_module: + * cleanup_module - free resources for an unload * * Unloading time. We release the MCA bus resources and the interrupt * at which point everything is ready to unload. The card must be stopped @@ -1472,7 +1677,7 @@ int init_module(void) * initialized it must be rebooted or the rings reloaded before any * transmit operations are allowed to start scribbling into memory. */ - + void cleanup_module(void) { int slot; @@ -1493,6 +1698,7 @@ void cleanup_module(void) kfree(this_device.priv); } free_irq(this_device.irq, &this_device); + release_region(this_device.base_addr, MC32_IO_EXTENT); } #endif /* MODULE */ diff --git a/drivers/net/3c527.h b/drivers/net/3c527.h index dfe2738cb..a696d0ef5 100644 --- a/drivers/net/3c527.h +++ b/drivers/net/3c527.h @@ -7,11 +7,19 @@ */ #define HOST_CMD 0 +#define HOST_CMD_START_RX (1<<3) +#define HOST_CMD_SUSPND_RX (3<<3) +#define HOST_CMD_RESTRT_RX (5<<3) + +#define HOST_CMD_SUSPND_TX 3 +#define HOST_CMD_RESTRT_TX 5 + #define HOST_STATUS 2 #define HOST_STATUS_CRR (1<<6) #define HOST_STATUS_CWR (1<<5) + #define HOST_CTRL 6 #define HOST_CTRL_ATTN (1<<7) #define HOST_CTRL_RESET (1<<6) @@ -19,6 +27,17 @@ #define HOST_RAMPAGE 8 +#define RX_HALTED (1<<0) +#define TX_HALTED (1<<1) +#define HALTED (RX_HALTED | TX_HALTED) +#define RUNNING 0 + +struct mc32_mailbox +{ + u16 mbox __attribute((packed)); + u16 data[1] __attribute((packed)); +}; + struct skb_header { u8 status __attribute((packed)); @@ -28,13 +47,37 @@ struct skb_header u32 data __attribute((packed)); }; -#define STATUS_MASK 0x0F -#define COMPLETED 0x80 -#define COMPLETED_OK 0x40 -#define BUFFER_BUSY 0x20 +struct mc32_stats +{ + /* RX Errors */ + u32 rx_crc_errors __attribute((packed)); + u32 rx_alignment_errors __attribute((packed)); + u32 rx_overrun_errors __attribute((packed)); + u32 rx_tooshort_errors __attribute((packed)); + u32 rx_toolong_errors __attribute((packed)); + u32 rx_outofresource_errors __attribute((packed)); + + u32 rx_discarded __attribute((packed)); /* via card pattern match filter */ -#define CONTROL_EOP 0x80 /* End Of Packet */ -#define CONTROL_EL 0x40 /* End of List */ + /* TX Errors */ + u32 tx_max_collisions __attribute((packed)); + u32 tx_carrier_errors __attribute((packed)); + u32 tx_underrun_errors __attribute((packed)); + u32 tx_cts_errors __attribute((packed)); + u32 tx_timeout_errors __attribute((packed)) ; + + /* various cruft */ + u32 dataA[6] __attribute((packed)); + u16 dataB[5] __attribute((packed)); + u32 dataC[14] __attribute((packed)); +}; + +#define STATUS_MASK 0x0F +#define COMPLETED (1<<7) +#define COMPLETED_OK (1<<6) +#define BUFFER_BUSY (1<<5) +#define CONTROL_EOP (1<<7) /* End Of Packet */ +#define CONTROL_EOL (1<<6) /* End of List */ -#define MCA_MC32_ID 0x0041 /* Our MCA ident */
\ No newline at end of file +#define MCA_MC32_ID 0x0041 /* Our MCA ident */ diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 98b704665..6b0f19670 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -118,7 +118,7 @@ LK1.1.11 13 Nov 2000 andrewm - Dump MOD_INC/DEC_USE_COUNT, use SET_MODULE_OWNER - LK1.1.12 1 Jan 2001 andrewm + LK1.1.12 1 Jan 2001 andrewm (2.4.0-pre1) - Call pci_enable_device before we request our IRQ (Tobias Ringstrom) - Add 3c590 PCI latency timer hack to vortex_probe1 (from 0.99Ra) - Added extended wait_for_completion for the 3c905CX. @@ -126,12 +126,28 @@ - Add HAS_NWAY to 3cSOHO100-TX (Brett Frankenberger) - Don't free skbs we don't own on oom path in vortex_open(). + LK1.1.13 27 Jan 2001 + - Added explicit `medialock' flag so we can truly + lock the media type down with `options'. + - "check ioremap return and some tidbits" (Arnaldo Carvalho de Melo <acme@conectiva.com.br>) + - Added and used EEPROM_NORESET for 3c556B PM resumes. + - Fixed leakage of vp->rx_ring. + - Break out separate HAS_HWCKSM device capability flag. + - Kill vp->tx_full (ANK) + - Merge zerocopy fragment handling (ANK?) + + LK1.1.14 15 Feb 2001 + - Enable WOL. Can be turned on with `enable_wol' module option. + - EISA and PCI initialisation fixes (jgarzik, Manfred Spraul) + - If a device's internalconfig register reports it has NWAY, + use it, even if autoselect is enabled. + - See http://www.uow.edu.au/~andrewm/linux/#3c59x-2.3 for more details. - Also see Documentation/networking/vortex.txt */ /* - * FIXME: This driver _could_ support MTU changing, but doesn't. See Don's hamaci.c implementation + * FIXME: This driver _could_ support MTU changing, but doesn't. See Don's hamachi.c implementation * as well as other drivers * * NOTE: If you make 'vortex_debug' a constant (#define vortex_debug 0) the driver shrinks by 2k @@ -154,15 +170,11 @@ static const int mtu = 1500; /* Maximum events (Rx packets, etc.) to handle at each interrupt. */ static int max_interrupt_work = 32; /* Tx timeout interval (millisecs) */ -static int watchdog = 400; +static int watchdog = 5000; /* Allow aggregation of Tx interrupts. Saves CPU load at the cost * of possible Tx stalls if the system is blocking interrupts * somewhere else. Undefine this to disable. - * AKPM 26 April 2000: enabling this still gets vestigial Tx timeouts - * in a heavily loaded (collision-prone) 10BaseT LAN. Should be OK with - * switched Ethernet. - * AKPM 24May00: vestigial timeouts have been removed by later fixes. */ #define tx_interrupt_mitigation 1 @@ -174,10 +186,6 @@ static int vortex_debug = VORTEX_DEBUG; static int vortex_debug = 1; #endif -/* Some values here only for performance evaluation and path-coverage - debugging. */ -static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0, rx_csumhits; - #ifndef __OPTIMIZE__ #error You must compile this file with the correct options! #error See the last lines of the source file. @@ -211,14 +219,16 @@ static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0, rx_csumhits; #include <linux/delay.h> static char version[] __devinitdata = -"3c59x.c:LK1.1.12 06 Jan 2000 Donald Becker and others. http://www.scyld.com/network/vortex.html " "$Revision: 1.102.2.46 $\n"; +"3c59x.c:LK1.1.13 27 Jan 2001 Donald Becker and others. http://www.scyld.com/network/vortex.html\n"; MODULE_AUTHOR("Donald Becker <becker@scyld.com>"); MODULE_DESCRIPTION("3Com 3c59x/3c90x/3c575 series Vortex/Boomerang/Cyclone driver"); MODULE_PARM(debug, "i"); MODULE_PARM(options, "1-" __MODULE_STRING(8) "i"); MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i"); +MODULE_PARM(hw_checksums, "1-" __MODULE_STRING(8) "i"); MODULE_PARM(flow_ctrl, "1-" __MODULE_STRING(8) "i"); +MODULE_PARM(enable_wol, "1-" __MODULE_STRING(8) "i"); MODULE_PARM(rx_copybreak, "i"); MODULE_PARM(max_interrupt_work, "i"); MODULE_PARM(compaq_ioaddr, "i"); @@ -332,7 +342,7 @@ enum { IS_VORTEX=1, IS_BOOMERANG=2, IS_CYCLONE=4, IS_TORNADO=8, EEPROM_8BIT=0x10, /* AKPM: Uses 0x230 as the base bitmaps for EEPROM reads */ HAS_PWR_CTRL=0x20, HAS_MII=0x40, HAS_NWAY=0x80, HAS_CB_FNS=0x100, INVERT_MII_PWR=0x200, INVERT_LED_PWR=0x400, MAX_COLLISION_RESET=0x800, - EEPROM_OFFSET=0x1000 }; + EEPROM_OFFSET=0x1000, EEPROM_NORESET=0x2000, HAS_HWCKSM=0x4000 }; enum vortex_chips { CH_3C590 = 0, @@ -405,58 +415,65 @@ static struct vortex_chip_info { {"3c900 Boomerang 10Mbps Combo", PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, }, {"3c900 Cyclone 10Mbps TPO", /* AKPM: from Don's 0.99M */ - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, }, {"3c900 Cyclone 10Mbps Combo", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, }, {"3c900 Cyclone 10Mbps TPC", /* AKPM: from Don's 0.99M */ - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, }, {"3c900B-FL Cyclone 10base-FL", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, }, {"3c905 Boomerang 100baseTx", PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, }, {"3c905 Boomerang 100baseT4", PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, }, {"3c905B Cyclone 100baseTx", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, }, {"3c905B Cyclone 10/100/BNC", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, }, {"3c905B-FX Cyclone 100baseFx", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, }, {"3c905C Tornado", - PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, }, {"3c980 Cyclone", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, }, {"3c980 10/100 Base-TX NIC(Python-T)", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, }, {"3cSOHO100-TX Hurricane", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, }, {"3c555 Laptop Hurricane", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|EEPROM_8BIT, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|EEPROM_8BIT|HAS_HWCKSM, 128, }, {"3c556 Laptop Tornado", - PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|EEPROM_8BIT|HAS_CB_FNS|INVERT_MII_PWR, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|EEPROM_8BIT|HAS_CB_FNS|INVERT_MII_PWR| + HAS_HWCKSM, 128, }, {"3c556B Laptop Hurricane", - PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|EEPROM_OFFSET|HAS_CB_FNS|INVERT_MII_PWR, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|EEPROM_OFFSET|HAS_CB_FNS|INVERT_MII_PWR| + EEPROM_NORESET|HAS_HWCKSM, 128, }, {"3c575 [Megahertz] 10/100 LAN CardBus", - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_8BIT, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_8BIT, 128, }, {"3c575 Boomerang CardBus", PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_8BIT, 128, }, {"3CCFE575BT Cyclone CardBus", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_LED_PWR, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT| + INVERT_LED_PWR|HAS_HWCKSM, 128, }, {"3CCFE575CT Tornado CardBus", - PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|MAX_COLLISION_RESET, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR| + MAX_COLLISION_RESET|HAS_HWCKSM, 128, }, {"3CCFE656 Cyclone CardBus", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|INVERT_LED_PWR, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR| + INVERT_LED_PWR|HAS_HWCKSM, 128, }, {"3CCFEM656B Cyclone+Winmodem CardBus", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|INVERT_LED_PWR, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR| + INVERT_LED_PWR|HAS_HWCKSM, 128, }, {"3CXFEM656C Tornado+Winmodem CardBus", /* From pcmcia-cs-3.1.5 */ - PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|MAX_COLLISION_RESET, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR| + MAX_COLLISION_RESET|HAS_HWCKSM, 128, }, {"3c450 HomePNA Tornado", /* AKPM: from Don's 0.99Q */ - PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, }, {0,}, /* 0 terminated list. */ }; @@ -631,11 +648,24 @@ enum rx_desc_status { IPChksumValid=1<<29, TCPChksumValid=1<<30, UDPChksumValid=1<<31, }; +#ifdef MAX_SKB_FRAGS +#define DO_ZEROCOPY 1 +#else +#define DO_ZEROCOPY 0 +#endif + struct boom_tx_desc { u32 next; /* Last entry points to 0. */ s32 status; /* bits 0:12 length, others see below. */ - u32 addr; - s32 length; +#if DO_ZEROCOPY + struct { + u32 addr; + s32 length; + } frag[1+MAX_SKB_FRAGS]; +#else + u32 addr; + s32 length; +#endif }; /* Values for the Tx status entry. */ @@ -668,6 +698,10 @@ struct vortex_private { struct pci_dev *pdev; char *cb_fn_base; /* CardBus function status addr space. */ + /* Some values here only for performance evaluation and path-coverage */ + int rx_nocopy, rx_copy, queued_packet, rx_csumhits; + int card_idx; + /* The remainder are related to chip state, mostly media selection. */ struct timer_list timer; /* Media selection timer. */ struct timer_list rx_oom_timer; /* Rx skb allocation retry timer */ @@ -679,9 +713,10 @@ struct vortex_private { full_bus_master_tx:1, full_bus_master_rx:2, /* Boomerang */ flow_ctrl:1, /* Use 802.3x flow control (PAUSE only) */ partner_flow_ctrl:1, /* Partner supports flow control */ - tx_full:1, has_nway:1, + enable_wol:1, /* Wake-on-LAN is enabled */ open:1, + medialock:1, must_free_region:1; /* Flag: if zero, Cardbus owns the I/O region */ int drv_flags; u16 status_enable; @@ -755,7 +790,9 @@ static void acpi_set_WOL(struct net_device *dev); #define MAX_UNITS 8 static int options[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1,}; static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; +static int hw_checksums[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; static int flow_ctrl[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; +static int enable_wol[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; /* #define dev_alloc_skb dev_alloc_skb_debug */ @@ -828,8 +865,7 @@ static int __init vortex_eisa_init (void) } rc = vortex_probe1(NULL, ioaddr, inw(ioaddr + 0xC88) >> 12, - EISA_TBL_OFFSET, - vortex_cards_found); + EISA_TBL_OFFSET, vortex_cards_found); if (rc == 0) vortex_cards_found++; else @@ -889,9 +925,9 @@ static int __devinit vortex_probe1(struct pci_dev *pdev, } dev = init_etherdev(NULL, sizeof(*vp)); + retval = -ENOMEM; if (!dev) { printk (KERN_ERR PFX "unable to allocate etherdev, aborting\n"); - retval = -ENOMEM; goto out; } SET_MODULE_OWNER(dev); @@ -909,6 +945,7 @@ static int __devinit vortex_probe1(struct pci_dev *pdev, vp->drv_flags = vci->drv_flags; vp->has_nway = (vci->drv_flags & HAS_NWAY) ? 1 : 0; vp->io_size = vci->io_size; + vp->card_idx = card_idx; /* module list only for EISA devices */ if (pdev == NULL) { @@ -953,10 +990,9 @@ static int __devinit vortex_probe1(struct pci_dev *pdev, vp->rx_ring = pci_alloc_consistent(pdev, sizeof(struct boom_rx_desc) * RX_RING_SIZE + sizeof(struct boom_tx_desc) * TX_RING_SIZE, &vp->rx_ring_dma); - if (vp->rx_ring == 0) { - retval = -ENOMEM; + retval = -ENOMEM; + if (vp->rx_ring == 0) goto free_region; - } vp->tx_ring = (struct boom_tx_desc *)(vp->rx_ring + RX_RING_SIZE); vp->tx_ring_dma = vp->rx_ring_dma + sizeof(struct boom_rx_desc) * RX_RING_SIZE; @@ -964,7 +1000,7 @@ static int __devinit vortex_probe1(struct pci_dev *pdev, /* if we are a PCI driver, we store info in pdev->driver_data * instead of a module list */ if (pdev) - pdev->driver_data = dev; + pci_set_drvdata(pdev, dev); /* The lower four bits are the media type. */ if (dev->mem_start) { @@ -982,6 +1018,8 @@ static int __devinit vortex_probe1(struct pci_dev *pdev, vp->media_override = 7; if (option >= 0) { vp->media_override = ((option & 7) == 2) ? 0 : option & 15; + if (vp->media_override != 7) + vp->medialock = 1; vp->full_duplex = (option & 0x200) ? 1 : 0; vp->bus_master = (option & 16) ? 1 : 0; } @@ -991,6 +1029,8 @@ static int __devinit vortex_probe1(struct pci_dev *pdev, vp->full_duplex = 1; if (flow_ctrl[card_idx] > 0) vp->flow_ctrl = 1; + if (enable_wol[card_idx] > 0) + vp->enable_wol = 1; } vp->force_fd = vp->full_duplex; @@ -1049,7 +1089,7 @@ static int __devinit vortex_probe1(struct pci_dev *pdev, EL3WINDOW(4); step = (inb(ioaddr + Wn4_NetDiag) & 0x1e) >> 1; - printk(KERN_INFO " product code '%c%c' rev %02x.%d date %02d-" + printk(KERN_INFO " product code %02x%02x rev %02x.%d date %02d-" "%02d-%02d\n", eeprom[6]&0xff, eeprom[6]>>8, eeprom[0x14], step, (eeprom[4]>>5) & 15, eeprom[4] & 31, eeprom[4]>>9); @@ -1059,8 +1099,12 @@ static int __devinit vortex_probe1(struct pci_dev *pdev, unsigned short n; fn_st_addr = pci_resource_start (pdev, 2); - if (fn_st_addr) + if (fn_st_addr) { vp->cb_fn_base = ioremap(fn_st_addr, 128); + retval = -ENOMEM; + if (!vp->cb_fn_base) + goto free_ring; + } printk(KERN_INFO "%s: CardBus functions mapped %8.8lx->%p\n", dev->name, fn_st_addr, vp->cb_fn_base); EL3WINDOW(2); @@ -1102,6 +1146,8 @@ static int __devinit vortex_probe1(struct pci_dev *pdev, XCVR(config) > XCVR_ExtMII ? "<invalid transceiver>" : media_tbl[XCVR(config)].name); vp->default_media = XCVR(config); + if (vp->default_media == XCVR_NWAY) + vp->has_nway = 1; vp->autoselect = AUTOSELECT(config); } @@ -1154,7 +1200,7 @@ static int __devinit vortex_probe1(struct pci_dev *pdev, } } - if (vp->capabilities & CapPwrMgmt) + if (pdev && vp->enable_wol && (vp->capabilities & CapPwrMgmt)) acpi_set_WOL(dev); if (vp->capabilities & CapBusMaster) { @@ -1167,21 +1213,44 @@ static int __devinit vortex_probe1(struct pci_dev *pdev, /* The 3c59x-specific entries in the device structure. */ dev->open = vortex_open; - dev->hard_start_xmit = vp->full_bus_master_tx ? - boomerang_start_xmit : vortex_start_xmit; + if (vp->full_bus_master_tx) { + dev->hard_start_xmit = boomerang_start_xmit; +#ifndef CONFIG_HIGHMEM + /* Actually, it still should work with iommu. */ + dev->features |= NETIF_F_SG; +#endif + if (((hw_checksums[card_idx] == -1) && (vp->drv_flags & HAS_HWCKSM)) || + (hw_checksums[card_idx] == 1)) { + dev->features |= NETIF_F_IP_CSUM; + } + } else { + dev->hard_start_xmit = vortex_start_xmit; + } + + if (vortex_debug > 0) { + printk(KERN_INFO "%s: scatter/gather %sabled. h/w checksums %sabled\n", + dev->name, + (dev->features & NETIF_F_SG) ? "en":"dis", + (dev->features & NETIF_F_IP_CSUM) ? "en":"dis"); + } + dev->stop = vortex_close; dev->get_stats = vortex_get_stats; dev->do_ioctl = vortex_ioctl; dev->set_multicast_list = set_rx_mode; dev->tx_timeout = vortex_tx_timeout; dev->watchdog_timeo = (watchdog * HZ) / 1000; -// publish_netdev(dev); return 0; +free_ring: + pci_free_consistent(pdev, + sizeof(struct boom_rx_desc) * RX_RING_SIZE + + sizeof(struct boom_tx_desc) * TX_RING_SIZE, + vp->rx_ring, + vp->rx_ring_dma); free_region: if (vp->must_free_region) release_region(ioaddr, vci->io_size); -// withdraw_netdev(dev); unregister_netdev(dev); kfree (dev); printk(KERN_ERR PFX "vortex_probe1 fails. Returns %d\n", retval); @@ -1189,7 +1258,8 @@ out: return retval; } -static void wait_for_completion(struct net_device *dev, int cmd) +static void +wait_for_completion(struct net_device *dev, int cmd) { int i; @@ -1202,7 +1272,8 @@ static void wait_for_completion(struct net_device *dev, int cmd) /* OK, that didn't work. Do it the slow way. One second */ for (i = 0; i < 100000; i++) { if (!(inw(dev->base_addr + EL3_STATUS) & CmdInProgress)) { - printk(KERN_INFO "%s: command 0x%04x took %d usecs! Please tell andrewm@uow.edu.au\n", + if (vortex_debug > 1) + printk(KERN_INFO "%s: command 0x%04x took %d usecs\n", dev->name, cmd, i * 10); return; } @@ -1218,26 +1289,23 @@ vortex_up(struct net_device *dev) long ioaddr = dev->base_addr; struct vortex_private *vp = (struct vortex_private *)dev->priv; unsigned int config; - int i, device_id; + int i; + + if (vp->pdev && vp->enable_wol) /* AKPM: test not needed? */ + pci_set_power_state(vp->pdev, 0); /* Go active */ - if (vp->pdev) - device_id = vp->pdev->device; - else - device_id = 0x5900; /* EISA */ - /* Before initializing select the active media port. */ EL3WINDOW(3); config = inl(ioaddr + Wn3_Config); if (vp->media_override != 7) { - if (vortex_debug > 1) - printk(KERN_INFO "%s: Media override to transceiver %d (%s).\n", - dev->name, vp->media_override, - media_tbl[vp->media_override].name); + 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) { if (vp->has_nway) { - printk(KERN_INFO "%s: using NWAY autonegotiation\n", dev->name); + printk(KERN_INFO "%s: using NWAY device table, not %d\n", dev->name, dev->if_port); dev->if_port = XCVR_NWAY; } else { /* Find first available media type, starting with 100baseTx. */ @@ -1245,8 +1313,7 @@ vortex_up(struct net_device *dev) while (! (vp->available_media & media_tbl[dev->if_port].mask)) dev->if_port = media_tbl[dev->if_port].next; printk(KERN_INFO "%s: first available media type: %s\n", - dev->name, - media_tbl[dev->if_port].name); + dev->name, media_tbl[dev->if_port].name); } } else { dev->if_port = vp->default_media; @@ -1270,13 +1337,9 @@ vortex_up(struct net_device *dev) vp->full_duplex = vp->force_fd; config = BFINS(config, dev->if_port, 20, 4); -//AKPM if (!vp->has_nway) - { - if (vortex_debug > 6) - printk(KERN_DEBUG "vortex_up(): writing 0x%x to InternalConfig\n", - config); - outl(config, ioaddr + Wn3_Config); - } + if (vortex_debug > 6) + printk(KERN_DEBUG "vortex_up(): writing 0x%x to InternalConfig\n", config); + outl(config, ioaddr + Wn3_Config); if (dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) { int mii_reg1, mii_reg5; @@ -1292,8 +1355,10 @@ vortex_up(struct net_device *dev) vp->partner_flow_ctrl = ((mii_reg5 & 0x0400) != 0); if (vortex_debug > 1) printk(KERN_INFO "%s: MII #%d status %4.4x, link partner capability %4.4x," - " setting %s-duplex.\n", dev->name, vp->phys[0], - mii_reg1, mii_reg5, vp->full_duplex ? "full" : "half"); + " info1 %04x, setting %s-duplex.\n", + dev->name, vp->phys[0], + mii_reg1, mii_reg5, + vp->info1, ((vp->info1 & 0x8000) || vp->full_duplex) ? "full" : "half"); EL3WINDOW(3); } @@ -1411,6 +1476,9 @@ vortex_open(struct net_device *dev) int i; int retval; + if (vp->pdev && vp->enable_wol) /* AKPM: test not needed? */ + pci_set_power_state(vp->pdev, 0); /* Go active */ + /* Use the now-standard shared IRQ implementation. */ if ((retval = request_irq(dev->irq, vp->full_bus_master_rx ? &boomerang_interrupt : &vortex_interrupt, SA_SHIRQ, dev->name, dev))) { @@ -1452,7 +1520,6 @@ vortex_open(struct net_device *dev) vortex_up(dev); vp->open = 1; - vp->tx_full = 0; return 0; out_free_irq: @@ -1463,7 +1530,8 @@ out: return retval; } -static void vortex_timer(unsigned long data) +static void +vortex_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; struct vortex_private *vp = (struct vortex_private *)dev->priv; @@ -1478,6 +1546,8 @@ static void vortex_timer(unsigned long data) printk(KERN_DEBUG "dev->watchdog_timeo=%d\n", dev->watchdog_timeo); } + if (vp->medialock) + goto leave_media_alone; disable_irq(dev->irq); old_window = inw(ioaddr + EL3_CMD) >> 13; EL3WINDOW(4); @@ -1512,7 +1582,7 @@ static void vortex_timer(unsigned long data) dev->name, vp->full_duplex ? "full" : "half", vp->phys[0], mii_reg5); /* Set the full-duplex bit. */ - EL3WINDOW(3); /* AKPM: this was missing from 2.3.99 3c59x.c! */ + EL3WINDOW(3); outw( (vp->full_duplex ? 0x20 : 0) | (dev->mtu > 1500 ? 0x40 : 0) | ((vp->full_duplex && vp->flow_ctrl && vp->partner_flow_ctrl) ? 0x100 : 0), @@ -1567,6 +1637,7 @@ static void vortex_timer(unsigned long data) EL3WINDOW(old_window); enable_irq(dev->irq); +leave_media_alone: if (vortex_debug > 2) printk(KERN_DEBUG "%s: Media selection timer finished, %s.\n", dev->name, media_tbl[dev->if_port].name); @@ -1599,8 +1670,7 @@ static void vortex_tx_timeout(struct net_device *dev) /* Bad idea here.. but we might as well handle a few events. */ { /* - * AKPM: block interrupts because vortex_interrupt - * does a bare spin_lock() + * Block interrupts because vortex_interrupt does a bare spin_lock() */ unsigned long flags; local_irq_save(flags); @@ -1619,18 +1689,12 @@ static void vortex_tx_timeout(struct net_device *dev) vp->stats.tx_errors++; if (vp->full_bus_master_tx) { - if (vortex_debug > 0) - printk(KERN_DEBUG "%s: Resetting the Tx ring pointer.\n", - dev->name); + printk(KERN_DEBUG "%s: Resetting the Tx ring pointer.\n", dev->name); if (vp->cur_tx - vp->dirty_tx > 0 && inl(ioaddr + DownListPtr) == 0) outl(vp->tx_ring_dma + (vp->dirty_tx % TX_RING_SIZE) * sizeof(struct boom_tx_desc), ioaddr + DownListPtr); - if (vp->tx_full && (vp->cur_tx - vp->dirty_tx <= TX_RING_SIZE - 1)) { - vp->tx_full = 0; + if (vp->cur_tx - vp->dirty_tx < TX_RING_SIZE) netif_wake_queue (dev); - } - if (vp->tx_full) - netif_stop_queue (dev); if (vp->drv_flags & IS_BOOMERANG) outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); outw(DownUnstall, ioaddr + EL3_CMD); @@ -1820,17 +1884,53 @@ boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->name, vp->cur_tx); } - if (vp->tx_full) { + if (vp->cur_tx - vp->dirty_tx >= TX_RING_SIZE) { if (vortex_debug > 0) - printk(KERN_WARNING "%s: Tx Ring full, refusing to send buffer.\n", + printk(KERN_WARNING "%s: BUG! Tx Ring full, refusing to send buffer.\n", dev->name); + netif_stop_queue(dev); return 1; } + vp->tx_skbuff[entry] = skb; + vp->tx_ring[entry].next = 0; +#if DO_ZEROCOPY + if (skb->ip_summed != CHECKSUM_HW) + vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded); + else + vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded | AddTCPChksum); + + if (!skb_shinfo(skb)->nr_frags) { + vp->tx_ring[entry].frag[0].addr = cpu_to_le32(pci_map_single(vp->pdev, skb->data, + skb->len, PCI_DMA_TODEVICE)); + vp->tx_ring[entry].frag[0].length = cpu_to_le32(skb->len | LAST_FRAG); + } else { + int i; + + vp->tx_ring[entry].frag[0].addr = cpu_to_le32(pci_map_single(vp->pdev, skb->data, + skb->len-skb->data_len, PCI_DMA_TODEVICE)); + vp->tx_ring[entry].frag[0].length = cpu_to_le32(skb->len-skb->data_len); + + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + + vp->tx_ring[entry].frag[i+1].addr = + cpu_to_le32(pci_map_single(vp->pdev, + (void*)page_address(frag->page) + frag->page_offset, + frag->size, PCI_DMA_TODEVICE)); + + if (i == skb_shinfo(skb)->nr_frags-1) + vp->tx_ring[entry].frag[i+1].length = cpu_to_le32(frag->size|LAST_FRAG); + else + vp->tx_ring[entry].frag[i+1].length = cpu_to_le32(frag->size); + } + } +#else vp->tx_ring[entry].addr = cpu_to_le32(pci_map_single(vp->pdev, skb->data, skb->len, PCI_DMA_TODEVICE)); vp->tx_ring[entry].length = cpu_to_le32(skb->len | LAST_FRAG); vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded); +#endif spin_lock_irqsave(&vp->lock, flags); /* Wait for the stall to complete. */ @@ -1838,18 +1938,19 @@ boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev) prev_entry->next = cpu_to_le32(vp->tx_ring_dma + entry * sizeof(struct boom_tx_desc)); if (inl(ioaddr + DownListPtr) == 0) { outl(vp->tx_ring_dma + entry * sizeof(struct boom_tx_desc), ioaddr + DownListPtr); - queued_packet++; + vp->queued_packet++; } vp->cur_tx++; if (vp->cur_tx - vp->dirty_tx > TX_RING_SIZE - 1) { - vp->tx_full = 1; netif_stop_queue (dev); } else { /* Clear previous interrupt enable. */ #if defined(tx_interrupt_mitigation) + /* Dubious. If in boomeang_interrupt "faster" cyclone ifdef + * were selected, this would corrupt DN_COMPLETE. No? + */ prev_entry->status &= cpu_to_le32(~TxIntrUploaded); #endif - /* netif_start_queue (dev); */ /* AKPM: redundant? */ } outw(DownUnstall, ioaddr + EL3_CMD); spin_unlock_irqrestore(&vp->lock, flags); @@ -1889,7 +1990,7 @@ static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs) vp->deferred = 0; } - if (status == 0xffff) /* AKPM: h/w no longer present (hotplug)? */ + if (status == 0xffff) /* h/w no longer present (hotplug)? */ goto handler_exit; if (vortex_debug > 4) @@ -1925,7 +2026,7 @@ static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs) netif_wake_queue(dev); } else { /* Interrupt when FIFO has room for max-sized packet. */ outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD); - netif_stop_queue(dev); /* AKPM: This is new */ + netif_stop_queue(dev); } } } @@ -1990,7 +2091,7 @@ static void boomerang_interrupt(int irq, void *dev_id, struct pt_regs *regs) if ((status & IntLatch) == 0) goto handler_exit; /* No interrupt: shared IRQs can cause this */ - if (status == 0xffff) { /* AKPM: h/w no longer present (hotplug)? */ + if (status == 0xffff) { /* h/w no longer present (hotplug)? */ if (vortex_debug > 1) printk(KERN_DEBUG "boomerang_interrupt(1): status = 0xffff\n"); goto handler_exit; @@ -2032,9 +2133,17 @@ static void boomerang_interrupt(int irq, void *dev_id, struct pt_regs *regs) if (vp->tx_skbuff[entry]) { struct sk_buff *skb = vp->tx_skbuff[entry]; - +#if DO_ZEROCOPY + int i; + for (i=0; i<=skb_shinfo(skb)->nr_frags; i++) + pci_unmap_single(vp->pdev, + le32_to_cpu(vp->tx_ring[entry].frag[i].addr), + le32_to_cpu(vp->tx_ring[entry].frag[i].length)&0xFFF, + PCI_DMA_TODEVICE); +#else pci_unmap_single(vp->pdev, le32_to_cpu(vp->tx_ring[entry].addr), skb->len, PCI_DMA_TODEVICE); +#endif dev_kfree_skb_irq(skb); vp->tx_skbuff[entry] = 0; } else { @@ -2044,10 +2153,9 @@ static void boomerang_interrupt(int irq, void *dev_id, struct pt_regs *regs) dirty_tx++; } vp->dirty_tx = dirty_tx; - if (vp->tx_full && (vp->cur_tx - dirty_tx <= TX_RING_SIZE - 1)) { + if (vp->cur_tx - dirty_tx <= TX_RING_SIZE - 1) { if (vortex_debug > 6) - printk(KERN_DEBUG "boomerang_interrupt: clearing tx_full\n"); - vp->tx_full = 0; + printk(KERN_DEBUG "boomerang_interrupt: wake queue\n"); netif_wake_queue (dev); } } @@ -2199,14 +2307,14 @@ boomerang_rx(struct net_device *dev) memcpy(skb_put(skb, pkt_len), vp->rx_skbuff[entry]->tail, pkt_len); - rx_copy++; + vp->rx_copy++; } else { /* Pass up the skbuff already on the Rx ring. */ skb = vp->rx_skbuff[entry]; vp->rx_skbuff[entry] = NULL; skb_put(skb, pkt_len); pci_unmap_single(vp->pdev, dma, PKT_BUF_SZ, PCI_DMA_FROMDEVICE); - rx_nocopy++; + vp->rx_nocopy++; } skb->protocol = eth_type_trans(skb, dev); { /* Use hardware checksum info. */ @@ -2215,7 +2323,7 @@ boomerang_rx(struct net_device *dev) (csum_bits == (IPChksumValid | TCPChksumValid) || csum_bits == (IPChksumValid | UDPChksumValid))) { skb->ip_summed = CHECKSUM_UNNECESSARY; - rx_csumhits++; + vp->rx_csumhits++; } } netif_rx(skb); @@ -2301,7 +2409,7 @@ vortex_down(struct net_device *dev) if (vp->full_bus_master_tx) outl(0, ioaddr + DownListPtr); - if (vp->capabilities & CapPwrMgmt) + if (vp->pdev && vp->enable_wol && (vp->capabilities & CapPwrMgmt)) acpi_set_WOL(dev); } @@ -2320,9 +2428,18 @@ vortex_close(struct net_device *dev) dev->name, inw(ioaddr + EL3_STATUS), inb(ioaddr + TxStatus)); printk(KERN_DEBUG "%s: vortex close stats: rx_nocopy %d rx_copy %d" " tx_queued %d Rx pre-checksummed %d.\n", - dev->name, rx_nocopy, rx_copy, queued_packet, rx_csumhits); + dev->name, vp->rx_nocopy, vp->rx_copy, vp->queued_packet, vp->rx_csumhits); } +#if DO_ZEROCOPY + if ( vp->rx_csumhits && + ((vp->drv_flags & HAS_HWCKSM) == 0) && + (hw_checksums[vp->card_idx] == -1)) { + printk(KERN_WARNING "%s supports hardware checksums, and we're not using them!\n", dev->name); + printk(KERN_WARNING "Please see http://www.uow.edu.au/~andrewm/zerocopy.html\n"); + } +#endif + free_irq(dev->irq, dev); if (vp->full_bus_master_rx) { /* Free Boomerang bus master Rx buffers. */ @@ -2335,14 +2452,24 @@ vortex_close(struct net_device *dev) } } if (vp->full_bus_master_tx) { /* Free Boomerang bus master Tx buffers. */ - for (i = 0; i < TX_RING_SIZE; i++) + for (i = 0; i < TX_RING_SIZE; i++) { if (vp->tx_skbuff[i]) { struct sk_buff *skb = vp->tx_skbuff[i]; - +#if DO_ZEROCOPY + int k; + + for (k=0; k<=skb_shinfo(skb)->nr_frags; k++) + pci_unmap_single(vp->pdev, + le32_to_cpu(vp->tx_ring[i].frag[k].addr), + le32_to_cpu(vp->tx_ring[i].frag[k].length)&0xFFF, + PCI_DMA_TODEVICE); +#else pci_unmap_single(vp->pdev, le32_to_cpu(vp->tx_ring[i].addr), skb->len, PCI_DMA_TODEVICE); +#endif dev_kfree_skb(skb); vp->tx_skbuff[i] = 0; } + } } vp->open = 0; @@ -2360,19 +2487,22 @@ dump_tx_ring(struct net_device *dev) int i; int stalled = inl(ioaddr + PktStatus) & 0x04; /* Possible racy. But it's only debug stuff */ - wait_for_completion(dev, DownStall); - printk(KERN_ERR " Flags; bus-master %d, full %d; dirty %d(%d) " - "current %d(%d).\n", - vp->full_bus_master_tx, vp->tx_full, + printk(KERN_ERR " Flags; bus-master %d, dirty %d(%d) current %d(%d)\n", + vp->full_bus_master_tx, vp->dirty_tx, vp->dirty_tx % TX_RING_SIZE, vp->cur_tx, vp->cur_tx % TX_RING_SIZE); printk(KERN_ERR " Transmit list %8.8x vs. %p.\n", inl(ioaddr + DownListPtr), &vp->tx_ring[vp->dirty_tx % TX_RING_SIZE]); + wait_for_completion(dev, DownStall); for (i = 0; i < TX_RING_SIZE; i++) { printk(KERN_ERR " %d: @%p length %8.8x status %8.8x\n", i, &vp->tx_ring[i], +#if DO_ZEROCOPY + le32_to_cpu(vp->tx_ring[i].frag[0].length), +#else le32_to_cpu(vp->tx_ring[i].length), +#endif le32_to_cpu(vp->tx_ring[i].status)); } if (!stalled) @@ -2436,8 +2566,6 @@ static void update_stats(long ioaddr, struct net_device *dev) vp->stats.tx_bytes += (up & 0xf0) << 12; } - /* We change back to window 7 (not 1) with the Vortex. */ - /* AKPM: the previous comment is obsolete - we switch back to the old window */ EL3WINDOW(old_window >> 13); return; } @@ -2600,12 +2728,6 @@ static void acpi_set_WOL(struct net_device *dev) struct vortex_private *vp = (struct vortex_private *)dev->priv; long ioaddr = dev->base_addr; - /* AKPM: This kills the 905 */ - if (vortex_debug > 1) { - printk(KERN_INFO PFX "Wake-on-LAN functions disabled\n"); - } - return; - /* Power up on: 1==Downloaded Filter, 2==Magic Packets, 4==Link Status. */ EL3WINDOW(7); outw(2, ioaddr + 0x0c); @@ -2613,13 +2735,13 @@ static void acpi_set_WOL(struct net_device *dev) outw(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CMD); outw(RxEnable, ioaddr + EL3_CMD); /* Change the power state to D3; RxEnable doesn't take effect. */ - pci_write_config_word(vp->pdev, 0xe0, 0x8103); + pci_set_power_state(vp->pdev, 0x8103); } static void __devexit vortex_remove_one (struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; + struct net_device *dev = pci_get_drvdata(pdev); struct vortex_private *vp; if (!dev) { @@ -2627,14 +2749,20 @@ static void __devexit vortex_remove_one (struct pci_dev *pdev) BUG(); } - vp = (void *)(dev->priv); + vp = dev->priv; /* AKPM: FIXME: we should have * if (vp->cb_fn_base) iounmap(vp->cb_fn_base); * here */ unregister_netdev(dev); - outw(TotalReset, dev->base_addr + EL3_CMD); + /* Should really use wait_for_completion() here */ + outw((vp->drv_flags & EEPROM_NORESET) ? (TotalReset|0x10) : TotalReset, dev->base_addr + EL3_CMD); + pci_free_consistent(pdev, + sizeof(struct boom_rx_desc) * RX_RING_SIZE + + sizeof(struct boom_tx_desc) * TX_RING_SIZE, + vp->rx_ring, + vp->rx_ring_dma); if (vp->must_free_region) release_region(dev->base_addr, vp->io_size); kfree(dev); @@ -2642,7 +2770,7 @@ static void __devexit vortex_remove_one (struct pci_dev *pdev) static struct pci_driver vortex_driver = { - name: "3c575_cb", + name: "3c59x", probe: vortex_init_one, remove: vortex_remove_one, suspend: vortex_suspend, @@ -2657,18 +2785,17 @@ static int vortex_have_eisa; static int __init vortex_init (void) { - int rc; - - rc = pci_module_init(&vortex_driver); - if (rc < 0) { - rc = vortex_eisa_init(); - if (rc > 0) - vortex_have_eisa = 1; - } else { + int pci_rc, eisa_rc; + + pci_rc = pci_module_init(&vortex_driver); + eisa_rc = vortex_eisa_init(); + + if (pci_rc == 0) vortex_have_pci = 1; - } + if (eisa_rc > 0) + vortex_have_eisa = 1; - return rc; + return (vortex_have_pci + vortex_have_eisa) ? 0 : -ENODEV; } @@ -2708,7 +2835,6 @@ static void __exit vortex_cleanup (void) module_init(vortex_init); module_exit(vortex_cleanup); - /* * Local variables: diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index c7c678ece..3ef480cda 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -3,14 +3,15 @@ 8139too.c: A RealTek RTL-8139 Fast Ethernet driver for Linux. Maintained by Jeff Garzik <jgarzik@mandrakesoft.com> + Copyright 2000,2001 Jeff Garzik Much code comes from Donald Becker's rtl8139.c driver, - versions 1.11 and older. This driver was originally based - on rtl8139.c version 1.07. Header of rtl8139.c version 1.11: + versions 1.13 and older. This driver was originally based + on rtl8139.c version 1.07. Header of rtl8139.c version 1.13: -----<snip>----- - Written 1997-2000 by Donald Becker. + Written 1997-2001 by Donald Becker. This software may be used and distributed according to the terms of the GNU General Public License (GPL), incorporated herein by reference. Drivers based on or derived from this @@ -74,7 +75,7 @@ Tobias Ringström - Rx interrupt status checking suggestion - Andrew Morton - (v0.9.13): clear blocked signals, avoid + Andrew Morton - Clear blocked signals, avoid buffer overrun setting current->comm. Submitting bug reports: @@ -133,8 +134,6 @@ posted MMIO writes to PCI space. This driver works around the problem by having an MMIO register write be immediately followed by an MMIO register read. -2) The RTL-8129 is only supported in Donald Becker's rtl8139 driver. - */ #include <linux/config.h> @@ -150,7 +149,7 @@ an MMIO register read. #include <asm/io.h> -#define RTL8139_VERSION "0.9.13" +#define RTL8139_VERSION "0.9.15c" #define MODNAME "8139too" #define RTL8139_DRIVER_NAME MODNAME " Fast Ethernet driver " RTL8139_VERSION #define PFX MODNAME ": " @@ -188,7 +187,9 @@ an MMIO register read. /* A few user-configurable values. */ /* media options */ -static int media[] = {-1, -1, -1, -1, -1, -1, -1, -1}; +#define MAX_UNITS 8 +static int media[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; +static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; /* Maximum events (Rx packets, etc.) to handle at each interrupt. */ static int max_interrupt_work = 20; @@ -230,6 +231,7 @@ static int multicast_filter_limit = 32; enum { + HAS_MII_XCVR = 0x010000, HAS_CHIP_XCVR = 0x020000, HAS_LNK_CHNG = 0x040000, }; @@ -237,6 +239,7 @@ enum { #define RTL_MIN_IO_SIZE 0x80 #define RTL8139B_IO_SIZE 256 +#define RTL8129_CAPS HAS_MII_XCVR #define RTL8139_CAPS HAS_CHIP_XCVR|HAS_LNK_CHNG typedef enum { @@ -246,19 +249,24 @@ typedef enum { /*MPX5030,*/ DELTA8139, ADDTRON8139, + DFE538TX, + RTL8129, } board_t; /* indexed by board_t, above */ static struct { const char *name; + u32 hw_flags; } board_info[] __devinitdata = { - { "RealTek RTL8139 Fast Ethernet" }, - { "RealTek RTL8139B PCI/CardBus" }, - { "SMC1211TX EZCard 10/100 (RealTek RTL8139)" }, -/* { MPX5030, "Accton MPX5030 (RealTek RTL8139)" },*/ - { "Delta Electronics 8139 10/100BaseTX" }, - { "Addtron Technolgy 8139 10/100BaseTX" }, + { "RealTek RTL8139 Fast Ethernet", RTL8139_CAPS }, + { "RealTek RTL8139B PCI/CardBus", RTL8139_CAPS }, + { "SMC1211TX EZCard 10/100 (RealTek RTL8139)", RTL8139_CAPS }, +/* { MPX5030, "Accton MPX5030 (RealTek RTL8139)", RTL8139_CAPS },*/ + { "Delta Electronics 8139 10/100BaseTX", RTL8139_CAPS }, + { "Addtron Technolgy 8139 10/100BaseTX", RTL8139_CAPS }, + { "D-Link DFE-538TX (RealTek RTL8139)", RTL8139_CAPS }, + { "RealTek RTL8129", RTL8129_CAPS }, }; @@ -269,6 +277,18 @@ static struct pci_device_id rtl8139_pci_tbl[] __devinitdata = { /* {0x1113, 0x1211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MPX5030 },*/ {0x1500, 0x1360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DELTA8139 }, {0x4033, 0x1360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ADDTRON8139 }, + {0x1186, 0x1300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DFE538TX }, + +#ifdef CONFIG_8139TOO_8129 + {0x10ec, 0x8129, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8129 }, +#endif + + /* some crazy cards report invalid vendor ids like + * 0x0001 here. The other ids are valid and constant, + * so we simply don't match on the main vendor id. + */ + {PCI_ANY_ID, 0x8139, 0x10ec, 0x8139, 0, 0, RTL8139 }, + {0,} }; MODULE_DEVICE_TABLE (pci, rtl8139_pci_tbl); @@ -391,10 +411,17 @@ enum Config1Bits { Cfg1_VPD_Enable = 0x02, Cfg1_PIO = 0x04, Cfg1_MMIO = 0x08, - Cfg1_LWAKE = 0x10, + LWAKE = 0x10, /* not on 8139, 8139A */ Cfg1_Driver_Load = 0x20, Cfg1_LED0 = 0x40, Cfg1_LED1 = 0x80, + SLEEP = (1 << 1), /* only on 8139, 8139A */ + PWRDN = (1 << 0), /* only on 8139, 8139A */ +}; + +/* Bits in Config4 */ +enum Config4Bits { + LWPTN = (1 << 2), /* not on 8139, 8139A */ }; enum RxConfigBits { @@ -463,48 +490,59 @@ typedef enum { CH_8139C, } chip_t; +enum chip_flags { + HasPwrDn = (1 << 0), + HasLWake = (1 << 1), +}; + /* directly indexed by chip_t, above */ const static struct { const char *name; u8 version; /* from RTL8139C docs */ u32 RxConfigMask; /* should clear the bits supported by this chip */ + u32 flags; } rtl_chip_info[] = { { "RTL-8139", 0x40, 0xf0fe0040, /* XXX copied from RTL8139A, verify */ + HasPwrDn, }, { "RTL-8139 rev K", 0x60, 0xf0fe0040, + HasPwrDn, }, { "RTL-8139A", 0x70, 0xf0fe0040, + 0, }, { "RTL-8139B", 0x78, - 0xf0fc0040 + 0xf0fc0040, + HasLWake, }, { "RTL-8130", 0x7C, 0xf0fe0040, /* XXX copied from RTL8139A, verify */ + HasLWake, }, { "RTL-8139C", 0x74, 0xf0fc0040, /* XXX copied from RTL8139B, verify */ + HasLWake, }, }; struct rtl8139_private { - board_t board; void *mmio_addr; int drv_flags; struct pci_dev *pci_dev; @@ -512,15 +550,16 @@ struct rtl8139_private { unsigned char *rx_ring; unsigned int cur_rx; /* Index into the Rx buffer of next Rx pkt. */ unsigned int tx_flag; - unsigned int cur_tx; - unsigned int dirty_tx; + unsigned long cur_tx; + unsigned long dirty_tx; /* The saved address of a sent-in-place packet/buffer, for skfree(). */ struct ring_info tx_info[NUM_TX_DESC]; unsigned char *tx_buf[NUM_TX_DESC]; /* Tx bounce buffers */ unsigned char *tx_bufs; /* Tx bounce buffer region. */ dma_addr_t rx_ring_dma; dma_addr_t tx_bufs_dma; - char phys[4]; /* MII device addresses. */ + signed char phys[4]; /* MII device addresses. */ + u16 advertising; /* NWay media advertisement */ char twistie, twist_row, twist_col; /* Twister tune state. */ unsigned int full_duplex:1; /* Full-duplex operation requested. */ unsigned int duplex_lock:1; @@ -539,7 +578,8 @@ MODULE_AUTHOR ("Jeff Garzik <jgarzik@mandrakesoft.com>"); MODULE_DESCRIPTION ("RealTek RTL-8139 Fast Ethernet driver"); MODULE_PARM (multicast_filter_limit, "i"); MODULE_PARM (max_interrupt_work, "i"); -MODULE_PARM (media, "1-" __MODULE_STRING(8) "i"); +MODULE_PARM (media, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM (full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); static int read_eeprom (void *ioaddr, int location, int addr_len); static int rtl8139_open (struct net_device *dev); @@ -627,11 +667,43 @@ static const unsigned int rtl8139_rx_config = (RX_DMA_BURST << RxCfgDMAShift); +static void __rtl8139_cleanup_dev (struct net_device *dev) +{ + struct rtl8139_private *tp; + struct pci_dev *pdev; + + assert (dev != NULL); + assert (dev->priv != NULL); + + tp = dev->priv; + assert (tp->pci_dev != NULL); + pdev = tp->pci_dev; + +#ifndef USE_IO_OPS + if (tp->mmio_addr) + iounmap (tp->mmio_addr); +#endif /* !USE_IO_OPS */ + + /* it's ok to call this even if we have no regions to free */ + pci_release_regions (pdev); + +#ifndef RTL8139_NDEBUG + /* poison memory before freeing */ + memset (dev, 0xBC, + sizeof (struct net_device) + + sizeof (struct rtl8139_private)); +#endif /* RTL8139_NDEBUG */ + + kfree (dev); + + pci_set_drvdata (pdev, NULL); +} + + static int __devinit rtl8139_init_board (struct pci_dev *pdev, - struct net_device **dev_out, - void **ioaddr_out) + struct net_device **dev_out) { - void *ioaddr = NULL; + void *ioaddr; struct net_device *dev; struct rtl8139_private *tp; u8 tmp8; @@ -643,20 +715,24 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev, DPRINTK ("ENTER\n"); assert (pdev != NULL); - assert (ioaddr_out != NULL); - *ioaddr_out = NULL; *dev_out = NULL; - /* dev zeroed in init_etherdev */ - dev = init_etherdev (NULL, sizeof (*tp)); + /* dev and dev->priv zeroed in alloc_etherdev */ + dev = alloc_etherdev (sizeof (*tp)); if (dev == NULL) { - printk (KERN_ERR PFX "unable to alloc new ethernet\n"); + printk (KERN_ERR PFX "%s: Unable to alloc new net device\n", pdev->slot_name); DPRINTK ("EXIT, returning -ENOMEM\n"); return -ENOMEM; } SET_MODULE_OWNER(dev); tp = dev->priv; + tp->pci_dev = pdev; + + /* enable device (incl. PCI PM wakeup and hotplug setup) */ + rc = pci_enable_device (pdev); + if (rc) + goto err_out; pio_start = pci_resource_start (pdev, 0); pio_end = pci_resource_end (pdev, 0); @@ -677,14 +753,14 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev, /* make sure PCI base addr 0 is PIO */ if (!(pio_flags & IORESOURCE_IO)) { - printk (KERN_ERR PFX "region #0 not a PIO resource, aborting\n"); + printk (KERN_ERR PFX "%s: region #0 not a PIO resource, aborting\n", pdev->slot_name); rc = -ENODEV; goto err_out; } /* make sure PCI base addr 1 is MMIO */ if (!(mmio_flags & IORESOURCE_MEM)) { - printk (KERN_ERR PFX "region #1 not an MMIO resource, aborting\n"); + printk (KERN_ERR PFX "%s: region #1 not an MMIO resource, aborting\n", pdev->slot_name); rc = -ENODEV; goto err_out; } @@ -692,75 +768,83 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev, /* check for weird/broken PCI region reporting */ if ((pio_len < RTL_MIN_IO_SIZE) || (mmio_len < RTL_MIN_IO_SIZE)) { - printk (KERN_ERR PFX "Invalid PCI region size(s), aborting\n"); + printk (KERN_ERR PFX "%s: Invalid PCI region size(s), aborting\n", pdev->slot_name); rc = -ENODEV; goto err_out; } - /* make sure our PIO region in PCI space is available */ - if (!request_region (pio_start, pio_len, dev->name)) { - printk (KERN_ERR PFX "no I/O resource available, aborting\n"); - rc = -EBUSY; - goto err_out; - } - - /* make sure our MMIO region in PCI space is available */ - if (!request_mem_region (mmio_start, mmio_len, dev->name)) { - printk (KERN_ERR PFX "no mem resource available, aborting\n"); - rc = -EBUSY; - goto err_out_free_pio; - } - - /* enable device (incl. PCI PM wakeup), and bus-mastering */ - rc = pci_enable_device (pdev); + rc = pci_request_regions (pdev, "8139too"); if (rc) - goto err_out_free_mmio; + goto err_out; + /* enable PCI bus-mastering */ pci_set_master (pdev); #ifdef USE_IO_OPS ioaddr = (void *) pio_start; + dev->base_addr = pio_start; #else /* ioremap MMIO region */ ioaddr = ioremap (mmio_start, mmio_len); if (ioaddr == NULL) { - printk (KERN_ERR PFX "cannot remap MMIO, aborting\n"); + printk (KERN_ERR PFX "%s: cannot remap MMIO, aborting\n", pdev->slot_name); rc = -EIO; - goto err_out_free_mmio; + goto err_out; } + dev->base_addr = (long) ioaddr; + tp->mmio_addr = ioaddr; #endif /* USE_IO_OPS */ + /* Bring the chip out of low-power mode. */ + if (rtl_chip_info[tp->chipset].flags & HasPwrDn) { + tmp8 = RTL_R8 (Config1); + if (tmp8 & (SLEEP|PWRDN)) { + RTL_W8_F (Cfg9346, Cfg9346_Unlock); + RTL_W8 (Config1, tmp8 & ~(SLEEP|PWRDN)); + RTL_W8_F (Cfg9346, Cfg9346_Lock); + } + } else { + u8 new_tmp8 = tmp8 = RTL_R8 (Config1); + if ((rtl_chip_info[tp->chipset].flags & HasLWake) && + (tmp8 & LWAKE)) + new_tmp8 &= ~LWAKE; + new_tmp8 |= Cfg1_PM_Enable; + if (new_tmp8 != tmp8) { + RTL_W8_F (Cfg9346, Cfg9346_Unlock); + RTL_W8 (Config1, tmp8); + RTL_W8_F (Cfg9346, Cfg9346_Lock); + } + if (rtl_chip_info[tp->chipset].flags & HasLWake) { + tmp8 = RTL_R8 (Config4); + if (tmp8 & LWPTN) + RTL_W8 (Config4, tmp8 & ~LWPTN); + } + } + /* Soft reset the chip. */ RTL_W8 (ChipCmd, (RTL_R8 (ChipCmd) & ChipCmdClear) | CmdReset); /* Check that the chip has finished the reset. */ - for (i = 1000; i > 0; i--) + for (i = 1000; i > 0; i--) { + barrier(); + udelay (10); if ((RTL_R8 (ChipCmd) & CmdReset) == 0) break; - else - udelay (10); - - /* Bring the chip out of low-power mode. */ - if (tp->chipset == CH_8139B) { - RTL_W8 (Config1, RTL_R8 (Config1) & ~(1<<4)); - RTL_W8 (Config4, RTL_R8 (Config4) & ~(1<<2)); - } else { - /* handle RTL8139A and RTL8139 cases */ - /* XXX from becker driver. is this right?? */ - RTL_W8 (Config1, 0); } /* make sure chip thinks PIO and MMIO are enabled */ tmp8 = RTL_R8 (Config1); if ((tmp8 & Cfg1_PIO) == 0) { - printk (KERN_ERR PFX "PIO not enabled, Cfg1=%02X, aborting\n", tmp8); + printk (KERN_ERR PFX "%s: PIO not enabled, Cfg1=%02X, aborting\n", + pdev->slot_name, tmp8); rc = -EIO; - goto err_out_iounmap; + goto err_out; } if ((tmp8 & Cfg1_MMIO) == 0) { - printk (KERN_ERR PFX "MMIO not enabled, Cfg1=%02X, aborting\n", tmp8); + printk (KERN_ERR PFX "%s: MMIO not enabled, Cfg1=%02X, aborting\n", + pdev->slot_name, tmp8); rc = -EIO; - goto err_out_iounmap; + goto err_out; } /* identify chip attached to board */ @@ -772,9 +856,9 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev, } /* if unknown chip, assume array element #0, original RTL-8139 in this case */ - printk (KERN_DEBUG PFX "PCI device %s: unknown chip version, assuming RTL-8139\n", + printk (KERN_DEBUG PFX "%s: unknown chip version, assuming RTL-8139\n", pdev->slot_name); - printk (KERN_DEBUG PFX "PCI device %s: TxConfig = 0x%lx\n", pdev->slot_name, RTL_R32 (TxConfig)); + printk (KERN_DEBUG PFX "%s: TxConfig = 0x%lx\n", pdev->slot_name, RTL_R32 (TxConfig)); tp->chipset = 0; match: @@ -784,22 +868,11 @@ match: rtl_chip_info[tp->chipset].name); DPRINTK ("EXIT, returning 0\n"); - *ioaddr_out = ioaddr; *dev_out = dev; return 0; -err_out_iounmap: - assert (ioaddr > 0); -#ifndef USE_IO_OPS - iounmap (ioaddr); -#endif /* !USE_IO_OPS */ -err_out_free_mmio: - release_mem_region (mmio_start, mmio_len); -err_out_free_pio: - release_region (pio_start, pio_len); err_out: - unregister_netdev (dev); - kfree (dev); + __rtl8139_cleanup_dev (dev); DPRINTK ("EXIT, returning %d\n", rc); return rc; } @@ -811,10 +884,9 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, struct net_device *dev = NULL; struct rtl8139_private *tp; int i, addr_len, option; - void *ioaddr = NULL; + void *ioaddr; static int board_idx = -1; - static int printed_version = 0; - u8 tmp; + static int printed_version; DPRINTK ("ENTER\n"); @@ -828,13 +900,14 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, printed_version = 1; } - i = rtl8139_init_board (pdev, &dev, &ioaddr); + i = rtl8139_init_board (pdev, &dev); if (i < 0) { DPRINTK ("EXIT, returning %d\n", i); return i; } tp = dev->priv; + ioaddr = tp->mmio_addr; assert (ioaddr != NULL); assert (dev != NULL); @@ -856,24 +929,23 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, dev->watchdog_timeo = TX_TIMEOUT; dev->irq = pdev->irq; - dev->base_addr = (unsigned long) ioaddr; /* dev->priv/tp zeroed and aligned in init_etherdev */ tp = dev->priv; /* note: tp->chipset set in rtl8139_init_board */ - tp->drv_flags = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | - PCI_COMMAND_MASTER | RTL8139_CAPS; - tp->pci_dev = pdev; - tp->board = ent->driver_data; + tp->drv_flags = board_info[ent->driver_data].hw_flags; tp->mmio_addr = ioaddr; spin_lock_init (&tp->lock); init_waitqueue_head (&tp->thr_wait); init_MUTEX_LOCKED (&tp->thr_exited); - pdev->driver_data = dev; + /* dev is fully set up and ready to use now */ + DPRINTK("about to register device named %s (%p)...\n", dev->name, dev); + i = register_netdev (dev); + if (i) goto err_out; - tp->phys[0] = 32; + pci_set_drvdata (pdev, dev); printk (KERN_INFO "%s: %s at 0x%lx, " "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, " @@ -889,70 +961,89 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, printk (KERN_DEBUG "%s: Identified 8139 chip type '%s'\n", dev->name, rtl_chip_info[tp->chipset].name); - /* Put the chip into low-power mode. */ - RTL_W8_F (Cfg9346, Cfg9346_Unlock); - - tmp = RTL_R8 (Config1) & Config1Clear; - tmp |= (tp->chipset == CH_8139B) ? 3 : 1; /* Enable PM/VPD */ - RTL_W8_F (Config1, tmp); + /* Find the connected MII xcvrs. + Doing this in open() would allow detecting external xcvrs later, but + takes too much time. */ +#ifdef CONFIG_8139TOO_8129 + if (tp->drv_flags & HAS_MII_XCVR) { + int phy, phy_idx = 0; + for (phy = 0; phy < 32 && phy_idx < sizeof(tp->phys); phy++) { + int mii_status = mdio_read(dev, phy, 1); + if (mii_status != 0xffff && mii_status != 0x0000) { + tp->phys[phy_idx++] = phy; + tp->advertising = mdio_read(dev, phy, 4); + printk(KERN_INFO "%s: MII transceiver %d status 0x%4.4x " + "advertising %4.4x.\n", + dev->name, phy, mii_status, tp->advertising); + } + } + if (phy_idx == 0) { + printk(KERN_INFO "%s: No MII transceivers found! Assuming SYM " + "transceiver.\n", + dev->name); + tp->phys[0] = 32; + } + } else +#endif + tp->phys[0] = 32; - RTL_W8_F (HltClk, 'H'); /* 'R' would leave the clock running. */ + /* Put the chip into low-power mode. */ + if (rtl_chip_info[tp->chipset].flags & HasPwrDn) { + RTL_W8_F (Cfg9346, Cfg9346_Unlock); + RTL_W8_F (Config1, RTL_R8 (Config1) | PWRDN); + RTL_W8_F (HltClk, 'H'); /* 'R' would leave the clock running. */ + RTL_W8_F (Cfg9346, Cfg9346_Lock); + } /* The lower four bits are the media type. */ - option = (board_idx >= ARRAY_SIZE(media)) ? 0 : media[board_idx]; + option = (board_idx >= MAX_UNITS) ? 0 : media[board_idx]; if (option > 0) { - tp->full_duplex = (option & 0x200) ? 1 : 0; - tp->default_port = option & 15; + tp->full_duplex = (option & 0x210) ? 1 : 0; + tp->default_port = option & 0xFF; if (tp->default_port) tp->medialock = 1; } - + if (board_idx < MAX_UNITS && full_duplex[board_idx] > 0) + tp->full_duplex = full_duplex[board_idx]; if (tp->full_duplex) { - printk (KERN_INFO - "%s: Media type forced to Full Duplex.\n", - dev->name); - mdio_write (dev, tp->phys[0], 4, 0x141); + printk(KERN_INFO "%s: Media type forced to Full Duplex.\n", dev->name); + /* Changing the MII-advertised media because might prevent + re-connection. */ tp->duplex_lock = 1; } + if (tp->default_port) { + printk(KERN_INFO " Forcing %dMbs %s-duplex operation.\n", + (option & 0x20 ? 100 : 10), + (option & 0x10 ? "full" : "half")); + mdio_write(dev, tp->phys[0], 0, + ((option & 0x20) ? 0x2000 : 0) | /* 100mbps? */ + ((option & 0x10) ? 0x0100 : 0)); /* Full duplex? */ + } DPRINTK ("EXIT - returning 0\n"); return 0; + +err_out: + __rtl8139_cleanup_dev (dev); + DPRINTK ("EXIT - returning %d\n", i); + return i; } static void __devexit rtl8139_remove_one (struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; + struct net_device *dev = pci_get_drvdata (pdev); struct rtl8139_private *np; DPRINTK ("ENTER\n"); assert (dev != NULL); - - np = (struct rtl8139_private *) (dev->priv); + np = dev->priv; assert (np != NULL); unregister_netdev (dev); -#ifndef USE_IO_OPS - iounmap (np->mmio_addr); -#endif /* !USE_IO_OPS */ - - release_region (pci_resource_start (pdev, 0), - pci_resource_len (pdev, 0)); - release_mem_region (pci_resource_start (pdev, 1), - pci_resource_len (pdev, 1)); - -#ifndef RTL8139_NDEBUG - /* poison memory before freeing */ - memset (dev, 0xBC, - sizeof (struct net_device) + - sizeof (struct rtl8139_private)); -#endif /* RTL8139_NDEBUG */ - - kfree (dev); - - pdev->driver_data = NULL; + __rtl8139_cleanup_dev (dev); DPRINTK ("EXIT\n"); } @@ -1035,7 +1126,7 @@ static int __devinit read_eeprom (void *ioaddr, int location, int addr_len) #define MDIO_WRITE0 (MDIO_DIR) #define MDIO_WRITE1 (MDIO_DIR | MDIO_DATA_OUT) -#define mdio_delay() readb(mdio_addr) +#define mdio_delay(mdio_addr) readb(mdio_addr) static char mii_2_8139_map[8] = { @@ -1059,9 +1150,9 @@ static void mdio_sync (void *mdio_addr) for (i = 32; i >= 0; i--) { writeb (MDIO_WRITE1, mdio_addr); - mdio_delay (); + mdio_delay (mdio_addr); writeb (MDIO_WRITE1 | MDIO_CLK, mdio_addr); - mdio_delay (); + mdio_delay (mdio_addr); } DPRINTK ("EXIT\n"); @@ -1083,27 +1174,28 @@ static int mdio_read (struct net_device *dev, int phy_id, int location) return location < 8 && mii_2_8139_map[location] ? readw (tp->mmio_addr + mii_2_8139_map[location]) : 0; } + +#ifdef CONFIG_8139TOO_8129 mdio_sync (mdio_addr); /* Shift the read command bits out. */ for (i = 15; i >= 0; i--) { int dataval = (mii_cmd & (1 << i)) ? MDIO_DATA_OUT : 0; writeb (MDIO_DIR | dataval, mdio_addr); - mdio_delay (); + mdio_delay (mdio_addr); writeb (MDIO_DIR | dataval | MDIO_CLK, mdio_addr); - mdio_delay (); + mdio_delay (mdio_addr); } /* Read the two transition, 16 data, and wire-idle bits. */ for (i = 19; i > 0; i--) { writeb (0, mdio_addr); - mdio_delay (); - retval = - (retval << 1) | ((readb (mdio_addr) & MDIO_DATA_IN) ? 1 - : 0); + mdio_delay (mdio_addr); + retval = (retval << 1) | ((readb (mdio_addr) & MDIO_DATA_IN) ? 1 : 0); writeb (MDIO_CLK, mdio_addr); - mdio_delay (); + mdio_delay (mdio_addr); } +#endif DPRINTK ("EXIT, returning %d\n", (retval >> 1) & 0xffff); return (retval >> 1) & 0xffff; @@ -1115,21 +1207,23 @@ static void mdio_write (struct net_device *dev, int phy_id, int location, { struct rtl8139_private *tp = dev->priv; void *mdio_addr = tp->mmio_addr + Config4; - int mii_cmd = - (0x5002 << 16) | (phy_id << 23) | (location << 18) | value; + int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location << 18) | value; int i; DPRINTK ("ENTER\n"); if (phy_id > 31) { /* Really a 8139. Use internal registers. */ - if (location < 8 && mii_2_8139_map[location]) { - writew (value, - tp->mmio_addr + mii_2_8139_map[location]); - readw (tp->mmio_addr + mii_2_8139_map[location]); - } - DPRINTK ("EXIT after directly using 8139 internal regs\n"); + void *ioaddr = tp->mmio_addr; + if (location == 0) { + RTL_W8_F (Cfg9346, Cfg9346_Unlock); + RTL_W16_F (BasicModeCtrl, value); + RTL_W8_F (Cfg9346, Cfg9346_Lock); + } else if (location < 8 && mii_2_8139_map[location]) + RTL_W16_F (mii_2_8139_map[location], value); return; } + +#ifdef CONFIG_8139TOO_8129 mdio_sync (mdio_addr); /* Shift the command bits out. */ @@ -1137,20 +1231,18 @@ static void mdio_write (struct net_device *dev, int phy_id, int location, int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0; writeb (dataval, mdio_addr); - mdio_delay (); + mdio_delay (mdio_addr); writeb (dataval | MDIO_CLK, mdio_addr); - mdio_delay (); + mdio_delay (mdio_addr); } - /* Clear out extra bits. */ for (i = 2; i > 0; i--) { writeb (0, mdio_addr); - mdio_delay (); + mdio_delay (mdio_addr); writeb (MDIO_CLK, mdio_addr); - mdio_delay (); + mdio_delay (mdio_addr); } - - DPRINTK ("EXIT\n"); +#endif } @@ -1231,6 +1323,8 @@ static void rtl8139_hw_start (struct net_device *dev) if ((RTL_R8 (ChipCmd) & CmdReset) == 0) break; + /* unlock Config[01234] and BMCR register writes */ + RTL_W8_F (Cfg9346, Cfg9346_Unlock); /* Restore our idea of the MAC address. */ RTL_W32_F (MAC0 + 0, cpu_to_le32 (*(u32 *) (dev->dev_addr + 0))); RTL_W32_F (MAC0 + 4, cpu_to_le32 (*(u32 *) (dev->dev_addr + 4))); @@ -1246,22 +1340,25 @@ static void rtl8139_hw_start (struct net_device *dev) /* Check this value: the documentation for IFG contradicts ifself. */ RTL_W32 (TxConfig, (TX_DMA_BURST << TxDMAShift)); - /* unlock Config[01234] and BMCR register writes */ - RTL_W8_F (Cfg9346, Cfg9346_Unlock); - udelay (10); - tp->cur_rx = 0; - if (tp->chipset >= CH_8139A) { - tmp = RTL_R8 (Config1) & Config1Clear; - tmp |= Cfg1_Driver_Load; - tmp |= (tp->chipset == CH_8139B) ? 3 : 1; /* Enable PM/VPD */ - RTL_W8_F (Config1, tmp); - } else { - u8 foo = RTL_R8 (Config1) & Config1Clear; - RTL_W8 (Config1, tp->full_duplex ? (foo|0x60) : (foo|0x20)); + /* This is check_duplex() */ + if (tp->phys[0] >= 0 || (tp->drv_flags & HAS_MII_XCVR)) { + u16 mii_reg5 = mdio_read(dev, tp->phys[0], 5); + if (mii_reg5 == 0xffff) + ; /* Not there */ + else if ((mii_reg5 & 0x0100) == 0x0100 + || (mii_reg5 & 0x00C0) == 0x0040) + tp->full_duplex = 1; + printk(KERN_INFO"%s: Setting %s%s-duplex based on" + " auto-negotiated partner ability %4.4x.\n", dev->name, + mii_reg5 == 0 ? "" : + (mii_reg5 & 0x0180) ? "100mbps " : "10mbps ", + tp->full_duplex ? "full" : "half", mii_reg5); } + RTL_W8 (Config1, RTL_R8 (Config1) | Cfg1_Driver_Load); + if (tp->chipset >= CH_8139B) { tmp = RTL_R8 (Config4) & ~(1<<2); /* chip will clear Rx FIFO overflow automatically */ @@ -1269,7 +1366,7 @@ static void rtl8139_hw_start (struct net_device *dev) RTL_W8 (Config4, tmp); /* disable magic packet scanning, which is enabled - * when PM is enabled above (Config1) */ + * when PM is enabled in Config1 */ RTL_W8 (Config3, RTL_R8 (Config3) & ~(1<<5)); } @@ -1442,9 +1539,11 @@ static inline void rtl8139_thread_iter (struct net_device *dev, " partner ability of %4.4x.\n", dev->name, tp->full_duplex ? "full" : "half", tp->phys[0], mii_reg5); +#if 0 RTL_W8 (Cfg9346, Cfg9346_Unlock); RTL_W8 (Config1, tp->full_duplex ? 0x60 : 0x20); RTL_W8 (Cfg9346, Cfg9346_Lock); +#endif } } @@ -1544,7 +1643,7 @@ static void rtl8139_tx_timeout (struct net_device *dev) RTL_W16 (IntrMask, 0x0000); /* Emit info to figure out what went wrong. */ - printk (KERN_DEBUG "%s: Tx queue start entry %d dirty entry %d.\n", + printk (KERN_DEBUG "%s: Tx queue start entry %ld dirty entry %ld.\n", dev->name, tp->cur_tx, tp->dirty_tx); for (i = 0; i < NUM_TX_DESC; i++) printk (KERN_DEBUG "%s: Tx descriptor %d is %8.8lx.%s\n", @@ -1559,6 +1658,8 @@ static void rtl8139_tx_timeout (struct net_device *dev) /* ...and finally, reset everything */ rtl8139_hw_start (dev); + + netif_wake_queue (dev); } @@ -1593,11 +1694,15 @@ static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev) tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN)); dev->trans_start = jiffies; + + spin_lock_irq (&tp->lock); + tp->cur_tx++; - mb(); if ((tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx) netif_stop_queue (dev); + spin_unlock_irq (&tp->lock); + DPRINTK ("%s: Queued Tx packet at %p size %u to slot %d.\n", dev->name, skb->data, skb->len, entry); @@ -1609,7 +1714,7 @@ static void rtl8139_tx_interrupt (struct net_device *dev, struct rtl8139_private *tp, void *ioaddr) { - unsigned int dirty_tx, tx_left; + unsigned long dirty_tx, tx_left; assert (dev != NULL); assert (tp != NULL); @@ -1673,9 +1778,8 @@ static void rtl8139_tx_interrupt (struct net_device *dev, #ifndef RTL8139_NDEBUG if (tp->cur_tx - dirty_tx > NUM_TX_DESC) { - printk (KERN_ERR - "%s: Out-of-sync dirty pointer, %d vs. %d.\n", - dev->name, dirty_tx, tp->cur_tx); + printk (KERN_ERR "%s: Out-of-sync dirty pointer, %ld vs. %ld.\n", + dev->name, dirty_tx, tp->cur_tx); dirty_tx += NUM_TX_DESC; } #endif /* RTL8139_NDEBUG */ @@ -1683,7 +1787,6 @@ static void rtl8139_tx_interrupt (struct net_device *dev, /* only wake the queue if we did work, and the queue is stopped */ if (tp->dirty_tx != dirty_tx) { tp->dirty_tx = dirty_tx; - mb(); if (netif_queue_stopped (dev)) netif_wake_queue (dev); } @@ -1856,8 +1959,8 @@ static void rtl8139_weird_interrupt (struct net_device *dev, void *ioaddr, int status, int link_changed) { - printk (KERN_DEBUG "%s: Abnormal interrupt, status %8.8x.\n", - dev->name, status); + DPRINTK ("%s: Abnormal interrupt, status %8.8x.\n", + dev->name, status); assert (dev != NULL); assert (tp != NULL); @@ -1875,9 +1978,11 @@ static void rtl8139_weird_interrupt (struct net_device *dev, || tp->duplex_lock; if (tp->full_duplex != duplex) { tp->full_duplex = duplex; +#if 0 RTL_W8 (Cfg9346, Cfg9346_Unlock); RTL_W8 (Config1, tp->full_duplex ? 0x60 : 0x20); RTL_W8 (Cfg9346, Cfg9346_Lock); +#endif } status &= ~RxUnderrun; } @@ -1917,8 +2022,6 @@ static void rtl8139_interrupt (int irq, void *dev_instance, void *ioaddr = tp->mmio_addr; int status = 0, link_changed = 0; /* avoid bogus "uninit" warning */ - spin_lock (&tp->lock); - do { status = RTL_R16 (IntrStatus); @@ -1949,7 +2052,7 @@ static void rtl8139_interrupt (int irq, void *dev_instance, RxFIFOOver error (I got the feeling this depends on the CPU speed, lower CPU speed --> more errors). After clearing the RxOverflow bit the transfer of the - packet was repeated and all data are error free transfered */ + packet was repeated and all data are error free transferred */ RTL_W16_F (IntrStatus, (status & RxFIFOOver) ? (status | RxOverflow) : status); DPRINTK ("%s: interrupt status=%#4.4x new intstat=%#4.4x.\n", @@ -1967,11 +2070,16 @@ static void rtl8139_interrupt (int irq, void *dev_instance, rtl8139_weird_interrupt (dev, tp, ioaddr, status, link_changed); - if (status & (RxOK | RxUnderrun | RxOverflow | RxFIFOOver)) /* Rx interrupt */ + if (netif_running (dev) && + status & (RxOK | RxUnderrun | RxOverflow | RxFIFOOver)) /* Rx interrupt */ rtl8139_rx_interrupt (dev, tp, ioaddr); - if (status & (TxOK | TxErr)) + if (netif_running (dev) && + status & (TxOK | TxErr)) { + spin_lock (&tp->lock); rtl8139_tx_interrupt (dev, tp, ioaddr); + spin_unlock (&tp->lock); + } boguscnt--; } while (boguscnt > 0); @@ -1986,8 +2094,6 @@ static void rtl8139_interrupt (int irq, void *dev_instance, RTL_W16 (IntrStatus, 0xffff); } - spin_unlock (&tp->lock); - DPRINTK ("%s: exiting interrupt, intr_status=%#4.4x.\n", dev->name, RTL_R16 (IntrStatus)); } @@ -2043,8 +2149,11 @@ static int rtl8139_close (struct net_device *dev) /* Green! Put the chip in low-power mode. */ RTL_W8 (Cfg9346, Cfg9346_Unlock); - RTL_W8 (Config1, 0x03); - RTL_W8 (HltClk, 'H'); /* 'R' would leave the clock running. */ + + if (rtl_chip_info[tp->chipset].flags & HasPwrDn) { + RTL_W8 (Config1, 0x03); + RTL_W8 (HltClk, 'H'); /* 'R' would leave the clock running. */ + } DPRINTK ("EXIT\n"); return 0; @@ -2074,7 +2183,19 @@ static int mii_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) break; } - mdio_write (dev, data[0], data[1] & 0x1f, data[2]); + if (data[0] == tp->phys[0]) { + u16 value = data[2]; + switch (data[1]) { + case 0: + /* Check for autonegotiation on or reset. */ + tp->medialock = (value & 0x9000) ? 0 : 1; + if (tp->medialock) + tp->full_duplex = (value & 0x0100) ? 1 : 0; + break; + case 4: tp->advertising = value; break; + } + } + mdio_write(dev, data[0], data[1] & 0x1f, data[2]); break; default: @@ -2095,8 +2216,10 @@ static struct net_device_stats *rtl8139_get_stats (struct net_device *dev) DPRINTK ("ENTER\n"); if (netif_running(dev)) { + spin_lock_irq (&tp->lock); tp->stats.rx_missed_errors += RTL_R32 (RxMissed); RTL_W32 (RxMissed, 0); + spin_unlock_irq (&tp->lock); } DPRINTK ("EXIT\n"); @@ -2117,12 +2240,11 @@ static inline u32 ether_crc (int length, unsigned char *data) unsigned char current_octet = *data++; int bit; for (bit = 0; bit < 8; bit++, current_octet >>= 1) - crc = (crc << 1) ^ - ((crc < 0) ^ (current_octet & 1) ? + crc = (crc << 1) ^ ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0); } - DPRINTK ("EXIT\n"); + DPRINTK ("EXIT, returning %u\n", crc); return crc; } @@ -2131,6 +2253,7 @@ static void rtl8139_set_rx_mode (struct net_device *dev) { struct rtl8139_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; + unsigned long flags; u32 mc_filter[2]; /* Multicast hash filter */ int i, rx_mode; u32 tmp; @@ -2164,9 +2287,7 @@ static void rtl8139_set_rx_mode (struct net_device *dev) mc_filter); } - /* if called from irq handler, lock already acquired */ - if (!in_irq ()) - spin_lock_irq (&tp->lock); + spin_lock_irqsave (&tp->lock, flags); /* We can safely update without stopping the chip. */ tmp = rtl8139_rx_config | rx_mode | @@ -2175,8 +2296,7 @@ static void rtl8139_set_rx_mode (struct net_device *dev) RTL_W32_F (MAR0 + 0, mc_filter[0]); RTL_W32_F (MAR0 + 4, mc_filter[1]); - if (!in_irq ()) - spin_unlock_irq (&tp->lock); + spin_unlock_irqrestore (&tp->lock, flags); DPRINTK ("EXIT\n"); } @@ -2184,11 +2304,14 @@ static void rtl8139_set_rx_mode (struct net_device *dev) static void rtl8139_suspend (struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; + struct net_device *dev = pci_get_drvdata (pdev); struct rtl8139_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; unsigned long flags; + if (!netif_running (dev)) + return; + netif_device_detach (dev); spin_lock_irqsave (&tp->lock, flags); @@ -2207,8 +2330,10 @@ static void rtl8139_suspend (struct pci_dev *pdev) static void rtl8139_resume (struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; + struct net_device *dev = pci_get_drvdata (pdev); + if (!netif_running (dev)) + return; netif_device_attach (dev); rtl8139_hw_start (dev); } diff --git a/drivers/net/82596.c b/drivers/net/82596.c index bb0e79f5a..ea276688b 100644 --- a/drivers/net/82596.c +++ b/drivers/net/82596.c @@ -40,8 +40,6 @@ */ -static const char *version = "82596.c $Revision: 1.4 $\n"; - #include <linux/config.h> #include <linux/module.h> @@ -65,6 +63,9 @@ static const char *version = "82596.c $Revision: 1.4 $\n"; #include <asm/pgtable.h> #include <asm/pgalloc.h> +static char version[] __initdata = + "82596.c $Revision: 1.4 $\n"; + /* DEBUG flags */ @@ -333,7 +334,7 @@ struct i596_private { spinlock_t lock; }; -char init_setup[] = +static char init_setup[] = { 0x8E, /* length, prefetch on */ 0xC8, /* fifo to 8, monitor off */ @@ -1132,9 +1133,9 @@ int __init i82596_probe(struct net_device *dev) /* this is easy the ethernet interface can only be at 0x300 */ /* first check nothing is already registered here */ - if (check_region(ioaddr, I596_TOTAL_SIZE)) { + if (!request_region(ioaddr, I596_TOTAL_SIZE, dev->name)) { printk("82596: IO address 0x%04x in use\n", ioaddr); - return -ENODEV; + return -EBUSY; } for (i = 0; i < 8; i++) { @@ -1144,19 +1145,15 @@ int __init i82596_probe(struct net_device *dev) /* checksum is a multiple of 0x100, got this wrong first time some machines have 0x100, some 0x200. The DOS driver doesn't - even bother with the checksum */ + even bother with the checksum. + Some other boards trip the checksum.. but then appear as + ether address 0. Trap these - AC */ - if (checksum % 0x100) - return -ENODEV; - - /* Some other boards trip the checksum.. but then appear as - * ether address 0. Trap these - AC */ - - if (memcmp(eth_addr, "\x00\x00\x49", 3) != 0) - return -ENODEV; - - if (!request_region(ioaddr, I596_TOTAL_SIZE, "i596")) + if ((checksum % 0x100) || + (memcmp(eth_addr, "\x00\x00\x49", 3) != 0)) { + release_region(ioaddr, I596_TOTAL_SIZE); return -ENODEV; + } dev->base_addr = ioaddr; dev->irq = 10; diff --git a/drivers/net/Config.in b/drivers/net/Config.in index d9b736858..c0e9bae05 100644 --- a/drivers/net/Config.in +++ b/drivers/net/Config.in @@ -117,9 +117,11 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then tristate ' ICL EtherTeam 16i/32 support' CONFIG_ETH16I tristate ' NE2000/NE1000 support' CONFIG_NE2000 if [ "$CONFIG_OBSOLETE" = "y" ]; then - tristate ' SEEQ8005 support (EXPERIMENTAL)' CONFIG_SEEQ8005 + dep_tristate ' SEEQ8005 support (EXPERIMENTAL)' CONFIG_SEEQ8005 $CONFIG_EXPERIMENTAL + fi + if [ "$CONFIG_OBSOLETE" = "y" ]; then + tristate ' SK_G16 support' CONFIG_SK_G16 fi - tristate ' SK_G16 support' CONFIG_SK_G16 fi if [ "$CONFIG_MCA" = "y" ]; then tristate ' SKnet MCA support' CONFIG_SKMC @@ -145,12 +147,14 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then dep_tristate ' EtherExpressPro/100 support' CONFIG_EEPRO100 $CONFIG_PCI dep_mbool ' Enable Power Management (EXPERIMENTAL)' CONFIG_EEPRO100_PM $CONFIG_EEPRO100 $CONFIG_EXPERIMENTAL dep_tristate ' Mylex EISA LNE390A/B support (EXPERIMENTAL)' CONFIG_LNE390 $CONFIG_EISA $CONFIG_EXPERIMENTAL - dep_tristate ' National Semiconductor DP83810 series PCI Ethernet support' CONFIG_NATSEMI $CONFIG_PCI + dep_tristate ' National Semiconductor DP8381x series PCI Ethernet support' CONFIG_NATSEMI $CONFIG_PCI dep_tristate ' PCI NE2000 and clones support (see help)' CONFIG_NE2K_PCI $CONFIG_PCI dep_tristate ' Novell/Eagle/Microdyne NE3210 EISA support (EXPERIMENTAL)' CONFIG_NE3210 $CONFIG_EISA $CONFIG_EXPERIMENTAL dep_tristate ' Racal-Interlan EISA ES3210 support (EXPERIMENTAL)' CONFIG_ES3210 $CONFIG_EISA $CONFIG_EXPERIMENTAL dep_tristate ' RealTek RTL-8139 PCI Fast Ethernet Adapter support' CONFIG_8139TOO $CONFIG_PCI - dep_tristate ' RealTek 8129 (not 8019/8029/8139!) support (EXPERIMENTAL)' CONFIG_RTL8129 $CONFIG_PCI $CONFIG_EXPERIMENTAL + dep_mbool ' Use PIO instead of MMIO' CONFIG_8139TOO_PIO $CONFIG_8139TOO + dep_mbool ' Support for automatic channel equalization (EXPERIMENTAL)' CONFIG_8139TOO_TUNE_TWISTER $CONFIG_8139TOO $CONFIG_EXPERIMENTAL + dep_mbool ' Support for older RTL-8129/8130 boards' CONFIG_8139TOO_8129 $CONFIG_8139TOO dep_tristate ' SiS 900/7016 PCI Fast Ethernet Adapter support' CONFIG_SIS900 $CONFIG_PCI dep_tristate ' SMC EtherPower II' CONFIG_EPIC100 $CONFIG_PCI dep_tristate ' Sundance Alta support' CONFIG_SUNDANCE $CONFIG_PCI @@ -208,14 +212,16 @@ endmenu bool 'FDDI driver support' CONFIG_FDDI if [ "$CONFIG_FDDI" = "y" ]; then - dep_tristate ' Digital DEFEA and DEFPA adapter support' CONFIG_DEFXX $CONFIG_PCI + if [ "$CONFIG_PCI" = "y" -o "$CONFIG_EISA" = "y" ]; then + tristate ' Digital DEFEA and DEFPA adapter support' CONFIG_DEFXX + fi tristate ' SysKonnect FDDI PCI support' CONFIG_SKFP fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then if [ "$CONFIG_INET" = "y" ]; then bool 'HIPPI driver support (EXPERIMENTAL)' CONFIG_HIPPI - if [ "$CONFIG_HIPPI" = "y" ]; then + if [ "$CONFIG_HIPPI" = "y" -a "$CONFIG_PCI" = "y" ]; then tristate ' Essential RoadRunner HIPPI PCI adapter support' CONFIG_ROADRUNNER if [ "$CONFIG_ROADRUNNER" != "n" ]; then bool ' Use large TX/RX rings' CONFIG_ROADRUNNER_LARGE_RINGS @@ -276,7 +282,7 @@ if [ "$CONFIG_NET_FC" = "y" ]; then fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate 'Red Creek Hardware VPN (EXPERIMENTAL)' CONFIG_RCPCI + dep_tristate 'Red Creek Hardware VPN (EXPERIMENTAL)' CONFIG_RCPCI $CONFIG_PCI tristate 'Traffic Shaper (EXPERIMENTAL)' CONFIG_SHAPER fi diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 5f9658fa5..d81d8c51b 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -15,8 +15,9 @@ O_TARGET := net.o # All of the (potential) objects that export symbols. # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'. -export-objs := 8390.o arlan.o aironet4500_core.o aironet4500_card.o ppp_async.o \ - ppp_generic.o slhc.o pppox.o auto_irq.o +export-objs := 8390.o arlan.o aironet4500_core.o aironet4500_card.o \ + ppp_async.o ppp_generic.o slhc.o pppox.o auto_irq.o \ + net_init.o ifeq ($(CONFIG_TULIP),y) obj-y += tulip/tulip.o @@ -49,6 +50,7 @@ obj-$(CONFIG_SUNLANCE) += sunlance.o obj-$(CONFIG_SUNQE) += sunqe.o obj-$(CONFIG_SUNBMAC) += sunbmac.o obj-$(CONFIG_MYRI_SBUS) += myri_sbus.o +obj-$(CONFIG_SUNGEM) += sungem.o obj-$(CONFIG_MACE) += mace.o obj-$(CONFIG_BMAC) += bmac.o @@ -163,7 +165,6 @@ obj-$(CONFIG_EL3) += 3c509.o obj-$(CONFIG_3C515) += 3c515.o obj-$(CONFIG_EEXPRESS) += eexpress.o obj-$(CONFIG_EEXPRESS_PRO) += eepro.o -obj-$(CONFIG_RTL8129) += rtl8129.o obj-$(CONFIG_8139TOO) += 8139too.o obj-$(CONFIG_WAVELAN) += wavelan.o obj-$(CONFIG_ARLAN) += arlan.o arlan-proc.o diff --git a/drivers/net/acenic_firmware.h b/drivers/net/acenic_firmware.h index 2a906a7bb..72229ff43 100644 --- a/drivers/net/acenic_firmware.h +++ b/drivers/net/acenic_firmware.h @@ -23,7 +23,7 @@ #define tigonFwRodata 0 #else /* Generated by genfw.c */ -u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = { +static u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = { 0x10000003, 0x0, 0xd, 0xd, 0x3c1d0001, 0x8fbd5c54, 0x3a0f021, 0x3c100000, 0x26104000, @@ -4397,7 +4397,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = { 0x3c010001, 0x220821, 0xac317e30, 0x8fbf0024, 0x8fb40020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, 0x3e00008, 0x27bd0028, 0x0 }; -u32 tigonFwRodata[(MAX_RODATA_LEN/4) + 1] __initdata = { +static u32 tigonFwRodata[(MAX_RODATA_LEN/4) + 1] __initdata = { 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, 0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e, @@ -4571,7 +4571,7 @@ u32 tigonFwRodata[(MAX_RODATA_LEN/4) + 1] __initdata = { 0x0, 0x14c38, 0x14c38, 0x14b80, 0x14bc4, 0x14c38, 0x14c38, 0x0, 0x0, 0x0 }; -u32 tigonFwData[(MAX_DATA_LEN/4) + 1] __initdata = { +static u32 tigonFwData[(MAX_DATA_LEN/4) + 1] __initdata = { 0x416c7465, 0x6f6e2041, 0x63654e49, 0x43205600, 0x416c7465, 0x6f6e2041, 0x63654e49, 0x43205600, 0x42424242, @@ -4612,7 +4612,7 @@ u32 tigonFwData[(MAX_DATA_LEN/4) + 1] __initdata = { #define tigon2FwSbssLen 0xcc #define tigon2FwBssAddr 0x00016f50 #define tigon2FwBssLen 0x20c0 -u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __initdata = { +static u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __initdata = { 0x0, 0x10000003, 0x0, 0xd, 0xd, 0x3c1d0001, 0x8fbd6d20, 0x3a0f021, 0x3c100000, @@ -9154,7 +9154,7 @@ u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __initdata = { 0x24020001, 0x8f430328, 0x1021, 0x24630001, 0x3e00008, 0xaf430328, 0x3e00008, 0x0, 0x0, 0x0, 0x0, 0x0 }; -u32 tigon2FwRodata[(MAX_RODATA_LEN/4) + 1] __initdata = { +static u32 tigon2FwRodata[(MAX_RODATA_LEN/4) + 1] __initdata = { 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, 0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f, @@ -9425,7 +9425,7 @@ u32 tigon2FwRodata[(MAX_RODATA_LEN/4) + 1] __initdata = { 0x14ed8, 0x14b8c, 0x14bd8, 0x14c24, 0x14ed8, 0x7365746d, 0x61636163, 0x74000000, 0x0, 0x0 }; -u32 tigon2FwData[(MAX_DATA_LEN/4) + 1] __initdata = { +static u32 tigon2FwData[(MAX_DATA_LEN/4) + 1] __initdata = { 0x1, 0x1, 0x1, 0xc001fc, 0x3ffc, 0xc00000, 0x416c7465, 0x6f6e2041, 0x63654e49, diff --git a/drivers/net/aironet4500_card.c b/drivers/net/aironet4500_card.c index 18a9d3832..259d506a1 100644 --- a/drivers/net/aironet4500_card.c +++ b/drivers/net/aironet4500_card.c @@ -370,7 +370,15 @@ int awc4500_pnp_probe(struct net_device *dev) request_region(isa_ioaddr, AIRONET4X00_IO_SIZE, "aironet4x00 ioaddr"); if (!dev) { - dev = init_etherdev(dev, 0 ); + dev = init_etherdev(NULL, 0); + if (!dev) { + release_region(isa_ioaddr, AIRONET4X00_IO_SIZE); + isapnp_cfg_begin(logdev->PNP_BUS->PNP_BUS_NUMBER, + logdev->PNP_DEV_NUMBER); + isapnp_deactivate(logdev->PNP_DEV_NUMBER); + isapnp_cfg_end(); + return -ENOMEM; + } } dev->priv = kmalloc(sizeof(struct awc_private),GFP_KERNEL ); memset(dev->priv,0,sizeof(struct awc_private)); @@ -524,7 +532,7 @@ int awc4500_isa_probe(struct net_device *dev) printk(KERN_WARNING " Use aironet4500_pnp if any problems(i.e. card malfunctioning). \n"); printk(KERN_WARNING " Note that this isa probe is not friendly... must give exact parameters \n"); - while (irq[card] !=0){ + while (irq[card] != 0){ isa_ioaddr = io[card]; isa_irq_line = irq[card]; @@ -532,7 +540,11 @@ int awc4500_isa_probe(struct net_device *dev) request_region(isa_ioaddr, AIRONET4X00_IO_SIZE, "aironet4x00 ioaddr"); if (!dev) { - dev = init_etherdev(dev, 0 ); + dev = init_etherdev(NULL, 0); + if (!dev) { + release_region(isa_ioaddr, AIRONET4X00_IO_SIZE); + return (card == 0) ? -ENOMEM : 0; + } } dev->priv = kmalloc(sizeof(struct awc_private),GFP_KERNEL ); memset(dev->priv,0,sizeof(struct awc_private)); diff --git a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c index 33e18b3a3..daf6dbf47 100644 --- a/drivers/net/appletalk/cops.c +++ b/drivers/net/appletalk/cops.c @@ -181,7 +181,7 @@ struct cops_local int board; /* Holds what board type is. */ int nodeid; /* Set to 1 once have nodeid. */ unsigned char node_acquire; /* Node ID when acquired. */ - struct at_addr node_addr; /* Full node addres */ + struct at_addr node_addr; /* Full node address */ }; /* Index to functions, as function prototypes. */ @@ -752,8 +752,8 @@ static void cops_rx(struct net_device *dev) { int pkt_len = 0; int rsp_type = 0; - struct sk_buff *skb; - struct cops_local *lp = (struct cops_local *)dev->priv; + struct sk_buff *skb = NULL; + struct cops_local *lp = dev->priv; int ioaddr = dev->base_addr; int boguscount = 0; unsigned long flags; @@ -771,6 +771,7 @@ static void cops_rx(struct net_device *dev) /* Wait for DMA to turn around. */ while(++boguscount<1000000) { + barrier(); if((inb(ioaddr+DAYNA_CARD_STATUS)&0x03)==DAYNA_RX_READY) break; } @@ -801,6 +802,7 @@ static void cops_rx(struct net_device *dev) lp->stats.rx_dropped++; while(pkt_len--) /* Discard packet */ inb(ioaddr); + restore_flags(flags); return; } skb->dev = dev; @@ -820,7 +822,7 @@ static void cops_rx(struct net_device *dev) printk(KERN_WARNING "%s: Bad packet length of %d bytes.\n", dev->name, pkt_len); lp->stats.tx_errors++; - kfree_skb(skb); + dev_kfree_skb_any(skb); return; } @@ -828,7 +830,7 @@ static void cops_rx(struct net_device *dev) if(rsp_type == LAP_INIT_RSP) { /* Nodeid taken from received packet. */ lp->node_acquire = skb->data[0]; - kfree_skb(skb); + dev_kfree_skb_any(skb); return; } @@ -837,7 +839,7 @@ static void cops_rx(struct net_device *dev) { printk(KERN_WARNING "%s: Bad packet type %d.\n", dev->name, rsp_type); lp->stats.tx_errors++; - kfree_skb(skb); + dev_kfree_skb_any(skb); return; } diff --git a/drivers/net/arcnet/Config.in b/drivers/net/arcnet/Config.in index 7c38a7422..3a4e7ff9d 100644 --- a/drivers/net/arcnet/Config.in +++ b/drivers/net/arcnet/Config.in @@ -14,10 +14,8 @@ if [ "$CONFIG_ARCNET" != "n" ]; then dep_tristate 'ARCnet COM90xx (IO mapped) chipset driver' CONFIG_ARCNET_COM90xxIO $CONFIG_ARCNET dep_tristate 'ARCnet COM90xx (RIM I) chipset driver' CONFIG_ARCNET_RIM_I $CONFIG_ARCNET dep_tristate 'ARCnet COM20020 chipset driver' CONFIG_ARCNET_COM20020 $CONFIG_ARCNET - if [ "$CONFIG_ARCNET_COM20020" != "n" ]; then - dep_tristate ' Support for COM20020 on ISA' CONFIG_ARCNET_COM20020_ISA $CONFIG_ARCNET_COM20020 $CONFIG_ARCNET - dep_tristate ' Support for COM20020 on PCI' CONFIG_ARCNET_COM20020_PCI $CONFIG_ARCNET_COM20020 $CONFIG_ARCNET - fi + dep_tristate ' Support for COM20020 on ISA' CONFIG_ARCNET_COM20020_ISA $CONFIG_ARCNET_COM20020 $CONFIG_ISA + dep_tristate ' Support for COM20020 on PCI' CONFIG_ARCNET_COM20020_PCI $CONFIG_ARCNET_COM20020 $CONFIG_PCI fi endmenu diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c index 64d3ae88f..3b64639b6 100644 --- a/drivers/net/arcnet/arcnet.c +++ b/drivers/net/arcnet/arcnet.c @@ -696,6 +696,9 @@ static void arcnet_timeout(struct net_device *dev) msg, status, lp->intmask, lp->lasttrans_dest); lp->last_timeout = jiffies; } + + if (lp->cur_tx == -1) + netif_wake_queue(dev); } diff --git a/drivers/net/arcnet/com20020-pci.c b/drivers/net/arcnet/com20020-pci.c index b341e09c5..9b0177843 100644 --- a/drivers/net/arcnet/com20020-pci.c +++ b/drivers/net/arcnet/com20020-pci.c @@ -78,8 +78,10 @@ static int __devinit com20020pci_probe(struct pci_dev *pdev, const struct pci_de if (!dev) return err; lp = dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL); - if (!lp) - return -ENOMEM; + if (!lp) { + err = -ENOMEM; + goto out_dev; + } memset(lp, 0, sizeof(struct arcnet_local)); pdev->driver_data = dev; @@ -98,17 +100,30 @@ static int __devinit com20020pci_probe(struct pci_dev *pdev, const struct pci_de if (check_region(ioaddr, ARCNET_TOTAL_SIZE)) { BUGMSG(D_INIT, "IO region %xh-%xh already allocated.\n", ioaddr, ioaddr + ARCNET_TOTAL_SIZE - 1); - return -EBUSY; + err = -EBUSY; + goto out_priv; } if (ASTATUS() == 0xFF) { BUGMSG(D_NORMAL, "IO address %Xh was reported by PCI BIOS, " "but seems empty!\n", ioaddr); - return -EIO; + err = -EIO; + goto out_priv; } - if (com20020_check(dev)) - return -EIO; + if (com20020_check(dev)) { + err = -EIO; + goto out_priv; + } + + if ((err = com20020_found(dev, SA_SHIRQ)) != 0) + goto out_priv; + + return 0; - return com20020_found(dev, SA_SHIRQ); +out_priv: + kfree(dev->priv); +out_dev: + kfree(dev); + return err; } static void __devexit com20020pci_remove(struct pci_dev *pdev) diff --git a/drivers/net/arlan-proc.c b/drivers/net/arlan-proc.c index e7d6adcd7..22b0411f1 100644 --- a/drivers/net/arlan-proc.c +++ b/drivers/net/arlan-proc.c @@ -185,7 +185,7 @@ static const char *arlan_hardware_type_string(struct net_device *dev) return "type A672T"; } } -#ifdef ARLAN_DEBUGING +#ifdef ARLAN_DEBUGGING static void arlan_print_diagnostic_info(struct net_device *dev) { int i; @@ -341,7 +341,7 @@ static int arlan_setup_card_by_book(struct net_device *dev) DEBUGSHM(4, "arlan configuredStatus = %d \n", arlan->configuredStatusFlag, u_char); DEBUGSHM(4, "arlan driver diagnostic: 0x%2x\n", arlan->diagnosticInfo, u_char); - /* issue nop command - no interupt */ + /* issue nop command - no interrupt */ arlan_command(dev, ARLAN_COMMAND_NOOP); if (arlan_command(dev, ARLAN_COMMAND_WAIT_NOW) != 0) return -1; @@ -818,7 +818,7 @@ static int arlan_sysctl_reset(ctl_table * ctl, int write, struct file *filp, #define CTBLN(num,card,nam) \ {num , #nam, &(arlan_conf[card].nam), \ sizeof(int), 0600, NULL, &proc_dointvec} -#ifdef ARLAN_DEBUGING +#ifdef ARLAN_DEBUGGING #define ARLAN_PROC_DEBUG_ENTRIES {48, "entry_exit_debug", &arlan_entry_and_exit_debug, \ sizeof(int), 0600, NULL, &proc_dointvec},\ diff --git a/drivers/net/arlan.c b/drivers/net/arlan.c index a329f863e..d64c7263c 100644 --- a/drivers/net/arlan.c +++ b/drivers/net/arlan.c @@ -32,9 +32,8 @@ static int retries = 5; static int async = 1; static int tx_queue_len = 1; static int arlan_EEPROM_bad; -static int arlan_entry_and_exit_debug; -#ifdef ARLAN_DEBUGING +#ifdef ARLAN_DEBUGGING static int arlan_entry_debug; static int arlan_exit_debug; @@ -71,6 +70,7 @@ MODULE_PARM(arlan_entry_and_exit_debug, "i"); MODULE_PARM(arlan_EEPROM_bad, "i"); EXPORT_SYMBOL(arlan_device); +EXPORT_SYMBOL(arlan_conf); EXPORT_SYMBOL(last_arlan); @@ -114,7 +114,7 @@ extern inline long long arlan_time(void) return ((long long) timev.tv_sec * 1000000 + timev.tv_usec); }; -#ifdef ARLAN_ENTRY_EXIT_DEBUGING +#ifdef ARLAN_ENTRY_EXIT_DEBUGGING #define ARLAN_DEBUG_ENTRY(name) \ {\ struct timeval timev;\ @@ -694,7 +694,7 @@ static void arlan_registration_timer(unsigned long data) } -#ifdef ARLAN_DEBUGING +#ifdef ARLAN_DEBUGGING static void arlan_print_registers(struct net_device *dev, int line) { @@ -1671,7 +1671,7 @@ static void arlan_rx_interrupt(struct net_device *dev, u_char rxStatus, u_short } /* we reach here if multicast filtering is on and packet * is multicast and not for receive */ - goto end_of_interupt; + goto end_of_interrupt; } } #endif // ARLAN_MULTICAST @@ -1728,7 +1728,7 @@ static void arlan_rx_interrupt(struct net_device *dev, u_char rxStatus, u_short break; default: - printk(KERN_ERR "arlan intr: recieved unknown status\n"); + printk(KERN_ERR "arlan intr: received unknown status\n"); priv->stats.rx_crc_errors++; break; } @@ -1896,7 +1896,7 @@ static int arlan_close(struct net_device *dev) return 0; } -#ifdef ARLAN_DEBUGING +#ifdef ARLAN_DEBUGGING static long alignLong(volatile u_char * ptr) { long ret; diff --git a/drivers/net/arlan.h b/drivers/net/arlan.h index 4b52ee59b..f0c19eacc 100644 --- a/drivers/net/arlan.h +++ b/drivers/net/arlan.h @@ -29,7 +29,7 @@ #include <linux/etherdevice.h> -//#define ARLAN_DEBUGING 1 +//#define ARLAN_DEBUGGING 1 #define ARLAN_PROC_INTERFACE #define MAX_ARLANS 4 /* not more than 4 ! */ @@ -50,7 +50,6 @@ extern int arlan_debug; extern char * siteName; extern int arlan_entry_debug; extern int arlan_exit_debug; -extern int arlan_entry_and_exit_debug; extern int testMemory; extern const char* arlan_version; extern int arlan_command(struct net_device * dev, int command); @@ -76,9 +75,9 @@ extern int arlan_command(struct net_device * dev, int command); #define IFDEBUG( L ) if ( (L) & arlan_debug ) #define ARLAN_FAKE_HDR_LEN 12 -#ifdef ARLAN_DEBUGING +#ifdef ARLAN_DEBUGGING #define DEBUG 1 - #define ARLAN_ENTRY_EXIT_DEBUGING 1 + #define ARLAN_ENTRY_EXIT_DEBUGGING 1 #define ARLAN_DEBUG(a,b) printk(KERN_DEBUG a, b) #else #define ARLAN_DEBUG(a,b) @@ -321,7 +320,7 @@ struct arlan_conf_stru { int tx_queue_len; }; -struct arlan_conf_stru arlan_conf[MAX_ARLANS]; +extern struct arlan_conf_stru arlan_conf[MAX_ARLANS]; struct TxParam { diff --git a/drivers/net/atp.c b/drivers/net/atp.c index 94a6cdb43..518431f8f 100644 --- a/drivers/net/atp.c +++ b/drivers/net/atp.c @@ -536,7 +536,6 @@ static void tx_timeout(struct net_device *dev) dev->trans_start = jiffies; netif_wake_queue(dev); np->stats.tx_errors++; - return; } static int atp_send_packet(struct sk_buff *skb, struct net_device *dev) diff --git a/drivers/net/bonding.c b/drivers/net/bonding.c index 5bc9797a1..2442de9dc 100644 --- a/drivers/net/bonding.c +++ b/drivers/net/bonding.c @@ -60,12 +60,6 @@ static struct net_device_stats *bond_get_stats(struct net_device *dev); static struct net_device *this_bond; -static int bond_open(struct net_device *dev) -{ - MOD_INC_USE_COUNT; - return 0; -} - static void release_one_slave(struct net_device *master, slave_t *slave) { bonding_t *bond = master->priv; @@ -81,7 +75,6 @@ static void release_one_slave(struct net_device *master, slave_t *slave) dev_put(slave->dev); kfree(slave); - MOD_DEC_USE_COUNT; } static int bond_close(struct net_device *master) @@ -92,21 +85,11 @@ static int bond_close(struct net_device *master) while ((slave = bond->next) != (slave_t*)bond) release_one_slave(master, slave); - MOD_DEC_USE_COUNT; return 0; } static void bond_set_multicast_list(struct net_device *master) { - bonding_t *bond = master->priv; - slave_t *slave; - - for (slave = bond->next; slave != (slave_t*)bond; slave = slave->next) { - slave->dev->mc_list = master->mc_list; - slave->dev->mc_count = master->mc_count; - slave->dev->flags = master->flags; - slave->dev->set_multicast_list(slave->dev); - } } static int bond_enslave(struct net_device *master, struct net_device *dev) @@ -142,7 +125,6 @@ static int bond_enslave(struct net_device *master, struct net_device *dev) spin_unlock_bh(&master->xmit_lock); - MOD_INC_USE_COUNT; return 0; } @@ -210,9 +192,7 @@ static int bond_event(struct notifier_block *this, unsigned long event, void *pt } static struct notifier_block bond_netdev_notifier={ - bond_event, - NULL, - 0 + notifier_call: bond_event }; static int __init bond_init(struct net_device *dev) @@ -233,7 +213,6 @@ static int __init bond_init(struct net_device *dev) /* Initialize the device structure. */ dev->hard_start_xmit = bond_xmit; dev->get_stats = bond_get_stats; - dev->open = bond_open; dev->stop = bond_close; dev->set_multicast_list = bond_set_multicast_list; dev->do_ioctl = bond_ioctl; @@ -289,20 +268,20 @@ static struct net_device_stats *bond_get_stats(struct net_device *dev) return &bond->stats; } -static struct net_device dev_bond = { - "", - 0, 0, 0, 0, - 0x0, 0, - 0, 0, 0, NULL, bond_init }; +static struct net_device dev_bond; static int __init bonding_init(void) { /* Find a name for this unit */ - int err=dev_alloc_name(&dev_bond,"bond%d"); + int err; + + dev_bond.init = bond_init; + err = dev_alloc_name(&dev_bond,"bond%d"); if (err<0) return err; + SET_MODULE_OWNER(&dev_bond); if (register_netdev(&dev_bond) != 0) return -EIO; diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c index b83a1905e..63e190a36 100644 --- a/drivers/net/cs89x0.c +++ b/drivers/net/cs89x0.c @@ -74,13 +74,14 @@ : Use SET_MODULE_OWNER() : Tidied up strange request_irq() abuse in net_open(). -*/ - -static char version[] = -"cs89x0.c: v2.4.0-test11-pre4 Russell Nelson <nelson@crynwr.com>, Andrew Morton <andrewm@uow.edu.au>\n"; - -/* ======================= end of configuration ======================= */ + Andrew Morton : Kernel 2.4.3-pre1 + : Request correct number of pages for DMA (Hugh Dickens) + : Select PP_ChipID _after_ unregister_netdev in cleanup_module() + : because unregister_netdev() calls get_stats. + : Make `version[]' __initdata + : Uninlined the read/write reg/word functions. +*/ /* Always include 'config.h' first in case the user wants to turn on or override something. */ @@ -121,6 +122,7 @@ static char version[] = #include <linux/in.h> #include <linux/slab.h> #include <linux/string.h> +#include <linux/init.h> #include <asm/system.h> #include <asm/bitops.h> #include <asm/io.h> @@ -137,6 +139,9 @@ static char version[] = #include "cs89x0.h" +static char version[] __initdata = +"cs89x0.c: v2.4.3-pre1 Russell Nelson <nelson@crynwr.com>, Andrew Morton <andrewm@uow.edu.au>\n"; + /* First, a few definitions that the brave might change. A zero-terminated list of I/O addresses to be probed. Some special flags.. Addr & 1 = Read back the address port, look for signature and reset @@ -260,7 +265,7 @@ int __init cs89x0_probe(struct net_device *dev) SET_MODULE_OWNER(dev); if (net_debug) - printk("cs89x0:cs89x0_probe()\n"); + printk("cs89x0:cs89x0_probe(0x%x)\n", base_addr); if (base_addr > 0x1ff) /* Check a single specified location. */ return cs89x0_probe1(dev, base_addr); @@ -275,27 +280,27 @@ int __init cs89x0_probe(struct net_device *dev) return -ENODEV; } -extern int inline +static int readreg(struct net_device *dev, int portno) { outw(portno, dev->base_addr + ADD_PORT); return inw(dev->base_addr + DATA_PORT); } -extern void inline +static void writereg(struct net_device *dev, int portno, int value) { outw(portno, dev->base_addr + ADD_PORT); outw(value, dev->base_addr + DATA_PORT); } -extern int inline +static int readword(struct net_device *dev, int portno) { return inw(dev->base_addr + portno); } -extern void inline +static void writeword(struct net_device *dev, int portno, int value) { outw(value, dev->base_addr + portno); @@ -383,7 +388,9 @@ cs89x0_probe1(struct net_device *dev, int ioaddr) lp = (struct net_local *)dev->priv; /* Grab the region so we can find another board if autoIRQ fails. */ - if (!request_region(ioaddr, NETCARD_IO_EXTENT, dev->name)) { + if (!request_region(ioaddr & ~3, NETCARD_IO_EXTENT, dev->name)) { + printk(KERN_ERR "%s: request_region(0x%x, 0x%x) failed\n", + dev->name, ioaddr, NETCARD_IO_EXTENT); retval = -EBUSY; goto out1; } @@ -393,16 +400,23 @@ cs89x0_probe1(struct net_device *dev, int ioaddr) expect to find the EISA signature word. An IO with a base of 0x3 will skip the test for the ADD_PORT. */ if (ioaddr & 1) { + if (net_debug > 1) + printk(KERN_INFO "%s: odd ioaddr 0x%x\n", dev->name, ioaddr); if ((ioaddr & 2) != 2) if ((inw((ioaddr & ~3)+ ADD_PORT) & ADD_MASK) != ADD_SIG) { + printk(KERN_ERR "%s: bad signature 0x%x\n", + dev->name, inw((ioaddr & ~3)+ ADD_PORT)); retval = -ENODEV; goto out2; } ioaddr &= ~3; outw(PP_ChipID, ioaddr + ADD_PORT); } +printk("PP_addr=0x%x\n", inw(ioaddr + ADD_PORT)); if (inw(ioaddr + DATA_PORT) != CHIP_EISA_ID_SIG) { + printk(KERN_ERR "%s: incorrect signature 0x%x\n", + dev->name, inw(ioaddr + DATA_PORT)); retval = -ENODEV; goto out2; } @@ -480,6 +494,10 @@ cs89x0_probe1(struct net_device *dev, int ioaddr) lp->adapter_cnf |= A_CNF_AUI | A_CNF_10B_T | A_CNF_MEDIA_AUI | A_CNF_MEDIA_10B_T | A_CNF_MEDIA_AUTO; + if (net_debug > 1) + printk(KERN_INFO "%s: PP_LineCTL=0x%x, adapter_cnf=0x%x\n", + dev->name, i, lp->adapter_cnf); + /* IRQ. Other chips already probe, see below. */ if (lp->chip_type == CS8900) lp->isa_config = readreg(dev, PP_CS8900_ISAINT) & INT_NO_MASK; @@ -519,6 +537,9 @@ cs89x0_probe1(struct net_device *dev, int ioaddr) dev->dev_addr[i*2] = eeprom_buff[i]; dev->dev_addr[i*2+1] = eeprom_buff[i] >> 8; } + if (net_debug > 1) + printk(KERN_DEBUG "%s: new adapter_cnf: 0%x\n", + dev->name, lp->adapter_cnf); } /* allow them to force multiple transceivers. If they force multiple, autosense */ @@ -533,6 +554,10 @@ cs89x0_probe1(struct net_device *dev, int ioaddr) else if (lp->force & FORCE_BNC) {lp->adapter_cnf |= A_CNF_MEDIA_10B_2; } } + if (net_debug > 1) + printk(KERN_DEBUG "%s: after force 0x%x, adapter_cnf=0x%x\n", + dev->name, lp->force, lp->adapter_cnf); + /* FIXME: We don't let you set dc-dc polarity or low RX squelch from the command line: add it here */ /* FIXME: We don't let you set the IMM bit from the command line: add it to lp->auto_neg_cnf here */ @@ -615,7 +640,7 @@ cs89x0_probe1(struct net_device *dev, int ioaddr) printk("cs89x0_probe1() successful\n"); return 0; out2: - release_region(ioaddr, NETCARD_IO_EXTENT); + release_region(ioaddr & ~3, NETCARD_IO_EXTENT); out1: kfree(dev->priv); dev->priv = 0; @@ -1075,7 +1100,7 @@ net_open(struct net_device *dev) if (lp->isa_config & ANY_ISA_DMA) { unsigned long flags; lp->dma_buff = (unsigned char *)__get_dma_pages(GFP_KERNEL, - (lp->dmasize * 1024) / PAGE_SIZE); + get_order(lp->dmasize * 1024)); if (!lp->dma_buff) { printk(KERN_ERR "%s: cannot get %dK memory for DMA\n", dev->name, lp->dmasize); @@ -1456,7 +1481,7 @@ net_rx(struct net_device *dev) static void release_dma_buff(struct net_local *lp) { if (lp->dma_buff) { - free_pages((unsigned long)(lp->dma_buff), (lp->dmasize * 1024) / PAGE_SIZE); + free_pages((unsigned long)(lp->dma_buff), get_order(lp->dmasize * 1024)); lp->dma_buff = 0; } } @@ -1690,10 +1715,10 @@ out: void cleanup_module(void) { - outw(PP_ChipID, dev_cs89x0.base_addr + ADD_PORT); if (dev_cs89x0.priv != NULL) { /* Free up the private structure, or leak memory :-) */ unregister_netdev(&dev_cs89x0); + outw(PP_ChipID, dev_cs89x0.base_addr + ADD_PORT); kfree(dev_cs89x0.priv); dev_cs89x0.priv = NULL; /* gets re-allocated by cs89x0_probe1 */ /* If we don't do this, we can't re-insmod it later. */ diff --git a/drivers/net/daynaport.c b/drivers/net/daynaport.c index 64e17a7c1..75b65db10 100644 --- a/drivers/net/daynaport.c +++ b/drivers/net/daynaport.c @@ -275,6 +275,9 @@ int __init mac8390_probe(struct net_device *dev) return -ENODEV; dev = init_etherdev(dev, 0); + if (!dev) + return -ENOMEM; + SET_MODULE_OWNER(dev); if (!version_printed) { printk(KERN_INFO "%s", version); @@ -445,7 +448,7 @@ int __init mac8390_probe(struct net_device *dev) } /* We should hopefully not get here */ - printk(KERN_ERR "Probe unsucessful.\n"); + printk(KERN_ERR "Probe unsuccessful.\n"); return -ENODEV; membad: @@ -630,7 +633,8 @@ static int __init ns8390_probe1(struct net_device *dev, int word16, char *model_ static int ns8390_open(struct net_device *dev) { - MOD_INC_USE_COUNT; + int ret; + ei_open(dev); /* At least on my card (a Focus Enhancements PDS card) I start */ @@ -639,11 +643,10 @@ static int ns8390_open(struct net_device *dev) /* - funaho@jurai.org (1999-05-17) */ /* Non-slow interrupt, works around issues with the SONIC driver */ - if (request_irq(dev->irq, ei_interrupt, 0, "8390 Ethernet", dev)) - { + ret = request_irq(dev->irq, ei_interrupt, 0, dev->name, dev); + if (ret) { printk ("%s: unable to get IRQ %d.\n", dev->name, dev->irq); - MOD_DEC_USE_COUNT; - return -EAGAIN; + return ret; } return 0; } @@ -654,7 +657,6 @@ static void ns8390_no_reset(struct net_device *dev) printk("Need to reset the NS8390 t=%lu...", jiffies); ei_status.txing = 0; if (ei_debug > 1) printk("reset not supported\n"); - return; } static int ns8390_close_card(struct net_device *dev) @@ -663,7 +665,6 @@ static int ns8390_close_card(struct net_device *dev) printk("%s: Shutting down ethercard.\n", dev->name); free_irq(dev->irq, dev); ei_close(dev); - MOD_DEC_USE_COUNT; return 0; } diff --git a/drivers/net/de4x5.c b/drivers/net/de4x5.c index fa894d644..3044ee4a3 100644 --- a/drivers/net/de4x5.c +++ b/drivers/net/de4x5.c @@ -929,8 +929,6 @@ static int de4x5_rx_ovfc(struct net_device *dev); static int autoconf_media(struct net_device *dev); static void create_packet(struct net_device *dev, char *frame, int len); -static void de4x5_us_delay(u32 usec); -static void de4x5_ms_delay(u32 msec); static void load_packet(struct net_device *dev, char *buf, u32 flags, struct sk_buff *skb); static int dc21040_autoconf(struct net_device *dev); static int dc21041_autoconf(struct net_device *dev); @@ -1096,13 +1094,13 @@ static int (*dc_infoblock[])(struct net_device *dev, u_char, u_char *) = { #define RESET_DE4X5 {\ int i;\ i=inl(DE4X5_BMR);\ - de4x5_ms_delay(1);\ + mdelay(1);\ outl(i | BMR_SWR, DE4X5_BMR);\ - de4x5_ms_delay(1);\ + mdelay(1);\ outl(i, DE4X5_BMR);\ - de4x5_ms_delay(1);\ - for (i=0;i<5;i++) {inl(DE4X5_BMR); de4x5_ms_delay(1);}\ - de4x5_ms_delay(1);\ + mdelay(1);\ + for (i=0;i<5;i++) {inl(DE4X5_BMR); mdelay(1);}\ + mdelay(1);\ } #define PHY_HARD_RESET {\ @@ -1146,7 +1144,7 @@ de4x5_hw_init(struct net_device *dev, u_long iobase, struct pci_dev *pdev) pcibios_write_config_byte(lp->bus_num, lp->device << 3, PCI_CFDA_PSM, WAKEUP); } - de4x5_ms_delay(10); + mdelay(10); RESET_DE4X5; @@ -1731,13 +1729,13 @@ de4x5_rx(struct net_device *dev) /* Push up the protocol stack */ skb->protocol=eth_type_trans(skb,dev); + de4x5_local_stats(dev, skb->data, pkt_len); netif_rx(skb); /* Update stats */ dev->last_rx = jiffies; lp->stats.rx_packets++; lp->stats.rx_bytes += pkt_len; - de4x5_local_stats(dev, skb->data, pkt_len); } } @@ -2303,6 +2301,9 @@ srom_search(struct pci_dev *dev) for (walk = walk->next; walk != &dev->bus_list; walk = walk->next) { struct pci_dev *this_dev = pci_dev_b(walk); + /* Skip the pci_bus list entry */ + if (list_entry(walk, struct pci_bus, devices) == dev->bus) continue; + pb = this_dev->bus->number; vendor = this_dev->vendor; device = this_dev->device << 8; @@ -3921,7 +3922,7 @@ reset_init_sia(struct net_device *dev, s32 csr13, s32 csr14, s32 csr15) outl(csr14, DE4X5_STRR); outl(csr13, DE4X5_SICR); - de4x5_ms_delay(10); + mdelay(10); return; } @@ -3949,33 +3950,6 @@ create_packet(struct net_device *dev, char *frame, int len) } /* -** Known delay in microseconds -*/ -static void -de4x5_us_delay(u32 usec) -{ - udelay(usec); - - return; -} - -/* -** Known delay in milliseconds, in millisecond steps. -*/ -static void -de4x5_ms_delay(u32 msec) -{ - u_int i; - - for (i=0; i<msec; i++) { - de4x5_us_delay(1000); - } - - return; -} - - -/* ** Look for a particular board name in the EISA configuration space */ static int @@ -4367,7 +4341,7 @@ srom_address(u_int command, u_long addr, u_char offset) for (i=0; i<6; i++, a <<= 1) { srom_latch(command | ((a & 0x80) ? DT_IN : 0), addr); } - de4x5_us_delay(1); + udelay(1); i = (getfrom_srom(addr) >> 3) & 0x01; @@ -4401,7 +4375,7 @@ srom_busy(u_int command, u_long addr) sendto_srom((command & 0x0000ff00) | DT_CS, addr); while (!((getfrom_srom(addr) >> 3) & 0x01)) { - de4x5_ms_delay(1); + mdelay(1); } sendto_srom(command & 0x0000ff00, addr); @@ -5332,7 +5306,7 @@ yawn(struct net_device *dev, int state) switch(state) { case WAKEUP: outb(WAKEUP, PCI_CFPM); - de4x5_ms_delay(10); + mdelay(10); break; case SNOOZE: @@ -5349,7 +5323,7 @@ yawn(struct net_device *dev, int state) case WAKEUP: pcibios_write_config_byte(lp->bus_num, lp->device << 3, PCI_CFDA_PSM, WAKEUP); - de4x5_ms_delay(10); + mdelay(10); break; case SNOOZE: diff --git a/drivers/net/de4x5.h b/drivers/net/de4x5.h index 4ab3889b7..dad88edce 100644 --- a/drivers/net/de4x5.h +++ b/drivers/net/de4x5.h @@ -287,7 +287,7 @@ #define STS_LNF 0x00001000 /* Link Fail */ #define STS_FD 0x00000800 /* Full-Duplex Short Frame Received */ #define STS_TM 0x00000800 /* Timer Expired (DC21041) */ -#define STS_ETI 0x00000400 /* Early Transmit Interupt */ +#define STS_ETI 0x00000400 /* Early Transmit Interrupt */ #define STS_AT 0x00000400 /* AUI/TP Pin */ #define STS_RWT 0x00000200 /* Receive Watchdog Time-Out */ #define STS_RPS 0x00000100 /* Receive Process Stopped */ diff --git a/drivers/net/de600.c b/drivers/net/de600.c index 4549d2c5e..efd974baa 100644 --- a/drivers/net/de600.c +++ b/drivers/net/de600.c @@ -616,11 +616,15 @@ de600_rx_intr(struct net_device *dev) for (i = size; i > 0; --i, ++buffer) *buffer = de600_read_byte(READ_DATA, dev); - ((struct net_device_stats *)(dev->priv))->rx_packets++; /* count all receives */ - skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); + + /* update stats */ + dev->last_rx = jiffies; + ((struct net_device_stats *)(dev->priv))->rx_packets++; /* count all receives */ + ((struct net_device_stats *)(dev->priv))->rx_bytes += size; /* count all received bytes */ + /* * If any worth-while packets have been received, netif_rx() * has done a mark_bh(INET_BH) for us and will work on them diff --git a/drivers/net/de620.c b/drivers/net/de620.c index ecc71eb00..713e40b6e 100644 --- a/drivers/net/de620.c +++ b/drivers/net/de620.c @@ -563,7 +563,6 @@ static int de620_start_xmit(struct sk_buff *skb, struct net_device *dev) printk(KERN_WARNING "%s: No tx-buffer available!\n", dev->name); restore_flags(flags); return 1; - break; } de620_write_block(dev, buffer, len); @@ -699,8 +698,10 @@ static int de620_rx_intr(struct net_device *dev) PRINTK(("Read %d bytes\n", size)); skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); /* deliver it "upstairs" */ + dev->last_rx = jiffies; /* count all receives */ ((struct net_device_stats *)(dev->priv))->rx_packets++; + ((struct net_device_stats *)(dev->priv))->rx_bytes += size; } } diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c index 6915d7a1f..7ea886861 100644 --- a/drivers/net/defxx.c +++ b/drivers/net/defxx.c @@ -195,6 +195,8 @@ * Jun 2000 jgarzik PCI and resource alloc cleanups * Jul 2000 tjeerd Much cleanup and some bug fixes * Sep 2000 tjeerd Fix leak on unload, cosmetic code cleanup + * Feb 2001 Skb allocation fixes + * Feb 2001 davej PCI enable cleanups. */ /* Include files */ @@ -225,7 +227,7 @@ /* Version information string - should be updated prior to each new release!!! */ static char version[] __devinitdata = - "defxx.c:v1.05d 2000/09/05 Lawrence V. Stefani and others\n"; + "defxx.c:v1.05e 2001/02/03 Lawrence V. Stefani and others\n"; #define DYNAMIC_BUFFERS 1 @@ -242,7 +244,7 @@ static void dfx_bus_init(struct net_device *dev); static void dfx_bus_config_check(DFX_board_t *bp); static int dfx_driver_init(struct net_device *dev); -static int dfx_adap_init(DFX_board_t *bp); +static int dfx_adap_init(DFX_board_t *bp, int get_buffers); static int dfx_open(struct net_device *dev); static int dfx_close(struct net_device *dev); @@ -264,8 +266,9 @@ static void dfx_hw_adap_reset(DFX_board_t *bp, PI_UINT32 type); static int dfx_hw_adap_state_rd(DFX_board_t *bp); static int dfx_hw_dma_uninit(DFX_board_t *bp, PI_UINT32 type); -static void dfx_rcv_init(DFX_board_t *bp); +static int dfx_rcv_init(DFX_board_t *bp, int get_buffers); static void dfx_rcv_queue_process(DFX_board_t *bp); +static void dfx_rcv_flush(DFX_board_t *bp); static int dfx_xmt_queue_pkt(struct sk_buff *skb, struct net_device *dev); static int dfx_xmt_done(DFX_board_t *bp); @@ -339,7 +342,6 @@ static inline void dfx_port_write_byte( u16 port = bp->base_addr + offset; outb(data, port); - return; } static inline void dfx_port_read_byte( @@ -352,7 +354,6 @@ static inline void dfx_port_read_byte( u16 port = bp->base_addr + offset; *data = inb(port); - return; } static inline void dfx_port_write_long( @@ -365,7 +366,6 @@ static inline void dfx_port_write_long( u16 port = bp->base_addr + offset; outl(data, port); - return; } static inline void dfx_port_read_long( @@ -378,7 +378,6 @@ static inline void dfx_port_read_long( u16 port = bp->base_addr + offset; *data = inl(port); - return; } @@ -395,6 +394,7 @@ static inline void dfx_port_read_long( * * Arguments: * pdev - pointer to pci device information (NULL for EISA) + * ioaddr - pointer to port (NULL for PCI) * * Functional Description: * @@ -415,6 +415,7 @@ static int __devinit dfx_init_one_pci_or_eisa(struct pci_dev *pdev, long ioaddr) struct net_device *dev; DFX_board_t *bp; /* board pointer */ static int version_disp; + int err; if (!version_disp) /* display version info if adapter is found */ { @@ -426,18 +427,27 @@ static int __devinit dfx_init_one_pci_or_eisa(struct pci_dev *pdev, long ioaddr) * init_fddidev() allocates a device structure with private data, clears the device structure and private data, * and calls fddi_setup() and register_netdev(). Not much left to do for us here. */ - dev = init_fddidev( NULL, sizeof(*bp)); - + dev = init_fddidev(NULL, sizeof(*bp)); if (!dev) { printk (KERN_ERR "defxx: unable to allocate fddidev, aborting\n"); return -ENOMEM; } - bp = (DFX_board_t*)dev->priv; + /* Enable PCI device. */ + if (pdev != NULL) { + err = pci_enable_device (pdev); + if (err) goto err_out; + ioaddr = pci_resource_start (pdev, 1); + } + + SET_MODULE_OWNER(dev); + + bp = dev->priv; if (!request_region (ioaddr, pdev ? PFI_K_CSR_IO_LEN : PI_ESIC_K_CSR_IO_LEN, dev->name)) { printk (KERN_ERR "%s: Cannot reserve I/O resource 0x%x @ 0x%lx, aborting\n", dev->name, PFI_K_CSR_IO_LEN, ioaddr); + err = -EBUSY; goto err_out; } @@ -461,14 +471,14 @@ static int __devinit dfx_init_one_pci_or_eisa(struct pci_dev *pdev, long ioaddr) /* PCI board */ bp->bus_type = DFX_BUS_TYPE_PCI; bp->pci_dev = pdev; - pdev->driver_data = dev; - if (pci_enable_device (pdev)) - goto err_out_region; + pci_set_drvdata (pdev, dev); pci_set_master (pdev); } - if (dfx_driver_init(dev) != DFX_K_SUCCESS) + if (dfx_driver_init(dev) != DFX_K_SUCCESS) { + err = -ENODEV; goto err_out_region; + } return 0; @@ -477,12 +487,12 @@ err_out_region: err_out: unregister_netdev(dev); kfree(dev); - return -ENODEV; + return err; } static int __devinit dfx_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { - return dfx_init_one_pci_or_eisa(pdev, pci_resource_start (pdev, 1)); + return dfx_init_one_pci_or_eisa(pdev, 0); } static int __init dfx_eisa_init(void) @@ -543,7 +553,7 @@ static int __init dfx_eisa_init(void) static void __devinit dfx_bus_init(struct net_device *dev) { - DFX_board_t *bp = (DFX_board_t *)dev->priv; + DFX_board_t *bp = dev->priv; u8 val; /* used for I/O read/writes */ DBG_printk("In dfx_bus_init...\n"); @@ -642,7 +652,6 @@ static void __devinit dfx_bus_init(struct net_device *dev) dfx_port_write_long(bp, PFI_K_REG_MODE_CTRL, (PFI_MODE_M_PDQ_INT_ENB | PFI_MODE_M_DMA_ENB)); } - return; } @@ -737,7 +746,6 @@ static void __devinit dfx_bus_config_check(DFX_board_t *bp) } } } - return; } @@ -779,7 +787,7 @@ static void __devinit dfx_bus_config_check(DFX_board_t *bp) static int __devinit dfx_driver_init(struct net_device *dev) { - DFX_board_t *bp = (DFX_board_t *)dev->priv; + DFX_board_t *bp = dev->priv; int alloc_size; /* total buffer size needed */ char *top_v, *curr_v; /* virtual addrs into memory block */ u32 top_p, curr_p; /* physical addrs into memory block */ @@ -977,6 +985,7 @@ static int __devinit dfx_driver_init(struct net_device *dev) * * Arguments: * bp - pointer to board information + * get_buffers - non-zero if buffers to be allocated * * Functional Description: * Issues the low-level firmware/hardware calls necessary to bring @@ -996,7 +1005,7 @@ static int __devinit dfx_driver_init(struct net_device *dev) * upon a successful return of this routine. */ -static int dfx_adap_init(DFX_board_t *bp) +static int dfx_adap_init(DFX_board_t *bp, int get_buffers) { DBG_printk("In dfx_adap_init...\n"); @@ -1131,9 +1140,23 @@ static int dfx_adap_init(DFX_board_t *bp) return(DFX_K_FAILURE); } + /* + * Remove any existing dynamic buffers (i.e. if the adapter is being + * reinitialized) + */ + + if (get_buffers) + dfx_rcv_flush(bp); + /* Initialize receive descriptor block and produce buffers */ - dfx_rcv_init(bp); + if (dfx_rcv_init(bp, get_buffers)) + { + printk("%s: Receive buffer allocation failed\n", bp->dev->name); + if (get_buffers) + dfx_rcv_flush(bp); + return(DFX_K_FAILURE); + } /* Issue START command and bring adapter to LINK_(UN)AVAILABLE state */ @@ -1141,6 +1164,8 @@ static int dfx_adap_init(DFX_board_t *bp) if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS) { printk("%s: Start command failed\n", bp->dev->name); + if (get_buffers) + dfx_rcv_flush(bp); return(DFX_K_FAILURE); } @@ -1183,19 +1208,17 @@ static int dfx_adap_init(DFX_board_t *bp) static int dfx_open(struct net_device *dev) { - DFX_board_t *bp = (DFX_board_t *)dev->priv; + int ret; + DFX_board_t *bp = dev->priv; DBG_printk("In dfx_open...\n"); - MOD_INC_USE_COUNT; - /* Register IRQ - support shared interrupts by passing device ptr */ - if (request_irq(dev->irq, (void *)dfx_interrupt, SA_SHIRQ, dev->name, dev)) - { + ret = request_irq(dev->irq, (void *)dfx_interrupt, SA_SHIRQ, dev->name, dev); + if (ret) { printk(KERN_ERR "%s: Requested IRQ %d is busy\n", dev->name, dev->irq); - MOD_DEC_USE_COUNT; - return -EAGAIN; + return ret; } /* @@ -1228,11 +1251,10 @@ static int dfx_open(struct net_device *dev) /* Reset and initialize adapter */ bp->reset_type = PI_PDATA_A_RESET_M_SKIP_ST; /* skip self-test */ - if (dfx_adap_init(bp) != DFX_K_SUCCESS) + if (dfx_adap_init(bp, 1) != DFX_K_SUCCESS) { printk(KERN_ERR "%s: Adapter open failed!\n", dev->name); free_irq(dev->irq, dev); - MOD_DEC_USE_COUNT; return -EAGAIN; } @@ -1276,7 +1298,7 @@ static int dfx_open(struct net_device *dev) static int dfx_close(struct net_device *dev) { - DFX_board_t *bp = (DFX_board_t *)dev->priv; + DFX_board_t *bp = dev->priv; DBG_printk("In dfx_close...\n"); @@ -1318,6 +1340,10 @@ static int dfx_close(struct net_device *dev) memset(bp->cons_block_virt, 0, sizeof(PI_CONSUMER_BLOCK)); + /* Release all dynamically allocate skb in the receive ring. */ + + dfx_rcv_flush(bp); + /* Clear device structure flags */ netif_stop_queue(dev); @@ -1326,7 +1352,6 @@ static int dfx_close(struct net_device *dev) free_irq(dev->irq, dev); - MOD_DEC_USE_COUNT; return(0); } @@ -1412,7 +1437,6 @@ static void dfx_int_pr_halt_id(DFX_board_t *bp) printk("%s: Halt ID: Unknown (code = %X)\n", bp->dev->name, halt_id); break; } - return; } @@ -1504,7 +1528,7 @@ static void dfx_int_type_0_process(DFX_board_t *bp) bp->link_available = PI_K_FALSE; /* link is no longer available */ bp->reset_type = 0; /* rerun on-board diagnostics */ printk("%s: Resetting adapter...\n", bp->dev->name); - if (dfx_adap_init(bp) != DFX_K_SUCCESS) + if (dfx_adap_init(bp, 0) != DFX_K_SUCCESS) { printk("%s: Adapter reset failed! Disabling adapter interrupts.\n", bp->dev->name); dfx_port_write_long(bp, PI_PDQ_K_REG_HOST_INT_ENB, PI_HOST_INT_K_DISABLE_ALL_INTS); @@ -1552,7 +1576,7 @@ static void dfx_int_type_0_process(DFX_board_t *bp) bp->link_available = PI_K_FALSE; /* link is no longer available */ bp->reset_type = 0; /* rerun on-board diagnostics */ printk("%s: Resetting adapter...\n", bp->dev->name); - if (dfx_adap_init(bp) != DFX_K_SUCCESS) + if (dfx_adap_init(bp, 0) != DFX_K_SUCCESS) { printk("%s: Adapter reset failed! Disabling adapter interrupts.\n", bp->dev->name); dfx_port_write_long(bp, PI_PDQ_K_REG_HOST_INT_ENB, PI_HOST_INT_K_DISABLE_ALL_INTS); @@ -1565,7 +1589,6 @@ static void dfx_int_type_0_process(DFX_board_t *bp) bp->link_available = PI_K_TRUE; /* set link available flag */ } } - return; } @@ -1611,7 +1634,7 @@ static void dfx_int_type_0_process(DFX_board_t *bp) static void dfx_int_common(struct net_device *dev) { - DFX_board_t *bp = (DFX_board_t *) dev->priv; + DFX_board_t *bp = dev->priv; PI_UINT32 port_status; /* Port Status register */ /* Process xmt interrupts - frequent case, so always call this routine */ @@ -1640,7 +1663,6 @@ static void dfx_int_common(struct net_device *dev) if (port_status & PI_PSTATUS_M_TYPE_0_PENDING) dfx_int_type_0_process(bp); /* process Type 0 interrupts */ - return; } @@ -1682,13 +1704,13 @@ static void dfx_int_common(struct net_device *dev) static void dfx_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - struct net_device *dev = (struct net_device *) dev_id; + struct net_device *dev = dev_id; DFX_board_t *bp; /* private board structure pointer */ u8 tmp; /* used for disabling/enabling ints */ /* Get board pointer only if device structure is valid */ - bp = (DFX_board_t *) dev->priv; + bp = dev->priv; spin_lock(&bp->lock); @@ -1732,7 +1754,6 @@ static void dfx_interrupt(int irq, void *dev_id, struct pt_regs *regs) } spin_unlock(&bp->lock); - return; } @@ -1781,7 +1802,7 @@ static void dfx_interrupt(int irq, void *dev_id, struct pt_regs *regs) static struct net_device_stats *dfx_ctl_get_stats(struct net_device *dev) { - DFX_board_t *bp = (DFX_board_t *)dev->priv; + DFX_board_t *bp = dev->priv; /* Fill the bp->stats structure with driver-maintained counters */ @@ -1966,7 +1987,7 @@ static struct net_device_stats *dfx_ctl_get_stats(struct net_device *dev) static void dfx_ctl_set_multicast_list(struct net_device *dev) { - DFX_board_t *bp = (DFX_board_t *)dev->priv; + DFX_board_t *bp = dev->priv; int i; /* used as index in for loop */ struct dev_mc_list *dmi; /* ptr to multicast addr entry */ @@ -2039,7 +2060,6 @@ static void dfx_ctl_set_multicast_list(struct net_device *dev) { DBG_printk("%s: Adapter filters updated!\n", dev->name); } - return; } @@ -2081,7 +2101,7 @@ static void dfx_ctl_set_multicast_list(struct net_device *dev) static int dfx_ctl_set_mac_address(struct net_device *dev, void *addr) { - DFX_board_t *bp = (DFX_board_t *)dev->priv; + DFX_board_t *bp = dev->priv; struct sockaddr *p_sockaddr = (struct sockaddr *)addr; /* Copy unicast address to driver-maintained structs and update count */ @@ -2540,7 +2560,6 @@ static void dfx_hw_adap_reset( /* Deassert reset */ dfx_port_write_long(bp, PI_PDQ_K_REG_PORT_RESET, 0); - return; } @@ -2631,8 +2650,7 @@ static int dfx_hw_dma_uninit(DFX_board_t *bp, PI_UINT32 type) return(DFX_K_HW_TIMEOUT); return(DFX_K_SUCCESS); } - - + /* * Align an sk_buff to a boundary power of 2 * @@ -2662,6 +2680,7 @@ static void my_skb_align(struct sk_buff *skb, int n) * * Arguments: * bp - pointer to board information + * get_buffers - non-zero if buffers to be allocated * * Functional Description: * This routine can be called during dfx_adap_init() or during an adapter @@ -2669,7 +2688,10 @@ static void my_skb_align(struct sk_buff *skb, int n) * LLC Host queue receive buffers. * * Return Codes: - * None + * Return 0 on success or -ENOMEM if buffer allocation failed (when using + * dynamic buffer allocation). If the buffer allocation failed, the + * already allocated buffers will not be released and the caller should do + * this. * * Assumptions: * The PDQ has been reset and the adapter and driver maintained Type 2 @@ -2680,7 +2702,7 @@ static void my_skb_align(struct sk_buff *skb, int n) * is notified. */ -static void dfx_rcv_init(DFX_board_t *bp) +static int dfx_rcv_init(DFX_board_t *bp, int get_buffers) { int i, j; /* used in for loop */ @@ -2702,20 +2724,22 @@ static void dfx_rcv_init(DFX_board_t *bp) * driver initialization when we allocated memory for the receive buffers. */ + if (get_buffers) { #ifdef DYNAMIC_BUFFERS for (i = 0; i < (int)(bp->rcv_bufs_to_post); i++) for (j = 0; (i + j) < (int)PI_RCV_DATA_K_NUM_ENTRIES; j += bp->rcv_bufs_to_post) { - struct sk_buff *newskb; + struct sk_buff *newskb = __dev_alloc_skb(NEW_SKB_SIZE, GFP_BUFFER); + if (!newskb) + return -ENOMEM; bp->descr_block_virt->rcv_data[i+j].long_0 = (u32) (PI_RCV_DESCR_M_SOP | ((PI_RCV_DATA_K_SIZE_MAX / PI_ALIGN_K_RCV_DATA_BUFF) << PI_RCV_DESCR_V_SEG_LEN)); - newskb = dev_alloc_skb(NEW_SKB_SIZE); /* * align to 128 bytes for compatibility with * the old EISA boards. */ - my_skb_align(newskb,128); + my_skb_align(newskb, 128); bp->descr_block_virt->rcv_data[i+j].long_1 = virt_to_bus(newskb->data); /* * p_rcv_buff_va is only used inside the @@ -2733,12 +2757,13 @@ static void dfx_rcv_init(DFX_board_t *bp) bp->p_rcv_buff_va[i+j] = (char *) (bp->rcv_block_virt + (i * PI_RCV_DATA_K_SIZE_MAX)); } #endif + } /* Update receive producer and Type 2 register */ bp->rcv_xmt_reg.index.rcv_prod = bp->rcv_bufs_to_post; dfx_port_write_long(bp, PI_PDQ_K_REG_TYPE_2_PROD, bp->rcv_xmt_reg.lword); - return; + return 0; } @@ -2833,7 +2858,7 @@ static void dfx_rcv_queue_process( bp->p_rcv_buff_va[entry] = (char *)newskb; bp->descr_block_virt->rcv_data[entry].long_1 = virt_to_bus(newskb->data); } else - skb = 0; + skb = NULL; } else #endif skb = dev_alloc_skb(pkt_len+3); /* alloc new buffer to pass up, add room for PRH */ @@ -2858,6 +2883,7 @@ static void dfx_rcv_queue_process( skb->dev = bp->dev; /* pass up device pointer */ skb->protocol = fddi_type_trans(skb, bp->dev); + bp->rcv_total_bytes += skb->len; netif_rx(skb); /* Update the rcv counters */ @@ -2865,8 +2891,6 @@ static void dfx_rcv_queue_process( bp->rcv_total_frames++; if (*(p_buff + RCV_BUFF_K_DA) & 0x01) bp->rcv_multicast_frames++; - - bp->rcv_total_bytes += skb->len; } } } @@ -2882,7 +2906,6 @@ static void dfx_rcv_queue_process( bp->rcv_xmt_reg.index.rcv_prod += 1; bp->rcv_xmt_reg.index.rcv_comp += 1; } - return; } @@ -2953,7 +2976,7 @@ static int dfx_xmt_queue_pkt( ) { - DFX_board_t *bp = (DFX_board_t *) dev->priv; + DFX_board_t *bp = dev->priv; u8 prod; /* local transmit producer index */ PI_XMT_DESCR *p_xmt_descr; /* ptr to transmit descriptor block entry */ XMT_DRIVER_DESCR *p_xmt_drv_descr; /* ptr to transmit driver descriptor */ @@ -3183,6 +3206,54 @@ static int dfx_xmt_done(DFX_board_t *bp) /* * ================= + * = dfx_rcv_flush = + * ================= + * + * Overview: + * Remove all skb's in the receive ring. + * + * Returns: + * None + * + * Arguments: + * bp - pointer to board information + * + * Functional Description: + * Free's all the dynamically allocated skb's that are + * currently attached to the device receive ring. This + * function is typically only used when the device is + * initialized or reinitialized. + * + * Return Codes: + * None + * + * Side Effects: + * None + */ +#ifdef DYNAMIC_BUFFERS +static void dfx_rcv_flush( DFX_board_t *bp ) + { + int i, j; + + for (i = 0; i < (int)(bp->rcv_bufs_to_post); i++) + for (j = 0; (i + j) < (int)PI_RCV_DATA_K_NUM_ENTRIES; j += bp->rcv_bufs_to_post) + { + struct sk_buff *skb; + skb = (struct sk_buff *)bp->p_rcv_buff_va[i+j]; + if (skb) + dev_kfree_skb(skb); + bp->p_rcv_buff_va[i+j] = NULL; + } + + } +#else +static inline void dfx_rcv_flush( DFX_board_t *bp ) +{ +} +#endif /* DYNAMIC_BUFFERS */ + +/* + * ================= * = dfx_xmt_flush = * ================= * @@ -3257,12 +3328,11 @@ static void dfx_xmt_flush( DFX_board_t *bp ) prod_cons = (u32)(bp->cons_block_virt->xmt_rcv_data & ~PI_CONS_M_XMT_INDEX); prod_cons |= (u32)(bp->rcv_xmt_reg.index.xmt_prod << PI_CONS_V_XMT_INDEX); bp->cons_block_virt->xmt_rcv_data = prod_cons; - return; } static void __devexit dfx_remove_one_pci_or_eisa(struct pci_dev *pdev, struct net_device *dev) { - DFX_board_t *bp = (DFX_board_t*)dev->priv; + DFX_board_t *bp = dev->priv; unregister_netdev(dev); release_region(dev->base_addr, pdev ? PFI_K_CSR_IO_LEN : PI_ESIC_K_CSR_IO_LEN ); @@ -3272,9 +3342,10 @@ static void __devexit dfx_remove_one_pci_or_eisa(struct pci_dev *pdev, struct ne static void __devexit dfx_remove_one (struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; + struct net_device *dev = pci_get_drvdata(pdev); dfx_remove_one_pci_or_eisa(pdev, dev); + pci_set_drvdata(pdev, NULL); } static struct pci_device_id dfx_pci_tbl[] __devinitdata = { diff --git a/drivers/net/depca.c b/drivers/net/depca.c index 1c6a0aa6d..8f77d2aa2 100644 --- a/drivers/net/depca.c +++ b/drivers/net/depca.c @@ -226,12 +226,12 @@ 0.52 16-Oct-00 Fixes for 2.3 io memory accesses Fix show-stopper (ints left masked) in depca_interrupt by <peterd@pnd-pc.demon.co.uk> + 0.53 12-Jan-01 Release resources on failure, bss tidbits + by acme@conectiva.com.br ========================================================================= */ -static const char *version = "depca.c:v0.51 1999/6/27 davies@maniac.ultranet.com\n"; - #include <linux/config.h> #include <linux/module.h> @@ -265,6 +265,9 @@ static const char *version = "depca.c:v0.51 1999/6/27 davies@maniac.ultranet.com #include "depca.h" +static char version[] __initdata = + "depca.c:v0.53 2001/1/12 davies@maniac.ultranet.com\n"; + #ifdef DEPCA_DEBUG static int depca_debug = DEPCA_DEBUG; #else @@ -309,7 +312,7 @@ static int depca_debug = 1; #define DEPCA_RAM_BASE_ADDRESSES {0xc0000,0xd0000,0xe0000,0x00000} #define DEPCA_IO_PORTS {0x300, 0x200, 0} #define DEPCA_TOTAL_SIZE 0x10 -static short mem_chkd = 0; +static short mem_chkd; /* ** Adapter ID for the MCA EtherWORKS DE210/212 adapter @@ -480,8 +483,9 @@ static char name[DEPCA_STRLEN]; static int num_depcas, num_eth; static int mem; /* For loadable module assignment use insmod mem=0x????? .... */ -static char *adapter_name = '\0'; /* If no PROM when loadable module +static char *adapter_name; /* = '\0'; If no PROM when loadable module use insmod adapter_name=DE??? ... + bss initializes this to zero */ /* ** Miscellaneous defines... @@ -496,6 +500,8 @@ depca_probe(struct net_device *dev) int tmp = num_depcas, status = -ENODEV; u_long iobase = dev->base_addr; + SET_MODULE_OWNER(dev); + if ((iobase == 0) && loading_module){ printk("Autoprobing is not supported when loading a module based driver.\n"); status = -EIO; @@ -566,15 +572,14 @@ depca_hw_init(struct net_device *dev, u_long ioaddr, int mca_slot) printk(", h/w address "); status = get_hw_addr(dev); - for (i=0; i<ETH_ALEN - 1; i++) { /* get the ethernet address */ - printk("%2.2x:", dev->dev_addr[i]); - } - printk("%2.2x", dev->dev_addr[i]); - if (status != 0) { printk(" which has an Ethernet PROM CRC error.\n"); return -ENXIO; } + for (i=0; i<ETH_ALEN - 1; i++) { /* get the ethernet address */ + printk("%2.2x:", dev->dev_addr[i]); + } + printk("%2.2x", dev->dev_addr[i]); /* Set up the maximum amount of network RAM(kB) */ netRAM = ((adapter != DEPCA) ? 64 : 48); @@ -616,17 +621,19 @@ depca_hw_init(struct net_device *dev, u_long ioaddr, int mca_slot) lp->mca_slot = mca_slot; lp->lock = SPIN_LOCK_UNLOCKED; sprintf(lp->adapter_name,"%s (%s)", name, dev->name); + status = -EBUSY; if (!request_region(ioaddr, DEPCA_TOTAL_SIZE, lp->adapter_name)) { printk(KERN_ERR "depca: I/O resource 0x%x @ 0x%lx busy\n", DEPCA_TOTAL_SIZE, ioaddr); - return -EBUSY; + goto out_priv; } /* Initialisation Block */ lp->sh_mem = ioremap(mem_start, mem_len); + status = -EIO; if (lp->sh_mem == NULL) { printk(KERN_ERR "depca: cannot remap ISA memory, aborting\n"); - return -EIO; + goto out_region; } lp->device_ram_start = mem_start & LA_MASK; @@ -700,20 +707,21 @@ depca_hw_init(struct net_device *dev, u_long ioaddr, int mca_slot) outw(INEA | INIT, DEPCA_DATA); irqnum = autoirq_report(1); + status = -ENXIO; if (!irqnum) { printk(" and failed to detect IRQ line.\n"); - status = -ENXIO; + goto out_region; } else { - for (dev->irq=0,i=0; (depca_irq[i]) && (!dev->irq); i++) { + for (dev->irq=0,i=0; (depca_irq[i]) && (!dev->irq); i++) if (irqnum == depca_irq[i]) { dev->irq = irqnum; printk(" and uses IRQ%d.\n", dev->irq); } - } + status = -ENXIO; if (!dev->irq) { printk(" but incorrect IRQ line detected.\n"); - status = -ENXIO; + goto out_region; } } #endif /* MODULE */ @@ -721,33 +729,30 @@ depca_hw_init(struct net_device *dev, u_long ioaddr, int mca_slot) printk(" and assigned IRQ%d.\n", dev->irq); } - if (!status) { - if (depca_debug > 1) { - printk(version); - } - - /* The DEPCA-specific entries in the device structure. */ - dev->open = &depca_open; - dev->hard_start_xmit = &depca_start_xmit; - dev->stop = &depca_close; - dev->get_stats = &depca_get_stats; - dev->set_multicast_list = &set_multicast_list; - dev->do_ioctl = &depca_ioctl; - dev->tx_timeout = depca_tx_timeout; - dev->watchdog_timeo = TX_TIMEOUT; - - dev->mem_start = 0; - - /* Fill in the generic field of the device structure. */ - ether_setup(dev); - } else { /* Incorrectly initialised hardware */ - release_region(ioaddr, DEPCA_TOTAL_SIZE); - if (dev->priv) { - kfree(dev->priv); - dev->priv = NULL; - } + if (depca_debug > 1) { + printk(version); } + /* The DEPCA-specific entries in the device structure. */ + dev->open = &depca_open; + dev->hard_start_xmit = &depca_start_xmit; + dev->stop = &depca_close; + dev->get_stats = &depca_get_stats; + dev->set_multicast_list = &set_multicast_list; + dev->do_ioctl = &depca_ioctl; + dev->tx_timeout = depca_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + + dev->mem_start = 0; + + /* Fill in the generic field of the device structure. */ + ether_setup(dev); + return 0; +out_region: + release_region(ioaddr, DEPCA_TOTAL_SIZE); +out_priv: + kfree(dev->priv); + dev->priv = NULL; return status; } @@ -794,9 +799,6 @@ depca_open(struct net_device *dev) printk("nicsr: 0x%02x\n",inb(DEPCA_NICSR)); } } - - MOD_INC_USE_COUNT; - return status; } @@ -1120,9 +1122,6 @@ depca_close(struct net_device *dev) ** Free the associated irq */ free_irq(dev->irq, dev); - - MOD_DEC_USE_COUNT; - return 0; } @@ -1927,14 +1926,14 @@ static int depca_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) tmp.addr[i] = dev->dev_addr[i]; } ioc->len = ETH_ALEN; - if (verify_area(VERIFY_WRITE, (void *)ioc->data, ioc->len)) return -EFAULT; - copy_to_user(ioc->data, tmp.addr, ioc->len); + if (copy_to_user(ioc->data, tmp.addr, ioc->len)) + return -EFAULT; break; case DEPCA_SET_HWADDR: /* Set the hardware address */ if (!capable(CAP_NET_ADMIN)) return -EPERM; - if (verify_area(VERIFY_READ, (void *)ioc->data, ETH_ALEN)) return -EFAULT; - copy_from_user(tmp.addr,ioc->data,ETH_ALEN); + if (copy_from_user(tmp.addr, ioc->data, ETH_ALEN)) + return -EFAULT; for (i=0; i<ETH_ALEN; i++) { dev->dev_addr[i] = tmp.addr[i]; } @@ -1982,14 +1981,14 @@ static int depca_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) case DEPCA_GET_MCA: /* Get the multicast address table */ ioc->len = (HASH_TABLE_LEN >> 3); - if (verify_area(VERIFY_WRITE, ioc->data, ioc->len)) return -EFAULT; - copy_to_user(ioc->data, lp->init_block.mcast_table, ioc->len); + if (copy_to_user(ioc->data, lp->init_block.mcast_table, ioc->len)) + return -EFAULT; break; case DEPCA_SET_MCA: /* Set a multicast address */ if (!capable(CAP_NET_ADMIN)) return -EPERM; - if (verify_area(VERIFY_READ, ioc->data, ETH_ALEN*ioc->len)) return -EFAULT; - copy_from_user(tmp.addr, ioc->data, ETH_ALEN * ioc->len); + if (copy_from_user(tmp.addr, ioc->data, ETH_ALEN * ioc->len)) + return -EFAULT; set_multicast_list(dev); break; @@ -2006,11 +2005,8 @@ static int depca_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) case DEPCA_GET_STATS: /* Get the driver statistics */ cli(); ioc->len = sizeof(lp->pktStats); - if (verify_area(VERIFY_WRITE, ioc->data, ioc->len)) { - status = -EFAULT; - } else { - copy_to_user(ioc->data, &lp->pktStats, ioc->len); - } + if (copy_to_user(ioc->data, &lp->pktStats, ioc->len)) + status = -EFAULT; sti(); break; @@ -2028,8 +2024,8 @@ static int depca_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) tmp.sval[i++] = inw(DEPCA_DATA); memcpy(&tmp.sval[i], &lp->init_block, sizeof(struct depca_init)); ioc->len = i+sizeof(struct depca_init); - if (verify_area(VERIFY_WRITE, ioc->data, ioc->len)) return -EFAULT; - copy_to_user(ioc->data, tmp.addr, ioc->len); + if (copy_to_user(ioc->data, tmp.addr, ioc->len)) + return -EFAULT; break; default: @@ -2040,13 +2036,7 @@ static int depca_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) } #ifdef MODULE -static struct net_device thisDepca = { - "", /* device name is inserted by /linux/drivers/net/net_init.c */ - 0, 0, 0, 0, - 0x200, 7, /* I/O address, IRQ */ - 0, 0, 0, NULL, depca_probe -}; - +static struct net_device thisDepca; static int irq=7; /* EDIT THESE LINE FOR YOUR CONFIGURATION */ static int io=0x200; /* Or use the irq= io= options to insmod */ MODULE_PARM(irq, "i"); @@ -2058,6 +2048,7 @@ init_module(void) { thisDepca.irq=irq; thisDepca.base_addr=io; + thisDepca.init = depca_probe; if (register_netdev(&thisDepca) != 0) return -EIO; diff --git a/drivers/net/dgrs.c b/drivers/net/dgrs.c index 30d786cd6..86adecdc6 100644 --- a/drivers/net/dgrs.c +++ b/drivers/net/dgrs.c @@ -71,49 +71,40 @@ * into the kernel. * - Better handling of multicast addresses. * + * Fixes: + * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 11/01/2001 + * - fix dgrs_found_device wrt checking kmalloc return and + * rollbacking the partial steps of the whole process when + * one of the devices can't be allocated. Fix SET_MODULE_OWNER + * on the loop to use devN instead of repeated calls to dev. + * + * davej <davej@suse.de> - 9/2/2001 + * - Enable PCI device before reading ioaddr/irq + * */ -static char *version = "$Id: dgrs.c,v 1.13 2000/06/06 04:07:00 rick Exp $"; - -#include <linux/version.h> #include <linux/module.h> - #include <linux/kernel.h> #include <linux/sched.h> #include <linux/string.h> #include <linux/delay.h> #include <linux/errno.h> #include <linux/ioport.h> -#include <linux/malloc.h> +#include <linux/slab.h> #include <linux/interrupt.h> #include <linux/pci.h> #include <linux/init.h> -#include <asm/bitops.h> -#include <asm/io.h> -#include <asm/byteorder.h> - #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/skbuff.h> -#include <linux/types.h> +#include <asm/bitops.h> +#include <asm/io.h> +#include <asm/byteorder.h> +#include <asm/uaccess.h> -/* - * API changed at linux version 2.1.0 - */ -#if LINUX_VERSION_CODE >= 0x20100 - #include <asm/uaccess.h> - #define IOREMAP(ADDR, LEN) ioremap(ADDR, LEN) - #define IOUNMAP(ADDR) iounmap(ADDR) - #define COPY_FROM_USER(DST,SRC,LEN) copy_from_user(DST,SRC,LEN) - #define COPY_TO_USER(DST,SRC,LEN) copy_to_user(DST,SRC,LEN) -#else - #include <linux/bios32.h> - #define IOREMAP(ADDR, LEN) vremap(ADDR, LEN) - #define IOUNMAP(ADDR) vfree(ADDR) - #define COPY_FROM_USER(DST,SRC,LEN) memcpy_fromfs(DST,SRC,LEN) - #define COPY_TO_USER(DST,SRC,LEN) memcpy_tofs(DST,SRC,LEN) -#endif +static char version[] __initdata = + "$Id: dgrs.c,v 1.13 2000/06/06 04:07:00 rick Exp $"; /* * DGRS include files @@ -130,13 +121,11 @@ typedef unsigned int bool; #include "dgrs_asstruct.h" #include "dgrs_bcomm.h" -#if LINUX_VERSION_CODE >= 0x20400 static struct pci_device_id dgrs_pci_tbl[] __initdata = { { SE6_PCI_VENDOR_ID, SE6_PCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(pci, dgrs_pci_tbl); -#endif /* LINUX_VERSION_CODE >= 0x20400 */ /* * Firmware. Compiled separately for local compilation, @@ -178,19 +167,19 @@ MODULE_DEVICE_TABLE(pci, dgrs_pci_tbl); * "Space.c" variables, now settable from module interface * Use the name below, minus the "dgrs_" prefix. See init_module(). */ -int dgrs_debug = 1; -int dgrs_dma = 1; -int dgrs_spantree = -1; -int dgrs_hashexpire = -1; -uchar dgrs_ipaddr[4] = { 0xff, 0xff, 0xff, 0xff}; -uchar dgrs_iptrap[4] = { 0xff, 0xff, 0xff, 0xff}; -__u32 dgrs_ipxnet = -1; -int dgrs_nicmode = 0; +static int dgrs_debug = 1; +static int dgrs_dma = 1; +static int dgrs_spantree = -1; +static int dgrs_hashexpire = -1; +static uchar dgrs_ipaddr[4] = { 0xff, 0xff, 0xff, 0xff}; +static uchar dgrs_iptrap[4] = { 0xff, 0xff, 0xff, 0xff}; +static __u32 dgrs_ipxnet = -1; +static int dgrs_nicmode = 0; /* * Chain of device structures */ -static struct net_device *dgrs_root_dev = NULL; +static struct net_device *dgrs_root_dev; /* * Private per-board data structure (dev->priv) @@ -316,7 +305,7 @@ check_board_dma(struct net_device *dev0) /* * Now map the DMA registers into our virtual space */ - priv0->vplxdma = (ulong *) IOREMAP (priv0->plxdma, 256); + priv0->vplxdma = (ulong *) ioremap (priv0->plxdma, 256); if (!priv0->vplxdma) { printk("%s: can't *remap() the DMA regs\n", dev0->name); @@ -843,7 +832,7 @@ static int dgrs_ioctl(struct net_device *devN, struct ifreq *ifr, int cmd) if (cmd != DGRSIOCTL) return -EINVAL; - if(COPY_FROM_USER(&ioc, ifr->ifr_data, sizeof(DGRS_IOCTL))) + if(copy_from_user(&ioc, ifr->ifr_data, sizeof(DGRS_IOCTL))) return -EFAULT; switch (ioc.cmd) @@ -851,7 +840,7 @@ static int dgrs_ioctl(struct net_device *devN, struct ifreq *ifr, int cmd) case DGRS_GETMEM: if (ioc.len != sizeof(ulong)) return -EINVAL; - if(COPY_TO_USER(ioc.data, &devN->mem_start, ioc.len)) + if(copy_to_user(ioc.data, &devN->mem_start, ioc.len)) return -EFAULT; return (0); case DGRS_SETFILTER: @@ -880,7 +869,7 @@ static int dgrs_ioctl(struct net_device *devN, struct ifreq *ifr, int cmd) if (ioc.len) { - if(COPY_FROM_USER(S2HN(privN->bcomm->bc_filter_area), + if(copy_from_user(S2HN(privN->bcomm->bc_filter_area), ioc.data, ioc.len)) return -EFAULT; privN->bcomm->bc_filter_cmd = BC_FILTER_SET; @@ -1003,7 +992,7 @@ dgrs_download(struct net_device *dev0) /* * Map in the dual port memory */ - priv0->vmem = IOREMAP(dev0->mem_start, 2048*1024); + priv0->vmem = ioremap(dev0->mem_start, 2048*1024); if (!priv0->vmem) { printk("%s: cannot map in board memory\n", dev0->name); @@ -1050,7 +1039,7 @@ dgrs_download(struct net_device *dev0) memcpy(priv0->vmem, dgrs_code, dgrs_ncode); /* Load code */ if (memcmp(priv0->vmem, dgrs_code, dgrs_ncode)) { - IOUNMAP(priv0->vmem); + iounmap(priv0->vmem); priv0->vmem = NULL; printk("%s: download compare failed\n", dev0->name); return -ENXIO; @@ -1249,13 +1238,17 @@ dgrs_found_device( ) { DGRS_PRIV *priv; - struct net_device *dev; + struct net_device *dev, *aux; /* Allocate and fill new device structure. */ int dev_size = sizeof(struct net_device) + sizeof(DGRS_PRIV); - int i; + int i, ret; dev = (struct net_device *) kmalloc(dev_size, GFP_KERNEL); + + if (!dev) + return -ENOMEM; + memset(dev, 0, dev_size); dev->priv = ((void *)dev) + sizeof(struct net_device); priv = (DGRS_PRIV *)dev->priv; @@ -1274,11 +1267,12 @@ dgrs_found_device( dev->init = dgrs_probe1; SET_MODULE_OWNER(dev); ether_setup(dev); - priv->next_dev = dgrs_root_dev; - dgrs_root_dev = dev; if (register_netdev(dev) != 0) return -EIO; + priv->next_dev = dgrs_root_dev; + dgrs_root_dev = dev; + if ( !dgrs_nicmode ) return (0); /* Switch mode, we are done */ @@ -1295,6 +1289,9 @@ dgrs_found_device( /* Allocate new dev and priv structures */ devN = (struct net_device *) kmalloc(dev_size, GFP_KERNEL); /* Make it an exact copy of dev[0]... */ + ret = -ENOMEM; + if (!devN) + goto fail; memcpy(devN, dev, dev_size); devN->priv = ((void *)devN) + sizeof(struct net_device); privN = (DGRS_PRIV *)devN->priv; @@ -1305,17 +1302,29 @@ dgrs_found_device( devN->irq = 0; /* ... and base MAC address off address of 1st port */ devN->dev_addr[5] += i; - privN->chan = i+1; - priv->devtbl[i] = devN; devN->init = dgrs_initclone; - SET_MODULE_OWNER(dev); + SET_MODULE_OWNER(devN); ether_setup(devN); + ret = -EIO; + if (register_netdev(devN)) { + kfree(devN); + goto fail; + } + privN->chan = i+1; + priv->devtbl[i] = devN; privN->next_dev = dgrs_root_dev; dgrs_root_dev = devN; - if (register_netdev(devN) != 0) - return -EIO; } - return (0); + return 0; +fail: aux = priv->next_dev; + while (dgrs_root_dev != aux) { + struct net_device *d = dgrs_root_dev; + + dgrs_root_dev = ((DGRS_PRIV *)d->priv)->next_dev; + unregister_netdev(d); + kfree(d); + } + return ret; } /* @@ -1341,6 +1350,17 @@ static int __init dgrs_scan(void) while ((pdev = pci_find_device(SE6_PCI_VENDOR_ID, SE6_PCI_DEVICE_ID, pdev)) != NULL) { + /* + * Get and check the bus-master and latency values. + * Some PCI BIOSes fail to set the master-enable bit, + * and the latency timer must be set to the maximum + * value to avoid data corruption that occurs when the + * timer expires during a transfer. Yes, it's a bug. + */ + if (pci_enable_device(pdev)) + continue; + pci_set_master(pdev); + plxreg = pci_resource_start (pdev, 0); io = pci_resource_start (pdev, 1); mem = pci_resource_start (pdev, 2); @@ -1365,17 +1385,6 @@ static int __init dgrs_scan(void) pci_read_config_dword(pdev, 0x30, &plxdma); plxdma &= ~15; - /* - * Get and check the bus-master and latency values. - * Some PCI BIOSes fail to set the master-enable bit, - * and the latency timer must be set to the maximum - * value to avoid data corruption that occurs when the - * timer expires during a transfer. Yes, it's a bug. - */ - if (pci_enable_device(pdev)) - continue; - pci_set_master(pdev); - dgrs_found_device(io, mem, irq, plxreg, plxdma); cards_found++; @@ -1470,8 +1479,8 @@ static int __init dgrs_init_module (void) if (dgrs_debug) { - printk("dgrs: SW=%s FW=Build %d %s\n", - version, dgrs_firmnum, dgrs_firmdate); + printk(KERN_INFO "dgrs: SW=%s FW=Build %d %s\nFW Version=%s\n", + version, dgrs_firmnum, dgrs_firmdate, dgrs_firmver); } /* @@ -1497,9 +1506,9 @@ static void __exit dgrs_cleanup_module (void) proc_reset(priv->devtbl[0], 1); if (priv->vmem) - IOUNMAP(priv->vmem); + iounmap(priv->vmem); if (priv->vplxdma) - IOUNMAP((uchar *) priv->vplxdma); + iounmap((uchar *) priv->vplxdma); release_region(dgrs_root_dev->base_addr, 256); diff --git a/drivers/net/dgrs_firmware.c b/drivers/net/dgrs_firmware.c index 8641eadd8..1e49e1e1f 100644 --- a/drivers/net/dgrs_firmware.c +++ b/drivers/net/dgrs_firmware.c @@ -1,7 +1,7 @@ -int dgrs_firmnum = 550; -char dgrs_firmver[] = "$Version$"; -char dgrs_firmdate[] = "11/16/96 03:45:15"; -unsigned char dgrs_code[] __initdata = { +static int dgrs_firmnum = 550; +static char dgrs_firmver[] = "$Version$"; +static char dgrs_firmdate[] = "11/16/96 03:45:15"; +static unsigned char dgrs_code[] __initdata = { 213,5,192,8,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,64,40,35,41, @@ -9963,4 +9963,4 @@ unsigned char dgrs_code[] __initdata = { 109,46,99,0,114,99,0,0,48,120,0,0, 0,0,0,0,0,0,0,0,0,0,0,0 } ; -int dgrs_ncode = 119520 ; +static int dgrs_ncode = 119520 ; diff --git a/drivers/net/dmfe.c b/drivers/net/dmfe.c index a9de39fc7..68755b5fb 100644 --- a/drivers/net/dmfe.c +++ b/drivers/net/dmfe.c @@ -127,16 +127,17 @@ #define DMFE_100MFD 5 #define DMFE_AUTO 8 -#define DMFE_TIMER_WUT jiffies+(HZ*2)/2 /* timer wakeup time : 1 second */ +#define DMFE_TIMER_WUT (HZ) /* timer wakeup time : 1 second */ #define DMFE_TX_TIMEOUT ((HZ*3)/2) /* tx packet time-out time 1.5 s" */ -#define DMFE_DBUG(dbug_now, msg, vaule) if (dmfe_debug || dbug_now) printk("DBUG: %s %x\n", msg, vaule) +#define DMFE_DBUG(dbug_now, msg, value) \ + if (dmfe_debug || dbug_now) \ + printk("DBUG: %s %x\n", msg, value) -#define DELAY_5US udelay(5) /* udelay scale 1 usec */ - -#define DELAY_1US udelay(1) /* udelay scale 1 usec */ - -#define SHOW_MEDIA_TYPE(mode) printk(KERN_WARNING "dmfe: Change Speed to %sMhz %s duplex\n",mode & 1 ?"100":"10", mode & 4 ? "full":"half"); +#define SHOW_MEDIA_TYPE(mode) \ + printk(KERN_WARNING "dmfe: Change Speed to %sMhz %s duplex\n", \ + mode & 1 ? "100" : "10", \ + mode & 4 ? "full":"half"); /* CR9 definition: SROM/MII */ @@ -150,9 +151,17 @@ #define PHY_DATA_0 0x00000 #define MDCLKH 0x10000 -#define SROM_CLK_WRITE(data, ioaddr) outl(data|CR9_SROM_READ|CR9_SRCS,ioaddr);DELAY_5US;outl(data|CR9_SROM_READ|CR9_SRCS|CR9_SRCLK,ioaddr);DELAY_5US;outl(data|CR9_SROM_READ|CR9_SRCS,ioaddr);DELAY_5US; - -#define __CHK_IO_SIZE(pci_id, dev_rev) ( ((pci_id)==PCI_DM9132_ID) || ((dev_rev) >= 0x02000030) ) ? DM9102A_IO_SIZE: DM9102_IO_SIZE +#define SROM_CLK_WRITE(data, ioaddr) \ + outl(data | CR9_SROM_READ | CR9_SRCS , ioaddr); \ + udelay(5); \ + outl(data | CR9_SROM_READ | CR9_SRCS | CR9_SRCLK, ioaddr); \ + udelay(5); \ + outl(data | CR9_SROM_READ | CR9_SRCS , ioaddr); \ + udelay(5); + +#define __CHK_IO_SIZE(pci_id, dev_rev) \ + ( ((pci_id)==PCI_DM9132_ID) || ((dev_rev) >= 0x02000030) ) ? \ + DM9102A_IO_SIZE : DM9102_IO_SIZE #define CHK_IO_SIZE(pci_dev, dev_rev) \ __CHK_IO_SIZE(((pci_dev)->device << 16) | (pci_dev)->vendor, dev_rev) @@ -353,9 +362,19 @@ static int __init dmfe_init_one (struct pci_dev *pdev, int i; struct net_device *dev; u32 dev_rev; + u16 pci_command; DMFE_DBUG(0, "dmfe_probe()", 0); + /* Enable Master/IO access, Disable memory access */ + i = pci_enable_device(pdev); + if (i) return i; + + pci_set_master(pdev); + pci_read_config_word(pdev, PCI_COMMAND, &pci_command); + pci_command &= ~PCI_COMMAND_MEMORY; + pci_write_config_word(pdev, PCI_COMMAND, pci_command); + pci_iobase = pci_resource_start(pdev, 0); pci_irqline = pdev->irq; @@ -372,11 +391,6 @@ static int __init dmfe_init_one (struct pci_dev *pdev, goto err_out; } - /* Enable Master/IO access, Disable memory access */ - if (pci_enable_device(pdev)) - goto err_out; - pci_set_master(pdev); - #if 0 /* pci_{enable_device,set_master} sets minimum latency for us now */ /* Set Latency Timer 80h */ @@ -403,7 +417,7 @@ static int __init dmfe_init_one (struct pci_dev *pdev, } db = dev->priv; - pdev->driver_data = dev; + pci_set_drvdata(pdev, dev); db->chip_id = ent->driver_data; db->ioaddr = pci_iobase; @@ -440,7 +454,7 @@ err_out: static void __exit dmfe_remove_one (struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; + struct net_device *dev = pci_get_drvdata(pdev); struct dmfe_board_info *db; DMFE_DBUG(0, "dmfe_remove_one()", 0); @@ -451,6 +465,8 @@ static void __exit dmfe_remove_one (struct pci_dev *pdev) release_region(dev->base_addr, CHK_IO_SIZE(pdev, db->chip_revision)); kfree(dev); /* free board information */ + pci_set_drvdata(pdev, NULL); + DMFE_DBUG(0, "dmfe_remove_one() exit", 0); } @@ -511,12 +527,12 @@ static int dmfe_open(struct net_device *dev) db->dm910x_chk_mode = 1; /* Enter the check mode */ } - /* Initilize DM910X board */ + /* Initialize DM910X board */ dmfe_init_dm910x(dev); /* set and active a timer process */ init_timer(&db->timer); - db->timer.expires = DMFE_TIMER_WUT; + db->timer.expires = jiffies + DMFE_TIMER_WUT; db->timer.data = (unsigned long) dev; db->timer.function = &dmfe_timer; add_timer(&db->timer); @@ -526,9 +542,9 @@ static int dmfe_open(struct net_device *dev) return 0; } -/* Initilize DM910X board +/* Initialize DM910X board Reset DM910X board - Initilize TX/Rx descriptor chain structure + Initialize TX/Rx descriptor chain structure Send the set-up frame Enable Tx/Rx machine */ @@ -541,7 +557,7 @@ static void dmfe_init_dm910x(struct net_device *dev) /* Reset DM910x board : need 32 PCI clock to complete */ outl(DM910X_RESET, ioaddr + DCR0); /* RESET MAC */ - DELAY_5US; + udelay(5); outl(db->cr0_data, ioaddr + DCR0); outl(0x180, ioaddr + DCR12); /* Let bit 7 output port */ @@ -559,7 +575,7 @@ static void dmfe_init_dm910x(struct net_device *dev) db->op_mode = db->media_mode; dmfe_process_mode(db); - /* Initiliaze Transmit/Receive decriptor and CR3/4 */ + /* Initialize Transmit/Receive decriptor and CR3/4 */ dmfe_descriptor_init(db, ioaddr); /* Init CR6 to program DM910x operation */ @@ -623,10 +639,10 @@ static int dmfe_start_xmit(struct sk_buff *skb, struct net_device *dev) if (db->tx_packet_cnt < TX_MAX_SEND_CNT) { txptr->tdes0 = 0x80000000; /* set owner bit to DM910X */ db->tx_packet_cnt++; /* Ready to send count */ - outl(0x1, dev->base_addr + DCR1); /* Issue Tx polling comand */ + outl(0x1, dev->base_addr + DCR1); /* Issue Tx polling command */ } else { db->tx_queue_cnt++; /* queue the tx packet */ - outl(0x1, dev->base_addr + DCR1); /* Issue Tx polling comand */ + outl(0x1, dev->base_addr + DCR1); /* Issue Tx polling command */ } /* Tx resource check */ @@ -654,7 +670,7 @@ static int dmfe_stop(struct net_device *dev) /* Reset & stop DM910X board */ outl(DM910X_RESET, ioaddr + DCR0); - DELAY_5US; + udelay(5); /* deleted timer */ del_timer_sync(&db->timer); @@ -673,7 +689,7 @@ static int dmfe_stop(struct net_device *dev) } /* - DM9102 insterrupt handler + DM9102 interrupt handler receive the packet to upper layer, free the transmitted packet */ @@ -935,7 +951,7 @@ static void dmfe_timer(unsigned long data) */ DMFE_DBUG(0, "Warn!! Warn!! Tx/Rx moniotr step1", db->tx_packet_cnt); dmfe_dynamic_reset(dev); - db->timer.expires = DMFE_TIMER_WUT; + db->timer.expires = jiffies + DMFE_TIMER_WUT; add_timer(&db->timer); return; } @@ -990,7 +1006,7 @@ static void dmfe_timer(unsigned long data) allocated_rx_buffer(db); /* Timer active again */ - db->timer.expires = DMFE_TIMER_WUT; + db->timer.expires = jiffies + DMFE_TIMER_WUT; add_timer(&db->timer); } @@ -999,7 +1015,7 @@ static void dmfe_timer(unsigned long data) Stop DM910X board Free Tx/Rx allocated memory Reset DM910X board - Re-initilize DM910X board + Re-initialize DM910X board */ static void dmfe_dynamic_reset(struct net_device *dev) { @@ -1027,7 +1043,7 @@ static void dmfe_dynamic_reset(struct net_device *dev) db->wait_reset = 0; db->rx_error_cnt = 0; - /* Re-initilize DM910X board */ + /* Re-initialize DM910X board */ dmfe_init_dm910x(dev); /* Leave dynamic reser route */ @@ -1123,7 +1139,7 @@ static void dmfe_descriptor_init(struct dmfe_board_info *db, u32 ioaddr) } /* - Update CR6 vaule + Update CR6 value Firstly stop DM910X , then written value and start */ static void update_cr6(u32 cr6_data, u32 ioaddr) @@ -1132,14 +1148,14 @@ static void update_cr6(u32 cr6_data, u32 ioaddr) cr6_tmp = cr6_data & ~0x2002; /* stop Tx/Rx */ outl(cr6_tmp, ioaddr + DCR6); - DELAY_5US; + udelay(5); outl(cr6_data, ioaddr + DCR6); cr6_tmp = inl(ioaddr + DCR6); /* printk("CR6 update %x ", cr6_tmp); */ } /* Send a setup frame for DM9132 - This setup frame initilize DM910X addres filter mode + This setup frame initialize DM910X address filter mode */ static void dm9132_id_table(struct net_device *dev, int mc_cnt) { @@ -1180,7 +1196,7 @@ static void dm9132_id_table(struct net_device *dev, int mc_cnt) } /* Send a setup frame for DM9102/DM9102A - This setup frame initilize DM910X addres filter mode + This setup frame initialize DM910X address filter mode */ static void send_filter_frame(struct net_device *dev, int mc_cnt) { @@ -1288,10 +1304,10 @@ static u16 read_srom_word(long ioaddr, int offset) for (i = 16; i > 0; i--) { outl(CR9_SROM_READ | CR9_SRCS | CR9_SRCLK, cr9_ioaddr); - DELAY_5US; + udelay(5); srom_data = (srom_data << 1) | ((inl(cr9_ioaddr) & CR9_CRDOUT) ? 1 : 0); outl(CR9_SROM_READ | CR9_SRCS, cr9_ioaddr); - DELAY_5US; + udelay(5); } outl(CR9_SROM_READ, cr9_ioaddr); @@ -1305,10 +1321,10 @@ static u16 read_srom_word(long ioaddr, int offset) static void dmfe_sense_speed(struct dmfe_board_info *db) { int i; - u16 phy_mode; + u16 phy_mode = 0; for (i = 1000; i; i--) { - DELAY_5US; + udelay(5); phy_mode = phy_read(db->ioaddr, db->phy_addr, 1, db->chip_id); if ((phy_mode & 0x24) == 0x24) break; @@ -1429,11 +1445,11 @@ static void phy_write(u32 iobase, u8 phy_addr, u8 offset, u16 phy_data, u32 chip phy_write_1bit(ioaddr, PHY_DATA_0); phy_write_1bit(ioaddr, PHY_DATA_1); - /* Send Phy addres */ + /* Send Phy address */ for (i = 0x10; i > 0; i = i >> 1) phy_write_1bit(ioaddr, phy_addr & i ? PHY_DATA_1 : PHY_DATA_0); - /* Send register addres */ + /* Send register address */ for (i = 0x10; i > 0; i = i >> 1) phy_write_1bit(ioaddr, offset & i ? PHY_DATA_1 : PHY_DATA_0); @@ -1476,11 +1492,11 @@ static u16 phy_read(u32 iobase, u8 phy_addr, u8 offset, u32 chip_id) phy_write_1bit(ioaddr, PHY_DATA_1); phy_write_1bit(ioaddr, PHY_DATA_0); - /* Send Phy addres */ + /* Send Phy address */ for (i = 0x10; i > 0; i = i >> 1) phy_write_1bit(ioaddr, phy_addr & i ? PHY_DATA_1 : PHY_DATA_0); - /* Send register addres */ + /* Send register address */ for (i = 0x10; i > 0; i = i >> 1) phy_write_1bit(ioaddr, offset & i ? PHY_DATA_1 : PHY_DATA_0); @@ -1503,11 +1519,11 @@ static u16 phy_read(u32 iobase, u8 phy_addr, u8 offset, u32 chip_id) static void phy_write_1bit(u32 ioaddr, u32 phy_data) { outl(phy_data, ioaddr); /* MII Clock Low */ - DELAY_1US; + udelay(1); outl(phy_data | MDCLKH, ioaddr); /* MII Clock High */ - DELAY_1US; + udelay(1); outl(phy_data, ioaddr); /* MII Clock Low */ - DELAY_1US; + udelay(1); } /* @@ -1518,10 +1534,10 @@ static u16 phy_read_1bit(u32 ioaddr) u16 phy_data; outl(0x50000, ioaddr); - DELAY_1US; + udelay(1); phy_data = (inl(ioaddr) >> 19) & 0x1; outl(0x40000, ioaddr); - DELAY_1US; + udelay(1); return phy_data; } @@ -1570,7 +1586,7 @@ MODULE_PARM(chkmode, "i"); /* Description: * when user used insmod to add module, system invoked init_module() - * to initilize and register. + * to initialize and register. */ static int __init dmfe_init_module(void) @@ -1599,12 +1615,10 @@ static int __init dmfe_init_module(void) rc = pci_module_init(&dmfe_driver); if (rc < 0) return rc; - if (rc >= 0) { - printk (KERN_INFO "Davicom DM91xx net driver loaded, version " - DMFE_VERSION "\n"); - return 0; - } - return -ENODEV; + + printk (KERN_INFO "Davicom DM91xx net driver loaded, version " + DMFE_VERSION "\n"); + return 0; } /* diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c index c201b202b..ff4da62ce 100644 --- a/drivers/net/eepro.c +++ b/drivers/net/eepro.c @@ -23,6 +23,7 @@ This is a compatibility hardware problem. Versions: + 0.12c fixing some problems with old cards (aris, 01/08/2001) 0.12b misc fixes (aris, 06/26/2000) 0.12a port of version 0.12a of 2.2.x kernels to 2.3.x (aris (aris@conectiva.com.br), 05/19/2000) @@ -96,7 +97,7 @@ */ static const char *version = - "eepro.c: v0.12b 04/26/2000 aris@conectiva.com.br\n"; + "eepro.c: v0.12c 01/08/2000 aris@conectiva.com.br\n"; #include <linux/module.h> @@ -501,8 +502,10 @@ static unsigned eeprom_reg = EEPROM_REG_PRO; /* set diagnose flag */ #define eepro_diag(ioaddr) outb(DIAGNOSE_CMD, ioaddr) +#ifdef ANSWER_TX_AND_RX /* experimental way of handling interrupts */ /* ack for rx/tx int */ #define eepro_ack_rxtx(ioaddr) outb (RX_INT | TX_INT, ioaddr + STATUS_REG) +#endif /* ack for rx int */ #define eepro_ack_rx(ioaddr) outb (RX_INT, ioaddr + STATUS_REG) @@ -585,7 +588,7 @@ int __init eepro_probe(struct net_device *dev) return -ENODEV; } -void printEEPROMInfo(short ioaddr, struct net_device *dev) +static void printEEPROMInfo(short ioaddr, struct net_device *dev) { unsigned short Word; int i,j; @@ -776,7 +779,8 @@ static int eepro_probe1(struct net_device *dev, short ioaddr) } if (dev->irq < 2) { printk(" Duh! illegal interrupt vector stored in EEPROM.\n"); - return -ENODEV; + kfree(dev->priv); + return -ENODEV; } else if (dev->irq==2) @@ -950,6 +954,7 @@ static int eepro_open(struct net_device *dev) || (irq2dev_map[dev->irq] = dev) == 0) && (irq2dev_map[dev->irq]!=dev)) { /* printk("%s: IRQ map wrong\n", dev->name); */ + free_irq(dev->irq, dev); return -EAGAIN; } #endif @@ -1067,6 +1072,8 @@ static int eepro_open(struct net_device *dev) } eepro_sel_reset(ioaddr); + SLOW_DOWN; + SLOW_DOWN; lp->tx_start = lp->tx_end = XMT_LOWER_LIMIT << 8; lp->tx_last = 0; @@ -1162,9 +1169,11 @@ eepro_interrupt(int irq, void *dev_id, struct pt_regs * regs) while (((status = inb(ioaddr + STATUS_REG)) & 0x06) && (boguscount--)) { switch (status & (RX_INT | TX_INT)) { +#ifdef ANSWER_TX_AND_RX case (RX_INT | TX_INT): eepro_ack_rxtx(ioaddr); break; +#endif case RX_INT: eepro_ack_rx(ioaddr); break; @@ -1178,6 +1187,9 @@ eepro_interrupt(int irq, void *dev_id, struct pt_regs * regs) /* Get the received packets */ eepro_rx(dev); +#ifndef ANSWER_TX_AND_RX + continue; +#endif } if (status & TX_INT) { if (net_debug > 4) @@ -1367,7 +1379,11 @@ set_multicast_list(struct net_device *dev) /* Re-enable RX and TX interrupts */ eepro_en_int(ioaddr); } - eepro_complete_selreset(ioaddr); + if (lp->eepro == LAN595FX_10ISA) { + eepro_complete_selreset(ioaddr); + } + else + eepro_en_rx(ioaddr); } /* The horrible routine to read a word from the serial EEPROM. */ @@ -1535,7 +1551,9 @@ hardware_send_packet(struct net_device *dev, void *buf, short length) printk(KERN_DEBUG "%s: exiting hardware_send_packet routine.\n", dev->name); return; } - netif_stop_queue(dev); + if (lp->eepro == LAN595FX_10ISA) + netif_stop_queue(dev); + if (net_debug > 5) printk(KERN_DEBUG "%s: exiting hardware_send_packet routine.\n", dev->name); } @@ -1591,6 +1609,7 @@ eepro_rx(struct net_device *dev) skb->protocol = eth_type_trans(skb,dev); netif_rx(skb); + dev->last_rx = jiffies; lp->stats.rx_packets++; } @@ -1654,9 +1673,13 @@ eepro_transmit_interrupt(struct net_device *dev) xmt_status = inw(ioaddr+IO_PORT); if ((xmt_status & TX_DONE_BIT) == 0) { - udelay(40); - boguscount--; - continue; + if (lp->eepro == LAN595FX_10ISA) { + udelay(40); + boguscount--; + continue; + } + else + break; } xmt_status = inw(ioaddr+IO_PORT); @@ -1723,10 +1746,12 @@ eepro_transmit_interrupt(struct net_device *dev) * interrupt again for tx. in other words: tx timeout what will take * a lot of time to happen, so we'll do a complete selreset. */ - if (!boguscount) + if (!boguscount && lp->eepro == LAN595FX_10ISA) eepro_complete_selreset(ioaddr); } +#ifdef MODULE + #define MAX_EEPRO 8 static struct net_device dev_eepro[MAX_EEPRO]; @@ -1737,7 +1762,7 @@ static int mem[MAX_EEPRO] = { /* Size of the rx buffer in KB */ }; static int autodetect; -static int n_eepro = 0; +static int n_eepro; /* For linux 2.1.xx */ MODULE_AUTHOR("Pascal Dupuis <dupuis@lei.ucl.ac.be> for the 2.1 stuff (locking,...)"); @@ -1747,8 +1772,6 @@ MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_EEPRO) "i"); MODULE_PARM(mem, "1-" __MODULE_STRING(MAX_EEPRO) "i"); MODULE_PARM(autodetect, "1-" __MODULE_STRING(1) "i"); -#ifdef MODULE - int init_module(void) { diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c index 279093b61..bd46cb910 100644 --- a/drivers/net/eexpress.c +++ b/drivers/net/eexpress.c @@ -592,7 +592,7 @@ static void eexp_timeout(struct net_device *dev) status = scb_status(dev); unstick_cu(dev); - printk(KERN_INFO "%s: transmit timed out, %s?", dev->name, + printk(KERN_INFO "%s: transmit timed out, %s?\n", dev->name, (SCB_complete(status)?"lost interrupt": "board on fire")); lp->stats.tx_errors++; diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c index 557cc4029..fc004ca13 100644 --- a/drivers/net/epic100.c +++ b/drivers/net/epic100.c @@ -1,6 +1,6 @@ /* epic100.c: A SMC 83c170 EPIC/100 Fast Ethernet driver for Linux. */ /* - Written/copyright 1997-2000 by Donald Becker. + Written/copyright 1997-2001 by Donald Becker. This software may be used and distributed according to the terms of the GNU General Public License (GPL), incorporated herein by reference. @@ -37,15 +37,19 @@ * Fix locking (jgarzik) * Limit 83c175 probe to ethernet-class PCI devices (rgooch) + LK1.1.6: + * Merge becker version 1.11 + * Move pci_enable_device before any PCI BAR len checks + */ /* These identify the driver base version and may not be removed. */ static const char version[] = -"epic100.c:v1.09 5/29/2000 Written by Donald Becker <becker@scyld.com>\n"; +"epic100.c:v1.11 1/7/2001 Written by Donald Becker <becker@scyld.com>\n"; static const char version2[] = " http://www.scyld.com/network/epic100.html\n"; static const char version3[] = -" (unofficial 2.4.x kernel port, version 1.1.5, September 7, 2000)\n"; +" (unofficial 2.4.x kernel port, version 1.1.6, January 11, 2001)\n"; /* The user-configurable values. These may be modified when a driver module is loaded.*/ @@ -61,7 +65,7 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; /* Set the copy breakpoint for the copy-only-tiny-frames scheme. Setting to > 1518 effectively disables this feature. */ -static int rx_copybreak = 0; +static int rx_copybreak; /* Operational parameters that are set at compile time. */ @@ -73,6 +77,8 @@ static int rx_copybreak = 0; #define TX_RING_SIZE 16 #define TX_QUEUE_LEN 10 /* Limit ring entries actually used. */ #define RX_RING_SIZE 32 +#define TX_TOTAL_SIZE TX_RING_SIZE*sizeof(struct epic_tx_desc) +#define RX_TOTAL_SIZE RX_RING_SIZE*sizeof(struct epic_rx_desc) /* Operational parameters that usually are not changed. */ /* Time in jiffies before concluding the transmitter is hung. */ @@ -161,14 +167,13 @@ enum pci_id_flags_bits { enum chip_capability_flags { MII_PWRDWN=1, TYPE2_INTR=2, NO_MII=4 }; #define EPIC_TOTAL_SIZE 0x100 +#define USE_IO_OPS 1 #ifdef USE_IO_OPS #define EPIC_IOTYPE PCI_USES_MASTER|PCI_USES_IO|PCI_ADDR0 #else #define EPIC_IOTYPE PCI_USES_MASTER|PCI_USES_MEM|PCI_ADDR1 #endif -#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr)) - typedef enum { SMSC_83C170_0, SMSC_83C170, @@ -185,7 +190,7 @@ struct epic_chip_info { /* indexed by chip_t */ -static struct epic_chip_info epic_chip_info[] __devinitdata = { +static struct epic_chip_info pci_id_tbl[] = { { "SMSC EPIC/100 83c170", EPIC_IOTYPE, EPIC_TOTAL_SIZE, TYPE2_INTR | NO_MII | MII_PWRDWN }, { "SMSC EPIC/100 83c170", @@ -269,16 +274,18 @@ enum desc_status_bits { DescOwn=0x8000, }; - +#define PRIV_ALIGN 15 /* Required alignment mask */ struct epic_private { - /* Tx and Rx rings first so that they remain paragraph aligned. */ - struct epic_rx_desc rx_ring[RX_RING_SIZE]; - struct epic_tx_desc tx_ring[TX_RING_SIZE]; + struct epic_rx_desc *rx_ring; + struct epic_tx_desc *tx_ring; /* The saved address of a sent-in-place packet/buffer, for skfree(). */ struct sk_buff* tx_skbuff[TX_RING_SIZE]; /* The addresses of receive-in-place skbuffs. */ struct sk_buff* rx_skbuff[RX_RING_SIZE]; + dma_addr_t tx_ring_dma; + dma_addr_t rx_ring_dma; + /* Ring pointers. */ spinlock_t lock; /* Group with Tx control cache line. */ unsigned int cur_tx, dirty_tx; @@ -290,7 +297,7 @@ struct epic_private { long last_rx_time; /* Last Rx, in jiffies. */ struct pci_dev *pci_dev; /* PCI bus location. */ - int chip_flags; + int chip_id, chip_flags; struct net_device_stats stats; struct timer_list timer; /* Media selection timer. */ @@ -301,7 +308,7 @@ struct epic_private { int mii_phy_cnt; unsigned int tx_full:1; /* The Tx queue is full. */ unsigned int full_duplex:1; /* Current duplex setting. */ - unsigned int force_fd:1; /* Full-duplex operation requested. */ + unsigned int duplex_lock:1; /* Duplex forced by the user. */ unsigned int default_port:4; /* Last dev->if_port value. */ unsigned int media2:4; /* Secondary monitored media port. */ unsigned int medialock:1; /* Don't sense media type. */ @@ -310,8 +317,8 @@ struct epic_private { static int epic_open(struct net_device *dev); static int read_eeprom(long ioaddr, int location); -static int mdio_read(long ioaddr, int phy_id, int location); -static void mdio_write(long ioaddr, int phy_id, int location, int value); +static int mdio_read(struct net_device *dev, int phy_id, int location); +static void mdio_write(struct net_device *dev, int phy_id, int loc, int val); static void epic_restart(struct net_device *dev); static void epic_timer(unsigned long data); static void epic_tx_timeout(struct net_device *dev); @@ -330,13 +337,15 @@ static int __devinit epic_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { static int card_idx = -1; - static int printed_version = 0; + static int printed_version; + long ioaddr; + int chip_idx = (int) ent->driver_data; + int irq; struct net_device *dev; struct epic_private *ep; int i, option = 0, duplex = 0; - struct epic_chip_info *ci = &epic_chip_info[ent->driver_data]; - long ioaddr; - int chip_idx = (int) ent->driver_data; + void *ring_space; + dma_addr_t ring_dma; card_idx++; @@ -344,37 +353,27 @@ static int __devinit epic_init_one (struct pci_dev *pdev, printk (KERN_INFO "%s" KERN_INFO "%s" KERN_INFO "%s", version, version2, version3); - if ((pci_resource_len(pdev, 0) < ci->io_size) || - (pci_resource_len(pdev, 1) < ci->io_size)) { + i = pci_enable_device(pdev); + if (i) + return i; + irq = pdev->irq; + + if (pci_resource_len(pdev, 0) < pci_id_tbl[chip_idx].io_size) { printk (KERN_ERR "card %d: no PCI region space\n", card_idx); return -ENODEV; } - i = pci_enable_device(pdev); - if (i) - return i; - pci_set_master(pdev); - dev = init_etherdev(NULL, sizeof (*ep)); + dev = alloc_etherdev(sizeof (*ep)); if (!dev) { printk (KERN_ERR "card %d: no memory for eth device\n", card_idx); return -ENOMEM; } + SET_MODULE_OWNER(dev); - /* request 100% of both regions 0 and 1, just to make - * sure noone else steals our regions while we are talking - * to them */ - if (!request_region (pci_resource_start (pdev, 0), - pci_resource_len (pdev, 0), dev->name)) { - printk (KERN_ERR "epic100 %d: I/O region busy\n", card_idx); + if (pci_request_regions(pdev, "epic100")) goto err_out_free_netdev; - } - if (!request_mem_region (pci_resource_start (pdev, 1), - pci_resource_len (pdev, 1), dev->name)) { - printk (KERN_ERR "epic100 %d: I/O region busy\n", card_idx); - goto err_out_free_pio; - } #ifdef USE_IO_OPS ioaddr = pci_resource_start (pdev, 0); @@ -383,10 +382,25 @@ static int __devinit epic_init_one (struct pci_dev *pdev, ioaddr = (long) ioremap (ioaddr, pci_resource_len (pdev, 1)); if (!ioaddr) { printk (KERN_ERR "epic100 %d: ioremap failed\n", card_idx); - goto err_out_free_mmio; + goto err_out_free_res; } #endif + pci_set_drvdata(pdev, dev); + ep = dev->priv; + + ring_space = pci_alloc_consistent(pdev, TX_TOTAL_SIZE, &ring_dma); + if (!ring_space) + goto err_out_iounmap; + ep->tx_ring = (struct epic_tx_desc *)ring_space; + ep->tx_ring_dma = ring_dma; + + ring_space = pci_alloc_consistent(pdev, RX_TOTAL_SIZE, &ring_dma); + if (!ring_space) + goto err_out_unmap_tx; + ep->rx_ring = (struct epic_rx_desc *)ring_space; + ep->rx_ring_dma = ring_dma; + if (dev->mem_start) { option = dev->mem_start; duplex = (dev->mem_start & 16) ? 1 : 0; @@ -397,69 +411,62 @@ static int __devinit epic_init_one (struct pci_dev *pdev, duplex = full_duplex[card_idx]; } - pdev->driver_data = dev; - dev->base_addr = ioaddr; - dev->irq = pdev->irq; + dev->irq = irq; - ep = dev->priv; - ep->pci_dev = pdev; - ep->chip_flags = ci->drv_flags; spin_lock_init (&ep->lock); - printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", - dev->name, ci->name, ioaddr, dev->irq); - /* Bring the chip out of low-power mode. */ outl(0x4200, ioaddr + GENCTL); /* Magic?! If we don't set this bit the MII interface won't work. */ outl(0x0008, ioaddr + TEST1); /* Turn on the MII transceiver. */ - outl(0x12, ioaddr + MIICfg); + outl(dev->if_port == 1 ? 0x13 : 0x12, ioaddr + MIICfg); if (chip_idx == 1) outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL); outl(0x0200, ioaddr + GENCTL); - /* This could also be read from the EEPROM. */ + /* Note: the '175 does not have a serial EEPROM. */ for (i = 0; i < 3; i++) ((u16 *)dev->dev_addr)[i] = le16_to_cpu(inw(ioaddr + LAN0 + i*4)); - for (i = 0; i < 5; i++) - printk("%2.2x:", dev->dev_addr[i]); - printk("%2.2x.\n", dev->dev_addr[i]); - if (debug > 2) { - printk(KERN_DEBUG "%s: EEPROM contents\n", dev->name); + printk(KERN_DEBUG "epic100(%s): EEPROM contents\n", + pdev->slot_name); for (i = 0; i < 64; i++) printk(" %4.4x%s", read_eeprom(ioaddr, i), i % 16 == 15 ? "\n" : ""); } + ep->pci_dev = pdev; + ep->chip_id = chip_idx; + ep->chip_flags = pci_id_tbl[chip_idx].drv_flags; + /* Find the connected MII xcvrs. Doing this in open() would allow detecting external xcvrs later, but takes much time and no cards have external MII. */ { int phy, phy_idx = 0; for (phy = 1; phy < 32 && phy_idx < sizeof(ep->phys); phy++) { - int mii_status = mdio_read(ioaddr, phy, 1); + int mii_status = mdio_read(dev, phy, 1); if (mii_status != 0xffff && mii_status != 0x0000) { ep->phys[phy_idx++] = phy; - printk(KERN_INFO "%s: MII transceiver #%d control " + printk(KERN_INFO "epic100(%s): MII transceiver #%d control " "%4.4x status %4.4x.\n", - dev->name, phy, mdio_read(ioaddr, phy, 0), mii_status); + pdev->slot_name, phy, mdio_read(dev, phy, 0), mii_status); } } ep->mii_phy_cnt = phy_idx; if (phy_idx != 0) { phy = ep->phys[0]; - ep->advertising = mdio_read(ioaddr, phy, 4); - printk( KERN_INFO "%s: Autonegotiation advertising %4.4x link " - "partner %4.4x.\n", - dev->name, ep->advertising, mdio_read(ioaddr, phy, 5)); + ep->advertising = mdio_read(dev, phy, 4); + printk(KERN_INFO "epic100(%s): Autonegotiation advertising %4.4x link " + "partner %4.4x.\n", + pdev->slot_name, ep->advertising, mdio_read(dev, phy, 5)); } else if ( ! (ep->chip_flags & NO_MII)) { - printk(KERN_WARNING "%s: ***WARNING***: No MII transceiver found!\n", - dev->name); + printk(KERN_WARNING "epic100(%s): ***WARNING***: No MII transceiver found!\n", + pdev->slot_name); /* Use the known PHY address of the EPII. */ ep->phys[0] = 3; } @@ -471,7 +478,11 @@ static int __devinit epic_init_one (struct pci_dev *pdev, outl(0x0008, ioaddr + GENCTL); /* The lower four bits are the media type. */ - ep->force_fd = duplex; + if (duplex) { + ep->duplex_lock = ep->full_duplex = 1; + printk(KERN_INFO "epic100(%s): Forced full duplex operation requested.\n", + pdev->slot_name); + } dev->if_port = ep->default_port = option; if (ep->default_port) ep->medialock = 1; @@ -486,18 +497,27 @@ static int __devinit epic_init_one (struct pci_dev *pdev, dev->watchdog_timeo = TX_TIMEOUT; dev->tx_timeout = &epic_tx_timeout; + i = register_netdev(dev); + if (i) + goto err_out_unmap_tx; + + printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", + dev->name, pci_id_tbl[chip_idx].name, ioaddr, dev->irq); + for (i = 0; i < 5; i++) + printk("%2.2x:", dev->dev_addr[i]); + printk("%2.2x.\n", dev->dev_addr[i]); + return 0; +err_out_unmap_tx: + pci_free_consistent(pdev, TX_TOTAL_SIZE, ep->tx_ring, ep->tx_ring_dma); +err_out_iounmap: #ifndef USE_IO_OPS -err_out_free_mmio: - release_mem_region (pci_resource_start (pdev, 1), - pci_resource_len (pdev, 1)); + iounmap(ioaddr); +err_out_free_res: #endif -err_out_free_pio: - release_region (pci_resource_start (pdev, 0), - pci_resource_len (pdev, 0)); + pci_release_regions(pdev); err_out_free_netdev: - unregister_netdev(dev); kfree(dev); return -ENODEV; } @@ -514,7 +534,7 @@ err_out_free_netdev: #define EE_ENB (0x0001 | EE_CS) /* Delay between EEPROM clock transitions. - No extra delay is needed with 33Mhz PCI, but 66Mhz is untested. + This serves to flush the operation to the PCI bus. */ #define eeprom_delay() inl(ee_addr) @@ -561,25 +581,38 @@ static int read_eeprom(long ioaddr, int location) #define MII_READOP 1 #define MII_WRITEOP 2 -static int mdio_read(long ioaddr, int phy_id, int location) +static int mdio_read(struct net_device *dev, int phy_id, int location) { + long ioaddr = dev->base_addr; + int read_cmd = (phy_id << 9) | (location << 4) | MII_READOP; int i; - outl((phy_id << 9) | (location << 4) | MII_READOP, ioaddr + MIICtrl); - /* Typical operation takes < 50 ticks. */ - for (i = 4000; i > 0; i--) - if ((inl(ioaddr + MIICtrl) & MII_READOP) == 0) + outl(read_cmd, ioaddr + MIICtrl); + /* Typical operation takes 25 loops. */ + for (i = 400; i > 0; i--) { + barrier(); + if ((inl(ioaddr + MIICtrl) & MII_READOP) == 0) { + /* Work around read failure bug. */ + if (phy_id == 1 && location < 6 + && inw(ioaddr + MIIData) == 0xffff) { + outl(read_cmd, ioaddr + MIICtrl); + continue; + } return inw(ioaddr + MIIData); + } + } return 0xffff; } -static void mdio_write(long ioaddr, int phy_id, int location, int value) +static void mdio_write(struct net_device *dev, int phy_id, int loc, int value) { + long ioaddr = dev->base_addr; int i; outw(value, ioaddr + MIIData); - outl((phy_id << 9) | (location << 4) | MII_WRITEOP, ioaddr + MIICtrl); - for (i = 10000; i > 0; i--) { + outl((phy_id << 9) | (loc << 4) | MII_WRITEOP, ioaddr + MIICtrl); + for (i = 10000; i > 0; i--) { + barrier(); if ((inl(ioaddr + MIICtrl) & MII_WRITEOP) == 0) break; } @@ -589,27 +622,21 @@ static void mdio_write(long ioaddr, int phy_id, int location, int value) static int epic_open(struct net_device *dev) { - struct epic_private *ep = (struct epic_private *)dev->priv; + struct epic_private *ep = dev->priv; long ioaddr = dev->base_addr; int i; int retval; - ep->full_duplex = ep->force_fd; - /* Soft reset the chip. */ outl(0x4001, ioaddr + GENCTL); - MOD_INC_USE_COUNT; - - if ((retval = request_irq(dev->irq, &epic_interrupt, SA_SHIRQ, dev->name, dev))) { - MOD_DEC_USE_COUNT; + if ((retval = request_irq(dev->irq, &epic_interrupt, SA_SHIRQ, dev->name, dev))) return retval; - } epic_init_ring(dev); outl(0x4000, ioaddr + GENCTL); - /* This next magic! line by Ken Yamaguchi.. ?? */ + /* This magic is documented in SMSC app note 7.15 */ outl(0x0008, ioaddr + TEST1); /* Pull the chip out of low-power mode, enable interrupts, and set for @@ -617,7 +644,7 @@ static int epic_open(struct net_device *dev) required by the details of which bits are reset and the transceiver wiring on the Ositech CardBus card. */ - outl(0x12, ioaddr + MIICfg); + outl(dev->if_port == 1 ? 0x13 : 0x12, ioaddr + MIICfg); if (ep->chip_flags & MII_PWRDWN) outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL); @@ -639,21 +666,20 @@ static int epic_open(struct net_device *dev) if (media2miictl[dev->if_port & 15]) { if (ep->mii_phy_cnt) - mdio_write(ioaddr, ep->phys[0], 0, media2miictl[dev->if_port&15]); + mdio_write(dev, ep->phys[0], 0, media2miictl[dev->if_port&15]); if (dev->if_port == 1) { if (debug > 1) printk(KERN_INFO "%s: Using the 10base2 transceiver, MII " "status %4.4x.\n", - dev->name, mdio_read(ioaddr, ep->phys[0], 1)); - outl(0x13, ioaddr + MIICfg); + dev->name, mdio_read(dev, ep->phys[0], 1)); } } else { - int mii_reg5 = mdio_read(ioaddr, ep->phys[0], 5); + int mii_reg5 = mdio_read(dev, ep->phys[0], 5); if (mii_reg5 != 0xffff) { if ((mii_reg5 & 0x0100) || (mii_reg5 & 0x01C0) == 0x0040) ep->full_duplex = 1; else if (! (mii_reg5 & 0x4000)) - mdio_write(ioaddr, ep->phys[0], 0, 0x1200); + mdio_write(dev, ep->phys[0], 0, 0x1200); if (debug > 1) printk(KERN_INFO "%s: Setting %s-duplex based on MII xcvr %d" " register read of %4.4x.\n", dev->name, @@ -663,8 +689,8 @@ static int epic_open(struct net_device *dev) } outl(ep->full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl); - outl(virt_to_bus(ep->rx_ring), ioaddr + PRxCDAR); - outl(virt_to_bus(ep->tx_ring), ioaddr + PTxCDAR); + outl(ep->rx_ring_dma, ioaddr + PRxCDAR); + outl(ep->tx_ring_dma, ioaddr + PTxCDAR); /* Start the chip's Rx process. */ set_rx_mode(dev); @@ -700,7 +726,7 @@ static int epic_open(struct net_device *dev) static void epic_pause(struct net_device *dev) { long ioaddr = dev->base_addr; - struct epic_private *ep = (struct epic_private *)dev->priv; + struct epic_private *ep = dev->priv; netif_stop_queue (dev); @@ -723,17 +749,19 @@ static void epic_pause(struct net_device *dev) static void epic_restart(struct net_device *dev) { long ioaddr = dev->base_addr; - struct epic_private *ep = (struct epic_private *)dev->priv; + struct epic_private *ep = dev->priv; int i; - printk(KERN_DEBUG "%s: Restarting the EPIC chip, Rx %d/%d Tx %d/%d.\n", - dev->name, ep->cur_rx, ep->dirty_rx, ep->dirty_tx, ep->cur_tx); /* Soft reset the chip. */ - outl(0x0001, ioaddr + GENCTL); + outl(0x4001, ioaddr + GENCTL); + printk(KERN_DEBUG "%s: Restarting the EPIC chip, Rx %d/%d Tx %d/%d.\n", + dev->name, ep->cur_rx, ep->dirty_rx, ep->dirty_tx, ep->cur_tx); udelay(1); - /* Duplicate code from epic_open(). */ - outl(0x0008, ioaddr + TEST1); + + /* This magic is documented in SMSC app note 7.15 */ + for (i = 16; i > 0; i--) + outl(0x0008, ioaddr + TEST1); #if defined(__powerpc__) || defined(__sparc__) /* Big endian */ outl(0x0432 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL); @@ -750,9 +778,10 @@ static void epic_restart(struct net_device *dev) ep->tx_threshold = TX_FIFO_THRESH; outl(ep->tx_threshold, ioaddr + TxThresh); outl(ep->full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl); - outl(virt_to_bus(&ep->rx_ring[ep->cur_rx%RX_RING_SIZE]), ioaddr + PRxCDAR); - outl(virt_to_bus(&ep->tx_ring[ep->dirty_tx%TX_RING_SIZE]), - ioaddr + PTxCDAR); + outl(ep->rx_ring_dma + (ep->cur_rx%RX_RING_SIZE)* + sizeof(struct epic_rx_desc), ioaddr + PRxCDAR); + outl(ep->tx_ring_dma + (ep->dirty_tx%TX_RING_SIZE)* + sizeof(struct epic_tx_desc), ioaddr + PTxCDAR); /* Start the chip's Rx process. */ set_rx_mode(dev); @@ -770,16 +799,34 @@ static void epic_restart(struct net_device *dev) return; } -static void epic_timer(unsigned long data) +static void check_media(struct net_device *dev) { - struct net_device *dev = (struct net_device *)data; - struct epic_private *ep = (struct epic_private *)dev->priv; + struct epic_private *ep = dev->priv; long ioaddr = dev->base_addr; - int next_tick = 60*HZ; - int mii_reg5 = ep->mii_phy_cnt ? mdio_read(ioaddr, ep->phys[0], 5) : 0; + int mii_reg5 = ep->mii_phy_cnt ? mdio_read(dev, ep->phys[0], 5) : 0; int negotiated = mii_reg5 & ep->advertising; int duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040; + if (ep->duplex_lock) + return; + if (mii_reg5 == 0xffff) /* Bogus read */ + return; + if (ep->full_duplex != duplex) { + ep->full_duplex = duplex; + printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d link" + " partner capability of %4.4x.\n", dev->name, + ep->full_duplex ? "full" : "half", ep->phys[0], mii_reg5); + outl(ep->full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl); + } +} + +static void epic_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct epic_private *ep = dev->priv; + long ioaddr = dev->base_addr; + int next_tick = 5*HZ; + if (debug > 3) { printk(KERN_DEBUG "%s: Media monitor tick, Tx status %8.8x.\n", dev->name, (int)inl(ioaddr + TxSTAT)); @@ -789,15 +836,7 @@ static void epic_timer(unsigned long data) (int)inl(ioaddr + INTSTAT), (int)inl(ioaddr + RxSTAT)); } - if (! ep->force_fd) { - if (ep->full_duplex != duplex) { - ep->full_duplex = duplex; - printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d link" - " partner capability of %4.4x.\n", dev->name, - ep->full_duplex ? "full" : "half", ep->phys[0], mii_reg5); - outl(ep->full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl); - } - } + check_media(dev); ep->timer.expires = jiffies + next_tick; add_timer(&ep->timer); @@ -805,7 +844,7 @@ static void epic_timer(unsigned long data) static void epic_tx_timeout(struct net_device *dev) { - struct epic_private *ep = (struct epic_private *)dev->priv; + struct epic_private *ep = dev->priv; long ioaddr = dev->base_addr; if (debug > 0) { @@ -827,13 +866,14 @@ static void epic_tx_timeout(struct net_device *dev) dev->trans_start = jiffies; ep->stats.tx_errors++; - return; + if (!ep->tx_full) + netif_wake_queue(dev); } /* Initialize the Rx and Tx rings, along with various 'dev' bits. */ static void epic_init_ring(struct net_device *dev) { - struct epic_private *ep = (struct epic_private *)dev->priv; + struct epic_private *ep = dev->priv; int i; ep->tx_full = 0; @@ -847,11 +887,12 @@ static void epic_init_ring(struct net_device *dev) for (i = 0; i < RX_RING_SIZE; i++) { ep->rx_ring[i].rxstatus = 0; ep->rx_ring[i].buflength = cpu_to_le32(ep->rx_buf_sz); - ep->rx_ring[i].next = virt_to_le32desc(&ep->rx_ring[i+1]); + ep->rx_ring[i].next = ep->rx_ring_dma + + (i+1)*sizeof(struct epic_rx_desc); ep->rx_skbuff[i] = 0; } /* Mark the last entry as wrapping the ring. */ - ep->rx_ring[i-1].next = virt_to_le32desc(&ep->rx_ring[0]); + ep->rx_ring[i-1].next = ep->rx_ring_dma; /* Fill in the Rx buffers. Handle allocation failure gracefully. */ for (i = 0; i < RX_RING_SIZE; i++) { @@ -861,7 +902,8 @@ static void epic_init_ring(struct net_device *dev) break; skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* 16 byte align the IP header. */ - ep->rx_ring[i].bufaddr = virt_to_le32desc(skb->tail); + ep->rx_ring[i].bufaddr = pci_map_single(ep->pci_dev, + skb->tail, ep->rx_buf_sz, PCI_DMA_FROMDEVICE); ep->rx_ring[i].rxstatus = cpu_to_le32(DescOwn); } ep->dirty_rx = (unsigned int)(i - RX_RING_SIZE); @@ -871,29 +913,31 @@ static void epic_init_ring(struct net_device *dev) for (i = 0; i < TX_RING_SIZE; i++) { ep->tx_skbuff[i] = 0; ep->tx_ring[i].txstatus = 0x0000; - ep->tx_ring[i].next = virt_to_le32desc(&ep->tx_ring[i+1]); + ep->tx_ring[i].next = ep->tx_ring_dma + + (i+1)*sizeof(struct epic_tx_desc); } - ep->tx_ring[i-1].next = virt_to_le32desc(&ep->tx_ring[0]); + ep->tx_ring[i-1].next = ep->tx_ring_dma; return; } static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct epic_private *ep = (struct epic_private *)dev->priv; + struct epic_private *ep = dev->priv; int entry, free_count; u32 ctrl_word; + long flags; /* Caution: the write order is important here, set the field with the "ownership" bit last. */ - spin_lock_irq(&ep->lock); /* Calculate the next Tx descriptor entry. */ + spin_lock_irqsave(&ep->lock, flags); free_count = ep->cur_tx - ep->dirty_tx; entry = ep->cur_tx % TX_RING_SIZE; ep->tx_skbuff[entry] = skb; - ep->tx_ring[entry].bufaddr = virt_to_le32desc(skb->data); - + ep->tx_ring[entry].bufaddr = pci_map_single(ep->pci_dev, skb->data, + skb->len, PCI_DMA_TODEVICE); if (free_count < TX_QUEUE_LEN/2) {/* Typical path */ ctrl_word = cpu_to_le32(0x100000); /* No interrupt */ } else if (free_count == TX_QUEUE_LEN/2) { @@ -914,8 +958,7 @@ static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev) if (ep->tx_full) netif_stop_queue(dev); - spin_unlock_irq(&ep->lock); - + spin_unlock_irqrestore(&ep->lock, flags); /* Trigger an immediate transmit demand. */ outl(TxQueued, dev->base_addr + COMMAND); @@ -933,13 +976,11 @@ static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev) after the Tx thread. */ static void epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs) { - struct net_device *dev = (struct net_device *)dev_instance; - struct epic_private *ep = (struct epic_private *)dev->priv; + struct net_device *dev = dev_instance; + struct epic_private *ep = dev->priv; long ioaddr = dev->base_addr; int status, boguscnt = max_interrupt_work; - spin_lock(&ep->lock); - do { status = inl(ioaddr + INTSTAT); /* Acknowledge all of the current interrupt sources ASAP. */ @@ -962,9 +1003,11 @@ static void epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs) /* Note: if this lock becomes a problem we can narrow the locked region at the cost of occasionally grabbing the lock more times. */ + spin_lock(&ep->lock); cur_tx = ep->cur_tx; dirty_tx = ep->dirty_tx; for (; cur_tx - dirty_tx > 0; dirty_tx++) { + struct sk_buff *skb; int entry = dirty_tx % TX_RING_SIZE; int txstatus = le32_to_cpu(ep->tx_ring[entry].txstatus); @@ -975,7 +1018,7 @@ static void epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs) /* There was an major error, log it. */ #ifndef final_version if (debug > 1) - printk("%s: Transmit error, Tx status %8.8x.\n", + printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n", dev->name, txstatus); #endif ep->stats.tx_errors++; @@ -996,13 +1039,16 @@ static void epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs) } /* Free the original skb. */ - dev_kfree_skb_irq(ep->tx_skbuff[entry]); + skb = ep->tx_skbuff[entry]; + pci_unmap_single(ep->pci_dev, ep->tx_ring[entry].bufaddr, + skb->len, PCI_DMA_TODEVICE); + dev_kfree_skb_irq(skb); ep->tx_skbuff[entry] = 0; } #ifndef final_version if (cur_tx - dirty_tx > TX_RING_SIZE) { - printk("%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n", + printk(KERN_WARNING "%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n", dev->name, dirty_tx, cur_tx, ep->tx_full); dirty_tx += TX_RING_SIZE; } @@ -1010,10 +1056,12 @@ static void epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs) ep->dirty_tx = dirty_tx; if (ep->tx_full && cur_tx - dirty_tx < TX_QUEUE_LEN - 4) { - /* The ring is no longer full, clear tbusy. */ + /* The ring is no longer full, allow new TX entries. */ ep->tx_full = 0; + spin_unlock(&ep->lock); netif_wake_queue(dev); - } + } else + spin_unlock(&ep->lock); } /* Check uncommon events all at once. */ @@ -1060,12 +1108,12 @@ static void epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs) printk(KERN_DEBUG "%s: exiting interrupt, intr_status=%#4.4x.\n", dev->name, status); - spin_unlock(&ep->lock); + return; } static int epic_rx(struct net_device *dev) { - struct epic_private *ep = (struct epic_private *)dev->priv; + struct epic_private *ep = dev->priv; int entry = ep->cur_rx % RX_RING_SIZE; int rx_work_limit = ep->dirty_rx + RX_RING_SIZE - ep->cur_rx; int work_done = 0; @@ -1074,7 +1122,7 @@ static int epic_rx(struct net_device *dev) printk(KERN_DEBUG " In epic_rx(), entry %d %8.8x.\n", entry, ep->rx_ring[entry].rxstatus); /* If we own the next entry, it's a new packet. Send it up. */ - while (!(le32_to_cpu(ep->rx_ring[entry].rxstatus) & DescOwn)) { + while ((ep->rx_ring[entry].rxstatus & cpu_to_le32(DescOwn)) == 0) { int status = le32_to_cpu(ep->rx_ring[entry].rxstatus); if (debug > 4) @@ -1098,6 +1146,10 @@ static int epic_rx(struct net_device *dev) short pkt_len = (status >> 16) - 4; struct sk_buff *skb; + pci_dma_sync_single(ep->pci_dev, ep->rx_ring[entry].bufaddr, + ep->rx_buf_sz, PCI_DMA_FROMDEVICE); + pci_unmap_single(ep->pci_dev, ep->rx_ring[entry].bufaddr, + ep->rx_buf_sz, PCI_DMA_FROMDEVICE); if (pkt_len > PKT_BUF_SZ - 4) { printk(KERN_ERR "%s: Oversized Ethernet frame, status %x " "%d bytes.\n", @@ -1141,7 +1193,8 @@ static int epic_rx(struct net_device *dev) break; skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ - ep->rx_ring[entry].bufaddr = virt_to_le32desc(skb->tail); + ep->rx_ring[entry].bufaddr = pci_map_single(ep->pci_dev, + skb->tail, ep->rx_buf_sz, PCI_DMA_FROMDEVICE); work_done++; } ep->rx_ring[entry].rxstatus = cpu_to_le32(DescOwn); @@ -1152,7 +1205,8 @@ static int epic_rx(struct net_device *dev) static int epic_close(struct net_device *dev) { long ioaddr = dev->base_addr; - struct epic_private *ep = (struct epic_private *)dev->priv; + struct epic_private *ep = dev->priv; + struct sk_buff *skb; int i; netif_stop_queue(dev); @@ -1167,31 +1221,36 @@ static int epic_close(struct net_device *dev) /* Free all the skbuffs in the Rx queue. */ for (i = 0; i < RX_RING_SIZE; i++) { - struct sk_buff *skb = ep->rx_skbuff[i]; + skb = ep->rx_skbuff[i]; ep->rx_skbuff[i] = 0; ep->rx_ring[i].rxstatus = 0; /* Not owned by Epic chip. */ ep->rx_ring[i].buflength = 0; - ep->rx_ring[i].bufaddr = 0xBADF00D0; /* An invalid address. */ if (skb) { + pci_unmap_single(ep->pci_dev, ep->rx_ring[i].bufaddr, + ep->rx_buf_sz, PCI_DMA_FROMDEVICE); dev_kfree_skb(skb); } + ep->rx_ring[i].bufaddr = 0xBADF00D0; /* An invalid address. */ } for (i = 0; i < TX_RING_SIZE; i++) { - if (ep->tx_skbuff[i]) - dev_kfree_skb(ep->tx_skbuff[i]); + skb = ep->tx_skbuff[i]; ep->tx_skbuff[i] = 0; + if (!skb) + continue; + pci_unmap_single(ep->pci_dev, ep->tx_ring[i].bufaddr, + skb->len, PCI_DMA_TODEVICE); + dev_kfree_skb(skb); } /* Green! Leave the chip in low-power mode. */ outl(0x0008, ioaddr + GENCTL); - MOD_DEC_USE_COUNT; return 0; } static struct net_device_stats *epic_get_stats(struct net_device *dev) { - struct epic_private *ep = (struct epic_private *)dev->priv; + struct epic_private *ep = dev->priv; long ioaddr = dev->base_addr; if (netif_running(dev)) { @@ -1233,7 +1292,7 @@ static inline unsigned ether_crc_le(int length, unsigned char *data) static void set_rx_mode(struct net_device *dev) { long ioaddr = dev->base_addr; - struct epic_private *ep = (struct epic_private *)dev->priv; + struct epic_private *ep = dev->priv; unsigned char mc_filter[8]; /* Multicast hash filter */ int i; @@ -1271,25 +1330,26 @@ static void set_rx_mode(struct net_device *dev) static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { + struct epic_private *ep = dev->priv; long ioaddr = dev->base_addr; u16 *data = (u16 *)&rq->ifr_data; switch(cmd) { case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ - data[0] = ((struct epic_private *)dev->priv)->phys[0] & 0x1f; + data[0] = ep->phys[0] & 0x1f; /* Fall Through */ case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ if (! netif_running(dev)) { outl(0x0200, ioaddr + GENCTL); outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL); } - data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f); + data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f); +#if 0 /* Just leave on if the ioctl() is ever used. */ if (! netif_running(dev)) { -#ifdef notdef /* Leave on if the ioctl() is used. */ outl(0x0008, ioaddr + GENCTL); outl((inl(ioaddr + NVCTL) & ~0x483C) | 0x0000, ioaddr + NVCTL); -#endif } +#endif return 0; case SIOCDEVPRIVATE+2: /* Write the specified MII register */ if (!capable(CAP_NET_ADMIN)) @@ -1298,13 +1358,26 @@ static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) outl(0x0200, ioaddr + GENCTL); outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL); } - mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]); + if (data[0] == ep->phys[0]) { + u16 value = data[2]; + switch (data[1]) { + case 0: + /* Check for autonegotiation on or reset. */ + ep->duplex_lock = (value & 0x9000) ? 0 : 1; + if (ep->duplex_lock) + ep->full_duplex = (value & 0x0100) ? 1 : 0; + break; + case 4: ep->advertising = value; break; + } + /* Perhaps check_duplex(dev), depending on chip semantics. */ + } + mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]); +#if 0 /* Leave on if the ioctl() is used. */ if (! netif_running(dev)) { -#ifdef notdef /* Leave on if the ioctl() is used. */ outl(0x0008, ioaddr + GENCTL); outl((inl(ioaddr + NVCTL) & ~0x483C) | 0x0000, ioaddr + NVCTL); -#endif } +#endif return 0; default: return -EOPNOTSUPP; @@ -1314,36 +1387,44 @@ static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) static void __devexit epic_remove_one (struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; + struct net_device *dev = pci_get_drvdata(pdev); + struct epic_private *ep = dev->priv; + pci_free_consistent(pdev, TX_TOTAL_SIZE, ep->tx_ring, ep->tx_ring_dma); + pci_free_consistent(pdev, RX_TOTAL_SIZE, ep->rx_ring, ep->rx_ring_dma); unregister_netdev(dev); #ifndef USE_IO_OPS - iounmap ((void*) dev->base_addr); + iounmap((void*) dev->base_addr); #endif - release_mem_region (pci_resource_start (pdev, 1), - pci_resource_len (pdev, 1)); - release_region (pci_resource_start (pdev, 0), - pci_resource_len (pdev, 0)); + pci_release_regions(pdev); kfree(dev); + pci_set_drvdata(pdev, NULL); + /* pci_power_off(pdev, -1); */ } static void epic_suspend (struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; + struct net_device *dev = pci_get_drvdata(pdev); long ioaddr = dev->base_addr; + if (!netif_running(dev)) + return; epic_pause(dev); /* Put the chip into low-power mode. */ outl(0x0008, ioaddr + GENCTL); + /* pci_power_off(pdev, -1); */ } static void epic_resume (struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; + struct net_device *dev = pci_get_drvdata(pdev); - epic_restart (dev); + if (!netif_running(dev)) + return; + epic_restart(dev); + /* pci_power_on(pdev); */ } diff --git a/drivers/net/eql.c b/drivers/net/eql.c index 64fffabe6..78210f3f4 100644 --- a/drivers/net/eql.c +++ b/drivers/net/eql.c @@ -197,7 +197,7 @@ static void eql_timer(unsigned long param); /* */ static int __init eql_init(struct net_device *dev) { - static unsigned version_printed = 0; + static unsigned version_printed; /* static unsigned num_masters = 0; */ equalizer_t *eql = 0; @@ -721,6 +721,9 @@ static void eql_delete_slave_queue(slave_queue_t *queue) static int eql_insert_slave(slave_queue_t *queue, slave_t *slave) { + unsigned long flags; + + save_flags(flags); cli (); if ( ! eql_is_full (queue) ) @@ -736,10 +739,10 @@ static int eql_insert_slave(slave_queue_t *queue, slave_t *slave) slave->next = queue->head->next; queue->head->next = slave; queue->num_slaves++; - sti (); + restore_flags(flags); return 0; } - sti (); + restore_flags(flags); return 1; } @@ -748,7 +751,9 @@ static slave_t *eql_remove_slave(slave_queue_t *queue, slave_t *slave) { slave_t *prev; slave_t *curr; + unsigned long flags; + save_flags(flags); cli (); prev = queue->head; @@ -766,10 +771,10 @@ static slave_t *eql_remove_slave(slave_queue_t *queue, slave_t *slave) prev->next = curr->next; queue->num_slaves--; curr->dev->flags = curr->dev->flags & ~IFF_SLAVE; - sti(); + restore_flags(flags); return curr; } - sti (); + restore_flags(flags); return 0; /* not found */ } @@ -784,6 +789,9 @@ static int eql_remove_slave_dev(slave_queue_t *queue, struct net_device *dev) if (target != 0) { + unsigned long flags; + + save_flags(flags); cli (); prev = queue->head; curr = prev->next; @@ -794,7 +802,7 @@ static int eql_remove_slave_dev(slave_queue_t *queue, struct net_device *dev) } prev->next = curr->next; queue->num_slaves--; - sti (); + restore_flags(flags); eql_delete_slave (curr); return 0; } @@ -847,8 +855,10 @@ static inline void eql_schedule_slaves(slave_queue_t *queue) */ unsigned long best_load = (unsigned long) ULONG_MAX; slave_t *slave = 0; + unsigned long flags; int i; + save_flags(flags); cli (); for (i = 1, slave = eql_first_slave (queue); i <= eql_number_slaves (queue); @@ -895,7 +905,7 @@ static inline void eql_schedule_slaves(slave_queue_t *queue) } } } /* for */ - sti (); + restore_flags(flags); eql_set_best_slave (queue, best_slave); } /* else */ if (slave_corpse != 0) @@ -948,9 +958,11 @@ static void eql_timer(unsigned long param) slave_t *slave; slave_t *slave_corpse = 0; int i; + unsigned long flags; if ( ! eql_is_empty (eql->queue) ) { + save_flags(flags); cli (); for (i = 1, slave = eql_first_slave (eql->queue); i <= eql_number_slaves (eql->queue); @@ -968,7 +980,7 @@ static void eql_timer(unsigned long param) slave_corpse = slave; } } - sti (); + restore_flags(flags); if (slave_corpse != 0) { printk ("eql: timer found dead slave, burying...\n"); diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c index e239dbdf9..37e8d13d7 100644 --- a/drivers/net/eth16i.c +++ b/drivers/net/eth16i.c @@ -1195,10 +1195,6 @@ static void eth16i_rx(struct net_device *dev) } skb->protocol=eth_type_trans(skb, dev); - netif_rx(skb); - dev->last_rx = jiffies; - lp->stats.rx_packets++; - lp->stats.rx_bytes += pkt_len; if( eth16i_debug > 5 ) { int i; @@ -1208,6 +1204,10 @@ static void eth16i_rx(struct net_device *dev) printk(KERN_DEBUG " %02x", skb->data[i]); printk(KERN_DEBUG ".\n"); } + netif_rx(skb); + dev->last_rx = jiffies; + lp->stats.rx_packets++; + lp->stats.rx_bytes += pkt_len; } /* else */ diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c index 35510ec7c..d23839071 100644 --- a/drivers/net/ewrk3.c +++ b/drivers/net/ewrk3.c @@ -997,19 +997,6 @@ static int ewrk3_rx(struct net_device *dev) isa_memcpy_fromio(p, buf, pkt_len); } - /* - ** Notify the upper protocol layers that there is another - ** packet to handle - */ - skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); - - /* - ** Update stats - */ - dev->last_rx = jiffies; - lp->stats.rx_packets++; - lp->stats.rx_bytes += pkt_len; for (i = 1; i < EWRK3_PKT_STAT_SZ - 1; i++) { if (pkt_len < i * EWRK3_PKT_BIN_SZ) { lp->pktStats.bins[i]++; @@ -1031,6 +1018,19 @@ static int ewrk3_rx(struct net_device *dev) if (lp->pktStats.bins[0] == 0) { /* Reset counters */ memset(&lp->pktStats, 0, sizeof(lp->pktStats)); } + /* + ** Notify the upper protocol layers that there is another + ** packet to handle + */ + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); + + /* + ** Update stats + */ + dev->last_rx = jiffies; + lp->stats.rx_packets++; + lp->stats.rx_bytes += pkt_len; } else { printk("%s: Insufficient memory; nuking packet.\n", dev->name); lp->stats.rx_dropped++; /* Really, deferred. */ diff --git a/drivers/net/fc/iph5526.c b/drivers/net/fc/iph5526.c index be7779d19..153ce1cd6 100644 --- a/drivers/net/fc/iph5526.c +++ b/drivers/net/fc/iph5526.c @@ -1074,11 +1074,11 @@ int wrap_around = FALSE, no_of_wrap_buffs = NO_OF_ENTRIES - 1; fi->fc_stats.rx_dropped++; fi->g.mfs_buffer_count += no_of_buffers; if (fi->g.mfs_buffer_count >= NO_OF_ENTRIES) { - int count = fi->g.mfs_buffer_count / NO_OF_ENTRIES; + int count = fi->g.mfs_buffer_count / NO_OF_ENTRIES; fi->g.mfs_buffer_count -= NO_OF_ENTRIES * count; update_MFSBQ_indx(fi, count); - return; } + return; } if (wrap_around) { int wrap_size = no_of_wrap_buffs * MFS_BUFFER_SIZE; diff --git a/drivers/net/fmv18x.c b/drivers/net/fmv18x.c index ef2c2f69e..06e86b367 100644 --- a/drivers/net/fmv18x.c +++ b/drivers/net/fmv18x.c @@ -52,6 +52,7 @@ static const char *version = #include <asm/io.h> #include <asm/dma.h> #include <linux/errno.h> +#include <linux/spinlock.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> @@ -79,6 +80,7 @@ struct net_local { uint rx_started:1; /* Packets are Rxing. */ uchar tx_queue; /* Number of packet on the Tx queue. */ ushort tx_queue_len; /* Current length of the Tx queue. */ + spinlock_t lock; }; @@ -161,6 +163,7 @@ static int __init fmv18x_probe1(struct net_device *dev, short ioaddr) char irqmap[4] = {3, 7, 10, 15}; char irqmap_pnp[8] = {3, 4, 5, 7, 9, 10, 11, 15}; unsigned int i, irq, retval; + struct net_local *lp; /* Resetting the chip doesn't reset the ISA interface, so don't bother. That means we have to be careful with the register values we probe for. @@ -268,6 +271,8 @@ static int __init fmv18x_probe1(struct net_device *dev, short ioaddr) goto out_irq; } memset(dev->priv, 0, sizeof(struct net_local)); + lp = dev->priv; + spin_lock_init(&lp->lock); dev->open = net_open; dev->stop = net_close; @@ -292,7 +297,7 @@ out: static int net_open(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = dev->priv; int ioaddr = dev->base_addr; /* Set the configuration register 0 to 32K 100ns. byte-wide memory, @@ -326,7 +331,7 @@ static int net_open(struct net_device *dev) static void net_timeout(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = dev->priv; int ioaddr = dev->base_addr; unsigned long flags; @@ -346,8 +351,7 @@ static void net_timeout(struct net_device *dev) htons(inw(ioaddr+FJ_CONFIG0))); lp->stats.tx_errors++; /* ToDo: We should try to restart the adaptor... */ - save_flags(flags); - cli(); + spin_lock_irqsave(&lp->lock, flags); /* Initialize LAN Controller and LAN Card */ outb(0xda, ioaddr + CONFIG_0); /* Initialize LAN Controller */ @@ -355,20 +359,21 @@ static void net_timeout(struct net_device *dev) outb(0x00, ioaddr + FJ_CONFIG1); /* Disable IRQ of LAN Card */ outb(0x00, ioaddr + FJ_BUFCNTL); /* Reset ? I'm not sure */ net_open(dev); - restore_flags(flags); + spin_unlock_irqrestore(&lp->lock, flags); + + netif_wake_queue(dev); } static int net_send_packet(struct sk_buff *skb, struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = dev->priv; int ioaddr = dev->base_addr; short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; unsigned char *buf = skb->data; + unsigned long flags; /* Block a transmit from overlapping. */ - netif_stop_queue(dev); - if (length > ETH_FRAME_LEN) { if (net_debug) printk("%s: Attempting to send a large packet (%d bytes).\n", @@ -383,6 +388,7 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev) codes we possibly catch a Tx interrupt. Thus we flag off tx_queue_ready, so that we prevent the interrupt routine (net_interrupt) to start transmitting. */ + spin_lock_irqsave(&lp->lock, flags); lp->tx_queue_ready = 0; { outw(length, ioaddr + DATAPORT); @@ -391,6 +397,8 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev) lp->tx_queue_len += length + 2; } lp->tx_queue_ready = 1; + spin_unlock_irqrestore(&lp->lock, flags); + if (lp->tx_started == 0) { /* If the Tx is idle, always trigger a transmit. */ outb(0x80 | lp->tx_queue, ioaddr + TX_START); @@ -398,10 +406,10 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev) lp->tx_queue_len = 0; dev->trans_start = jiffies; lp->tx_started = 1; - netif_wake_queue(dev); } else if (lp->tx_queue_len < 4096 - 1502) /* Yes, there is room for one more packet. */ - netif_wake_queue(dev); + else + netif_stop_queue(dev); dev_kfree_skb(skb); return 0; @@ -417,7 +425,7 @@ net_interrupt(int irq, void *dev_id, struct pt_regs *regs) int ioaddr, status; ioaddr = dev->base_addr; - lp = (struct net_local *)dev->priv; + lp = dev->priv; status = inw(ioaddr + TX_STATUS); outw(status, ioaddr + TX_STATUS); @@ -447,6 +455,7 @@ net_interrupt(int irq, void *dev_id, struct pt_regs *regs) lp->stats.collisions++; } if (status & 0x82) { + spin_lock(&lp->lock); lp->stats.tx_packets++; if (lp->tx_queue && lp->tx_queue_ready) { outb(0x80 | lp->tx_queue, ioaddr + TX_START); @@ -458,6 +467,7 @@ net_interrupt(int irq, void *dev_id, struct pt_regs *regs) lp->tx_started = 0; netif_wake_queue(dev); /* Inform upper layers. */ } + spin_unlock(&lp->lock); } } return; @@ -466,7 +476,7 @@ net_interrupt(int irq, void *dev_id, struct pt_regs *regs) /* We have a good packet(s), get it/them out of the buffers. */ static void net_rx(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = dev->priv; int ioaddr = dev->base_addr; int boguscount = 5; @@ -581,7 +591,7 @@ static int net_close(struct net_device *dev) closed. */ static struct net_device_stats *net_get_stats(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = dev->priv; return &lp->stats; } diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c index 35fa12e0c..8997b8280 100644 --- a/drivers/net/hamachi.c +++ b/drivers/net/hamachi.c @@ -129,7 +129,6 @@ static int tx_params[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; * Enable mii_ioctl. Added interrupt coalescing parameter adjustment. * 2/19/99 Pete Wyckoff <wyckoff@ca.sandia.gov> */ -#define HAVE_PRIVATE_IOCTL /* play with 64-bit addrlen; seems to be a teensy bit slower --pw */ /* #define ADDRLEN 64 */ @@ -477,6 +476,7 @@ enum desc_status_bits { }; #define PRIV_ALIGN 15 /* Required alignment mask */ +#define MII_CNT 4 struct hamachi_private { /* Descriptor rings first for alignment. Tx requires a second descriptor for status. */ @@ -503,7 +503,7 @@ struct hamachi_private { /* MII transceiver section. */ int mii_cnt; /* MII device addresses. */ u16 advertising; /* NWay media advertisement */ - unsigned char phys[2]; /* MII device addresses. */ + unsigned char phys[MII_CNT]; /* MII device addresses, only first one used. */ u_int32_t rx_int_var, tx_int_var; /* interrupt control variables */ u_int32_t option; /* Hold on to a copy of the options */ u_int8_t pad[16]; /* Used for 32-byte alignment */ @@ -531,9 +531,7 @@ static int read_eeprom(long ioaddr, int location); static int mdio_read(long ioaddr, int phy_id, int location); static void mdio_write(long ioaddr, int phy_id, int location, int value); static int hamachi_open(struct net_device *dev); -#ifdef HAVE_PRIVATE_IOCTL static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -#endif static void hamachi_timer(unsigned long data); static void hamachi_tx_timeout(struct net_device *dev); static void hamachi_init_ring(struct net_device *dev); @@ -554,7 +552,7 @@ static int __init hamachi_init_one (struct pci_dev *pdev, struct hamachi_private *hmp; int option, i, rx_int_var, tx_int_var, boguscnt; int chip_id = ent->driver_data; - int irq = pdev->irq; + int irq; long ioaddr; static int card_idx = 0; struct net_device *dev; @@ -562,21 +560,29 @@ static int __init hamachi_init_one (struct pci_dev *pdev, if (hamachi_debug > 0 && did_version++ == 0) printk(version); + if (pci_enable_device(pdev)) + return -EIO; + ioaddr = pci_resource_start(pdev, 0); #ifdef __alpha__ /* Really "64 bit addrs" */ ioaddr |= (pci_resource_start(pdev, 1) << 32); #endif - if (pci_enable_device(pdev)) - return -EIO; pci_set_master(pdev); + i = pci_request_regions(pdev, "hamachi"); + if (i) return i; + + irq = pdev->irq; ioaddr = (long) ioremap(ioaddr, 0x400); - if (!ioaddr) + if (!ioaddr) { + pci_release_regions(pdev); return -ENOMEM; + } - dev = init_etherdev(NULL, sizeof(struct hamachi_private)); + dev = alloc_etherdev(sizeof(struct hamachi_private)); if (!dev) { + pci_release_regions(pdev); iounmap((char *)ioaddr); return -ENOMEM; } @@ -587,16 +593,9 @@ static int __init hamachi_init_one (struct pci_dev *pdev, dev->hard_header_len += 8; /* for cksum tag */ #endif - printk(KERN_INFO "%s: %s type %x at 0x%lx, ", - dev->name, chip_tbl[chip_id].name, readl(ioaddr + ChipRev), - ioaddr); - for (i = 0; i < 6; i++) dev->dev_addr[i] = 1 ? read_eeprom(ioaddr, 4 + i) : readb(ioaddr + StationAddr + i); - for (i = 0; i < 5; i++) - printk("%2.2x:", dev->dev_addr[i]); - printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); #if ! defined(final_version) if (hamachi_debug > 4) @@ -605,15 +604,6 @@ static int __init hamachi_init_one (struct pci_dev *pdev, read_eeprom(ioaddr, i), i % 16 != 15 ? " " : "\n"); #endif -#if 0 /* Moving this until after the force 32 check and reset. */ - i = readb(ioaddr + PCIClkMeas); - printk(KERN_INFO "%s: %d-bit %d Mhz PCI bus (%d), Virtual Jumpers " - "%2.2x, LPA %4.4x.\n", - dev->name, readw(ioaddr + MiscStatus) & 1 ? 64 : 32, - i ? 2000/(i&0x7f) : 0, i&0x7f, (int)readb(ioaddr + VirtualJumpers), - readw(ioaddr + ANLinkPartnerAbility)); -#endif - hmp = dev->priv; spin_lock_init(&hmp->lock); @@ -642,12 +632,6 @@ static int __init hamachi_init_one (struct pci_dev *pdev, i = readb(ioaddr + PCIClkMeas); } - printk(KERN_INFO "%s: %d-bit %d Mhz PCI bus (%d), Virtual Jumpers " - "%2.2x, LPA %4.4x.\n", - dev->name, readw(ioaddr + MiscStatus) & 1 ? 64 : 32, - i ? 2000/(i&0x7f) : 0, i&0x7f, (int)readb(ioaddr + VirtualJumpers), - readw(ioaddr + ANLinkPartnerAbility)); - dev->base_addr = ioaddr; dev->irq = irq; @@ -693,17 +677,36 @@ static int __init hamachi_init_one (struct pci_dev *pdev, dev->stop = &hamachi_close; dev->get_stats = &hamachi_get_stats; dev->set_multicast_list = &set_rx_mode; -#ifdef HAVE_PRIVATE_IOCTL dev->do_ioctl = &mii_ioctl; -#endif dev->tx_timeout = &hamachi_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; if (mtu) dev->mtu = mtu; + i = register_netdev(dev); + if (i) { + kfree(dev); + iounmap((char *)ioaddr); + pci_release_regions(pdev); + return i; + } + + printk(KERN_INFO "%s: %s type %x at 0x%lx, ", + dev->name, chip_tbl[chip_id].name, readl(ioaddr + ChipRev), + ioaddr); + for (i = 0; i < 5; i++) + printk("%2.2x:", dev->dev_addr[i]); + printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); + i = readb(ioaddr + PCIClkMeas); + printk(KERN_INFO "%s: %d-bit %d Mhz PCI bus (%d), Virtual Jumpers " + "%2.2x, LPA %4.4x.\n", + dev->name, readw(ioaddr + MiscStatus) & 1 ? 64 : 32, + i ? 2000/(i&0x7f) : 0, i&0x7f, (int)readb(ioaddr + VirtualJumpers), + readw(ioaddr + ANLinkPartnerAbility)); + if (chip_tbl[hmp->chip_id].flags & CanHaveMII) { int phy, phy_idx = 0; - for (phy = 0; phy < 32 && phy_idx < 4; phy++) { + for (phy = 0; phy < 32 && phy_idx < MII_CNT; phy++) { int mii_status = mdio_read(ioaddr, phy, 1); if (mii_status != 0xffff && mii_status != 0x0000) { @@ -782,7 +785,7 @@ static void mdio_write(long ioaddr, int phy_id, int location, int value) static int hamachi_open(struct net_device *dev) { - struct hamachi_private *hmp = (struct hamachi_private *)dev->priv; + struct hamachi_private *hmp = dev->priv; long ioaddr = dev->base_addr; int i; u_int32_t rx_int_var, tx_int_var; @@ -930,7 +933,7 @@ static int hamachi_open(struct net_device *dev) static inline int hamachi_tx(struct net_device *dev) { - struct hamachi_private *hmp = (struct hamachi_private *)dev->priv; + struct hamachi_private *hmp = dev->priv; /* Update the dirty pointer until we find an entry that is still owned by the card */ @@ -956,7 +959,7 @@ static inline int hamachi_tx(struct net_device *dev) static void hamachi_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; - struct hamachi_private *hmp = (struct hamachi_private *)dev->priv; + struct hamachi_private *hmp = dev->priv; long ioaddr = dev->base_addr; int next_tick = 10*HZ; @@ -981,7 +984,7 @@ static void hamachi_timer(unsigned long data) static void hamachi_tx_timeout(struct net_device *dev) { int i; - struct hamachi_private *hmp = (struct hamachi_private *)dev->priv; + struct hamachi_private *hmp = dev->priv; long ioaddr = dev->base_addr; printk(KERN_WARNING "%s: Hamachi transmit timed out, status %8.8x," @@ -1063,7 +1066,6 @@ static void hamachi_tx_timeout(struct net_device *dev) /* Mark the last entry as wrapping the ring. */ hmp->rx_ring[RX_RING_SIZE-1].status_n_length |= cpu_to_le32(DescEndRing); - /* Trigger an immediate transmit demand. */ dev->trans_start = jiffies; hmp->stats.tx_errors++; @@ -1072,13 +1074,15 @@ static void hamachi_tx_timeout(struct net_device *dev) writew(0x0002, dev->base_addr + TxCmd); /* STOP Tx */ writew(0x0001, dev->base_addr + TxCmd); /* START Tx */ writew(0x0001, dev->base_addr + RxCmd); /* START Rx */ + + netif_wake_queue(dev); } /* Initialize the Rx and Tx rings, along with various 'dev' bits. */ static void hamachi_init_ring(struct net_device *dev) { - struct hamachi_private *hmp = (struct hamachi_private *)dev->priv; + struct hamachi_private *hmp = dev->priv; int i; hmp->tx_full = 0; @@ -1176,7 +1180,7 @@ do { \ static int hamachi_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct hamachi_private *hmp = (struct hamachi_private *)dev->priv; + struct hamachi_private *hmp = dev->priv; unsigned entry; u16 status; @@ -1290,7 +1294,7 @@ static int hamachi_start_xmit(struct sk_buff *skb, struct net_device *dev) after the Tx thread. */ static void hamachi_interrupt(int irq, void *dev_instance, struct pt_regs *rgs) { - struct net_device *dev = (struct net_device *)dev_instance; + struct net_device *dev = dev_instance; struct hamachi_private *hmp; long ioaddr, boguscnt = max_interrupt_work; @@ -1302,7 +1306,7 @@ static void hamachi_interrupt(int irq, void *dev_instance, struct pt_regs *rgs) #endif ioaddr = dev->base_addr; - hmp = (struct hamachi_private *)dev->priv; + hmp = dev->priv; spin_lock(&hmp->lock); do { @@ -1444,7 +1448,7 @@ static unsigned short hamachi_eth_type_trans(struct sk_buff *skb, for clarity and better register allocation. */ static int hamachi_rx(struct net_device *dev) { - struct hamachi_private *hmp = (struct hamachi_private *)dev->priv; + struct hamachi_private *hmp = dev->priv; int entry = hmp->cur_rx % RX_RING_SIZE; int boguscnt = (hmp->dirty_rx + RX_RING_SIZE) - hmp->cur_rx; @@ -1651,7 +1655,7 @@ static int hamachi_rx(struct net_device *dev) static void hamachi_error(struct net_device *dev, int intr_status) { long ioaddr = dev->base_addr; - struct hamachi_private *hmp = (struct hamachi_private *)dev->priv; + struct hamachi_private *hmp = dev->priv; if (intr_status & (LinkChange|NegotiationChange)) { if (hamachi_debug > 1) @@ -1685,7 +1689,7 @@ static void hamachi_error(struct net_device *dev, int intr_status) static int hamachi_close(struct net_device *dev) { long ioaddr = dev->base_addr; - struct hamachi_private *hmp = (struct hamachi_private *)dev->priv; + struct hamachi_private *hmp = dev->priv; int i; netif_stop_queue(dev); @@ -1758,7 +1762,7 @@ static int hamachi_close(struct net_device *dev) static struct net_device_stats *hamachi_get_stats(struct net_device *dev) { long ioaddr = dev->base_addr; - struct hamachi_private *hmp = (struct hamachi_private *)dev->priv; + struct hamachi_private *hmp = dev->priv; /* We should lock this segment of code for SMP eventually, although the vulnerability window is very small and statistics are @@ -1812,7 +1816,6 @@ static void set_rx_mode(struct net_device *dev) } } -#ifdef HAVE_PRIVATE_IOCTL static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { long ioaddr = dev->base_addr; @@ -1853,7 +1856,6 @@ static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) return -EOPNOTSUPP; } } -#endif /* HAVE_PRIVATE_IOCTL */ static void __exit hamachi_remove_one (struct pci_dev *pdev) @@ -1865,6 +1867,7 @@ static void __exit hamachi_remove_one (struct pci_dev *pdev) unregister_netdev(dev); iounmap((char *)dev->base_addr); kfree(dev); + pci_release_regions(pdev); pci_set_drvdata(pdev, NULL); } } diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c index 8c9222fc4..d256ef600 100644 --- a/drivers/net/hamradio/scc.c +++ b/drivers/net/hamradio/scc.c @@ -582,7 +582,7 @@ static inline void scc_spint(struct scc_channel *scc) if (skb != NULL) dev_kfree_skb_irq(skb); - scc->rx_buff = NULL; + scc->rx_buff = skb = NULL; } if(status & END_FR && skb != NULL) /* end of frame */ @@ -689,7 +689,7 @@ static void scc_isr(int irq, void *dev_id, struct pt_regs *regs) break; } - /* This looks wierd and it is. At least the BayCom USCC doesn't + /* This looks weird and it is. At least the BayCom USCC doesn't * use the Interrupt Daisy Chain, thus we'll have to start * all over again to be sure not to miss an interrupt from * (any of) the other chip(s)... diff --git a/drivers/net/hamradio/soundmodem/gentbl.c b/drivers/net/hamradio/soundmodem/gentbl.c index a481a56f9..a2ff74f01 100644 --- a/drivers/net/hamradio/soundmodem/gentbl.c +++ b/drivers/net/hamradio/soundmodem/gentbl.c @@ -26,6 +26,7 @@ */ #include <stdio.h> +#include <stdlib.h> #include <math.h> #include <string.h> diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c index cad45e4fa..36479e42d 100644 --- a/drivers/net/hp100.c +++ b/drivers/net/hp100.c @@ -45,6 +45,8 @@ ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** +** 1.57b -> 1.57c - Arnaldo Carvalho de Melo <acme@conectiva.com.br> +** - release resources on failure in init_module ** ** 1.57 -> 1.57b - Jean II ** - fix spinlocks, SMP is now working ! @@ -265,12 +267,14 @@ static struct hp100_eisa_id hp100_eisa_ids[] = { #define HP100_EISA_IDS_SIZE (sizeof(hp100_eisa_ids)/sizeof(struct hp100_eisa_id)) +#ifdef CONFIG_PCI static struct hp100_pci_id hp100_pci_ids[] = { { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585A }, { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585B }, { PCI_VENDOR_ID_COMPEX, PCI_DEVICE_ID_COMPEX_ENET100VG4 }, { PCI_VENDOR_ID_COMPEX2, PCI_DEVICE_ID_COMPEX2_100VG } }; +#endif #define HP100_PCI_IDS_SIZE (sizeof(hp100_pci_ids)/sizeof(struct hp100_pci_id)) @@ -1896,7 +1900,7 @@ static void hp100_rx( struct net_device *dev ) /* First get indication of received lan packet */ /* RX_PKT_CND indicates the number of packets which have been fully */ - /* received onto the card but have not been fully transfered of the card */ + /* received onto the card but have not been fully transferred of the card */ packets = hp100_inb( RX_PKT_CNT ); #ifdef HP100_DEBUG_RX if ( packets > 1 ) @@ -1967,11 +1971,6 @@ static void hp100_rx( struct net_device *dev ) insl( ioaddr + HP100_REG_DATA32, ptr, pkt_len >> 2 ); skb->protocol = eth_type_trans( skb, dev ); - - netif_rx( skb ); - dev->last_rx = jiffies; - lp->stats.rx_packets++; - lp->stats.rx_bytes += pkt_len; #ifdef HP100_DEBUG_RX printk( "hp100: %s: rx: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", @@ -1979,6 +1978,10 @@ static void hp100_rx( struct net_device *dev ) ptr[ 0 ], ptr[ 1 ], ptr[ 2 ], ptr[ 3 ], ptr[ 4 ], ptr[ 5 ], ptr[ 6 ], ptr[ 7 ], ptr[ 8 ], ptr[ 9 ], ptr[ 10 ], ptr[ 11 ] ); #endif + netif_rx( skb ); + dev->last_rx = jiffies; + lp->stats.rx_packets++; + lp->stats.rx_bytes += pkt_len; } /* Indicate the card that we have got the packet */ @@ -3017,16 +3020,34 @@ void hp100_RegisterDump( struct net_device *dev ) #ifdef MODULE /* Parameters set by insmod */ -int hp100_port[5] = { 0, -1, -1, -1, -1 }; +static int hp100_port[5] = { 0, -1, -1, -1, -1 }; MODULE_PARM(hp100_port, "1-5i"); /* Allocate 5 string of length IFNAMSIZ, one string for each device */ -char hp100_name[5][IFNAMSIZ] = { "", "", "", "", "" }; +static char hp100_name[5][IFNAMSIZ] = { "", "", "", "", "" }; /* Allow insmod to write those 5 strings individually */ MODULE_PARM(hp100_name, "1-5c" __MODULE_STRING(IFNAMSIZ)); /* List of devices */ -static struct net_device *hp100_devlist[5] = { NULL, NULL, NULL, NULL, NULL }; +static struct net_device *hp100_devlist[5]; + +static void release_dev(int i) +{ + struct net_device *d = hp100_devlist[i]; + struct hp100_private *p = (struct hp100_private *)d->priv; + + unregister_netdev(d); + release_region(d->base_addr, HP100_REGION_SIZE); + + if (p->mode == 1) /* busmaster */ + kfree(p->page_vaddr); + if (p->mem_ptr_virt) + iounmap(p->mem_ptr_virt); + kfree(d->priv); + d->priv = NULL; + kfree(d); + hp100_devlist[i] = NULL; +} /* * Note: if you have more than five 100vg cards in your pc, feel free to @@ -3053,6 +3074,8 @@ int init_module( void ) { /* Create device and set basics args */ hp100_devlist[i] = kmalloc(sizeof(struct net_device), GFP_KERNEL); + if (!hp100_devlist[i]) + goto fail; memset(hp100_devlist[i], 0x00, sizeof(struct net_device)); #if LINUX_VERSION_CODE >= 0x020362 /* 2.3.99-pre7 */ memcpy(hp100_devlist[i]->name, hp100_name[i], IFNAMSIZ); /* Copy name */ @@ -3075,6 +3098,13 @@ int init_module( void ) } /* Loop over all devices */ return cards > 0 ? 0 : -ENODEV; + fail: + while (cards && --i) + if (hp100_devlist[i]) { + release_dev(i); + --cards; + } + return -ENOMEM; } void cleanup_module( void ) @@ -3084,18 +3114,7 @@ void cleanup_module( void ) /* TODO: Check if all skb's are released/freed. */ for(i = 0; i < 5; i++) if(hp100_devlist[i] != (struct net_device *) NULL) - { - unregister_netdev( hp100_devlist[i] ); - release_region( hp100_devlist[i]->base_addr, HP100_REGION_SIZE ); - if( ((struct hp100_private *)hp100_devlist[i]->priv)->mode==1 ) /* busmaster */ - kfree( ((struct hp100_private *)hp100_devlist[i]->priv)->page_vaddr ); - if ( ((struct hp100_private *)hp100_devlist[i]->priv) -> mem_ptr_virt ) - iounmap( ((struct hp100_private *)hp100_devlist[i]->priv) -> mem_ptr_virt ); - kfree( hp100_devlist[i]->priv ); - hp100_devlist[i]->priv = NULL; - kfree(hp100_devlist[i]); - hp100_devlist[i] = (struct net_device *) NULL; - } + release_dev(i); } #endif /* MODULE */ diff --git a/drivers/net/ibmlana.h b/drivers/net/ibmlana.h index 58429842a..aa7bfa34d 100644 --- a/drivers/net/ibmlana.h +++ b/drivers/net/ibmlana.h @@ -127,12 +127,12 @@ typedef struct { #define TCREG_POWC 0x4000 /* timer start out of window detect */ #define TCREG_CRCI 0x2000 /* inhibit CRC generation */ #define TCREG_EXDIS 0x1000 /* disable excessive deferral timer */ -#define TCREG_EXD 0x0400 /* excessive deferral occured */ -#define TCREG_DEF 0x0200 /* single deferral occured */ +#define TCREG_EXD 0x0400 /* excessive deferral occurred */ +#define TCREG_DEF 0x0200 /* single deferral occurred */ #define TCREG_NCRS 0x0100 /* no carrier detected */ #define TCREG_CRSL 0x0080 /* carrier lost */ -#define TCREG_EXC 0x0040 /* excessive collisions occured */ -#define TCREG_OWC 0x0020 /* out of window collision occured */ +#define TCREG_EXC 0x0040 /* excessive collisions occurred */ +#define TCREG_OWC 0x0020 /* out of window collision occurred */ #define TCREG_PMB 0x0008 /* packet monitored bad */ #define TCREG_FU 0x0004 /* FIFO underrun */ #define TCREG_BCM 0x0002 /* byte count mismatch of fragments */ @@ -141,7 +141,7 @@ typedef struct { /* Interrupt Mask Register */ #define SONIC_IMREG 0x08 -#define IMREG_BREN 0x4000 /* interrupt when bus retry occured */ +#define IMREG_BREN 0x4000 /* interrupt when bus retry occurred */ #define IMREG_HBLEN 0x2000 /* interrupt when heartbeat lost */ #define IMREG_LCDEN 0x1000 /* interrupt when CAM loaded */ #define IMREG_PINTEN 0x0800 /* interrupt when PINT in TDA set */ @@ -160,7 +160,7 @@ typedef struct { /* Interrupt Status Register */ #define SONIC_ISREG 0x0a -#define ISREG_BR 0x4000 /* bus retry occured */ +#define ISREG_BR 0x4000 /* bus retry occurred */ #define ISREG_HBL 0x2000 /* heartbeat lost */ #define ISREG_LCD 0x1000 /* CAM loaded */ #define ISREG_PINT 0x0800 /* PINT in TDA set */ diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c index 958a4088c..c0cda0ce3 100644 --- a/drivers/net/ioc3-eth.c +++ b/drivers/net/ioc3-eth.c @@ -8,28 +8,6 @@ * Copyright (C) 1999, 2000 Ralf Baechle * Copyright (C) 1995, 1999, 2000 by Silicon Graphics, Inc. * - * Reporting bugs: - * - * If you find problems with this drivers, then if possible do the - * following. Hook up a terminal to the MSC port, send an NMI to the CPUs - * by typing ^Tnmi (where ^T stands for <CTRL>-T). You'll see something - * like: - * 1A 000: - * 1A 000: *** NMI while in Kernel and no NMI vector installed on node 0 - * 1A 000: *** Error EPC: 0xffffffff800265e4 (0xffffffff800265e4) - * 1A 000: *** Press ENTER to continue. - * - * Next enter the command ``lw i:0x86000f0 0x18'' and include this - * commands output which will look like below with your bugreport. - * - * 1A 000: POD MSC Dex> lw i:0x86000f0 0x18 - * 1A 000: 92000000086000f0: 0021f28c 00000000 00000000 00000000 - * 1A 000: 9200000008600100: a5000000 01cde000 00000000 000004e0 - * 1A 000: 9200000008600110: 00000650 00000000 00110b15 00000000 - * 1A 000: 9200000008600120: 006d0005 77bbca0a a5000000 01ce0000 - * 1A 000: 9200000008600130: 80000500 00000500 00002538 05690008 - * 1A 000: 9200000008600140: 00000000 00000000 000003e1 0000786d - * * To do: * * - Handle allocation failures in ioc3_alloc_skb() more gracefully. @@ -50,6 +28,12 @@ #include <linux/errno.h> #include <linux/module.h> #include <linux/pci.h> +#ifdef CONFIG_SERIAL +#include <linux/serial.h> +#include <asm/serial.h> +#define IOC3_BAUD (22000000 / (3*16)) +#define IOC3_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST) +#endif #include <linux/netdevice.h> #include <linux/etherdevice.h> @@ -889,6 +873,27 @@ ioc3_close(struct net_device *dev) return 0; } +static void inline ioc3_serial_probe(struct pci_dev *pdev, + struct ioc3 *ioc3) +{ + struct serial_struct req; + + /* Register to interrupt zero because we share the interrupt with + the serial driver which we don't properly support yet. */ + memset(&req, 0, sizeof(req)); + req.irq = 0; + req.flags = IOC3_COM_FLAGS; + req.io_type = SERIAL_IO_MEM; + req.iomem_reg_shift = 0; + req.baud_base = IOC3_BAUD; + + req.iomem_base = (unsigned char *) &ioc3->sregs.uarta; + register_serial(&req); + + req.iomem_base = (unsigned char *) &ioc3->sregs.uartb; + register_serial(&req); +} + static int __devinit ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -900,34 +905,34 @@ static int __devinit ioc3_probe(struct pci_dev *pdev, u32 vendor, model, rev; int phy, err; - dev = init_etherdev(0, sizeof(struct ioc3_private)); - + dev = alloc_etherdev(sizeof(struct ioc3_private)); if (!dev) return -ENOMEM; + err = pci_request_regions(pdev, "ioc3"); + if (err) + goto out_free; + SET_MODULE_OWNER(dev); ip = dev->priv; - memset(ip, 0, sizeof(*ip)); - - /* - * This probably needs to be register_netdevice, or call - * init_etherdev so that it calls register_netdevice. Quick - * hack for now. - */ - netif_device_attach(dev); dev->irq = pdev->irq; - ioc3_base = pdev->resource[0].start; - ioc3_size = pdev->resource[0].end - ioc3_base; + ioc3_base = pci_resource_start(pdev, 0); + ioc3_size = pci_resource_len(pdev, 0); ioc3 = (struct ioc3 *) ioremap(ioc3_base, ioc3_size); if (!ioc3) { - printk(KERN_CRIT"%s: Unable to map device I/O.\n", dev->name); + printk(KERN_CRIT "ioc3eth(%s): Didn't find a PHY, goodbye.\n", + pdev->slot_name); err = -ENOMEM; - goto out_free; + goto out_res; } ip->regs = ioc3; +#ifdef CONFIG_SERIAL + ioc3_serial_probe(pdev, ioc3); +#endif + spin_lock_init(&ip->ioc3_lock); ioc3_stop(dev); @@ -954,9 +959,9 @@ static int __devinit ioc3_probe(struct pci_dev *pdev, rev = mii3 & 0xf; printk(KERN_INFO"Using PHY %d, vendor 0x%x, model %d, rev %d.\n", phy, vendor, model, rev); - printk(KERN_INFO "%s: MII transceiver found at MDIO address " + printk(KERN_INFO "ioc3eth(%s): MII transceiver found at MDIO address " "%d, config %4.4x status %4.4x.\n", - dev->name, phy, mii0, mii_status); + pdev->slot_name, phy, mii0, mii_status); ioc3_ssram_disc(ip); printk("IOC3 SSRAM has %d kbyte.\n", ip->emcr & EMCR_BUFSIZ ? 128 : 64); @@ -973,12 +978,18 @@ static int __devinit ioc3_probe(struct pci_dev *pdev, dev->do_ioctl = ioc3_ioctl; dev->set_multicast_list = ioc3_set_multicast_list; + err = register_netdev(dev); + if (err) + goto out_stop; + return 0; out_stop: ioc3_stop(dev); free_irq(dev->irq, dev); ioc3_free_rings(ip); +out_res: + pci_release_regions(pdev); out_free: kfree(dev); return err; diff --git a/drivers/net/irda/irport.c b/drivers/net/irda/irport.c index d08583f84..679d25c30 100644 --- a/drivers/net/irda/irport.c +++ b/drivers/net/irda/irport.c @@ -609,7 +609,7 @@ static void irport_timeout(struct net_device *dev) * * Transmits the current frame until FIFO is full, then * waits until the next transmitt interrupt, and continues until the - * frame is transmited. + * frame is transmitted. */ int irport_hard_xmit(struct sk_buff *skb, struct net_device *dev) { @@ -1008,7 +1008,7 @@ static struct net_device_stats *irport_net_get_stats(struct net_device *dev) #ifdef MODULE MODULE_PARM(io, "1-4i"); -MODULE_PARM_DESC(io, "Base I/O adresses"); +MODULE_PARM_DESC(io, "Base I/O addresses"); MODULE_PARM(irq, "1-4i"); MODULE_PARM_DESC(irq, "IRQ lines"); diff --git a/drivers/net/irda/irtty.c b/drivers/net/irda/irtty.c index 8102f5ffb..ff052798b 100644 --- a/drivers/net/irda/irtty.c +++ b/drivers/net/irda/irtty.c @@ -824,7 +824,7 @@ int irtty_set_mode(struct net_device *dev, int mode) /* * Function irtty_raw_read (self, buf, len) * - * Receive incomming data. This function sleeps, so it must only be + * Receive incoming data. This function sleeps, so it must only be * called with a process context. Timeout is currently defined to be * a multiple of 10 ms. */ diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c index 6d6c7ed5f..92f8e7356 100644 --- a/drivers/net/irda/nsc-ircc.c +++ b/drivers/net/irda/nsc-ircc.c @@ -1263,7 +1263,7 @@ static void nsc_ircc_dma_xmit(struct nsc_ircc_cb *self, int iobase) * Function nsc_ircc_pio_xmit (self, iobase) * * Transmit data using PIO. Returns the number of bytes that actually - * got transfered + * got transferred * */ static int nsc_ircc_pio_write(int iobase, __u8 *buf, int len, int fifo_size) diff --git a/drivers/net/irda/smc-ircc.c b/drivers/net/irda/smc-ircc.c index b62eeaf3e..503610899 100644 --- a/drivers/net/irda/smc-ircc.c +++ b/drivers/net/irda/smc-ircc.c @@ -560,7 +560,7 @@ static void ircc_change_speed(void *priv, __u32 speed) */ /* outb(UART_MCR_OUT2, self->io.sir_base + UART_MCR); */ - /* Be ready for incomming frames */ + /* Be ready for incoming frames */ ircc_dma_receive(self, iobase); } else { /* Install SIR transmit handler */ diff --git a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c index 12c017294..2f10dc0a9 100644 --- a/drivers/net/irda/w83977af_ir.c +++ b/drivers/net/irda/w83977af_ir.c @@ -875,7 +875,7 @@ int w83977af_dma_receive_complete(struct w83977af_ir *self) self->stats.rx_fifo_errors++; } else { - /* Check if we have transfered all data to memory */ + /* Check if we have transferred all data to memory */ switch_bank(iobase, SET0); if (inb(iobase+USR) & USR_RDR) { #ifdef CONFIG_USE_INTERNAL_TIMER diff --git a/drivers/net/jazzsonic.c b/drivers/net/jazzsonic.c index d1555d6e8..80f918cc8 100644 --- a/drivers/net/jazzsonic.c +++ b/drivers/net/jazzsonic.c @@ -62,7 +62,7 @@ static unsigned int sonic_debug = 1; #endif /* - * Base address and interupt of the SONIC controller on JAZZ boards + * Base address and interrupt of the SONIC controller on JAZZ boards */ static struct { unsigned int port; diff --git a/drivers/net/lance.c b/drivers/net/lance.c index 54981fcaf..876768f4b 100644 --- a/drivers/net/lance.c +++ b/drivers/net/lance.c @@ -33,6 +33,9 @@ Forward ported v1.14 to 2.1.129, merged the PCI and misc changes from the 2.1 version of the old driver - Alan Cox + + Get rid of check_region, check kmalloc return in lance_probe1 + Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 11/01/2001 */ static const char *version = "lance.c:v1.15ac 1999/11/13 dplatt@3do.com, becker@cesdis.gsfc.nasa.gov\n"; @@ -61,9 +64,9 @@ int lance_probe(struct net_device *dev); static int lance_probe1(struct net_device *dev, int ioaddr, int irq, int options); #ifdef LANCE_DEBUG -int lance_debug = LANCE_DEBUG; +static int lance_debug = LANCE_DEBUG; #else -int lance_debug = 1; +static int lance_debug = 1; #endif /* @@ -295,6 +298,7 @@ static int irq[MAX_CARDS]; MODULE_PARM(io, "1-" __MODULE_STRING(MAX_CARDS) "i"); MODULE_PARM(dma, "1-" __MODULE_STRING(MAX_CARDS) "i"); MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_CARDS) "i"); +MODULE_PARM(lance_debug, "i"); int init_module(void) { @@ -352,17 +356,27 @@ int lance_probe(struct net_device *dev) for (port = lance_portlist; *port; port++) { int ioaddr = *port; + struct resource *r = request_region(ioaddr, LANCE_TOTAL_SIZE, + "lance-probe"); - if ( check_region(ioaddr, LANCE_TOTAL_SIZE) == 0) { + if (r) { /* Detect "normal" 0x57 0x57 and the NI6510EB 0x52 0x44 signatures w/ minimal I/O reads */ char offset15, offset14 = inb(ioaddr + 14); if ((offset14 == 0x52 || offset14 == 0x57) && - ((offset15 = inb(ioaddr + 15)) == 0x57 || offset15 == 0x44)) { + ((offset15 = inb(ioaddr + 15)) == 0x57 || + offset15 == 0x44)) { result = lance_probe1(dev, ioaddr, 0, 0); - if ( !result ) return 0; + if (!result) { + struct lance_private *lp = dev->priv; + int ver = lp->chip_version; + + r->name = chip_table[ver].name; + return 0; + } } + release_resource(r); } } return -ENODEV; @@ -444,12 +458,10 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int printk(" %2.2x", dev->dev_addr[i] = inb(ioaddr + i)); dev->base_addr = ioaddr; - request_region(ioaddr, LANCE_TOTAL_SIZE, chip_table[lance_version].name); - /* Make certain the data structures used by the LANCE are aligned and DMAble. */ lp = (struct lance_private *)(((unsigned long)kmalloc(sizeof(*lp)+7, - GFP_DMA | GFP_KERNEL)+7) & ~7); + GFP_DMA | GFP_KERNEL)+7) & ~7); if(lp==NULL) return -ENODEV; if (lance_debug > 6) printk(" (#0x%05lx)", (unsigned long)lp); @@ -457,11 +469,15 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int dev->priv = lp; lp->name = chipname; lp->rx_buffs = (unsigned long)kmalloc(PKT_BUF_SZ*RX_RING_SIZE, - GFP_DMA | GFP_KERNEL); - if (lance_need_isa_bounce_buffers) + GFP_DMA | GFP_KERNEL); + if (!lp->rx_buffs) + goto out_lp; + if (lance_need_isa_bounce_buffers) { lp->tx_bounce_buffs = kmalloc(PKT_BUF_SZ*TX_RING_SIZE, - GFP_DMA | GFP_KERNEL); - else + GFP_DMA | GFP_KERNEL); + if (!lp->tx_bounce_buffs) + goto out_rx; + } else lp->tx_bounce_buffs = NULL; lp->chip_version = lance_version; @@ -628,6 +644,9 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int dev->watchdog_timeo = TX_TIMEOUT; return 0; +out_rx: kfree((void*)lp->rx_buffs); +out_lp: kfree(lp); + return -ENOMEM; } static int diff --git a/drivers/net/mac89x0.c b/drivers/net/mac89x0.c index 847a77ef1..40bee086c 100644 --- a/drivers/net/mac89x0.c +++ b/drivers/net/mac89x0.c @@ -48,6 +48,11 @@ I/O space and NuBus interrupts for these cards, but neglected to provide anything even remotely resembling a NuBus ROM. Therefore we have to probe for them in a brain-damaged ISA-like fashion. + + Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 11/01/2001 + check kmalloc and release the allocated memory on failure in + mac89x0_probe and in init_module + use save_flags/restore_flags in net_get_stat, not just cli/sti */ static char *version = @@ -167,9 +172,9 @@ writereg(struct net_device *dev, int portno, int value) anywhere else until we have a really good reason to do so. */ int __init mac89x0_probe(struct net_device *dev) { - static int once_is_enough = 0; + static int once_is_enough; struct net_local *lp; - static unsigned version_printed = 0; + static unsigned version_printed; int i, slot; unsigned rev_type = 0; unsigned long ioaddr; @@ -213,6 +218,8 @@ int __init mac89x0_probe(struct net_device *dev) /* Initialize the net_device structure. */ if (dev->priv == NULL) { dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); + if (!dev->priv) + return -ENOMEM; memset(dev->priv, 0, sizeof(struct net_local)); } lp = (struct net_local *)dev->priv; @@ -252,6 +259,8 @@ int __init mac89x0_probe(struct net_device *dev) /* Try to read the MAC address */ if ((readreg(dev, PP_SelfST) & (EEPROM_PRESENT | EEPROM_OK)) == 0) { printk("\nmac89x0: No EEPROM, giving up now.\n"); + kfree(dev->priv); + dev->priv = NULL; return -ENODEV; } else { for (i = 0; i < ETH_ALEN; i += 2) { @@ -558,12 +567,14 @@ static struct net_device_stats * net_get_stats(struct net_device *dev) { struct net_local *lp = (struct net_local *)dev->priv; + unsigned long flags; + save_flags(flags); cli(); /* Update the statistics from the device registers. */ lp->stats.rx_missed_errors += (readreg(dev, PP_RxMiss) >> 6); lp->stats.collisions += (readreg(dev, PP_TxCol) >> 6); - sti(); + restore_flags(flags); return &lp->stats; } @@ -621,16 +632,16 @@ EXPORT_NO_SYMBOLS; int init_module(void) { - struct net_local *lp; - net_debug = debug; dev_cs89x0.init = mac89x0_probe; dev_cs89x0.priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); + if (!dev_cs89x0.priv) + return -ENOMEM; memset(dev_cs89x0.priv, 0, sizeof(struct net_local)); - lp = (struct net_local *)dev_cs89x0.priv; if (register_netdev(&dev_cs89x0) != 0) { printk(KERN_WARNING "mac89x0.c: No card found\n"); + kfree(dev_cs89x0.priv); return -ENXIO; } return 0; diff --git a/drivers/net/mace.c b/drivers/net/mace.c index 2f84f6f09..88598f06f 100644 --- a/drivers/net/mace.c +++ b/drivers/net/mace.c @@ -87,7 +87,7 @@ static void __mace_set_address(struct net_device *dev, void *addr); /* * If we can't get a skbuff when we need it, we use this area for DMA. */ -static unsigned char dummy_buf[RX_BUFLEN+2]; +static unsigned char *dummy_buf; /* Bit-reverse one byte of an ethernet hardware address. */ static inline int @@ -106,7 +106,7 @@ static int __init mace_probe(void) for (mace = find_devices("mace"); mace != NULL; mace = mace->next) mace_probe1(mace); - return 0; + return mace_devs? 0: -ENODEV; } static void __init mace_probe1(struct device_node *mace) @@ -132,6 +132,14 @@ static void __init mace_probe1(struct device_node *mace) } } + if (dummy_buf == NULL) { + dummy_buf = kmalloc(RX_BUFLEN+2, GFP_KERNEL); + if (dummy_buf == NULL) { + printk(KERN_ERR "MACE: couldn't allocate dummy buffer\n"); + return; + } + } + dev = init_etherdev(0, PRIV_BYTES); if (!dev) return; @@ -898,6 +906,10 @@ static void __exit mace_cleanup (void) unregister_netdev(dev); kfree(dev); } + if (dummy_buf != NULL) { + kfree(dummy_buf); + dummy_buf = NULL; + } } module_init(mace_probe); diff --git a/drivers/net/macmace.c b/drivers/net/macmace.c index 38843f5e4..a93002904 100644 --- a/drivers/net/macmace.c +++ b/drivers/net/macmace.c @@ -632,7 +632,7 @@ static void mace68k_handle_misc_intrs(struct mace68k_data *mp, int intr) } /* - * A transmit error has occured. (We kick the transmit side from + * A transmit error has occurred. (We kick the transmit side from * the DMA completion) */ @@ -661,7 +661,7 @@ static void mace68k_xmit_error(struct net_device *dev) } /* - * A receive interrupt occured. + * A receive interrupt occurred. */ static void mace68k_recv_interrupt(struct net_device *dev) diff --git a/drivers/net/macsonic.c b/drivers/net/macsonic.c index a5e695f70..2e0984869 100644 --- a/drivers/net/macsonic.c +++ b/drivers/net/macsonic.c @@ -59,8 +59,8 @@ #include "sonic.h" -static int sonic_debug = 0; -static int sonic_version_printed = 0; +static int sonic_debug; +static int sonic_version_printed; extern int macsonic_probe(struct net_device* dev); extern int mac_onboard_sonic_probe(struct net_device* dev); @@ -272,7 +272,7 @@ int __init mac_onboard_sonic_ethernet_addr(struct net_device* dev) int __init mac_onboard_sonic_probe(struct net_device* dev) { /* Bwahahaha */ - static int once_is_more_than_enough = 0; + static int once_is_more_than_enough; struct sonic_local* lp; int i; @@ -316,9 +316,14 @@ int __init mac_onboard_sonic_probe(struct net_device* dev) if (dev) { dev = init_etherdev(dev, sizeof(struct sonic_local)); + if (!dev) + return -ENOMEM; /* methinks this will always be true but better safe than sorry */ - if (dev->priv == NULL) + if (dev->priv == NULL) { dev->priv = kmalloc(sizeof(struct sonic_local), GFP_KERNEL); + if (!dev->priv) /* FIXME: kfree dev if necessary */ + return -ENOMEM; + } } else { dev = init_etherdev(NULL, sizeof(struct sonic_local)); } @@ -438,7 +443,7 @@ int __init macsonic_ident(struct nubus_dev* ndev) int __init mac_nubus_sonic_probe(struct net_device* dev) { - static int slots = 0; + static int slots; struct nubus_dev* ndev = NULL; struct sonic_local* lp; unsigned long base_addr, prom_addr; @@ -567,11 +572,7 @@ int __init mac_nubus_sonic_probe(struct net_device* dev) #ifdef MODULE static char namespace[16] = ""; -static struct net_device dev_macsonic = { - NULL, - 0, 0, 0, 0, - 0, 0, - 0, 0, 0, NULL, NULL }; +static struct net_device dev_macsonic; MODULE_PARM(sonic_debug, "i"); diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index 533cddcff..01b432320 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -1,6 +1,6 @@ -/* natsemi.c: A Linux PCI Ethernet driver for the NatSemi DP83810 series. */ +/* natsemi.c: A Linux PCI Ethernet driver for the NatSemi DP8381x series. */ /* - Written/copyright 1999-2000 by Donald Becker. + Written/copyright 1999-2001 by Donald Becker. This software may be used and distributed according to the terms of the GNU General Public License (GPL), incorporated herein by reference. @@ -31,25 +31,28 @@ - Call netif_start_queue from dev->tx_timeout - wmb() in start_tx() to flush data - Update Tx locking + - Clean up PCI enable (davej) + Version 1.0.4: + - Merge Donald Becker's natsemi.c version 1.07 */ /* These identify the driver base version and may not be removed. */ static const char version1[] = -"natsemi.c:v1.05 8/7/2000 Written by Donald Becker <becker@scyld.com>\n"; +"natsemi.c:v1.07 1/9/2001 Written by Donald Becker <becker@scyld.com>\n"; static const char version2[] = " http://www.scyld.com/network/natsemi.html\n"; static const char version3[] = -" (unofficial 2.4.x kernel port, version 1.0.3, January 21, 2001 Jeff Garzik, Tjeerd Mulder)\n"; +" (unofficial 2.4.x kernel port, version 1.0.4, February 26, 2001 Jeff Garzik, Tjeerd Mulder)\n"; /* Updated to recommendations in pci-skeleton v2.03. */ /* Automatically extracted configuration info: probe-func: natsemi_probe -config-in: tristate 'National Semiconductor DP83810 series PCI Ethernet support' CONFIG_NATSEMI +config-in: tristate 'National Semiconductor DP8381x series PCI Ethernet support' CONFIG_NATSEMI -c-help-name: National Semiconductor DP83810 series PCI Ethernet support +c-help-name: National Semiconductor DP8381x series PCI Ethernet support c-help-symbol: CONFIG_NATSEMI -c-help: This driver is for the National Semiconductor DP83810 series, +c-help: This driver is for the National Semiconductor DP8381x series, c-help: including the 83815 chip. c-help: More specific information and updates are available from c-help: http://www.scyld.com/network/natsemi.html @@ -87,7 +90,7 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; bonding and packet priority. There are no ill effects from too-large receive rings. */ #define TX_RING_SIZE 16 -#define TX_QUEUE_LEN 10 /* Limit ring entries actually used. */ +#define TX_QUEUE_LEN 10 /* Limit ring entries actually used, min 4. */ #define RX_RING_SIZE 32 /* Operational parameters that usually are not changed. */ @@ -127,7 +130,7 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; #define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr)) MODULE_AUTHOR("Donald Becker <becker@scyld.com>"); -MODULE_DESCRIPTION("National Semiconductor DP83810 series PCI Ethernet driver"); +MODULE_DESCRIPTION("National Semiconductor DP8381x series PCI Ethernet driver"); MODULE_PARM(max_interrupt_work, "i"); MODULE_PARM(mtu, "i"); MODULE_PARM(debug, "i"); @@ -192,14 +195,13 @@ threaded by the hardware and interrupt handling software. The send packet thread has partial control over the Tx ring and 'dev->tbusy' flag. It sets the tbusy flag whenever it's queuing a Tx packet. If the next -queue slot is empty, it clears the tbusy flag when finished. Under 2.4, the -"tbusy flag" is now controlled by netif_{start,stop,wake}_queue() and tested -by netif_queue_stopped(). +queue slot is empty, it clears the tbusy flag when finished otherwise it sets +the 'lp->tx_full' flag. The interrupt handler has exclusive control over the Rx ring and records stats from the Tx ring. After reaping the stats, it marks the Tx queue entry as -empty by incrementing the dirty_tx mark. Iff Tx queueing is stopped and Tx -entries were reaped, the Tx queue is started and scheduled. +empty by incrementing the dirty_tx mark. Iff the 'lp->tx_full' flag is set, it +clears both the tx_full and tbusy flags. IV. Notes @@ -258,6 +260,7 @@ enum register_offsets { WOLCmd=0x40, PauseCmd=0x44, RxFilterAddr=0x48, RxFilterData=0x4C, BootRomAddr=0x50, BootRomData=0x54, StatsCtrl=0x5C, StatsData=0x60, RxPktErrs=0x60, RxMissed=0x68, RxCRCErrs=0x64, + PCIPM = 0x44, }; /* Bit in ChipCmd. */ @@ -271,24 +274,20 @@ enum intr_status_bits { IntrRxDone=0x0001, IntrRxIntr=0x0002, IntrRxErr=0x0004, IntrRxEarly=0x0008, IntrRxIdle=0x0010, IntrRxOverrun=0x0020, IntrTxDone=0x0040, IntrTxIntr=0x0080, IntrTxErr=0x0100, - IntrTxIdle=0x0200, IntrTxOverrun=0x0400, + IntrTxIdle=0x0200, IntrTxUnderrun=0x0400, StatsMax=0x0800, LinkChange=0x4000, WOLPkt=0x2000, RxResetDone=0x1000000, TxResetDone=0x2000000, IntrPCIErr=0x00f00000, - IntrAbnormalSummary=0xCD20, + IntrNormalSummary=0x0251, IntrAbnormalSummary=0xED20, }; /* Bits in the RxMode register. */ enum rx_mode_bits { - EnableFilter = 0x80000000, - AcceptBroadcast = 0x40000000, - AcceptAllMulticast = 0x20000000, - AcceptAllPhys = 0x10000000, - AcceptMyPhys = 0x08000000, - AcceptMulticast = 0x00200000, - AcceptErr=0x20, /* these 2 are in another register */ - AcceptRunt=0x10,/* and are not used in this driver */ + AcceptErr=0x20, AcceptRunt=0x10, + AcceptBroadcast=0xC0000000, + AcceptMulticast=0x00200000, AcceptAllMulticast=0x20000000, + AcceptAllPhys=0x10000000, AcceptMyPhys=0x08000000, }; /* The Rx and Tx buffer descriptors. */ @@ -334,9 +333,9 @@ struct netdev_private { u32 cur_rx_mode; u32 rx_filter[16]; /* FIFO and PCI burst thresholds. */ - int tx_config, rx_config; + u32 tx_config, rx_config; /* original contents of ClkRun register */ - int SavedClkRun; + u32 SavedClkRun; /* MII transceiver section. */ u16 advertising; /* NWay media advertisement */ @@ -346,7 +345,6 @@ struct netdev_private { static int eeprom_read(long ioaddr, int location); static int mdio_read(struct net_device *dev, int phy_id, int location); -static void mdio_write(struct net_device *dev, int phy_id, int location, int value); static int netdev_open(struct net_device *dev); static void check_duplex(struct net_device *dev); static void netdev_timer(unsigned long data); @@ -368,68 +366,70 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, { struct net_device *dev; struct netdev_private *np; - int i, option, irq = pdev->irq, chip_idx = ent->driver_data; + int i, option, irq, chip_idx = ent->driver_data; static int find_cnt = -1; static int printed_version; unsigned long ioaddr, iosize; const int pcibar = 1; /* PCI base address register */ + int prev_eedata; + u32 tmp; if ((debug <= 1) && !printed_version++) printk(KERN_INFO "%s" KERN_INFO "%s" KERN_INFO "%s", version1, version2, version3); + i = pci_enable_device(pdev); + if (i) return i; + + /* natsemi has a non-standard PM control register + * in PCI config space. Some boards apparently need + * to be brought to D0 in this manner. + */ + pci_read_config_dword(pdev, PCIPM, &tmp); + if (tmp & (0x03|0x100)) { + /* D0 state, disable PME assertion */ + u32 newtmp = tmp & ~(0x03|0x100); + pci_write_config_dword(pdev, PCIPM, newtmp); + } + find_cnt++; option = find_cnt < MAX_UNITS ? options[find_cnt] : 0; ioaddr = pci_resource_start(pdev, pcibar); iosize = pci_resource_len(pdev, pcibar); - - if (pci_enable_device(pdev)) - return -EIO; + irq = pdev->irq; + if (natsemi_pci_info[chip_idx].flags & PCI_USES_MASTER) pci_set_master(pdev); - dev = init_etherdev(NULL, sizeof (struct netdev_private)); + dev = alloc_etherdev(sizeof (struct netdev_private)); if (!dev) return -ENOMEM; SET_MODULE_OWNER(dev); + i = pci_request_regions(pdev, dev->name); + if (i) { + kfree(dev); + return i; + } + { - void *mmio; - if (request_mem_region(ioaddr, iosize, dev->name) == NULL) { - unregister_netdev(dev); - kfree(dev); - return -EBUSY; - } - mmio = ioremap (ioaddr, iosize); + void *mmio = ioremap (ioaddr, iosize); if (!mmio) { - release_mem_region(ioaddr, iosize); - unregister_netdev(dev); + pci_release_regions(pdev); kfree(dev); return -ENOMEM; } ioaddr = (unsigned long) mmio; } - printk(KERN_INFO "%s: %s at 0x%lx, ", - dev->name, natsemi_pci_info[chip_idx].name, ioaddr); - - for (i = 0; i < ETH_ALEN/2; i++) { - /* weird organization */ - unsigned short a; - a = (le16_to_cpu(eeprom_read(ioaddr, i + 6)) >> 15) + - (le16_to_cpu(eeprom_read(ioaddr, i + 7)) << 1); - ((u16 *)dev->dev_addr)[i] = a; + /* Work around the dropped serial bit. */ + prev_eedata = eeprom_read(ioaddr, 6); + for (i = 0; i < 3; i++) { + int eedata = eeprom_read(ioaddr, i + 7); + dev->dev_addr[i*2] = (eedata << 1) + (prev_eedata >> 15); + dev->dev_addr[i*2+1] = eedata >> 7; + prev_eedata = eedata; } - for (i = 0; i < ETH_ALEN-1; i++) - printk("%2.2x:", dev->dev_addr[i]); - printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); - -#if ! defined(final_version) /* Dump the EEPROM contents during development. */ - if (debug > 4) - for (i = 0; i < 64; i++) - printk("%4.4x%s", - eeprom_read(ioaddr, i), i % 16 != 15 ? " " : "\n"); -#endif /* Reset the chip to erase previous misconfiguration. */ writel(ChipReset, ioaddr + ChipCmd); @@ -440,7 +440,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, np = dev->priv; np->pci_dev = pdev; - pdev->driver_data = dev; + pci_set_drvdata(pdev, dev); np->iosize = iosize; spin_lock_init(&np->lock); @@ -474,7 +474,31 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, if (mtu) dev->mtu = mtu; - np->advertising = readl(ioaddr + 0x90); + i = register_netdev(dev); + if (i) { + pci_release_regions(pdev); + unregister_netdev(dev); + kfree(dev); + pci_set_drvdata(pdev, NULL); + return i; + } + + printk(KERN_INFO "%s: %s at 0x%lx, ", + dev->name, natsemi_pci_info[chip_idx].name, ioaddr); + for (i = 0; i < ETH_ALEN-1; i++) + printk("%2.2x:", dev->dev_addr[i]); + printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); + + np->advertising = mdio_read(dev, 1, 4); + if ((readl(ioaddr + ChipConfig) & 0xe000) != 0xe000) { + u32 chip_config = readl(ioaddr + ChipConfig); + printk(KERN_INFO "%s: Transceiver default autonegotiation %s " + "10%s %s duplex.\n", + dev->name, + chip_config & 0x2000 ? "enabled, advertise" : "disabled, force", + chip_config & 0x4000 ? "0" : "", + chip_config & 0x8000 ? "full" : "half"); + } printk(KERN_INFO "%s: Transceiver status 0x%4.4x advertising %4.4x.\n", dev->name, (int)readl(ioaddr + 0x84), np->advertising); @@ -522,12 +546,12 @@ static int eeprom_read(long addr, int location) eeprom_delay(ee_addr); } writel(EE_ChipSelect, ee_addr); + eeprom_delay(ee_addr); - for (i = 16; i > 0; i--) { + for (i = 0; i < 16; i++) { writel(EE_ChipSelect | EE_ShiftClk, ee_addr); eeprom_delay(ee_addr); - /* data bits are LSB first */ - retval = (retval >> 1) | ((readl(ee_addr) & EE_DataOut) ? 0x8000 : 0); + retval |= (readl(ee_addr) & EE_DataOut) ? 1 << i : 0; writel(EE_ChipSelect, ee_addr); eeprom_delay(ee_addr); } @@ -550,16 +574,10 @@ static int mdio_read(struct net_device *dev, int phy_id, int location) return 0xffff; } -static void mdio_write(struct net_device *dev, int phy_id, int location, int value) -{ - if (phy_id == 1 && location < 32) - writew(value, dev->base_addr + 0x80 + (location<<2)); -} - static int netdev_open(struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; int i; @@ -586,20 +604,26 @@ static int netdev_open(struct net_device *dev) /* Initialize other registers. */ /* Configure the PCI bus bursts and FIFO thresholds. */ /* Configure for standard, in-spec Ethernet. */ - np->tx_config = (1<<28) + /* Automatic transmit padding */ - (1<<23) + /* Excessive collision retry */ - (0x0<<20) + /* Max DMA burst = 512 byte */ - (8<<8) + /* fill threshold = 256 byte */ - 2; /* drain threshold = 64 byte */ + + if (readl(ioaddr + ChipConfig) & 0x20000000) { /* Full duplex */ + np->tx_config = 0xD0801002; + np->rx_config = 0x10000020; + } else { + np->tx_config = 0x10801002; + np->rx_config = 0x0020; + } writel(np->tx_config, ioaddr + TxConfig); - np->rx_config = (0x0<<20) /* Max DMA burst = 512 byte */ + - (0x8<<1); /* Drain Threshold = 64 byte */ writel(np->rx_config, ioaddr + RxConfig); if (dev->if_port == 0) dev->if_port = np->default_port; - /* Disable PME */ + /* Disable PME: + * The PME bit is initialized from the EEPROM contents. + * PCI cards probably have PME disabled, but motherboard + * implementations may have PME set to enable WakeOnLan. + * With PME set the chip will scan incoming packets but + * nothing will be written to memory. */ np->SavedClkRun = readl(ioaddr + ClkRun); writel(np->SavedClkRun & ~0x100, ioaddr + ClkRun); @@ -608,10 +632,8 @@ static int netdev_open(struct net_device *dev) check_duplex(dev); set_rx_mode(dev); - /* Enable interrupts by setting the interrupt mask. - * We don't listen for TxDone interrupts and rely on TxIdle. */ - writel(IntrAbnormalSummary | IntrTxIdle | IntrRxIdle | IntrRxDone, - ioaddr + IntrMask); + /* Enable interrupts by setting the interrupt mask. */ + writel(IntrNormalSummary | IntrAbnormalSummary | 0x1f, ioaddr + IntrMask); writel(1, ioaddr + IntrEnable); writel(RxOn | TxOn, ioaddr + ChipCmd); @@ -633,7 +655,7 @@ static int netdev_open(struct net_device *dev) static void check_duplex(struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; int duplex; @@ -661,7 +683,7 @@ static void check_duplex(struct net_device *dev) static void netdev_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; int next_tick = 60*HZ; @@ -675,7 +697,7 @@ static void netdev_timer(unsigned long data) static void tx_timeout(struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; printk(KERN_WARNING "%s: Transmit timed out, status %8.8x," @@ -702,14 +724,14 @@ static void tx_timeout(struct net_device *dev) dev->trans_start = jiffies; np->stats.tx_errors++; - netif_start_queue(dev); + netif_wake_queue(dev); } /* Initialize the Rx and Tx rings, along with various 'dev' bits. */ static void init_ring(struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; int i; np->cur_rx = np->cur_tx = 0; @@ -736,7 +758,7 @@ static void init_ring(struct net_device *dev) skb->dev = dev; /* Mark as being used by this device. */ np->rx_ring[i].addr = virt_to_le32desc(skb->tail); np->rx_ring[i].cmd_status = - cpu_to_le32(np->rx_buf_sz); + cpu_to_le32(DescIntr | np->rx_buf_sz); } np->dirty_rx = (unsigned int)(i - RX_RING_SIZE); @@ -751,7 +773,7 @@ static void init_ring(struct net_device *dev) static int start_tx(struct sk_buff *skb, struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; unsigned entry; /* Note: Ordering is important here, set the field with the @@ -763,7 +785,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) np->tx_skbuff[entry] = skb; np->tx_ring[entry].addr = virt_to_le32desc(skb->data); - np->tx_ring[entry].cmd_status = cpu_to_le32(DescOwn | skb->len); + np->tx_ring[entry].cmd_status = cpu_to_le32(DescOwn|DescIntr | skb->len); np->cur_tx++; /* StrongARM: Explicitly cache flush np->tx_ring and skb->data,skb->len. */ @@ -819,7 +841,7 @@ static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) if (intr_status == 0) break; - if (intr_status & (IntrRxDone | IntrRxErr | IntrRxIdle | IntrRxOverrun)) + if (intr_status & (IntrRxDone | IntrRxIntr)) netdev_rx(dev); spin_lock(&np->lock); @@ -886,7 +908,7 @@ static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) for clarity and better register allocation. */ static int netdev_rx(struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; int entry = np->cur_rx % RX_RING_SIZE; int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx; s32 desc_status = le32_to_cpu(np->rx_head_desc->cmd_status); @@ -898,7 +920,6 @@ static int netdev_rx(struct net_device *dev) entry, desc_status); if (--boguscnt < 0) break; - if ((desc_status & (DescMore|DescPktOK|RxTooLong)) != DescPktOK) { if (desc_status & DescMore) { printk(KERN_WARNING "%s: Oversized(?) Ethernet frame spanned " @@ -984,7 +1005,7 @@ static int netdev_rx(struct net_device *dev) np->rx_ring[entry].addr = virt_to_le32desc(skb->tail); } np->rx_ring[entry].cmd_status = - cpu_to_le32(np->rx_buf_sz); + cpu_to_le32(DescIntr | np->rx_buf_sz); } /* Restart Rx engine if stopped. */ @@ -994,7 +1015,7 @@ static int netdev_rx(struct net_device *dev) static void netdev_error(struct net_device *dev, int intr_status) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; if (intr_status & LinkChange) { @@ -1006,7 +1027,17 @@ static void netdev_error(struct net_device *dev, int intr_status) if (intr_status & StatsMax) { get_stats(dev); } - if ((intr_status & ~(LinkChange|StatsMax|RxResetDone|TxResetDone|0x83ff)) + if (intr_status & IntrTxUnderrun) { + if ((np->tx_config & 0x3f) < 62) + np->tx_config += 2; + writel(np->tx_config, ioaddr + TxConfig); + } + if (intr_status & WOLPkt) { + int wol_status = readl(ioaddr + WOLCmd); + printk(KERN_NOTICE "%s: Link wake-up event %8.8x", + dev->name, wol_status); + } + if ((intr_status & ~(LinkChange|StatsMax|RxResetDone|TxResetDone|0xA7ff)) && debug) printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n", dev->name, intr_status); @@ -1020,7 +1051,7 @@ static void netdev_error(struct net_device *dev, int intr_status) static struct net_device_stats *get_stats(struct net_device *dev) { long ioaddr = dev->base_addr; - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; /* We should lock this segment of code for SMP eventually, although the vulnerability window is very small and statistics are @@ -1061,8 +1092,8 @@ static inline unsigned ether_crc_le(int length, unsigned char *data) static void set_rx_mode(struct net_device *dev) { long ioaddr = dev->base_addr; - struct netdev_private *np = (struct netdev_private *)dev->priv; - u16 mc_filter[32]; /* Multicast hash filter */ + struct netdev_private *np = dev->priv; + u8 mc_filter[64]; /* Multicast hash filter */ u32 rx_mode; if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ @@ -1082,18 +1113,19 @@ static void set_rx_mode(struct net_device *dev) set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x1ff, mc_filter); } - for (i = 0; i < 32; i++) { - writew(0x200 + (i<<1), ioaddr + RxFilterAddr); - writew(cpu_to_be16(mc_filter[i]), ioaddr + RxFilterData); - } rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; + for (i = 0; i < 64; i += 2) { + writew(0x200 + i, ioaddr + RxFilterAddr); + writew((mc_filter[i+1]<<8) + mc_filter[i], ioaddr + RxFilterData); + } } - writel(rx_mode | EnableFilter, ioaddr + RxFilterAddr); + writel(rx_mode, ioaddr + RxFilterAddr); np->cur_rx_mode = rx_mode; } static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { + struct netdev_private *np = dev->priv; u16 *data = (u16 *)&rq->ifr_data; switch(cmd) { @@ -1106,7 +1138,20 @@ static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) case SIOCDEVPRIVATE+2: /* Write the specified MII register */ if (!capable(CAP_NET_ADMIN)) return -EPERM; - mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]); + if (data[0] == 1) { + u16 miireg = data[1] & 0x1f; + u16 value = data[2]; + writew(value, dev->base_addr + 0x80 + (miireg << 2)); + switch (miireg) { + case 0: + /* Check for autonegotiation on or reset. */ + np->duplex_lock = (value & 0x9000) ? 0 : 1; + if (np->duplex_lock) + np->full_duplex = (value & 0x0100) ? 1 : 0; + break; + case 4: np->advertising = value; break; + } + } return 0; default: return -EOPNOTSUPP; @@ -1116,7 +1161,7 @@ static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) static int netdev_close(struct net_device *dev) { long ioaddr = dev->base_addr; - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; int i; netif_stop_queue(dev); @@ -1187,14 +1232,13 @@ static int netdev_close(struct net_device *dev) static void __devexit natsemi_remove1 (struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; - struct netdev_private *np = (struct netdev_private *)dev->priv; - const int pcibar = 1; /* PCI base address register */ + struct net_device *dev = pci_get_drvdata(pdev); unregister_netdev (dev); - release_mem_region(pci_resource_start(pdev, pcibar), np->iosize); + pci_release_regions (pdev); iounmap ((char *) dev->base_addr); kfree (dev); + pci_set_drvdata(pdev, NULL); } static struct pci_driver natsemi_driver = { diff --git a/drivers/net/ne.c b/drivers/net/ne.c index 1c362e5c1..cb60613ba 100644 --- a/drivers/net/ne.c +++ b/drivers/net/ne.c @@ -76,13 +76,18 @@ static unsigned int netcard_portlist[] __initdata = { }; #endif -static struct { unsigned short vendor, function; char *name; } -isapnp_clone_list[] __initdata = { - {ISAPNP_VENDOR('E','D','I'), ISAPNP_FUNCTION(0x0216), "NN NE2000" }, - {ISAPNP_VENDOR('P','N','P'), ISAPNP_FUNCTION(0x80d6), "Generic PNP" }, - {0,} +static struct isapnp_device_id isapnp_clone_list[] __initdata = { + { ISAPNP_ANY_ID, ISAPNP_ANY_ID, + ISAPNP_VENDOR('E','D','I'), ISAPNP_FUNCTION(0x0216), + (long) "NN NE2000" }, + { ISAPNP_ANY_ID, ISAPNP_ANY_ID, + ISAPNP_VENDOR('P','N','P'), ISAPNP_FUNCTION(0x80d6), + (long) "Generic PNP" }, + { } /* terminate list */ }; +MODULE_DEVICE_TABLE(isapnp, isapnp_clone_list); + #ifdef SUPPORT_NE_BAD_CLONES /* A list of bad clones that we none-the-less recognize. */ static struct { const char *name8, *name16; unsigned char SAprefix[4];} @@ -206,7 +211,7 @@ static int __init ne_probe_isapnp(struct net_device *dev) dev->base_addr = idev->resource[0].start; dev->irq = idev->irq_resource[0].start; printk(KERN_INFO "ne.c: ISAPnP reports %s at i/o %#lx, irq %d.\n", - isapnp_clone_list[i].name, + (char *) isapnp_clone_list[i].driver_data, dev->base_addr, dev->irq); if (ne_probe1(dev, dev->base_addr) != 0) { /* Shouldn't happen. */ diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c index 8234f838a..755aa1579 100644 --- a/drivers/net/ne2k-pci.c +++ b/drivers/net/ne2k-pci.c @@ -239,7 +239,7 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev, } } - dev = init_etherdev(NULL, 0); + dev = alloc_etherdev(0); if (!dev) { printk (KERN_ERR "ne2k-pci: cannot allocate ethernet device\n"); goto err_out_free_res; @@ -312,17 +312,11 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev, /* Allocate dev->priv and fill in 8390 specific dev fields. */ if (ethdev_init(dev)) { - printk (KERN_ERR "%s: unable to get memory for dev->priv.\n", dev->name); + printk (KERN_ERR "ne2kpci(%s): unable to get memory for dev->priv.\n", + pdev->slot_name); goto err_out_free_netdev; } - printk("%s: %s found at %#lx, IRQ %d, ", - dev->name, pci_clone_list[chip_idx].name, ioaddr, dev->irq); - for(i = 0; i < 6; i++) { - printk("%2.2X%s", SA_prom[i], i == 5 ? ".\n": ":"); - dev->dev_addr[i] = SA_prom[i]; - } - ei_status.name = pci_clone_list[chip_idx].name; ei_status.tx_start_page = start_page; ei_status.stop_page = stop_page; @@ -346,13 +340,27 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev, dev->open = &ne2k_pci_open; dev->stop = &ne2k_pci_close; NS8390_init(dev, 0); + + i = register_netdev(dev); + if (i) + goto err_out_free_8390; + + printk("%s: %s found at %#lx, IRQ %d, ", + dev->name, pci_clone_list[chip_idx].name, ioaddr, dev->irq); + for(i = 0; i < 6; i++) { + printk("%2.2X%s", SA_prom[i], i == 5 ? ".\n": ":"); + dev->dev_addr[i] = SA_prom[i]; + } + return 0; +err_out_free_8390: + kfree(dev->priv); err_out_free_netdev: - unregister_netdev (dev); kfree (dev); err_out_free_res: release_region (ioaddr, NE_IO_EXTENT); + pci_set_drvdata (pdev, NULL); return -ENODEV; } diff --git a/drivers/net/net_init.c b/drivers/net/net_init.c index b95403544..46bea969c 100644 --- a/drivers/net/net_init.c +++ b/drivers/net/net_init.c @@ -28,10 +28,12 @@ up. We now share common code and have regularised name allocation setups. Abolished the 16 card limits. 03/19/2000 - jgarzik and Urban Widmark: init_etherdev 32-byte align + 03/21/2001 - jgarzik: alloc_etherdev and friends */ #include <linux/config.h> +#include <linux/module.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/types.h> @@ -68,6 +70,33 @@ */ +static struct net_device *alloc_netdev(int sizeof_priv, const char *mask, + void (*setup)(struct net_device *)) +{ + struct net_device *dev; + int alloc_size; + + /* ensure 32-byte alignment of the private area */ + alloc_size = sizeof (*dev) + sizeof_priv + 31; + + dev = (struct net_device *) kmalloc (alloc_size, GFP_KERNEL); + if (dev == NULL) + { + printk(KERN_ERR "alloc_dev: Unable to allocate device memory.\n"); + return NULL; + } + + memset(dev, 0, alloc_size); + + if (sizeof_priv) + dev->priv = (void *) (((long)(dev + 1) + 31) & ~31); + + setup(dev); + strcpy(dev->name, mask); + + return dev; +} + static struct net_device *init_alloc_dev(int sizeof_priv) { struct net_device *dev; @@ -142,6 +171,17 @@ static struct net_device *init_netdev(struct net_device *dev, int sizeof_priv, return dev; } +static int __register_netdev(struct net_device *dev) +{ + dev_init_buffers(dev); + + if (dev->init && dev->init(dev) != 0) { + unregister_netdev(dev); + return -EIO; + } + return 0; +} + /** * init_etherdev - Register ethernet device * @dev: An ethernet device structure to be filled in, or %NULL if a new @@ -164,6 +204,25 @@ struct net_device *init_etherdev(struct net_device *dev, int sizeof_priv) return init_netdev(dev, sizeof_priv, "eth%d", ether_setup); } +/** + * alloc_etherdev - Register ethernet device + * @sizeof_priv: Size of additional driver-private structure to be allocated + * for this ethernet device + * + * Fill in the fields of the device structure with ethernet-generic values. + * + * Constructs a new net device, complete with a private data area of + * size @sizeof_priv. A 32-byte (not bit) alignment is enforced for + * this private data area. + */ + +struct net_device *alloc_etherdev(int sizeof_priv) +{ + return alloc_netdev(sizeof_priv, "eth%d", ether_setup); +} + +EXPORT_SYMBOL(init_etherdev); +EXPORT_SYMBOL(alloc_etherdev); static int eth_mac_addr(struct net_device *dev, void *p) { @@ -184,11 +243,48 @@ static int eth_change_mtu(struct net_device *dev, int new_mtu) #ifdef CONFIG_FDDI +/** + * init_fddidev - Register FDDI device + * @dev: A FDDI device structure to be filled in, or %NULL if a new + * struct should be allocated. + * @sizeof_priv: Size of additional driver-private structure to be allocated + * for this ethernet device + * + * Fill in the fields of the device structure with FDDI-generic values. + * + * If no device structure is passed, a new one is constructed, complete with + * a private data area of size @sizeof_priv. A 32-byte (not bit) + * alignment is enforced for this private data area. + * + * If an empty string area is passed as dev->name, or a new structure is made, + * a new name string is constructed. + */ + struct net_device *init_fddidev(struct net_device *dev, int sizeof_priv) { return init_netdev(dev, sizeof_priv, "fddi%d", fddi_setup); } +/** + * alloc_fddidev - Register FDDI device + * @sizeof_priv: Size of additional driver-private structure to be allocated + * for this FDDI device + * + * Fill in the fields of the device structure with FDDI-generic values. + * + * Constructs a new net device, complete with a private data area of + * size @sizeof_priv. A 32-byte (not bit) alignment is enforced for + * this private data area. + */ + +struct net_device *alloc_fddidev(int sizeof_priv) +{ + return alloc_netdev(sizeof_priv, "fddi%d", fddi_setup); +} + +EXPORT_SYMBOL(init_fddidev); +EXPORT_SYMBOL(alloc_fddidev); + static int fddi_change_mtu(struct net_device *dev, int new_mtu) { if ((new_mtu < FDDI_K_SNAP_HLEN) || (new_mtu > FDDI_K_SNAP_DLEN)) @@ -227,19 +323,59 @@ static int hippi_mac_addr(struct net_device *dev, void *p) } +/** + * init_hippi_dev - Register HIPPI device + * @dev: A HIPPI device structure to be filled in, or %NULL if a new + * struct should be allocated. + * @sizeof_priv: Size of additional driver-private structure to be allocated + * for this ethernet device + * + * Fill in the fields of the device structure with HIPPI-generic values. + * + * If no device structure is passed, a new one is constructed, complete with + * a private data area of size @sizeof_priv. A 32-byte (not bit) + * alignment is enforced for this private data area. + * + * If an empty string area is passed as dev->name, or a new structure is made, + * a new name string is constructed. + */ + struct net_device *init_hippi_dev(struct net_device *dev, int sizeof_priv) { return init_netdev(dev, sizeof_priv, "hip%d", hippi_setup); } +/** + * alloc_hippi_dev - Register HIPPI device + * @sizeof_priv: Size of additional driver-private structure to be allocated + * for this HIPPI device + * + * Fill in the fields of the device structure with HIPPI-generic values. + * + * Constructs a new net device, complete with a private data area of + * size @sizeof_priv. A 32-byte (not bit) alignment is enforced for + * this private data area. + */ + +struct net_device *alloc_hippi_dev(int sizeof_priv) +{ + return alloc_netdev(sizeof_priv, "hip%d", hippi_setup); +} + +int register_hipdev(struct net_device *dev) +{ + return __register_netdev(dev); +} void unregister_hipdev(struct net_device *dev) { - rtnl_lock(); - unregister_netdevice(dev); - rtnl_unlock(); + unregister_netdev(dev); } +EXPORT_SYMBOL(init_hippi_dev); +EXPORT_SYMBOL(alloc_hippi_dev); +EXPORT_SYMBOL(register_hipdev); +EXPORT_SYMBOL(unregister_hipdev); static int hippi_neigh_setup_dev(struct net_device *dev, struct neigh_parms *p) { @@ -283,6 +419,7 @@ void ether_setup(struct net_device *dev) dev_init_buffers(dev); } +EXPORT_SYMBOL(ether_setup); #ifdef CONFIG_FDDI @@ -312,6 +449,7 @@ void fddi_setup(struct net_device *dev) return; } +EXPORT_SYMBOL(fddi_setup); #endif /* CONFIG_FDDI */ @@ -349,6 +487,7 @@ void hippi_setup(struct net_device *dev) dev_init_buffers(dev); } +EXPORT_SYMBOL(hippi_setup); #endif /* CONFIG_HIPPI */ #if defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE) @@ -387,26 +526,10 @@ void ltalk_setup(struct net_device *dev) dev_init_buffers(dev); } +EXPORT_SYMBOL(ltalk_setup); #endif /* CONFIG_ATALK || CONFIG_ATALK_MODULE */ -int ether_config(struct net_device *dev, struct ifmap *map) -{ - if (map->mem_start != (u_long)(-1)) - dev->mem_start = map->mem_start; - if (map->mem_end != (u_long)(-1)) - dev->mem_end = map->mem_end; - if (map->base_addr != (u_short)(-1)) - dev->base_addr = map->base_addr; - if (map->irq != (u_char)(-1)) - dev->irq = map->irq; - if (map->dma != (u_char)(-1)) - dev->dma = map->dma; - if (map->port != (u_char)(-1)) - dev->if_port = map->port; - return 0; -} - int register_netdev(struct net_device *dev) { int err; @@ -420,8 +543,8 @@ int register_netdev(struct net_device *dev) if (strchr(dev->name, '%')) { - err = -EBUSY; - if(dev_alloc_name(dev, dev->name)<0) + err = dev_alloc_name(dev, dev->name); + if (err < 0) goto out; } @@ -431,17 +554,12 @@ int register_netdev(struct net_device *dev) if (dev->name[0]==0 || dev->name[0]==' ') { - err = -EBUSY; - if(dev_alloc_name(dev, "eth%d")<0) + err = dev_alloc_name(dev, "eth%d"); + if (err < 0) goto out; } - - - err = -EIO; - if (register_netdevice(dev)) - goto out; - err = 0; + err = register_netdevice(dev); out: rtnl_unlock(); @@ -455,10 +573,12 @@ void unregister_netdev(struct net_device *dev) rtnl_unlock(); } +EXPORT_SYMBOL(register_netdev); +EXPORT_SYMBOL(unregister_netdev); #ifdef CONFIG_TR -static void tr_configure(struct net_device *dev) +void tr_setup(struct net_device *dev) { /* * Configure and register @@ -479,32 +599,61 @@ static void tr_configure(struct net_device *dev) dev->flags = IFF_BROADCAST | IFF_MULTICAST ; } +/** + * init_trdev - Register token ring device + * @dev: A token ring device structure to be filled in, or %NULL if a new + * struct should be allocated. + * @sizeof_priv: Size of additional driver-private structure to be allocated + * for this ethernet device + * + * Fill in the fields of the device structure with token ring-generic values. + * + * If no device structure is passed, a new one is constructed, complete with + * a private data area of size @sizeof_priv. A 32-byte (not bit) + * alignment is enforced for this private data area. + * + * If an empty string area is passed as dev->name, or a new structure is made, + * a new name string is constructed. + */ + struct net_device *init_trdev(struct net_device *dev, int sizeof_priv) { - return init_netdev(dev, sizeof_priv, "tr%d", tr_configure); + return init_netdev(dev, sizeof_priv, "tr%d", tr_setup); } -void tr_setup(struct net_device *dev) +/** + * alloc_trdev - Register token ring device + * @sizeof_priv: Size of additional driver-private structure to be allocated + * for this token ring device + * + * Fill in the fields of the device structure with token ring-generic values. + * + * Constructs a new net device, complete with a private data area of + * size @sizeof_priv. A 32-byte (not bit) alignment is enforced for + * this private data area. + */ + +struct net_device *alloc_trdev(int sizeof_priv) { + return alloc_netdev(sizeof_priv, "tr%d", tr_setup); } int register_trdev(struct net_device *dev) { - dev_init_buffers(dev); - - if (dev->init && dev->init(dev) != 0) { - unregister_trdev(dev); - return -EIO; - } - return 0; + return __register_netdev(dev); } void unregister_trdev(struct net_device *dev) { - rtnl_lock(); - unregister_netdevice(dev); - rtnl_unlock(); + unregister_netdev(dev); } + +EXPORT_SYMBOL(tr_setup); +EXPORT_SYMBOL(init_trdev); +EXPORT_SYMBOL(alloc_trdev); +EXPORT_SYMBOL(register_trdev); +EXPORT_SYMBOL(unregister_trdev); + #endif /* CONFIG_TR */ @@ -526,31 +675,62 @@ void fc_setup(struct net_device *dev) /* New-style flags. */ dev->flags = IFF_BROADCAST; dev_init_buffers(dev); - return; } +/** + * init_fcdev - Register fibre channel device + * @dev: A fibre channel device structure to be filled in, or %NULL if a new + * struct should be allocated. + * @sizeof_priv: Size of additional driver-private structure to be allocated + * for this ethernet device + * + * Fill in the fields of the device structure with fibre channel-generic values. + * + * If no device structure is passed, a new one is constructed, complete with + * a private data area of size @sizeof_priv. A 32-byte (not bit) + * alignment is enforced for this private data area. + * + * If an empty string area is passed as dev->name, or a new structure is made, + * a new name string is constructed. + */ struct net_device *init_fcdev(struct net_device *dev, int sizeof_priv) { return init_netdev(dev, sizeof_priv, "fc%d", fc_setup); } +/** + * alloc_fcdev - Register fibre channel device + * @sizeof_priv: Size of additional driver-private structure to be allocated + * for this fibre channel device + * + * Fill in the fields of the device structure with fibre channel-generic values. + * + * Constructs a new net device, complete with a private data area of + * size @sizeof_priv. A 32-byte (not bit) alignment is enforced for + * this private data area. + */ + +struct net_device *alloc_fcdev(int sizeof_priv) +{ + return alloc_netdev(sizeof_priv, "fc%d", fc_setup); +} + int register_fcdev(struct net_device *dev) { - dev_init_buffers(dev); - if (dev->init && dev->init(dev) != 0) { - unregister_fcdev(dev); - return -EIO; - } - return 0; + return __register_netdev(dev); } void unregister_fcdev(struct net_device *dev) { - rtnl_lock(); - unregister_netdevice(dev); - rtnl_unlock(); + unregister_netdev(dev); } +EXPORT_SYMBOL(fc_setup); +EXPORT_SYMBOL(init_fcdev); +EXPORT_SYMBOL(alloc_fcdev); +EXPORT_SYMBOL(register_fcdev); +EXPORT_SYMBOL(unregister_fcdev); + #endif /* CONFIG_NET_FC */ diff --git a/drivers/net/ni5010.c b/drivers/net/ni5010.c index 2eb5f7d1e..c5f91937c 100644 --- a/drivers/net/ni5010.c +++ b/drivers/net/ni5010.c @@ -469,7 +469,7 @@ static void ni5010_interrupt(int irq, void *dev_id, struct pt_regs *regs) } if ((status & IS_DMA_INT) == 0) { - PRINTK((KERN_DEBUG "%s: DMA complete (???)\n", dev->name)); + PRINTK((KERN_DEBUG "%s: DMA complete (?)\n", dev->name)); outb(0, IE_DMA_RST); /* Reset DMA int */ } diff --git a/drivers/net/ni52.h b/drivers/net/ni52.h index 24d6d8d4c..68f19175a 100644 --- a/drivers/net/ni52.h +++ b/drivers/net/ni52.h @@ -68,7 +68,7 @@ struct scb_struct unsigned short cbl_offset; /* pointeroffset, command block list */ unsigned short rfa_offset; /* pointeroffset, receive frame area */ unsigned short crc_errs; /* CRC-Error counter */ - unsigned short aln_errs; /* allignmenterror counter */ + unsigned short aln_errs; /* alignmenterror counter */ unsigned short rsc_errs; /* Resourceerror counter */ unsigned short ovrn_errs; /* OVerrunerror counter */ }; diff --git a/drivers/net/oaknet.c b/drivers/net/oaknet.c index 9455d6453..1a5a53981 100644 --- a/drivers/net/oaknet.c +++ b/drivers/net/oaknet.c @@ -53,7 +53,7 @@ static const char *name = "National DP83902AV"; -static struct net_device *oaknet_devs = NULL; +static struct net_device *oaknet_devs; /* Function Prototypes */ @@ -94,6 +94,7 @@ static int __init oaknet_init(void) { register int i; int reg0, regd; + int ret; struct net_device tmp, *dev = NULL; #if 0 unsigned long ioaddr = OAKNET_IO_BASE; @@ -102,6 +103,8 @@ static int __init oaknet_init(void) #endif bd_t *bip = (bd_t *)__res; + if (!ioaddr) + return -ENOMEM; /* * This MUST happen here because of the nic_* macros * which have an implicit dependency on dev->base_addr. @@ -110,15 +113,15 @@ static int __init oaknet_init(void) tmp.base_addr = ioaddr; dev = &tmp; + ret = -EBUSY; if (!request_region(OAKNET_IO_BASE, OAKNET_IO_SIZE, name)) - return -EBUSY; + goto out_unmap; /* Quick register check to see if the device is really there. */ - if ((reg0 = ei_ibp(ioaddr)) == 0xFF) { - release_region(OAKNET_IO_BASE, OAKNET_IO_SIZE); - return (ENODEV); - } + ret = -ENODEV; + if ((reg0 = ei_ibp(ioaddr)) == 0xFF) + goto out_region; /* * That worked. Now a more thorough check, using the multicast @@ -134,13 +137,11 @@ static int __init oaknet_init(void) /* It's no good. Fix things back up and leave. */ + ret = -ENODEV; if (ei_ibp(ioaddr + EN0_COUNTER0) != 0) { ei_obp(reg0, ioaddr); ei_obp(regd, ioaddr + 0x0D); - dev->base_addr = 0; - - release_region(dev->base_addr, OAKNET_IO_SIZE); - return (-ENODEV); + goto out_region; } /* @@ -149,10 +150,9 @@ static int __init oaknet_init(void) */ dev = init_etherdev(NULL, 0); - if (!dev) { - release_region(dev->base_addr, OAKNET_IO_SIZE); - return (-ENOMEM); - } + ret = -ENOMEM; + if (!dev) + goto out_region; SET_MODULE_OWNER(dev); oaknet_devs = dev; @@ -166,10 +166,10 @@ static int __init oaknet_init(void) /* Allocate 8390-specific device-private area and fields. */ + ret = -ENOMEM; if (ethdev_init(dev)) { printk(" unable to get memory for dev->priv.\n"); - release_region(dev->base_addr, OAKNET_IO_SIZE); - return (-ENOMEM); + goto out_dev; } /* @@ -182,12 +182,11 @@ static int __init oaknet_init(void) /* Attempt to get the interrupt line */ + ret = -EAGAIN; if (request_irq(dev->irq, ei_interrupt, 0, name, dev)) { printk("%s: unable to request interrupt %d.\n", dev->name, dev->irq); - kfree(dev->priv); - release_region(dev->base_addr, OAKNET_IO_SIZE); - return (EAGAIN); + goto out_priv; } /* Tell the world about what and where we've found. */ @@ -218,6 +217,16 @@ static int __init oaknet_init(void) NS8390_init(dev, FALSE); return (0); +out_priv: + kfree(dev->priv); +out_dev: + unregister_netdev(dev); + kfree(dev); +out_region: + release_region(OAKNET_IO_BASE, OAKNET_IO_SIZE); +out_unmap: + iounmap(ioaddr); + return ret; } /* @@ -303,8 +312,6 @@ oaknet_reset_8390(struct net_device *dev) ei_obp(E8390_STOP | E8390_NODMA | E8390_PAGE0, base + E8390_CMD); ei_status.txing = 0; ei_status.dmaing = 0; - - return; } /* @@ -365,8 +372,6 @@ oaknet_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, outb_p(ENISR_RDC, base + EN0_ISR); /* ACK Remote DMA interrupt */ ei_status.dmaing &= ~0x01; - - return; } /* @@ -444,8 +449,6 @@ oaknet_block_input(struct net_device *dev, int count, struct sk_buff *skb, #ifdef OAKNET_DISINT restore_flags(flags); #endif - - return; } /* @@ -627,8 +630,6 @@ retry: ei_obp(ENISR_RDC, base + EN0_ISR); /* Ack intr. */ ei_status.dmaing &= ~0x01; - - return; } /* @@ -636,7 +637,7 @@ retry: * * Description: * This routine prints out a last-ditch informative message to the console - * indicating that a DMA error occured. If you see this, it's the last + * indicating that a DMA error occurred. If you see this, it's the last * thing you'll see. * * Input(s): @@ -658,8 +659,6 @@ oaknet_dma_error(struct net_device *dev, const char *name) "[DMAstat:%d][irqlock:%d][intr:%ld]\n", dev->name, name, ei_status.dmaing, ei_status.irqlock, dev->interrupt); - - return; } /* @@ -686,12 +685,13 @@ static void __exit oaknet_cleanup_module (void) void *priv = oaknet_devs->priv; free_irq(oaknet_devs->irq, oaknet_devs); release_region(ioaddr, OAKNET_IO_SIZE); + iounmap(ioaddr); unregister_netdev(oaknet_dev); kfree(priv); } - oaknet_devs = NULL; - + /* Convert to loop once driver supports multiple devices. */ + kfree(oaknet_devs); } module_init(oaknet_init_module); diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c index 5e89874b7..c9fa18d4d 100644 --- a/drivers/net/pci-skeleton.c +++ b/drivers/net/pci-skeleton.c @@ -504,7 +504,7 @@ static int netdrv_start_xmit (struct sk_buff *skb, static void netdrv_interrupt (int irq, void *dev_instance, struct pt_regs *regs); static int netdrv_close (struct net_device *dev); -static int mii_ioctl (struct net_device *dev, struct ifreq *rq, int cmd); +static int netdrv_ioctl (struct net_device *dev, struct ifreq *rq, int cmd); static struct net_device_stats *netdrv_get_stats (struct net_device *dev); static inline u32 ether_crc (int length, unsigned char *data); static void netdrv_set_rx_mode (struct net_device *dev); @@ -600,7 +600,7 @@ static int __devinit netdrv_init_board (struct pci_dev *pdev, *dev_out = NULL; /* dev zeroed in init_etherdev */ - dev = init_etherdev (NULL, sizeof (*tp)); + dev = alloc_etherdev (sizeof (*tp)); if (dev == NULL) { printk (KERN_ERR PFX "unable to alloc new ethernet\n"); DPRINTK ("EXIT, returning -ENOMEM\n"); @@ -609,6 +609,11 @@ static int __devinit netdrv_init_board (struct pci_dev *pdev, SET_MODULE_OWNER(dev); tp = dev->priv; + /* enable device (incl. PCI PM wakeup), and bus-mastering */ + rc = pci_enable_device (pdev); + if (rc) + goto err_out; + pio_start = pci_resource_start (pdev, 0); pio_end = pci_resource_end (pdev, 0); pio_flags = pci_resource_flags (pdev, 0); @@ -623,8 +628,6 @@ static int __devinit netdrv_init_board (struct pci_dev *pdev, * we talk to the chip directly */ DPRINTK("PIO region size == 0x%02X\n", pio_len); DPRINTK("MMIO region size == 0x%02lX\n", mmio_len); - if (pio_len == RTL8139B_IO_SIZE) - tp->chipset = CH_8139B; /* make sure PCI base addr 0 is PIO */ if (!(pio_flags & IORESOURCE_IO)) { @@ -648,24 +651,9 @@ static int __devinit netdrv_init_board (struct pci_dev *pdev, goto err_out; } - /* make sure our PIO region in PCI space is available */ - if (!request_region (pio_start, pio_len, dev->name)) { - printk (KERN_ERR PFX "no I/O resource available, aborting\n"); - rc = -EBUSY; - goto err_out; - } - - /* make sure our MMIO region in PCI space is available */ - if (!request_mem_region (mmio_start, mmio_len, dev->name)) { - printk (KERN_ERR PFX "no mem resource available, aborting\n"); - rc = -EBUSY; - goto err_out_free_pio; - } - - /* enable device (incl. PCI PM wakeup), and bus-mastering */ - rc = pci_enable_device (pdev); + rc = pci_request_regions (pdev, "pci-skeleton"); if (rc) - goto err_out_free_mmio; + goto err_out; pci_set_master (pdev); @@ -677,7 +665,7 @@ static int __devinit netdrv_init_board (struct pci_dev *pdev, if (ioaddr == NULL) { printk (KERN_ERR PFX "cannot remap MMIO, aborting\n"); rc = -EIO; - goto err_out_free_mmio; + goto err_out_free_res; } #endif /* USE_IO_OPS */ @@ -692,14 +680,7 @@ static int __devinit netdrv_init_board (struct pci_dev *pdev, udelay (10); /* Bring the chip out of low-power mode. */ - if (tp->chipset == CH_8139B) { - NETDRV_W8 (Config1, NETDRV_R8 (Config1) & ~(1<<4)); - NETDRV_W8 (Config4, NETDRV_R8 (Config4) & ~(1<<2)); - } else { - /* handle RTL8139A and RTL8139 cases */ - /* XXX from becker driver. is this right?? */ - NETDRV_W8 (Config1, 0); - } + /* <insert device-specific code here> */ #ifndef USE_IO_OPS /* sanity checks -- ensure PIO and MMIO registers agree */ @@ -709,19 +690,6 @@ static int __devinit netdrv_init_board (struct pci_dev *pdev, assert (inb (pio_start+RxConfig) == readb (ioaddr+RxConfig)); #endif /* !USE_IO_OPS */ - /* make sure chip thinks PIO and MMIO are enabled */ - tmp8 = NETDRV_R8 (Config1); - if ((tmp8 & Cfg1_PIO) == 0) { - printk (KERN_ERR PFX "PIO not enabled, Cfg1=%02X, aborting\n", tmp8); - rc = -EIO; - goto err_out_iounmap; - } - if ((tmp8 & Cfg1_MMIO) == 0) { - printk (KERN_ERR PFX "MMIO not enabled, Cfg1=%02X, aborting\n", tmp8); - rc = -EIO; - goto err_out_iounmap; - } - /* identify chip attached to board */ tmp = NETDRV_R8 (ChipVersion); for (i = ARRAY_SIZE (rtl_chip_info) - 1; i >= 0; i--) @@ -742,22 +710,22 @@ match: tp->chipset, rtl_chip_info[tp->chipset].name); + i = register_netdev (dev); + if (i) + goto err_out_unmap; + DPRINTK ("EXIT, returning 0\n"); *ioaddr_out = ioaddr; *dev_out = dev; return 0; -err_out_iounmap: - assert (ioaddr > 0); +err_out_unmap: #ifndef USE_IO_OPS - iounmap (ioaddr); -#endif /* !USE_IO_OPS */ -err_out_free_mmio: - release_mem_region (mmio_start, mmio_len); -err_out_free_pio: - release_region (pio_start, pio_len); + iounmap(ioaddr); +err_out_free_res: +#endif + pci_release_regions (pdev); err_out: - unregister_netdev (dev); kfree (dev); DPRINTK ("EXIT, returning %d\n", rc); return rc; @@ -810,7 +778,7 @@ static int __devinit netdrv_init_one (struct pci_dev *pdev, dev->stop = netdrv_close; dev->get_stats = netdrv_get_stats; dev->set_multicast_list = netdrv_set_rx_mode; - dev->do_ioctl = mii_ioctl; + dev->do_ioctl = netdrv_ioctl; dev->tx_timeout = netdrv_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; @@ -828,7 +796,7 @@ static int __devinit netdrv_init_one (struct pci_dev *pdev, tp->mmio_addr = ioaddr; tp->lock = SPIN_LOCK_UNLOCKED; - pdev->driver_data = dev; + pci_set_drvdata(pdev, dev); tp->phys[0] = 32; @@ -849,12 +817,6 @@ static int __devinit netdrv_init_one (struct pci_dev *pdev, /* Put the chip into low-power mode. */ NETDRV_W8_F (Cfg9346, Cfg9346_Unlock); - tmp = NETDRV_R8 (Config1) & Config1Clear; - tmp |= (tp->chipset == CH_8139B) ? 3 : 1; /* Enable PM/VPD */ - NETDRV_W8_F (Config1, tmp); - - NETDRV_W8_F (HltClk, 'H'); /* 'R' would leave the clock running. */ - /* The lower four bits are the media type. */ option = (board_idx > 7) ? 0 : media[board_idx]; if (option > 0) { @@ -879,14 +841,14 @@ static int __devinit netdrv_init_one (struct pci_dev *pdev, static void __devexit netdrv_remove_one (struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; + struct net_device *dev = pci_get_drvdata (pdev); struct netdrv_private *np; DPRINTK ("ENTER\n"); assert (dev != NULL); - np = (struct netdrv_private *) (dev->priv); + np = dev->priv; assert (np != NULL); unregister_netdev (dev); @@ -895,10 +857,7 @@ static void __devexit netdrv_remove_one (struct pci_dev *pdev) iounmap (np->mmio_addr); #endif /* !USE_IO_OPS */ - release_region (pci_resource_start (pdev, 0), - pci_resource_len (pdev, 0)); - release_mem_region (pci_resource_start (pdev, 1), - pci_resource_len (pdev, 1)); + pci_release_regions (pdev); #ifndef NETDRV_NDEBUG /* poison memory before freeing */ @@ -909,7 +868,7 @@ static void __devexit netdrv_remove_one (struct pci_dev *pdev) kfree (dev); - pdev->driver_data = NULL; + pci_set_drvdata (pdev, NULL); pci_power_off (pdev, -1); @@ -1029,7 +988,7 @@ static void mdio_sync (void *mdio_addr) static int mdio_read (struct net_device *dev, int phy_id, int location) { - struct netdrv_private *tp = (struct netdrv_private *) dev->priv; + struct netdrv_private *tp = dev->priv; void *mdio_addr = tp->mmio_addr + Config4; int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location; int retval = 0; @@ -1072,7 +1031,7 @@ static int mdio_read (struct net_device *dev, int phy_id, int location) static void mdio_write (struct net_device *dev, int phy_id, int location, int value) { - struct netdrv_private *tp = (struct netdrv_private *) dev->priv; + struct netdrv_private *tp = dev->priv; void *mdio_addr = tp->mmio_addr + Config4; int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location << 18) | value; @@ -1115,7 +1074,7 @@ static void mdio_write (struct net_device *dev, int phy_id, int location, static int netdrv_open (struct net_device *dev) { - struct netdrv_private *tp = (struct netdrv_private *) dev->priv; + struct netdrv_private *tp = dev->priv; int retval; #ifdef NETDRV_DEBUG void *ioaddr = tp->mmio_addr; @@ -1176,7 +1135,7 @@ static int netdrv_open (struct net_device *dev) /* Start the hardware at open or resume. */ static void netdrv_hw_start (struct net_device *dev) { - struct netdrv_private *tp = (struct netdrv_private *) dev->priv; + struct netdrv_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; u32 i; u8 tmp; @@ -1213,27 +1172,6 @@ static void netdrv_hw_start (struct net_device *dev) tp->cur_rx = 0; - if (tp->chipset >= CH_8139A) { - tmp = NETDRV_R8 (Config1) & Config1Clear; - tmp |= Cfg1_Driver_Load; - tmp |= (tp->chipset == CH_8139B) ? 3 : 1; /* Enable PM/VPD */ - NETDRV_W8_F (Config1, tmp); - } else { - u8 foo = NETDRV_R8 (Config1) & Config1Clear; - NETDRV_W8 (Config1, tp->full_duplex ? (foo|0x60) : (foo|0x20)); - } - - if (tp->chipset >= CH_8139B) { - tmp = NETDRV_R8 (Config4) & ~(1<<2); - /* chip will clear Rx FIFO overflow automatically */ - tmp |= (1<<7); - NETDRV_W8 (Config4, tmp); - - /* disable magic packet scanning, which is enabled - * when PM is enabled above (Config1) */ - NETDRV_W8 (Config3, NETDRV_R8 (Config3) & ~(1<<5)); - } - /* Lock Config[01234] and BMCR register writes */ NETDRV_W8_F (Cfg9346, Cfg9346_Lock); udelay (10); @@ -1268,7 +1206,7 @@ static void netdrv_hw_start (struct net_device *dev) /* Initialize the Rx and Tx rings, along with various 'dev' bits. */ static void netdrv_init_ring (struct net_device *dev) { - struct netdrv_private *tp = (struct netdrv_private *) dev->priv; + struct netdrv_private *tp = dev->priv; int i; DPRINTK ("ENTER\n"); @@ -1287,104 +1225,10 @@ static void netdrv_init_ring (struct net_device *dev) } -#ifndef NETDRV_TUNE_TWISTER -static inline void netdrv_tune_twister (struct net_device *dev, - struct netdrv_private *tp) {} -#else -static void netdrv_tune_twister (struct net_device *dev, - struct netdrv_private *tp) -{ - int linkcase; - - DPRINTK ("ENTER\n"); - - /* This is a complicated state machine to configure the "twister" for - impedance/echos based on the cable length. - All of this is magic and undocumented. - */ - switch (tp->twistie) { - case 1: - if (NETDRV_R16 (CSCR) & CSCR_LinkOKBit) { - /* We have link beat, let us tune the twister. */ - NETDRV_W16 (CSCR, CSCR_LinkDownOffCmd); - tp->twistie = 2; /* Change to state 2. */ - next_tick = HZ / 10; - } else { - /* Just put in some reasonable defaults for when beat returns. */ - NETDRV_W16 (CSCR, CSCR_LinkDownCmd); - NETDRV_W32 (FIFOTMS, 0x20); /* Turn on cable test mode. */ - NETDRV_W32 (PARA78, PARA78_default); - NETDRV_W32 (PARA7c, PARA7c_default); - tp->twistie = 0; /* Bail from future actions. */ - } - break; - case 2: - /* Read how long it took to hear the echo. */ - linkcase = NETDRV_R16 (CSCR) & CSCR_LinkStatusBits; - if (linkcase == 0x7000) - tp->twist_row = 3; - else if (linkcase == 0x3000) - tp->twist_row = 2; - else if (linkcase == 0x1000) - tp->twist_row = 1; - else - tp->twist_row = 0; - tp->twist_col = 0; - tp->twistie = 3; /* Change to state 2. */ - next_tick = HZ / 10; - break; - case 3: - /* Put out four tuning parameters, one per 100msec. */ - if (tp->twist_col == 0) - NETDRV_W16 (FIFOTMS, 0); - NETDRV_W32 (PARA7c, param[(int) tp->twist_row] - [(int) tp->twist_col]); - next_tick = HZ / 10; - if (++tp->twist_col >= 4) { - /* For short cables we are done. - For long cables (row == 3) check for mistune. */ - tp->twistie = - (tp->twist_row == 3) ? 4 : 0; - } - break; - case 4: - /* Special case for long cables: check for mistune. */ - if ((NETDRV_R16 (CSCR) & - CSCR_LinkStatusBits) == 0x7000) { - tp->twistie = 0; - break; - } else { - NETDRV_W32 (PARA7c, 0xfb38de03); - tp->twistie = 5; - next_tick = HZ / 10; - } - break; - case 5: - /* Retune for shorter cable (column 2). */ - NETDRV_W32 (FIFOTMS, 0x20); - NETDRV_W32 (PARA78, PARA78_default); - NETDRV_W32 (PARA7c, PARA7c_default); - NETDRV_W32 (FIFOTMS, 0x00); - tp->twist_row = 2; - tp->twist_col = 0; - tp->twistie = 3; - next_tick = HZ / 10; - break; - - default: - /* do nothing */ - break; - } - - DPRINTK ("EXIT\n"); -} -#endif /* NETDRV_TUNE_TWISTER */ - - static void netdrv_timer (unsigned long data) { struct net_device *dev = (struct net_device *) data; - struct netdrv_private *tp = (struct netdrv_private *) dev->priv; + struct netdrv_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; int next_tick = 60 * HZ; int mii_reg5; @@ -1407,8 +1251,6 @@ static void netdrv_timer (unsigned long data) } } - netdrv_tune_twister (dev, tp); - DPRINTK ("%s: Media selection tick, Link partner %4.4x.\n", dev->name, NETDRV_R16 (NWayLPAR)); DPRINTK ("%s: Other registers are IntMask %4.4x IntStatus %4.4x" @@ -1451,7 +1293,7 @@ static void netdrv_tx_clear (struct netdrv_private *tp) static void netdrv_tx_timeout (struct net_device *dev) { - struct netdrv_private *tp = (struct netdrv_private *) dev->priv; + struct netdrv_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; int i; u8 tmp8; @@ -1498,7 +1340,7 @@ static void netdrv_tx_timeout (struct net_device *dev) static int netdrv_start_xmit (struct sk_buff *skb, struct net_device *dev) { - struct netdrv_private *tp = (struct netdrv_private *) dev->priv; + struct netdrv_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; int entry; @@ -1713,18 +1555,6 @@ static void netdrv_rx_interrupt (struct net_device *dev, } #endif - /* E. Gill */ - /* Note from BSD driver: - * Here's a totally undocumented fact for you. When the - * RealTek chip is in the process of copying a packet into - * RAM for you, the length will be 0xfff0. If you spot a - * packet header with this value, you need to stop. The - * datasheet makes absolutely no mention of this and - * RealTek should be shot for this. - */ - if (rx_size == 0xfff0) - break; - /* If Rx err or invalid rx_size/rx_status received * (which happens if we get lost in the ring), * Rx process gets reset, so we abort any further @@ -1839,7 +1669,7 @@ static void netdrv_interrupt (int irq, void *dev_instance, struct pt_regs *regs) { struct net_device *dev = (struct net_device *) dev_instance; - struct netdrv_private *tp = (struct netdrv_private *) dev->priv; + struct netdrv_private *tp = dev->priv; int boguscnt = max_interrupt_work; void *ioaddr = tp->mmio_addr; int status = 0, link_changed = 0; /* avoid bogus "uninit" warning */ @@ -1853,31 +1683,8 @@ static void netdrv_interrupt (int irq, void *dev_instance, if (status == 0xFFFF) break; - /* Acknowledge all of the current interrupt sources ASAP, but - an first get an additional status bit from CSCR. */ - if (status & RxUnderrun) - link_changed = NETDRV_R16 (CSCR) & CSCR_LinkChangeBit; - - /* E. Gill */ - /* In case of an RxFIFOOver we must also clear the RxOverflow - bit to avoid dropping frames for ever. Believe me, I got a - lot of troubles copying huge data (approximately 2 RxFIFOOver - errors per 1GB data transfer). - The following is written in the 'p-guide.pdf' file (RTL8139(A/B) - Programming guide V0.1, from 1999/1/15) on page 9 from REALTEC. - ----------------------------------------------------------- - 2. RxFIFOOvw handling: - When RxFIFOOvw occurs, all incoming packets are discarded. - Clear ISR(RxFIFOOvw) doesn't dismiss RxFIFOOvw event. To - dismiss RxFIFOOvw event, the ISR(RxBufOvw) must be written - with a '1'. - ----------------------------------------------------------- - Unfortunately I was not able to find any reason for the - RxFIFOOver error (I got the feeling this depends on the - CPU speed, lower CPU speed --> more errors). - After clearing the RxOverflow bit the transfer of the - packet was repeated and all data are error free transfered */ - NETDRV_W16_F (IntrStatus, (status & RxFIFOOver) ? (status | RxOverflow) : status); + /* Acknowledge all of the current interrupt sources ASAP */ + NETDRV_W16_F (IntrStatus, status); DPRINTK ("%s: interrupt status=%#4.4x new intstat=%#4.4x.\n", dev->name, status, @@ -1922,7 +1729,7 @@ static void netdrv_interrupt (int irq, void *dev_instance, static int netdrv_close (struct net_device *dev) { - struct netdrv_private *tp = (struct netdrv_private *) dev->priv; + struct netdrv_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; unsigned long flags; @@ -1964,16 +1771,16 @@ static int netdrv_close (struct net_device *dev) /* Green! Put the chip in low-power mode. */ NETDRV_W8 (Cfg9346, Cfg9346_Unlock); NETDRV_W8 (Config1, 0x03); - NETDRV_W8 (HltClk, 'H'); /* 'R' would leave the clock running. */ + NETDRV_W8 (Cfg9346, Cfg9346_Lock); DPRINTK ("EXIT\n"); return 0; } -static int mii_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) +static int netdrv_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) { - struct netdrv_private *tp = (struct netdrv_private *) dev->priv; + struct netdrv_private *tp = dev->priv; u16 *data = (u16 *) & rq->ifr_data; unsigned long flags; int rc = 0; @@ -2014,7 +1821,7 @@ static int mii_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) static struct net_device_stats *netdrv_get_stats (struct net_device *dev) { - struct netdrv_private *tp = (struct netdrv_private *) dev->priv; + struct netdrv_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; DPRINTK ("ENTER\n"); @@ -2062,7 +1869,7 @@ static inline u32 ether_crc (int length, unsigned char *data) static void netdrv_set_rx_mode (struct net_device *dev) { - struct netdrv_private *tp = (struct netdrv_private *) dev->priv; + struct netdrv_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; u32 mc_filter[2]; /* Multicast hash filter */ int i, rx_mode; @@ -2117,11 +1924,13 @@ static void netdrv_set_rx_mode (struct net_device *dev) static void netdrv_suspend (struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; - struct netdrv_private *tp = (struct netdrv_private *) dev->priv; + struct net_device *dev = pci_get_drvdata (pdev); + struct netdrv_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; unsigned long flags; + if (!netif_running(dev)) + return; netif_device_detach (dev); spin_lock_irqsave (&tp->lock, flags); @@ -2142,8 +1951,10 @@ static void netdrv_suspend (struct pci_dev *pdev) static void netdrv_resume (struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; + struct net_device *dev = pci_get_drvdata (pdev); + if (!netif_running(dev)) + return; pci_power_on (pdev); netif_device_attach (dev); netdrv_hw_start (dev); diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c index 08cab2b59..b82741f43 100644 --- a/drivers/net/pcmcia/3c574_cs.c +++ b/drivers/net/pcmcia/3c574_cs.c @@ -1166,7 +1166,9 @@ static int el3_rx(struct net_device *dev, int worklimit) skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); + dev->last_rx = jiffies; lp->stats.rx_packets++; + lp->stats.rx_bytes += pkt_len; } else { DEBUG(1, "%s: couldn't allocate a sk_buff of" " size %d.\n", dev->name, pkt_len); diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c index 5efb5907a..c8e024446 100644 --- a/drivers/net/pcmcia/3c589_cs.c +++ b/drivers/net/pcmcia/3c589_cs.c @@ -4,7 +4,7 @@ Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net - 3c589_cs.c 1.154 2000/09/30 17:39:04 + 3c589_cs.c 1.156 2001/02/07 00:19:41 The network driver code is based on Donald Becker's 3c589 code: @@ -117,7 +117,7 @@ static int pc_debug = PCMCIA_DEBUG; MODULE_PARM(pc_debug, "i"); #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) static char *version = -"3c589_cs.c 1.154 2000/09/30 17:39:04 (David Hinds)"; +"3c589_cs.c 1.156 2001/02/07 00:19:41 (David Hinds)"; #else #define DEBUG(n, args...) #endif @@ -993,8 +993,9 @@ static int el3_rx(struct net_device *dev) skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); + dev->last_rx = jiffies; lp->stats.rx_packets++; - lp->stats.rx_bytes += skb->len; + lp->stats.rx_bytes += pkt_len; } else { DEBUG(1, "%s: couldn't allocate a sk_buff of" " size %d.\n", dev->name, pkt_len); diff --git a/drivers/net/pcmcia/Config.in b/drivers/net/pcmcia/Config.in index 0f116b23d..f38572572 100644 --- a/drivers/net/pcmcia/Config.in +++ b/drivers/net/pcmcia/Config.in @@ -26,6 +26,7 @@ if [ "$CONFIG_NET_PCMCIA" = "y" ]; then bool ' Pcmcia Wireless LAN' CONFIG_NET_PCMCIA_RADIO if [ "$CONFIG_NET_PCMCIA_RADIO" = "y" ]; then dep_tristate ' Aviator/Raytheon 2.4MHz wireless support' CONFIG_PCMCIA_RAYCS $CONFIG_PCMCIA + dep_tristate ' Hermes support (Orinoco/WavelanIEEE/PrismII/Symbol 802.11b cards)' CONFIG_PCMCIA_HERMES $CONFIG_PCMCIA dep_tristate ' Xircom Netwave AirSurfer wireless support' CONFIG_PCMCIA_NETWAVE $CONFIG_PCMCIA dep_tristate ' AT&T/Lucent Wavelan wireless support' CONFIG_PCMCIA_WAVELAN $CONFIG_PCMCIA dep_tristate ' Aironet 4500/4800 PCMCIA support' CONFIG_AIRONET4500_CS $CONFIG_AIRONET4500 $CONFIG_PCMCIA diff --git a/drivers/net/pcmcia/Makefile b/drivers/net/pcmcia/Makefile index 1258504de..b36b51cf2 100644 --- a/drivers/net/pcmcia/Makefile +++ b/drivers/net/pcmcia/Makefile @@ -12,7 +12,7 @@ obj-n := obj- := # Things that need to export symbols -export-objs := ray_cs.o +export-objs := ray_cs.o hermes.o # 16-bit client drivers obj-$(CONFIG_PCMCIA_3C589) += 3c589_cs.o @@ -25,6 +25,7 @@ obj-$(CONFIG_PCMCIA_XIRC2PS) += xirc2ps_cs.o obj-$(CONFIG_ARCNET_COM20020_CS)+= com20020_cs.o # 16-bit wireless client drivers +obj-$(CONFIG_PCMCIA_HERMES) += orinoco_cs.o hermes.o obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o obj-$(CONFIG_PCMCIA_NETWAVE) += netwave_cs.o obj-$(CONFIG_PCMCIA_WAVELAN) += wavelan_cs.o diff --git a/drivers/net/pcmcia/aironet4500_cs.c b/drivers/net/pcmcia/aironet4500_cs.c index 503e033d8..b1b3e8df1 100644 --- a/drivers/net/pcmcia/aironet4500_cs.c +++ b/drivers/net/pcmcia/aironet4500_cs.c @@ -177,8 +177,14 @@ static dev_link_t *awc_attach(void) /* Create the PC card device object. */ link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); - memset(link, 0, sizeof(struct dev_link_t)); + if (!link) + return NULL; link->dev = kmalloc(sizeof(struct dev_node_t), GFP_KERNEL); + if (!link->dev) { + kfree(link); + return NULL; + } + memset(link, 0, sizeof(struct dev_link_t)); memset(link->dev, 0, sizeof(struct dev_node_t)); link->release.function = &awc_release; @@ -199,7 +205,6 @@ static dev_link_t *awc_attach(void) /* Create the network device object. */ dev = kmalloc(sizeof(struct net_device ), GFP_KERNEL); - memset(dev,0,sizeof(struct net_device)); // dev = init_etherdev(0, sizeof(struct awc_private) ); if (!dev ) { printk(KERN_CRIT "out of mem on dev alloc \n"); @@ -207,6 +212,7 @@ static dev_link_t *awc_attach(void) kfree(link); return NULL; }; + memset(dev,0,sizeof(struct net_device)); dev->priv = kmalloc(sizeof(struct awc_private), GFP_KERNEL); if (!dev->priv ) {printk(KERN_CRIT "out of mem on dev priv alloc \n"); return NULL;}; memset(dev->priv,0,sizeof(struct awc_private)); diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c index 8cdc3dbe6..4836a5577 100644 --- a/drivers/net/pcmcia/fmvj18x_cs.c +++ b/drivers/net/pcmcia/fmvj18x_cs.c @@ -1,5 +1,5 @@ /*====================================================================== - fmvj18x_cs.c,v 2.0 2000/10/01 03:13:53 root Exp + fmvj18x_cs.c 2.2 2001/01/07 A fmvj18x (and its compatibles) PCMCIA client driver @@ -19,7 +19,7 @@ Director, National Security Agency. This software may be used and distributed according to the terms - of the GNU Public License, incorporated herein by reference. + of the GNU General Public License, incorporated herein by reference. The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O Center of Excellence in Space Data and Information Sciences @@ -87,8 +87,7 @@ MODULE_PARM(sram_config, "i"); driver version infomation */ #ifdef PCMCIA_DEBUG -static char *version = - "fmvj18x_cs.c,v 2.0 2000/10/01 03:13:53 root Exp"; +static char *version = "fmvj18x_cs.c 2.2 2001/01/07"; #endif /*====================================================================*/ @@ -96,6 +95,7 @@ static char *version = PCMCIA event handlers */ static void fmvj18x_config(dev_link_t *link); +static int fmvj18x_get_hwinfo(dev_link_t *link, u_char *node_id); static void fmvj18x_release(u_long arg); static int fmvj18x_event(event_t event, int priority, event_callback_args_t *args); @@ -103,7 +103,7 @@ static dev_link_t *fmvj18x_attach(void); static void fmvj18x_detach(dev_link_t *); /* - LAN controler(MBH86960A) specific routines + LAN controller(MBH86960A) specific routines */ static int fjn_config(struct net_device *dev, struct ifmap *map); static int fjn_open(struct net_device *dev); @@ -122,7 +122,9 @@ static dev_link_t *dev_list = NULL; /* card type */ -typedef enum { MBH10302, MBH10304, TDK, CONTEC, LA501, UNGERMANN } cardtype_t; +typedef enum { MBH10302, MBH10304, TDK, CONTEC, LA501, UNGERMANN, + XXX10304 +} cardtype_t; #define MANFID_UNGERMANN 0x02c0 @@ -223,8 +225,8 @@ typedef struct local_info_t { #define RECV_ALL 0x03 /* (RX_MODE) */ #define CONFIG0_DFL 0x5a /* 16bit bus, 4K x 2 Tx queues */ #define CONFIG0_DFL_1 0x5e /* 16bit bus, 8K x 2 Tx queues */ -#define CONFIG0_RST 0xda /* Data Link Controler off (CONFIG_0) */ -#define CONFIG0_RST_1 0xde /* Data Link Controler off (CONFIG_0) */ +#define CONFIG0_RST 0xda /* Data Link Controller off (CONFIG_0) */ +#define CONFIG0_RST_1 0xde /* Data Link Controller off (CONFIG_0) */ #define BANK_0 0xa0 /* bank 0 (CONFIG_1) */ #define BANK_1 0xa4 /* bank 1 (CONFIG_1) */ #define BANK_2 0xa8 /* bank 2 (CONFIG_1) */ @@ -235,8 +237,8 @@ typedef struct local_info_t { #define MANU_MODE 0x03 /* Stop and skip packet on 16 col */ #define TDK_AUTO_MODE 0x47 /* Auto skip packet on 16 col detected */ #define TDK_MANU_MODE 0x43 /* Stop and skip packet on 16 col */ -#define INTR_OFF 0x0d /* LAN controler ignores interrupts */ -#define INTR_ON 0x1d /* LAN controler will catch interrupts */ +#define INTR_OFF 0x0d /* LAN controller ignores interrupts */ +#define INTR_ON 0x1d /* LAN controller will catch interrupts */ #define TX_TIMEOUT ((400*HZ)/1000) @@ -321,8 +323,10 @@ static dev_link_t *fmvj18x_attach(void) ether_setup(dev); dev->open = &fjn_open; dev->stop = &fjn_close; +#ifdef HAVE_TX_TIMEOUT dev->tx_timeout = fjn_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; +#endif /* Register with Card Services */ link->next = dev_list; @@ -438,6 +442,12 @@ static void fmvj18x_config(dev_link_t *link) switch (le16_to_cpu(buf[0])) { case MANFID_TDK: cardtype = TDK; + if (le16_to_cpu(buf[1]) == PRODID_TDK_CF010) { + cs_status_t status; + CardServices(GetStatus, handle, &status); + if (status.CardState & CS_EVENT_3VCARD) + link->conf.Vcc = 33; /* inserted in 3.3V slot */ + } break; case MANFID_CONTEC: cardtype = CONTEC; @@ -461,6 +471,15 @@ static void fmvj18x_config(dev_link_t *link) else buf[0] = 0xffff; switch (le16_to_cpu(buf[0])) { + case MANFID_FUJITSU: + if (le16_to_cpu(buf[1]) == PRODID_FUJITSU_MBH10304) { + cardtype = XXX10304; /* MBH10304 with buggy CIS */ + link->conf.ConfigIndex = 0x20; + } else { + cardtype = MBH10302; + link->conf.ConfigIndex = 1; + } + break; case MANFID_UNGERMANN: cardtype = UNGERMANN; /* @@ -505,7 +524,7 @@ req_irq: else outb(BANK_0, ioaddr + CONFIG_1); - /* Reset controler */ + /* Reset controller */ if( sram_config == 0 ) outb(CONFIG0_RST, ioaddr + CONFIG_0); else @@ -550,6 +569,19 @@ req_irq: dev->dev_addr[i] = inb(ioaddr + UNGERMANN_MAC_ID + i); card_name = "Access/CARD"; break; + case XXX10304: + /* Read MACID from Buggy CIS */ + if (fmvj18x_get_hwinfo(link, tuple.TupleData) == -1) { + printk(KERN_NOTICE "fmvj18x_cs: unable to read hardware net + address."); + unregister_netdev(dev); + goto failed; + } + for (i = 0 ; i < 6; i++) { + dev->dev_addr[i] = tuple.TupleData[i]; + } + card_name = "FMV-J182"; + break; case MBH10302: default: /* Read MACID from register */ @@ -580,7 +612,60 @@ failed: fmvj18x_release((u_long)link); } /* fmvj18x_config */ - +/*====================================================================*/ + +static int fmvj18x_get_hwinfo(dev_link_t *link, u_char *node_id) +{ + win_req_t req; + memreq_t mem; + u_char *base; + int i, j; + + /* Allocate a small memory window */ + req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE; + req.Base = 0; req.Size = 0; + req.AccessSpeed = 0; + link->win = (window_handle_t)link->handle; + i = CardServices(RequestWindow, &link->win, &req); + if (i != CS_SUCCESS) { + cs_error(link->handle, RequestWindow, i); + return -1; + } + + base = ioremap(req.Base, req.Size); + mem.Page = 0; + mem.CardOffset = 0; + CardServices(MapMemPage, link->win, &mem); + + /* + * MBH10304 CISTPL_FUNCE_LAN_NODE_ID format + * 22 0d xx xx xx 04 06 yy yy yy yy yy yy ff + * 'xx' is garbage. + * 'yy' is MAC address. + */ + for (i = 0; i < 0x200; i++) { + if (readb(base+i*2) == 0x22) { + if (readb(base+(i-1)*2) == 0xff + && readb(base+(i+5)*2) == 0x04 + && readb(base+(i+6)*2) == 0x06 + && readb(base+(i+13)*2) == 0xff) + break; + } + } + + if (i != 0x200) { + for (j = 0 ; j < 6; j++,i++) { + node_id[j] = readb(base+(i+7)*2); + } + } + + iounmap(base); + j = CardServices(ReleaseWindow, link->win); + if (j != CS_SUCCESS) + cs_error(link->handle, ReleaseWindow, j); + return (i != 0x200) ? 0 : -1; + +} /* fmvj18x_get_hwinfo */ /*====================================================================*/ static void fmvj18x_release(u_long arg) @@ -775,7 +860,7 @@ static void fjn_tx_timeout(struct net_device *dev) lp->sent = 0; lp->open_time = jiffies; sti(); - netif_start_queue(dev); + netif_wake_queue(dev); } static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev) @@ -923,7 +1008,7 @@ static void fjn_reset(struct net_device *dev) outb(D_TX_INTR, ioaddr + TX_INTR); outb(D_RX_INTR, ioaddr + RX_INTR); - /* Turn on interrupts from LAN card controler */ + /* Turn on interrupts from LAN card controller */ if( lp->cardtype != TDK ) outb(INTR_ON, ioaddr + LAN_CTRL); } /* fjn_reset */ @@ -995,8 +1080,9 @@ static void fjn_rx(struct net_device *dev) #endif netif_rx(skb); + dev->last_rx = jiffies; lp->stats.rx_packets++; - lp->stats.rx_bytes += skb->len; + lp->stats.rx_bytes += pkt_len; } if (--boguscount <= 0) break; diff --git a/drivers/net/pcmcia/hermes.c b/drivers/net/pcmcia/hermes.c new file mode 100644 index 000000000..dbc66b360 --- /dev/null +++ b/drivers/net/pcmcia/hermes.c @@ -0,0 +1,502 @@ +/* hermes.c + * + * Driver core for the "Hermes" wireless MAC controller, as used in + * the Lucent Orinoco and Cabletron RoamAbout cards. It should also + * work on the hfa3841 and hfa3842 MAC controller chips used in the + * Prism I & II chipsets. + * + * This is not a complete driver, just low-level access routines for + * the MAC controller itself. + * + * Based on the prism2 driver from Absolute Value Systems' linux-wlan + * project, the Linux wvlan_cs driver, Lucent's HCF-Light + * (wvlan_hcf.c) library, and the NetBSD wireless driver. + * + * Copyright (C) 2000, David Gibson, Linuxcare Australia <hermes@gibson.dropbear.id.au> + * + * This file distributed under the GPL, version 2. + */ + +static const char *version = "hermes.c: 12 Dec 2000 David Gibson <hermes@gibson.dropbear.id.au>"; + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/smp.h> +#include <asm/io.h> +#include <linux/ptrace.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <asm/errno.h> + +#include "hermes.h" + +#define CMD_BUSY_TIMEOUT (100) /* In iterations of ~1us */ +#define CMD_INIT_TIMEOUT (50000) /* in iterations of ~10us */ +#define CMD_COMPL_TIMEOUT (10000) /* in iterations of ~10us */ +#define ALLOC_COMPL_TIMEOUT (1000) /* in iterations of ~10us */ +#define BAP_BUSY_TIMEOUT (500) /* In iterations of ~1us */ +#define BAP_ERROR_RETRY (10) /* How many times to retry a BAP seek when there is an error */ + +#define MAX(a, b) ( (a) > (b) ? (a) : (b) ) +#define MIN(a, b) ( (a) < (b) ? (a) : (b) ) + +/* + * Debugging helpers + */ + +#undef HERMES_DEBUG +#ifdef HERMES_DEBUG + +#include <stdarg.h> + +#define DMSG(stuff...) do {printk(KERN_DEBUG "hermes @ 0x%x: " , hw->iobase); \ + printk(#stuff);} while (0) + +#define DEBUG(lvl, stuff...) if ( (lvl) <= HERMES_DEBUG) DMSG(#stuff) + +#else /* ! HERMES_DEBUG */ + +#define DEBUG(lvl, stuff...) do { } while (0) + +#endif /* ! HERMES_DEBUG */ + +/* + * Prototypes + */ + +static int hermes_issue_cmd(hermes_t *hw, uint16_t cmd, uint16_t param0); + +/* + * Internal inline functions + */ + +/* + * Internal functions + */ + +/* Issue a command to the chip. Waiting for it to complete is the caller's + problem. + + Returns -EBUSY if the command register is busy, 0 on success. + + Callable from any context. +*/ +static int hermes_issue_cmd(hermes_t *hw, uint16_t cmd, uint16_t param0) +{ + uint16_t reg; +/* unsigned long k = CMD_BUSY_TIMEOUT; */ + + /* First check that the command register is not busy */ + reg = hermes_read_regn(hw, CMD); + if (reg & HERMES_CMD_BUSY) { + return -EBUSY; + } + + hermes_write_regn(hw, PARAM2, 0); + hermes_write_regn(hw, PARAM1, 0); + hermes_write_regn(hw, PARAM0, param0); + hermes_write_regn(hw, CMD, cmd); + + return 0; +} + +/* + * Function definitions + */ + +void hermes_struct_init(hermes_t *hw, ushort io) +{ + hw->iobase = io; + hw->inten = 0x0; +} + +int hermes_reset(hermes_t *hw) +{ + uint16_t status, reg; + int err = 0; + int k; + + /* We don't want to be interrupted while resetting the chipset */ + hw->inten = 0x0; + hermes_write_regn(hw, INTEN, 0); + hermes_write_regn(hw, EVACK, 0xffff); + + /* Because we hope we can reset the card even if it gets into + a stupid state, we actually wait to see if the command + register will unbusy itself */ + k = CMD_BUSY_TIMEOUT; + reg = hermes_read_regn(hw, CMD); + while (k && (reg & HERMES_CMD_BUSY)) { + if (reg == 0xffff) /* Special case - the card has probably been removed, + so don't wait for the timeout */ + return -ENODEV; + + k--; + udelay(1); + reg = hermes_read_regn(hw, CMD); + } + + /* No need to explicitly handle the timeout - hermes_issue_cmd() will + probably return -EBUSY */ + + /* We don't use hermes_docmd_wait here, because the reset wipes + the magic constant in SWSUPPORT0 away, and it gets confused */ + err = hermes_issue_cmd(hw, HERMES_CMD_INIT, 0); + if (err) + return err; + + reg = hermes_read_regn(hw, EVSTAT); + k = CMD_INIT_TIMEOUT; + while ( (! (reg & HERMES_EV_CMD)) && k) { + k--; + udelay(10); + reg = hermes_read_regn(hw, EVSTAT); + } + + DEBUG(0, "Reset completed in %d iterations\n", CMD_INIT_TIMEOUT - k); + + hermes_write_regn(hw, SWSUPPORT0, HERMES_MAGIC); + + if (! hermes_present(hw)) { + DEBUG(0, "hermes @ 0x%x: Card removed during reset.\n", + hw->iobase); + err = -ENODEV; + goto out; + } + + if (! (reg & HERMES_EV_CMD)) { + printk(KERN_ERR "hermes @ 0x%x: Timeout waiting for card to reset (reg=0x%04x)!\n", + hw->iobase, reg); + err = -ETIMEDOUT; + goto out; + } + + status = hermes_read_regn(hw, STATUS); + + hermes_write_regn(hw, EVACK, HERMES_EV_CMD); + + err = status & HERMES_STATUS_RESULT; + + out: + return err; +} + +/* Issue a command to the chip, and (busy!) wait for it to + * complete. + * + * Returns: < 0 on internal error, 0 on success, > 0 on error returned by the firmware + * + * Callable from any context, but locking is your problem. */ +int hermes_docmd_wait(hermes_t *hw, uint16_t cmd, uint16_t parm0, hermes_response_t *resp) +{ + int err; + int k; + uint16_t reg; + + err = hermes_issue_cmd(hw, cmd, parm0); + if (err) { + if (! hermes_present(hw)) { + printk(KERN_WARNING "hermes @ 0x%x: Card removed while issuing command.\n", + hw->iobase); + err = -ENODEV; + } else + printk(KERN_ERR "hermes @ 0x%x: CMD register busy in hermes_issue_command().\n", + hw->iobase); + goto out; + } + + reg = hermes_read_regn(hw, EVSTAT); + k = CMD_COMPL_TIMEOUT; + while ( (! (reg & HERMES_EV_CMD)) && k) { + k--; + udelay(10); + reg = hermes_read_regn(hw, EVSTAT); + } + + if (! hermes_present(hw)) { + printk(KERN_WARNING "hermes @ 0x%x: Card removed while waiting for command completion.\n", + hw->iobase); + err = -ENODEV; + goto out; + } + + if (! (reg & HERMES_EV_CMD)) { + printk(KERN_ERR "hermes @ 0x%x: Timeout waiting for command completion.\n", + hw->iobase); + err = -ETIMEDOUT; + goto out; + } + + resp->status = hermes_read_regn(hw, STATUS); + resp->resp0 = hermes_read_regn(hw, RESP0); + resp->resp1 = hermes_read_regn(hw, RESP1); + resp->resp2 = hermes_read_regn(hw, RESP2); + + hermes_write_regn(hw, EVACK, HERMES_EV_CMD); + + err = resp->status & HERMES_STATUS_RESULT; + + out: + return err; +} + +int hermes_allocate(hermes_t *hw, uint16_t size, uint16_t *fid) +{ + int err = 0; + hermes_response_t resp; + int k; + uint16_t reg; + + if ( (size < HERMES_ALLOC_LEN_MIN) || (size > HERMES_ALLOC_LEN_MAX) ) + return -EINVAL; + + err = hermes_docmd_wait(hw, HERMES_CMD_ALLOC, size, &resp); + if (err) { + printk(KERN_WARNING "hermes @ 0x%x: Frame allocation command failed (0x%X).\n", + hw->iobase, err); + return err; + } + + reg = hermes_read_regn(hw, EVSTAT); + k = ALLOC_COMPL_TIMEOUT; + while ( (! (reg & HERMES_EV_ALLOC)) && k) { + k--; + udelay(10); + reg = hermes_read_regn(hw, EVSTAT); + } + + if (! hermes_present(hw)) { + printk(KERN_WARNING "hermes @ 0x%x: Card removed waiting for frame allocation.\n", + hw->iobase); + return -ENODEV; + } + + if (! (reg & HERMES_EV_ALLOC)) { + printk(KERN_ERR "hermes @ 0x%x: Timeout waiting for frame allocation\n", + hw->iobase); + return -ETIMEDOUT; + } + + *fid = hermes_read_regn(hw, ALLOCFID); + hermes_write_regn(hw, EVACK, HERMES_EV_ALLOC); + + return 0; +} + +/* Set up a BAP to read a particular chunk of data from card's internal buffer. + * + * Returns: < 0 on internal failure (errno), 0 on success, >0 on error + * from firmware + * + * Callable from any context */ +static int hermes_bap_seek(hermes_t *hw, int bap, uint16_t id, uint16_t offset) +{ + int sreg = bap ? HERMES_SELECT1 : HERMES_SELECT0; + int oreg = bap ? HERMES_OFFSET1 : HERMES_OFFSET0; + int k; + int l = BAP_ERROR_RETRY; + uint16_t reg; + + /* Paranoia.. */ + if ( (offset > HERMES_BAP_OFFSET_MAX) || (offset % 2) ) + return -EINVAL; + + k = BAP_BUSY_TIMEOUT; + reg = hermes_read_reg(hw, oreg); + + if (reg & HERMES_OFFSET_BUSY) + return -EBUSY; + + /* Now we actually set up the transfer */ + retry: + hermes_write_reg(hw, sreg, id); + hermes_write_reg(hw, oreg, offset); + + /* Wait for the BAP to be ready */ + k = BAP_BUSY_TIMEOUT; + reg = hermes_read_reg(hw, oreg); + while ( (reg & (HERMES_OFFSET_BUSY | HERMES_OFFSET_ERR)) && k) { + k--; + udelay(1); + reg = hermes_read_reg(hw, oreg); + } + + if (reg & HERMES_OFFSET_BUSY) + return -ETIMEDOUT; + + /* For some reason, seeking the BAP seems to randomly fail somewhere + (firmware bug?). We retry a few times before giving up. */ + if (reg & HERMES_OFFSET_ERR) { + if (l--) { + udelay(1); + goto retry; + } else + return -EIO; + } + + return 0; +} + +/* Read a block of data from the chip's buffer, via the + * BAP. Synchronization/serialization is the caller's problem. len + * must be even. + * + * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware + */ +int hermes_bap_pread(hermes_t *hw, int bap, void *buf, uint16_t len, + uint16_t id, uint16_t offset) +{ + int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; + int err = 0; + + if (len % 2) + return -EINVAL; + + err = hermes_bap_seek(hw, bap, id, offset); + if (err) + goto out; + + /* Actually do the transfer */ + hermes_read_data(hw, dreg, buf, len/2); + + out: + return err; +} + +/* Write a block of data to the chip's buffer, via the + * BAP. Synchronization/serialization is the caller's problem. len + * must be even. + * + * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware + */ +int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, uint16_t len, + uint16_t id, uint16_t offset) +{ + int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; + int err = 0; + + if (len % 2) + return -EINVAL; + + err = hermes_bap_seek(hw, bap, id, offset); + if (err) + goto out; + + /* Actually do the transfer */ + hermes_write_data(hw, dreg, buf, len/2); + + out: + return err; +} + +/* Read a Length-Type-Value record from the card. + * + * If length is NULL, we ignore the length read from the card, and + * read the entire buffer regardless. This is useful because some of + * the configuration records appear to have incorrect lengths in + * practice. + * + * Callable from user or bh context. */ +int hermes_read_ltv(hermes_t *hw, int bap, uint16_t rid, int buflen, + uint16_t *length, void *buf) +{ + int err = 0; + int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; + uint16_t rlength, rtype; + hermes_response_t resp; + int count; + + if (buflen % 2) + return -EINVAL; + + err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS, rid, &resp); + if (err) + goto out; + + err = hermes_bap_seek(hw, bap, rid, 0); + if (err) + goto out; + + rlength = hermes_read_reg(hw, dreg); + rtype = hermes_read_reg(hw, dreg); + + if (length) + *length = rlength; + + if (rtype != rid) + printk(KERN_WARNING "hermes_read_ltv(): rid (0x%04x) does " + "not match type (0x%04x)\n", rid, rtype); + if (HERMES_RECLEN_TO_BYTES(rlength) > buflen) + printk(KERN_WARNING "hermes @ 0x%x: Truncating LTV record from %d to %d bytes. " + "(rid=0x%04x, len=0x%04x)\n", hw->iobase, + HERMES_RECLEN_TO_BYTES(rlength), buflen, rid, rlength); + + /* For now we always read the whole buffer, the + lengths in the records seem to be wrong, frequently */ + count = buflen / 2; + +#if 0 + if (length) + count = (MIN(buflen, rlength) + 1) / 2; + else { + count = buflen / 2; + if (rlength != buflen) + printk(KERN_WARNING "hermes_read_ltv(): Incorrect \ +record length %d instead of %d on RID 0x%04x\n", rlength, buflen, rid); + } +#endif + hermes_read_data(hw, dreg, buf, count); + + out: + return err; +} + +int hermes_write_ltv(hermes_t *hw, int bap, uint16_t rid, + uint16_t length, const void *value) +{ + int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; + int err = 0; + hermes_response_t resp; + int count; + + DEBUG(3, "write_ltv(): bap=%d rid=0x%04x length=%d (value=0x%04x)\n", + bap, rid, length, * ((uint16_t *)value)); + + err = hermes_bap_seek(hw, bap, rid, 0); + if (err) + goto out; + + hermes_write_reg(hw, dreg, length); + hermes_write_reg(hw, dreg, rid); + + count = length - 1; + + hermes_write_data(hw, dreg, value, count); + + err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE, + rid, &resp); + + out: + return err; +} + +EXPORT_SYMBOL(hermes_struct_init); +EXPORT_SYMBOL(hermes_reset); +EXPORT_SYMBOL(hermes_docmd_wait); +EXPORT_SYMBOL(hermes_allocate); + +EXPORT_SYMBOL(hermes_bap_pread); +EXPORT_SYMBOL(hermes_bap_pwrite); +EXPORT_SYMBOL(hermes_read_ltv); +EXPORT_SYMBOL(hermes_write_ltv); + +static int __init init_hermes(void) +{ + printk(KERN_INFO "%s\n", version); + + return 0; +} + +module_init(init_hermes); diff --git a/drivers/net/pcmcia/hermes.h b/drivers/net/pcmcia/hermes.h new file mode 100644 index 000000000..91529f1cb --- /dev/null +++ b/drivers/net/pcmcia/hermes.h @@ -0,0 +1,398 @@ +/* hermes.h + * + * Driver core for the "Hermes" wireless MAC controller, as used in + * the Lucent Orinoco and Cabletron RoamAbout cards. It should also + * work on the hfa3841 and hfa3842 MAC controller chips used in the + * Prism I & II chipsets. + * + * This is not a complete driver, just low-level access routines for + * the MAC controller itself. + * + * Based on the prism2 driver from Absolute Value Systems' linux-wlan + * project, the Linux wvlan_cs driver, Lucent's HCF-Light + * (wvlan_hcf.c) library, and the NetBSD wireless driver. + * + * Copyright (C) 2000, David Gibson, Linuxcare Australia <hermes@gibson.dropbear.id.au> + * + * Portions taken from hfa384x.h, Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. + * + * This file distributed under the GPL, version 2. + */ + +#ifndef _HERMES_H +#define _HERMES_H + +/* Notes on locking: + * + * As a module of low level hardware access routines, there is no + * locking. Users of this module should ensure that they serialize + * access to the hermes_t structure, and to the hardware +*/ + +#include <linux/delay.h> +#include <linux/if_ether.h> + +/* + * Limits and constants + */ +#define HERMES_ALLOC_LEN_MIN ((uint16_t)4) +#define HERMES_ALLOC_LEN_MAX ((uint16_t)2400) +#define HERMES_LTV_LEN_MAX (34) +#define HERMES_BAP_DATALEN_MAX ((uint16_t)4096) +#define HERMES_BAP_OFFSET_MAX ((uint16_t)4096) +#define HERMES_PORTID_MAX ((uint16_t)7) +#define HERMES_NUMPORTS_MAX ((uint16_t)(HERMES_PORTID_MAX+1)) +#define HERMES_PDR_LEN_MAX ((uint16_t)260) /* in bytes, from EK */ +#define HERMES_PDA_RECS_MAX ((uint16_t)200) /* a guess */ +#define HERMES_PDA_LEN_MAX ((uint16_t)1024) /* in bytes, from EK */ +#define HERMES_SCANRESULT_MAX ((uint16_t)35) +#define HERMES_CHINFORESULT_MAX ((uint16_t)8) +#define HERMES_FRAME_LEN_MAX (2304) +#define HERMES_MAX_MULTICAST (16) +#define HERMES_MAGIC (0x7d1f) + +/* + * Hermes register offsets + */ +#define HERMES_CMD (0x00) +#define HERMES_PARAM0 (0x02) +#define HERMES_PARAM1 (0x04) +#define HERMES_PARAM2 (0x06) +#define HERMES_STATUS (0x08) +#define HERMES_RESP0 (0x0A) +#define HERMES_RESP1 (0x0C) +#define HERMES_RESP2 (0x0E) +#define HERMES_INFOFID (0x10) +#define HERMES_RXFID (0x20) +#define HERMES_ALLOCFID (0x22) +#define HERMES_TXCOMPLFID (0x24) +#define HERMES_SELECT0 (0x18) +#define HERMES_OFFSET0 (0x1C) +#define HERMES_DATA0 (0x36) +#define HERMES_SELECT1 (0x1A) +#define HERMES_OFFSET1 (0x1E) +#define HERMES_DATA1 (0x38) +#define HERMES_EVSTAT (0x30) +#define HERMES_INTEN (0x32) +#define HERMES_EVACK (0x34) +#define HERMES_CONTROL (0x14) +#define HERMES_SWSUPPORT0 (0x28) +#define HERMES_SWSUPPORT1 (0x2A) +#define HERMES_SWSUPPORT2 (0x2C) +#define HERMES_AUXPAGE (0x3A) +#define HERMES_AUXOFFSET (0x3C) +#define HERMES_AUXDATA (0x3E) + +/* + * CMD register bitmasks + */ +#define HERMES_CMD_BUSY ((uint16_t)0x8000) +#define HERMES_CMD_AINFO ((uint16_t)0x7f00) +#define HERMES_CMD_MACPORT ((uint16_t)0x0700) +#define HERMES_CMD_RECL ((uint16_t)0x0100) +#define HERMES_CMD_WRITE ((uint16_t)0x0100) +#define HERMES_CMD_PROGMODE ((uint16_t)0x0300) +#define HERMES_CMD_CMDCODE ((uint16_t)0x003f) + +/* + * STATUS register bitmasks + */ +#define HERMES_STATUS_RESULT ((uint16_t)0x7f00) +#define HERMES_STATUS_CMDCODE ((uint16_t)0x003f) + +/* + * OFFSET refister bitmasks + */ +#define HERMES_OFFSET_BUSY ((uint16_t)0x8000) +#define HERMES_OFFSET_ERR ((uint16_t)0x4000) +#define HERMES_OFFSET_DATAOFF ((uint16_t)0x0ffe) + +/* + * Event register bitmasks (INTEN, EVSTAT, EVACK) + */ +#define HERMES_EV_TICK ((uint16_t)0x8000) +#define HERMES_EV_WTERR ((uint16_t)0x4000) +#define HERMES_EV_INFDROP ((uint16_t)0x2000) +#define HERMES_EV_INFO ((uint16_t)0x0080) +#define HERMES_EV_DTIM ((uint16_t)0x0020) +#define HERMES_EV_CMD ((uint16_t)0x0010) +#define HERMES_EV_ALLOC ((uint16_t)0x0008) +#define HERMES_EV_TXEXC ((uint16_t)0x0004) +#define HERMES_EV_TX ((uint16_t)0x0002) +#define HERMES_EV_RX ((uint16_t)0x0001) + +/* + * Command codes + */ +/*--- Controller Commands --------------------------*/ +#define HERMES_CMD_INIT ((uint16_t)0x00) +#define HERMES_CMD_ENABLE ((uint16_t)0x01) +#define HERMES_CMD_DISABLE ((uint16_t)0x02) +#define HERMES_CMD_DIAG ((uint16_t)0x03) + +/*--- Buffer Mgmt Commands --------------------------*/ +#define HERMES_CMD_ALLOC ((uint16_t)0x0A) +#define HERMES_CMD_TX ((uint16_t)0x0B) +#define HERMES_CMD_CLRPRST ((uint16_t)0x12) + +/*--- Regulate Commands --------------------------*/ +#define HERMES_CMD_NOTIFY ((uint16_t)0x10) +#define HERMES_CMD_INQ ((uint16_t)0x11) + +/*--- Configure Commands --------------------------*/ +#define HERMES_CMD_ACCESS ((uint16_t)0x21) +#define HERMES_CMD_DOWNLD ((uint16_t)0x22) + +/*--- Debugging Commands -----------------------------*/ +#define HERMES_CMD_MONITOR ((uint16_t)(0x38)) +#define HERMES_MONITOR_ENABLE ((uint16_t)(0x0b)) +#define HERMES_MONITOR_DISABLE ((uint16_t)(0x0f)) + +/* + * Configuration RIDs + */ + +#define HERMES_RID_CNF_PORTTYPE ((uint16_t)0xfc00) +#define HERMES_RID_CNF_MACADDR ((uint16_t)0xfc01) +#define HERMES_RID_CNF_DESIRED_SSID ((uint16_t)0xfc02) +#define HERMES_RID_CNF_CHANNEL ((uint16_t)0xfc03) +#define HERMES_RID_CNF_OWN_SSID ((uint16_t)0xfc04) +#define HERMES_RID_CNF_SYSTEM_SCALE ((uint16_t)0xfc06) +#define HERMES_RID_CNF_MAX_DATA_LEN ((uint16_t)0xfc07) +#define HERMES_RID_CNF_PM_ENABLE ((uint16_t)0xfc09) +#define HERMES_RID_CNF_PM_MCAST_RX ((uint16_t)0xfc0b) +#define HERMES_RID_CNF_PM_PERIOD ((uint16_t)0xfc0c) +#define HERMES_RID_CNF_PM_HOLDOVER ((uint16_t)0xfc0d) +#define HERMES_RID_CNF_NICKNAME ((uint16_t)0xfc0e) +#define HERMES_RID_CNF_WEP_ON ((uint16_t)0xfc20) +#define HERMES_RID_CNF_MWO_ROBUST ((uint16_t)0xfc25) +#define HERMES_RID_CNF_PRISM2_WEP_ON ((uint16_t)0xfc28) +#define HERMES_RID_CNF_MULTICAST_LIST ((uint16_t)0xfc80) +#define HERMES_RID_CNF_CREATEIBSS ((uint16_t)0xfc81) +#define HERMES_RID_CNF_FRAG_THRESH ((uint16_t)0xfc82) +#define HERMES_RID_CNF_RTS_THRESH ((uint16_t)0xfc83) +#define HERMES_RID_CNF_TX_RATE_CTRL ((uint16_t)0xfc84) +#define HERMES_RID_CNF_PROMISCUOUS ((uint16_t)0xfc85) +#define HERMES_RID_CNF_KEYS ((uint16_t)0xfcb0) +#define HERMES_RID_CNF_TX_KEY ((uint16_t)0xfcb1) +#define HERMES_RID_CNF_TICKTIME ((uint16_t)0xfce0) + +#define HERMES_RID_CNF_PRISM2_TX_KEY ((uint16_t)0xfc23) +#define HERMES_RID_CNF_PRISM2_KEY0 ((uint16_t)0xfc24) +#define HERMES_RID_CNF_PRISM2_KEY1 ((uint16_t)0xfc25) +#define HERMES_RID_CNF_PRISM2_KEY2 ((uint16_t)0xfc26) +#define HERMES_RID_CNF_PRISM2_KEY3 ((uint16_t)0xfc27) +#define HERMES_RID_CNF_SYMBOL_AUTH_TYPE ((uint16_t)0xfc2A) +/* This one is read only */ +#define HERMES_RID_CNF_SYMBOL_KEY_LENGTH ((uint16_t)0xfc2B) +#define HERMES_RID_CNF_SYMBOL_BASIC_RATES ((uint16_t)0xfc8A) + +/* + * Information RIDs + */ +#define HERMES_RID_CHANNEL_LIST ((uint16_t)0xfd10) +#define HERMES_RID_STAIDENTITY ((uint16_t)0xfd20) +#define HERMES_RID_CURRENT_SSID ((uint16_t)0xfd41) +#define HERMES_RID_CURRENT_BSSID ((uint16_t)0xfd42) +#define HERMES_RID_COMMSQUALITY ((uint16_t)0xfd43) +#define HERMES_RID_CURRENT_TX_RATE ((uint16_t)0xfd44) +#define HERMES_RID_WEP_AVAIL ((uint16_t)0xfd4f) +#define HERMES_RID_CURRENT_CHANNEL ((uint16_t)0xfdc1) +#define HERMES_RID_DATARATES ((uint16_t)0xfdc6) + +/* + * Frame structures and constants + */ + +typedef struct hermes_frame_desc { + /* Hermes - i.e. little-endian byte-order */ + uint16_t status; /* 0x0 */ + uint16_t res1, res2; /* 0x2, 0x4 */ + uint16_t q_info; /* 0x6 */ + uint16_t res3, res4; /* 0x8, 0xA */ + uint16_t tx_ctl; /* 0xC */ +} __attribute__ ((packed)) hermes_frame_desc_t; + +#define HERMES_RXSTAT_ERR ((uint16_t)0x0003) +#define HERMES_RXSTAT_MACPORT ((uint16_t)0x0700) +#define HERMES_RXSTAT_MSGTYPE ((uint16_t)0xE000) + +#define HERMES_RXSTAT_BADCRC ((uint16_t)0x0001) +#define HERMES_RXSTAT_UNDECRYPTABLE ((uint16_t)0x0002) + +/* RFC-1042 encoded frame */ +#define HERMES_RXSTAT_1042 ((uint16_t)0x2000) +/* Bridge-tunnel encoded frame */ +#define HERMES_RXSTAT_TUNNEL ((uint16_t)0x4000) +/* Wavelan-II Management Protocol frame */ +#define HERMES_RXSTAT_WMP ((uint16_t)0x6000) + +#ifdef __KERNEL__ + +/* Basic control structure */ +typedef struct hermes { + uint iobase; + + uint16_t inten; /* Which interrupts should be enabled? */ +} hermes_t; + +typedef struct hermes_response { + uint16_t status, resp0, resp1, resp2; +} hermes_response_t; + +/* Firmware information structure */ +typedef struct hermes_identity { + uint16_t id, vendor, major, minor; +} __attribute__ ((packed)) hermes_identity_t; + +/* "ID" structure - used for ESSID and station nickname */ +typedef struct hermes_id { + uint16_t len; + uint16_t val[16]; +} __attribute__ ((packed)) hermes_id_t; + +typedef struct hermes_commsqual { + uint16_t qual, signal, noise; +} __attribute__ ((packed)) hermes_commsqual_t; + +typedef struct hermes_multicast { + uint8_t addr[HERMES_MAX_MULTICAST][ETH_ALEN]; +} __attribute__ ((packed)) hermes_multicast_t; + +/* Register access convenience macros */ +#define hermes_read_reg(hw, off) (inw((hw)->iobase + (off))) +#define hermes_write_reg(hw, off, val) (outw_p((val), (hw)->iobase + (off))) + +#define hermes_read_regn(hw, name) (hermes_read_reg((hw), HERMES_##name)) +#define hermes_write_regn(hw, name, val) (hermes_write_reg((hw), HERMES_##name, (val))) + +/* Note that for the next two, the count is in 16-bit words, not bytes */ +#define hermes_read_data(hw, off, buf, count) (insw((hw)->iobase + (off), (buf), (count))) +#define hermes_write_data(hw, off, buf, count) (outsw((hw)->iobase + (off), (buf), (count))) + +/* Function prototypes */ +void hermes_struct_init(hermes_t *hw, ushort io); +int hermes_reset(hermes_t *hw); +int hermes_docmd_wait(hermes_t *hw, uint16_t cmd, uint16_t parm0, hermes_response_t *resp); +int hermes_allocate(hermes_t *hw, uint16_t size, uint16_t *fid); + + +int hermes_bap_pread(hermes_t *hw, int bap, void *buf, uint16_t len, + uint16_t id, uint16_t offset); +int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, uint16_t len, + uint16_t id, uint16_t offset); +int hermes_read_ltv(hermes_t *hw, int bap, uint16_t rid, int buflen, + uint16_t *length, void *buf); +int hermes_write_ltv(hermes_t *hw, int bap, uint16_t rid, + uint16_t length, const void *value); + +/* Inline functions */ + +static inline int hermes_present(hermes_t *hw) +{ + return hermes_read_regn(hw, SWSUPPORT0) == HERMES_MAGIC; +} + +static inline void hermes_enable_interrupt(hermes_t *hw, uint16_t events) +{ + hw->inten |= events; + hermes_write_regn(hw, INTEN, hw->inten); +} + +static inline void hermes_set_irqmask(hermes_t *hw, uint16_t events) +{ + hw->inten = events; + hermes_write_regn(hw, INTEN, events); +} + +static inline int hermes_enable_port(hermes_t *hw, int port) +{ + hermes_response_t resp; + + return hermes_docmd_wait(hw, HERMES_CMD_ENABLE | (port << 8), + 0, &resp); +} + +static inline int hermes_disable_port(hermes_t *hw, int port) +{ + hermes_response_t resp; + + return hermes_docmd_wait(hw, HERMES_CMD_ENABLE | (port << 8), + 0, &resp); +} + +#define HERMES_BYTES_TO_RECLEN(n) ( ((n) % 2) ? (((n)+1)/2)+1 : ((n)/2)+1 ) +#define HERMES_RECLEN_TO_BYTES(n) ( ((n)-1) * 2 ) + +#define HERMES_READ_RECORD(hw, bap, rid, buf) \ + (hermes_read_ltv((hw),(bap),(rid), sizeof(*buf), NULL, (buf))) +#define HERMES_WRITE_RECORD(hw, bap, rid, buf) \ + (hermes_write_ltv((hw),(bap),(rid),HERMES_BYTES_TO_RECLEN(sizeof(*buf)),(buf))) +#define HERMES_WRITE_RECORD_LEN(hw, bap, rid, buf, len) \ + (hermes_write_ltv((hw),(bap),(rid),HERMES_BYTES_TO_RECLEN(len),(buf))) + +static inline int hermes_read_wordrec(hermes_t *hw, int bap, uint16_t rid, uint16_t *word) +{ + uint16_t rec; + int err; + + err = HERMES_READ_RECORD(hw, bap, rid, &rec); + *word = le16_to_cpu(rec); + return err; +} + +static inline int hermes_write_wordrec(hermes_t *hw, int bap, uint16_t rid, uint16_t word) +{ + uint16_t rec = cpu_to_le16(word); + return HERMES_WRITE_RECORD(hw, bap, rid, &rec); +} + +static inline int hermes_read_staidentity(hermes_t *hw, int bap, hermes_identity_t *buf) +{ + int err; + + err = HERMES_READ_RECORD(hw, bap, HERMES_RID_STAIDENTITY, buf); + if (err) + return err; + + le16_to_cpus(&buf->id); + le16_to_cpus(&buf->vendor); + le16_to_cpus(&buf->major); + le16_to_cpus(&buf->minor); + + return 0; +} + +static inline int hermes_read_commsqual(hermes_t *hw, int bap, hermes_commsqual_t *buf) +{ + int err; + + err = HERMES_READ_RECORD(hw, bap, HERMES_RID_COMMSQUALITY, buf); + if (err) + return err; + + le16_to_cpus(&buf->qual); + le16_to_cpus(&buf->signal); + le16_to_cpus(&buf->noise); + + return 0; +} + +#else /* ! __KERNEL__ */ + +/* These are provided for the benefit of userspace drivers and testing programs + which use ioperm() or iopl() */ + +#define hermes_read_reg(base, off) (inw((base) + (off))) +#define hermes_write_reg(base, off, val) (outw((val), (base) + (off))) + +#define hermes_read_regn(base, name) (hermes_read_reg((base), HERMES_##name)) +#define hermes_write_regn(base, name, val) (hermes_write_reg((base), HERMES_##name, (val))) + +/* Note that for the next two, the count is in 16-bit words, not bytes */ +#define hermes_read_data(base, off, buf, count) (insw((base) + (off), (buf), (count))) +#define hermes_write_data(base, off, buf, count) (outsw((base) + (off), (buf), (count))) + +#endif /* ! __KERNEL__ */ + +#endif /* _HERMES_H */ diff --git a/drivers/net/pcmcia/i82593.h b/drivers/net/pcmcia/i82593.h index 6d66baf6d..33acb8add 100644 --- a/drivers/net/pcmcia/i82593.h +++ b/drivers/net/pcmcia/i82593.h @@ -221,4 +221,4 @@ struct i82593_conf_block { #define I82593_MAX_MULTICAST_ADDRESSES 128 /* Hardware hashed filter */ -#endif _I82593_H +#endif /* _I82593_H */ diff --git a/drivers/net/pcmcia/netwave_cs.c b/drivers/net/pcmcia/netwave_cs.c index a5bef517b..d393e6f95 100644 --- a/drivers/net/pcmcia/netwave_cs.c +++ b/drivers/net/pcmcia/netwave_cs.c @@ -1463,16 +1463,16 @@ static int netwave_rx(struct net_device *dev) { skb->protocol = eth_type_trans(skb,dev); /* Queue packet for network layer */ netif_rx(skb); - + + dev->last_rx = jiffies; + priv->stats.rx_packets++; + priv->stats.rx_bytes += rcvLen; + /* Got the packet, tell the adapter to skip it */ wait_WOC(iobase); writeb(NETWAVE_CMD_SRP, ramBase + NETWAVE_EREG_CB + 0); writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 1); DEBUG(3, "Packet reception ok\n"); - - priv->stats.rx_packets++; - - priv->stats.rx_bytes += skb->len; } return 0; } diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c index 9b7f8f048..331cda65e 100644 --- a/drivers/net/pcmcia/nmclan_cs.c +++ b/drivers/net/pcmcia/nmclan_cs.c @@ -1288,9 +1288,9 @@ static int mace_rx(struct net_device *dev, unsigned char RxCnt) skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); /* Send the packet to the upper (protocol) layers. */ - + dev->last_rx = jiffies; lp->linux_stats.rx_packets++; - lp->linux_stats.rx_bytes += skb->len; + lp->linux_stats.rx_bytes += pkt_len; outb(0xFF, ioaddr + AM2150_RCV_NEXT); /* skip to next frame */ continue; } else { diff --git a/drivers/net/pcmcia/orinoco_cs.c b/drivers/net/pcmcia/orinoco_cs.c new file mode 100644 index 000000000..3b53704dc --- /dev/null +++ b/drivers/net/pcmcia/orinoco_cs.c @@ -0,0 +1,4018 @@ +/* orinoco_cs.c 0.03 - (formerly known as dldwd_cs.c) + * + * A driver for "Hermes" chipset based PCMCIA wireless adaptors, such + * as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/ + * EnteraSys RoamAbout 802.11, ELSA Airlancer, Melco Buffalo and others). + * It should also be usable on various Prism II based cards such as the + * Linksys, D-Link and Farallon Skyline. It should also work on Symbol + * cards such as the 3Com AirConnect and Ericsson WLAN. + * + * Copyright (C) 2000 David Gibson, Linuxcare Australia <hermes@gibson.dropbear.id.au> + * With some help from : + * Copyright (C) 2001 Jean Tourrilhes, HP Labs <jt@hpl.hp.com> + * + * Based on dummy_cs.c 1.27 2000/06/12 21:27:25 + * + * Portions based on wvlan_cs.c 1.0.6, Copyright Andreas Neuhaus <andy@fasta.fh-dortmund.de> + * http://www.fasta.fh-dortmund.de/users/andy/wvlan/ + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * <dahinds@users.sourceforge.net>. Portions created by David + * A. Hinds are Copyright (C) 1999 David A. Hinds. All Rights + * Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License version 2 (the "GPL"), in which + * case the provisions of the GPL are applicable instead of the above. + * If you wish to allow the use of your version of this file only + * under the terms of the GPL and not to allow others to use your + * version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ + +/* Notes on locking: + * + * The basic principle of operation is that everything except the + * interrupt handler is serialized through a single spinlock in the + * dldwd_priv_t structure, using dldwd_lock() and + * dldwd_unlock() (which in turn use spin_lock_bh() and spin_unlock_bh()). + * + * The kernel's IRQ handling stuff ensures that the interrupt handler + * does not re-enter itself. The interrupt handler is written such + * that everything it does is safe without a lock: chiefly this means + * that the Rx path uses one of the Hermes chipset's BAPs while + * everything else uses the other. + * + * For the moment access to the device statistics from the interrupt + * handler is unsafe - we just put up with any resulting errors in the + * statisics. FIXME: This should probably be changed to store the + * stats in atomic types. + * + * EXCEPT that we don't want the irq handler running when we actually + * reset or shut down the card, because strange things might happen + * (probably the worst would be one packet of garbage, but you can't + * be too careful). For this we use __dldwd_stop_irqs() which will set + * a flag to disable the interrupt handler, and wait for any + * outstanding instances of the handler to complete. THIS WILL LOSE + * INTERRUPTS! so it shouldn't be used except for resets, when we + * don't care about that.*/ + +/* + * Tentative changelog... + * + * v0.01 -> v0.02 - 21/3/2001 - Jean II + * o Allow to use regular ethX device name instead of dldwdX + * o Warning on IBSS with ESSID=any for firmware 6.06 + * o Put proper range.throughput values (optimistic) + * o IWSPY support (IOCTL and stat gather in Rx path) + * o Allow setting frequency in Ad-Hoc mode + * o Disable WEP setting if !has_wep to work on old firmware + * o Fix txpower range + * o Start adding support for Samsung/Compaq firmware + * + * v0.02 -> v0.03 - 23/3/2001 - Jean II + * o Start adding Symbol support - need to check all that + * o Fix Prism2/Symbol WEP to accept 128 bits keys + * o Add Symbol WEP (add authentication type) + * o Add Prism2/Symbol rate + * o Add PM timeout (holdover duration) + * o Enable "iwconfig eth0 key off" and friends (toggle flags) + * o Enable "iwconfig eth0 power unicast/all" (toggle flags) + * o Try with an intel card. It report firmware 1.01, behave like + * an antiquated firmware, however on windows it says 2.00. Yuck ! + * o Workaround firmware bug in allocate buffer (Intel 1.01) + * o Finish external renaming to orinoco... + * o Testing with various Wavelan firmwares + * + * TODO - Jean II + * o inline functions (lot's of candidate, need to reorder code) + * o Separate Pcmcia specific code to help Airport/Mini PCI driver + * o Test PrismII/Symbol cards & firmware versions + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/ptrace.h> +#include <linux/malloc.h> +#include <linux/string.h> +#include <linux/timer.h> +#include <linux/ioport.h> +#include <asm/uaccess.h> +#include <asm/io.h> +#include <asm/system.h> +#include <linux/proc_fs.h> +#include <linux/netdevice.h> +#include <linux/if_arp.h> +#include <linux/etherdevice.h> +#include <linux/wireless.h> + +#include <pcmcia/version.h> +#include <pcmcia/cs_types.h> +#include <pcmcia/cs.h> +#include <pcmcia/cistpl.h> +#include <pcmcia/cisreg.h> +#include <pcmcia/ds.h> +#include <pcmcia/bus_ops.h> + +#include "hermes.h" + +#ifdef PCMCIA_DEBUG +static int pc_debug = PCMCIA_DEBUG; +static char *version = "orinoco_cs.c 0.03 (David Gibson <hermes@gibson.dropbear.id.au>)"; +MODULE_PARM(pc_debug, "i"); +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) +#define DEBUGMORE(n, args...) do { if (pc_debug>(n)) printk(args); } while (0) +#else +#define DEBUG(n, args...) do { } while (0) +#define DEBUGMORE(n, args...) do { } while (0) +#endif + +#define TRACE_ENTER(devname) DEBUG(2, "%s: -> " __FUNCTION__ "()\n", devname); +#define TRACE_EXIT(devname) DEBUG(2, "%s: <- " __FUNCTION__ "()\n", devname); + +#define MAX(a, b) ( (a) > (b) ? (a) : (b) ) +#define MIN(a, b) ( (a) < (b) ? (a) : (b) ) + +#define RUP_EVEN(a) ( (a) % 2 ? (a) + 1 : (a) ) + + +#if (! defined (WIRELESS_EXT)) || (WIRELESS_EXT < 10) +#error "orinoco_cs requires Wireless extensions v10 or later." +#endif /* (! defined (WIRELESS_EXT)) || (WIRELESS_EXT < 10) */ +#define WIRELESS_SPY // enable iwspy support + +/*====================================================================*/ + +/* Parameters that can be set with 'insmod' */ + +/* The old way: bit map of interrupts to choose from */ +/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, and 3 */ +static uint irq_mask = 0xdeb8; +/* Newer, simpler way of listing specific interrupts */ +static int irq_list[4] = { -1 }; +/* Control device name allocation. 0 -> dldwdX ; 1 -> ethX */ +static int eth = 1; + +MODULE_PARM(irq_mask, "i"); +MODULE_PARM(irq_list, "1-4i"); +MODULE_PARM(eth, "i"); + +/*====================================================================*/ + +#define DLDWD_MIN_MTU 256 +#define DLDWD_MAX_MTU (HERMES_FRAME_LEN_MAX - ENCAPS_OVERHEAD) + +#define LTV_BUF_SIZE 128 +#define USER_BAP 0 +#define IRQ_BAP 1 +#define DLDWD_MACPORT 0 +#define IRQ_LOOP_MAX 10 +#define TX_NICBUF_SIZE 2048 +#define TX_NICBUF_SIZE_BUG 1585 /* Bug in Intel firmware */ +#define MAX_KEYS 4 +#define MAX_KEY_SIZE 14 +#define LARGE_KEY_SIZE 13 +#define SMALL_KEY_SIZE 5 +#define MAX_FRAME_SIZE 2304 + +const long channel_frequency[] = { + 2412, 2417, 2422, 2427, 2432, 2437, 2442, + 2447, 2452, 2457, 2462, 2467, 2472, 2484 +}; + +#define NUM_CHANNELS ( sizeof(channel_frequency) / sizeof(channel_frequency[0]) ) + +/* This tables gives the actual meanings of the bitrate IDs returned by the firmware. + It gives the rate in halfMb/s, negative indicates auto mode */ +const int rate_list[] = { 0, 2, 4, -22, 11, 22, -4, -11, 0, 0, 0, 0}; + +#define NUM_RATES (sizeof(rate_list) / sizeof(rate_list[0])) +typedef struct dldwd_key { + uint16_t len; + char data[MAX_KEY_SIZE]; +} __attribute__ ((packed)) dldwd_key_t; + +typedef dldwd_key_t dldwd_keys_t[MAX_KEYS]; + +typedef struct dldwd_priv { + dev_link_t link; + dev_node_t node; + int instance; + + spinlock_t lock; + long state; +#define DLDWD_STATE_INIRQ 0 +#define DLDWD_STATE_DOIRQ 1 + + /* Net device stuff */ + struct net_device ndev; + struct net_device_stats stats; + struct iw_statistics wstats; + + + /* Hardware control variables */ + hermes_t hw; + uint16_t txfid; + + /* Capabilities of the hardware/firmware */ + hermes_identity_t firmware_info; + int firmware_type; +#define FIRMWARE_TYPE_LUCENT 1 +#define FIRMWARE_TYPE_PRISM2 2 +#define FIRMWARE_TYPE_SYMBOL 3 + int has_ibss, has_port3, prefer_port3, has_ibss_any; + int has_wep, has_big_wep; + int has_mwo; + int has_pm; + int broken_reset, broken_allocate; + uint16_t channel_mask; + + /* Current configuration */ + uint32_t iw_mode; + int port_type, allow_ibss; + uint16_t wep_on, wep_auth, tx_key; + dldwd_keys_t keys; + char nick[IW_ESSID_MAX_SIZE+1]; + char desired_essid[IW_ESSID_MAX_SIZE+1]; + uint16_t frag_thresh, mwo_robust; + uint16_t channel; + uint16_t ap_density, rts_thresh; + uint16_t tx_rate_ctrl; + uint16_t pm_on, pm_mcast, pm_period, pm_timeout; + + int promiscuous, allmulti, mc_count; + +#ifdef WIRELESS_SPY + int spy_number; + u_char spy_address[IW_MAX_SPY][ETH_ALEN]; + struct iw_quality spy_stat[IW_MAX_SPY]; +#endif + + /* /proc based debugging stuff */ + struct proc_dir_entry *dir_dev; + struct proc_dir_entry *dir_regs; + struct proc_dir_entry *dir_recs; +} dldwd_priv_t; + +struct p80211_hdr { + uint16_t frame_ctl; + uint16_t duration_id; + uint8_t addr1[ETH_ALEN]; + uint8_t addr2[ETH_ALEN]; + uint8_t addr3[ETH_ALEN]; + uint16_t seq_ctl; + uint8_t addr4[ETH_ALEN]; + uint16_t data_len; +} __attribute__ ((packed)); + +/* Frame control field constants */ +#define DLDWD_FCTL_VERS 0x0002 +#define DLDWD_FCTL_FTYPE 0x000c +#define DLDWD_FCTL_STYPE 0x00f0 +#define DLDWD_FCTL_TODS 0x0100 +#define DLDWD_FCTL_FROMDS 0x0200 +#define DLDWD_FCTL_MOREFRAGS 0x0400 +#define DLDWD_FCTL_RETRY 0x0800 +#define DLDWD_FCTL_PM 0x1000 +#define DLDWD_FCTL_MOREDATA 0x2000 +#define DLDWD_FCTL_WEP 0x4000 +#define DLDWD_FCTL_ORDER 0x8000 + +#define DLDWD_FTYPE_MGMT 0x0000 +#define DLDWD_FTYPE_CTL 0x0004 +#define DLDWD_FTYPE_DATA 0x0008 + +struct p8022_hdr { + uint8_t dsap; + uint8_t ssap; + uint8_t ctrl; + uint8_t oui[3]; +} __attribute__ ((packed)); + +struct dldwd_frame_hdr { + hermes_frame_desc_t desc; + struct p80211_hdr p80211; + struct ethhdr p8023; + struct p8022_hdr p8022; + uint16_t ethertype; +} __attribute__ ((packed)); + +#define P8023_OFFSET (sizeof(hermes_frame_desc_t) + \ + sizeof(struct p80211_hdr)) +#define ENCAPS_OVERHEAD (sizeof(struct p8022_hdr) + 2) + +/* + * Function prototypes + */ + +/* PCMCIA gumpf */ + +static void dldwd_config(dev_link_t * link); +static void dldwd_release(u_long arg); +static int dldwd_event(event_t event, int priority, + event_callback_args_t * args); + +static dev_link_t *dldwd_attach(void); +static void dldwd_detach(dev_link_t *); + +/* Hardware control routines */ + +static int __dldwd_hw_reset(dldwd_priv_t *priv); +static void dldwd_shutdown(dldwd_priv_t *dev); +static int dldwd_reset(dldwd_priv_t *dev); +static int __dldwd_hw_setup_wep(dldwd_priv_t *priv); +static int dldwd_hw_get_bssid(dldwd_priv_t *priv, char buf[ETH_ALEN]); +static int dldwd_hw_get_essid(dldwd_priv_t *priv, int *active, char buf[IW_ESSID_MAX_SIZE+1]); +static long dldwd_hw_get_freq(dldwd_priv_t *priv); +static int dldwd_hw_get_bitratelist(dldwd_priv_t *priv, int *numrates, + int32_t *rates, int max); + +/* Interrupt handling routines */ +void dldwd_interrupt(int irq, void * dev_id, struct pt_regs *regs); +static void __dldwd_ev_tick(dldwd_priv_t *priv, hermes_t *hw); +static void __dldwd_ev_wterr(dldwd_priv_t *priv, hermes_t *hw); +static void __dldwd_ev_infdrop(dldwd_priv_t *priv, hermes_t *hw); +static void __dldwd_ev_info(dldwd_priv_t *priv, hermes_t *hw); +static void __dldwd_ev_rx(dldwd_priv_t *priv, hermes_t *hw); +static void __dldwd_ev_txexc(dldwd_priv_t *priv, hermes_t *hw); +static void __dldwd_ev_tx(dldwd_priv_t *priv, hermes_t *hw); +static void __dldwd_ev_alloc(dldwd_priv_t *priv, hermes_t *hw); + +/* struct net_device methods */ +static int dldwd_init(struct net_device *dev); +static int dldwd_open(struct net_device *dev); +static int dldwd_stop(struct net_device *dev); + +static int dldwd_xmit(struct sk_buff *skb, struct net_device *dev); +static void dldwd_tx_timeout(struct net_device *dev); + +static struct net_device_stats *dldwd_get_stats(struct net_device *dev); +static struct iw_statistics *dldwd_get_wireless_stats(struct net_device *dev); +static void dldwd_stat_gather(struct net_device *dev, + struct sk_buff *skb, + struct dldwd_frame_hdr *hdr); + +static int dldwd_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq); +static int dldwd_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq); +static int dldwd_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq); +static int dldwd_ioctl_setessid(struct net_device *dev, struct iw_point *erq); +static int dldwd_ioctl_getessid(struct net_device *dev, struct iw_point *erq); +static int dldwd_ioctl_setnick(struct net_device *dev, struct iw_point *nrq); +static int dldwd_ioctl_getnick(struct net_device *dev, struct iw_point *nrq); +static int dldwd_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq); +static int dldwd_ioctl_getsens(struct net_device *dev, struct iw_param *srq); +static int dldwd_ioctl_setsens(struct net_device *dev, struct iw_param *srq); +static int dldwd_ioctl_setrts(struct net_device *dev, struct iw_param *rrq); +static int dldwd_ioctl_setfrag(struct net_device *dev, struct iw_param *frq); +static int dldwd_ioctl_getfrag(struct net_device *dev, struct iw_param *frq); +static int dldwd_ioctl_setrate(struct net_device *dev, struct iw_param *frq); +static int dldwd_ioctl_getrate(struct net_device *dev, struct iw_param *frq); +static int dldwd_ioctl_setpower(struct net_device *dev, struct iw_param *prq); +static int dldwd_ioctl_getpower(struct net_device *dev, struct iw_param *prq); +static int dldwd_ioctl_setport3(struct net_device *dev, struct iwreq *wrq); +static int dldwd_ioctl_getport3(struct net_device *dev, struct iwreq *wrq); +static int dldwd_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); + +static int dldwd_change_mtu(struct net_device *dev, int new_mtu); +static void __dldwd_set_multicast_list(struct net_device *dev); + +/* /proc debugging stuff */ +static int dldwd_proc_init(void); +static void dldwd_proc_cleanup(void); +static int dldwd_proc_dev_init(dldwd_priv_t *dev); +static void dldwd_proc_dev_cleanup(dldwd_priv_t *dev); + +/* + * Inline functions + */ +static inline void +dldwd_lock(dldwd_priv_t *priv) +{ + spin_lock_bh(&priv->lock); +} + +static inline void +dldwd_unlock(dldwd_priv_t *priv) +{ + spin_unlock_bh(&priv->lock); +} + +static inline int +dldwd_irqs_allowed(dldwd_priv_t *priv) +{ + return test_bit(DLDWD_STATE_DOIRQ, &priv->state); +} + +static inline void +__dldwd_stop_irqs(dldwd_priv_t *priv) +{ + hermes_t *hw = &priv->hw; + + hermes_set_irqmask(hw, 0); + clear_bit(DLDWD_STATE_DOIRQ, &priv->state); + while (test_bit(DLDWD_STATE_INIRQ, &priv->state)) + ; +} + +static inline void +__dldwd_start_irqs(dldwd_priv_t *priv, uint16_t irqmask) +{ + hermes_t *hw = &priv->hw; + + TRACE_ENTER(priv->ndev.name); + + __cli(); + set_bit(DLDWD_STATE_DOIRQ, &priv->state); + hermes_set_irqmask(hw, irqmask); + __sti(); + + TRACE_EXIT(priv->ndev.name); +} + +static inline void +set_port_type(dldwd_priv_t *priv) +{ + switch (priv->iw_mode) { + case IW_MODE_INFRA: + priv->port_type = 1; + priv->allow_ibss = 0; + break; + case IW_MODE_ADHOC: + if (priv->prefer_port3) { + priv->port_type = 3; + priv->allow_ibss = 0; + } else { + priv->port_type = 1; + priv->allow_ibss = 1; + } + break; + default: + printk(KERN_ERR "%s: Invalid priv->iw_mode in set_port_type()\n", + priv->ndev.name); + } +} + +static inline void +dldwd_set_multicast_list(struct net_device *dev) +{ + dldwd_priv_t *priv = dev->priv; + + dldwd_lock(priv); + __dldwd_set_multicast_list(dev); + dldwd_unlock(priv); +} + +/* + * Hardware control routines + */ + +static int +__dldwd_hw_reset(dldwd_priv_t *priv) +{ + hermes_t *hw = &priv->hw; + int err; + + if (! priv->broken_reset) + return hermes_reset(hw); + else { + hw->inten = 0; + hermes_write_regn(hw, INTEN, 0); + err = hermes_disable_port(hw, 0); + hermes_write_regn(hw, EVACK, 0xffff); + return err; + } +} + +static void +dldwd_shutdown(dldwd_priv_t *priv) +{ +/* hermes_t *hw = &priv->hw; */ + int err = 0; + + TRACE_ENTER(priv->ndev.name); + + dldwd_lock(priv); + __dldwd_stop_irqs(priv); + + err = __dldwd_hw_reset(priv); + if (err && err != -ENODEV) /* If the card is gone, we don't care about shutting it down */ + printk(KERN_ERR "%s: Error %d shutting down Hermes chipset\n", priv->ndev.name, err); + + dldwd_unlock(priv); + + TRACE_EXIT(priv->ndev.name); +} + +static int +dldwd_reset(dldwd_priv_t *priv) +{ + struct net_device *dev = &priv->ndev; + hermes_t *hw = &priv->hw; + int err = 0; + hermes_id_t idbuf; + int frame_size; + + TRACE_ENTER(priv->ndev.name); + + dldwd_lock(priv); + + __dldwd_stop_irqs(priv); + + err = __dldwd_hw_reset(priv); + if (err) + goto out; + + frame_size = TX_NICBUF_SIZE; + /* This stupid bug is present in Intel firmware 1.10, and + * may be fixed in later firmwares - Jean II */ + if(priv->broken_allocate) + frame_size = TX_NICBUF_SIZE_BUG; + err = hermes_allocate(hw, frame_size, &priv->txfid); + if (err) + goto out; + + /* Now set up all the parameters on the card */ + + /* Set up the link mode */ + + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PORTTYPE, priv->port_type); + if (err) + goto out; + if (priv->has_ibss) { + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_CREATEIBSS, + priv->allow_ibss); + if (err) + goto out; + if((strlen(priv->desired_essid) == 0) && (priv->allow_ibss) + && (!priv->has_ibss_any)) { + printk(KERN_WARNING "%s: This firmware requires an \ +ESSID in IBSS-Ad-Hoc mode.\n", dev->name); + /* With wvlan_cs, in this case, we would crash. + * hopefully, this driver will behave better... + * Jean II */ + } + } + + /* Set up encryption */ + if (priv->has_wep) { + err = __dldwd_hw_setup_wep(priv); + if (err) + goto out; + } + + /* Set the desired ESSID */ + idbuf.len = cpu_to_le16(strlen(priv->desired_essid)); + memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val)); + err = hermes_write_ltv(hw, USER_BAP, (priv->port_type == 3) ? + HERMES_RID_CNF_OWN_SSID : HERMES_RID_CNF_DESIRED_SSID, + HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2), + &idbuf); + if (err) + goto out; + + /* Set the station name */ + idbuf.len = cpu_to_le16(strlen(priv->nick)); + memcpy(&idbuf.val, priv->nick, sizeof(idbuf.val)); + err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNF_NICKNAME, + HERMES_BYTES_TO_RECLEN(strlen(priv->nick)+2), + &idbuf); + if (err) + goto out; + + /* Set the channel/frequency */ + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_CHANNEL, priv->channel); + if (err) + goto out; + + /* Set AP density */ + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYSTEM_SCALE, priv->ap_density); + if (err) + goto out; + + /* Set RTS threshold */ + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_RTS_THRESH, priv->rts_thresh); + if (err) + goto out; + + /* Set fragmentation threshold or MWO robustness */ + if (priv->has_mwo) + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNF_MWO_ROBUST, priv->mwo_robust); + else + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNF_FRAG_THRESH, priv->frag_thresh); + if (err) + goto out; + + /* Set bitrate */ + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_TX_RATE_CTRL, + priv->tx_rate_ctrl); + if (err) + goto out; + + /* Set power management */ + if (priv->has_pm) { + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_ENABLE, + priv->pm_on); + if (err) + goto out; + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_MCAST_RX, + priv->pm_mcast); + if (err) + goto out; + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_PERIOD, + priv->pm_period); + if (err) + goto out; + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_HOLDOVER, + priv->pm_timeout); + if (err) + goto out; + } + + /* Set promiscuity / multicast*/ + priv->promiscuous = 0; + priv->allmulti = 0; + priv->mc_count = 0; + __dldwd_set_multicast_list(dev); + + err = hermes_enable_port(hw, DLDWD_MACPORT); + if (err) + goto out; + + __dldwd_start_irqs(priv, HERMES_EV_RX | HERMES_EV_ALLOC | + HERMES_EV_TX | HERMES_EV_TXEXC | + HERMES_EV_WTERR | HERMES_EV_INFO | + HERMES_EV_INFDROP); + + out: + dldwd_unlock(priv); + + TRACE_EXIT(priv->ndev.name); + + return err; +} + +static int __dldwd_hw_setup_wep(dldwd_priv_t *priv) +{ + hermes_t *hw = &priv->hw; + int err = 0; + + switch (priv->firmware_type) { + case FIRMWARE_TYPE_LUCENT: /* Lucent style WEP */ + if (priv->wep_on) { + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_TX_KEY, priv->tx_key); + if (err) + return err; + + err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNF_KEYS, &priv->keys); + if (err) + return err; + } + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_WEP_ON, priv->wep_on); + if (err) + return err; + break; + + case FIRMWARE_TYPE_PRISM2: /* Prism II style WEP */ + case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */ + if (priv->wep_on) { + char keybuf[LARGE_KEY_SIZE+1]; + int keylen; + int i; + + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PRISM2_TX_KEY, + priv->tx_key); + if (err) + return err; + + keybuf[LARGE_KEY_SIZE] = '\0'; + + /* Write all 4 keys */ + for(i = 0; i < MAX_KEYS; i++) { + keylen = priv->keys[i].len; + keybuf[SMALL_KEY_SIZE] = '\0'; + memcpy(keybuf, priv->keys[i].data, keylen); + err = HERMES_WRITE_RECORD_LEN(hw, USER_BAP, HERMES_RID_CNF_PRISM2_KEY0, &keybuf, keylen); + if (err) + return err; + } + /* Symbol cards : set the authentication : + * 0 -> no encryption, 1 -> open, + * 2 -> shared key, 3 -> shared key 128bit only */ + if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL) { + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYMBOL_AUTH_TYPE, priv->wep_auth); + if (err) + return err; + } + } + + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PRISM2_WEP_ON, priv->wep_on); + if (err) + return err; + break; + + default: + if (priv->wep_on) { + printk(KERN_ERR "%s: WEP enabled, although not supported!\n", + priv->ndev.name); + return -EINVAL; + } + } + + return 0; +} + +static int dldwd_hw_get_bssid(dldwd_priv_t *priv, char buf[ETH_ALEN]) +{ + hermes_t *hw = &priv->hw; + int err = 0; + + dldwd_lock(priv); + + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_BSSID, + ETH_ALEN, NULL, buf); + + dldwd_unlock(priv); + + return err; +} + +static int dldwd_hw_get_essid(dldwd_priv_t *priv, int *active, + char buf[IW_ESSID_MAX_SIZE+1]) +{ + hermes_t *hw = &priv->hw; + int err = 0; + hermes_id_t essidbuf; + char *p = (char *)(&essidbuf.val); + int len; + + TRACE_ENTER(priv->ndev.name); + + dldwd_lock(priv); + + if (strlen(priv->desired_essid) > 0) { + /* We read the desired SSID from the hardware rather + than from priv->desired_essid, just in case the + firmware is allowed to change it on us. I'm not + sure about this */ + /* My guess is that the OWN_SSID should always be whatever + * we set to the card, whereas CURRENT_SSID is the one that + * may change... - Jean II */ + uint16_t rid; + + *active = 1; + + rid = (priv->port_type == 3) ? HERMES_RID_CNF_OWN_SSID : + HERMES_RID_CNF_DESIRED_SSID; + + err = hermes_read_ltv(hw, USER_BAP, rid, sizeof(essidbuf), + NULL, &essidbuf); + if (err) + goto fail_unlock; + } else { + *active = 0; + + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_SSID, + sizeof(essidbuf), NULL, &essidbuf); + if (err) + goto fail_unlock; + } + + len = le16_to_cpu(essidbuf.len); + + memset(buf, 0, sizeof(buf)); + memcpy(buf, p, len); + buf[len] = '\0'; + + fail_unlock: + dldwd_unlock(priv); + + TRACE_EXIT(priv->ndev.name); + + return err; +} + +static long dldwd_hw_get_freq(dldwd_priv_t *priv) +{ + + hermes_t *hw = &priv->hw; + int err = 0; + uint16_t channel; + long freq = 0; + + dldwd_lock(priv); + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENT_CHANNEL, &channel); + if (err) + goto out; + + if ( (channel < 1) || (channel > NUM_CHANNELS) ) { + struct net_device *dev = &priv->ndev; + + printk(KERN_WARNING "%s: Channel out of range (%d)!\n", dev->name, channel); + err = -EBUSY; + goto out; + + } + freq = channel_frequency[channel-1] * 100000; + + out: + dldwd_unlock(priv); + + if (err > 0) + err = -EBUSY; + return err ? err : freq; +} + +static int dldwd_hw_get_bitratelist(dldwd_priv_t *priv, int *numrates, + int32_t *rates, int max) +{ + hermes_t *hw = &priv->hw; + hermes_id_t list; + unsigned char *p = (unsigned char *)&list.val; + int err = 0; + int num; + int i; + + dldwd_lock(priv); + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_DATARATES, sizeof(list), + NULL, &list); + dldwd_unlock(priv); + + if (err) + return err; + + num = le16_to_cpu(list.len); + *numrates = num; + num = MIN(num, max); + + for (i = 0; i < num; i++) { + rates[i] = (p[i] & 0x7f) * 500000; /* convert to bps */ + } + + return 0; +} + +#ifndef PCMCIA_DEBUG +static inline void show_rx_frame(struct dldwd_frame_hdr *frame) {} +#else +static void show_rx_frame(struct dldwd_frame_hdr *frame) +{ + printk(KERN_DEBUG "RX descriptor:\n"); + printk(KERN_DEBUG " status = 0x%04x\n", frame->desc.status); + printk(KERN_DEBUG " res1 = 0x%04x\n", frame->desc.res1); + printk(KERN_DEBUG " res2 = 0x%04x\n", frame->desc.res2); + printk(KERN_DEBUG " q_info = 0x%04x\n", frame->desc.q_info); + printk(KERN_DEBUG " res3 = 0x%04x\n", frame->desc.res3); + printk(KERN_DEBUG " res4 = 0x%04x\n", frame->desc.res4); + printk(KERN_DEBUG " tx_ctl = 0x%04x\n", frame->desc.tx_ctl); + + printk(KERN_DEBUG "IEEE 802.11 header:\n"); + printk(KERN_DEBUG " frame_ctl = 0x%04x\n", + frame->p80211.frame_ctl); + printk(KERN_DEBUG " duration_id = 0x%04x\n", + frame->p80211.duration_id); + printk(KERN_DEBUG " addr1 = %02x:%02x:%02x:%02x:%02x:%02x\n", + frame->p80211.addr1[0], frame->p80211.addr1[1], + frame->p80211.addr1[2], frame->p80211.addr1[3], + frame->p80211.addr1[4], frame->p80211.addr1[5]); + printk(KERN_DEBUG " addr2 = %02x:%02x:%02x:%02x:%02x:%02x\n", + frame->p80211.addr2[0], frame->p80211.addr2[1], + frame->p80211.addr2[2], frame->p80211.addr2[3], + frame->p80211.addr2[4], frame->p80211.addr2[5]); + printk(KERN_DEBUG " addr3 = %02x:%02x:%02x:%02x:%02x:%02x\n", + frame->p80211.addr3[0], frame->p80211.addr3[1], + frame->p80211.addr3[2], frame->p80211.addr3[3], + frame->p80211.addr3[4], frame->p80211.addr3[5]); + printk(KERN_DEBUG " seq_ctl = 0x%04x\n", + frame->p80211.seq_ctl); + printk(KERN_DEBUG " addr4 = %02x:%02x:%02x:%02x:%02x:%02x\n", + frame->p80211.addr4[0], frame->p80211.addr4[1], + frame->p80211.addr4[2], frame->p80211.addr4[3], + frame->p80211.addr4[4], frame->p80211.addr4[5]); + printk(KERN_DEBUG " data_len = 0x%04x\n", + frame->p80211.data_len); + + printk(KERN_DEBUG "IEEE 802.3 header:\n"); + printk(KERN_DEBUG " dest = %02x:%02x:%02x:%02x:%02x:%02x\n", + frame->p8023.h_dest[0], frame->p8023.h_dest[1], + frame->p8023.h_dest[2], frame->p8023.h_dest[3], + frame->p8023.h_dest[4], frame->p8023.h_dest[5]); + printk(KERN_DEBUG " src = %02x:%02x:%02x:%02x:%02x:%02x\n", + frame->p8023.h_source[0], frame->p8023.h_source[1], + frame->p8023.h_source[2], frame->p8023.h_source[3], + frame->p8023.h_source[4], frame->p8023.h_source[5]); + printk(KERN_DEBUG " len = 0x%04x\n", frame->p8023.h_proto); + + printk(KERN_DEBUG "IEEE 802.2 LLC/SNAP header:\n"); + printk(KERN_DEBUG " DSAP = 0x%02x\n", frame->p8022.dsap); + printk(KERN_DEBUG " SSAP = 0x%02x\n", frame->p8022.ssap); + printk(KERN_DEBUG " ctrl = 0x%02x\n", frame->p8022.ctrl); + printk(KERN_DEBUG " OUI = %02x:%02x:%02x\n", + frame->p8022.oui[0], frame->p8022.oui[1], frame->p8022.oui[2]); + printk(KERN_DEBUG " ethertype = 0x%04x\n", frame->ethertype); +} +#endif + +/* + * Interrupt handler + */ +void dldwd_interrupt(int irq, void * dev_id, struct pt_regs *regs) +{ + dldwd_priv_t *priv = (dldwd_priv_t *) dev_id; + hermes_t *hw = &priv->hw; + struct net_device *dev = &priv->ndev; + int count = IRQ_LOOP_MAX; + uint16_t evstat, events; + static int old_time = 0, timecount = 0; /* Eugh, revolting hack for now */ + + if (test_and_set_bit(DLDWD_STATE_INIRQ, &priv->state)) + BUG(); + + if (! dldwd_irqs_allowed(priv)) { + clear_bit(DLDWD_STATE_INIRQ, &priv->state); + return; + } + + DEBUG(3, "%s: dldwd_interrupt() irq %d\n", priv->ndev.name, irq); + + while (1) { + if (jiffies != old_time) + timecount = 0; + if ( (++timecount > 50) || (! count--) ) { + printk(KERN_CRIT "%s: IRQ handler is looping too \ +much! Shutting down.\n", + dev->name); + /* Perform an emergency shutdown */ + clear_bit(DLDWD_STATE_DOIRQ, &priv->state); + hermes_set_irqmask(hw, 0); + break; + } + + evstat = hermes_read_regn(hw, EVSTAT); + DEBUG(3, "__dldwd_interrupt(): count=%d EVSTAT=0x%04x inten=0x%04x\n", + count, evstat, hw->inten); + + events = evstat & hw->inten; + + if (! events) { + if (netif_queue_stopped(dev)) { + /* There seems to be a firmware bug which + sometimes causes the card to give an + interrupt with no event set, when there + sould be a Tx completed event. */ + DEBUG(3, "%s: Interrupt with no event (ALLOCFID=0x%04x)\n", + dev->name, (int)hermes_read_regn(hw, ALLOCFID)); + events = HERMES_EV_TX | HERMES_EV_ALLOC; + } else /* Nothing's happening, we're done */ + break; + } + + /* Check the card hasn't been removed */ + if (! hermes_present(hw)) { + DEBUG(0, "dldwd_interrupt(): card removed\n"); + break; + } + + if (events & HERMES_EV_TICK) + __dldwd_ev_tick(priv, hw); + if (events & HERMES_EV_WTERR) + __dldwd_ev_wterr(priv, hw); + if (events & HERMES_EV_INFDROP) + __dldwd_ev_infdrop(priv, hw); + if (events & HERMES_EV_INFO) + __dldwd_ev_info(priv, hw); + if (events & HERMES_EV_RX) + __dldwd_ev_rx(priv, hw); + if (events & HERMES_EV_TXEXC) + __dldwd_ev_txexc(priv, hw); + if (events & HERMES_EV_TX) + __dldwd_ev_tx(priv, hw); + if (events & HERMES_EV_ALLOC) + __dldwd_ev_alloc(priv, hw); + + hermes_write_regn(hw, EVACK, events); + } + + clear_bit(DLDWD_STATE_INIRQ, &priv->state); +} + +static void __dldwd_ev_tick(dldwd_priv_t *priv, hermes_t *hw) +{ + printk(KERN_DEBUG "%s: TICK\n", priv->ndev.name); +} + +static void __dldwd_ev_wterr(dldwd_priv_t *priv, hermes_t *hw) +{ + /* This seems to happen a fair bit under load, but ignoring it + seems to work fine...*/ + DEBUG(1, "%s: MAC controller error (WTERR). Ignoring.\n", + priv->ndev.name); +} + +static void __dldwd_ev_infdrop(dldwd_priv_t *priv, hermes_t *hw) +{ + printk(KERN_WARNING "%s: Information frame lost.\n", priv->ndev.name); +} + +static void __dldwd_ev_info(dldwd_priv_t *priv, hermes_t *hw) +{ + DEBUG(3, "%s: Information frame received.\n", priv->ndev.name); + /* We don't actually do anything about it - we assume the MAC + controller can deal with it */ +} + +static void __dldwd_ev_rx(dldwd_priv_t *priv, hermes_t *hw) +{ + struct net_device *dev = &priv->ndev; + struct net_device_stats *stats = &priv->stats; + struct iw_statistics *wstats = &priv->wstats; + struct sk_buff *skb = NULL; + uint16_t rxfid, status; + int length, data_len, data_off; + char *p; + struct dldwd_frame_hdr hdr; + struct ethhdr *eh; + int err; + + rxfid = hermes_read_regn(hw, RXFID); + DEBUG(3, "__dldwd_ev_rx(): RXFID=0x%04x\n", rxfid); + + /* We read in the entire frame header here. This isn't really + necessary, since we ignore most of it, but it's + conceptually simpler. We can tune this later if + necessary. */ + err = hermes_bap_pread(hw, IRQ_BAP, &hdr, sizeof(hdr), rxfid, 0); + if (err) { + printk(KERN_ERR "%s: error %d reading frame header. " + "Frame dropped.\n", dev->name, err); + stats->rx_errors++; + goto drop; + } + + status = le16_to_cpu(hdr.desc.status); + + if (status & HERMES_RXSTAT_ERR) { + if ((status & HERMES_RXSTAT_ERR) == HERMES_RXSTAT_BADCRC) { + stats->rx_crc_errors++; + printk(KERN_WARNING "%s: Bad CRC on Rx. Frame dropped.\n", + dev->name); + show_rx_frame(&hdr); + } else if ((status & HERMES_RXSTAT_ERR) + == HERMES_RXSTAT_UNDECRYPTABLE) { + wstats->discard.code++; + printk(KERN_WARNING "%s: Undecryptable frame on Rx. Frame dropped.\n", + dev->name); + } else { + wstats->discard.misc++; + printk("%s: Unknown Rx error (0x%x). Frame dropped.\n", + dev->name, status & HERMES_RXSTAT_ERR); + } + stats->rx_errors++; + goto drop; + } + + length = le16_to_cpu(hdr.p80211.data_len); + /* Yes, you heard right, that's le16. 802.2 and 802.3 are + big-endian, but 802.11 is little-endian believe it or + not. */ + /* Correct. 802.3 is big-endian byte order and little endian bit + * order, whereas 802.11 is little endian for both byte and bit + * order. That's specified in the 802.11 spec. - Jean II */ + + /* Sanity check */ + if (length > MAX_FRAME_SIZE) { + printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n", + dev->name, length); + stats->rx_length_errors++; + stats->rx_errors++; + goto drop; + } + + /* We need space for the packet data itself, plus an ethernet + header, plus 2 bytes so we can align the IP header on a + 32bit boundary, plus 1 byte so we can read in odd length + packets from the card, which has an IO granularity of 16 + bits */ + skb = dev_alloc_skb(length+ETH_HLEN+2+1); + if (!skb) { + printk(KERN_WARNING "%s: Can't allocate skb for Rx\n", + dev->name); + stats->rx_dropped++; + goto drop; + } + + skb_reserve(skb, 2); /* This way the IP header is aligned */ + + /* Handle decapsulation */ + switch (status & HERMES_RXSTAT_MSGTYPE) { + /* These both indicate a SNAP within 802.2 LLC within + 802.3 within 802.11 frame which we'll need to + de-encapsulate. IEEE and ISO OSI have a lot to + answer for. */ + case HERMES_RXSTAT_1042: + case HERMES_RXSTAT_TUNNEL: + data_len = length - ENCAPS_OVERHEAD; + data_off = sizeof(hdr); + + eh = (struct ethhdr *)skb_put(skb, ETH_HLEN); + + memcpy(eh, &hdr.p8023, sizeof(hdr.p8023)); + eh->h_proto = hdr.ethertype; + + break; + + /* Otherwise, we just throw the whole thing in, and hope + the protocol layer can deal with it as 802.3 */ + default: + data_len = length; + data_off = P8023_OFFSET; + break; + } + + p = skb_put(skb, data_len); + if (hermes_bap_pread(hw, IRQ_BAP, p, RUP_EVEN(data_len), + rxfid, data_off) != 0) { + printk(KERN_WARNING "%s: Error reading packet data\n", + dev->name); + stats->rx_errors++; + goto drop; + } + + dev->last_rx = jiffies; + skb->dev = dev; + skb->protocol = eth_type_trans(skb, dev); + skb->ip_summed = CHECKSUM_NONE; + + /* Process the wireless stats if needed */ + dldwd_stat_gather(dev, skb, &hdr); + + /* Pass the packet to the networking stack */ + netif_rx(skb); + stats->rx_packets++; + stats->rx_bytes += length; + + return; + + drop: + if (skb) + dev_kfree_skb_irq(skb); + return; +} + +static void __dldwd_ev_txexc(dldwd_priv_t *priv, hermes_t *hw) +{ + struct net_device *dev = &priv->ndev; + struct net_device_stats *stats = &priv->stats; + + printk(KERN_WARNING "%s: Tx error!\n", dev->name); + + netif_wake_queue(dev); + stats->tx_errors++; +} + +static void __dldwd_ev_tx(dldwd_priv_t *priv, hermes_t *hw) +{ + struct net_device *dev = &priv->ndev; + struct net_device_stats *stats = &priv->stats; + + DEBUG(3, "%s: Transmit completed\n", dev->name); + + stats->tx_packets++; + netif_wake_queue(dev); +} + +static void __dldwd_ev_alloc(dldwd_priv_t *priv, hermes_t *hw) +{ + uint16_t allocfid; + + allocfid = hermes_read_regn(hw, ALLOCFID); + DEBUG(3, "%s: Allocation complete FID=0x%04x\n", priv->ndev.name, allocfid); + + /* For some reason we don't seem to get transmit completed events properly */ + if (allocfid == priv->txfid) + __dldwd_ev_tx(priv, hw); + +/* hermes_write_regn(hw, ALLOCFID, 0); */ +} + +/* + * struct net_device methods + */ + +static int dldwd_init(struct net_device *dev) +{ + dldwd_priv_t *priv = dev->priv; + hermes_t *hw = &priv->hw; + int err = 0; + hermes_id_t nickbuf; + uint16_t reclen; + int len; + char *vendor_str; + uint32_t firmver; + + TRACE_ENTER("dldwd"); + + dldwd_lock(priv); + + err = hermes_reset(hw); + if (err != 0) { + printk(KERN_ERR "%s: failed to reset hardware\n", dev->name); + goto out; + } + + /* Get the firmware version */ + err = hermes_read_staidentity(hw, USER_BAP, &priv->firmware_info); + if (err) { + printk(KERN_WARNING "%s: Error %d reading firmware info. Wildly guessing capabilities...\n", + dev->name, err); + memset(&priv->firmware_info, 0, sizeof(priv->firmware_info)); + } + + firmver = ((uint32_t)priv->firmware_info.major << 16) | priv->firmware_info.minor; + + /* Determine capabilities from the firmware version */ + + switch (priv->firmware_info.vendor) { + case 0x1: + /* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout, + * ELSA, Melco, HP, IBM, Dell 1150 cards */ + vendor_str = "Lucent"; + /* Lucent MAC : 00:60:1D:* & 00:02:2D:* */ + + priv->firmware_type = FIRMWARE_TYPE_LUCENT; + priv->broken_reset = 0; + priv->broken_allocate = 0; + priv->has_port3 = 1; + priv->has_ibss = (firmver >= 0x60006); + priv->has_ibss_any = (firmver >= 0x60010); + priv->has_wep = (firmver >= 0x40020); + priv->has_big_wep = 1; /* FIXME: this is wrong - how do we tell + Gold cards from the others? */ + priv->has_mwo = (firmver >= 0x60000); + priv->has_pm = (firmver >= 0x40020); + /* Tested with Lucent firmware : + * 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 => Jean II + * Tested CableTron firmware : 4.32 => Anton */ + break; + case 0x2: + vendor_str = "Generic Prism II"; + /* Note : my Intel card report this value, but I can't do + * much with it, so I guess it's broken - Jean II */ + + priv->firmware_type = FIRMWARE_TYPE_PRISM2; + priv->broken_reset = 0; + priv->broken_allocate = (firmver <= 0x10001); + priv->has_port3 = 1; + priv->has_ibss = 0; /* FIXME: no idea if this is right */ + priv->has_wep = (firmver >= 0x20000); + priv->has_big_wep = 1; + priv->has_mwo = 0; + priv->has_pm = (firmver >= 0x20000); + /* Tested with Intel firmware : 1.01 => Jean II */ + /* Note : firmware 1.01 is *seriously* broken */ + break; + case 0x3: + vendor_str = "Samsung"; + /* To check - Should cover Samsung & Compaq */ + + priv->firmware_type = FIRMWARE_TYPE_PRISM2; + priv->broken_reset = 0; + priv->broken_allocate = 0; + priv->has_port3 = 1; + priv->has_ibss = 0; /* FIXME: available in later firmwares */ + priv->has_wep = (firmver >= 0x20000); /* FIXME */ + priv->has_big_wep = 0; /* FIXME */ + priv->has_mwo = 0; + priv->has_pm = (firmver >= 0x20000); /* FIXME */ + break; + case 0x6: + vendor_str = "LinkSys/D-Link"; + /* To check */ + + priv->firmware_type = FIRMWARE_TYPE_PRISM2; + priv->broken_reset = 0; + priv->broken_allocate = 0; + priv->has_port3 = 1; + priv->has_ibss = 0; /* FIXME: available in later firmwares */ + priv->has_wep = (firmver >= 0x20000); /* FIXME */ + priv->has_big_wep = 0; + priv->has_mwo = 0; + priv->has_pm = (firmver >= 0x20000); /* FIXME */ + break; +#if 0 + case 0x???: /* Could someone help here ??? */ + vendor_str = "Symbol"; + /* Symbol , 3Com AirConnect, Ericsson WLAN */ + + priv->firmware_type = FIRMWARE_TYPE_SYMBOL; + priv->broken_reset = 0; + priv->broken_allocate = 0; + priv->has_port3 = 1; + priv->has_ibss = 0; /* FIXME: available in later firmwares */ + priv->has_wep = (firmver >= 0x20000); /* FIXME */ + priv->has_big_wep = 1; /* Probably RID_SYMBOL_KEY_LENGTH */ + priv->has_mwo = 0; + priv->has_pm = (firmver >= 0x20000); + break; +#endif + default: + vendor_str = "UNKNOWN"; + + priv->firmware_type = 0; + priv->broken_reset = 0; + priv->broken_allocate = 0; + priv->has_port3 = 0; + priv->has_ibss = 0; + priv->has_wep = 0; + priv->has_big_wep = 0; + priv->has_mwo = 0; + priv->has_pm = 0; + } + + printk(KERN_INFO "%s: Firmware ID %02X vendor 0x%x (%s) version %d.%02d\n", + dev->name, priv->firmware_info.id, priv->firmware_info.vendor, + vendor_str, priv->firmware_info.major, priv->firmware_info.minor); + + if ((priv->broken_reset) || (priv->broken_allocate)) + printk(KERN_INFO "%s: Buggy firmware, please upgrade ASAP.\n", dev->name); + if (priv->has_port3) + printk(KERN_INFO "%s: Ad-hoc demo mode supported.\n", dev->name); + if (priv->has_ibss) + printk(KERN_INFO "%s: IEEE standard IBSS ad-hoc mode supported.\n", + dev->name); + if (priv->has_wep) { + printk(KERN_INFO "%s: WEP supported, ", dev->name); + if (priv->has_big_wep) + printk("\"128\"-bit key.\n"); + else + printk("40-bit key."); + } + + /* Get the MAC address */ + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNF_MACADDR, + ETH_ALEN, NULL, dev->dev_addr); + if (err) { + printk(KERN_WARNING "%s: failed to read MAC address!\n", + dev->name); + goto out; + } + + printk(KERN_INFO "%s: MAC address %02X:%02X:%02X:%02X:%02X:%02X\n", + dev->name, dev->dev_addr[0], dev->dev_addr[1], + dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], + dev->dev_addr[5]); + + /* Get the station name */ + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNF_NICKNAME, + sizeof(nickbuf), &reclen, &nickbuf); + if (err) { + printk(KERN_ERR "%s: failed to read station name!n", + dev->name); + goto out; + } + if ( nickbuf.len ) + len = MIN(IW_ESSID_MAX_SIZE, le16_to_cpu(nickbuf.len)); + else + len = MIN(IW_ESSID_MAX_SIZE, 2 * reclen); + memcpy(priv->nick, &nickbuf.val, len); + priv->nick[len] = '\0'; + + printk(KERN_INFO "%s: Station name \"%s\"\n", dev->name, priv->nick); + + /* Get allowed channels */ + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CHANNEL_LIST, &priv->channel_mask); + if (err) { + printk(KERN_ERR "%s: failed to read channel list!\n", + dev->name); + goto out; + } + + /* Get initial AP density */ + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYSTEM_SCALE, &priv->ap_density); + if (err) { + printk(KERN_ERR "%s: failed to read AP density!\n", dev->name); + goto out; + } + + /* Get initial RTS threshold */ + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_RTS_THRESH, &priv->rts_thresh); + if (err) { + printk(KERN_ERR "%s: failed to read RTS threshold!\n", dev->name); + goto out; + } + + /* Get initial fragmentation settings */ + if (priv->has_mwo) + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_MWO_ROBUST, + &priv->mwo_robust); + else + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_FRAG_THRESH, + &priv->frag_thresh); + if (err) { + printk(KERN_ERR "%s: failed to read fragmentation settings!\n", dev->name); + goto out; + } + + /* Set initial bitrate control*/ + priv->tx_rate_ctrl = 3; + + /* Power management setup */ + if (priv->has_pm) { + priv->pm_on = 0; + priv->pm_mcast = 1; + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_PERIOD, + &priv->pm_period); + if (err) { + printk(KERN_ERR "%s: failed to read power management period!\n", + dev->name); + goto out; + } + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_HOLDOVER, + &priv->pm_timeout); + if (err) { + printk(KERN_ERR "%s: failed to read power management timeout!\n", + dev->name); + goto out; + } + } + + /* Set up the default configuration */ + priv->iw_mode = IW_MODE_INFRA; + /* By default use IEEE/IBSS ad-hoc mode if we have it */ + priv->prefer_port3 = priv->has_port3 && (! priv->has_ibss); + set_port_type(priv); + + priv->promiscuous = 0; + priv->allmulti = 0; + priv->wep_on = 0; + priv->tx_key = 0; + + printk(KERN_INFO "%s: ready\n", dev->name); + + out: + dldwd_unlock(priv); + + TRACE_EXIT("dldwd"); + + return err; +} + +static int dldwd_open(struct net_device *dev) +{ + dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; + dev_link_t *link = &priv->link; + int err = 0; + + TRACE_ENTER(dev->name); + + link->open++; + MOD_INC_USE_COUNT; + netif_device_attach(dev); + + err = dldwd_reset(priv); + if (err) + dldwd_stop(dev); + else + netif_start_queue(dev); + + TRACE_EXIT(dev->name); + + return err; +} + +static int dldwd_stop(struct net_device *dev) +{ + dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; + dev_link_t *link = &priv->link; + + TRACE_ENTER(dev->name); + + netif_stop_queue(dev); + + dldwd_shutdown(priv); + + link->open--; + + if (link->state & DEV_STALE_CONFIG) + mod_timer(&link->release, jiffies + HZ/20); + + MOD_DEC_USE_COUNT; + + TRACE_EXIT(dev->name); + + return 0; +} + +static struct net_device_stats *dldwd_get_stats(struct net_device *dev) +{ + dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; + + return &priv->stats; +} + +static struct iw_statistics *dldwd_get_wireless_stats(struct net_device *dev) +{ + dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; + hermes_t *hw = &priv->hw; + struct iw_statistics *wstats = &priv->wstats; + int err = 0; + hermes_commsqual_t cq; + + dldwd_lock(priv); + + if (priv->port_type == 3) { + memset(&wstats->qual, 0, sizeof(wstats->qual)); +#ifdef WIRELESS_SPY + /* If a spy address is defined, we report stats of the + * first spy address - Jean II */ + if (priv->spy_number > 0) { + wstats->qual.qual = priv->spy_stat[0].qual; + wstats->qual.level = priv->spy_stat[0].level; + wstats->qual.noise = priv->spy_stat[0].noise; + wstats->qual.updated = priv->spy_stat[0].updated; + } +#endif /* WIRELESS_SPY */ + } else { + err = hermes_read_commsqual(hw, USER_BAP, &cq); + + DEBUG(3, "%s: Global stats = %X-%X-%X\n", dev->name, + cq.qual, cq.signal, cq.noise); + + /* Why are we using MIN/MAX ? We don't really care + * if the value goes above max, because we export the + * raw dBm values anyway. The normalisation should be done + * in user space - Jean II */ + wstats->qual.qual = MAX(MIN(cq.qual, 0x8b-0x2f), 0); + wstats->qual.level = MAX(MIN(cq.signal, 0x8a), 0x2f) - 0x95; + wstats->qual.noise = MAX(MIN(cq.noise, 0x8a), 0x2f) - 0x95; + wstats->qual.updated = 7; + } + + dldwd_unlock(priv); + + if (err) + return NULL; + + return wstats; +} + +#ifdef WIRELESS_SPY +static inline void dldwd_spy_gather(struct net_device *dev, + u_char *mac, + hermes_commsqual_t *cq) +{ + dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; + int i; + + /* Gather wireless spy statistics: for each packet, compare the + * source address with out list, and if match, get the stats... */ + for (i = 0; i < priv->spy_number; i++) + if (!memcmp(mac, priv->spy_address[i], ETH_ALEN)) { + priv->spy_stat[i].qual = MAX(MIN(cq->qual, 0x8b-0x2f), 0); + priv->spy_stat[i].level = MAX(MIN(cq->signal, 0x8a), 0x2f) - 0x95; + priv->spy_stat[i].noise = MAX(MIN(cq->noise, 0x8a), 0x2f) - 0x95; + priv->spy_stat[i].updated = 7; + } +} +#endif /* WIRELESS_SPY */ + +static void dldwd_stat_gather(struct net_device *dev, + struct sk_buff *skb, + struct dldwd_frame_hdr *hdr) +{ + dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; + hermes_commsqual_t cq; + + /* Using spy support with lots of Rx packets, like in an + * infrastructure (AP), will really slow down everything, because + * the MAC address must be compared to each entry of the spy list. + * If the user really asks for it (set some address in the + * spy list), we do it, but he will pay the price. + * Note that to get here, you need both WIRELESS_SPY + * compiled in AND some addresses in the list !!! + */ +#ifdef WIRELESS_EXT + /* Note : gcc will optimise the whole section away if + * WIRELESS_SPY is not defined... - Jean II */ + if ( +#ifdef WIRELESS_SPY + (priv->spy_number > 0) || +#endif + 0 ) + { + u_char *stats = (u_char *) &(hdr->desc.q_info); + /* This code may look strange. Everywhere we are using 16 bit + * ints except here. I've verified that these are are the + * correct values. Please check on PPC - Jean II */ + cq.signal = stats[1]; /* High order byte */ + cq.noise = stats[0]; /* Low order byte */ + cq.qual = stats[0] - stats[1]; /* Better than nothing */ + + DEBUG(3, "%s: Packet stats = %X-%X-%X\n", dev->name, + cq.qual, cq.signal, cq.noise); + +#ifdef WIRELESS_SPY + dldwd_spy_gather(dev, skb->mac.raw + ETH_ALEN, &cq); +#endif + } +#endif /* WIRELESS_EXT */ +} + +struct p8022_hdr encaps_hdr = { + 0xaa, 0xaa, 0x03, {0x00, 0x00, 0xf8} +}; + +static int dldwd_xmit(struct sk_buff *skb, struct net_device *dev) +{ + dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; + struct net_device_stats *stats = &priv->stats; + hermes_t *hw = &priv->hw; + int err = 0; + uint16_t txfid = priv->txfid; + char *p; + struct ethhdr *eh; + int len, data_len, data_off; + struct dldwd_frame_hdr hdr; + hermes_response_t resp; + + if (! netif_running(dev)) { + printk(KERN_ERR "%s: Tx on stopped device!\n", + dev->name); + return 1; + + } + + if (netif_queue_stopped(dev)) { + printk(KERN_ERR "%s: Tx while transmitter busy!\n", + dev->name); + return 1; + } + + dldwd_lock(priv); + + /* Length of the packet body */ + len = MAX(skb->len - ETH_HLEN, ETH_ZLEN); + + eh = (struct ethhdr *)skb->data; + + /* Build the IEEE 802.11 header */ + memset(&hdr, 0, sizeof(hdr)); + memcpy(hdr.p80211.addr1, eh->h_dest, ETH_ALEN); + memcpy(hdr.p80211.addr2, eh->h_source, ETH_ALEN); + hdr.p80211.frame_ctl = DLDWD_FTYPE_DATA; + + /* Encapsulate Ethernet-II frames */ + if (ntohs(eh->h_proto) > 1500) { /* Ethernet-II frame */ + data_len = len; + data_off = sizeof(hdr); + p = skb->data + ETH_HLEN; + + /* 802.11 header */ + hdr.p80211.data_len = cpu_to_le16(data_len + ENCAPS_OVERHEAD); + + /* 802.3 header */ + memcpy(hdr.p8023.h_dest, eh->h_dest, ETH_ALEN); + memcpy(hdr.p8023.h_source, eh->h_source, ETH_ALEN); + hdr.p8023.h_proto = htons(data_len + ENCAPS_OVERHEAD); + + /* 802.2 header */ + memcpy(&hdr.p8022, &encaps_hdr, sizeof(encaps_hdr)); + + hdr.ethertype = eh->h_proto; + err = hermes_bap_pwrite(hw, USER_BAP, &hdr, sizeof(hdr), + txfid, 0); + if (err) { + printk(KERN_ERR + "%s: Error %d writing packet header to BAP\n", + dev->name, err); + stats->tx_errors++; + goto fail; + } + } else { /* IEEE 802.3 frame */ + data_len = len + ETH_HLEN; + data_off = P8023_OFFSET; + p = skb->data; + + /* 802.11 header */ + hdr.p80211.data_len = cpu_to_le16(len); + err = hermes_bap_pwrite(hw, USER_BAP, &hdr, P8023_OFFSET, + txfid, 0); + if (err) { + printk(KERN_ERR + "%s: Error %d writing packet header to BAP\n", + dev->name, err); + stats->tx_errors++; + goto fail; + } + } + + /* Round up for odd length packets */ + err = hermes_bap_pwrite(hw, USER_BAP, p, RUP_EVEN(data_len), txfid, data_off); + if (err) { + printk(KERN_ERR "%s: Error %d writing packet data to BAP\n", + dev->name, err); + stats->tx_errors++; + goto fail; + } + + + /* Finally, we actually initiate the send */ + err = hermes_docmd_wait(hw, HERMES_CMD_TX | HERMES_CMD_RECL, txfid, &resp); + if (err) { + printk(KERN_ERR "%s: Error %d transmitting packet\n", dev->name, err); + stats->tx_errors++; + goto fail; + } + + dev->trans_start = jiffies; + stats->tx_bytes += data_off + data_len; + + netif_stop_queue(dev); + + dldwd_unlock(priv); + + dev_kfree_skb(skb); + + return 0; + fail: + + dldwd_unlock(priv); + return err; +} + +static void dldwd_tx_timeout(struct net_device *dev) +{ + dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; + struct net_device_stats *stats = &priv->stats; + int err = 0; + + printk(KERN_WARNING "%s: Tx timeout! Resetting card.\n", dev->name); + + stats->tx_errors++; + + err = dldwd_reset(priv); + if (err) + printk(KERN_ERR "%s: Error %d resetting card on Tx timeout!\n", + dev->name, err); + else { + dev->trans_start = jiffies; + netif_wake_queue(dev); + } +} + +static int dldwd_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq) +{ + dldwd_priv_t *priv = dev->priv; + int err = 0; + int ptype; + struct iw_range range; + int numrates; + int i, k; + + TRACE_ENTER(dev->name); + + err = verify_area(VERIFY_WRITE, rrq->pointer, sizeof(range)); + if (err) + return err; + + rrq->length = sizeof(range); + + dldwd_lock(priv); + ptype = priv->port_type; + dldwd_unlock(priv); + + memset(&range, 0, sizeof(range)); + + /* Much of this shamelessly taken from wvlan_cs.c. No idea + * what it all means -dgibson */ + range.min_nwid = range.max_nwid = 0; /* We don't use nwids */ + + /* Set available channels/frequencies */ + range.num_channels = NUM_CHANNELS; + k = 0; + for (i = 0; i < NUM_CHANNELS; i++) { + if (priv->channel_mask & (1 << i)) { + range.freq[k].i = i + 1; + range.freq[k].m = channel_frequency[i] * 100000; + range.freq[k].e = 1; + k++; + } + + if (k >= IW_MAX_FREQUENCIES) + break; + } + range.num_frequency = k; + + range.sensitivity = 3; + + if ((ptype == 3) && (priv->spy_number == 0)){ + /* Quality stats meaningless in ad-hoc mode */ + range.max_qual.qual = 0; + range.max_qual.level = 0; + range.max_qual.noise = 0; + } else { + range.max_qual.qual = 0x8b - 0x2f; + range.max_qual.level = 0x2f - 0x95 - 1; + range.max_qual.noise = 0x2f - 0x95 - 1; + } + + err = dldwd_hw_get_bitratelist(priv, &numrates, + range.bitrate, IW_MAX_BITRATES); + if (err) + return err; + range.num_bitrates = numrates; + + /* Set an indication of the max TCP throughput in bit/s that we can + * expect using this interface. May be use for QoS stuff... + * Jean II */ + if(numrates > 2) + range.throughput = 5 * 1000 * 1000; /* ~5 Mb/s */ + else + range.throughput = 1.5 * 1000 * 1000; /* ~1.5 Mb/s */ + + range.min_rts = 0; + range.max_rts = 2347; + range.min_frag = 256; + range.max_frag = 2346; + + dldwd_lock(priv); + if (priv->has_wep) { + range.max_encoding_tokens = MAX_KEYS; + + range.encoding_size[0] = SMALL_KEY_SIZE; + range.num_encoding_sizes = 1; + + if (priv->has_big_wep) { + range.encoding_size[1] = LARGE_KEY_SIZE; + range.num_encoding_sizes = 2; + } + } else { + range.num_encoding_sizes = 0; + range.max_encoding_tokens = 0; + } + dldwd_unlock(priv); + + range.min_pmp = 0; + range.max_pmp = 65535000; + range.min_pmt = 0; + range.max_pmt = 65535 * 1000; /* ??? */ + range.pmp_flags = IW_POWER_PERIOD; + range.pmt_flags = IW_POWER_TIMEOUT; + range.pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_UNICAST_R; + + range.num_txpower = 1; + range.txpower[0] = 15; /* 15dBm */ + range.txpower_capa = IW_TXPOW_DBM; + + if (copy_to_user(rrq->pointer, &range, sizeof(range))) + return -EFAULT; + + TRACE_EXIT(dev->name); + + return 0; +} + +static int dldwd_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq) +{ + dldwd_priv_t *priv = dev->priv; + int index = (erq->flags & IW_ENCODE_INDEX) - 1; + int setindex = priv->tx_key; + int enable = priv->wep_on; + int auth = priv->wep_auth; + uint16_t xlen = 0; + int err = 0; + char keybuf[MAX_KEY_SIZE]; + + if (erq->pointer) { + /* We actually have a key to set */ + + if (copy_from_user(keybuf, erq->pointer, erq->length)) + return -EFAULT; + } + + dldwd_lock(priv); + + if (erq->pointer) { + if (erq->length > MAX_KEY_SIZE) { + err = -E2BIG; + goto out; + } + + if ( (erq->length > LARGE_KEY_SIZE) + || ( ! priv->has_big_wep && (erq->length > SMALL_KEY_SIZE)) ) { + err = -EINVAL; + goto out; + } + + if ((index < 0) || (index >= MAX_KEYS)) + index = priv->tx_key; + + if (erq->length > SMALL_KEY_SIZE) { + xlen = LARGE_KEY_SIZE; + } else if (erq->length > 0) { + xlen = SMALL_KEY_SIZE; + } else + xlen = 0; + + /* Switch on WEP if off */ + if ((!enable) && (xlen > 0)) { + setindex = index; + enable = 1; + } + } else { + /* Important note : if the user do "iwconfig eth0 enc off", + * we will arrive there with an index of -1. This is valid + * but need to be taken care off... Jean II */ + if ((index < 0) || (index >= MAX_KEYS)) { + if((index != -1) || (erq->flags == 0)) { + err = -EINVAL; + goto out; + } + } else { + /* Set the index : Check that the key is valid */ + if(priv->keys[index].len == 0) { + err = -EINVAL; + goto out; + } + setindex = index; + } + } + + if (erq->flags & IW_ENCODE_DISABLED) + enable = 0; + /* Only for symbol cards (so far) - Jean II */ + if (erq->flags & IW_ENCODE_OPEN) + auth = 1; + if (erq->flags & IW_ENCODE_RESTRICTED) + auth = 2; /* If all key are 128 -> should be 3 ??? */ + /* Agree with master wep setting */ + if (enable == 0) + auth = 0; + else if(auth == 0) + auth = 1; /* Encryption require some authentication */ + + if (erq->pointer) { + priv->keys[index].len = cpu_to_le16(xlen); + memset(priv->keys[index].data, 0, sizeof(priv->keys[index].data)); + memcpy(priv->keys[index].data, keybuf, erq->length); + } + priv->tx_key = setindex; + priv->wep_on = enable; + priv->wep_auth = auth; + + out: + dldwd_unlock(priv); + + return 0; +} + +static int dldwd_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq) +{ + dldwd_priv_t *priv = dev->priv; + int index = (erq->flags & IW_ENCODE_INDEX) - 1; + uint16_t xlen = 0; + char keybuf[MAX_KEY_SIZE]; + + + dldwd_lock(priv); + + if ((index < 0) || (index >= MAX_KEYS)) + index = priv->tx_key; + + erq->flags = 0; + if (! priv->wep_on) + erq->flags |= IW_ENCODE_DISABLED; + erq->flags |= index + 1; + + /* Only for symbol cards - Jean II */ + if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL) { + switch(priv->wep_auth) { + case 1: + erq->flags |= IW_ENCODE_OPEN; + break; + case 2: + case 3: + erq->flags |= IW_ENCODE_RESTRICTED; + break; + case 0: + default: + break; + } + } + + xlen = le16_to_cpu(priv->keys[index].len); + + erq->length = xlen; + + if (erq->pointer) { + memcpy(keybuf, priv->keys[index].data, MAX_KEY_SIZE); + } + + dldwd_unlock(priv); + + if (erq->pointer) { + if (copy_to_user(erq->pointer, keybuf, xlen)) + return -EFAULT; + } + + return 0; +} + +static int dldwd_ioctl_setessid(struct net_device *dev, struct iw_point *erq) +{ + dldwd_priv_t *priv = dev->priv; + char essidbuf[IW_ESSID_MAX_SIZE+1]; + + /* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it + * anyway... - Jean II */ + + memset(&essidbuf, 0, sizeof(essidbuf)); + + if (erq->flags) { + if (erq->length > IW_ESSID_MAX_SIZE) + return -E2BIG; + + if (copy_from_user(&essidbuf, erq->pointer, erq->length)) + return -EFAULT; + + essidbuf[erq->length] = '\0'; + } + + dldwd_lock(priv); + + memcpy(priv->desired_essid, essidbuf, IW_ESSID_MAX_SIZE+1); + + dldwd_unlock(priv); + + return 0; +} + +static int dldwd_ioctl_getessid(struct net_device *dev, struct iw_point *erq) +{ + dldwd_priv_t *priv = dev->priv; + char essidbuf[IW_ESSID_MAX_SIZE+1]; + int active; + int err = 0; + + TRACE_ENTER(dev->name); + + err = dldwd_hw_get_essid(priv, &active, essidbuf); + if (err) + return err; + + erq->flags = 1; + erq->length = strlen(essidbuf) + 1; + if (erq->pointer) + if ( copy_to_user(erq->pointer, essidbuf, erq->length) ) + return -EFAULT; + + TRACE_EXIT(dev->name); + + return 0; +} + +static int dldwd_ioctl_setnick(struct net_device *dev, struct iw_point *nrq) +{ + dldwd_priv_t *priv = dev->priv; + char nickbuf[IW_ESSID_MAX_SIZE+1]; + + if (nrq->length > IW_ESSID_MAX_SIZE) + return -E2BIG; + + memset(nickbuf, 0, sizeof(nickbuf)); + + if (copy_from_user(nickbuf, nrq->pointer, nrq->length)) + return -EFAULT; + + nickbuf[nrq->length] = '\0'; + + dldwd_lock(priv); + + memcpy(priv->nick, nickbuf, sizeof(priv->nick)); + + dldwd_unlock(priv); + + return 0; +} + +static int dldwd_ioctl_getnick(struct net_device *dev, struct iw_point *nrq) +{ + dldwd_priv_t *priv = dev->priv; + char nickbuf[IW_ESSID_MAX_SIZE+1]; + + dldwd_lock(priv); + memcpy(nickbuf, priv->nick, IW_ESSID_MAX_SIZE+1); + dldwd_unlock(priv); + + nrq->length = strlen(nickbuf)+1; + + if (copy_to_user(nrq->pointer, nickbuf, sizeof(nickbuf))) + return -EFAULT; + + return 0; +} + +static int dldwd_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq) +{ + dldwd_priv_t *priv = dev->priv; + int chan = -1; + + /* We can only use this in Ad-Hoc demo mode to set the operating + * frequency, or in IBSS mode to set the frequency where the IBSS + * will be created - Jean II */ + if (priv->iw_mode != IW_MODE_ADHOC) + return -EOPNOTSUPP; + + if ( (frq->e == 0) && (frq->m <= 1000) ) { + /* Setting by channel number */ + chan = frq->m; + } else { + /* Setting by frequency - search the table */ + int mult = 1; + int i; + + for (i = 0; i < (6 - frq->e); i++) + mult *= 10; + + for (i = 0; i < NUM_CHANNELS; i++) + if (frq->m == (channel_frequency[i] * mult)) + chan = i+1; + } + + if ( (chan < 1) || (chan > NUM_CHANNELS) || + ! (priv->channel_mask & (1 << (chan-1)) ) ) + return -EINVAL; + + dldwd_lock(priv); + priv->channel = chan; + dldwd_unlock(priv); + + return 0; +} + +static int dldwd_ioctl_getsens(struct net_device *dev, struct iw_param *srq) +{ + dldwd_priv_t *priv = dev->priv; + hermes_t *hw = &priv->hw; + uint16_t val; + int err; + + dldwd_lock(priv); + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYSTEM_SCALE, &val); + dldwd_unlock(priv); + + if (err) + return err; + + srq->value = val; + srq->fixed = 0; /* auto */ + + return 0; +} + +static int dldwd_ioctl_setsens(struct net_device *dev, struct iw_param *srq) +{ + dldwd_priv_t *priv = dev->priv; + int val = srq->value; + + if ((val < 1) || (val > 3)) + return -EINVAL; + + dldwd_lock(priv); + priv->ap_density = val; + dldwd_unlock(priv); + + return 0; +} + +static int dldwd_ioctl_setrts(struct net_device *dev, struct iw_param *rrq) +{ + dldwd_priv_t *priv = dev->priv; + int val = rrq->value; + + if (rrq->disabled) + val = 2347; + + if ( (val < 0) || (val > 2347) ) + return -EINVAL; + + dldwd_lock(priv); + priv->rts_thresh = val; + dldwd_unlock(priv); + + return 0; +} + +static int dldwd_ioctl_setfrag(struct net_device *dev, struct iw_param *frq) +{ + dldwd_priv_t *priv = dev->priv; + int err = 0; + + dldwd_lock(priv); + + if (priv->has_mwo) { + if (frq->disabled) + priv->mwo_robust = 0; + else { + if (frq->fixed) + printk(KERN_WARNING "%s: Fixed fragmentation not \ +supported on this firmware. Using MWO robust instead.\n", dev->name); + priv->mwo_robust = 1; + } + } else { + if (frq->disabled) + priv->frag_thresh = 2346; + else { + if ( (frq->value < 256) || (frq->value > 2346) ) + err = -EINVAL; + else + priv->frag_thresh = frq->value & ~0x1; /* must be even */ + } + } + + dldwd_unlock(priv); + + return err; +} + +static int dldwd_ioctl_getfrag(struct net_device *dev, struct iw_param *frq) +{ + dldwd_priv_t *priv = dev->priv; + hermes_t *hw = &priv->hw; + int err = 0; + uint16_t val; + + dldwd_lock(priv); + + if (priv->has_mwo) { + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_MWO_ROBUST, &val); + if (err) + val = 0; + + frq->value = val ? 2347 : 0; + frq->disabled = ! val; + frq->fixed = 0; + } else { + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_FRAG_THRESH, &val); + if (err) + val = 0; + + frq->value = val; + frq->disabled = (val >= 2346); + frq->fixed = 1; + } + + dldwd_unlock(priv); + + return err; +} + +static int dldwd_ioctl_setrate(struct net_device *dev, struct iw_param *rrq) +{ + dldwd_priv_t *priv = dev->priv; + int err = 0; + int rate_ctrl = -1; + int fixed, upto; + int brate; + int i; + + dldwd_lock(priv); + + /* Normalise value */ + brate = rrq->value / 500000; + + switch (priv->firmware_type) { + case FIRMWARE_TYPE_LUCENT: /* Lucent style rate */ + if (! rrq->fixed) { + if (brate > 0) + brate = -brate; + else + brate = -22; + } + + for (i = 0; i < NUM_RATES; i++) + if (rate_list[i] == brate) { + rate_ctrl = i; + break; + } + + if ( (rate_ctrl < 1) || (rate_ctrl >= NUM_RATES) ) + err = -EINVAL; + else + priv->tx_rate_ctrl = rate_ctrl; + break; + case FIRMWARE_TYPE_PRISM2: /* Prism II style rate */ + case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */ + switch(brate) { + case 0: + fixed = 0x0; + upto = 0x15; + break; + case 2: + fixed = 0x1; + upto = 0x1; + break; + case 4: + fixed = 0x2; + upto = 0x3; + break; + case 11: + fixed = 0x4; + upto = 0x7; + break; + case 22: + fixed = 0x8; + upto = 0x15; + break; + default: + fixed = 0x0; + upto = 0x0; + } + if (rrq->fixed) + rate_ctrl = fixed; + else + rate_ctrl = upto; + if (rate_ctrl == 0) + err = -EINVAL; + else + priv->tx_rate_ctrl = rate_ctrl; + break; + } + + dldwd_unlock(priv); + + return err; +} + +static int dldwd_ioctl_getrate(struct net_device *dev, struct iw_param *rrq) +{ + dldwd_priv_t *priv = dev->priv; + hermes_t *hw = &priv->hw; + int err = 0; + uint16_t val; + int brate = 0; + + dldwd_lock(priv); + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_TX_RATE_CTRL, &val); + if (err) + goto out; + + switch (priv->firmware_type) { + case FIRMWARE_TYPE_LUCENT: /* Lucent style rate */ + brate = rate_list[val]; + + if (brate < 0) { + rrq->fixed = 0; + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENT_TX_RATE, &val); + if (err) + goto out; + + if (val == 6) + brate = 11; + else + brate = 2*val; + } else + rrq->fixed = 1; + break; + case FIRMWARE_TYPE_PRISM2: /* Prism II style rate */ + case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */ + /* Check if auto or fixed (crude approximation) */ + if((val & 0x1) && (val > 1)) { + rrq->fixed = 0; + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENT_TX_RATE, &val); + if (err) + goto out; + } else + rrq->fixed = 1; + + if(val >= 8) + brate = 22; + else if(val >= 4) + brate = 11; + else if(val >= 2) + brate = 4; + else + brate = 2; + break; + } + + rrq->value = brate * 500000; + rrq->disabled = 0; + + out: + dldwd_unlock(priv); + + return err; +} + +static int dldwd_ioctl_setpower(struct net_device *dev, struct iw_param *prq) +{ + dldwd_priv_t *priv = dev->priv; + int err = 0; + + + dldwd_lock(priv); + + if (prq->disabled) { + priv->pm_on = 0; + } else { + switch (prq->flags & IW_POWER_MODE) { + case IW_POWER_UNICAST_R: + priv->pm_mcast = 0; + priv->pm_on = 1; + break; + case IW_POWER_ALL_R: + priv->pm_mcast = 1; + priv->pm_on = 1; + break; + case IW_POWER_ON: + /* No flags : but we may have a value - Jean II */ + break; + default: + err = -EINVAL; + } + if (err) + goto out; + + if (prq->flags & IW_POWER_TIMEOUT) { + priv->pm_on = 1; + priv->pm_timeout = prq->value / 1000; + } + if (prq->flags & IW_POWER_PERIOD) { + priv->pm_on = 1; + priv->pm_period = prq->value / 1000; + } + /* It's valid to not have a value if we are just toggling + * the flags... Jean II */ + if(!priv->pm_on) { + err = -EINVAL; + goto out; + } + } + + out: + dldwd_unlock(priv); + + return err; +} + +static int dldwd_ioctl_getpower(struct net_device *dev, struct iw_param *prq) +{ + dldwd_priv_t *priv = dev->priv; + hermes_t *hw = &priv->hw; + int err = 0; + uint16_t enable, period, timeout, mcast; + + dldwd_lock(priv); + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_ENABLE, &enable); + if (err) + goto out; + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_PERIOD, &period); + if (err) + goto out; + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_HOLDOVER, &timeout); + if (err) + goto out; + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_MCAST_RX, &mcast); + if (err) + goto out; + + prq->disabled = !enable; + /* Note : by default, display the period */ + if ((prq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { + prq->flags = IW_POWER_TIMEOUT; + prq->value = timeout * 1000; + } else { + prq->flags = IW_POWER_PERIOD; + prq->value = period * 1000; + } + if (mcast) + prq->flags |= IW_POWER_ALL_R; + else + prq->flags |= IW_POWER_UNICAST_R; + + out: + dldwd_unlock(priv); + + return err; +} + +static int dldwd_ioctl_setport3(struct net_device *dev, struct iwreq *wrq) +{ + dldwd_priv_t *priv = dev->priv; + int val = *( (int *) wrq->u.name ); + int err = 0; + + dldwd_lock(priv); + switch (val) { + case 0: /* Try to do IEEE ad-hoc mode */ + if (! priv->has_ibss) { + err = -EINVAL; + break; + } + priv->prefer_port3 = 0; + + break; + + case 1: /* Try to do Lucent proprietary ad-hoc mode */ + if (! priv->has_port3) { + err = -EINVAL; + break; + } + priv->prefer_port3 = 1; + break; + + default: + err = -EINVAL; + } + + dldwd_unlock(priv); + + return err; +} + +static int dldwd_ioctl_getport3(struct net_device *dev, struct iwreq *wrq) +{ + dldwd_priv_t *priv = dev->priv; + int *val = (int *)wrq->u.name; + + dldwd_lock(priv); + *val = priv->prefer_port3; + dldwd_unlock(priv); + + return 0; +} + +/* Spy is used for link quality/strength measurements in Ad-Hoc mode + * Jean II */ +static int dldwd_ioctl_setspy(struct net_device *dev, struct iw_point *srq) +{ + dldwd_priv_t *priv = dev->priv; + struct sockaddr address[IW_MAX_SPY]; + int number = srq->length; + int i; + int err = 0; + + /* Check the number of addresses */ + if (number > IW_MAX_SPY) + return -E2BIG; + + /* Get the data in the driver */ + if (srq->pointer) { + if (copy_from_user(address, srq->pointer, + sizeof(struct sockaddr) * number)) + return -EFAULT; + } + + /* Make sure nobody mess with the structure while we do */ + dldwd_lock(priv); + + /* dldwd_lock() doesn't disable interrupts, so make sure the + * interrupt rx path don't get confused while we copy */ + priv->spy_number = 0; + + if (number > 0) { + /* Extract the addresses */ + for (i = 0; i < number; i++) + memcpy(priv->spy_address[i], address[i].sa_data, + ETH_ALEN); + /* Reset stats */ + memset(priv->spy_stat, 0, + sizeof(struct iw_quality) * IW_MAX_SPY); + /* Set number of addresses */ + priv->spy_number = number; + } + + /* Time to show what we have done... */ + DEBUG(0, "%s: New spy list:\n", dev->name); + for (i = 0; i < number; i++) { + DEBUG(0, "%s: %d - %02x:%02x:%02x:%02x:%02x:%02x\n", + dev->name, i+1, + priv->spy_address[i][0], priv->spy_address[i][1], + priv->spy_address[i][2], priv->spy_address[i][3], + priv->spy_address[i][4], priv->spy_address[i][5]); + } + + /* Now, let the others play */ + dldwd_unlock(priv); + + return err; +} + +static int dldwd_ioctl_getspy(struct net_device *dev, struct iw_point *srq) +{ + dldwd_priv_t *priv = dev->priv; + struct sockaddr address[IW_MAX_SPY]; + struct iw_quality spy_stat[IW_MAX_SPY]; + int number; + int i; + + dldwd_lock(priv); + + number = priv->spy_number; + if ((number > 0) && (srq->pointer)) { + /* Create address struct */ + for (i = 0; i < number; i++) { + memcpy(address[i].sa_data, priv->spy_address[i], + ETH_ALEN); + address[i].sa_family = AF_UNIX; + } + /* Copy stats */ + /* In theory, we should disable irqs while copying the stats + * because the rx path migh update it in the middle... + * Bah, who care ? - Jean II */ + memcpy(&spy_stat, priv->spy_stat, + sizeof(struct iw_quality) * IW_MAX_SPY); + for (i=0; i < number; i++) + priv->spy_stat[i].updated = 0; + } + + dldwd_unlock(priv); + + /* Push stuff to user space */ + srq->length = number; + if(copy_to_user(srq->pointer, address, + sizeof(struct sockaddr) * number)) + return -EFAULT; + if(copy_to_user(srq->pointer + (sizeof(struct sockaddr)*number), + &spy_stat, sizeof(struct iw_quality) * number)) + return -EFAULT; + + return 0; +} + +static int dldwd_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + dldwd_priv_t *priv = dev->priv; + struct iwreq *wrq = (struct iwreq *)rq; + int err = 0; + int changed = 0; + + TRACE_ENTER(dev->name); + + switch (cmd) { + case SIOCGIWNAME: + DEBUG(1, "%s: SIOCGIWNAME\n", dev->name); + strcpy(wrq->u.name, "IEEE 802.11-DS"); + break; + + case SIOCGIWAP: + DEBUG(1, "%s: SIOCGIWAP\n", dev->name); + wrq->u.ap_addr.sa_family = ARPHRD_ETHER; + err = dldwd_hw_get_bssid(priv, wrq->u.ap_addr.sa_data); + break; + + case SIOCGIWRANGE: + DEBUG(1, "%s: SIOCGIWRANGE\n", dev->name); + err = dldwd_ioctl_getiwrange(dev, &wrq->u.data); + break; + + case SIOCSIWMODE: + DEBUG(1, "%s: SIOCSIWMODE\n", dev->name); + dldwd_lock(priv); + switch (wrq->u.mode) { + case IW_MODE_ADHOC: + if (! (priv->has_ibss || priv->has_port3) ) + err = -EINVAL; + else { + priv->iw_mode = IW_MODE_ADHOC; + changed = 1; + } + break; + + case IW_MODE_INFRA: + priv->iw_mode = IW_MODE_INFRA; + changed = 1; + break; + + default: + err = -EINVAL; + break; + } + set_port_type(priv); + dldwd_unlock(priv); + break; + + case SIOCGIWMODE: + DEBUG(1, "%s: SIOCGIWMODE\n", dev->name); + dldwd_lock(priv); + wrq->u.mode = priv->iw_mode; + dldwd_unlock(priv); + break; + + case SIOCSIWENCODE: + DEBUG(1, "%s: SIOCSIWENCODE\n", dev->name); + if (! priv->has_wep) { + err = -EOPNOTSUPP; + break; + } + + err = dldwd_ioctl_setiwencode(dev, &wrq->u.encoding); + if (! err) + changed = 1; + break; + + case SIOCGIWENCODE: + DEBUG(1, "%s: SIOCGIWENCODE\n", dev->name); + if (! priv->has_wep) { + err = -EOPNOTSUPP; + break; + } + + if (! capable(CAP_NET_ADMIN)) { + err = -EPERM; + break; + } + + err = dldwd_ioctl_getiwencode(dev, &wrq->u.encoding); + break; + + case SIOCSIWESSID: + DEBUG(1, "%s: SIOCSIWESSID\n", dev->name); + err = dldwd_ioctl_setessid(dev, &wrq->u.essid); + if (! err) + changed = 1; + break; + + case SIOCGIWESSID: + DEBUG(1, "%s: SIOCGIWESSID\n", dev->name); + err = dldwd_ioctl_getessid(dev, &wrq->u.essid); + break; + + case SIOCSIWNICKN: + DEBUG(1, "%s: SIOCSIWNICKN\n", dev->name); + err = dldwd_ioctl_setnick(dev, &wrq->u.data); + if (! err) + changed = 1; + break; + + case SIOCGIWNICKN: + DEBUG(1, "%s: SIOCGIWNICKN\n", dev->name); + err = dldwd_ioctl_getnick(dev, &wrq->u.data); + break; + + case SIOCGIWFREQ: + DEBUG(1, "%s: SIOCGIWFREQ\n", dev->name); + wrq->u.freq.m = dldwd_hw_get_freq(priv); + wrq->u.freq.e = 1; + break; + + case SIOCSIWFREQ: + DEBUG(1, "%s: SIOCSIWFREQ\n", dev->name); + err = dldwd_ioctl_setfreq(dev, &wrq->u.freq); + if (! err) + changed = 1; + break; + + case SIOCGIWSENS: + DEBUG(1, "%s: SIOCGIWSENS\n", dev->name); + err = dldwd_ioctl_getsens(dev, &wrq->u.sens); + break; + + case SIOCSIWSENS: + DEBUG(1, "%s: SIOCSIWSENS\n", dev->name); + err = dldwd_ioctl_setsens(dev, &wrq->u.sens); + if (! err) + changed = 1; + break; + + case SIOCGIWRTS: + DEBUG(1, "%s: SIOCGIWRTS\n", dev->name); + wrq->u.rts.value = priv->rts_thresh; + wrq->u.rts.disabled = (wrq->u.rts.value == 2347); + wrq->u.rts.fixed = 1; + break; + + case SIOCSIWRTS: + DEBUG(1, "%s: SIOCSIWRTS\n", dev->name); + err = dldwd_ioctl_setrts(dev, &wrq->u.rts); + if (! err) + changed = 1; + break; + + case SIOCSIWFRAG: + DEBUG(1, "%s: SIOCSIWFRAG\n", dev->name); + err = dldwd_ioctl_setfrag(dev, &wrq->u.frag); + if (! err) + changed = 1; + break; + + case SIOCGIWFRAG: + DEBUG(1, "%s: SIOCGIWFRAG\n", dev->name); + err = dldwd_ioctl_getfrag(dev, &wrq->u.frag); + break; + + case SIOCSIWRATE: + DEBUG(1, "%s: SIOCSIWRATE\n", dev->name); + err = dldwd_ioctl_setrate(dev, &wrq->u.bitrate); + if (! err) + changed = 1; + break; + + case SIOCGIWRATE: + DEBUG(1, "%s: SIOCGIWRATE\n", dev->name); + err = dldwd_ioctl_getrate(dev, &wrq->u.bitrate); + break; + + case SIOCSIWPOWER: + DEBUG(1, "%s: SIOCSIWPOWER\n", dev->name); + err = dldwd_ioctl_setpower(dev, &wrq->u.power); + if (! err) + changed = 1; + break; + + case SIOCGIWPOWER: + DEBUG(1, "%s: SIOCGIWPOWER\n", dev->name); + err = dldwd_ioctl_getpower(dev, &wrq->u.power); + break; + + case SIOCGIWTXPOW: + DEBUG(1, "%s: SIOCGIWTXPOW\n", dev->name); + /* The card only supports one tx power, so this is easy */ + wrq->u.txpower.value = 15; /* dBm */ + wrq->u.txpower.fixed = 1; + wrq->u.txpower.disabled = 0; + wrq->u.txpower.flags = IW_TXPOW_DBM; + break; + + case SIOCSIWSPY: + DEBUG(1, "%s: SIOCSIWSPY\n", dev->name); + + err = dldwd_ioctl_setspy(dev, &wrq->u.data); + break; + + case SIOCGIWSPY: + DEBUG(1, "%s: SIOCGIWSPY\n", dev->name); + + err = dldwd_ioctl_getspy(dev, &wrq->u.data); + break; + + case SIOCGIWPRIV: + DEBUG(1, "%s: SIOCGIWPRIV\n", dev->name); + if (wrq->u.data.pointer) { + struct iw_priv_args privtab[] = { + { SIOCDEVPRIVATE + 0x0, 0, 0, "force_reset" }, + { SIOCDEVPRIVATE + 0x2, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "set_port3" }, + { SIOCDEVPRIVATE + 0x3, 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_port3" } + }; + + err = verify_area(VERIFY_WRITE, wrq->u.data.pointer, sizeof(privtab)); + if (err) + break; + + wrq->u.data.length = sizeof(privtab) / sizeof(privtab[0]); + if (copy_to_user(wrq->u.data.pointer, privtab, sizeof(privtab))) + err = -EFAULT; + } + break; + + case SIOCDEVPRIVATE + 0x0: /* force_reset */ + DEBUG(1, "%s: SIOCDEVPRIVATE + 0x0 (force_reset)\n", + dev->name); + if (! capable(CAP_NET_ADMIN)) { + err = -EPERM; + break; + } + + printk(KERN_DEBUG "%s: Forcing reset!\n", dev->name); + dldwd_reset(priv); + break; + + case SIOCDEVPRIVATE + 0x2: /* set_port3 */ + DEBUG(1, "%s: SIOCDEVPRIVATE + 0x2 (set_port3)\n", + dev->name); + if (! capable(CAP_NET_ADMIN)) { + err = -EPERM; + break; + } + + err = dldwd_ioctl_setport3(dev, wrq); + if (! err) + changed = 1; + break; + + case SIOCDEVPRIVATE + 0x3: /* get_port3 */ + DEBUG(1, "%s: SIOCDEVPRIVATE + 0x3 (get_port3)\n", + dev->name); + err = dldwd_ioctl_getport3(dev, wrq); + break; + + default: + err = -EOPNOTSUPP; + } + + if (! err && changed && netif_running(dev)) { + err = dldwd_reset(priv); + if (err) + dldwd_stop(dev); + } + + TRACE_EXIT(dev->name); + + return err; +} + +static int dldwd_change_mtu(struct net_device *dev, int new_mtu) +{ + TRACE_ENTER(dev->name); + + if ( (new_mtu < DLDWD_MIN_MTU) || (new_mtu > DLDWD_MAX_MTU) ) + return -EINVAL; + + dev->mtu = new_mtu; + + TRACE_EXIT(dev->name); + + return 0; +} + +static void __dldwd_set_multicast_list(struct net_device *dev) +{ + dldwd_priv_t *priv = dev->priv; + hermes_t *hw = &priv->hw; + int err = 0; + int promisc, allmulti, mc_count; + + TRACE_ENTER(dev->name); + + DEBUG(3, "dev->flags=0x%x, priv->promiscuous=%d, dev->mc_count=%d priv->mc_count=%d\n", + dev->flags, priv->promiscuous, dev->mc_count, priv->mc_count); + + /* The Hermes doesn't seem to have an allmulti mode, so we go + * into promiscuous mode and let the upper levels deal. */ + if ( (dev->flags & IFF_PROMISC) ) { + promisc = 1; + allmulti = 0; + mc_count = 0; + } else if ( (dev->flags & IFF_ALLMULTI) || + (dev->mc_count > HERMES_MAX_MULTICAST) ) { + promisc = 0; + allmulti = 1; + mc_count = HERMES_MAX_MULTICAST; + } else { + promisc = 0; + allmulti = 0; + mc_count = dev->mc_count; + } + + DEBUG(3, "promisc=%d mc_count=%d\n", + promisc, mc_count); + + if (promisc != priv->promiscuous) { /* Don't touch the hardware if we don't have to */ + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PROMISCUOUS, + promisc); + if (err) { + printk(KERN_ERR "%s: Error %d setting promiscuity to %d.\n", + dev->name, err, promisc); + } else + priv->promiscuous = promisc; + } + + if (allmulti) { + /* FIXME: This method of doing allmulticast reception + comes from the NetBSD driver. Haven't actually + tested whether it works or not. */ + hermes_multicast_t mclist; + + memset(&mclist, 0, sizeof(mclist)); + err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNF_MULTICAST_LIST, &mclist); + if (err) + printk(KERN_ERR "%s: Error %d setting multicast list.\n", + dev->name, err); + else + priv->allmulti = 1; + + } else if (mc_count || (! mc_count && priv->mc_count) ) { + struct dev_mc_list *p = dev->mc_list; + hermes_multicast_t mclist; + int i; + + for (i = 0; i < mc_count; i++) { + /* First some paranoid checks */ + if (! p) { + printk(KERN_ERR "%s: Multicast list shorter than mc_count.\n", + dev->name); + break; + } + if (p->dmi_addrlen != ETH_ALEN) { + + printk(KERN_ERR "%s: Bad address size (%d) in multicast list.\n", + dev->name, p->dmi_addrlen); + break; + } + + memcpy(mclist.addr[i], p->dmi_addr, ETH_ALEN); + p = p->next; + } + + /* More paranoia */ + if (p) + printk(KERN_ERR "%s: Multicast list longer than mc_count.\n", + dev->name); + + priv->mc_count = i; + + DEBUG(3, "priv->mc_count = %d\n", priv->mc_count); + + err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNF_MULTICAST_LIST, + HERMES_BYTES_TO_RECLEN(priv->mc_count * ETH_ALEN), + &mclist); + if (err) + printk(KERN_ERR "%s: Error %d setting multicast list.\n", + dev->name, err); + else + priv->allmulti = 0; + } + + /* Since we can set the promiscuous flag when it wasn't asked + for, make sure the net_device knows about it. */ + if (priv->promiscuous) + dev->flags |= IFF_PROMISC; + else + dev->flags &= ~IFF_PROMISC; + + if (priv->allmulti) + dev->flags |= IFF_ALLMULTI; + else + dev->flags &= ~IFF_ALLMULTI; + + TRACE_EXIT(dev->name); +} + +/* + * procfs stuff + */ + +static struct proc_dir_entry *dir_base = NULL; + +/* + * This function updates the total amount of data printed so far. It then + * determines if the amount of data printed into a buffer has reached the + * offset requested. If it hasn't, then the buffer is shifted over so that + * the next bit of data can be printed over the old bit. If the total + * amount printed so far exceeds the total amount requested, then this + * function returns 1, otherwise 0. + */ +static int + +shift_buffer(char *buffer, int requested_offset, int requested_len, + int *total, int *slop, char **buf) +{ + int printed; + + printed = *buf - buffer; + if (*total + printed <= requested_offset) { + *total += printed; + *buf = buffer; + } + else { + if (*total < requested_offset) { + *slop = requested_offset - *total; + } + *total = requested_offset + printed - *slop; + } + if (*total > requested_offset + requested_len) { + return 1; + } + else { + return 0; + } +} + +/* + * This function calculates the actual start of the requested data + * in the buffer. It also calculates actual length of data returned, + * which could be less that the amount of data requested. + */ +#define PROC_BUFFER_SIZE 4096 +#define PROC_SAFE_SIZE 3072 + +static int +calc_start_len(char *buffer, char **start, int requested_offset, + int requested_len, int total, char *buf) +{ + int return_len, buffer_len; + + buffer_len = buf - buffer; + if (buffer_len >= PROC_BUFFER_SIZE - 1) { + printk(KERN_ERR "calc_start_len: exceeded /proc buffer size\n"); + } + + /* + * There may be bytes before and after the + * chunk that was actually requested. + */ + return_len = total - requested_offset; + if (return_len < 0) { + return_len = 0; + } + *start = buf - return_len; + if (return_len > requested_len) { + return_len = requested_len; + } + return return_len; +} + +static int +dldwd_proc_get_hermes_regs(char *page, char **start, off_t requested_offset, + int requested_len, int *eof, void *data) +{ + dldwd_priv_t *dev = (dldwd_priv_t *)data; + hermes_t *hw = &dev->hw; + char *buf; + int total = 0, slop = 0; + + buf = page; + +#define DHERMESREG(name) buf += sprintf(buf, "%-16s: %04x\n", #name, hermes_read_regn(hw, name)) + + DHERMESREG(CMD); + DHERMESREG(PARAM0); + DHERMESREG(PARAM1); + DHERMESREG(PARAM2); + DHERMESREG(STATUS); + DHERMESREG(RESP0); + DHERMESREG(RESP1); + DHERMESREG(RESP2); + DHERMESREG(INFOFID); + DHERMESREG(RXFID); + DHERMESREG(ALLOCFID); + DHERMESREG(TXCOMPLFID); + DHERMESREG(SELECT0); + DHERMESREG(OFFSET0); + DHERMESREG(SELECT1); + DHERMESREG(OFFSET1); + DHERMESREG(EVSTAT); + DHERMESREG(INTEN); + DHERMESREG(EVACK); + DHERMESREG(CONTROL); + DHERMESREG(SWSUPPORT0); + DHERMESREG(SWSUPPORT1); + DHERMESREG(SWSUPPORT2); + DHERMESREG(AUXPAGE); + DHERMESREG(AUXOFFSET); + DHERMESREG(AUXDATA); +#undef DHERMESREG + + shift_buffer(page, requested_offset, requested_len, &total, + &slop, &buf); + return calc_start_len(page, start, requested_offset, requested_len, + total, buf); +} + +struct { + uint16_t rid; + char *name; + int minlen, maxlen; + int displaytype; +#define DISPLAY_WORDS 0 +#define DISPLAY_BYTES 1 +#define DISPLAY_STRING 2 +} record_table[] = { +#define RTCNFENTRY(name, type) { HERMES_RID_CNF_##name, #name, 0, LTV_BUF_SIZE, type } + RTCNFENTRY(PORTTYPE, DISPLAY_WORDS), + RTCNFENTRY(MACADDR, DISPLAY_BYTES), + RTCNFENTRY(DESIRED_SSID, DISPLAY_STRING), + RTCNFENTRY(CHANNEL, DISPLAY_WORDS), + RTCNFENTRY(OWN_SSID, DISPLAY_STRING), + RTCNFENTRY(SYSTEM_SCALE, DISPLAY_WORDS), + RTCNFENTRY(MAX_DATA_LEN, DISPLAY_WORDS), + RTCNFENTRY(PM_ENABLE, DISPLAY_WORDS), + RTCNFENTRY(PM_MCAST_RX, DISPLAY_WORDS), + RTCNFENTRY(PM_PERIOD, DISPLAY_WORDS), + RTCNFENTRY(NICKNAME, DISPLAY_STRING), + RTCNFENTRY(WEP_ON, DISPLAY_WORDS), + RTCNFENTRY(MWO_ROBUST, DISPLAY_WORDS), + RTCNFENTRY(MULTICAST_LIST, DISPLAY_BYTES), + RTCNFENTRY(CREATEIBSS, DISPLAY_WORDS), + RTCNFENTRY(FRAG_THRESH, DISPLAY_WORDS), + RTCNFENTRY(RTS_THRESH, DISPLAY_WORDS), + RTCNFENTRY(TX_RATE_CTRL, DISPLAY_WORDS), + RTCNFENTRY(PROMISCUOUS, DISPLAY_WORDS), + RTCNFENTRY(KEYS, DISPLAY_BYTES), + RTCNFENTRY(TX_KEY, DISPLAY_WORDS), + RTCNFENTRY(TICKTIME, DISPLAY_WORDS), + RTCNFENTRY(PRISM2_TX_KEY, DISPLAY_WORDS), + RTCNFENTRY(PRISM2_KEY0, DISPLAY_BYTES), + RTCNFENTRY(PRISM2_KEY1, DISPLAY_BYTES), + RTCNFENTRY(PRISM2_KEY2, DISPLAY_BYTES), + RTCNFENTRY(PRISM2_KEY3, DISPLAY_BYTES), + RTCNFENTRY(PRISM2_WEP_ON, DISPLAY_WORDS), +#undef RTCNFENTRY +#define RTINFENTRY(name,type) { HERMES_RID_##name, #name, 0, LTV_BUF_SIZE, type } + RTINFENTRY(CHANNEL_LIST, DISPLAY_WORDS), + RTINFENTRY(STAIDENTITY, DISPLAY_WORDS), + RTINFENTRY(CURRENT_SSID, DISPLAY_STRING), + RTINFENTRY(CURRENT_BSSID, DISPLAY_BYTES), + RTINFENTRY(COMMSQUALITY, DISPLAY_WORDS), + RTINFENTRY(CURRENT_TX_RATE, DISPLAY_WORDS), + RTINFENTRY(WEP_AVAIL, DISPLAY_WORDS), + RTINFENTRY(CURRENT_CHANNEL, DISPLAY_WORDS), + RTINFENTRY(DATARATES, DISPLAY_BYTES), +#undef RTINFENTRY +}; +#define NUM_RIDS ( sizeof(record_table) / sizeof(record_table[0]) ) + +static int +dldwd_proc_get_hermes_recs(char *page, char **start, off_t requested_offset, + int requested_len, int *eof, void *data) +{ + dldwd_priv_t *dev = (dldwd_priv_t *)data; + hermes_t *hw = &dev->hw; + char *buf; + int total = 0, slop = 0; + int i; + uint16_t length; + int err; + + buf = page; + + /* print out all the config RIDs */ + for (i = 0; i < NUM_RIDS; i++) { + uint16_t rid = record_table[i].rid; + int minlen = record_table[i].minlen; + int maxlen = record_table[i].maxlen; + int len; + uint8_t *val8; + uint16_t *val16; + int j; + + val8 = kmalloc(maxlen + 2, GFP_KERNEL); + if (! val8) + return -ENOMEM; + + err = hermes_read_ltv(hw, USER_BAP, rid, maxlen, + &length, val8); + if (err) { + DEBUG(0, "Error %d reading RID 0x%04x\n", err, rid); + continue; + } + val16 = (uint16_t *)val8; + + buf += sprintf(buf, "%-15s (0x%04x): length=%d (%d bytes)\tvalue=", record_table[i].name, + rid, length, (length-1)*2); + len = MIN( MAX(minlen, (length-1)*2), maxlen); + + switch (record_table[i].displaytype) { + case DISPLAY_WORDS: + for (j = 0; j < len / 2; j++) { + buf += sprintf(buf, "%04X-", le16_to_cpu(val16[j])); + } + buf--; + break; + + case DISPLAY_BYTES: + default: + for (j = 0; j < len; j++) { + buf += sprintf(buf, "%02X:", val8[j]); + } + buf--; + break; + + case DISPLAY_STRING: + len = MIN(len, le16_to_cpu(val16[0])+2); + val8[len] = '\0'; + buf += sprintf(buf, "\"%s\"", (char *)&val16[1]); + break; + } + + buf += sprintf(buf, "\n"); + + kfree(val8); + + if (shift_buffer(page, requested_offset, requested_len, + &total, &slop, &buf)) + break; + + if ( (buf - page) > PROC_SAFE_SIZE ) + break; + } + + return calc_start_len(page, start, requested_offset, requested_len, + total, buf); +} + +/* initialise the /proc subsystem for the hermes driver, creating the + * separate entries */ +static int +dldwd_proc_init(void) +{ + int err = 0; + + TRACE_ENTER("dldwd"); + + /* create the directory for it to sit in */ + dir_base = create_proc_entry("hermes", S_IFDIR, &proc_root); + if (dir_base == NULL) { + printk(KERN_ERR "Unable to initialise /proc/hermes.\n"); + dldwd_proc_cleanup(); + err = -ENOMEM; + } + + TRACE_EXIT("dldwd"); + + return err; +} + +static int +dldwd_proc_dev_init(dldwd_priv_t *dev) +{ + dev->dir_dev = NULL; + /* create the directory for it to sit in */ + dev->dir_dev = create_proc_entry(dev->node.dev_name, S_IFDIR | S_IRUGO | S_IXUGO, + dir_base); + if (dev->dir_dev == NULL) { + printk(KERN_ERR "Unable to initialise /proc/hermes/%s.\n", dev->node.dev_name); + goto fail; + } + + dev->dir_regs = NULL; + dev->dir_regs = create_proc_read_entry("regs", S_IFREG | S_IRUGO, + dev->dir_dev, dldwd_proc_get_hermes_regs, dev); + if (dev->dir_regs == NULL) { + printk(KERN_ERR "Unable to initialise /proc/hermes/%s/regs.\n", dev->node.dev_name); + goto fail; + } + + dev->dir_recs = NULL; + dev->dir_recs = create_proc_read_entry("recs", S_IFREG | S_IRUGO, + dev->dir_dev, dldwd_proc_get_hermes_recs, dev); + if (dev->dir_recs == NULL) { + printk(KERN_ERR "Unable to initialise /proc/hermes/%s/recs.\n", dev->node.dev_name); + goto fail; + } + + return 0; + fail: + dldwd_proc_dev_cleanup(dev); + return -ENOMEM; +} + +static void +dldwd_proc_dev_cleanup(dldwd_priv_t *priv) +{ + if (priv->dir_regs) { + remove_proc_entry("regs", priv->dir_dev); + priv->dir_regs = NULL; + } + if (priv->dir_recs) { + remove_proc_entry("recs", priv->dir_dev); + priv->dir_recs = NULL; + } + if (priv->dir_dev) { + remove_proc_entry(priv->node.dev_name, dir_base); + priv->dir_dev = NULL; + } +} + +static void +dldwd_proc_cleanup(void) +{ + TRACE_ENTER("dldwd"); + + if (dir_base) { + remove_proc_entry("hermes", &proc_root); + dir_base = NULL; + } + + TRACE_EXIT("dldwd"); +} + +/*====================================================================*/ + +/* + * From here on in, it's all PCMCIA junk, taken almost directly from + * dummy_cs.c + */ + +/* + The dev_info variable is the "key" that is used to match up this + device driver with appropriate cards, through the card configuration + database. +*/ + +static dev_info_t dev_info = "orinoco_cs"; + +/* + A linked list of "instances" of the dummy device. Each actual + PCMCIA card corresponds to one device instance, and is described + by one dev_link_t structure (defined in ds.h). + + You may not want to use a linked list for this -- for example, the + memory card driver uses an array of dev_link_t pointers, where minor + device numbers are used to derive the corresponding array index. +*/ + +static dev_link_t *dev_list = NULL; +static int num_instances = 0; + +/*====================================================================*/ + +static void cs_error(client_handle_t handle, int func, int ret) +{ + error_info_t err = { func, ret }; + CardServices(ReportError, handle, &err); +} + +/*====================================================================== + dldwd_attach() creates an "instance" of the driver, allocating + local data structures for one device. The device is registered + with Card Services. + + The dev_link structure is initialized, but we don't actually + configure the card at this point -- we wait until we receive a + card insertion event. + ======================================================================*/ + +static dev_link_t *dldwd_attach(void) +{ + dldwd_priv_t *priv; + dev_link_t *link; + struct net_device *ndev; + client_reg_t client_reg; + int ret, i; + + TRACE_ENTER("dldwd"); + + /* Allocate space for private device-specific data */ + priv = kmalloc(sizeof(*priv), GFP_KERNEL); + if (! priv) { + link = NULL; + goto out; + } + + memset(priv, 0, sizeof(*priv)); + priv->instance = num_instances++; /* FIXME: Racy? */ + spin_lock_init(&priv->lock); + + link = &priv->link; + ndev = &priv->ndev; + link->priv = ndev->priv = priv; + + /* Initialize the dev_link_t structure */ + link->release.function = &dldwd_release; + link->release.data = (u_long) link; + + /* Interrupt setup */ + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; + link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; + if (irq_list[0] == -1) + link->irq.IRQInfo2 = irq_mask; + else + for (i = 0; i < 4; i++) + link->irq.IRQInfo2 |= 1 << irq_list[i]; + link->irq.Handler = NULL; + + /* + General socket configuration defaults can go here. In this + client, we assume very little, and rely on the CIS for almost + everything. In most clients, many details (i.e., number, sizes, + and attributes of IO windows) are fixed by the nature of the + device, and can be hard-wired here. + */ + link->conf.Attributes = 0; + link->conf.IntType = INT_MEMORY_AND_IO; + + /* Set up the net_device */ + ether_setup(ndev); + ndev->init = dldwd_init; + ndev->open = dldwd_open; + ndev->stop = dldwd_stop; + ndev->hard_start_xmit = dldwd_xmit; + ndev->tx_timeout = dldwd_tx_timeout; + ndev->watchdog_timeo = 4*HZ; /* 4 second timeout */ + + ndev->get_stats = dldwd_get_stats; + ndev->get_wireless_stats = dldwd_get_wireless_stats; + + ndev->do_ioctl = dldwd_ioctl; + + ndev->change_mtu = dldwd_change_mtu; + ndev->set_multicast_list = dldwd_set_multicast_list; + + netif_stop_queue(ndev); + + /* Register with Card Services */ + link->next = dev_list; + dev_list = link; + client_reg.dev_info = &dev_info; + client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; + client_reg.EventMask = + CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | + CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | + CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; + client_reg.event_handler = &dldwd_event; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + ret = CardServices(RegisterClient, &link->handle, &client_reg); + if (ret != CS_SUCCESS) { + cs_error(link->handle, RegisterClient, ret); + dldwd_detach(link); + link = NULL; + goto out; + } + + out: + TRACE_EXIT("dldwd"); + return link; +} /* dldwd_attach */ + +/*====================================================================== + This deletes a driver "instance". The device is de-registered + with Card Services. If it has been released, all local data + structures are freed. Otherwise, the structures will be freed + when the device is released. + ======================================================================*/ + +static void dldwd_detach(dev_link_t * link) +{ + dev_link_t **linkp; + dldwd_priv_t *priv = link->priv; + + TRACE_ENTER("dldwd"); + + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) + break; + if (*linkp == NULL) + goto out; + + /* + If the device is currently configured and active, we won't + actually delete it yet. Instead, it is marked so that when + the release() function is called, that will trigger a proper + detach(). + */ + if (link->state & DEV_CONFIG) { +#ifdef PCMCIA_DEBUG + printk(KERN_DEBUG "orinoco_cs: detach postponed, '%s' " + "still locked\n", link->dev->dev_name); +#endif + link->state |= DEV_STALE_LINK; + goto out; + } + + /* Break the link with Card Services */ + if (link->handle) + CardServices(DeregisterClient, link->handle); + + /* Unlink device structure, and free it */ + *linkp = link->next; + DEBUG(0, "orinoco_cs: detach: link=%p link->dev=%p\n", link, link->dev); + if (link->dev) { + DEBUG(0, "orinoco_cs: About to unregister net device %p\n", + &priv->ndev); + unregister_netdev(&priv->ndev); + } + kfree(priv); + + num_instances--; /* FIXME: Racy? */ + + out: + TRACE_EXIT("dldwd"); +} /* dldwd_detach */ + +/*====================================================================== + dldwd_config() is scheduled to run after a CARD_INSERTION event + is received, to configure the PCMCIA socket, and to make the + device available to the system. + ======================================================================*/ + +#define CS_CHECK(fn, args...) \ +while ((last_ret=CardServices(last_fn=(fn),args))!=0) goto cs_failed + +#define CFG_CHECK(fn, args...) \ +if (CardServices(fn, args) != 0) goto next_entry + +static void dldwd_config(dev_link_t * link) +{ + client_handle_t handle = link->handle; + dldwd_priv_t *priv = link->priv; + hermes_t *hw = &priv->hw; + struct net_device *ndev = &priv->ndev; + tuple_t tuple; + cisparse_t parse; + int last_fn, last_ret; + u_char buf[64]; + config_info_t conf; + cisinfo_t info; + + TRACE_ENTER("dldwd"); + + CS_CHECK(ValidateCIS, handle, &info); + + /* + This reads the card's CONFIG tuple to find its configuration + registers. + */ + tuple.DesiredTuple = CISTPL_CONFIG; + tuple.Attributes = 0; + tuple.TupleData = buf; + tuple.TupleDataMax = sizeof(buf); + tuple.TupleOffset = 0; + CS_CHECK(GetFirstTuple, handle, &tuple); + CS_CHECK(GetTupleData, handle, &tuple); + CS_CHECK(ParseTuple, handle, &tuple, &parse); + link->conf.ConfigBase = parse.config.base; + link->conf.Present = parse.config.rmask[0]; + + /* Configure card */ + link->state |= DEV_CONFIG; + + /* Look up the current Vcc */ + CS_CHECK(GetConfigurationInfo, handle, &conf); + link->conf.Vcc = conf.Vcc; + + DEBUG(0, "dldwd_config: ConfigBase = 0x%x link->conf.Vcc = %d\n", + link->conf.ConfigBase, link->conf.Vcc); + + /* + In this loop, we scan the CIS for configuration table entries, + each of which describes a valid card configuration, including + voltage, IO window, memory window, and interrupt settings. + + We make no assumptions about the card to be configured: we use + just the information available in the CIS. In an ideal world, + this would work for any PCMCIA card, but it requires a complete + and accurate CIS. In practice, a driver usually "knows" most of + these things without consulting the CIS, and most client drivers + will only use the CIS to fill in implementation-defined details. + */ + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + CS_CHECK(GetFirstTuple, handle, &tuple); + while (1) { + cistpl_cftable_entry_t dflt = { 0 }; + cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); + CFG_CHECK(GetTupleData, handle, &tuple); + CFG_CHECK(ParseTuple, handle, &tuple, &parse); + + DEBUG(0, "dldwd_config: index = 0x%x, flags = 0x%x\n", + cfg->index, cfg->flags); + + if (cfg->flags & CISTPL_CFTABLE_DEFAULT) + dflt = *cfg; + if (cfg->index == 0) + goto next_entry; + link->conf.ConfigIndex = cfg->index; + + /* Does this card need audio output? */ + if (cfg->flags & CISTPL_CFTABLE_AUDIO) { + link->conf.Attributes |= CONF_ENABLE_SPKR; + link->conf.Status = CCSR_AUDIO_ENA; + } + + /* Use power settings for Vcc and Vpp if present */ + /* Note that the CIS values need to be rescaled */ + if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { + if (conf.Vcc != + cfg->vcc.param[CISTPL_POWER_VNOM] / + 10000) goto next_entry; + } else if (dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) { + if (conf.Vcc != + dflt.vcc.param[CISTPL_POWER_VNOM] / + 10000) goto next_entry; + } + + if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) + link->conf.Vpp1 = link->conf.Vpp2 = + cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; + else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) + link->conf.Vpp1 = link->conf.Vpp2 = + dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; + + DEBUG(0, "dldwd_config: We seem to have configured Vcc and Vpp\n"); + + /* Do we need to allocate an interrupt? */ + if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) + link->conf.Attributes |= CONF_ENABLE_IRQ; + + /* IO window settings */ + link->io.NumPorts1 = link->io.NumPorts2 = 0; + if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { + cistpl_io_t *io = + (cfg->io.nwin) ? &cfg->io : &dflt.io; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + if (!(io->flags & CISTPL_IO_8BIT)) + link->io.Attributes1 = + IO_DATA_PATH_WIDTH_16; + if (!(io->flags & CISTPL_IO_16BIT)) + link->io.Attributes1 = + IO_DATA_PATH_WIDTH_8; + link->io.IOAddrLines = + io->flags & CISTPL_IO_LINES_MASK; + link->io.BasePort1 = io->win[0].base; + link->io.NumPorts1 = io->win[0].len; + if (io->nwin > 1) { + link->io.Attributes2 = + link->io.Attributes1; + link->io.BasePort2 = io->win[1].base; + link->io.NumPorts2 = io->win[1].len; + } + + /* This reserves IO space but doesn't actually enable it */ + CFG_CHECK(RequestIO, link->handle, &link->io); + } + + + /* If we got this far, we're cool! */ + + break; + + next_entry: + if (link->io.NumPorts1) + CardServices(ReleaseIO, link->handle, &link->io); + CS_CHECK(GetNextTuple, handle, &tuple); + } + + /* + Allocate an interrupt line. Note that this does not assign a + handler to the interrupt, unless the 'Handler' member of the + irq structure is initialized. + */ + if (link->conf.Attributes & CONF_ENABLE_IRQ) { + int i; + + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; + link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; + if (irq_list[0] == -1) + link->irq.IRQInfo2 = irq_mask; + else + for (i=0; i<4; i++) + link->irq.IRQInfo2 |= 1 << irq_list[i]; + + link->irq.Handler = dldwd_interrupt; + link->irq.Instance = priv; + + CS_CHECK(RequestIRQ, link->handle, &link->irq); + } + + /* We initialize the hermes structure before completing PCMCIA + configuration just in case the interrupt handler gets + called. */ + hermes_struct_init(hw, link->io.BasePort1); + + /* + This actually configures the PCMCIA socket -- setting up + the I/O windows and the interrupt mapping, and putting the + card and host interface into "Memory and IO" mode. + */ + CS_CHECK(RequestConfiguration, link->handle, &link->conf); + + ndev->base_addr = link->io.BasePort1; + ndev->irq = link->irq.AssignedIRQ; + + /* Instance name : by default, use hermesX, on demand use the + * regular ethX (less risky) - Jean II */ + if(!eth) + sprintf(ndev->name, "hermes%d", priv->instance); + else + ndev->name[0] = '\0'; + /* Tell the stack we exist */ + if (register_netdev(ndev) != 0) { + printk(KERN_ERR "orinoco_cs: register_netdev() failed\n"); + goto failed; + } + strcpy(priv->node.dev_name, ndev->name); + + /* Finally, report what we've done */ + printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d", + priv->node.dev_name, link->conf.ConfigIndex, + link->conf.Vcc / 10, link->conf.Vcc % 10); + if (link->conf.Vpp1) + printk(", Vpp %d.%d", link->conf.Vpp1 / 10, + link->conf.Vpp1 % 10); + if (link->conf.Attributes & CONF_ENABLE_IRQ) + printk(", irq %d", link->irq.AssignedIRQ); + if (link->io.NumPorts1) + printk(", io 0x%04x-0x%04x", link->io.BasePort1, + link->io.BasePort1 + link->io.NumPorts1 - 1); + if (link->io.NumPorts2) + printk(" & 0x%04x-0x%04x", link->io.BasePort2, + link->io.BasePort2 + link->io.NumPorts2 - 1); + printk("\n"); + + /* And give us the proc nodes for debugging */ + if (dldwd_proc_dev_init(priv) != 0) { + printk(KERN_ERR "orinoco_cs: Failed to create /proc node for %s\n", + priv->node.dev_name); + goto failed; + } + + /* + At this point, the dev_node_t structure(s) need to be + initialized and arranged in a linked list at link->dev. + */ + priv->node.major = priv->node.minor = 0; + link->dev = &priv->node; + link->state &= ~DEV_CONFIG_PENDING; + + TRACE_EXIT("dldwd"); + + return; + + cs_failed: + cs_error(link->handle, last_fn, last_ret); + failed: + dldwd_release((u_long) link); + + TRACE_EXIT("dldwd"); +} /* dldwd_config */ + +/*====================================================================== + After a card is removed, dldwd_release() will unregister the + device, and release the PCMCIA configuration. If the device is + still open, this will be postponed until it is closed. + ======================================================================*/ + +static void dldwd_release(u_long arg) +{ + dev_link_t *link = (dev_link_t *) arg; + dldwd_priv_t *priv = link->priv; + + TRACE_ENTER(link->dev->dev_name); + + /* + If the device is currently in use, we won't release until it + is actually closed, because until then, we can't be sure that + no one will try to access the device or its data structures. + */ + if (link->open) { + DEBUG(0, "orinoco_cs: release postponed, '%s' still open\n", + link->dev->dev_name); + link->state |= DEV_STALE_CONFIG; + return; + } + + /* + In a normal driver, additional code may be needed to release + other kernel data structures associated with this device. + */ + + dldwd_proc_dev_cleanup(priv); + + /* Don't bother checking to see if these succeed or not */ + CardServices(ReleaseConfiguration, link->handle); + if (link->io.NumPorts1) + CardServices(ReleaseIO, link->handle, &link->io); + if (link->irq.AssignedIRQ) + CardServices(ReleaseIRQ, link->handle, &link->irq); + link->state &= ~DEV_CONFIG; + + TRACE_EXIT(link->dev->dev_name); +} /* dldwd_release */ + +/*====================================================================== + The card status event handler. Mostly, this schedules other + stuff to run after an event is received. + + When a CARD_REMOVAL event is received, we immediately set a + private flag to block future accesses to this device. All the + functions that actually access the device should check this flag + to make sure the card is still present. + ======================================================================*/ + +static int dldwd_event(event_t event, int priority, + event_callback_args_t * args) +{ + dev_link_t *link = args->client_data; + dldwd_priv_t *priv = (dldwd_priv_t *)link->priv; + struct net_device *dev = &priv->ndev; + + TRACE_ENTER("dldwd"); + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + dldwd_shutdown(priv); + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) { + netif_stop_queue(dev); + netif_device_detach(dev); + mod_timer(&link->release, jiffies + HZ / 20); + } + break; + case CS_EVENT_CARD_INSERTION: + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + dldwd_config(link); + break; + case CS_EVENT_PM_SUSPEND: + + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + dldwd_shutdown(priv); + /* Mark the device as stopped, to block IO until later */ + + if (link->state & DEV_CONFIG) { + if (link->open) { + netif_stop_queue(dev); + netif_device_detach(dev); + } + CardServices(ReleaseConfiguration, link->handle); + } + break; + case CS_EVENT_PM_RESUME: + link->state &= ~DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_CARD_RESET: + if (link->state & DEV_CONFIG) { + CardServices(RequestConfiguration, link->handle, + &link->conf); + + if (link->open) { + if (dldwd_reset(priv) == 0) { + netif_device_attach(dev); + netif_start_queue(dev); + } else { + printk(KERN_ERR "%s: Error resetting device on PCMCIA event\n", + dev->name); + dldwd_stop(dev); + } + } + } + /* + In a normal driver, additional code may go here to restore + the device state and restart IO. + */ + break; + } + + TRACE_EXIT("dldwd"); + + return 0; +} /* dldwd_event */ + +static int __init init_dldwd_cs(void) +{ + servinfo_t serv; + int err; + + TRACE_ENTER("dldwd"); + + printk(KERN_INFO "dldwd: David's Less Dodgy WaveLAN/IEEE Driver\n"); + + DEBUG(0, "%s\n", version); + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { + printk(KERN_NOTICE "orinoco_cs: Card Services release " + "does not match!\n"); + return -1; + } + register_pccard_driver(&dev_info, &dldwd_attach, &dldwd_detach); + + + err = dldwd_proc_init(); + + TRACE_EXIT("dldwd"); + return err; +} + +static void __exit exit_dldwd_cs(void) +{ + TRACE_ENTER("dldwd"); + + dldwd_proc_cleanup(); + + unregister_pccard_driver(&dev_info); + + if (dev_list) + DEBUG(0, "orinoco_cs: Removing leftover devices.\n"); + while (dev_list != NULL) { + del_timer(&dev_list->release); + if (dev_list->state & DEV_CONFIG) + dldwd_release((u_long) dev_list); + dldwd_detach(dev_list); + } + + TRACE_EXIT("dldwd"); +} + +module_init(init_dldwd_cs); +module_exit(exit_dldwd_cs); diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index 9befdebfc..8a5c5f33a 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -11,7 +11,7 @@ Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net - pcnet_cs.c 1.126 2000/10/02 20:38:23 + pcnet_cs.c 1.132 2001/02/09 03:13:29 The network driver code is based on Donald Becker's NE2000 code: @@ -72,7 +72,7 @@ static int pc_debug = PCMCIA_DEBUG; MODULE_PARM(pc_debug, "i"); #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) static char *version = -"pcnet_cs.c 1.126 2000/10/02 20:38:23 (David Hinds)"; +"pcnet_cs.c 1.132 2001/02/09 03:13:29 (David Hinds)"; #else #define DEBUG(n, args...) #endif @@ -137,7 +137,7 @@ typedef struct hw_info_t { #define HAS_IBM_MISC 0x08 #define IS_DL10019 0x10 #define IS_DL10022 0x20 -#define IS_AX88190 0x40 +#define HAS_MII 0x40 #define USE_SHMEM 0x80 /* autodetected */ static hw_info_t hw_info[] = { @@ -204,8 +204,8 @@ static hw_info_t hw_info[] = { #define NR_INFO (sizeof(hw_info)/sizeof(hw_info_t)) static hw_info_t default_info = { 0, 0, 0, 0, 0 }; -static hw_info_t dl10019_info = { 0, 0, 0, 0, IS_DL10019 }; -static hw_info_t dl10022_info = { 0, 0, 0, 0, IS_DL10019|IS_DL10022 }; +static hw_info_t dl10019_info = { 0, 0, 0, 0, IS_DL10019|HAS_MII }; +static hw_info_t dl10022_info = { 0, 0, 0, 0, IS_DL10022|HAS_MII }; typedef struct pcnet_dev_t { struct net_device dev; /* so &dev == &pcnet_dev_t */ @@ -507,10 +507,10 @@ static hw_info_t *get_ax88190(dev_link_t *link) if (link->conf.ConfigBase != 0x03c0) return NULL; - outb_p(0x01, EN0_DCFG); /* Set word-wide access. */ - outb_p(0x00, EN0_RSARLO); /* DMA starting at 0x0400. */ - outb_p(0x04, EN0_RSARHI); - outb_p(E8390_RREAD+E8390_START, E8390_CMD); + outb_p(0x01, ioaddr + EN0_DCFG); /* Set word-wide access. */ + outb_p(0x00, ioaddr + EN0_RSARLO); /* DMA starting at 0x0400. */ + outb_p(0x04, ioaddr + EN0_RSARHI); + outb_p(E8390_RREAD+E8390_START, ioaddr + E8390_CMD); for (i = 0; i < 6; i += 2) { j = inw(ioaddr + PCNET_DATAPORT); @@ -718,6 +718,7 @@ static void pcnet_config(dev_link_t *link) info->flags |= (delay_output) ? DELAY_OUTPUT : 0; if ((manfid == MANFID_SOCKET) && ((prodid == PRODID_SOCKET_LPE) || + (prodid == PRODID_SOCKET_LPE_CF) || (prodid == PRODID_SOCKET_EIO))) info->flags &= ~USE_BIG_BUF; if (!use_big_buf) @@ -746,13 +747,11 @@ static void pcnet_config(dev_link_t *link) link->dev = &info->node; link->state &= ~DEV_CONFIG_PENDING; - if (info->flags & IS_DL10019) { + if (info->flags & (IS_DL10019|IS_DL10022)) { dev->do_ioctl = &do_ioctl; printk(KERN_INFO "%s: NE2000 (DL100%d rev %02x): ", dev->name, ((info->flags & IS_DL10022) ? 22 : 19), inb(dev->base_addr + 0x1a)); - } else if (info->flags & IS_AX88190) { - printk(KERN_INFO "%s: NE2000 (AX88190): ", dev->name); } else printk(KERN_INFO "%s: NE2000 Compatible: ", dev->name); printk("io %#3lx, irq %d,", dev->base_addr, dev->irq); @@ -1024,6 +1023,8 @@ static void pcnet_reset_8390(struct net_device *dev) ei_status.txing = ei_status.dmaing = 0; + outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, nic_base + E8390_CMD); + outb(inb(nic_base + PCNET_RESET), nic_base + PCNET_RESET); for (i = 0; i < 100; i++) { @@ -1092,10 +1093,17 @@ static void ei_watchdog(u_long arg) return; } - if (!(info->flags & IS_DL10019)) + if (!(info->flags & HAS_MII)) + goto reschedule; + + link = mdio_read(dev->base_addr + DLINK_GPIO, 0, 1); + if (!link || (link == 0xffff)) { + printk(KERN_INFO "%s: MII is missing!\n", dev->name); + info->flags &= ~HAS_MII; goto reschedule; + } - link = mdio_read(dev->base_addr + DLINK_GPIO, 0, 1) & 0x0004; + link &= 0x0004; if (link != info->link_status) { u_short p = mdio_read(dev->base_addr + DLINK_GPIO, 0, 5); printk(KERN_INFO "%s: %s link beat\n", dev->name, diff --git a/drivers/net/pcmcia/ray_cs.c b/drivers/net/pcmcia/ray_cs.c index 90d62149a..d51d7aaab 100644 --- a/drivers/net/pcmcia/ray_cs.c +++ b/drivers/net/pcmcia/ray_cs.c @@ -2219,9 +2219,9 @@ static void rx_data(struct net_device *dev, struct rcs *prcs, unsigned int pkt_a skb->protocol = eth_type_trans(skb,dev); netif_rx(skb); - + dev->last_rx = jiffies; local->stats.rx_packets++; - local->stats.rx_bytes += skb->len; + local->stats.rx_bytes += total_len; /* Gather signal strength per address */ #ifdef WIRELESS_SPY diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index fe49974d0..478a4d1eb 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -8,7 +8,7 @@ Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net - smc91c92_cs.c 1.104 2000/08/31 21:25:13 + smc91c92_cs.c 1.106 2001/02/07 00:19:58 This driver contains code written by Donald Becker (becker@cesdis.gsfc.nasa.gov), Rowan Hughes (x-csrdh@jcu.edu.au), @@ -231,7 +231,7 @@ enum RxCfg { RxAllMulti = 0x0004, RxPromisc = 0x0002, RxEnable = 0x0100, RxStripCRC = 0x0200}; #define RCR_SOFTRESET 0x8000 /* resets the chip */ #define RCR_STRIP_CRC 0x200 /* strips CRC */ -#define RCR_ENABLE 0x100 /* IFF this is set, we can recieve packets */ +#define RCR_ENABLE 0x100 /* IFF this is set, we can receive packets */ #define RCR_ALMUL 0x4 /* receive all multicast packets */ #define RCR_PROMISC 0x2 /* enable promiscuous mode */ @@ -1617,8 +1617,9 @@ static void smc_rx(struct net_device *dev) skb->dev = dev; netif_rx(skb); + dev->last_rx = jiffies; smc->stats.rx_packets++; - smc->stats.rx_bytes += skb->len; + smc->stats.rx_bytes += packet_length; if (rx_status & RS_MULTICAST) smc->stats.multicast++; } else { diff --git a/drivers/net/pcmcia/wavelan.h b/drivers/net/pcmcia/wavelan.h index 0e1ee227d..2d03b182c 100644 --- a/drivers/net/pcmcia/wavelan.h +++ b/drivers/net/pcmcia/wavelan.h @@ -7,11 +7,11 @@ * Original copyright follow. See wavelan_cs.h for details. * * This file contain the declarations of the Wavelan hardware. Note that - * the Pcmcia Wavelan include a i82593 controler (see definitions in + * the Pcmcia Wavelan include a i82593 controller (see definitions in * file i82593.h). * * The main difference between the pcmcia hardware and the ISA one is - * the Ethernet Controler (i82593 instead of i82586). The i82593 allow + * the Ethernet Controller (i82593 instead of i82586). The i82593 allow * only one send buffer. The PSA (Parameter Storage Area : EEprom for * permanent storage of various info) is memory mapped, but not the * MMI (Modem Management Interface). diff --git a/drivers/net/pcmcia/wavelan_cs.c b/drivers/net/pcmcia/wavelan_cs.c index f435466a0..9b0a51f89 100644 --- a/drivers/net/pcmcia/wavelan_cs.c +++ b/drivers/net/pcmcia/wavelan_cs.c @@ -37,6 +37,12 @@ * Apr 2 '98 made changes to bring the i82593 control/int handling in line * with offical specs... * + * Changes: + * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 08/08/2000 + * - reorganize kmallocs in wavelan_attach, checking all for failure + * and releasing the previous allocations if one fails + * + * **************************************************************************** * Copyright 1995 * Anthony D. Joseph @@ -512,7 +518,7 @@ void wv_roam_init(struct net_device *dev) /* Do not remove this unless you have a good reason */ printk(KERN_NOTICE "%s: Warning, you have enabled roaming on" " device %s !\n", dev->name, dev->name); - printk(KERN_NOTICE "Roaming is currently an experimental unsuported feature" + printk(KERN_NOTICE "Roaming is currently an experimental unsupported feature" " of the Wavelan driver.\n"); printk(KERN_NOTICE "It may work, but may also make the driver behave in" " erratic ways or crash.\n"); @@ -820,7 +826,7 @@ static inline int WAVELAN_BEACON(unsigned char *data) /************************ I82593 SUBROUTINES *************************/ /* - * Usefull subroutines to manage the Ethernet controler + * Useful subroutines to manage the Ethernet controller */ /*------------------------------------------------------------------*/ @@ -853,7 +859,7 @@ wv_82593_cmd(device * dev, /* We are waiting for command completion */ wv_wait_completed = TRUE; - /* Issue the command to the controler */ + /* Issue the command to the controller */ outb(cmd, LCCR(base)); /* If we don't have to check the result of the command */ @@ -1398,7 +1404,7 @@ wv_init_info(device * dev) printk("2430.5"); break; default: - printk("???"); + printk("unknown"); } } @@ -1713,7 +1719,7 @@ wv_set_frequency(u_long base, /* i/o port of the card */ memcmp(dac, dac_verify, 2 * 2)) { #ifdef DEBUG_IOCTL_ERROR - printk(KERN_INFO "Wavelan: wv_set_frequency : unable to write new frequency to EEprom (??)\n"); + printk(KERN_INFO "Wavelan: wv_set_frequency : unable to write new frequency to EEprom (?)\n"); #endif return -EOPNOTSUPP; } @@ -1774,7 +1780,7 @@ wv_frequency_list(u_long base, /* i/o port of the card */ #if WIRELESS_EXT > 7 const int BAND_NUM = 10; /* Number of bands */ int c = 0; /* Channel number */ -#endif WIRELESS_EXT +#endif /* WIRELESS_EXT */ /* Read the frequency table */ fee_read(base, 0x71 /* frequency table */, @@ -1792,7 +1798,7 @@ wv_frequency_list(u_long base, /* i/o port of the card */ (c < BAND_NUM)) c++; list[i].i = c; /* Set the list index */ -#endif WIRELESS_EXT +#endif /* WIRELESS_EXT */ /* put in the list */ list[i].m = (((freq + 24) * 5) + 24000L) * 10000; @@ -1962,7 +1968,7 @@ wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */ case SIOCGIWFREQ: /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) - * (does it work for everybody ??? - especially old cards...) */ + * (does it work for everybody XXX - especially old cards...) */ if(!(mmc_in(base, mmroff(0, mmr_fee_status)) & (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { @@ -2524,11 +2530,12 @@ wavelan_get_wireless_stats(device * dev) printk(KERN_DEBUG "%s: ->wavelan_get_wireless_stats()\n", dev->name); #endif + if (lp == NULL) /* XXX will this ever occur? */ + return NULL; + /* Disable interrupts & save flags */ spin_lock_irqsave (&lp->lock, flags); - if(lp == (net_local *) NULL) - return (iw_stats *) NULL; wstats = &lp->wstats; /* Get data from the mmc */ @@ -2727,8 +2734,9 @@ wv_packet_read(device * dev, netif_rx(skb); /* Keep stats up to date */ + dev->last_rx = jiffies; lp->stats.rx_packets++; - lp->stats.rx_bytes += skb->len; + lp->stats.rx_bytes += sksize; #ifdef DEBUG_RX_TRACE printk(KERN_DEBUG "%s: <-wv_packet_read()\n", dev->name); @@ -2949,7 +2957,7 @@ wv_packet_write(device * dev, /*------------------------------------------------------------------*/ /* * This routine is called when we want to send a packet (NET3 callback) - * In this routine, we check if the the harware is ready to accept + * In this routine, we check if the hardware is ready to accept * the packet. We also prevent reentrance. Then, we call the function * to send the packet... */ @@ -2974,7 +2982,7 @@ static int wavelan_packet_xmit (struct sk_buff *skb, * In other words, prevent reentering this routine. */ if (1) { - /* If somebody has asked to reconfigure the controler, we can do it now */ + /* If somebody has asked to reconfigure the controller, we can do it now */ if (lp->reconfig_82593) { lp->reconfig_82593 = FALSE; wv_82593_config (dev); @@ -3144,7 +3152,7 @@ wv_mmc_init(device * dev) */ /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) - * (does it work for everybody ??? - especially old cards...) */ + * (does it work for everybody XXX - especially old cards...) */ /* Note : WFREQSEL verify that it is able to read from EEprom * a sensible frequency (address 0x00) + that MMR_FEE_STATUS_ID * is 0xA (Xilinx version) or 0xB (Ariadne version). @@ -3332,7 +3340,7 @@ wv_ru_start(device * dev) /*------------------------------------------------------------------*/ /* - * This routine does a standard config of the WaveLAN controler (i82593). + * This routine does a standard config of the WaveLAN controller (i82593). * In the ISA driver, this is integrated in wavelan_hardware_reset() * (called by wv_hw_config(), wv_82593_reconfig() & wavelan_packet_xmit()) */ @@ -3596,7 +3604,7 @@ wv_hw_config(device * dev) hacr_write_slow(base, HACR_RESET); hacr_write(base, HACR_DEFAULT); - /* Check if the the module has been powered up... */ + /* Check if the module has been powered up... */ if(hasr_read(base) & HASR_NO_CLK) { #ifdef DEBUG_CONFIG_ERRORS @@ -3614,7 +3622,7 @@ wv_hw_config(device * dev) outb(OP0_RESET, LCCR(base)); mdelay(1); /* A bit crude ! */ - /* Initialize the LAN controler */ + /* Initialize the LAN controller */ if((wv_82593_config(dev) == FALSE) || (wv_diag(dev) == FALSE)) { @@ -3822,7 +3830,7 @@ wv_pcmcia_config(dev_link_t * link) return FALSE; } - /* ???? Could you explain me this, Dave ? */ + /* XXX Could you explain me this, Dave ? */ link->dev = &((net_local *) dev->priv)->node; #ifdef DEBUG_CONFIG_TRACE @@ -3918,7 +3926,7 @@ wv_flush_stale_links(void) * This function is the interrupt handler for the WaveLAN card. This * routine will be called whenever: * 1. A packet is received. - * 2. A packet has successfully been transfered and the unit is + * 2. A packet has successfully been transferred and the unit is * ready to transmit another packet. * 3. A command has completed execution. */ @@ -4285,7 +4293,7 @@ wavelan_open(device * dev) /* Power up (power up time is 250us) */ hacr_write(base, HACR_DEFAULT); - /* Check if the the module has been powered up... */ + /* Check if the module has been powered up... */ if(hasr_read(base) & HASR_NO_CLK) { #ifdef DEBUG_CONFIG_ERRORS @@ -4424,7 +4432,24 @@ wavelan_attach(void) /* Initialize the dev_link_t structure */ link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); + if (!link) + return NULL; + + /* Allocate the generic data structure */ + dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); + if (!dev) + goto fail_alloc_dev; + + /* Allocate the wavelan-specific data structure. */ + lp = (net_local *) kmalloc(sizeof(net_local), GFP_KERNEL); + if (!lp) + goto fail_alloc_dev_priv; + + memset(lp, 0, sizeof(net_local)); memset(link, 0, sizeof(struct dev_link_t)); + memset(dev, 0, sizeof(struct net_device)); + + dev->priv = lp; /* Unused for the Wavelan */ link->release.function = &wv_pcmcia_release; @@ -4454,15 +4479,8 @@ wavelan_attach(void) link->next = dev_list; dev_list = link; - /* Allocate the generic data structure */ - dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); - memset(dev, 0x00, sizeof(struct net_device)); link->priv = link->irq.Instance = dev; - /* Allocate the wavelan-specific data structure. */ - dev->priv = lp = (net_local *) kmalloc(sizeof(net_local), GFP_KERNEL); - memset(lp, 0x00, sizeof(net_local)); - /* Init specific data */ wv_wait_completed = 0; lp->status = FALSE; @@ -4531,6 +4549,12 @@ wavelan_attach(void) #endif return link; + +fail_alloc_dev_priv: + kfree(dev); +fail_alloc_dev: + kfree(link); + return NULL; } /*------------------------------------------------------------------*/ @@ -4683,7 +4707,7 @@ wavelan_event(event_t event, /* The event received */ * obliged to close nicely the wavelan here. David, could you * close the device before suspending them ? And, by the way, * could you, on resume, add a "route add -net ..." after the - * ifconfig up ??? Thanks... */ + * ifconfig up XXX Thanks... */ /* Stop receiving new messages and wait end of transmission */ wv_ru_stop(dev); @@ -4711,7 +4735,7 @@ wavelan_event(event_t event, /* The event received */ if(link->state & DEV_CONFIG) { CardServices(RequestConfiguration, link->handle, &link->conf); - if(link->open) /* If RESET -> True, If RESUME -> False ??? */ + if(link->open) /* If RESET -> True, If RESUME -> False XXX */ { wv_hw_reset(dev); netif_device_attach(dev); diff --git a/drivers/net/pcmcia/wavelan_cs.h b/drivers/net/pcmcia/wavelan_cs.h index 68b2f5fc1..1cf51dc77 100644 --- a/drivers/net/pcmcia/wavelan_cs.h +++ b/drivers/net/pcmcia/wavelan_cs.h @@ -96,7 +96,7 @@ * * wavelan.h : Description of the hardware interface & structs * - * i82593.h : Description if the Ethernet controler + * i82593.h : Description if the Ethernet controller */ /* --------------------------- HISTORY --------------------------- */ @@ -225,7 +225,7 @@ * - wavelan_set_multicast_list : avoid reset * - add wireless extensions (ioctl & get_wireless_stats) * get/set nwid/frequency on fly, info for /proc/net/wireless - * - Supress useless stuff from lp (net_local), but add link + * - Suppress useless stuff from lp (net_local), but add link * - More inlines * - Lot of others minor details & cleanups * @@ -315,7 +315,7 @@ * o Rename wavelan_release to wv_pcmcia_release & move up * o move unregister_netdev to wavelan_detach() * o wavelan_release() no longer call wavelan_detach() - * o Supress "release" timer + * o Suppress "release" timer * o Other cleanups & fixes * - New MAC address in the probe * - Reorg PSA_CRC code (endian neutral & cleaner) @@ -430,14 +430,14 @@ #undef DEBUG_CONFIG_INFO /* What's going on... */ #define DEBUG_CONFIG_ERRORS /* Errors on configuration */ #undef DEBUG_TX_TRACE /* Transmission calls */ -#undef DEBUG_TX_INFO /* Header of the transmited packet */ +#undef DEBUG_TX_INFO /* Header of the transmitted packet */ #undef DEBUG_TX_FAIL /* Normal failure conditions */ #define DEBUG_TX_ERROR /* Unexpected conditions */ #undef DEBUG_RX_TRACE /* Transmission calls */ -#undef DEBUG_RX_INFO /* Header of the transmited packet */ +#undef DEBUG_RX_INFO /* Header of the transmitted packet */ #undef DEBUG_RX_FAIL /* Normal failure conditions */ #define DEBUG_RX_ERROR /* Unexpected conditions */ -#undef DEBUG_PACKET_DUMP 32 /* Dump packet on the screen */ +#undef DEBUG_PACKET_DUMP /* Dump packet on the screen */ #undef DEBUG_IOCTL_TRACE /* Misc call by Linux */ #undef DEBUG_IOCTL_INFO /* Various debug info */ #define DEBUG_IOCTL_ERROR /* What's going wrong */ @@ -557,7 +557,7 @@ struct net_local en_stats stats; /* Ethernet interface statistics */ int nresets; /* Number of hw resets */ u_char configured; /* If it is configured */ - u_char reconfig_82593; /* Need to reconfigure the controler */ + u_char reconfig_82593; /* Need to reconfigure the controller */ u_char promiscuous; /* Promiscuous mode */ u_char allmulticast; /* All Multicast mode */ int mc_count; /* Number of multicast addresses */ @@ -669,7 +669,7 @@ static int char *, int); static inline void - wv_82593_reconfig(device *); /* Reconfigure the controler */ + wv_82593_reconfig(device *); /* Reconfigure the controller */ /* ------------------- DEBUG & INFO SUBROUTINES ------------------- */ static inline void wv_init_info(device *); /* display startup info */ diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index abe0e1e37..541622308 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c @@ -125,7 +125,7 @@ enum xirc_esr { enum xirc_isr { TxBufOvr = 0x01, /* TX Buffer Overflow */ PktTxed = 0x02, /* Packet Transmitted */ - MACIntr = 0x04, /* MAC Interrupt occured */ + MACIntr = 0x04, /* MAC Interrupt occurred */ TxResGrant = 0x08, /* Tx Reservation Granted */ RxFullPkt = 0x20, /* Rx Full Packet */ RxPktRej = 0x40, /* Rx Packet Rejected */ @@ -382,6 +382,7 @@ static int init_mii(struct net_device *dev); static void do_powerdown(struct net_device *dev); static int do_stop(struct net_device *dev); + /*=============== Helper functions =========================*/ static void flush_stale_links(void) @@ -1350,7 +1351,6 @@ xirc2ps_interrupt(int irq, void *dev_id, struct pt_regs *regs) * packets */ lp->stats.rx_dropped++; DEBUG(2, "%s: RX drop, too much done\n", dev->name); - PutWord(XIRCREG0_DO, 0x8000); /* issue cmd: skip_rx_packet */ } else if (rsr & PktRxOk) { struct sk_buff *skb; @@ -1420,13 +1420,13 @@ xirc2ps_interrupt(int irq, void *dev_id, struct pt_regs *regs) skb->protocol = eth_type_trans(skb, dev); skb->dev = dev; netif_rx(skb); + dev->last_rx = jiffies; lp->stats.rx_packets++; lp->stats.rx_bytes += pktlen; if (!(rsr & PhyPkt)) lp->stats.multicast++; } - PutWord(XIRCREG0_DO, 0x8000); /* issue cmd: skip_rx_packet */ - } else { + } else { /* bad packet */ DEBUG(5, "rsr=%#02x\n", rsr); } if (rsr & PktTooLong) { @@ -1441,6 +1441,9 @@ xirc2ps_interrupt(int irq, void *dev_id, struct pt_regs *regs) lp->stats.rx_fifo_errors++; /* okay ? */ DEBUG(3, "%s: Alignment error\n", dev->name); } + + /* clear the received/dropped/error packet */ + PutWord(XIRCREG0_DO, 0x8000); /* issue cmd: skip_rx_packet */ /* get the new ethernet status */ eth_status = GetByte(XIRCREG_ESR); diff --git a/drivers/net/pcmcia/xircom_tulip_cb.c b/drivers/net/pcmcia/xircom_tulip_cb.c index 2839dbbe7..911ab5770 100644 --- a/drivers/net/pcmcia/xircom_tulip_cb.c +++ b/drivers/net/pcmcia/xircom_tulip_cb.c @@ -503,10 +503,11 @@ static void outl_CSR6 (u32 newcsr6, long ioaddr, int chip_idx) } static struct net_device *tulip_probe1(struct pci_dev *pdev, - struct net_device *dev, long ioaddr, int irq, + long ioaddr, int irq, int chip_idx, int board_idx) { static int did_version; /* Already printed version info. */ + struct net_device *dev; struct tulip_private *tp; /* See note below on the multiport cards. */ static unsigned char last_phys_addr[6] = {0x00, 'L', 'i', 'n', 'u', 'x'}; @@ -519,7 +520,9 @@ static struct net_device *tulip_probe1(struct pci_dev *pdev, if (tulip_debug > 0 && did_version++ == 0) printk(KERN_INFO "%s", version); - dev = init_etherdev(dev, 0); + dev = alloc_etherdev(0); + if (!dev) + return NULL; pci_read_config_byte(pdev, PCI_REVISION_ID, &chip_rev); /* Bring the 21143 out of sleep mode. @@ -527,23 +530,11 @@ static struct net_device *tulip_probe1(struct pci_dev *pdev, if (tulip_tbl[chip_idx].flags & HAS_ACPI) pci_write_config_dword(pdev, 0x40, 0x00000000); - printk(KERN_INFO "%s: %s rev %d at %#3lx,", - dev->name, tulip_tbl[chip_idx].chip_name, chip_rev, ioaddr); - /* Stop the chip's Tx and Rx processes. */ outl_CSR6(inl(ioaddr + CSR6) & ~0x2002, ioaddr, chip_idx); /* Clear the missed-packet counter. */ (volatile int)inl(ioaddr + CSR8); - if (chip_idx == DC21041) { - if (inl(ioaddr + CSR9) & 0x8000) { - printk(" 21040 compatible mode,"); - chip_idx = DC21040; - } else { - printk(" 21041 mode,"); - } - } - /* The station address ROM is read byte serially. The register must be polled, waiting for the value to be read bit serially from the EEPROM. @@ -661,14 +652,10 @@ static struct net_device *tulip_probe1(struct pci_dev *pdev, #endif } - for (i = 0; i < 6; i++) - printk("%c%2.2X", i ? ':' : ' ', last_phys_addr[i] = dev->dev_addr[i]); - printk(", IRQ %d.\n", irq); last_irq = irq; /* We do a request_region() only to register /proc/ioports info. */ - /* Note that proper size is tulip_tbl[chip_idx].chip_name, but... */ - request_region(ioaddr, tulip_tbl[chip_idx].io_size, dev->name); + request_region(ioaddr, tulip_tbl[chip_idx].io_size, "xircom_tulip_cb"); dev->base_addr = ioaddr; dev->irq = irq; @@ -693,17 +680,6 @@ static struct net_device *tulip_probe1(struct pci_dev *pdev, else if (chip_idx == AX88140) tp->csr0 |= 0x2000; -#ifdef TULIP_FULL_DUPLEX - tp->full_duplex = 1; - tp->full_duplex_lock = 1; -#endif -#ifdef TULIP_DEFAULT_MEDIA - tp->default_port = TULIP_DEFAULT_MEDIA; -#endif -#ifdef TULIP_NO_MEDIA_SWITCH - tp->medialock = 1; -#endif - /* The lower four bits are the media type. */ if (board_idx >= 0 && board_idx < MAX_UNITS) { tp->default_port = options[board_idx] & 15; @@ -759,14 +735,14 @@ static struct net_device *tulip_probe1(struct pci_dev *pdev, int reg4 = ((mii_status>>6) & tp->to_advertise) | 1; tp->phys[phy_idx] = phy; tp->advertising[phy_idx++] = reg4; - printk(KERN_INFO "%s: MII transceiver #%d " + printk(KERN_INFO "xircom(%s): MII transceiver #%d " "config %4.4x status %4.4x advertising %4.4x.\n", - dev->name, phy, mii_reg0, mii_status, mii_advert); + pdev->slot_name, phy, mii_reg0, mii_status, mii_advert); /* Fixup for DLink with miswired PHY. */ if (mii_advert != reg4) { - printk(KERN_DEBUG "%s: Advertising %4.4x on PHY %d," + printk(KERN_DEBUG "xircom(%s): Advertising %4.4x on PHY %d," " previously advertising %4.4x.\n", - dev->name, reg4, phy, mii_advert); + pdev->slot_name, reg4, phy, mii_advert); mdio_write(dev, phy, 4, reg4); } /* Enable autonegotiation: some boards default to off. */ @@ -777,8 +753,8 @@ static struct net_device *tulip_probe1(struct pci_dev *pdev, } tp->mii_cnt = phy_idx; if (tp->mtable && tp->mtable->has_mii && phy_idx == 0) { - printk(KERN_INFO "%s: ***WARNING***: No MII transceiver found!\n", - dev->name); + printk(KERN_INFO "xircom(%s): ***WARNING***: No MII transceiver found!\n", + pdev->slot_name); tp->phys[0] = 1; } } @@ -799,37 +775,10 @@ static struct net_device *tulip_probe1(struct pci_dev *pdev, /* Reset the xcvr interface and turn on heartbeat. */ switch (chip_idx) { - case DC21041: - outl(0x00000000, ioaddr + CSR13); - outl(0xFFFFFFFF, ioaddr + CSR14); - outl(0x00000008, ioaddr + CSR15); /* Listen on AUI also. */ - outl_CSR6(inl(ioaddr + CSR6) | 0x0200, ioaddr, chip_idx); - outl(0x0000EF05, ioaddr + CSR13); - break; - case DC21040: - outl(0x00000000, ioaddr + CSR13); - outl(0x00000004, ioaddr + CSR13); - break; case DC21140: default: if (tp->mtable) outl(tp->mtable->csr12dir | 0x100, ioaddr + CSR12); break; - case DC21142: - case PNIC2: - if (tp->mii_cnt || media_cap[dev->if_port] & MediaIsMII) { - outl_CSR6(0x82020000, ioaddr, chip_idx); - outl(0x0000, ioaddr + CSR13); - outl(0x0000, ioaddr + CSR14); - outl_CSR6(0x820E0000, ioaddr, chip_idx); - } else { - outl_CSR6(0x82420200, ioaddr, chip_idx); - outl(0x0001, ioaddr + CSR13); - outl(0x0003FFFF, ioaddr + CSR14); - outl(0x0008, ioaddr + CSR15); - outl(0x0001, ioaddr + CSR13); - outl(0x1301, ioaddr + CSR12); /* Start NWay. */ - } - break; case X3201_3: outl(0x0008, ioaddr + CSR15); udelay(5); /* The delays are Xircom recommended to give the @@ -842,29 +791,24 @@ static struct net_device *tulip_probe1(struct pci_dev *pdev, udelay(5); outl_CSR6(0x32000200, ioaddr, chip_idx); break; - case LC82C168: - if ( ! tp->mii_cnt) { - outl_CSR6(0x00420000, ioaddr, chip_idx); - outl(0x30, ioaddr + CSR12); - outl(0x0001F078, ioaddr + 0xB8); - outl(0x0201F078, ioaddr + 0xB8); /* Turn on autonegotiation. */ - } - break; - case MX98713: case COMPEX9881: - outl_CSR6(0x00000000, ioaddr, chip_idx); - outl(0x000711C0, ioaddr + CSR14); /* Turn on NWay. */ - outl(0x00000001, ioaddr + CSR13); - break; - case MX98715: case MX98725: - outl_CSR6(0x01a80000, ioaddr, chip_idx); - outl(0xFFFFFFFF, ioaddr + CSR14); - outl(0x00001000, ioaddr + CSR12); - break; - case COMET: - /* No initialization necessary. */ - break; } + if (register_netdev(dev)) { + request_region(ioaddr, tulip_tbl[chip_idx].io_size, "xircom_tulip_cb"); + if (tp->mtable) + kfree(tp->mtable); + kfree(dev->priv); + kfree(dev); + return NULL; + } + + printk(KERN_INFO "%s: %s rev %d at %#3lx,", + dev->name, tulip_tbl[chip_idx].chip_name, chip_rev, ioaddr); + for (i = 0; i < 6; i++) + printk("%c%2.2X", i ? ':' : ' ', + last_phys_addr[i] = dev->dev_addr[i]); + printk(", IRQ %d.\n", irq); + return dev; } @@ -1347,11 +1291,11 @@ tulip_up(struct net_device *dev) } /* Put the setup frame on the Tx list. */ - tp->tx_ring[0].length = 0x08000000 | 192; + tp->tx_ring[tp->cur_tx].length = 0x08000000 | 192; /* Lie about the address of our setup frame to make the */ /* chip happy */ - tp->tx_ring[0].buffer1 = virt_to_bus(tp->setup_frame); - tp->tx_ring[0].status = DescOwned; + tp->tx_ring[tp->cur_tx].buffer1 = virt_to_bus(tp->setup_frame); + tp->tx_ring[tp->cur_tx].status = DescOwned; tp->cur_tx++; } @@ -2388,7 +2332,7 @@ static void tulip_init_ring(struct net_device *dev) #ifdef CARDBUS if (tp->chip_id == X3201_3) tp->tx_aligned_skbuff[i] = dev_alloc_skb(PKT_BUF_SZ); -#endif CARDBUS +#endif /* CARDBUS */ } tp->tx_ring[i-1].buffer2 = virt_to_bus(&tp->tx_ring[0]); } @@ -3081,8 +3025,7 @@ static int __devinit tulip_pci_probe(struct pci_dev *pdev, const struct pci_devi if (pci_enable_device (pdev)) return -ENODEV; pci_set_master (pdev); - dev = tulip_probe1(pdev, NULL, - pci_resource_start (pdev, 0), pdev->irq, + dev = tulip_probe1(pdev, pci_resource_start (pdev, 0), pdev->irq, id->driver_data, board_idx++); if (dev) { pdev->driver_data = dev; diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 33139b17b..c2c1e4404 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -490,6 +490,12 @@ pcnet32_probe_pci(struct pci_dev *pdev, const struct pci_device_id *ent) printk(KERN_INFO "pcnet32_probe_pci: found device %#08x.%#08x\n", ent->vendor, ent->device); + if ((err = pci_enable_device(pdev)) < 0) { + printk(KERN_ERR "pcnet32.c: failed to enable device -- err=%d\n", err); + return err; + } + pci_set_master(pdev); + ioaddr = pci_resource_start (pdev, 0); printk(KERN_INFO " ioaddr=%#08lx resource_flags=%#08lx\n", ioaddr, pci_resource_flags (pdev, 0)); if (!ioaddr) { @@ -502,13 +508,6 @@ pcnet32_probe_pci(struct pci_dev *pdev, const struct pci_device_id *ent) return -ENODEV; } - if ((err = pci_enable_device(pdev)) < 0) { - printk(KERN_ERR "pcnet32.c: failed to enable device -- err=%d\n", err); - return err; - } - - pci_set_master(pdev); - return pcnet32_probe1(ioaddr, pdev->irq, 1, card_idx, pdev); } @@ -634,10 +633,35 @@ pcnet32_probe1(unsigned long ioaddr, unsigned char irq_line, int shared, int car printk(KERN_INFO "%s: %s at %#3lx,", dev->name, chipname, ioaddr); - /* There is a 16 byte station address PROM at the base address. - The first six bytes are the station address. */ + /* In most chips, after a chip reset, the ethernet address is read from the + * station address PROM at the base address and programmed into the + * "Physical Address Registers" CSR12-14. + * As a precautionary measure, we read the PROM values and complain if + * they disagree with the CSRs. Either way, we use the CSR values, and + * double check that they are valid. + */ + for (i = 0; i < 3; i++) { + unsigned int val; + val = a->read_csr(ioaddr, i+12) & 0x0ffff; + /* There may be endianness issues here. */ + dev->dev_addr[2*i] = val & 0x0ff; + dev->dev_addr[2*i+1] = (val >> 8) & 0x0ff; + } + { + u8 promaddr[6]; + for (i = 0; i < 6; i++) { + promaddr[i] = inb(ioaddr + i); + } + if( memcmp( promaddr, dev->dev_addr, 6) ) + printk(" warning: PROM address does not match CSR address"); + } + /* if the ethernet address is not valid, force to 00:00:00:00:00:00 */ + if( !is_valid_ether_addr(dev->dev_addr) ) + for (i = 0; i < 6; i++) + dev->dev_addr[i]=0; + for (i = 0; i < 6; i++) - printk(" %2.2x", dev->dev_addr[i] = inb(ioaddr + i)); + printk(" %2.2x", dev->dev_addr[i] ); if (((chip_version + 1) & 0xfffe) == 0x2624) { /* Version 0x2623 or 0x2624 */ i = a->read_csr(ioaddr, 80) & 0x0C00; /* Check tx_start_pt */ @@ -666,7 +690,7 @@ pcnet32_probe1(unsigned long ioaddr, unsigned char irq_line, int shared, int car request_region(ioaddr, PCNET32_TOTAL_SIZE, chipname); /* pci_alloc_consistent returns page-aligned memory, so we do not have to check the alignment */ - if ((lp = (struct pcnet32_private *)pci_alloc_consistent(pdev, sizeof(*lp), &lp_dma_addr)) == NULL) + if ((lp = pci_alloc_consistent(pdev, sizeof(*lp), &lp_dma_addr)) == NULL) return -ENOMEM; memset(lp, 0, sizeof(*lp)); @@ -774,7 +798,7 @@ pcnet32_probe1(unsigned long ioaddr, unsigned char irq_line, int shared, int car static int pcnet32_open(struct net_device *dev) { - struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; + struct pcnet32_private *lp = dev->priv; unsigned long ioaddr = dev->base_addr; u16 val; int i; @@ -785,6 +809,10 @@ pcnet32_open(struct net_device *dev) return -EAGAIN; } + /* Check for a valid station address */ + if( !is_valid_ether_addr(dev->dev_addr) ) + return -EINVAL; + /* Reset the PCNET32 */ lp->a.reset (ioaddr); @@ -828,6 +856,12 @@ pcnet32_open(struct net_device *dev) if (lp->options & PORT_100) val |= 0x08; lp->a.write_bcr (ioaddr, 32, val); + } else { + if (lp->options & PORT_ASEL) { /* enable auto negotiate, setup, disable fd */ + val = lp->a.read_bcr(ioaddr, 32) & ~0x98; + val |= 0x20; + lp->a.write_bcr(ioaddr, 32, val); + } } #ifdef DO_DXSUFLO @@ -895,7 +929,7 @@ pcnet32_open(struct net_device *dev) static void pcnet32_purge_tx_ring(struct net_device *dev) { - struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; + struct pcnet32_private *lp = dev->priv; int i; for (i = 0; i < TX_RING_SIZE; i++) { @@ -913,7 +947,7 @@ pcnet32_purge_tx_ring(struct net_device *dev) static int pcnet32_init_ring(struct net_device *dev) { - struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; + struct pcnet32_private *lp = dev->priv; int i; lp->tx_full = 0; @@ -954,7 +988,7 @@ pcnet32_init_ring(struct net_device *dev) static void pcnet32_restart(struct net_device *dev, unsigned int csr0_bits) { - struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; + struct pcnet32_private *lp = dev->priv; unsigned long ioaddr = dev->base_addr; int i; @@ -976,7 +1010,7 @@ pcnet32_restart(struct net_device *dev, unsigned int csr0_bits) static void pcnet32_tx_timeout (struct net_device *dev) { - struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; + struct pcnet32_private *lp = dev->priv; unsigned int ioaddr = dev->base_addr; /* Transmitter timeout, serious problems. */ @@ -1009,7 +1043,7 @@ pcnet32_tx_timeout (struct net_device *dev) static int pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; + struct pcnet32_private *lp = dev->priv; unsigned int ioaddr = dev->base_addr; u16 status; int entry; @@ -1077,7 +1111,7 @@ pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev) static void pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs) { - struct net_device *dev = (struct net_device *)dev_id; + struct net_device *dev = dev_id; struct pcnet32_private *lp; unsigned long ioaddr; u16 csr0,rap; @@ -1090,7 +1124,7 @@ pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs) } ioaddr = dev->base_addr; - lp = (struct pcnet32_private *)dev->priv; + lp = dev->priv; spin_lock(&lp->lock); @@ -1223,7 +1257,7 @@ pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs) static int pcnet32_rx(struct net_device *dev) { - struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; + struct pcnet32_private *lp = dev->priv; int entry = lp->cur_rx & RX_RING_MOD_MASK; /* If we own the next entry, it's a new packet. Send it up. */ @@ -1317,7 +1351,7 @@ static int pcnet32_close(struct net_device *dev) { unsigned long ioaddr = dev->base_addr; - struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; + struct pcnet32_private *lp = dev->priv; int i; netif_stop_queue(dev); @@ -1367,7 +1401,7 @@ pcnet32_close(struct net_device *dev) static struct net_device_stats * pcnet32_get_stats(struct net_device *dev) { - struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; + struct pcnet32_private *lp = dev->priv; unsigned long ioaddr = dev->base_addr; u16 saved_addr; unsigned long flags; @@ -1384,7 +1418,7 @@ pcnet32_get_stats(struct net_device *dev) /* taken from the sunlance driver, which it took from the depca driver */ static void pcnet32_load_multicast (struct net_device *dev) { - struct pcnet32_private *lp = (struct pcnet32_private *) dev->priv; + struct pcnet32_private *lp = dev->priv; volatile struct pcnet32_init_block *ib = &lp->init_block; volatile u16 *mcast_table = (u16 *)&ib->filter; struct dev_mc_list *dmi=dev->mc_list; @@ -1437,7 +1471,7 @@ static void pcnet32_load_multicast (struct net_device *dev) static void pcnet32_set_multicast_list(struct net_device *dev) { unsigned long ioaddr = dev->base_addr; - struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; + struct pcnet32_private *lp = dev->priv; if (dev->flags&IFF_PROMISC) { /* Log any net taps. */ @@ -1457,7 +1491,7 @@ static void pcnet32_set_multicast_list(struct net_device *dev) static int pcnet32_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { unsigned long ioaddr = dev->base_addr; - struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; + struct pcnet32_private *lp = dev->priv; u16 *data = (u16 *)&rq->ifr_data; int phyaddr = lp->a.read_bcr (ioaddr, 33); @@ -1546,7 +1580,7 @@ static void __exit pcnet32_cleanup_module(void) /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ while (pcnet32_dev) { - struct pcnet32_private *lp = (struct pcnet32_private *) pcnet32_dev->priv; + struct pcnet32_private *lp = pcnet32_dev->priv; next_dev = lp->next; unregister_netdev(pcnet32_dev); release_region(pcnet32_dev->base_addr, PCNET32_TOTAL_SIZE); diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c index 9897dfe40..490a40258 100644 --- a/drivers/net/pppoe.c +++ b/drivers/net/pppoe.c @@ -737,7 +737,7 @@ int pppoe_ioctl(struct socket *sock, unsigned int cmd, err = 0; break; - default: + default:; }; return err; diff --git a/drivers/net/rclanmtl.h b/drivers/net/rclanmtl.h index 36408cb77..61d1a9cb2 100644 --- a/drivers/net/rclanmtl.h +++ b/drivers/net/rclanmtl.h @@ -97,7 +97,7 @@ typedef void (*PFNWAITCALLBACK)(void); /* void argument avoids compiler complai typedef void (*PFNTXCALLBACK)(U32 Status, U16 PcktCount, PU32 BufferContext, - U16 AdaterID); + struct net_device *); /* ** type PFNRXCALLBACK @@ -445,7 +445,7 @@ void RCProcI2OMsgQ(struct net_device *dev); /* ** Disable and Enable I2O interrupts. I2O interrupts are enabled at Init time ** but can be disabled and re-enabled through these two function calls. - ** Packets will still be put into any posted recieved buffers and packets will + ** Packets will still be put into any posted received buffers and packets will ** be sent through RCI2OSendPacket() functions. Disabling I2O interrupts ** will prevent hardware interrupt to host even though the outbound I2O msg ** queue is not emtpy. diff --git a/drivers/net/rcpci45.c b/drivers/net/rcpci45.c index 1e92de817..00525064a 100644 --- a/drivers/net/rcpci45.c +++ b/drivers/net/rcpci45.c @@ -119,7 +119,7 @@ MODULE_DEVICE_TABLE(pci, rcpci45_pci_table); static void __exit rcpci45_remove_one(struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; + struct net_device *dev = pci_get_drvdata(pdev); PDPA pDpa = dev->priv; if (!dev) { @@ -134,10 +134,12 @@ static void __exit rcpci45_remove_one(struct pci_dev *pdev) unregister_netdev(dev); free_irq(dev->irq, dev); iounmap((void *)dev->base_addr); + pci_release_regions(pdev); kfree(pDpa->PLanApiPA); kfree(pDpa->pPab); kfree(pDpa); kfree(dev); + pci_set_drvdata(pdev, NULL); } static int RCinit(struct net_device *dev) @@ -156,12 +158,10 @@ static int rcpci45_init_one(struct pci_dev *pdev, { unsigned long *vaddr; PDPA pDpa; - int error = -ENOMEM; + int error; static int card_idx = -1; struct net_device *dev; - unsigned long pci_start = pci_resource_start(pdev,0); - unsigned long pci_len = pci_resource_len(pdev,0); - + unsigned long pci_start, pci_len; card_idx++; @@ -177,10 +177,20 @@ static int rcpci45_init_one(struct pci_dev *pdev, dev = init_etherdev(NULL, sizeof(*pDpa)); if (!dev) { printk(KERN_ERR "(rcpci45 driver:) unable to allocate in init_etherdev\n"); + error = -ENOMEM; + goto err_out; + } + + error = pci_enable_device(pdev); + if (error) { + printk(KERN_ERR "(rcpci45 driver:) %d: unable to enable pci device, aborting\n",card_idx); goto err_out; } + error = -ENOMEM; + pci_start = pci_resource_start(pdev,0); + pci_len = pci_resource_len(pdev,0); - pdev->driver_data = dev; + pci_set_drvdata(pdev, dev); pDpa = dev->priv; pDpa->id = card_idx; @@ -188,6 +198,7 @@ static int rcpci45_init_one(struct pci_dev *pdev, if (!pci_start || !(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { printk(KERN_ERR "(rcpci45 driver:) No PCI memory resources! Aborting.\n"); + error = -EBUSY; goto err_out_free_dev; } @@ -214,20 +225,14 @@ static int rcpci45_init_one(struct pci_dev *pdev, * I/O read/write. Thus, we need to map it to some virtual address * area in order to access the registers as normal memory. */ - if (request_mem_region(pci_start, pci_len, dev->name) == NULL) { - printk(KERN_ERR "(rcpci45 driver:) %d: resource 0x%lx @ 0x%lx busy, aborting\n",card_idx, pci_start, pci_len); - goto err_out_free_msgbuf; - } - - if (pci_enable_device(pdev)) { - printk(KERN_ERR "(rcpci45 driver:) %d: unable to enable pci device, aborting\n",card_idx); - goto err_out_free_msgbuf; - } + error = pci_request_regions(pdev, dev->name); + if (error) + goto err_out_free_msgbuf; vaddr = (ulong *) ioremap (pci_start, pci_len); if (!vaddr) { printk(KERN_ERR "(rcpci45 driver:) Unable to remap address range from %lu to %lu\n", pci_start, pci_start+pci_len); - goto err_out_free_msgbuf; + goto err_out_free_region; } dprintk("rcpci45_init_one: 0x%x, priv = 0x%x, vaddr = 0x%x\n", @@ -239,13 +244,14 @@ static int rcpci45_init_one(struct pci_dev *pdev, return 0; /* success */ - + err_out_free_region: + pci_release_regions(pdev); err_out_free_msgbuf: kfree(pDpa->msgbuf); err_out_free_dev: + unregister_netdev(dev); kfree(dev); err_out: - unregister_netdev(dev); card_idx--; return error; } @@ -270,7 +276,7 @@ static int RCopen(struct net_device *dev) { int post_buffers = MAX_NMBR_RCV_BUFFERS; - PDPA pDpa = (PDPA) dev->priv; + PDPA pDpa = dev->priv; int count = 0; int requested = 0; int error; @@ -278,8 +284,8 @@ RCopen(struct net_device *dev) dprintk("(rcpci45 driver:) RCopen\n"); /* Request a shared interrupt line. */ - if ( (error=request_irq(dev->irq, (void *)RCinterrupt, - SA_INTERRUPT|SA_SHIRQ, "RedCreek VPN Adapter", dev)) ) { + error=request_irq(dev->irq, RCinterrupt, SA_SHIRQ, dev->name, dev); + if (error) { printk(KERN_ERR "(rcpci45 driver:) %s: unable to get IRQ %d\n", dev->name, dev->irq ); goto err_out; } @@ -361,7 +367,7 @@ static int RC_xmit_packet(struct sk_buff *skb, struct net_device *dev) { - PDPA pDpa = (PDPA) dev->priv; + PDPA pDpa = dev->priv; singleTCB tcb; psingleTCB ptcb = &tcb; RC_RETURN status = 0; @@ -384,7 +390,7 @@ RC_xmit_packet(struct sk_buff *skb, struct net_device *dev) /* * we'll get the context when the adapter interrupts us to tell us that - * the transmision is done. At that time, we can free skb. + * the transmission is done. At that time, we can free skb. */ ptcb->b.context = (U32)skb; ptcb->b.scount = 1; @@ -662,9 +668,9 @@ RCinterrupt(int irq, void *dev_id, struct pt_regs *regs) { PDPA pDpa; - struct net_device *dev = (struct net_device *)(dev_id); + struct net_device *dev = dev_id; - pDpa = (PDPA) (dev->priv); + pDpa = dev->priv; if (pDpa->shutdown) dprintk("shutdown: service irq\n"); @@ -681,7 +687,7 @@ RCinterrupt(int irq, void *dev_id, struct pt_regs *regs) static void rc_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; - PDPA pDpa = (PDPA) (dev->priv); + PDPA pDpa = dev->priv; int init_status; static int retry; int post_buffers = MAX_NMBR_RCV_BUFFERS; @@ -760,7 +766,7 @@ static void rc_timer(unsigned long data) static int RCclose(struct net_device *dev) { - PDPA pDpa = (PDPA) dev->priv; + PDPA pDpa = dev->priv; netif_stop_queue(dev); diff --git a/drivers/net/rtl8129.c b/drivers/net/rtl8129.c deleted file mode 100644 index 028044b8a..000000000 --- a/drivers/net/rtl8129.c +++ /dev/null @@ -1,1483 +0,0 @@ -/* rtl8129.c: A RealTek RTL8129 Fast Ethernet driver for Linux. */ -/* - Written 1997-1999 by Donald Becker. - - This software may be used and distributed according to the terms - of the GNU Public License, incorporated herein by reference. - All other rights reserved. - - This driver is for boards based on the RTL8129 PCI ethernet chip. - - 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 - - Support and updates available at - http://cesdis.gsfc.nasa.gov/linux/drivers/rtl8139.html - - Twister-tuning table provided by Kinston <shangh@realtek.com.tw>. -*/ - -static const char *version = -"rtl8129.c:v1.07 5/6/99 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/rtl8139.html\n"; - -/* A few user-configurable values. */ -/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ -static int max_interrupt_work = 20; -#define rtl8129_debug debug -static int rtl8129_debug = 1; - -/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). - The RTL chips use a 64 element hash table based on the Ethernet CRC. */ -static int multicast_filter_limit = 32; - -/* Used to pass the full-duplex flag, etc. */ -#define MAX_UNITS 8 /* More are supported, limit only on options */ -static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; -static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; - -/* Size of the in-memory receive ring. */ -#define RX_BUF_LEN_IDX 3 /* 0==8K, 1==16K, 2==32K, 3==64K */ -#define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX) -/* Size of the Tx bounce buffers -- must be at least (dev->mtu+14+4). */ -#define TX_BUF_SIZE 1536 - -/* PCI Tuning Parameters - Threshold is bytes transferred to chip before transmission starts. */ -#define TX_FIFO_THRESH 256 /* In bytes, rounded down to 32 byte units. */ - -/* The following settings are log_2(bytes)-4: 0 == 16 bytes .. 6==1024. */ -#define RX_FIFO_THRESH 4 /* Rx buffer level before first PCI xfer. */ -#define RX_DMA_BURST 4 /* Maximum PCI burst, '4' is 256 bytes */ -#define TX_DMA_BURST 4 /* Calculate as 16<<val. */ - -/* Operational parameters that usually are not changed. */ -/* Time in jiffies before concluding the transmitter is hung. */ -#define TX_TIMEOUT (4*HZ) - -#include <linux/module.h> -#include <linux/version.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/string.h> -#include <linux/timer.h> -#include <linux/errno.h> -#include <linux/ioport.h> -#include <linux/malloc.h> -#include <linux/interrupt.h> -#include <linux/init.h> -#include <linux/pci.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/skbuff.h> -#include <asm/processor.h> /* Processor type for cache alignment. */ -#include <asm/bitops.h> -#include <asm/io.h> - -/* Kernel compatibility defines, some common to David Hind's PCMCIA package. - This is only in the support-all-kernels source code. */ - -#define RUN_AT(x) (jiffies + (x)) - -#include <linux/delay.h> - -#if LINUX_VERSION_CODE < 0x20123 -#define test_and_set_bit(val, addr) set_bit(val, addr) -#endif -#if LINUX_VERSION_CODE <= 0x20139 -#define net_device_stats enet_statistics -#else -#define NETSTATS_VER2 -#endif -#if LINUX_VERSION_CODE < 0x20155 || defined(CARDBUS) -/* Grrrr, the PCI code changed, but did not consider CardBus... */ -#include <linux/bios32.h> -#define PCI_SUPPORT_VER1 -#else -#define PCI_SUPPORT_VER2 -#endif - -/* The I/O extent. */ -#define RTL8129_TOTAL_SIZE 0x80 - -/* - Theory of Operation - -I. Board Compatibility - -This device driver is designed for the RealTek RTL8129, the RealTek Fast -Ethernet controllers for PCI. This chip is used on a few clone boards. - - -II. Board-specific settings - -PCI bus devices are configured by the system at boot time, so no jumpers -need to be set on the board. The system BIOS will assign the -PCI INTA signal to a (preferably otherwise unused) system IRQ line. -Note: Kernel versions earlier than 1.3.73 do not support shared PCI -interrupt lines. - -III. Driver operation - -IIIa. Rx Ring buffers - -The receive unit uses a single linear ring buffer rather than the more -common (and more efficient) descriptor-based architecture. Incoming frames -are sequentially stored into the Rx region, and the host copies them into -skbuffs. - -Comment: While it is theoretically possible to process many frames in place, -any delay in Rx processing would cause us to drop frames. More importantly, -the Linux protocol stack is not designed to operate in this manner. - -IIIb. Tx operation - -The RTL8129 uses a fixed set of four Tx descriptors in register space. -In a stunningly bad design choice, Tx frames must be 32 bit aligned. Linux -aligns the IP header on word boundaries, and 14 byte ethernet header means -that almost all frames will need to be copied to an alignment buffer. - -IVb. References - -http://www.realtek.com.tw/cn/cn.html -http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html - -IVc. Errata - -*/ - - -/* This table drives the PCI probe routines. It's mostly boilerplate in all - of the drivers, and will likely be provided by some future kernel. - Note the matching code -- the first table entry matchs all 56** cards but - second only the 1234 card. -*/ -enum pci_flags_bit { - PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4, - PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3, -}; -struct pci_id_info { - const char *name; - u16 vendor_id, device_id, device_id_mask, flags; - int io_size; - struct net_device *(*probe1)(struct pci_dev *pdev, int pci_bus, int pci_devfn, long ioaddr, int irq, int chip_idx, int fnd_cnt); -}; - -static struct net_device * rtl8129_probe1(struct pci_dev *pdev, int pci_bus, - int pci_devfn, long ioaddr, - int irq, int chp_idx, int fnd_cnt); - -static struct pci_id_info pci_tbl[] = -{{ "RealTek RTL8129 Fast Ethernet", - 0x10ec, 0x8129, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1}, -#ifdef USE_8139_SUPPORT_ALSO - { "RealTek RTL8139 Fast Ethernet", - 0x10ec, 0x8139, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1}, - { "SMC1211TX EZCard 10/100 (RealTek RTL8139)", - 0x1113, 0x1211, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1}, - { "Accton MPX5030 (RealTek RTL8139)", - 0x1113, 0x1211, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1}, -#endif - {0,}, /* 0 terminated list. */ -}; - -/* The capability table matches the chip table above. */ -enum {HAS_MII_XCVR=0x01, HAS_CHIP_XCVR=0x02, HAS_LNK_CHNG=0x04}; -static int rtl_cap_tbl[] = { - HAS_MII_XCVR, HAS_CHIP_XCVR|HAS_LNK_CHNG, HAS_CHIP_XCVR|HAS_LNK_CHNG, -}; - - -/* The rest of these values should never change. */ -#define NUM_TX_DESC 4 /* Number of Tx descriptor registers. */ - -/* Symbolic offsets to registers. */ -enum RTL8129_registers { - MAC0=0, /* Ethernet hardware address. */ - MAR0=8, /* Multicast filter. */ - TxStatus0=0x10, /* Transmit status (Four 32bit registers). */ - TxAddr0=0x20, /* Tx descriptors (also four 32bit). */ - RxBuf=0x30, RxEarlyCnt=0x34, RxEarlyStatus=0x36, - ChipCmd=0x37, RxBufPtr=0x38, RxBufAddr=0x3A, - IntrMask=0x3C, IntrStatus=0x3E, - TxConfig=0x40, RxConfig=0x44, - Timer=0x48, /* A general-purpose counter. */ - RxMissed=0x4C, /* 24 bits valid, write clears. */ - Cfg9346=0x50, Config0=0x51, Config1=0x52, - FlashReg=0x54, GPPinData=0x58, GPPinDir=0x59, MII_SMI=0x5A, HltClk=0x5B, - MultiIntr=0x5C, TxSummary=0x60, - MII_BMCR=0x62, MII_BMSR=0x64, NWayAdvert=0x66, NWayLPAR=0x68, - NWayExpansion=0x6A, - /* Undocumented registers, but required for proper operation. */ - FIFOTMS=0x70, /* FIFO Test Mode Select */ - CSCR=0x74, /* Chip Status and Configuration Register. */ - PARA78=0x78, PARA7c=0x7c, /* Magic transceiver parameter register. */ -}; - -enum ChipCmdBits { - CmdReset=0x10, CmdRxEnb=0x08, CmdTxEnb=0x04, RxBufEmpty=0x01, }; - -/* Interrupt register bits, using my own meaningful names. */ -enum IntrStatusBits { - PCIErr=0x8000, PCSTimeout=0x4000, - RxFIFOOver=0x40, RxUnderrun=0x20, RxOverflow=0x10, - TxErr=0x08, TxOK=0x04, RxErr=0x02, RxOK=0x01, -}; -enum TxStatusBits { - TxHostOwns=0x2000, TxUnderrun=0x4000, TxStatOK=0x8000, - TxOutOfWindow=0x20000000, TxAborted=0x40000000, TxCarrierLost=0x80000000, -}; -enum RxStatusBits { - RxMulticast=0x8000, RxPhysical=0x4000, RxBroadcast=0x2000, - RxBadSymbol=0x0020, RxRunt=0x0010, RxTooLong=0x0008, RxCRCErr=0x0004, - RxBadAlign=0x0002, RxStatusOK=0x0001, -}; - -/* Twister tuning parameters from RealTek. - Completely undocumented, but required to tune bad links. */ -enum CSCRBits { - CSCR_LinkOKBit=0x0400, CSCR_LinkChangeBit=0x0800, - CSCR_LinkStatusBits=0x0f000, CSCR_LinkDownOffCmd=0x003c0, - CSCR_LinkDownCmd=0x0f3c0, -}; -static const unsigned long param[4][4]={ - {0x0cb39de43,0x0cb39ce43,0x0fb38de03,0x0cb38de43}, - {0x0cb39de43,0x0cb39ce43,0x0cb39ce83,0x0cb39ce83}, - {0x0cb39de43,0x0cb39ce43,0x0cb39ce83,0x0cb39ce83}, - {0x0bb39de43,0x0bb39ce43,0x0bb39ce83,0x0bb39ce83} -}; - -struct ring_info { - struct sk_buff *skb; - dma_addr_t mapping; -}; - -struct rtl8129_private { - char devname[8]; /* Used only for kernel debugging. */ - const char *product_name; - struct net_device *next_module; - struct pci_dev *pdev; - int chip_id; - int chip_revision; - unsigned char pci_bus, pci_devfn; - struct net_device_stats stats; - struct timer_list timer; /* Media selection timer. */ - unsigned int cur_rx; /* Index into the Rx buffer of next Rx pkt. */ - unsigned int cur_tx, dirty_tx, tx_flag; - /* The saved address of a sent-in-place packet/buffer, for skfree(). */ - struct ring_info tx_info[NUM_TX_DESC]; - unsigned char *tx_buf[NUM_TX_DESC]; /* Tx bounce buffers */ - unsigned char *rx_ring; - unsigned char *tx_bufs; /* Tx bounce buffer region. */ - dma_addr_t rx_ring_dma; - dma_addr_t tx_bufs_dma; - char phys[4]; /* MII device addresses. */ - char twistie, twist_cnt; /* Twister tune state. */ - unsigned int tx_full:1; /* The Tx queue is full. */ - unsigned int full_duplex:1; /* Full-duplex operation requested. */ - unsigned int duplex_lock:1; - unsigned int default_port:4; /* Last dev->if_port value. */ - unsigned int media2:4; /* Secondary monitored media port. */ - unsigned int medialock:1; /* Don't sense media type. */ - unsigned int mediasense:1; /* Media sensing in progress. */ -}; - -MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>"); -MODULE_DESCRIPTION("RealTek RTL8129 Fast Ethernet driver"); -MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); -MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); -MODULE_PARM(multicast_filter_limit, "i"); -MODULE_PARM(max_interrupt_work, "i"); -MODULE_PARM(debug, "i"); - -static int rtl8129_open(struct net_device *dev); -static int read_eeprom(long ioaddr, int location); -static int mdio_read(struct net_device *dev, int phy_id, int location); -static void mdio_write(struct net_device *dev, int phy_id, int location, int val); -static void rtl8129_timer(unsigned long data); -static void rtl8129_tx_timeout(struct net_device *dev); -static void rtl8129_init_ring(struct net_device *dev); -static int rtl8129_start_xmit(struct sk_buff *skb, struct net_device *dev); -static int rtl8129_rx(struct net_device *dev); -static void rtl8129_interrupt(int irq, void *dev_instance, struct pt_regs *regs); -static int rtl8129_close(struct net_device *dev); -static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -static struct net_device_stats *rtl8129_get_stats(struct net_device *dev); -static inline u32 ether_crc(int length, unsigned char *data); -static void set_rx_mode(struct net_device *dev); - - -/* A list of all installed RTL8129 devices, for removing the driver module. */ -static struct net_device *root_rtl8129_dev = NULL; - -/* Ideally we would detect all network cards in slot order. That would - be best done a central PCI probe dispatch, which wouldn't work - well when dynamically adding drivers. So instead we detect just the - Rtl81*9 cards in slot order. */ - -static int __init rtl8129_probe(void) -{ - int cards_found = 0; - int pci_index = 0; - unsigned char pci_bus, pci_device_fn; - struct net_device *dev; - - if ( ! pcibios_present()) - return -ENODEV; - - for (; pci_index < 0xff; pci_index++) { - struct pci_dev *pdev; - u16 vendor, device, pci_command, new_command; - int chip_idx, irq; - long ioaddr; - - if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pci_index, - &pci_bus, &pci_device_fn) - != PCIBIOS_SUCCESSFUL) - break; - pcibios_read_config_word(pci_bus, pci_device_fn, - PCI_VENDOR_ID, &vendor); - pcibios_read_config_word(pci_bus, pci_device_fn, - PCI_DEVICE_ID, &device); - - for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++) - if (vendor == pci_tbl[chip_idx].vendor_id - && (device & pci_tbl[chip_idx].device_id_mask) == - pci_tbl[chip_idx].device_id) - break; - if (pci_tbl[chip_idx].vendor_id == 0) /* Compiled out! */ - continue; - - pdev = pci_find_slot(pci_bus, pci_device_fn); - - ioaddr = pci_resource_start(pdev, 0); - irq = pdev->irq; - - if (pci_enable_device(pdev)) - continue; - - if ((pci_tbl[chip_idx].flags & PCI_USES_IO) && - check_region(ioaddr, pci_tbl[chip_idx].io_size)) - continue; - - /* Activate the card: fix for brain-damaged Win98 BIOSes. */ - pcibios_read_config_word(pci_bus, pci_device_fn, - PCI_COMMAND, &pci_command); - new_command = pci_command | (pci_tbl[chip_idx].flags & 7); - if (pci_command != new_command) { - printk(KERN_INFO " The PCI BIOS has not enabled the" - " device at %d/%d! Updating PCI command %4.4x->%4.4x.\n", - pci_bus, pci_device_fn, pci_command, new_command); - pcibios_write_config_word(pci_bus, pci_device_fn, - PCI_COMMAND, new_command); - } - - dev = pci_tbl[chip_idx].probe1(pdev, pci_bus, pci_device_fn, ioaddr, irq, chip_idx, cards_found); - - if (dev && (pci_tbl[chip_idx].flags & PCI_COMMAND_MASTER)) { - u8 pci_latency; - pcibios_read_config_byte(pci_bus, pci_device_fn, - PCI_LATENCY_TIMER, &pci_latency); - if (pci_latency < 32) { - printk(KERN_NOTICE " PCI latency timer (CFLT) is " - "unreasonably low at %d. Setting to 64 clocks.\n", - pci_latency); - pcibios_write_config_byte(pci_bus, pci_device_fn, - PCI_LATENCY_TIMER, 64); - } - } - dev = 0; - cards_found++; - } - - return cards_found ? 0 : -ENODEV; -} - -static struct net_device *rtl8129_probe1(struct pci_dev *pdev, int pci_bus, - int pci_devfn, long ioaddr, - int irq, int chip_idx, int found_cnt) -{ - static int did_version = 0; /* Already printed version info. */ - struct rtl8129_private *tp; - int i, option = found_cnt < MAX_UNITS ? options[found_cnt] : 0; - struct net_device *dev; - - if (rtl8129_debug > 0 && did_version++ == 0) - printk(KERN_INFO "%s", version); - - dev = init_etherdev(NULL, 0); - if (dev == NULL) - goto out; - - printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", - dev->name, pci_tbl[chip_idx].name, ioaddr, irq); - - /* Bring the chip out of low-power mode. */ - outb(0x00, ioaddr + Config1); - - if (read_eeprom(ioaddr, 0) != 0xffff) { - for (i = 0; i < 3; i++) { - ((u16 *)(dev->dev_addr))[i] = - le16_to_cpu(read_eeprom(ioaddr, i + 7)); - } - } else { - for (i = 0; i < 6; i++) - dev->dev_addr[i] = inb(ioaddr + MAC0 + i); - } - for (i = 0; i < 5; i++) - printk("%2.2x:", dev->dev_addr[i]); - printk("%2.2x.\n", dev->dev_addr[i]); - - /* We do a request_region() to register /proc/ioports info. */ - if (!request_region(ioaddr, pci_tbl[chip_idx].io_size, dev->name)) - goto out_free_dev; - - dev->base_addr = ioaddr; - dev->irq = irq; - - /* Some data structures must be quadword aligned. */ - tp = kmalloc(sizeof(*tp), GFP_KERNEL | GFP_DMA); - if (tp == NULL) - goto out_release_region; - - memset(tp, 0, sizeof(*tp)); - dev->priv = tp; - - tp->next_module = root_rtl8129_dev; - root_rtl8129_dev = dev; - - tp->pdev = pdev; - tp->chip_id = chip_idx; - tp->pci_bus = pci_bus; - tp->pci_devfn = pci_devfn; - - /* Find the connected MII xcvrs. - Doing this in open() would allow detecting external xcvrs later, but - takes too much time. */ - if (rtl_cap_tbl[chip_idx] & HAS_MII_XCVR) { - int phy, phy_idx; - for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(tp->phys); - phy++) { - int mii_status = mdio_read(dev, phy, 1); - if (mii_status != 0xffff && mii_status != 0x0000) { - tp->phys[phy_idx++] = phy; - printk(KERN_INFO "%s: MII transceiver found at address %d.\n", - dev->name, phy); - } - } - if (phy_idx == 0) { - printk(KERN_INFO "%s: No MII transceivers found! Assuming SYM " - "transceiver.\n", - dev->name); - tp->phys[0] = -1; - } - } else - tp->phys[0] = 32; - - /* Put the chip into low-power mode. */ - outb(0xC0, ioaddr + Cfg9346); - outb(0x03, ioaddr + Config1); - outb('H', ioaddr + HltClk); /* 'R' would leave the clock running. */ - - /* The lower four bits are the media type. */ - if (option > 0) { - tp->full_duplex = (option & 0x200) ? 1 : 0; - tp->default_port = option & 15; - if (tp->default_port) - tp->medialock = 1; - } - - if (found_cnt < MAX_UNITS && full_duplex[found_cnt] > 0) - tp->full_duplex = full_duplex[found_cnt]; - - if (tp->full_duplex) { - printk(KERN_INFO "%s: Media type forced to Full Duplex.\n", dev->name); - mdio_write(dev, tp->phys[0], 4, 0x141); - tp->duplex_lock = 1; - } - - /* The Rtl8129-specific entries in the device structure. */ - dev->open = &rtl8129_open; - dev->hard_start_xmit = &rtl8129_start_xmit; - dev->tx_timeout = &rtl8129_tx_timeout; - dev->watchdog_timeo = TX_TIMEOUT; - dev->stop = &rtl8129_close; - dev->get_stats = &rtl8129_get_stats; - dev->set_multicast_list = &set_rx_mode; - dev->do_ioctl = &mii_ioctl; - return dev; - -out_release_region: - release_region(ioaddr, pci_tbl[chip_idx].io_size); -out_free_dev: - unregister_netdev(dev); - kfree(dev); -out: - return NULL; -} - -/* Serial EEPROM section. */ - -/* EEPROM_Ctrl bits. */ -#define EE_SHIFT_CLK 0x04 /* EEPROM shift clock. */ -#define EE_CS 0x08 /* EEPROM chip select. */ -#define EE_DATA_WRITE 0x02 /* EEPROM chip data in. */ -#define EE_WRITE_0 0x00 -#define EE_WRITE_1 0x02 -#define EE_DATA_READ 0x01 /* EEPROM chip data out. */ -#define EE_ENB (0x80 | EE_CS) - -/* Delay between EEPROM clock transitions. - No extra delay is needed with 33Mhz PCI, but 66Mhz may change this. - */ - -#define eeprom_delay() inl(ee_addr) - -/* The EEPROM commands include the alway-set leading bit. */ -#define EE_WRITE_CMD (5 << 6) -#define EE_READ_CMD (6 << 6) -#define EE_ERASE_CMD (7 << 6) - -static int read_eeprom(long ioaddr, int location) -{ - int i; - unsigned retval = 0; - long ee_addr = ioaddr + Cfg9346; - int read_cmd = location | EE_READ_CMD; - - outb(EE_ENB & ~EE_CS, ee_addr); - outb(EE_ENB, ee_addr); - - /* Shift the read command bits out. */ - for (i = 10; i >= 0; i--) { - int dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; - outb(EE_ENB | dataval, ee_addr); - eeprom_delay(); - outb(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr); - eeprom_delay(); - } - outb(EE_ENB, ee_addr); - eeprom_delay(); - - for (i = 16; i > 0; i--) { - outb(EE_ENB | EE_SHIFT_CLK, ee_addr); - eeprom_delay(); - retval = (retval << 1) | ((inb(ee_addr) & EE_DATA_READ) ? 1 : 0); - outb(EE_ENB, ee_addr); - eeprom_delay(); - } - - /* Terminate the EEPROM access. */ - outb(~EE_CS, ee_addr); - return retval; -} - -/* MII serial management: mostly bogus for now. */ -/* Read and write the MII management registers using software-generated - serial MDIO protocol. - The maximum data clock rate is 2.5 Mhz. The minimum timing is usually - met by back-to-back PCI I/O cycles, but we insert a delay to avoid - "overclocking" issues. */ -#define MDIO_DIR 0x80 -#define MDIO_DATA_OUT 0x04 -#define MDIO_DATA_IN 0x02 -#define MDIO_CLK 0x01 -#define MDIO_WRITE0 (MDIO_DIR) -#define MDIO_WRITE1 (MDIO_DIR | MDIO_DATA_OUT) - -#define mdio_delay() inb(mdio_addr) - -static char mii_2_8139_map[8] = {MII_BMCR, MII_BMSR, 0, 0, NWayAdvert, - NWayLPAR, NWayExpansion, 0 }; - -/* Syncronize the MII management interface by shifting 32 one bits out. */ -static void mdio_sync(long mdio_addr) -{ - int i; - - for (i = 32; i >= 0; i--) { - outb(MDIO_WRITE1, mdio_addr); - mdio_delay(); - outb(MDIO_WRITE1 | MDIO_CLK, mdio_addr); - mdio_delay(); - } - return; -} -static int mdio_read(struct net_device *dev, int phy_id, int location) -{ - long mdio_addr = dev->base_addr + MII_SMI; - int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location; - int retval = 0; - int i; - - if (phy_id > 31) { /* Really a 8139. Use internal registers. */ - return location < 8 && mii_2_8139_map[location] ? - inw(dev->base_addr + mii_2_8139_map[location]) : 0; - } - mdio_sync(mdio_addr); - /* Shift the read command bits out. */ - for (i = 15; i >= 0; i--) { - int dataval = (mii_cmd & (1 << i)) ? MDIO_DATA_OUT : 0; - - outb(MDIO_DIR | dataval, mdio_addr); - mdio_delay(); - outb(MDIO_DIR | dataval | MDIO_CLK, mdio_addr); - mdio_delay(); - } - - /* Read the two transition, 16 data, and wire-idle bits. */ - for (i = 19; i > 0; i--) { - outb(0, mdio_addr); - mdio_delay(); - retval = (retval << 1) | ((inb(mdio_addr) & MDIO_DATA_IN) ? 1 : 0); - outb(MDIO_CLK, mdio_addr); - mdio_delay(); - } - return (retval>>1) & 0xffff; -} - -static void mdio_write(struct net_device *dev, int phy_id, int location, int value) -{ - long mdio_addr = dev->base_addr + MII_SMI; - int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value; - int i; - - if (phy_id > 31) { /* Really a 8139. Use internal registers. */ - if (location < 8 && mii_2_8139_map[location]) - outw(value, dev->base_addr + mii_2_8139_map[location]); - return; - } - mdio_sync(mdio_addr); - - /* Shift the command bits out. */ - for (i = 31; i >= 0; i--) { - int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0; - outb(dataval, mdio_addr); - mdio_delay(); - outb(dataval | MDIO_CLK, mdio_addr); - mdio_delay(); - } - /* Clear out extra bits. */ - for (i = 2; i > 0; i--) { - outb(0, mdio_addr); - mdio_delay(); - outb(MDIO_CLK, mdio_addr); - mdio_delay(); - } - return; -} - - -static int -rtl8129_open(struct net_device *dev) -{ - struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; - long ioaddr = dev->base_addr; - int i, retval; - - MOD_INC_USE_COUNT; - - /* Soft reset the chip. */ - outb(CmdReset, ioaddr + ChipCmd); - - if ((retval = request_irq(dev->irq, &rtl8129_interrupt, SA_SHIRQ, dev->name, dev))) { - MOD_DEC_USE_COUNT; - return retval; - } - - tp->tx_bufs = pci_alloc_consistent(tp->pdev, - TX_BUF_SIZE * NUM_TX_DESC, - &tp->tx_bufs_dma); - tp->rx_ring = pci_alloc_consistent(tp->pdev, - RX_BUF_LEN + 16, - &tp->rx_ring_dma); - if (tp->tx_bufs == NULL || tp->rx_ring == NULL) { - free_irq(dev->irq, dev); - if (tp->tx_bufs) - pci_free_consistent(tp->pdev, - TX_BUF_SIZE * NUM_TX_DESC, - tp->tx_bufs, tp->tx_bufs_dma); - if (tp->rx_ring) - pci_free_consistent(tp->pdev, - RX_BUF_LEN + 16, - tp->rx_ring, tp->rx_ring_dma); - if (rtl8129_debug > 0) - printk(KERN_ERR "%s: Couldn't allocate a %d byte receive ring.\n", - dev->name, RX_BUF_LEN); - MOD_DEC_USE_COUNT; - return -ENOMEM; - } - rtl8129_init_ring(dev); - - /* Check that the chip has finished the reset. */ - for (i = 1000; i > 0; i--) - if ((inb(ioaddr + ChipCmd) & CmdReset) == 0) - break; - - for (i = 0; i < 6; i++) - outb(dev->dev_addr[i], ioaddr + MAC0 + i); - - /* Must enable Tx/Rx before setting transfer thresholds! */ - outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd); - outl((RX_FIFO_THRESH << 13) | (RX_BUF_LEN_IDX << 11) | (RX_DMA_BURST<<8), - ioaddr + RxConfig); - outl((TX_DMA_BURST<<8)|0x03000000, ioaddr + TxConfig); - tp->tx_flag = (TX_FIFO_THRESH<<11) & 0x003f0000; - - tp->full_duplex = tp->duplex_lock; - if (tp->phys[0] >= 0 || (rtl_cap_tbl[tp->chip_id] & HAS_MII_XCVR)) { - u16 mii_reg5 = mdio_read(dev, tp->phys[0], 5); - if (mii_reg5 == 0xffff) - ; /* Not there */ - else if ((mii_reg5 & 0x0100) == 0x0100 - || (mii_reg5 & 0x00C0) == 0x0040) - tp->full_duplex = 1; - if (rtl8129_debug > 1) - printk(KERN_INFO"%s: Setting %s%s-duplex based on" - " auto-negotiated partner ability %4.4x.\n", dev->name, - mii_reg5 == 0 ? "" : - (mii_reg5 & 0x0180) ? "100mbps " : "10mbps ", - tp->full_duplex ? "full" : "half", mii_reg5); - } - - outb(0xC0, ioaddr + Cfg9346); - outb(tp->full_duplex ? 0x60 : 0x20, ioaddr + Config1); - outb(0x00, ioaddr + Cfg9346); - - outl(tp->rx_ring_dma, ioaddr + RxBuf); - - /* Start the chip's Tx and Rx process. */ - outl(0, ioaddr + RxMissed); - set_rx_mode(dev); - - outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd); - - /* Enable all known interrupts by setting the interrupt mask. */ - outw(PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver - | TxErr | TxOK | RxErr | RxOK, ioaddr + IntrMask); - - if (rtl8129_debug > 1) - printk(KERN_DEBUG"%s: rtl8129_open() ioaddr %#lx IRQ %d" - " GP Pins %2.2x %s-duplex.\n", - dev->name, ioaddr, dev->irq, inb(ioaddr + GPPinData), - tp->full_duplex ? "full" : "half"); - - /* Set the timer to switch to check for link beat and perhaps switch - to an alternate media type. */ - init_timer(&tp->timer); - tp->timer.expires = RUN_AT((24*HZ)/10); /* 2.4 sec. */ - tp->timer.data = (unsigned long)dev; - tp->timer.function = &rtl8129_timer; - add_timer(&tp->timer); - - return 0; -} - -static void rtl8129_timer(unsigned long data) -{ - struct net_device *dev = (struct net_device *)data; - struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; - long ioaddr = dev->base_addr; - int next_tick = 60*HZ; - int mii_reg5 = mdio_read(dev, tp->phys[0], 5); - - if (! tp->duplex_lock && mii_reg5 != 0xffff) { - int duplex = (mii_reg5&0x0100) || (mii_reg5 & 0x01C0) == 0x0040; - if (tp->full_duplex != duplex) { - tp->full_duplex = duplex; - printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d link" - " partner ability of %4.4x.\n", dev->name, - tp->full_duplex ? "full" : "half", tp->phys[0], mii_reg5); - outb(0xC0, ioaddr + Cfg9346); - outb(tp->full_duplex ? 0x60 : 0x20, ioaddr + Config1); - outb(0x00, ioaddr + Cfg9346); - } - } - /* Check for bogusness. */ - if (inw(ioaddr + IntrStatus) & (TxOK | RxOK)) { - int status = inw(ioaddr + IntrStatus); - if (status & (TxOK | RxOK)) { /* Double check */ - printk(KERN_ERR "%s: RTL8129 Interrupt line blocked, status %x.\n", - dev->name, status); - rtl8129_interrupt(dev->irq, dev, 0); - } - } - if (netif_queue_stopped(dev) && - (jiffies - dev->trans_start) >= 2*TX_TIMEOUT) - rtl8129_tx_timeout(dev); - -#if 0 - if (tp->twistie) { - unsigned int CSCRval = inw(ioaddr + CSCR); /* Read link status. */ - if (tp->twistie == 1) { - if (CSCRval & CSCR_LinkOKBit) { - outw(CSCR_LinkDownOffCmd, ioaddr + CSCR); - tp->twistie = 2; - next_tick = HZ/10; - } else { - outw(CSCR_LinkDownCmd, ioaddr + CSCR); - outl(FIFOTMS_default,ioaddr + FIFOTMS); - outl(PARA78_default ,ioaddr + PARA78); - outl(PARA7c_default ,ioaddr + PARA7c); - tp->twistie = 0; - } - } else if (tp->twistie == 2) { - int linkcase = (CSCRval & CSCR_LinkStatusBits) >> 12; - int row; - if (linkcase >= 0x7000) row = 3; - else if (linkcase >= 0x3000) row = 2; - else if (linkcase >= 0x1000) row = 1; - else row = 0; - tp->twistie == row + 3; - outw(0,ioaddr+FIFOTMS); - outl(param[row][0], ioaddr+PARA7c); - tp->twist_cnt = 1; - } else { - outl(param[tp->twistie-3][tp->twist_cnt], ioaddr+PARA7c); - if (++tp->twist_cnt < 4) { - next_tick = HZ/10; - } else if (tp->twistie-3 == 3) { - if ((CSCRval & CSCR_LinkStatusBits) != 0x7000) { - outl(PARA7c_xxx, ioaddr+PARA7c); - next_tick = HZ/10; /* 100ms. */ - outl(FIFOTMS_default, ioaddr+FIFOTMS); - outl(PARA78_default, ioaddr+PARA78); - outl(PARA7c_default, ioaddr+PARA7c); - tp->twistie == 3 + 3; - outw(0,ioaddr+FIFOTMS); - outl(param[3][0], ioaddr+PARA7c); - tp->twist_cnt = 1; - } - } - } - } -#endif - - if (rtl8129_debug > 2) { - if (rtl_cap_tbl[tp->chip_id] & HAS_MII_XCVR) - printk(KERN_DEBUG"%s: Media selection tick, GP pins %2.2x.\n", - dev->name, inb(ioaddr + GPPinData)); - else - printk(KERN_DEBUG"%s: Media selection tick, Link partner %4.4x.\n", - dev->name, inw(ioaddr + NWayLPAR)); - printk(KERN_DEBUG"%s: Other registers are IntMask %4.4x IntStatus %4.4x" - " RxStatus %4.4x.\n", - dev->name, inw(ioaddr + IntrMask), inw(ioaddr + IntrStatus), - inl(ioaddr + RxEarlyStatus)); - printk(KERN_DEBUG"%s: Chip config %2.2x %2.2x.\n", - dev->name, inb(ioaddr + Config0), inb(ioaddr + Config1)); - } - - tp->timer.expires = RUN_AT(next_tick); - add_timer(&tp->timer); -} - -static void rtl8129_tx_timeout(struct net_device *dev) -{ - struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; - long ioaddr = dev->base_addr; - int mii_reg, i; - - if (rtl8129_debug > 0) - printk(KERN_WARNING "%s: Transmit timeout, status %2.2x %4.4x " - "media %2.2x.\n", - dev->name, inb(ioaddr + ChipCmd), inw(ioaddr + IntrStatus), - inb(ioaddr + GPPinData)); - - /* Disable interrupts by clearing the interrupt mask. */ - outw(0x0000, ioaddr + IntrMask); - /* Emit info to figure out what went wrong. */ - printk("%s: Tx queue start entry %d dirty entry %d.\n", - dev->name, tp->cur_tx, tp->dirty_tx); - for (i = 0; i < NUM_TX_DESC; i++) - printk(KERN_DEBUG"%s: Tx descriptor %d is %8.8x.%s\n", - dev->name, i, inl(ioaddr + TxStatus0 + i*4), - i == tp->dirty_tx % NUM_TX_DESC ? " (queue head)" : ""); - printk(KERN_DEBUG"%s: MII #%d registers are:", dev->name, tp->phys[0]); - for (mii_reg = 0; mii_reg < 8; mii_reg++) - printk(" %4.4x", mdio_read(dev, tp->phys[0], mii_reg)); - printk(".\n"); - - /* Soft reset the chip. */ - outb(CmdReset, ioaddr + ChipCmd); - /* Check that the chip has finished the reset. */ - for (i = 1000; i > 0; i--) - if ((inb(ioaddr + ChipCmd) & CmdReset) == 0) - break; - for (i = 0; i < 6; i++) - outb(dev->dev_addr[i], ioaddr + MAC0 + i); - - outb(0x00, ioaddr + Cfg9346); - tp->cur_rx = 0; - /* Must enable Tx/Rx before setting transfer thresholds! */ - outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd); - outl((RX_FIFO_THRESH << 13) | (RX_BUF_LEN_IDX << 11) | (RX_DMA_BURST<<8), - ioaddr + RxConfig); - outl((TX_DMA_BURST<<8), ioaddr + TxConfig); - set_rx_mode(dev); - { /* Save the unsent Tx packets. */ - struct sk_buff *saved_skb[NUM_TX_DESC], *skb; - int j; - for (j = 0; tp->cur_tx - tp->dirty_tx > 0 ; j++, tp->dirty_tx++) { - struct ring_info *rp = &tp->tx_info[tp->dirty_tx % NUM_TX_DESC]; - - saved_skb[j] = rp->skb; - if (rp->mapping != 0) { - pci_unmap_single(tp->pdev, rp->mapping, rp->skb->len, PCI_DMA_TODEVICE); - rp->mapping = 0; - } - } - tp->dirty_tx = tp->cur_tx = 0; - - for (i = 0; i < j; i++) { - skb = tp->tx_info[i].skb = saved_skb[i]; - if ((long)skb->data & 3) { /* Must use alignment buffer. */ - memcpy(tp->tx_buf[i], skb->data, skb->len); - outl(tp->tx_bufs_dma + (tp->tx_buf[i] - tp->tx_bufs), - ioaddr + TxAddr0 + i*4); - } else { - tp->tx_info[i].mapping = - pci_map_single(tp->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); - outl(tp->tx_info[i].mapping, ioaddr + TxAddr0 + i*4); - } - /* Note: the chip doesn't have auto-pad! */ - outl(tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN), - ioaddr + TxStatus0 + i*4); - } - tp->cur_tx = i; - while (i < NUM_TX_DESC) { - tp->tx_info[i].skb = NULL; - tp->tx_info[i].mapping = 0; - i++; - } - if (tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) {/* Typical path */ - netif_wake_queue(dev); - tp->tx_full = 0; - } else { - tp->tx_full = 1; - netif_stop_queue(dev); - } - } - - dev->trans_start = jiffies; - tp->stats.tx_errors++; - /* Enable all known interrupts by setting the interrupt mask. */ - outw(PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver - | TxErr | TxOK | RxErr | RxOK, ioaddr + IntrMask); - return; -} - - -/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ -static void -rtl8129_init_ring(struct net_device *dev) -{ - struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; - int i; - - tp->tx_full = 0; - tp->cur_rx = 0; - tp->dirty_tx = tp->cur_tx = 0; - - for (i = 0; i < NUM_TX_DESC; i++) { - tp->tx_buf[i] = &tp->tx_bufs[i*TX_BUF_SIZE]; - tp->tx_info[i].skb = NULL; - tp->tx_info[i].mapping = 0; - } -} - -static int -rtl8129_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; - long ioaddr = dev->base_addr; - int entry; - - netif_stop_queue(dev); - - /* Calculate the next Tx descriptor entry. */ - entry = tp->cur_tx % NUM_TX_DESC; - - tp->tx_info[entry].skb = skb; - if ((long)skb->data & 3) { /* Must use alignment buffer. */ - tp->tx_info[entry].mapping = 0; - memcpy(tp->tx_buf[entry], skb->data, skb->len); - outl(tp->tx_bufs_dma + (tp->tx_buf[entry] - tp->tx_bufs), - ioaddr + TxAddr0 + entry*4); - } else { - tp->tx_info[entry].mapping = - pci_map_single(tp->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); - outl(tp->tx_info[entry].mapping, ioaddr + TxAddr0 + entry*4); - } - /* Note: the chip doesn't have auto-pad! */ - outl(tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN), - ioaddr + TxStatus0 + entry*4); - - if (++tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) { /* Typical path */ - netif_start_queue(dev); - } else { - tp->tx_full = 1; - } - - dev->trans_start = jiffies; - if (rtl8129_debug > 4) - printk(KERN_DEBUG"%s: Queued Tx packet at %p size %d to slot %d.\n", - dev->name, skb->data, (int)skb->len, entry); - - return 0; -} - -/* The interrupt handler does all of the Rx thread work and cleans up - after the Tx thread. */ -static void rtl8129_interrupt(int irq, void *dev_instance, struct pt_regs *regs) -{ - struct net_device *dev = (struct net_device *)dev_instance; - struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; - int boguscnt = max_interrupt_work; - int status, link_changed = 0; - long ioaddr = dev->base_addr; - - do { - status = inw(ioaddr + IntrStatus); - /* Acknowledge all of the current interrupt sources ASAP, but - an first get an additional status bit from CSCR. */ - if ((status & RxUnderrun) && inw(ioaddr+CSCR) & CSCR_LinkChangeBit) - link_changed = 1; - outw(status, ioaddr + IntrStatus); - - if (rtl8129_debug > 4) - printk(KERN_DEBUG"%s: interrupt status=%#4.4x new intstat=%#4.4x.\n", - dev->name, status, inw(ioaddr + IntrStatus)); - - if ((status & (PCIErr|PCSTimeout|RxUnderrun|RxOverflow|RxFIFOOver - |TxErr|TxOK|RxErr|RxOK)) == 0) - break; - - if (status & (RxOK|RxUnderrun|RxOverflow|RxFIFOOver))/* Rx interrupt */ - rtl8129_rx(dev); - - if (status & (TxOK | TxErr)) { - unsigned int dirty_tx = tp->dirty_tx; - - while (tp->cur_tx - dirty_tx > 0) { - int entry = dirty_tx % NUM_TX_DESC; - int txstatus = inl(ioaddr + TxStatus0 + entry*4); - - if ( ! (txstatus & (TxStatOK | TxUnderrun | TxAborted))) - break; /* It still hasn't been Txed */ - - /* Note: TxCarrierLost is always asserted at 100mbps. */ - if (txstatus & (TxOutOfWindow | TxAborted)) { - /* There was an major error, log it. */ - if (rtl8129_debug > 1) - printk(KERN_NOTICE"%s: Transmit error, Tx status %8.8x.\n", - dev->name, txstatus); - tp->stats.tx_errors++; - if (txstatus&TxAborted) { - tp->stats.tx_aborted_errors++; - outl((TX_DMA_BURST<<8)|0x03000001, ioaddr + TxConfig); - } - if (txstatus&TxCarrierLost) tp->stats.tx_carrier_errors++; - if (txstatus&TxOutOfWindow) tp->stats.tx_window_errors++; -#ifdef ETHER_STATS - if ((txstatus & 0x0f000000) == 0x0f000000) - tp->stats.collisions16++; -#endif - } else { - if (txstatus & TxUnderrun) { - /* Add 64 to the Tx FIFO threshold. */ - if (tp->tx_flag < 0x00300000) - tp->tx_flag += 0x00020000; - tp->stats.tx_fifo_errors++; - } - tp->stats.collisions += (txstatus >> 24) & 15; -#if LINUX_VERSION_CODE > 0x20119 - tp->stats.tx_bytes += txstatus & 0x7ff; -#endif - tp->stats.tx_packets++; - } - - if (tp->tx_info[entry].mapping != 0) { - pci_unmap_single(tp->pdev, - tp->tx_info[entry].mapping, - tp->tx_info[entry].skb->len, - PCI_DMA_TODEVICE); - tp->tx_info[entry].mapping = 0; - } - - /* Free the original skb. */ - dev_kfree_skb_irq(tp->tx_info[entry].skb); - tp->tx_info[entry].skb = NULL; - if (tp->tx_full) { - /* The ring is no longer full, wake the queue. */ - tp->tx_full = 0; - netif_wake_queue(dev); - } - dirty_tx++; - } - -#ifndef final_version - if (tp->cur_tx - dirty_tx > NUM_TX_DESC) { - printk(KERN_ERR"%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n", - dev->name, dirty_tx, tp->cur_tx, tp->tx_full); - dirty_tx += NUM_TX_DESC; - } -#endif - tp->dirty_tx = dirty_tx; - } - - /* Check uncommon events with one test. */ - if (status & (PCIErr|PCSTimeout |RxUnderrun|RxOverflow|RxFIFOOver - |TxErr|RxErr)) { - if (rtl8129_debug > 2) - printk(KERN_NOTICE"%s: Abnormal interrupt, status %8.8x.\n", - dev->name, status); - - if (status == 0xffffffff) - break; - /* Update the error count. */ - tp->stats.rx_missed_errors += inl(ioaddr + RxMissed); - outl(0, ioaddr + RxMissed); - - if ((status & RxUnderrun) && link_changed && - (rtl_cap_tbl[tp->chip_id] & HAS_LNK_CHNG)) { - /* Really link-change on new chips. */ - int lpar = inw(ioaddr + NWayLPAR); - int duplex = (lpar&0x0100)||(lpar & 0x01C0) == 0x0040; - if (tp->full_duplex != duplex) { - tp->full_duplex = duplex; - outb(0xC0, ioaddr + Cfg9346); - outb(tp->full_duplex ? 0x60 : 0x20, ioaddr + Config1); - outb(0x00, ioaddr + Cfg9346); - } - status &= ~RxUnderrun; - } - if (status & (RxUnderrun | RxOverflow | RxErr | RxFIFOOver)) - tp->stats.rx_errors++; - - if (status & (PCSTimeout)) tp->stats.rx_length_errors++; - if (status & (RxUnderrun|RxFIFOOver)) tp->stats.rx_fifo_errors++; - if (status & RxOverflow) { - tp->stats.rx_over_errors++; - tp->cur_rx = inw(ioaddr + RxBufAddr) % RX_BUF_LEN; - outw(tp->cur_rx - 16, ioaddr + RxBufPtr); - } - if (status & PCIErr) { - u32 pci_cmd_status; - pcibios_read_config_dword(tp->pci_bus, tp->pci_devfn, - PCI_COMMAND, &pci_cmd_status); - - printk(KERN_ERR "%s: PCI Bus error %4.4x.\n", - dev->name, pci_cmd_status); - } - } - if (--boguscnt < 0) { - printk(KERN_WARNING"%s: Too much work at interrupt, " - "IntrStatus=0x%4.4x.\n", - dev->name, status); - /* Clear all interrupt sources. */ - outw(0xffff, ioaddr + IntrStatus); - break; - } - } while (1); - - if (rtl8129_debug > 3) - printk(KERN_DEBUG"%s: exiting interrupt, intr_status=%#4.4x.\n", - dev->name, inl(ioaddr + IntrStatus)); - return; -} - -/* The data sheet doesn't describe the Rx ring at all, so I'm guessing at the - field alignments and semantics. */ -static int rtl8129_rx(struct net_device *dev) -{ - struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; - long ioaddr = dev->base_addr; - unsigned char *rx_ring = tp->rx_ring; - u16 cur_rx = tp->cur_rx; - - if (rtl8129_debug > 4) - printk(KERN_DEBUG"%s: In rtl8129_rx(), current %4.4x BufAddr %4.4x," - " free to %4.4x, Cmd %2.2x.\n", - dev->name, cur_rx, inw(ioaddr + RxBufAddr), - inw(ioaddr + RxBufPtr), inb(ioaddr + ChipCmd)); - - while ((inb(ioaddr + ChipCmd) & 1) == 0) { - int ring_offset = cur_rx % RX_BUF_LEN; - u32 rx_status = le32_to_cpu(*(u32*)(rx_ring + ring_offset)); - int rx_size = rx_status >> 16; - - if (rtl8129_debug > 4) { - int i; - printk(KERN_DEBUG"%s: rtl8129_rx() status %4.4x, size %4.4x, cur %4.4x.\n", - dev->name, rx_status, rx_size, cur_rx); - printk(KERN_DEBUG"%s: Frame contents ", dev->name); - for (i = 0; i < 70; i++) - printk(" %2.2x", le32_to_cpu(rx_ring[ring_offset + i])); - printk(".\n"); - } - if (rx_status & RxTooLong) { - if (rtl8129_debug > 0) - printk(KERN_NOTICE"%s: Oversized Ethernet frame, status %4.4x!\n", - dev->name, rx_status); - tp->stats.rx_length_errors++; - } else if (rx_status & - (RxBadSymbol|RxRunt|RxTooLong|RxCRCErr|RxBadAlign)) { - if (rtl8129_debug > 1) - printk(KERN_DEBUG"%s: Ethernet frame had errors," - " status %4.4x.\n", dev->name, rx_status); - tp->stats.rx_errors++; - if (rx_status & (RxBadSymbol|RxBadAlign)) - tp->stats.rx_frame_errors++; - if (rx_status & (RxRunt|RxTooLong)) tp->stats.rx_length_errors++; - if (rx_status & RxCRCErr) tp->stats.rx_crc_errors++; - /* Reset the receiver, based on RealTek recommendation. (Bug?) */ - tp->cur_rx = 0; - outb(CmdTxEnb, ioaddr + ChipCmd); - outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd); - outl((RX_FIFO_THRESH << 13) | (RX_BUF_LEN_IDX << 11) | - (RX_DMA_BURST<<8), ioaddr + RxConfig); - } else { - /* Malloc up new buffer, compatible with net-2e. */ - /* Omit the four octet CRC from the length. */ - struct sk_buff *skb; - int pkt_size = rx_size - 4; - - skb = dev_alloc_skb(pkt_size + 2); - if (skb == NULL) { - printk(KERN_WARNING"%s: Memory squeeze, deferring packet.\n", - dev->name); - /* We should check that some rx space is free. - If not, free one and mark stats->rx_dropped++. */ - tp->stats.rx_dropped++; - break; - } - skb->dev = dev; - skb_reserve(skb, 2); /* 16 byte align the IP fields. */ - if (ring_offset+rx_size > RX_BUF_LEN) { - int semi_count = RX_BUF_LEN - ring_offset - 4; - memcpy(skb_put(skb, semi_count), &rx_ring[ring_offset + 4], - semi_count); - memcpy(skb_put(skb, pkt_size-semi_count), rx_ring, - pkt_size-semi_count); - if (rtl8129_debug > 4) { - int i; - printk(KERN_DEBUG"%s: Frame wrap @%d", - dev->name, semi_count); - for (i = 0; i < 16; i++) - printk(" %2.2x", le32_to_cpu(rx_ring[i])); - printk(".\n"); - memset(rx_ring, 0xcc, 16); - } - } else { -#if 1 /* USE_IP_COPYSUM */ - eth_copy_and_sum(skb, &rx_ring[ring_offset + 4], - pkt_size, 0); - skb_put(skb, pkt_size); -#else - memcpy(skb_put(skb, pkt_size), &rx_ring[ring_offset + 4], - pkt_size); -#endif - } - skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); -#if LINUX_VERSION_CODE > 0x20119 - tp->stats.rx_bytes += pkt_size; -#endif - tp->stats.rx_packets++; - } - - cur_rx = (cur_rx + rx_size + 4 + 3) & ~3; - outw(cur_rx - 16, ioaddr + RxBufPtr); - } - if (rtl8129_debug > 4) - printk(KERN_DEBUG"%s: Done rtl8129_rx(), current %4.4x BufAddr %4.4x," - " free to %4.4x, Cmd %2.2x.\n", - dev->name, cur_rx, inw(ioaddr + RxBufAddr), - inw(ioaddr + RxBufPtr), inb(ioaddr + ChipCmd)); - tp->cur_rx = cur_rx; - return 0; -} - -static int -rtl8129_close(struct net_device *dev) -{ - long ioaddr = dev->base_addr; - struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; - int i; - - netif_stop_queue(dev); - - del_timer_sync(&tp->timer); - - if (rtl8129_debug > 1) - printk(KERN_DEBUG"%s: Shutting down ethercard, status was 0x%4.4x.\n", - dev->name, inw(ioaddr + IntrStatus)); - - /* Disable interrupts by clearing the interrupt mask. */ - outw(0x0000, ioaddr + IntrMask); - - /* Stop the chip's Tx and Rx DMA processes. */ - outb(0x00, ioaddr + ChipCmd); - - /* Update the error counts. */ - tp->stats.rx_missed_errors += inl(ioaddr + RxMissed); - outl(0, ioaddr + RxMissed); - - free_irq(dev->irq, dev); - - for (i = 0; i < NUM_TX_DESC; i++) { - struct sk_buff *skb = tp->tx_info[i].skb; - dma_addr_t mapping = tp->tx_info[i].mapping; - - if (skb) { - if (mapping) - pci_unmap_single(tp->pdev, mapping, skb->len, PCI_DMA_TODEVICE); - dev_kfree_skb(skb); - } - tp->tx_info[i].skb = NULL; - tp->tx_info[i].mapping = 0; - } - pci_free_consistent(tp->pdev, RX_BUF_LEN + 16, - tp->rx_ring, tp->rx_ring_dma); - pci_free_consistent(tp->pdev, TX_BUF_SIZE * NUM_TX_DESC, - tp->tx_bufs, tp->tx_bufs_dma); - tp->rx_ring = NULL; - tp->tx_bufs = NULL; - - /* Green! Put the chip in low-power mode. */ - outb(0xC0, ioaddr + Cfg9346); - outb(0x03, ioaddr + Config1); - outb('H', ioaddr + HltClk); /* 'R' would leave the clock running. */ - - MOD_DEC_USE_COUNT; - - return 0; -} - -static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -{ - struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; - u16 *data = (u16 *)&rq->ifr_data; - - switch(cmd) { - case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ - data[0] = tp->phys[0] & 0x3f; - /* Fall Through */ - case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ - data[3] = mdio_read(dev, data[0], data[1] & 0x1f); - return 0; - case SIOCDEVPRIVATE+2: /* Write the specified MII register */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - mdio_write(dev, data[0], data[1] & 0x1f, data[2]); - return 0; - default: - return -EOPNOTSUPP; - } -} - -static struct net_device_stats * -rtl8129_get_stats(struct net_device *dev) -{ - struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; - long ioaddr = dev->base_addr; - - if (netif_running(dev)) { - tp->stats.rx_missed_errors += inl(ioaddr + RxMissed); - outl(0, ioaddr + RxMissed); - } - - return &tp->stats; -} - -/* Set or clear the multicast filter for this adaptor. - This routine is not state sensitive and need not be SMP locked. */ - -static unsigned const ethernet_polynomial = 0x04c11db7U; -static inline u32 ether_crc(int length, unsigned char *data) -{ - int crc = -1; - - while (--length >= 0) { - unsigned char current_octet = *data++; - int bit; - for (bit = 0; bit < 8; bit++, current_octet >>= 1) - crc = (crc << 1) ^ - ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0); - } - return crc; -} - -/* Bits in RxConfig. */ -enum rx_mode_bits { - AcceptErr=0x20, AcceptRunt=0x10, AcceptBroadcast=0x08, - AcceptMulticast=0x04, AcceptMyPhys=0x02, AcceptAllPhys=0x01, -}; - -static void set_rx_mode(struct net_device *dev) -{ - long ioaddr = dev->base_addr; - u32 mc_filter[2]; /* Multicast hash filter */ - int i, rx_mode; - - if (rtl8129_debug > 3) - printk(KERN_DEBUG"%s: set_rx_mode(%4.4x) done -- Rx config %8.8x.\n", - dev->name, dev->flags, inl(ioaddr + RxConfig)); - - /* Note: do not reorder, GCC is clever about common statements. */ - if (dev->flags & IFF_PROMISC) { - /* Unconditionally log net taps. */ - printk(KERN_NOTICE"%s: Promiscuous mode enabled.\n", dev->name); - rx_mode = AcceptBroadcast|AcceptMulticast|AcceptMyPhys|AcceptAllPhys; - mc_filter[1] = mc_filter[0] = 0xffffffff; - } else if ((dev->mc_count > multicast_filter_limit) - || (dev->flags & IFF_ALLMULTI)) { - /* Too many to filter perfectly -- accept all multicasts. */ - rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; - mc_filter[1] = mc_filter[0] = 0xffffffff; - } else { - struct dev_mc_list *mclist; - rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; - mc_filter[1] = mc_filter[0] = 0; - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; - i++, mclist = mclist->next) - set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26, mc_filter); - } - /* We can safely update without stopping the chip. */ - outb(rx_mode, ioaddr + RxConfig); - outl(mc_filter[0], ioaddr + MAR0 + 0); - outl(mc_filter[1], ioaddr + MAR0 + 4); - return; -} - - -static void __exit rtl8129_cleanup (void) -{ - struct net_device *next_dev; - - /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ - while (root_rtl8129_dev) { - struct rtl8129_private *tp = - (struct rtl8129_private *)root_rtl8129_dev->priv; - next_dev = tp->next_module; - unregister_netdev(root_rtl8129_dev); - release_region(root_rtl8129_dev->base_addr, - pci_tbl[tp->chip_id].io_size); - kfree(tp); - kfree(root_rtl8129_dev); - root_rtl8129_dev = next_dev; - } -} - -module_init(rtl8129_probe); -module_exit(rtl8129_cleanup); - -/* - * Local variables: - * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c rtl8129.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" - * c-indent-level: 4 - * c-basic-offset: 4 - * tab-width: 4 - * End: - */ diff --git a/drivers/net/sb1000.c b/drivers/net/sb1000.c index 5c069a286..5f83d5c99 100644 --- a/drivers/net/sb1000.c +++ b/drivers/net/sb1000.c @@ -137,6 +137,14 @@ static inline int sb1000_set_PIDs(const int ioaddr[], const char* name, static inline int sb1000_rx(struct net_device *dev); static inline void sb1000_error_dpc(struct net_device *dev); +static struct isapnp_device_id id_table[] = { + { ISAPNP_ANY_ID, ISAPNP_ANY_ID, + ISAPNP_VENDOR('G','I','C'), ISAPNP_FUNCTION(0x1000), 0 }, + {0} +}; + +MODULE_DEVICE_TABLE(isapnp, id_table); + /* probe for SB1000 using Plug-n-Play mechanism */ int sb1000_probe(struct net_device *dev) diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index f96666e62..2e433744b 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -18,6 +18,7 @@ preliminary Rev. 1.0 Jan. 18, 1998 http://www.sis.com.tw/support/databook.htm + Rev 1.07.09 Feb. 9 2001 Dave Jones <davej@suse.de> PCI enable cleanup Rev 1.07.08 Jan. 8 2001 Lei-Chun Chang added RTL8201 PHY support Rev 1.07.07 Nov. 29 2000 Lei-Chun Chang added kernel-doc extractable documentation and 630 workaround fix Rev 1.07.06 Nov. 7 2000 Jeff Garzik <jgarzik@mandrakesoft.com> some bug fix and cleaning @@ -60,7 +61,7 @@ #include "sis900.h" static const char *version = -"sis900.c: v1.07.08 1/8/2001\n"; +"sis900.c: v1.07.09 2/9/2001\n"; static int max_interrupt_work = 20; static int multicast_filter_limit = 128; @@ -252,34 +253,37 @@ static int __devinit sis630e_get_mac_addr(struct pci_dev * pci_dev, struct net_d static int __devinit sis900_probe (struct pci_dev *pci_dev, const struct pci_device_id *pci_id) { struct sis900_private *sis_priv; - long ioaddr = pci_resource_start(pci_dev, 0); + long ioaddr; struct net_device *net_dev; - int irq = pci_dev->irq; - int i, ret = 0; + int irq; + int i, ret; u8 revision; char *card_name = card_names[pci_id->driver_data]; - if (!pci_dma_supported(pci_dev, SIS900_DMA_MASK)) { + /* setup various bits in PCI command register */ + ret = pci_enable_device (pci_dev); + if (ret) return ret; + + i = pci_set_dma_mask(pci_dev, SIS900_DMA_MASK); + if (i) { printk(KERN_ERR "sis900.c: architecture does not support " "32bit PCI busmaster DMA\n"); - return -ENODEV; + return i; } - /* setup various bits in PCI command register */ - if (pci_enable_device (pci_dev)) - return -ENODEV; pci_set_master(pci_dev); - net_dev = init_etherdev(NULL, sizeof(struct sis900_private)); + irq = pci_dev->irq; + ioaddr = pci_resource_start(pci_dev, 0); + + net_dev = alloc_etherdev(sizeof(struct sis900_private)); if (!net_dev) return -ENOMEM; SET_MODULE_OWNER(net_dev); - if (!request_region(ioaddr, SIS900_TOTAL_SIZE, net_dev->name)) { - printk(KERN_ERR "sis900.c: can't allocate I/O space at 0x%lX\n", ioaddr); - ret = -EBUSY; + ret = pci_request_regions(pci_dev, "sis900"); + if (ret) goto err_out; - } pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &revision); if (revision == SIS630E_900_REV || revision == SIS630EA1_900_REV) @@ -294,13 +298,6 @@ static int __devinit sis900_probe (struct pci_dev *pci_dev, const struct pci_dev goto err_out_region; } - /* print some information about our NIC */ - printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", net_dev->name, - card_name, ioaddr, irq); - for (i = 0; i < 5; i++) - printk("%2.2x:", (u8)net_dev->dev_addr[i]); - printk("%2.2x.\n", net_dev->dev_addr[i]); - sis_priv = net_dev->priv; /* We do a request_region() to register /proc/ioports info. */ @@ -315,8 +312,7 @@ static int __devinit sis900_probe (struct pci_dev *pci_dev, const struct pci_dev goto err_out_region; } - pci_dev->driver_data = net_dev; - pci_dev->dma_mask = SIS900_DMA_MASK; + pci_set_drvdata(pci_dev, net_dev); /* The SiS900-specific entries in the device structure. */ net_dev->open = &sis900_open; @@ -329,12 +325,24 @@ static int __devinit sis900_probe (struct pci_dev *pci_dev, const struct pci_dev net_dev->tx_timeout = sis900_tx_timeout; net_dev->watchdog_timeo = TX_TIMEOUT; + ret = register_netdev(net_dev); + if (ret) + goto err_out_cleardev; + + /* print some information about our NIC */ + printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", net_dev->name, + card_name, ioaddr, irq); + for (i = 0; i < 5; i++) + printk("%2.2x:", (u8)net_dev->dev_addr[i]); + printk("%2.2x.\n", net_dev->dev_addr[i]); + return 0; +err_out_cleardev: + pci_set_drvdata(pci_dev, NULL); err_out_region: - release_region(ioaddr, SIS900_TOTAL_SIZE); + pci_release_regions(pci_dev); err_out: - unregister_netdev(net_dev); kfree(net_dev); return ret; } @@ -350,7 +358,7 @@ err_out: static int __init sis900_mii_probe (struct net_device * net_dev) { - struct sis900_private * sis_priv = (struct sis900_private *)net_dev->priv; + struct sis900_private * sis_priv = net_dev->priv; int phy_addr; u8 revision; @@ -608,7 +616,7 @@ static void mdio_write(struct net_device *net_dev, int phy_id, int location, int static int sis900_open(struct net_device *net_dev) { - struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; + struct sis900_private *sis_priv = net_dev->priv; long ioaddr = net_dev->base_addr; u8 revision; int ret; @@ -701,7 +709,7 @@ sis900_init_rxfilter (struct net_device * net_dev) static void sis900_init_tx_ring(struct net_device *net_dev) { - struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; + struct sis900_private *sis_priv = net_dev->priv; long ioaddr = net_dev->base_addr; int i; @@ -735,7 +743,7 @@ sis900_init_tx_ring(struct net_device *net_dev) static void sis900_init_rx_ring(struct net_device *net_dev) { - struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; + struct sis900_private *sis_priv = net_dev->priv; long ioaddr = net_dev->base_addr; int i; @@ -806,7 +814,7 @@ sis900_init_rx_ring(struct net_device *net_dev) static void sis630_set_eq(struct net_device *net_dev, u8 revision) { - struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; + struct sis900_private *sis_priv = net_dev->priv; u16 reg14h, eq_value, max_value=0, min_value=0; u8 host_bridge_rev; int i, maxcount=10; @@ -873,7 +881,7 @@ static void sis630_set_eq(struct net_device *net_dev, u8 revision) static void sis900_timer(unsigned long data) { struct net_device *net_dev = (struct net_device *)data; - struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; + struct sis900_private *sis_priv = net_dev->priv; struct mii_phy *mii_phy = sis_priv->mii; static int next_tick = 5*HZ; u16 status; @@ -950,7 +958,7 @@ static void sis900_timer(unsigned long data) static void sis900_check_mode (struct net_device *net_dev, struct mii_phy *mii_phy) { - struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; + struct sis900_private *sis_priv = net_dev->priv; long ioaddr = net_dev->base_addr; int speed, duplex; u32 tx_flags = 0, rx_flags = 0; @@ -1169,7 +1177,7 @@ static void rtl8201_read_mode(struct net_device *net_dev, int phy_addr, int *spe static void sis900_tx_timeout(struct net_device *net_dev) { - struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; + struct sis900_private *sis_priv = net_dev->priv; long ioaddr = net_dev->base_addr; unsigned long flags; int i; @@ -1222,7 +1230,7 @@ static void sis900_tx_timeout(struct net_device *net_dev) static int sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev) { - struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; + struct sis900_private *sis_priv = net_dev->priv; long ioaddr = net_dev->base_addr; unsigned int entry; unsigned long flags; @@ -1271,8 +1279,8 @@ sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev) static void sis900_interrupt(int irq, void *dev_instance, struct pt_regs *regs) { - struct net_device *net_dev = (struct net_device *)dev_instance; - struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; + struct net_device *net_dev = dev_instance; + struct sis900_private *sis_priv = net_dev->priv; int boguscnt = max_interrupt_work; long ioaddr = net_dev->base_addr; u32 status; @@ -1330,7 +1338,7 @@ static void sis900_interrupt(int irq, void *dev_instance, struct pt_regs *regs) static int sis900_rx(struct net_device *net_dev) { - struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; + struct sis900_private *sis_priv = net_dev->priv; long ioaddr = net_dev->base_addr; unsigned int entry = sis_priv->cur_rx % NUM_RX_DESC; u32 rx_status = sis_priv->rx_ring[entry].cmdsts; @@ -1459,7 +1467,7 @@ static int sis900_rx(struct net_device *net_dev) static void sis900_finish_xmit (struct net_device *net_dev) { - struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; + struct sis900_private *sis_priv = net_dev->priv; for (; sis_priv->dirty_tx < sis_priv->cur_tx; sis_priv->dirty_tx++) { unsigned int entry; @@ -1469,14 +1477,14 @@ static void sis900_finish_xmit (struct net_device *net_dev) tx_status = sis_priv->tx_ring[entry].cmdsts; if (tx_status & OWN) { - /* The packet is not transmited yet (owned by hardware) ! + /* The packet is not transmitted yet (owned by hardware) ! Note: the interrupt is generated only when Tx Machine is idle, so this is an almost impossible case */ break; } if (tx_status & (ABORT | UNDERRUN | OWCOLL)) { - /* packet unsuccessfully transmited */ + /* packet unsuccessfully transmitted */ if (sis900_debug > 3) printk(KERN_INFO "%s: Transmit " "error, Tx status %8.8x.\n", @@ -1491,7 +1499,7 @@ static void sis900_finish_xmit (struct net_device *net_dev) if (tx_status & OWCOLL) sis_priv->stats.tx_window_errors++; } else { - /* packet successfully transmited */ + /* packet successfully transmitted */ sis_priv->stats.collisions += (tx_status & COLCNT) >> 16; sis_priv->stats.tx_bytes += tx_status & DSIZE; sis_priv->stats.tx_packets++; @@ -1524,7 +1532,7 @@ static int sis900_close(struct net_device *net_dev) { long ioaddr = net_dev->base_addr; - struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; + struct sis900_private *sis_priv = net_dev->priv; int i; netif_stop_queue(net_dev); @@ -1568,7 +1576,7 @@ sis900_close(struct net_device *net_dev) static int mii_ioctl(struct net_device *net_dev, struct ifreq *rq, int cmd) { - struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; + struct sis900_private *sis_priv = net_dev->priv; u16 *data = (u16 *)&rq->ifr_data; switch(cmd) { @@ -1598,7 +1606,7 @@ static int mii_ioctl(struct net_device *net_dev, struct ifreq *rq, int cmd) static struct net_device_stats * sis900_get_stats(struct net_device *net_dev) { - struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; + struct sis900_private *sis_priv = net_dev->priv; return &sis_priv->stats; } @@ -1615,7 +1623,7 @@ sis900_get_stats(struct net_device *net_dev) static int sis900_set_config(struct net_device *dev, struct ifmap *map) { - struct sis900_private *sis_priv = (struct sis900_private *)dev->priv; + struct sis900_private *sis_priv = dev->priv; struct mii_phy *mii_phy = sis_priv->mii; u16 status; @@ -1838,11 +1846,12 @@ static void sis900_reset(struct net_device *net_dev) static void __devexit sis900_remove(struct pci_dev *pci_dev) { - struct net_device *net_dev = pci_dev->driver_data; + struct net_device *net_dev = pci_get_drvdata(pci_dev); unregister_netdev(net_dev); - release_region(net_dev->base_addr, SIS900_TOTAL_SIZE); kfree(net_dev); + pci_release_regions(pci_dev); + pci_set_drvdata(pci_dev, NULL); } #define SIS900_MODULE_NAME "sis900" diff --git a/drivers/net/sk98lin/h/lm80.h b/drivers/net/sk98lin/h/lm80.h index 0e165bb0b..8ac65aba3 100644 --- a/drivers/net/sk98lin/h/lm80.h +++ b/drivers/net/sk98lin/h/lm80.h @@ -126,7 +126,7 @@ extern "C" { #define LM80_IS_BTI (1<<1) /* state of BTI# pin */ #define LM80_IS_FAN1 (1<<2) /* count limit exceeded for Fan 1 */ #define LM80_IS_FAN2 (1<<3) /* count limit exceeded for Fan 2 */ -#define LM80_IS_CI (1<<4) /* Chassis Intrusion occured */ +#define LM80_IS_CI (1<<4) /* Chassis Intrusion occurred */ #define LM80_IS_OS (1<<5) /* OS temperature limit exceeded */ /* bit 6 and 7 are reserved in LM80_ISRC_2 */ #define LM80_IS_HT_IRQ_MD (1<<6) /* Hot temperature interrupt mode */ diff --git a/drivers/net/sk98lin/h/skgehw.h b/drivers/net/sk98lin/h/skgehw.h index aa2a3fad9..45993da2b 100644 --- a/drivers/net/sk98lin/h/skgehw.h +++ b/drivers/net/sk98lin/h/skgehw.h @@ -499,7 +499,7 @@ extern "C" { /* * The HW-Spec. call this registers Timeout Value 0..11. But this names are * not usable in SW. Please notice these are NOT real timeouts, these are - * the number of qWords transfered continously. + * the number of qWords transferred continously. */ #define B3_RI_WTO_R1 0x0190 /* 8 bit RAM Iface WR Timeout Queue R1 (TO0) */ #define B3_RI_WTO_XA1 0x0191 /* 8 bit RAM Iface WR Timeout Queue XA1 (TO1) */ @@ -984,7 +984,7 @@ extern "C" { /* B3_RI_TEST 8 bit RAM Iface Test Register */ /* Bit 15..4: reserved */ -#define RI_T_EV (1<<3) /* Bit 3: Timeout Event occured */ +#define RI_T_EV (1<<3) /* Bit 3: Timeout Event occurred */ #define RI_T_ON (1<<2) /* Bit 2: Timeout Timer Test On */ #define RI_T_OFF (1<<1) /* Bit 1: Timeout Timer Test Off */ #define RI_T_STEP (1<<0) /* Bit 0: Timeout Timer Step */ @@ -1034,19 +1034,19 @@ extern "C" { /* B3_MA_RC_TEST 16 bit MAC Arbiter Recovery Test Reg */ /* B3_PA_TEST 16 bit Packet Arbiter Test Register */ /* Bit 15, 11, 7, and 3 are reserved in B3_PA_TEST */ -#define TX2_T_EV (1<<15) /* Bit 15: TX2 Timeout/Recv Event occured*/ +#define TX2_T_EV (1<<15) /* Bit 15: TX2 Timeout/Recv Event occurred*/ #define TX2_T_ON (1<<14) /* Bit 14: TX2 Timeout/Recv Timer Test On*/ #define TX2_T_OFF (1<<13) /* Bit 13: TX2 Timeout/Recv Timer Tst Off*/ #define TX2_T_STEP (1<<12) /* Bit 12: TX2 Timeout/Recv Timer Step */ -#define TX1_T_EV (1<<11) /* Bit 11: TX1 Timeout/Recv Event occured*/ +#define TX1_T_EV (1<<11) /* Bit 11: TX1 Timeout/Recv Event occurred*/ #define TX1_T_ON (1<<10) /* Bit 10: TX1 Timeout/Recv Timer Test On*/ #define TX1_T_OFF (1<<9) /* Bit 9: TX1 Timeout/Recv Timer Tst Off*/ #define TX1_T_STEP (1<<8) /* Bit 8: TX1 Timeout/Recv Timer Step */ -#define RX2_T_EV (1<<7) /* Bit 7: RX2 Timeout/Recv Event occured*/ +#define RX2_T_EV (1<<7) /* Bit 7: RX2 Timeout/Recv Event occurred*/ #define RX2_T_ON (1<<6) /* Bit 6: RX2 Timeout/Recv Timer Test On*/ #define RX2_T_OFF (1<<5) /* Bit 5: RX2 Timeout/Recv Timer Tst Off*/ #define RX2_T_STEP (1<<4) /* Bit 4: RX2 Timeout/Recv Timer Step */ -#define RX1_T_EV (1<<3) /* Bit 3: RX1 Timeout/Recv Event occured*/ +#define RX1_T_EV (1<<3) /* Bit 3: RX1 Timeout/Recv Event occurred*/ #define RX1_T_ON (1<<2) /* Bit 2: RX1 Timeout/Recv Timer Test On*/ #define RX1_T_OFF (1<<1) /* Bit 1: RX1 Timeout/Recv Timer Tst Off*/ #define RX1_T_STEP (1<<0) /* Bit 0: RX1 Timeout/Recv Timer Step */ diff --git a/drivers/net/sk98lin/h/xmac_ii.h b/drivers/net/sk98lin/h/xmac_ii.h index ff380db6f..10fb37786 100644 --- a/drivers/net/sk98lin/h/xmac_ii.h +++ b/drivers/net/sk98lin/h/xmac_ii.h @@ -277,7 +277,7 @@ extern "C" { * XMAC Bit Definitions * * If the bit access behaviour differs from the register access behaviour - * (r/w, ro) this is docomented after the bit number. The following bit + * (r/w, ro) this is documented after the bit number. The following bit * access behaviours are used: * (sc) self clearing * (ro) read only @@ -412,7 +412,7 @@ extern "C" { #define XM_ST_BC (1L<<7) /* Bit 7: Broadcast packet */ #define XM_ST_MC (1L<<6) /* Bit 6: Multicast packet */ #define XM_ST_UC (1L<<5) /* Bit 5: Unicast packet */ -#define XM_ST_TX_UR (1L<<4) /* Bit 4: FIFO Underrun occured */ +#define XM_ST_TX_UR (1L<<4) /* Bit 4: FIFO Underrun occurred */ #define XM_ST_CS_ERR (1L<<3) /* Bit 3: Carrier Sense Error */ #define XM_ST_LAT_COL (1L<<2) /* Bit 2: Late Collision Error */ #define XM_ST_MUL_COL (1L<<1) /* Bit 1: Multiple Collisions */ diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c index e88ec69ae..87d8b4e9d 100644 --- a/drivers/net/sk98lin/skge.c +++ b/drivers/net/sk98lin/skge.c @@ -109,7 +109,7 @@ * Transmit descriptor polling was not reenabled after SkGePortInit. * * Revision 1.16 1999/07/27 15:17:29 cgoos - * Added some "\n" in output strings (removed while debuging...). + * Added some "\n" in output strings (removed while debugging...). * * Revision 1.15 1999/07/23 12:09:30 cgoos * Performance optimization, rx checksumming, large frame support. @@ -260,7 +260,7 @@ static const char SysKonnectBuildNumber[] = #define VER_STRING "3.05" -/* for debuging on x86 only */ +/* for debugging on x86 only */ /* #define BREAKPOINT() asm(" int $3"); */ /* use of a transmit complete interrupt */ @@ -518,6 +518,12 @@ SK_AC *pAC; } /* FreeResources */ +static struct pci_device_id skge_pci_tbl[] __initdata = { + { PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_GE, PCI_ANY_ID, PCI_ANY_ID, }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(pci, skge_pci_tbl); + MODULE_AUTHOR("Christoph Goos <cgoos@syskonnect.de>"); MODULE_DESCRIPTION("SysKonnect SK-NET Gigabit Ethernet SK-98xx driver"); MODULE_PARM(AutoNeg_A, "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s"); @@ -2616,7 +2622,7 @@ unsigned int Flags; /* for spin lock */ * Description: * This function is called if an ioctl is issued on the device. * There are three subfunction for reading, writing and test-writing - * the private MIB data structure (usefull for SysKonnect-internal tools). + * the private MIB data structure (useful for SysKonnect-internal tools). * * Returns: * 0, if everything is ok diff --git a/drivers/net/sk98lin/skgeinit.c b/drivers/net/sk98lin/skgeinit.c index 8dba1dc90..68357da59 100644 --- a/drivers/net/sk98lin/skgeinit.c +++ b/drivers/net/sk98lin/skgeinit.c @@ -122,7 +122,7 @@ * chg: Default is autosensing with AUTOFULL mode * * Revision 1.31 1998/11/25 15:36:16 gklug - * fix: do NOT stop LED Timer when port should be stoped + * fix: do NOT stop LED Timer when port should be stopped * * Revision 1.30 1998/11/24 13:15:28 gklug * add: Init PCkeckPar struct member @@ -1118,10 +1118,10 @@ int QuIoOffs) /* Queue IO Address Offset */ * * Dir = SK_STOP_TX Stops the transmit path only and resets * the XMAC. The receive queue is still and - * the pending rx frames may still transfered + * the pending rx frames may still transferred * into the RxD. * SK_STOP_RX Stop the receive path. The tansmit path - * has to be stoped once before. + * has to be stopped once before. * SK_STOP_ALL SK_STOP_TX + SK_STOP_RX * * RstMode=SK_SOFT_RST Resets the XMAC. The PHY is still alive. @@ -1129,7 +1129,7 @@ int QuIoOffs) /* Queue IO Address Offset */ * * Example: * 1) A Link Down event was signaled for a port. Therefore the activity - * of this port should be stoped and a hardware reset should be issued + * of this port should be stopped and a hardware reset should be issued * to enable the workaround of XMAC errata #2. But the received frames * should not be discarded. * ... diff --git a/drivers/net/sk98lin/skgepnmi.c b/drivers/net/sk98lin/skgepnmi.c index 33c51f544..e64548652 100644 --- a/drivers/net/sk98lin/skgepnmi.c +++ b/drivers/net/sk98lin/skgepnmi.c @@ -149,7 +149,7 @@ * Fixed: Couldnot delete VPD keys on UNIX. * * Revision 1.48 1998/12/09 14:11:10 mhaveman - * -Add: Debugmessage for XMAC_RESET supressed to minimize output. + * -Add: Debugmessage for XMAC_RESET suppressed to minimize output. * -Fixed: RlmtChangeThreshold will now be initialized. * -Fixed: VPD_ENTRIES_LIST extended value with unnecessary space char. * -Fixed: On VPD key creation an invalid key name could be created @@ -206,7 +206,7 @@ * -Fixed bug for RX counters. On an RX overflow interrupt the high * words of all RX counters were incremented. * -SET operations on FLOWCTRL_MODE and LINK_MODE accept now the - * value 0, which has no effect. It is usefull for multiple instance + * value 0, which has no effect. It is useful for multiple instance * SETs. * * Revision 1.37 1998/11/20 08:02:04 mhaveman @@ -1600,7 +1600,7 @@ int Level) /* Initialization level */ * * Returns: * SK_PNMI_ERR_OK The request was successfully performed - * SK_PNMI_ERR_GENERAL A general severe internal error occured + * SK_PNMI_ERR_GENERAL A general severe internal error occurred * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to take * the data. * SK_PNMI_ERR_UNKNOWN_OID The requested OID is unknown @@ -1632,13 +1632,13 @@ SK_U32 Instance) /* Instance (1..n) that is to be queried or -1 */ * Description: * Calls a general sub-function for all this stuff. The preset does * the same as a set, but returns just before finally setting the - * new value. This is usefull to check if a set might be successfull. + * new value. This is useful to check if a set might be successful. * If as instance a -1 is passed, an array of values is supposed and * all instance of the OID will be set. * * Returns: * SK_PNMI_ERR_OK The request was successfully performed. - * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_GENERAL A general severe internal error occurred. * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain * the correct data (e.g. a 32bit value is * needed, but a 16 bit value was passed). @@ -1674,13 +1674,13 @@ SK_U32 Instance) /* Instance (1..n) that is to be set or -1 */ * Description: * Calls a general sub-function for all this stuff. The preset does * the same as a set, but returns just before finally setting the - * new value. This is usefull to check if a set might be successfull. + * new value. This is useful to check if a set might be successful. * If as instance a -1 is passed, an array of values is supposed and * all instance of the OID will be set. * * Returns: * SK_PNMI_ERR_OK The request was successfully performed. - * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_GENERAL A general severe internal error occurred. * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain * the correct data (e.g. a 32bit value is * needed, but a 16 bit value was passed). @@ -1723,7 +1723,7 @@ SK_U32 Instance) /* Instance (1..n) that is to be set or -1 */ * * Returns: * SK_PNMI_ERR_OK The request was successfully performed - * SK_PNMI_ERR_GENERAL A general severe internal error occured + * SK_PNMI_ERR_GENERAL A general severe internal error occurred * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to take * the data. */ @@ -1884,7 +1884,7 @@ unsigned int *pLen) /* Length of buffer */ * Description: * Calls a general sub-function for all this set stuff. The preset does * the same as a set, but returns just before finally setting the - * new value. This is usefull to check if a set might be successfull. + * new value. This is useful to check if a set might be successful. * The sub-function runs through the IdTable, checks which OIDs are able * to set, and calls the handler function of the OID to perform the * preset. The return value of the function will also be stored in @@ -1893,7 +1893,7 @@ unsigned int *pLen) /* Length of buffer */ * * Returns: * SK_PNMI_ERR_OK The request was successfully performed. - * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_GENERAL A general severe internal error occurred. * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain * the correct data (e.g. a 32bit value is * needed, but a 16 bit value was passed). @@ -1929,7 +1929,7 @@ unsigned int *pLen) /* Length of buffer */ * * Returns: * SK_PNMI_ERR_OK The request was successfully performed. - * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_GENERAL A general severe internal error occurred. * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain * the correct data (e.g. a 32bit value is * needed, but a 16 bit value was passed). @@ -2816,7 +2816,7 @@ SK_U32 Id) /* Object identifier to be searched */ * * Returns: * SK_PNMI_ERR_OK The request was successfully performed. - * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_GENERAL A general severe internal error occurred. * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain * the correct data (e.g. a 32bit value is * needed, but a 16 bit value was passed). @@ -2883,7 +2883,7 @@ unsigned int TableIndex) /* Index to the Id table */ * * Returns: * SK_PNMI_ERR_OK The request was successfully performed. - * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_GENERAL A general severe internal error occurred. * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain * the correct data (e.g. a 32bit value is * needed, but a 16 bit value was passed). @@ -3017,7 +3017,7 @@ unsigned int TableIndex) /* Index to the Id table */ * * Returns: * SK_PNMI_ERR_OK The request was successfully performed. - * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_GENERAL A general severe internal error occurred. * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain * the correct data (e.g. a 32bit value is * needed, but a 16 bit value was passed). @@ -3159,7 +3159,7 @@ unsigned int TableIndex) /* Index to the Id table */ * * Returns: * SK_PNMI_ERR_OK The request was successfully performed. - * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_GENERAL A general severe internal error occurred. * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain * the correct data (e.g. a 32bit value is * needed, but a 16 bit value was passed). @@ -3299,7 +3299,7 @@ unsigned int TableIndex) /* Index to the Id table */ * * Returns: * SK_PNMI_ERR_OK The request was successfully performed. - * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_GENERAL A general severe internal error occurred. * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain * the correct data (e.g. a 32bit value is * needed, but a 16 bit value was passed). @@ -3509,7 +3509,7 @@ unsigned int TableIndex) /* Index to the Id table */ * * Returns: * SK_PNMI_ERR_OK The request was successfully performed. - * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_GENERAL A general severe internal error occurred. * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain * the correct data (e.g. a 32bit value is * needed, but a 16 bit value was passed). @@ -3628,7 +3628,7 @@ unsigned int TableIndex) /* Index to the Id table */ * * Returns: * SK_PNMI_ERR_OK The request was successfully performed. - * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_GENERAL A general severe internal error occurred. * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain * the correct data (e.g. a 32bit value is * needed, but a 16 bit value was passed). @@ -3872,7 +3872,7 @@ unsigned int TableIndex) /* Index to the Id table */ * * Returns: * SK_PNMI_ERR_OK The request was successfully performed. - * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_GENERAL A general severe internal error occurred. * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain * the correct data (e.g. a 32bit value is * needed, but a 16 bit value was passed). @@ -4352,7 +4352,7 @@ unsigned int TableIndex) /* Index to the Id table */ * * Returns: * SK_PNMI_ERR_OK The request was successfully performed. - * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_GENERAL A general severe internal error occurred. * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain * the correct data (e.g. a 32bit value is * needed, but a 16 bit value was passed). @@ -4956,7 +4956,7 @@ unsigned int TableIndex) /* Index to the Id table */ * * Returns: * SK_PNMI_ERR_OK The request was successfully performed. - * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_GENERAL A general severe internal error occurred. * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain * the correct data (e.g. a 32bit value is * needed, but a 16 bit value was passed). @@ -5264,7 +5264,7 @@ unsigned int TableIndex) /* Index to the Id table */ * * Returns: * SK_PNMI_ERR_OK The request was successfully performed. - * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_GENERAL A general severe internal error occurred. * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain * the correct data (e.g. a 32bit value is * needed, but a 16 bit value was passed). @@ -5449,7 +5449,7 @@ unsigned int TableIndex) /* Index to the Id table */ * * Returns: * SK_PNMI_ERR_OK The request was successfully performed. - * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_GENERAL A general severe internal error occurred. * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain * the correct data (e.g. a 32bit value is * needed, but a 16 bit value was passed). @@ -6052,7 +6052,7 @@ unsigned int TableIndex) /* Index to the Id table */ * * Returns: * SK_PNMI_ERR_OK The request was successfully performed. - * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_GENERAL A general severe internal error occurred. * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain * the correct data (e.g. a 32bit value is * needed, but a 16 bit value was passed). @@ -6502,7 +6502,7 @@ unsigned int PhysPortIndex) /* Physical port index */ * * Description: * The COMMON module only tells us if the mode is half or full duplex. - * But in the decade of auto sensing it is usefull for the user to + * But in the decade of auto sensing it is useful for the user to * know if the mode was negotiated or forced. Therefore we have a * look to the mode, which was last used by the negotiation process. * @@ -6764,7 +6764,7 @@ unsigned int LastMac) /* Index of the last Mac to be updated */ /* * It is an auto-clearing register. If the command bits - * went to zero again, the statistics are transfered. + * went to zero again, the statistics are transferred. * Normally the command should be executed immediately. * But just to be sure we execute a loop. */ @@ -7037,7 +7037,7 @@ SK_IOC IoC) /* IO context handle */ * * Description: * The trap buffer stores various events. A user application somehow - * gets notified that an event occured and retrieves the trap buffer + * gets notified that an event occurred and retrieves the trap buffer * contens (or simply polls the buffer). The buffer is organized as * a ring which stores the newest traps at the beginning. The oldest * traps are overwritten by the newest ones. Each trap entry has a diff --git a/drivers/net/sk98lin/skgesirq.c b/drivers/net/sk98lin/skgesirq.c index b61782866..7e02e80d5 100644 --- a/drivers/net/sk98lin/skgesirq.c +++ b/drivers/net/sk98lin/skgesirq.c @@ -695,14 +695,14 @@ SK_U32 Istatus) /* Interrupt status word */ /* Check whether XMACs are correctly initialized */ if ((Istatus & (IS_PA_TO_RX1 | IS_PA_TO_TX1)) && !pAC->GIni.GP[MAC_1].PState) { - /* XMAC was not initialized but Packet timeout occured */ + /* XMAC was not initialized but Packet timeout occurred */ SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E004, SKERR_SIRQ_E004MSG) ; } if ((Istatus & (IS_PA_TO_RX2 | IS_PA_TO_TX2)) && !pAC->GIni.GP[MAC_2].PState) { - /* XMAC was not initialized but Packet timeout occured */ + /* XMAC was not initialized but Packet timeout occurred */ SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E005, SKERR_SIRQ_E005MSG) ; } @@ -1012,7 +1012,7 @@ int Port) /* Which port should be checked */ */ /* * we received a bunch of frames or no - * CRC error occured on the network -> + * CRC error occurred on the network -> * ok. */ pPrt->PPrevRx = RxCts; @@ -1255,7 +1255,7 @@ int Port) /* Which port should be checked */ SkHWLinkUp(pAC, IoC, Port) ; Done = SkXmAutoNegDone(pAC,IoC,Port); if (Done != SK_AND_OK) { - /* Get PHY parameters, for debuging only */ + /* Get PHY parameters, for debugging only */ PHY_READ(IoC, pPrt, Port, PHY_XMAC_AUNE_LP, &LpAb); PHY_READ(IoC, pPrt, Port, PHY_XMAC_RES_ABI, @@ -1294,7 +1294,7 @@ int Port) /* Which port should be checked */ pPrt->PAutoNegTimeOut ++; if (pPrt->PAutoNegTimeOut >= SK_AND_MAX_TO) { /* - * Timeout occured. + * Timeout occurred. * What do we need now? */ SK_DBG_MSG(pAC,SK_DBGMOD_HWM, @@ -1304,7 +1304,7 @@ int Port) /* Which port should be checked */ if (pPrt->PLinkModeConf == SK_LMODE_AUTOSENSE && pPrt->PLipaAutoNeg != SK_LIPA_AUTO) { /* - * Timeout occured + * Timeout occurred * Set Link manually up. */ SkHWSenseSetNext(pAC, IoC, Port, @@ -1445,7 +1445,7 @@ int Port) /* Which port should be checked */ SkHWLinkUp(pAC, IoC, Port); Done = SkXmAutoNegDone(pAC,IoC,Port); if (Done != SK_AND_OK) { - /* Get PHY parameters, for debuging only */ + /* Get PHY parameters, for debugging only */ PHY_READ(IoC, pPrt, Port, PHY_BCOM_AUNE_LP, &LpAb); @@ -1583,7 +1583,7 @@ int Port) /* Which port should be checked */ SkHWLinkUp(pAC, IoC, Port) ; Done = SkXmAutoNegDone(pAC,IoC,Port); if (Done != SK_AND_OK) { - /* Get PHY parameters, for debuging only */ + /* Get PHY parameters, for debugging only */ PHY_READ(IoC, pPrt, Port, PHY_LONE_AUNE_LP, &LpAb); @@ -1624,7 +1624,7 @@ int Port) /* Which port should be checked */ pPrt->PAutoNegTimeOut ++; if (pPrt->PAutoNegTimeOut >= SK_AND_MAX_TO) { /* - * Timeout occured. + * Timeout occurred. * What do we need now? */ SK_DBG_MSG(pAC,SK_DBGMOD_HWM, @@ -1634,7 +1634,7 @@ int Port) /* Which port should be checked */ if (pPrt->PLinkModeConf == SK_LMODE_AUTOSENSE && pPrt->PLipaAutoNeg != SK_LIPA_AUTO) { /* - * Timeout occured + * Timeout occurred * Set Link manually up. */ SkHWSenseSetNext(pAC, IoC, Port, diff --git a/drivers/net/sk98lin/ski2c.c b/drivers/net/sk98lin/ski2c.c index 447d62122..82db6887f 100644 --- a/drivers/net/sk98lin/ski2c.c +++ b/drivers/net/sk98lin/ski2c.c @@ -1000,7 +1000,7 @@ SK_SENSOR *pSen) /* Get the current time */ CurrTime = SkOsGetTime(pAC); - /* Set para to the most usefull setting: + /* Set para to the most useful setting: * The current sensor. */ ParaLocal.Para64 = (SK_U64) pAC->I2c.CurrSens; diff --git a/drivers/net/sk98lin/skqueue.c b/drivers/net/sk98lin/skqueue.c index e8e40e853..58832ea74 100644 --- a/drivers/net/sk98lin/skqueue.c +++ b/drivers/net/sk98lin/skqueue.c @@ -147,7 +147,7 @@ SK_EVPARA Para) /* Event parameter */ * send command to state machine * end * return error reported by individual Event function - * 0 if no error occured. + * 0 if no error occurred. */ int SkEventDispatcher( SK_AC *pAC, /* Adapters Context */ diff --git a/drivers/net/sk98lin/skxmac2.c b/drivers/net/sk98lin/skxmac2.c index 6e7de7ebe..ccdef30ba 100644 --- a/drivers/net/sk98lin/skxmac2.c +++ b/drivers/net/sk98lin/skxmac2.c @@ -278,7 +278,7 @@ static int SkXmAutoNegDoneNat (SK_AC*, SK_IOC, int); * o don't set XMR_FS_ERR in frame SK_BIG_PK_OK_ON/OFF * status for frames > 1514 bytes * - * for incomming packets may be enabled/disabled by this function. + * for incoming packets may be enabled/disabled by this function. * Additional modes may be added later. * Multiple modes can be enabled/disabled at the same time. * The new configuration is stored into the HWAC port configuration @@ -755,8 +755,8 @@ int Port) /* Port Index (MAC_1 + n) */ /* * configure the XMACs Station Address - * B2_MAC_2 = xx xx xx xx xx x1 is programed to XMAC A - * B2_MAC_3 = xx xx xx xx xx x2 is programed to XMAC B + * B2_MAC_2 = xx xx xx xx xx x1 is programmed to XMAC A + * B2_MAC_3 = xx xx xx xx xx x2 is programmed to XMAC B */ for (i = 0; i < 3; i++) { /* diff --git a/drivers/net/sk_g16.c b/drivers/net/sk_g16.c index 94dab355a..b107a64e0 100644 --- a/drivers/net/sk_g16.c +++ b/drivers/net/sk_g16.c @@ -218,9 +218,9 @@ static const char *rcsid = "$Id: sk_g16.c,v 1.1 1994/06/30 16:25:15 root Exp $"; * */ -#define SK_IOREG (board->ioreg) /* LANCE data registers. */ -#define SK_PORT (board->port) /* Control, Status register */ -#define SK_IOCOM (board->iocom) /* I/O Command */ +#define SK_IOREG (&board->ioreg) /* LANCE data registers. */ +#define SK_PORT (&board->port) /* Control, Status register */ +#define SK_IOCOM (&board->iocom) /* I/O Command */ /* * SK_G16 Status/Control Register bits @@ -1102,7 +1102,7 @@ static int SK_lance_init(struct net_device *dev, unsigned short mode) writel((unsigned long) p->tmdbufs[i], tmdp->u.buffer); /* assign buffer */ /* Mark TMD as start and end of packet */ - writeb(TX_STP | TX_ENP, tmdp->u.s.status); + writeb(TX_STP | TX_ENP, &tmdp->u.s.status); } @@ -1122,32 +1122,32 @@ static int SK_lance_init(struct net_device *dev, unsigned short mode) * receiving packets, set status and release RMD */ - writeb(RX_OWN, rmdp->u.s.status); + writeb(RX_OWN, &rmdp->u.s.status); - writew(-PKT_BUF_SZ, rmdp->blen); /* Buffer Size (two's complement) */ + writew(-PKT_BUF_SZ, &rmdp->blen); /* Buffer Size (two's complement) */ - writeb(0, rmdp->mlen); /* init message length */ + writeb(0, &rmdp->mlen); /* init message length */ } /* Fill LANCE Initialize Block */ - writew(mode, (p->ram)->ib.mode); /* Set operation mode */ + writew(mode, (&((p->ram)->ib.mode))); /* Set operation mode */ for (i = 0; i < ETH_ALEN; i++) /* Set physical address */ { - writeb(dev->dev_addr[i], (p->ram)->ib.paddr[i]); + writeb(dev->dev_addr[i], (&((p->ram)->ib.paddr[i]))); } for (i = 0; i < 8; i++) /* Set multicast, logical address */ { - writeb(0, (p->ram)->ib.laddr[i]); /* We do not use logical addressing */ + writeb(0, (&((p->ram)->ib.laddr[i]))); /* We do not use logical addressing */ } /* Set ring descriptor pointers and set number of descriptors */ - writel((int)p->rmdhead | RMDNUMMASK, (p->ram)->ib.rdrp); - writel((int)p->tmdhead | TMDNUMMASK, (p->ram)->ib.tdrp); + writel((int)p->rmdhead | RMDNUMMASK, (&((p->ram)->ib.rdrp))); + writel((int)p->tmdhead | TMDNUMMASK, (&((p->ram)->ib.tdrp))); /* Prepare LANCE Control and Status Registers */ @@ -1281,7 +1281,7 @@ static int SK_send_packet(struct sk_buff *skb, struct net_device *dev) memcpy_toio((tmdp->u.buffer & 0x00ffffff), skb->data, skb->len); - writew(-len, tmdp->blen); /* set length to transmit */ + writew(-len, &tmdp->blen); /* set length to transmit */ /* * Packet start and end is always set because we use the maximum @@ -1289,7 +1289,7 @@ static int SK_send_packet(struct sk_buff *skb, struct net_device *dev) * Relinquish ownership to LANCE */ - writeb(TX_OWN | TX_STP | TX_ENP, tmdp->u.s.status); + writeb(TX_OWN | TX_STP | TX_ENP, &tmdp->u.s.status); /* Start Demand Transmission */ SK_write_reg(CSR0, CSR0_TDMD | CSR0_INEA); @@ -1301,7 +1301,7 @@ static int SK_send_packet(struct sk_buff *skb, struct net_device *dev) p->tmdnum &= TMDNUM-1; /* Do we own the next transmit buffer ? */ - if (! (readb((p->tmdhead + p->tmdnum)->u.s.status) & TX_OWN) ) + if (! (readb(&((p->tmdhead + p->tmdnum)->u.s.status)) & TX_OWN) ) { /* * We own next buffer and are ready to transmit, so @@ -1421,7 +1421,7 @@ static void SK_txintr(struct net_device *dev) p->tmdlast++; p->tmdlast &= TMDNUM-1; - tmdstat = readb(tmdp->u.s.status); + tmdstat = readb(&tmdp->u.s.status); /* * We check status of transmitted packet. @@ -1429,7 +1429,7 @@ static void SK_txintr(struct net_device *dev) */ if (tmdstat & TX_ERR) /* Error occurred */ { - int stat2 = readw(tmdp->status2); + int stat2 = readw(&tmdp->status2); printk("%s: TX error: %04x %04x\n", dev->name, tmdstat, stat2); @@ -1458,7 +1458,7 @@ static void SK_txintr(struct net_device *dev) p->stats.tx_errors++; - writew(0, tmdp->status2); /* Clear error flags */ + writew(0, &tmdp->status2); /* Clear error flags */ } else if (tmdstat & TX_MORE) /* Collisions occurred ? */ { @@ -1534,7 +1534,7 @@ static void SK_rxintr(struct net_device *dev) * it up to higher layer */ - while (!( (rmdstat = readb(rmdp->u.s.status)) & RX_OWN)) + while (!( (rmdstat = readb(&rmdp->u.s.status)) & RX_OWN)) { /* * Start and end of packet must be set, because we use @@ -1564,7 +1564,7 @@ static void SK_rxintr(struct net_device *dev) * packets. */ - writeb(RX_OWN, rmdp->u.s.status); /* Relinquish ownership to LANCE */ + writeb(RX_OWN, &rmdp->u.s.status); /* Relinquish ownership to LANCE */ } else if (rmdstat & RX_ERR) /* Receive Error ? */ @@ -1576,13 +1576,13 @@ static void SK_rxintr(struct net_device *dev) if (rmdstat & RX_FRAM) p->stats.rx_frame_errors++; if (rmdstat & RX_CRC) p->stats.rx_crc_errors++; - writeb(RX_OWN, rmdp->u.s.status); /* Relinquish ownership to LANCE */ + writeb(RX_OWN, &rmdp->u.s.status); /* Relinquish ownership to LANCE */ } else /* We have a packet which can be queued for the upper layers */ { - int len = readw(rmdp->mlen) & 0x0fff; /* extract message length from receive buffer */ + int len = readw(&rmdp->mlen) & 0x0fff; /* extract message length from receive buffer */ struct sk_buff *skb; skb = dev_alloc_skb(len+2); /* allocate socket buffer */ @@ -1595,7 +1595,7 @@ static void SK_rxintr(struct net_device *dev) * to Lance, update statistics and go ahead. */ - writeb(RX_OWN, rmdp->u.s.status); /* Relinquish ownership to LANCE */ + writeb(RX_OWN, &rmdp->u.s.status); /* Relinquish ownership to LANCE */ printk("%s: Couldn't allocate sk_buff, deferring packet.\n", dev->name); p->stats.rx_dropped++; @@ -1633,7 +1633,7 @@ static void SK_rxintr(struct net_device *dev) * free our descriptor and update statistics */ - writeb(RX_OWN, rmdp->u.s.status); + writeb(RX_OWN, &rmdp->u.s.status); dev->last_rx = jiffies; p->stats.rx_packets++; p->stats.rx_bytes += len; diff --git a/drivers/net/skfp/drvfbi.c b/drivers/net/skfp/drvfbi.c index 93533c5ef..0f473dd93 100644 --- a/drivers/net/skfp/drvfbi.c +++ b/drivers/net/skfp/drvfbi.c @@ -849,7 +849,7 @@ int dma; #ifdef EISA -/*arrays with io adresses of dma controller length and adress registers*/ +/*arrays with io addresses of dma controller length and address registers*/ static const int cntr[8] = { 0x001,0x003,0x005,0x007,0,0x0c6,0x0ca,0x0ce } ; static const int base[8] = { 0x000,0x002,0x004,0x006,0,0x0c4,0x0c8,0x0cc } ; static const int page[8] = { 0x087,0x083,0x081,0x082,0,0x08b,0x089,0x08a } ; diff --git a/drivers/net/skfp/fplustm.c b/drivers/net/skfp/fplustm.c index 4d816c584..103df16e1 100644 --- a/drivers/net/skfp/fplustm.c +++ b/drivers/net/skfp/fplustm.c @@ -87,7 +87,7 @@ static const u_short my_sagp = 0xffff ; /* short group address (n.u.) */ /* - * usefull interrupt bits + * useful interrupt bits */ static int mac_imsk1u = FM_STXABRS | FM_STXABRA0 | FM_SXMTABT ; static int mac_imsk1l = FM_SQLCKS | FM_SQLCKA0 | FM_SPCEPDS | FM_SPCEPDA0| @@ -1381,7 +1381,7 @@ struct s_smc *smc ; CHECK_CAM() ; /* - * wirte the multicast addres into the CAM + * write the multicast address into the CAM */ outpw(FM_A(FM_AFCOMP2), (u_short)((tb->a.a[0]<<8)+tb->a.a[1])) ; diff --git a/drivers/net/skfp/h/skfbi.h b/drivers/net/skfp/h/skfbi.h index f127bddb8..43ddc5561 100644 --- a/drivers/net/skfp/h/skfbi.h +++ b/drivers/net/skfp/h/skfbi.h @@ -90,7 +90,7 @@ #define SKFDDI_PSZ 32 /* address PROM size */ /* - * address transmision from logical to physical offset address on board + * address transmission from logical to physical offset address on board */ #define FMA(a) (0x0400|((a)<<1)) /* FORMAC+ (r/w) */ #define P1A(a) (0x0800|((a)<<1)) /* PLC1 (r/w) */ @@ -347,7 +347,7 @@ #define SA_PMD_TYPE (8) /* start addr. PMD-Type */ /* - * address transmision from logical to physical offset address on board + * address transmission from logical to physical offset address on board */ #define FMA(a) (0x0100|((a)<<1)) /* FORMAC+ (r/w) */ #define P2(a) (0x00c0|((a)<<1)) /* PLC2 (r/w) (DAS) */ @@ -677,7 +677,7 @@ #ifdef ISA /* - * address transmision from logic NPADDR6-0 to physical offset address on board + * address transmission from logic NPADDR6-0 to physical offset address on board */ #define FMA(a) (0x8000|(((a)&0x07)<<1)|(((a)&0x78)<<7)) /* FORMAC+ (r/w) */ #define PRA(a) (0x1000|(((a)&0x07)<<1)|(((a)&0x18)<<7)) /* PROM (read only)*/ @@ -942,7 +942,7 @@ /* PCI_SUB_ID 16 bit Subsystem ID */ /* PCI_BASE_ROM 32 bit Expansion ROM Base Address */ -#define PCI_ROMBASE 0xfffe0000L /* Bit 31..17: ROM BASE addres (1st) */ +#define PCI_ROMBASE 0xfffe0000L /* Bit 31..17: ROM BASE address (1st) */ #define PCI_ROMBASZ 0x0001c000L /* Bit 16..14: Treat as BASE or SIZE */ #define PCI_ROMSIZE 0x00003800L /* Bit 13..11: ROM Size Requirements */ #define PCI_ROMEN 0x00000001L /* Bit 0: Address Decode enable */ @@ -1685,7 +1685,7 @@ #define PCI_PROG_INTFC 0x00 /* PCI programming Interface (=0) */ /* - * address transmision from logical to physical offset address on board + * address transmission from logical to physical offset address on board */ #define FMA(a) (0x0400|((a)<<2)) /* FORMAC+ (r/w) (SN3) */ #define P1(a) (0x0380|((a)<<2)) /* PLC1 (r/w) (DAS) */ diff --git a/drivers/net/skfp/h/smc.h b/drivers/net/skfp/h/smc.h index b909586bc..5164b8900 100644 --- a/drivers/net/skfp/h/smc.h +++ b/drivers/net/skfp/h/smc.h @@ -297,7 +297,7 @@ struct s_srf { #define RS_NORINGOP (1<< 5) /* no ring op */ #define RS_VERSION (1<< 4) /* SMT version mismatch */ #define RS_STUCKBYPASSS (1<< 3) /* stuck bypass */ -#define RS_EVENT (1<< 2) /* FDDI event occured */ +#define RS_EVENT (1<< 2) /* FDDI event occurred */ #define RS_RINGOPCHANGE (1<< 1) /* ring op changed */ #define RS_RES0 (1<< 0) /* reserved */ diff --git a/drivers/net/skfp/pcmplc.c b/drivers/net/skfp/pcmplc.c index 5479b27ea..b19b2a81b 100644 --- a/drivers/net/skfp/pcmplc.c +++ b/drivers/net/skfp/pcmplc.c @@ -1722,7 +1722,7 @@ unsigned int cmd; } if (cmd & PL_EBUF_ERR) { /* elastic buff. det. over-|underflow*/ /* - * Check whether the SRF Condition occured. + * Check whether the SRF Condition occurred. */ if (!plc->ebuf_cont && phy->mib->fddiPORTPCMState == PC8_ACTIVE){ /* diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c index 64f1b8051..89762b6c7 100644 --- a/drivers/net/skfp/skfddi.c +++ b/drivers/net/skfp/skfddi.c @@ -182,12 +182,17 @@ extern void mac_clear_multicast(struct s_smc *smc); extern void enable_tx_irq(struct s_smc *smc, u_short queue); extern void mac_drv_clear_txd(struct s_smc *smc); +static struct pci_device_id skfddi_pci_tbl[] __initdata = { + { PCI_VENDOR_ID_SK, PCI_DEVICE_ID_SK_FP, PCI_ANY_ID, PCI_ANY_ID, }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(pci, skfddi_pci_tbl); // Define module-wide (static) variables -static int num_boards = 0; /* total number of adapters configured */ -static int num_fddi = 0; -static int autoprobed = 0; +static int num_boards; /* total number of adapters configured */ +static int num_fddi; +static int autoprobed; #ifdef MODULE int init_module(void); @@ -195,7 +200,7 @@ void cleanup_module(void); static struct net_device *unlink_modules(struct net_device *p); static int loading_module = 1; #else -static int loading_module = 0; +static int loading_module; #endif // MODULE #ifdef DRIVERDEBUG @@ -1632,7 +1637,7 @@ void *mac_drv_get_space(struct s_smc *smc, unsigned int size) * This function is called by the hardware dependent module. * It allocates the memory for the RxD and TxD descriptors. * - * This memory must be non-cached, non-movable and non-swapable. + * This memory must be non-cached, non-movable and non-swappable. * This memory should start at a physical page boundary. * Args * smc - A pointer to the SMT context struct. diff --git a/drivers/net/skfp/srf.c b/drivers/net/skfp/srf.c index d5f091c54..ce757a19f 100644 --- a/drivers/net/skfp/srf.c +++ b/drivers/net/skfp/srf.c @@ -197,7 +197,7 @@ int cond ; struct s_srf_evc *evc ; int cond_asserted = 0 ; int cond_deasserted = 0 ; - int event_occured = 0 ; + int event_occurred = 0 ; int tsr ; int T_Limit = 2*TICKS_PER_SECOND ; @@ -246,7 +246,7 @@ int cond ; *evc->evc_multiple = FALSE ; } smc->srf.any_report = TRUE ; - event_occured = TRUE ; + event_occurred = TRUE ; } #ifdef FDDI_MIB snmp_srf_event(smc,evc) ; @@ -268,7 +268,7 @@ int cond ; break ; } /* SR01c */ - if (event_occured && tsr < T_Limit) { + if (event_occurred && tsr < T_Limit) { smc->srf.sr_state = SR1_HOLDOFF ; break ; } @@ -286,7 +286,7 @@ int cond ; break ; } /* SR00d */ - if (event_occured && tsr >= T_Limit) { + if (event_occurred && tsr >= T_Limit) { smc->srf.TSR = smt_get_time() ; smt_send_srf(smc) ; break ; diff --git a/drivers/net/slhc.c b/drivers/net/slhc.c index 410bb59c9..3112a4d66 100644 --- a/drivers/net/slhc.c +++ b/drivers/net/slhc.c @@ -81,8 +81,6 @@ #include <net/checksum.h> #include <asm/unaligned.h> -int last_retran; - static unsigned char *encode(unsigned char *cp, unsigned short n); static long decode(unsigned char **cpp); static unsigned char * put16(unsigned char *cp, unsigned short x); @@ -256,8 +254,7 @@ slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, ip = (struct iphdr *) icp; /* Bail if this packet isn't TCP, or is an IP fragment */ - if(ip->protocol != IPPROTO_TCP || (ntohs(ip->frag_off) & 0x1fff) || - (ip->frag_off & 32)){ + if (ip->protocol != IPPROTO_TCP || (ntohs(ip->frag_off) & 0x3fff)) { /* Send as regular IP */ if(ip->protocol != IPPROTO_TCP) comp->sls_o_nontcp++; @@ -351,10 +348,9 @@ found: */ oth = &cs->cs_tcp; - if(last_retran - || ip->version != cs->cs_ip.version || ip->ihl != cs->cs_ip.ihl + if(ip->version != cs->cs_ip.version || ip->ihl != cs->cs_ip.ihl || ip->tos != cs->cs_ip.tos - || (ip->frag_off & 64) != (cs->cs_ip.frag_off & 64) + || (ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000)) || ip->ttl != cs->cs_ip.ttl || th->doff != cs->cs_tcp.doff || (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0) diff --git a/drivers/net/smc-mca.c b/drivers/net/smc-mca.c index 2b5fb3fc4..999311f0c 100644 --- a/drivers/net/smc-mca.c +++ b/drivers/net/smc-mca.c @@ -213,7 +213,7 @@ int __init ultramca_probe(struct net_device *dev) dev->mem_start = 0; num_pages = 40; - switch (j) { /* 'j' = card-# in const array above [hs] */ + switch (adapter) { /* card-# in const array above [hs] */ case _61c8_SMC_Ethercard_PLUS_Elite_A_BNC_AUI_WD8013EP_A: case _61c9_SMC_Ethercard_PLUS_Elite_A_UTP_AUI_WD8013EP_A: { @@ -373,9 +373,9 @@ static void ultramca_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr * #ifdef notdef /* Officially this is what we are doing, but the readl() is faster */ - memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr)); + isa_memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr)); #else - ((unsigned int*)hdr)[0] = readl(hdr_start); + ((unsigned int*)hdr)[0] = isa_readl(hdr_start); #endif } @@ -390,12 +390,12 @@ static void ultramca_block_input(struct net_device *dev, int count, struct sk_bu if (xfer_start + count > dev->rmem_end) { /* We must wrap the input move. */ int semi_count = dev->rmem_end - xfer_start; - memcpy_fromio(skb->data, xfer_start, semi_count); + isa_memcpy_fromio(skb->data, xfer_start, semi_count); count -= semi_count; - memcpy_fromio(skb->data + semi_count, dev->rmem_start, count); + isa_memcpy_fromio(skb->data + semi_count, dev->rmem_start, count); } else { /* Packet is in one chunk -- we can copy + cksum. */ - eth_io_copy_and_sum(skb, xfer_start, count, 0); + isa_eth_io_copy_and_sum(skb, xfer_start, count, 0); } } @@ -405,7 +405,7 @@ static void ultramca_block_output(struct net_device *dev, int count, const unsig { unsigned long shmem = dev->mem_start + ((start_page - START_PG) << 8); - memcpy_toio(shmem, buf, count); + isa_memcpy_toio(shmem, buf, count); } static int ultramca_close_card(struct net_device *dev) diff --git a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c index 0236c79cc..7b81e51c0 100644 --- a/drivers/net/smc-ultra.c +++ b/drivers/net/smc-ultra.c @@ -20,6 +20,7 @@ ultra_probe() Detecting and initializing the card. ultra_probe1() + ultra_probe_isapnp() ultra_open() The card-specific details of starting, stopping ultra_reset_8390() and resetting the 8390 NIC core. @@ -43,11 +44,19 @@ Paul Gortmaker : multiple card support for module users. Donald Becker : 4/17/96 PIO support, minor potential problems avoided. Donald Becker : 6/6/96 correctly set auto-wrap bit. + Alexander Sotirov : 1/20/01 Added support for ISAPnP cards + + Note about the ISA PnP support: + + This driver can not autoprobe for more than one SMC EtherEZ PnP card. + You have to configure the second card manually through the /proc/isapnp + interface and then load the module with an explicit io=0x___ option. */ static const char *version = "smc-ultra.c:v2.02 2/3/98 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n"; +#include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> @@ -55,6 +64,7 @@ static const char *version = #include <linux/errno.h> #include <linux/string.h> #include <linux/init.h> +#include <linux/isapnp.h> #include <asm/io.h> #include <asm/system.h> @@ -69,6 +79,10 @@ static unsigned int ultra_portlist[] __initdata = int ultra_probe(struct net_device *dev); static int ultra_probe1(struct net_device *dev, int ioaddr); +#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE +static int ultra_probe_isapnp(struct net_device *dev); +#endif + static int ultra_open(struct net_device *dev); static void ultra_reset_8390(struct net_device *dev); static void ultra_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, @@ -85,6 +99,17 @@ static void ultra_pio_output(struct net_device *dev, int count, const unsigned char *buf, const int start_page); static int ultra_close_card(struct net_device *dev); +#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE +static struct isapnp_device_id ultra_device_ids[] __initdata = { + { ISAPNP_VENDOR('S','M','C'), ISAPNP_FUNCTION(0x8416), + ISAPNP_VENDOR('S','M','C'), ISAPNP_FUNCTION(0x8416), + (long) "SMC EtherEZ (8416)" }, + { } /* terminate list */ +}; + +MODULE_DEVICE_TABLE(isapnp, ultra_device_ids); +#endif + #define START_PG 0x00 /* First page of TX buffer */ @@ -114,6 +139,14 @@ int __init ultra_probe(struct net_device *dev) else if (base_addr != 0) /* Don't probe at all. */ return -ENXIO; +#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE + /* Look for any installed ISAPnP cards */ + if (isapnp_present() && (ultra_probe_isapnp(dev) == 0)) + return 0; + + printk(KERN_NOTICE "smc-ultra.c: No ISAPnP cards found, trying standard ones...\n"); +#endif + for (i = 0; ultra_portlist[i]; i++) if (ultra_probe1(dev, ultra_portlist[i]) == 0) return 0; @@ -245,6 +278,48 @@ out: return retval; } +#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE +static int __init ultra_probe_isapnp(struct net_device *dev) +{ + int i; + + for (i = 0; ultra_device_ids[i].vendor != 0; i++) { + struct pci_dev *idev = NULL; + + while ((idev = isapnp_find_dev(NULL, + ultra_device_ids[i].vendor, + ultra_device_ids[i].function, + idev))) { + /* Avoid already found cards from previous calls */ + if (idev->prepare(idev)) + continue; + if (idev->activate(idev)) + continue; + /* if no irq, search for next */ + if (idev->irq_resource[0].start == 0) + continue; + /* found it */ + dev->base_addr = idev->resource[0].start; + dev->irq = idev->irq_resource[0].start; + printk(KERN_INFO "smc-ultra.c: ISAPnP reports %s at i/o %#lx, irq %d.\n", + (char *) ultra_device_ids[i].driver_data, + + dev->base_addr, dev->irq); + if (ultra_probe1(dev, dev->base_addr) != 0) { /* Shouldn't happen. */ + printk(KERN_ERR "smc-ultra.c: Probe of ISAPnP card at %#lx failed.\n", dev->base_addr); return -ENXIO; + } + ei_status.priv = (unsigned long)idev; + break; + } + if (!idev) + continue; + return 0; + } + + return -ENODEV; +} +#endif + static int ultra_open(struct net_device *dev) { @@ -465,6 +540,13 @@ cleanup_module(void) if (dev->priv != NULL) { /* NB: ultra_close_card() does free_irq */ int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; + +#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE + struct pci_dev *idev = (struct pci_dev *)ei_status.priv; + if (idev) + idev->deactivate(idev); +#endif + unregister_netdev(dev); release_region(ioaddr, ULTRA_IO_EXTENT); kfree(dev->priv); diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c index e0904b499..2bd7f8f5c 100644 --- a/drivers/net/smc9194.c +++ b/drivers/net/smc9194.c @@ -238,12 +238,12 @@ static void smc_interrupt(int irq, void *, struct pt_regs *regs); . This is a separate procedure to handle the receipt of a packet, to . leave the interrupt code looking slightly cleaner */ -inline static void smc_rcv( struct net_device *dev ); +static inline void smc_rcv( struct net_device *dev ); /* . This handles a TX interrupt, which is only called when an error . relating to a packet is sent. */ -inline static void smc_tx( struct net_device * dev ); +static inline void smc_tx( struct net_device * dev ); /* ------------------------------------------------------------ @@ -616,7 +616,7 @@ static void smc_hardware_send_packet( struct net_device * dev ) if ( packet_no & 0x80 ) { /* or isn't there? BAD CHIP! */ printk(KERN_DEBUG CARDNAME": Memory allocation failed. \n"); - dev_kfree_skb_irq(skb); + dev_kfree_skb_any(skb); lp->saved_skb = NULL; netif_wake_queue(dev); return; @@ -679,7 +679,7 @@ static void smc_hardware_send_packet( struct net_device * dev ) PRINTK2((CARDNAME": Sent packet of length %d \n",length)); lp->saved_skb = NULL; - dev_kfree_skb_irq (skb); + dev_kfree_skb_any (skb); dev->trans_start = jiffies; @@ -1341,9 +1341,9 @@ static void smc_rcv(struct net_device *dev) skb = dev_alloc_skb( packet_length + 5); if ( skb == NULL ) { - printk(KERN_NOTICE CARDNAME - ": Low memory, packet dropped.\n"); + printk(KERN_NOTICE CARDNAME ": Low memory, packet dropped.\n"); lp->stats.rx_dropped++; + goto done; } /* @@ -1396,11 +1396,10 @@ static void smc_rcv(struct net_device *dev) lp->stats.rx_length_errors++; if ( status & RS_BADCRC) lp->stats.rx_crc_errors++; } + +done: /* error or good, tell the card to get rid of this packet */ outw( MC_RELEASE, ioaddr + MMU_CMD ); - - - return; } diff --git a/drivers/net/sonic.h b/drivers/net/sonic.h index d070f06e3..5ef7689ef 100644 --- a/drivers/net/sonic.h +++ b/drivers/net/sonic.h @@ -445,7 +445,7 @@ typedef struct { struct sonic_local { sonic_cda_t cda; /* virtual CPU address of CDA */ sonic_td_t tda[SONIC_NUM_TDS]; /* transmit descriptor area */ - sonic_rr_t rra[SONIC_NUM_RRS]; /* receive resource arrea */ + sonic_rr_t rra[SONIC_NUM_RRS]; /* receive resource area */ sonic_rd_t rda[SONIC_NUM_RDS]; /* receive descriptor area */ struct sk_buff* tx_skb[SONIC_NUM_TDS]; /* skbuffs for packets to transmit */ unsigned int tx_laddr[SONIC_NUM_TDS]; /* logical DMA address fro skbuffs */ diff --git a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c index 08088fa96..b7e6083b4 100644 --- a/drivers/net/sun3lance.c +++ b/drivers/net/sun3lance.c @@ -148,9 +148,9 @@ struct lance_private { int new_rx, new_tx; /* The next free ring entry */ int old_tx, old_rx; /* ring entry to be processed */ struct net_device_stats stats; -/* These two must be ints for set_bit() */ - int tx_full; - int lock; +/* These two must be longs for set_bit() */ + long tx_full; + long lock; }; /* I/O register access macros */ @@ -303,8 +303,11 @@ static int __init lance_probe( struct net_device *dev) } init_etherdev( dev, sizeof(struct lance_private) ); - if (!dev->priv) + if (!dev->priv) { dev->priv = kmalloc( sizeof(struct lance_private), GFP_KERNEL ); + if (!dev->priv) + return 0; + } lp = (struct lance_private *)dev->priv; MEM = (struct lance_memory *)sun3_dvma_malloc(sizeof(struct lance_memory)); diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c index 6c3aa536a..3fc364fc1 100644 --- a/drivers/net/sunbmac.c +++ b/drivers/net/sunbmac.c @@ -1,4 +1,4 @@ -/* $Id: sunbmac.c,v 1.23 2001/01/20 03:36:40 davem Exp $ +/* $Id: sunbmac.c,v 1.25 2001/02/18 08:10:21 davem Exp $ * sunbmac.c: Driver for Sparc BigMAC 100baseT ethernet adapters. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com) @@ -902,19 +902,15 @@ static void bigmac_interrupt(int irq, void *dev_id, struct pt_regs *regs) static int bigmac_open(struct net_device *dev) { struct bigmac *bp = (struct bigmac *) dev->priv; - int res; + int ret; - if (request_irq(dev->irq, &bigmac_interrupt, - SA_SHIRQ, "BIG MAC", (void *) bp)) { + ret = request_irq(dev->irq, &bigmac_interrupt, SA_SHIRQ, dev->name, bp); + if (ret) { printk(KERN_ERR "BIGMAC: Can't order irq %d to go.\n", dev->irq); - return -EAGAIN; + return ret; } init_timer(&bp->bigmac_timer); - res = bigmac_init(bp, 0); - if (!res) { - MOD_INC_USE_COUNT; - } - return res; + return bigmac_init(bp, 0); } static int bigmac_close(struct net_device *dev) @@ -928,7 +924,6 @@ static int bigmac_close(struct net_device *dev) bigmac_stop(bp); bigmac_clean_rings(bp); free_irq(dev->irq, (void *)bp); - MOD_DEC_USE_COUNT; return 0; } @@ -1058,7 +1053,10 @@ static int __init bigmac_ether_init(struct net_device *dev, struct sbus_dev *qec int i; /* Get a new device struct for this interface. */ - dev = init_etherdev(0, sizeof(struct bigmac)); + dev = init_etherdev(NULL, sizeof(struct bigmac)); + if (!dev) + return -ENOMEM; + SET_MODULE_OWNER(dev); if (version_printed++ == 0) printk(KERN_INFO "%s", version); @@ -1075,7 +1073,7 @@ static int __init bigmac_ether_init(struct net_device *dev, struct sbus_dev *qec printk("\n"); /* Setup softc, with backpointers to QEC and BigMAC SBUS device structs. */ - bp = (struct bigmac *) dev->priv; + bp = dev->priv; bp->qec_sdev = qec_sdev; bp->bigmac_sdev = qec_sdev->child; diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index c3b7a4567..b99134da6 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c @@ -314,6 +314,7 @@ enum desc_status_bits { #define PRIV_ALIGN 15 /* Required alignment mask */ /* Use __attribute__((aligned (L1_CACHE_BYTES))) to maintain alignment within the structure. */ +#define MII_CNT 4 struct netdev_private { /* Descriptor rings first for alignment. */ struct netdev_desc rx_ring[RX_RING_SIZE]; @@ -346,7 +347,7 @@ struct netdev_private { /* MII transceiver section. */ int mii_cnt; /* MII device addresses. */ u16 advertising; /* NWay media advertisement */ - unsigned char phys[2]; /* MII device addresses. */ + unsigned char phys[MII_CNT]; /* MII device addresses, only first one used. */ }; /* The station address location in the EEPROM. */ @@ -379,7 +380,7 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev, struct netdev_private *np; static int card_idx; int chip_idx = ent->driver_data; - int irq = pdev->irq; + int irq; int i, option = card_idx < MAX_UNITS ? options[card_idx] : 0; long ioaddr; @@ -387,33 +388,28 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev, return -EIO; pci_set_master(pdev); - dev = init_etherdev(NULL, sizeof(*np)); + irq = pdev->irq; + + dev = alloc_etherdev(sizeof(*np)); if (!dev) return -ENOMEM; SET_MODULE_OWNER(dev); + if (pci_request_regions(pdev, "sundance")) + goto err_out_netdev; + #ifdef USE_IO_OPS ioaddr = pci_resource_start(pdev, 0); - if (!request_region(ioaddr, pci_id_tbl[chip_idx].io_size, dev->name)) - goto err_out_netdev; #else ioaddr = pci_resource_start(pdev, 1); - if (!request_mem_region(ioaddr, pci_id_tbl[chip_idx].io_size, dev->name)) - goto err_out_netdev; ioaddr = (long) ioremap (ioaddr, pci_id_tbl[chip_idx].io_size); if (!ioaddr) goto err_out_iomem; #endif - printk(KERN_INFO "%s: %s at 0x%lx, ", - dev->name, pci_id_tbl[chip_idx].name, ioaddr); - for (i = 0; i < 3; i++) ((u16 *)dev->dev_addr)[i] = le16_to_cpu(eeprom_read(ioaddr, i + EEPROM_SA_OFFSET)); - for (i = 0; i < 5; i++) - printk("%2.2x:", dev->dev_addr[i]); - printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); dev->base_addr = ioaddr; dev->irq = irq; @@ -453,10 +449,20 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev, if (mtu) dev->mtu = mtu; + i = register_netdev(dev); + if (i) + goto err_out_cleardev; + + printk(KERN_INFO "%s: %s at 0x%lx, ", + dev->name, pci_id_tbl[chip_idx].name, ioaddr); + for (i = 0; i < 5; i++) + printk("%2.2x:", dev->dev_addr[i]); + printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); + if (1) { int phy, phy_idx = 0; np->phys[0] = 1; /* Default setting */ - for (phy = 0; phy < 32 && phy_idx < 4; phy++) { + for (phy = 0; phy < 32 && phy_idx < MII_CNT; phy++) { int mii_status = mdio_read(dev, phy, 1); if (mii_status != 0xffff && mii_status != 0x0000) { np->phys[phy_idx++] = phy; @@ -483,13 +489,14 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev, card_idx++; return 0; +err_out_cleardev: + pci_set_drvdata(pdev, NULL); #ifndef USE_IO_OPS + iounmap((void *)ioaddr); err_out_iomem: - release_mem_region(pci_resource_start(pdev, 1), - pci_id_tbl[chip_idx].io_size); #endif + pci_release_regions(pdev); err_out_netdev: - unregister_netdev (dev); kfree (dev); return -ENODEV; } @@ -604,7 +611,7 @@ static void mdio_write(struct net_device *dev, int phy_id, int location, int val static int netdev_open(struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; int i; @@ -667,7 +674,7 @@ static int netdev_open(struct net_device *dev) static void check_duplex(struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; int mii_reg5 = mdio_read(dev, np->phys[0], 5); int negotiated = mii_reg5 & np->advertising; @@ -689,7 +696,7 @@ static void check_duplex(struct net_device *dev) static void netdev_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; int next_tick = 10*HZ; @@ -706,7 +713,7 @@ static void netdev_timer(unsigned long data) static void tx_timeout(struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; printk(KERN_WARNING "%s: Transmit timed out, status %2.2x," @@ -735,14 +742,16 @@ static void tx_timeout(struct net_device *dev) dev->trans_start = jiffies; np->stats.tx_errors++; - return; + + if (!np->tx_full) + netif_wake_queue(dev); } /* Initialize the Rx and Tx rings, along with various 'dev' bits. */ static void init_ring(struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; int i; np->tx_full = 0; @@ -784,7 +793,7 @@ static void init_ring(struct net_device *dev) static int start_tx(struct sk_buff *skb, struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; struct netdev_desc *txdesc; unsigned entry; @@ -838,7 +847,7 @@ static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) int boguscnt = max_interrupt_work; ioaddr = dev->base_addr; - np = (struct netdev_private *)dev->priv; + np = dev->priv; spin_lock(&np->lock); do { @@ -935,7 +944,7 @@ static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) for clarity and better register allocation. */ static int netdev_rx(struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; int entry = np->cur_rx % RX_RING_SIZE; int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx; @@ -1026,7 +1035,7 @@ static int netdev_rx(struct net_device *dev) static void netdev_error(struct net_device *dev, int intr_status) { long ioaddr = dev->base_addr; - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; if (intr_status & IntrDrvRqst) { /* Stop the down counter and turn interrupts back on. */ @@ -1055,7 +1064,7 @@ static void netdev_error(struct net_device *dev, int intr_status) static struct net_device_stats *get_stats(struct net_device *dev) { long ioaddr = dev->base_addr; - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; int i; /* We should lock this segment of code for SMP eventually, although @@ -1165,7 +1174,7 @@ static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) static int netdev_close(struct net_device *dev) { long ioaddr = dev->base_addr; - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; int i; netif_stop_queue(dev); @@ -1227,23 +1236,19 @@ static int netdev_close(struct net_device *dev) static void __devexit sundance_remove1 (struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; + struct net_device *dev = pci_get_drvdata(pdev); /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ while (dev) { - struct netdev_private *np = (void *)(dev->priv); unregister_netdev(dev); -#ifdef USE_IO_OPS - release_region(dev->base_addr, pci_id_tbl[np->chip_id].io_size); -#else - release_mem_region(pci_resource_start(pdev, 1), - pci_id_tbl[np->chip_id].io_size); + pci_release_regions(pdev); +#ifndef USE_IO_OPS iounmap((char *)(dev->base_addr)); #endif kfree(dev); } - pdev->driver_data = NULL; + pci_set_drvdata(pdev, NULL); } static struct pci_driver sundance_driver = { diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c new file mode 100644 index 000000000..5003724a6 --- /dev/null +++ b/drivers/net/sungem.c @@ -0,0 +1,1494 @@ +/* $Id: sungem.c,v 1.8 2001/03/22 22:48:51 davem Exp $ + * sungem.c: Sun GEM ethernet driver. + * + * Copyright (C) 2000, 2001 David S. Miller (davem@redhat.com) + */ + +#include <linux/module.h> + +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/types.h> +#include <linux/fcntl.h> +#include <linux/interrupt.h> +#include <linux/ptrace.h> +#include <linux/ioport.h> +#include <linux/in.h> +#include <linux/malloc.h> +#include <linux/string.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/pci.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> + +#include <asm/system.h> +#include <asm/bitops.h> +#include <asm/io.h> +#include <asm/byteorder.h> + +#ifdef __sparc__ +#include <asm/idprom.h> +#include <asm/openprom.h> +#include <asm/oplib.h> +#include <asm/pbm.h> +#endif + +#include "sungem.h" + +static char version[] __devinitdata = + "sungem.c:v0.75 21/Mar/01 David S. Miller (davem@redhat.com)\n"; + +MODULE_AUTHOR("David S. Miller (davem@redhat.com)"); +MODULE_DESCRIPTION("Sun GEM Gbit ethernet driver"); +MODULE_PARM(gem_debug, "i"); + +#define GEM_MODULE_NAME "gem" +#define PFX GEM_MODULE_NAME ": " + +#ifdef GEM_DEBUG +int gem_debug = GEM_DEBUG; +#else +int gem_debug = 1; +#endif + +static struct pci_device_id gem_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_GEM, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, + + /* These models only differ from the original GEM in + * that their tx/rx fifos are of a different size and + * they only support 10/100 speeds. -DaveM + */ + { PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_RIO_GEM, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, +#if 0 + /* Need to figure this one out. */ + { PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_PPC_GEM, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, +#endif + {0, } +}; + +MODULE_DEVICE_TABLE(pci, gem_pci_tbl); + +static u16 phy_read(struct gem *gp, int reg) +{ + u32 cmd; + int limit = 10000; + + cmd = (1 << 30); + cmd |= (2 << 28); + cmd |= (gp->mii_phy_addr << 23) & MIF_FRAME_PHYAD; + cmd |= (reg << 18) & MIF_FRAME_REGAD; + cmd |= (MIF_FRAME_TAMSB); + writel(cmd, gp->regs + MIF_FRAME); + + while (limit--) { + cmd = readl(gp->regs + MIF_FRAME); + if (cmd & MIF_FRAME_TALSB) + break; + + udelay(10); + } + + if (!limit) + cmd = 0xffff; + + return cmd & MIF_FRAME_DATA; +} + +static void phy_write(struct gem *gp, int reg, u16 val) +{ + u32 cmd; + int limit = 10000; + + cmd = (1 << 30); + cmd |= (1 << 28); + cmd |= (gp->mii_phy_addr << 23) & MIF_FRAME_PHYAD; + cmd |= (reg << 18) & MIF_FRAME_REGAD; + cmd |= (MIF_FRAME_TAMSB); + cmd |= (val & MIF_FRAME_DATA); + writel(cmd, gp->regs + MIF_FRAME); + + while (limit--) { + cmd = readl(gp->regs + MIF_FRAME); + if (cmd & MIF_FRAME_TALSB) + break; + + udelay(10); + } +} + +static void gem_handle_mif_event(struct gem *gp, u32 reg_val, u32 changed_bits) +{ +} + +static int gem_pcs_interrupt(struct net_device *dev, struct gem *gp, u32 gem_status) +{ + u32 pcs_istat = readl(gp->regs + PCS_ISTAT); + u32 pcs_miistat; + + if (!(pcs_istat & PCS_ISTAT_LSC)) { + printk(KERN_ERR "%s: PCS irq but no link status change???\n", + dev->name); + return 0; + } + + /* The link status bit latches on zero, so you must + * read it twice in such a case to see a transition + * to the link being up. + */ + pcs_miistat = readl(gp->regs + PCS_MIISTAT); + if (!(pcs_miistat & PCS_MIISTAT_LS)) + pcs_miistat |= + (readl(gp->regs + PCS_MIISTAT) & + PCS_MIISTAT_LS); + + if (pcs_miistat & PCS_MIISTAT_ANC) { + /* The remote-fault indication is only valid + * when autoneg has completed. + */ + if (pcs_miistat & PCS_MIISTAT_RF) + printk(KERN_INFO "%s: PCS AutoNEG complete, " + "RemoteFault\n", dev->name); + else + printk(KERN_INFO "%s: PCS AutoNEG complete.\n", + dev->name); + } + + if (pcs_miistat & PCS_MIISTAT_LS) + printk(KERN_INFO "%s: PCS link is now up.\n", + dev->name); + else + printk(KERN_INFO "%s: PCS link is now down.\n", + dev->name); + + return 0; +} + +static int gem_txmac_interrupt(struct net_device *dev, struct gem *gp, u32 gem_status) +{ + u32 txmac_stat = readl(gp->regs + MAC_TXSTAT); + + /* Defer timer expiration is quite normal, + * don't even log the event. + */ + if ((txmac_stat & MAC_TXSTAT_DTE) && + !(txmac_stat & ~MAC_TXSTAT_DTE)) + return 0; + + if (txmac_stat & MAC_TXSTAT_URUN) { + printk("%s: TX MAC xmit underrun.\n", + dev->name); + gp->net_stats.tx_fifo_errors++; + } + + if (txmac_stat & MAC_TXSTAT_MPE) { + printk("%s: TX MAC max packet size error.\n", + dev->name); + gp->net_stats.tx_errors++; + } + + /* The rest are all cases of one of the 16-bit TX + * counters expiring. + */ + if (txmac_stat & MAC_TXSTAT_NCE) + gp->net_stats.collisions += 0x10000; + + if (txmac_stat & MAC_TXSTAT_ECE) { + gp->net_stats.tx_aborted_errors += 0x10000; + gp->net_stats.collisions += 0x10000; + } + + if (txmac_stat & MAC_TXSTAT_LCE) { + gp->net_stats.tx_aborted_errors += 0x10000; + gp->net_stats.collisions += 0x10000; + } + + /* We do not keep track of MAC_TXSTAT_FCE and + * MAC_TXSTAT_PCE events. + */ + return 0; +} + +static int gem_rxmac_interrupt(struct net_device *dev, struct gem *gp, u32 gem_status) +{ + u32 rxmac_stat = readl(gp->regs + MAC_RXSTAT); + + if (rxmac_stat & MAC_RXSTAT_OFLW) { + printk("%s: RX MAC fifo overflow.\n", + dev->name); + gp->net_stats.rx_over_errors++; + gp->net_stats.rx_fifo_errors++; + } + + if (rxmac_stat & MAC_RXSTAT_ACE) + gp->net_stats.rx_frame_errors += 0x10000; + + if (rxmac_stat & MAC_RXSTAT_CCE) + gp->net_stats.rx_crc_errors += 0x10000; + + if (rxmac_stat & MAC_RXSTAT_LCE) + gp->net_stats.rx_length_errors += 0x10000; + + /* We do not track MAC_RXSTAT_FCE and MAC_RXSTAT_VCE + * events. + */ + return 0; +} + +static int gem_mac_interrupt(struct net_device *dev, struct gem *gp, u32 gem_status) +{ + u32 mac_cstat = readl(gp->regs + MAC_CSTAT); + + /* This interrupt is just for pause frame and pause + * tracking. It is useful for diagnostics and debug + * but probably by default we will mask these events. + */ + if (mac_cstat & MAC_CSTAT_PS) + gp->pause_entered++; + + if (mac_cstat & MAC_CSTAT_PRCV) + gp->pause_last_time_recvd = (mac_cstat >> 16); + + return 0; +} + +static int gem_mif_interrupt(struct net_device *dev, struct gem *gp, u32 gem_status) +{ + u32 mif_status = readl(gp->regs + MIF_STATUS); + u32 reg_val, changed_bits; + + reg_val = (mif_status & MIF_STATUS_DATA) >> 16; + changed_bits = (mif_status & MIF_STATUS_STAT); + + gem_handle_mif_event(gp, reg_val, changed_bits); + + return 0; +} + +static int gem_pci_interrupt(struct net_device *dev, struct gem *gp, u32 gem_status) +{ + u32 pci_estat = readl(gp->regs + GREG_PCIESTAT); + + if (gp->pdev->device == PCI_DEVICE_ID_SUN_GEM) { + printk(KERN_ERR "%s: PCI error [%04x] ", + dev->name, pci_estat); + + if (pci_estat & GREG_PCIESTAT_BADACK) + printk("<No ACK64# during ABS64 cycle> "); + if (pci_estat & GREG_PCIESTAT_DTRTO) + printk("<Delayed transaction timeout> "); + if (pci_estat & GREG_PCIESTAT_OTHER) + printk("<other>"); + printk("\n"); + } else { + pci_estat |= GREG_PCIESTAT_OTHER; + printk(KERN_ERR "%s: PCI error\n", dev->name); + } + + if (pci_estat & GREG_PCIESTAT_OTHER) { + u16 pci_cfg_stat; + + /* Interrogate PCI config space for the + * true cause. + */ + pci_read_config_word(gp->pdev, PCI_STATUS, + &pci_cfg_stat); + printk(KERN_ERR "%s: Read PCI cfg space status [%04x]\n", + dev->name, pci_cfg_stat); + if (pci_cfg_stat & PCI_STATUS_PARITY) + printk(KERN_ERR "%s: PCI parity error detected.\n", + dev->name); + if (pci_cfg_stat & PCI_STATUS_SIG_TARGET_ABORT) + printk(KERN_ERR "%s: PCI target abort.\n", + dev->name); + if (pci_cfg_stat & PCI_STATUS_REC_TARGET_ABORT) + printk(KERN_ERR "%s: PCI master acks target abort.\n", + dev->name); + if (pci_cfg_stat & PCI_STATUS_REC_MASTER_ABORT) + printk(KERN_ERR "%s: PCI master abort.\n", + dev->name); + if (pci_cfg_stat & PCI_STATUS_SIG_SYSTEM_ERROR) + printk(KERN_ERR "%s: PCI system error SERR#.\n", + dev->name); + if (pci_cfg_stat & PCI_STATUS_DETECTED_PARITY) + printk(KERN_ERR "%s: PCI parity error.\n", + dev->name); + + /* Write the error bits back to clear them. */ + pci_cfg_stat &= (PCI_STATUS_PARITY | + PCI_STATUS_SIG_TARGET_ABORT | + PCI_STATUS_REC_TARGET_ABORT | + PCI_STATUS_REC_MASTER_ABORT | + PCI_STATUS_SIG_SYSTEM_ERROR | + PCI_STATUS_DETECTED_PARITY); + pci_write_config_word(gp->pdev, + PCI_STATUS, pci_cfg_stat); + } + + /* For all PCI errors, we should reset the chip. */ + return 1; +} + +static void gem_stop(struct gem *, unsigned long); +static void gem_init_rings(struct gem *, int); +static void gem_init_hw(struct gem *); + +/* All non-normal interrupt conditions get serviced here. + * Returns non-zero if we should just exit the interrupt + * handler right now (ie. if we reset the card which invalidates + * all of the other original irq status bits). + */ +static int gem_abnormal_irq(struct net_device *dev, struct gem *gp, u32 gem_status) +{ + if (gem_status & GREG_STAT_RXNOBUF) { + /* Frame arrived, no free RX buffers available. */ + gp->net_stats.rx_dropped++; + } + + if (gem_status & GREG_STAT_RXTAGERR) { + /* corrupt RX tag framing */ + gp->net_stats.rx_errors++; + + goto do_reset; + } + + if (gem_status & GREG_STAT_PCS) { + if (gem_pcs_interrupt(dev, gp, gem_status)) + goto do_reset; + } + + if (gem_status & GREG_STAT_TXMAC) { + if (gem_txmac_interrupt(dev, gp, gem_status)) + goto do_reset; + } + + if (gem_status & GREG_STAT_RXMAC) { + if (gem_rxmac_interrupt(dev, gp, gem_status)) + goto do_reset; + } + + if (gem_status & GREG_STAT_MAC) { + if (gem_mac_interrupt(dev, gp, gem_status)) + goto do_reset; + } + + if (gem_status & GREG_STAT_MIF) { + if (gem_mif_interrupt(dev, gp, gem_status)) + goto do_reset; + } + + if (gem_status & GREG_STAT_PCIERR) { + if (gem_pci_interrupt(dev, gp, gem_status)) + goto do_reset; + } + + return 0; + +do_reset: + gem_stop(gp, gp->regs); + gem_init_rings(gp, 1); + gem_init_hw(gp); + return 1; +} + +static __inline__ void gem_tx(struct net_device *dev, struct gem *gp, u32 gem_status) +{ + int entry, limit; + + entry = gp->tx_old; + limit = ((gem_status & GREG_STAT_TXNR) >> GREG_STAT_TXNR_SHIFT); + while (entry != limit) { + struct sk_buff *skb; + struct gem_txd *txd; + u32 dma_addr; + + txd = &gp->init_block->txd[entry]; + skb = gp->tx_skbs[entry]; + dma_addr = (u32) le64_to_cpu(txd->buffer); + pci_unmap_single(gp->pdev, dma_addr, + skb->len, PCI_DMA_TODEVICE); + gp->tx_skbs[entry] = NULL; + + gp->net_stats.tx_bytes += skb->len; + gp->net_stats.tx_packets++; + + dev_kfree_skb_irq(skb); + + entry = NEXT_TX(entry); + } + gp->tx_old = entry; + + if (netif_queue_stopped(dev) && + TX_BUFFS_AVAIL(gp) > 0) + netif_wake_queue(dev); +} + +static __inline__ void gem_post_rxds(struct gem *gp, int limit) +{ + int cluster_start, curr, count, kick; + + cluster_start = curr = (gp->rx_new & ~(4 - 1)); + count = 0; + kick = -1; + while (curr != limit) { + curr = NEXT_RX(curr); + if (++count == 4) { + struct gem_rxd *rxd = + &gp->init_block->rxd[cluster_start]; + for (;;) { + rxd->status_word = cpu_to_le64(RXDCTRL_FRESH); + rxd++; + cluster_start = NEXT_RX(cluster_start); + if (cluster_start == curr) + break; + } + kick = curr; + count = 0; + } + } + if (kick >= 0) + writel(kick, gp->regs + RXDMA_KICK); +} + +static void gem_rx(struct gem *gp) +{ + int entry, drops; + + entry = gp->rx_new; + drops = 0; + for (;;) { + struct gem_rxd *rxd = &gp->init_block->rxd[entry]; + struct sk_buff *skb; + u64 status = cpu_to_le64(rxd->status_word); + u32 dma_addr; + int len; + + if ((status & RXDCTRL_OWN) != 0) + break; + + skb = gp->rx_skbs[entry]; + + len = (status & RXDCTRL_BUFSZ) >> 16; + if ((len < ETH_ZLEN) || (status & RXDCTRL_BAD)) { + gp->net_stats.rx_errors++; + if (len < ETH_ZLEN) + gp->net_stats.rx_length_errors++; + if (len & RXDCTRL_BAD) + gp->net_stats.rx_crc_errors++; + + /* We'll just return it to GEM. */ + drop_it: + gp->net_stats.rx_dropped++; + goto next; + } + + dma_addr = (u32) cpu_to_le64(rxd->buffer); + if (len > RX_COPY_THRESHOLD) { + struct sk_buff *new_skb; + + new_skb = gem_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC); + if (new_skb == NULL) { + drops++; + goto drop_it; + } + pci_unmap_single(gp->pdev, dma_addr, + RX_BUF_ALLOC_SIZE, PCI_DMA_FROMDEVICE); + gp->rx_skbs[entry] = new_skb; + new_skb->dev = gp->dev; + skb_put(new_skb, (ETH_FRAME_LEN + RX_OFFSET)); + rxd->buffer = cpu_to_le64(pci_map_single(gp->pdev, + new_skb->data, + RX_BUF_ALLOC_SIZE, + PCI_DMA_FROMDEVICE)); + skb_reserve(new_skb, RX_OFFSET); + + /* Trim the original skb for the netif. */ + skb_trim(skb, len); + } else { + struct sk_buff *copy_skb = dev_alloc_skb(len + 2); + + if (copy_skb == NULL) { + drops++; + goto drop_it; + } + + copy_skb->dev = gp->dev; + skb_reserve(copy_skb, 2); + skb_put(copy_skb, len); + pci_dma_sync_single(gp->pdev, dma_addr, len, PCI_DMA_FROMDEVICE); + memcpy(copy_skb->data, skb->data, len); + + /* We'll reuse the original ring buffer. */ + skb = copy_skb; + } + + skb->protocol = eth_type_trans(skb, gp->dev); + netif_rx(skb); + + gp->net_stats.rx_packets++; + gp->net_stats.rx_bytes += len; + + next: + entry = NEXT_RX(entry); + } + + gem_post_rxds(gp, entry); + + gp->rx_new = entry; + + if (drops) + printk(KERN_INFO "%s: Memory squeeze, deferring packet.\n", + gp->dev->name); +} + +static void gem_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *) dev_id; + struct gem *gp = (struct gem *) dev->priv; + u32 gem_status = readl(gp->regs + GREG_STAT); + + spin_lock(&gp->lock); + + if (gem_status & GREG_STAT_ABNORMAL) { + if (gem_abnormal_irq(dev, gp, gem_status)) + goto out; + } + if (gem_status & (GREG_STAT_TXALL | GREG_STAT_TXINTME)) + gem_tx(dev, gp, gem_status); + if (gem_status & GREG_STAT_RXDONE) + gem_rx(gp); + +out: + spin_unlock(&gp->lock); +} + +static int gem_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct gem *gp = (struct gem *) dev->priv; + long len; + int entry, avail; + u32 mapping; + + len = skb->len; + mapping = pci_map_single(gp->pdev, skb->data, len, PCI_DMA_TODEVICE); + + spin_lock_irq(&gp->lock); + entry = gp->tx_new; + gp->tx_skbs[entry] = skb; + + gp->tx_new = NEXT_TX(entry); + avail = TX_BUFFS_AVAIL(gp); + if (avail <= 0) + netif_stop_queue(dev); + + { + struct gem_txd *txd = &gp->init_block->txd[entry]; + u64 ctrl = (len & TXDCTRL_BUFSZ) | TXDCTRL_EOF | TXDCTRL_SOF; + + txd->control_word = cpu_to_le64(ctrl); + txd->buffer = cpu_to_le64(mapping); + } + + writel(gp->tx_new, gp->regs + TXDMA_KICK); + spin_unlock_irq(&gp->lock); + + dev->trans_start = jiffies; + + return 0; +} + +#define STOP_TRIES 32 + +static void gem_stop(struct gem *gp, unsigned long regs) +{ + int limit; + u32 val; + + writel(GREG_SWRST_TXRST | GREG_SWRST_RXRST, regs + GREG_SWRST); + + limit = STOP_TRIES; + + do { + udelay(20); + val = readl(regs + GREG_SWRST); + if (limit-- <= 0) + break; + } while (val & (GREG_SWRST_TXRST | GREG_SWRST_RXRST)); + + if (limit <= 0) + printk(KERN_ERR "gem: SW reset is ghetto.\n"); +} + +/* A link-up condition has occurred, initialize and enable the + * rest of the chip. + */ +static void gem_set_link_modes(struct gem *gp) +{ + u32 val; + int full_duplex, speed; + + full_duplex = 0; + speed = 10; + if (gp->phy_type == phy_mii_mdio0 || + gp->phy_type == phy_mii_mdio1) { + if (gp->lstate == aneg_wait) { + val = phy_read(gp, PHY_LPA); + if (val & (PHY_LPA_10FULL | PHY_LPA_100FULL)) + full_duplex = 1; + if (val & (PHY_LPA_100FULL | PHY_LPA_100HALF)) + speed = 100; + } else { + val = phy_read(gp, PHY_CTRL); + if (val & PHY_CTRL_FDPLX) + full_duplex = 1; + if (val & PHY_CTRL_SPD100) + speed = 100; + } + } else { + u32 pcs_lpa = readl(gp->regs + PCS_MIILP); + + if (pcs_lpa & PCS_MIIADV_FD) + full_duplex = 1; + speed = 1000; + } + + printk(KERN_INFO "%s: Link is up at %d Mbps, %s-duplex.\n", + gp->dev->name, speed, (full_duplex ? "full" : "half")); + + val = (MAC_TXCFG_EIPG0 | MAC_TXCFG_NGU); + if (full_duplex) { + val |= (MAC_TXCFG_ICS | MAC_TXCFG_ICOLL); + } else { + /* MAC_TXCFG_NBO must be zero. */ + } + writel(val, gp->regs + MAC_TXCFG); + + val = (MAC_XIFCFG_OE | MAC_XIFCFG_LLED); + if (!full_duplex && + (gp->phy_type == phy_mii_mdio0 || + gp->phy_type == phy_mii_mdio1)) { + val |= MAC_XIFCFG_DISE; + } else if (full_duplex) { + val |= MAC_XIFCFG_FLED; + } + writel(val, gp->regs + MAC_XIFCFG); + + if (gp->phy_type == phy_serialink || + gp->phy_type == phy_serdes) { + u32 pcs_lpa = readl(gp->regs + PCS_MIILP); + + val = readl(gp->regs + MAC_MCCFG); + if (pcs_lpa & (PCS_MIIADV_SP | PCS_MIIADV_AP)) + val |= (MAC_MCCFG_SPE | MAC_MCCFG_RPE); + else + val &= ~(MAC_MCCFG_SPE | MAC_MCCFG_RPE); + writel(val, gp->regs + MAC_MCCFG); + + /* XXX Set up PCS MII Control and Serialink Control + * XXX registers. + */ + + if (!full_duplex) + writel(512, gp->regs + MAC_STIME); + else + writel(64, gp->regs + MAC_STIME); + } else { + /* Set slot-time of 64. */ + writel(64, gp->regs + MAC_STIME); + } + + /* We are ready to rock, turn everything on. */ + val = readl(gp->regs + TXDMA_CFG); + writel(val | TXDMA_CFG_ENABLE, gp->regs + TXDMA_CFG); + val = readl(gp->regs + RXDMA_CFG); + writel(val | RXDMA_CFG_ENABLE, gp->regs + RXDMA_CFG); + val = readl(gp->regs + MAC_TXCFG); + writel(val | MAC_TXCFG_ENAB, gp->regs + MAC_TXCFG); + val = readl(gp->regs + MAC_RXCFG); + writel(val | MAC_RXCFG_ENAB, gp->regs + MAC_RXCFG); +} + +static int gem_mdio_link_not_up(struct gem *gp) +{ + if (gp->lstate == aneg_wait) { + u16 val = phy_read(gp, PHY_CTRL); + + /* Try forced modes. */ + val &= ~(PHY_CTRL_ANRES | PHY_CTRL_ANENAB); + val &= ~(PHY_CTRL_FDPLX); + val |= PHY_CTRL_SPD100; + phy_write(gp, PHY_CTRL, val); + gp->timer_ticks = 0; + gp->lstate = force_wait; + return 1; + } else { + /* Downgrade from 100 to 10 Mbps if necessary. + * If already at 10Mbps, warn user about the + * situation every 10 ticks. + */ + u16 val = phy_read(gp, PHY_CTRL); + if (val & PHY_CTRL_SPD100) { + val &= ~PHY_CTRL_SPD100; + phy_write(gp, PHY_CTRL, val); + gp->timer_ticks = 0; + return 1; + } else { + printk(KERN_ERR "%s: Link down, cable problem?\n", + gp->dev->name); + val |= (PHY_CTRL_ANRES | PHY_CTRL_ANENAB); + phy_write(gp, PHY_CTRL, val); + gp->timer_ticks = 1; + gp->lstate = aneg_wait; + return 1; + } + } +} + +static void gem_link_timer(unsigned long data) +{ + struct gem *gp = (struct gem *) data; + int restart_timer = 0; + + gp->timer_ticks++; + if (gp->phy_type == phy_mii_mdio0 || + gp->phy_type == phy_mii_mdio1) { + u16 val = phy_read(gp, PHY_STAT); + + if (val & PHY_STAT_LSTAT) { + gem_set_link_modes(gp); + } else if (gp->timer_ticks < 10) { + restart_timer = 1; + } else { + restart_timer = gem_mdio_link_not_up(gp); + } + } else { + /* XXX Code PCS support... XXX */ + } + + if (restart_timer) { + gp->link_timer.expires = jiffies + ((12 * HZ) / 10); + add_timer(&gp->link_timer); + } +} + +static void gem_clean_rings(struct gem *gp) +{ + struct gem_init_block *gb = gp->init_block; + struct sk_buff *skb; + int i; + u32 dma_addr; + + for (i = 0; i < RX_RING_SIZE; i++) { + struct gem_rxd *rxd; + + rxd = &gb->rxd[i]; + if (gp->rx_skbs[i] != NULL) { + + skb = gp->rx_skbs[i]; + dma_addr = (u32) le64_to_cpu(rxd->buffer); + pci_unmap_single(gp->pdev, dma_addr, + RX_BUF_ALLOC_SIZE, + PCI_DMA_FROMDEVICE); + dev_kfree_skb_any(skb); + gp->rx_skbs[i] = NULL; + } + rxd->status_word = 0; + rxd->buffer = 0; + } + + for (i = 0; i < TX_RING_SIZE; i++) { + if (gp->tx_skbs[i] != NULL) { + struct gem_txd *txd; + + skb = gp->tx_skbs[i]; + txd = &gb->txd[i]; + dma_addr = (u32) le64_to_cpu(txd->buffer); + pci_unmap_single(gp->pdev, dma_addr, + skb->len, PCI_DMA_TODEVICE); + dev_kfree_skb_any(skb); + gp->tx_skbs[i] = NULL; + } + } +} + +static void gem_init_rings(struct gem *gp, int from_irq) +{ + struct gem_init_block *gb = gp->init_block; + struct net_device *dev = gp->dev; + int i, gfp_flags = GFP_KERNEL; + u32 dma_addr; + + if (from_irq) + gfp_flags = GFP_ATOMIC; + + gp->rx_new = gp->rx_old = gp->tx_new = gp->tx_old = 0; + + gem_clean_rings(gp); + + for (i = 0; i < RX_RING_SIZE; i++) { + struct sk_buff *skb; + struct gem_rxd *rxd = &gb->rxd[i]; + + skb = gem_alloc_skb(RX_BUF_ALLOC_SIZE, gfp_flags); + if (!skb) { + rxd->buffer = 0; + rxd->status_word = 0; + continue; + } + + gp->rx_skbs[i] = skb; + skb->dev = dev; + skb_put(skb, (ETH_FRAME_LEN + RX_OFFSET)); + dma_addr = pci_map_single(gp->pdev, skb->data, + RX_BUF_ALLOC_SIZE, + PCI_DMA_FROMDEVICE); + rxd->buffer = cpu_to_le64(dma_addr); + rxd->status_word = cpu_to_le64(RXDCTRL_FRESH); + skb_reserve(skb, RX_OFFSET); + } + + for (i = 0; i < TX_RING_SIZE; i++) { + struct gem_txd *txd = &gb->txd[i]; + + txd->control_word = 0; + txd->buffer = 0; + } +} + +static void gem_init_phy(struct gem *gp) +{ + if (gp->pdev->device == PCI_DEVICE_ID_SUN_GEM) { + /* Init datapath mode register. */ + if (gp->phy_type == phy_mii_mdio0 || + gp->phy_type == phy_mii_mdio1) { + writel(PCS_DMODE_MGM, gp->regs + PCS_DMODE); + } else if (gp->phy_type == phy_serialink) { + writel(PCS_DMODE_SM, gp->regs + PCS_DMODE); + } else { + writel(PCS_DMODE_ESM, gp->regs + PCS_DMODE); + } + } + + if (gp->phy_type == phy_mii_mdio0 || + gp->phy_type == phy_mii_mdio1) { + u16 val = phy_read(gp, PHY_CTRL); + int limit = 10000; + + /* Take PHY out of isloate mode and reset it. */ + val &= ~PHY_CTRL_ISO; + val |= PHY_CTRL_RST; + phy_write(gp, PHY_CTRL, val); + + while (limit--) { + val = phy_read(gp, PHY_CTRL); + if ((val & PHY_CTRL_RST) == 0) + break; + udelay(10); + } + + /* Init advertisement and enable autonegotiation. */ + phy_write(gp, PHY_ADV, + (PHY_ADV_10HALF | PHY_ADV_10FULL | + PHY_ADV_100HALF | PHY_ADV_100FULL)); + + val |= (PHY_CTRL_ANRES | PHY_CTRL_ANENAB); + phy_write(gp, PHY_CTRL, val); + } else { + /* XXX Implement me XXX */ + } +} + +static void gem_init_dma(struct gem *gp) +{ + u32 val; + + val = (TXDMA_CFG_BASE | (0x4ff << 10) | TXDMA_CFG_PMODE); + writel(val, gp->regs + TXDMA_CFG); + + writel(0, gp->regs + TXDMA_DBHI); + writel(gp->gblock_dvma, gp->regs + TXDMA_DBLOW); + + writel(0, gp->regs + TXDMA_KICK); + + val = (RXDMA_CFG_BASE | (RX_OFFSET << 10) | + ((14 / 2) << 13) | RXDMA_CFG_FTHRESH_128); + writel(val, gp->regs + RXDMA_CFG); + + writel(0, gp->regs + RXDMA_DBHI); + writel((gp->gblock_dvma + + (TX_RING_SIZE * sizeof(struct gem_txd))), + gp->regs + RXDMA_DBLOW); + + writel(RX_RING_SIZE - 4, gp->regs + RXDMA_KICK); + + val = (((gp->rx_pause_off / 64) << 0) & RXDMA_PTHRESH_OFF); + val |= (((gp->rx_pause_on / 64) << 12) & RXDMA_PTHRESH_ON); + writel(val, gp->regs + RXDMA_PTHRESH); + + if (readl(gp->regs + GREG_BIFCFG) & GREG_BIFCFG_M66EN) + writel(((5 & RXDMA_BLANK_IPKTS) | + ((8 << 12) & RXDMA_BLANK_ITIME)), + gp->regs + RXDMA_BLANK); + else + writel(((5 & RXDMA_BLANK_IPKTS) | + ((4 << 12) & RXDMA_BLANK_ITIME)), + gp->regs + RXDMA_BLANK); +} + +#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */ + +static void gem_init_mac(struct gem *gp) +{ + unsigned char *e = &gp->dev->dev_addr[0]; + u32 rxcfg; + + if (gp->pdev->device == PCI_DEVICE_ID_SUN_GEM) + writel(0x1bf0, gp->regs + MAC_SNDPAUSE); + + writel(0x00, gp->regs + MAC_IPG0); + writel(0x08, gp->regs + MAC_IPG1); + writel(0x04, gp->regs + MAC_IPG2); + writel(0x40, gp->regs + MAC_STIME); + writel(0x40, gp->regs + MAC_MINFSZ); + writel(0x5ee, gp->regs + MAC_MAXFSZ); + writel(0x07, gp->regs + MAC_PASIZE); + writel(0x04, gp->regs + MAC_JAMSIZE); + writel(0x10, gp->regs + MAC_ATTLIM); + writel(0x8808, gp->regs + MAC_MCTYPE); + + writel((e[5] | (e[4] << 8)) & 0x3ff, gp->regs + MAC_RANDSEED); + + writel((e[4] << 8) | e[5], gp->regs + MAC_ADDR0); + writel((e[2] << 8) | e[3], gp->regs + MAC_ADDR1); + writel((e[0] << 8) | e[1], gp->regs + MAC_ADDR2); + + writel(0, gp->regs + MAC_ADDR3); + writel(0, gp->regs + MAC_ADDR4); + writel(0, gp->regs + MAC_ADDR5); + + writel(0x0001, gp->regs + MAC_ADDR6); + writel(0xc200, gp->regs + MAC_ADDR7); + writel(0x0180, gp->regs + MAC_ADDR8); + + writel(0, gp->regs + MAC_AFILT0); + writel(0, gp->regs + MAC_AFILT1); + writel(0, gp->regs + MAC_AFILT2); + writel(0, gp->regs + MAC_AF21MSK); + writel(0, gp->regs + MAC_AF0MSK); + + rxcfg = 0; + if ((gp->dev->flags & IFF_ALLMULTI) || + (gp->dev->mc_count > 256)) { + writel(0xffff, gp->regs + MAC_HASH0); + writel(0xffff, gp->regs + MAC_HASH1); + writel(0xffff, gp->regs + MAC_HASH2); + writel(0xffff, gp->regs + MAC_HASH3); + writel(0xffff, gp->regs + MAC_HASH4); + writel(0xffff, gp->regs + MAC_HASH5); + writel(0xffff, gp->regs + MAC_HASH6); + writel(0xffff, gp->regs + MAC_HASH7); + writel(0xffff, gp->regs + MAC_HASH8); + writel(0xffff, gp->regs + MAC_HASH9); + writel(0xffff, gp->regs + MAC_HASH10); + writel(0xffff, gp->regs + MAC_HASH11); + writel(0xffff, gp->regs + MAC_HASH12); + writel(0xffff, gp->regs + MAC_HASH13); + writel(0xffff, gp->regs + MAC_HASH14); + writel(0xffff, gp->regs + MAC_HASH15); + } else if (gp->dev->flags & IFF_PROMISC) { + rxcfg |= MAC_RXCFG_PROM; + } else { + u16 hash_table[16]; + u32 crc, poly = CRC_POLYNOMIAL_LE; + struct dev_mc_list *dmi = gp->dev->mc_list; + int i, j, bit, byte; + + for (i = 0; i < 16; i++) + hash_table[i] = 0; + + for (i = 0; i < gp->dev->mc_count; i++) { + char *addrs = dmi->dmi_addr; + + dmi = dmi->next; + + if (!(*addrs & 1)) + continue; + + crc = 0xffffffffU; + for (byte = 0; byte < 6; byte++) { + for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) { + int test; + + test = ((bit ^ crc) & 0x01); + crc >>= 1; + if (test) + crc = crc ^ poly; + } + } + crc >>= 24; + hash_table[crc >> 4] |= 1 << (crc & 0xf); + } + writel(hash_table[0], gp->regs + MAC_HASH0); + writel(hash_table[1], gp->regs + MAC_HASH1); + writel(hash_table[2], gp->regs + MAC_HASH2); + writel(hash_table[3], gp->regs + MAC_HASH3); + writel(hash_table[4], gp->regs + MAC_HASH4); + writel(hash_table[5], gp->regs + MAC_HASH5); + writel(hash_table[6], gp->regs + MAC_HASH6); + writel(hash_table[7], gp->regs + MAC_HASH7); + writel(hash_table[8], gp->regs + MAC_HASH8); + writel(hash_table[9], gp->regs + MAC_HASH9); + writel(hash_table[10], gp->regs + MAC_HASH10); + writel(hash_table[11], gp->regs + MAC_HASH11); + writel(hash_table[12], gp->regs + MAC_HASH12); + writel(hash_table[13], gp->regs + MAC_HASH13); + writel(hash_table[14], gp->regs + MAC_HASH14); + writel(hash_table[15], gp->regs + MAC_HASH15); + } + + writel(0, gp->regs + MAC_NCOLL); + writel(0, gp->regs + MAC_FASUCC); + writel(0, gp->regs + MAC_ECOLL); + writel(0, gp->regs + MAC_LCOLL); + writel(0, gp->regs + MAC_DTIMER); + writel(0, gp->regs + MAC_PATMPS); + writel(0, gp->regs + MAC_RFCTR); + writel(0, gp->regs + MAC_LERR); + writel(0, gp->regs + MAC_AERR); + writel(0, gp->regs + MAC_FCSERR); + writel(0, gp->regs + MAC_RXCVERR); + + /* Clear RX/TX/MAC/XIF config, we will set these up and enable + * them once a link is established. + */ + writel(0, gp->regs + MAC_TXCFG); + writel(rxcfg, gp->regs + MAC_RXCFG); + writel(0, gp->regs + MAC_MCCFG); + writel(0, gp->regs + MAC_XIFCFG); + + writel((MAC_TXSTAT_URUN | MAC_TXSTAT_MPE | + MAC_TXSTAT_NCE | MAC_TXSTAT_ECE | + MAC_TXSTAT_LCE | MAC_TXSTAT_FCE | + MAC_TXSTAT_DTE | MAC_TXSTAT_PCE), gp->regs + MAC_TXMASK); + writel((MAC_RXSTAT_OFLW | MAC_RXSTAT_FCE | + MAC_RXSTAT_ACE | MAC_RXSTAT_CCE | + MAC_RXSTAT_LCE | MAC_RXSTAT_VCE), gp->regs + MAC_RXMASK); + writel(0, gp->regs + MAC_MCMASK); +} + +static void gem_init_hw(struct gem *gp) +{ + gem_init_phy(gp); + gem_init_dma(gp); + gem_init_mac(gp); + + writel(GREG_STAT_TXDONE, gp->regs + GREG_IMASK); + + gp->timer_ticks = 0; + gp->lstate = aneg_wait; + gp->link_timer.expires = jiffies + ((12 * HZ) / 10); + add_timer(&gp->link_timer); +} + +static int gem_open(struct net_device *dev) +{ + struct gem *gp = (struct gem *) dev->priv; + unsigned long regs = gp->regs; + + del_timer(&gp->link_timer); + + if (request_irq(gp->pdev->irq, gem_interrupt, + SA_SHIRQ, dev->name, (void *)dev)) + return -EAGAIN; + + gem_stop(gp, regs); + gem_init_rings(gp, 0); + gem_init_hw(gp); + + return 0; +} + +static int gem_close(struct net_device *dev) +{ + struct gem *gp = dev->priv; + + free_irq(gp->pdev->irq, (void *)dev); + return 0; +} + +static struct net_device_stats *gem_get_stats(struct net_device *dev) +{ + struct gem *gp = dev->priv; + struct net_device_stats *stats = &gp->net_stats; + + stats->rx_crc_errors += readl(gp->regs + MAC_FCSERR); + writel(0, gp->regs + MAC_FCSERR); + + stats->rx_frame_errors += readl(gp->regs + MAC_AERR); + writel(0, gp->regs + MAC_AERR); + + stats->rx_length_errors += readl(gp->regs + MAC_LERR); + writel(0, gp->regs + MAC_LERR); + + stats->tx_aborted_errors += readl(gp->regs + MAC_ECOLL); + stats->collisions += + (readl(gp->regs + MAC_ECOLL) + + readl(gp->regs + MAC_LCOLL)); + writel(0, gp->regs + MAC_ECOLL); + writel(0, gp->regs + MAC_LCOLL); + + return &gp->net_stats; +} + +static void gem_set_multicast(struct net_device *dev) +{ + struct gem *gp = dev->priv; + + netif_stop_queue(dev); + + if ((gp->dev->flags & IFF_ALLMULTI) || + (gp->dev->mc_count > 256)) { + writel(0xffff, gp->regs + MAC_HASH0); + writel(0xffff, gp->regs + MAC_HASH1); + writel(0xffff, gp->regs + MAC_HASH2); + writel(0xffff, gp->regs + MAC_HASH3); + writel(0xffff, gp->regs + MAC_HASH4); + writel(0xffff, gp->regs + MAC_HASH5); + writel(0xffff, gp->regs + MAC_HASH6); + writel(0xffff, gp->regs + MAC_HASH7); + writel(0xffff, gp->regs + MAC_HASH8); + writel(0xffff, gp->regs + MAC_HASH9); + writel(0xffff, gp->regs + MAC_HASH10); + writel(0xffff, gp->regs + MAC_HASH11); + writel(0xffff, gp->regs + MAC_HASH12); + writel(0xffff, gp->regs + MAC_HASH13); + writel(0xffff, gp->regs + MAC_HASH14); + writel(0xffff, gp->regs + MAC_HASH15); + } else if (gp->dev->flags & IFF_PROMISC) { + u32 rxcfg = readl(gp->regs + MAC_RXCFG); + int limit = 10000; + + writel(rxcfg & ~MAC_RXCFG_ENAB, gp->regs + MAC_RXCFG); + while (readl(gp->regs + MAC_RXCFG) & MAC_RXCFG_ENAB) { + if (!limit--) + break; + udelay(10); + } + + rxcfg |= MAC_RXCFG_PROM; + writel(rxcfg, gp->regs + MAC_RXCFG); + } else { + u16 hash_table[16]; + u32 crc, poly = CRC_POLYNOMIAL_LE; + struct dev_mc_list *dmi = gp->dev->mc_list; + int i, j, bit, byte; + + for (i = 0; i < 16; i++) + hash_table[i] = 0; + + for (i = 0; i < dev->mc_count; i++) { + char *addrs = dmi->dmi_addr; + + dmi = dmi->next; + + if (!(*addrs & 1)) + continue; + + crc = 0xffffffffU; + for (byte = 0; byte < 6; byte++) { + for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) { + int test; + + test = ((bit ^ crc) & 0x01); + crc >>= 1; + if (test) + crc = crc ^ poly; + } + } + crc >>= 24; + hash_table[crc >> 4] |= 1 << (crc & 0xf); + } + writel(hash_table[0], gp->regs + MAC_HASH0); + writel(hash_table[1], gp->regs + MAC_HASH1); + writel(hash_table[2], gp->regs + MAC_HASH2); + writel(hash_table[3], gp->regs + MAC_HASH3); + writel(hash_table[4], gp->regs + MAC_HASH4); + writel(hash_table[5], gp->regs + MAC_HASH5); + writel(hash_table[6], gp->regs + MAC_HASH6); + writel(hash_table[7], gp->regs + MAC_HASH7); + writel(hash_table[8], gp->regs + MAC_HASH8); + writel(hash_table[9], gp->regs + MAC_HASH9); + writel(hash_table[10], gp->regs + MAC_HASH10); + writel(hash_table[11], gp->regs + MAC_HASH11); + writel(hash_table[12], gp->regs + MAC_HASH12); + writel(hash_table[13], gp->regs + MAC_HASH13); + writel(hash_table[14], gp->regs + MAC_HASH14); + writel(hash_table[15], gp->regs + MAC_HASH15); + } + + netif_wake_queue(dev); +} + +static int gem_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + return -EINVAL; +} + +static int __devinit gem_check_invariants(struct gem *gp) +{ + struct pci_dev *pdev = gp->pdev; + u32 mif_cfg = readl(gp->regs + MIF_CFG); + + if (pdev->device == PCI_DEVICE_ID_SUN_RIO_GEM +#if 0 + || pdev->device == PCI_DEVICE_ID_SUN_PPC_GEM +#endif + ) { + /* One of the MII PHYs _must_ be present + * as these chip versions have no gigabit + * PHY. + */ + if ((mif_cfg & (MIF_CFG_MDI0 | MIF_CFG_MDI1)) == 0) { + printk(KERN_ERR PFX "RIO GEM lacks MII phy, mif_cfg[%08x]\n", + mif_cfg); + return -1; + } + } + + /* Determine initial PHY interface type guess. MDIO1 is the + * external PHY and thus takes precedence over MDIO0. + */ + if (mif_cfg & MIF_CFG_MDI1) + gp->phy_type = phy_mii_mdio1; + else if (mif_cfg & MIF_CFG_MDI0) + gp->phy_type = phy_mii_mdio0; + else + gp->phy_type = phy_serialink; + + if (gp->phy_type == phy_mii_mdio1 || + gp->phy_type == phy_mii_mdio0) { + int i; + + for (i = 0; i < 32; i++) { + gp->mii_phy_addr = i; + if (phy_read(gp, PHY_CTRL) != 0xffff) + break; + } + } + + /* Fetch the FIFO configurations now too. */ + gp->tx_fifo_sz = readl(gp->regs + TXDMA_FSZ) * 64; + gp->rx_fifo_sz = readl(gp->regs + RXDMA_FSZ) * 64; + + if (pdev->device == PCI_DEVICE_ID_SUN_GEM) { + if (gp->tx_fifo_sz != (9 * 1024) || + gp->rx_fifo_sz != (20 * 1024)) { + printk(KERN_ERR PFX "GEM has bogus fifo sizes tx(%d) rx(%d)\n", + gp->tx_fifo_sz, gp->rx_fifo_sz); + return -1; + } + } else { + if (gp->tx_fifo_sz != (2 * 1024) || + gp->rx_fifo_sz != (2 * 1024)) { + printk(KERN_ERR PFX "RIO GEM has bogus fifo sizes tx(%d) rx(%d)\n", + gp->tx_fifo_sz, gp->rx_fifo_sz); + return -1; + } + } + + /* Calculate pause thresholds. Setting the OFF threshold to the + * full RX fifo size effectively disables PAUSE generation which + * is what we do for 10/100 only GEMs which have FIFOs too small + * to make real gains from PAUSE. + */ + if (gp->rx_fifo_sz <= (2 * 1024)) { + gp->rx_pause_off = gp->rx_pause_on = gp->rx_fifo_sz; + } else { + int off = ((gp->rx_fifo_sz * 3) / 4); + int on = off - (1 * 1024); + + gp->rx_pause_off = off; + gp->rx_pause_on = on; + } + + { + u32 bifcfg = readl(gp->regs + GREG_BIFCFG); + + bifcfg |= GREG_BIFCFG_B64DIS; + writel(bifcfg, gp->regs + GREG_BIFCFG); + } + + return 0; +} + +static int __devinit gem_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + static int gem_version_printed = 0; + unsigned long gemreg_base, gemreg_len; + struct net_device *dev; + struct gem *gp; + int i; + + if (gem_version_printed++ == 0) + printk(KERN_INFO "%s", version); + + gemreg_base = pci_resource_start(pdev, 0); + gemreg_len = pci_resource_len(pdev, 0); + + if ((pci_resource_flags(pdev, 0) & IORESOURCE_IO) != 0) { + printk(KERN_ERR PFX "Cannot find proper PCI device " + "base address, aborting.\n"); + return -ENODEV; + } + + dev = init_etherdev(NULL, sizeof(*gp)); + if (!dev) { + printk(KERN_ERR PFX "Etherdev init failed, aborting.\n"); + return -ENOMEM; + } + + if (!request_mem_region(gemreg_base, gemreg_len, dev->name)) { + printk(KERN_ERR PFX "MMIO resource (0x%lx@0x%lx) unavailable, " + "aborting.\n", gemreg_base, gemreg_len); + goto err_out_free_netdev; + } + + if (pci_enable_device(pdev)) { + printk(KERN_ERR PFX "Cannot enable MMIO operation, " + "aborting.\n"); + goto err_out_free_mmio_res; + } + + pci_set_master(pdev); + + gp = dev->priv; + memset(gp, 0, sizeof(*gp)); + + gp->pdev = pdev; + dev->base_addr = (long) pdev; + + spin_lock_init(&gp->lock); + + gp->regs = (unsigned long) ioremap(gemreg_base, gemreg_len); + if (gp->regs == 0UL) { + printk(KERN_ERR PFX "Cannot map device registers, " + "aborting.\n"); + goto err_out_free_mmio_res; + } + + if (gem_check_invariants(gp)) + goto err_out_iounmap; + + /* It is guarenteed that the returned buffer will be at least + * PAGE_SIZE aligned. + */ + gp->init_block = (struct gem_init_block *) + pci_alloc_consistent(pdev, sizeof(struct gem_init_block), + &gp->gblock_dvma); + if (!gp->init_block) { + printk(KERN_ERR PFX "Cannot allocate init block, " + "aborting.\n"); + goto err_out_iounmap; + } + + pci_set_drvdata(pdev, dev); + + printk(KERN_INFO "%s: Sun GEM (PCI) 10/100/1000BaseT Ethernet ", + dev->name); + +#ifdef __sparc__ + memcpy(dev->dev_addr, idprom->id_ethaddr, 6); +#endif + + for (i = 0; i < 6; i++) + printk("%2.2x%c", dev->dev_addr[i], + i == 5 ? ' ' : ':'); + printk("\n"); + + init_timer(&gp->link_timer); + gp->link_timer.function = gem_link_timer; + gp->link_timer.data = (unsigned long) gp; + + gp->dev = dev; + dev->open = gem_open; + dev->stop = gem_close; + dev->hard_start_xmit = gem_start_xmit; + dev->get_stats = gem_get_stats; + dev->set_multicast_list = gem_set_multicast; + dev->do_ioctl = gem_ioctl; + dev->irq = pdev->irq; + dev->dma = 0; + + return 0; + +err_out_iounmap: + iounmap((void *) gp->regs); + +err_out_free_mmio_res: + release_mem_region(gemreg_base, gemreg_len); + +err_out_free_netdev: + unregister_netdev(dev); + kfree(dev); + + return -ENODEV; + +} + +static void gem_suspend(struct pci_dev *pdev) +{ +} + +static void gem_resume(struct pci_dev *pdev) +{ +} + +static void __devexit gem_remove_one(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + + if (dev) { + struct gem *gp = dev->priv; + + unregister_netdev(dev); + + pci_free_consistent(pdev, + sizeof(struct gem_init_block), + gp->init_block, + gp->gblock_dvma); + iounmap((void *) gp->regs); + release_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + kfree(dev); + + pci_set_drvdata(pdev, NULL); + } +} + +static struct pci_driver gem_driver = { + name: GEM_MODULE_NAME, + id_table: gem_pci_tbl, + probe: gem_init_one, + remove: gem_remove_one, + suspend: gem_suspend, + resume: gem_resume, +}; + +static int __init gem_init(void) +{ + return pci_module_init(&gem_driver); +} + +static void __exit gem_cleanup(void) +{ + pci_unregister_driver(&gem_driver); +} + +module_init(gem_init); +module_exit(gem_cleanup); diff --git a/drivers/net/sungem.h b/drivers/net/sungem.h new file mode 100644 index 000000000..2e3f9c9a5 --- /dev/null +++ b/drivers/net/sungem.h @@ -0,0 +1,969 @@ +/* $Id: sungem.h,v 1.5 2001/03/21 23:02:04 davem Exp $ + * sungem.h: Definitions for Sun GEM ethernet driver. + * + * Copyright (C) 2000 David S. Miller (davem@redhat.com) + */ + +#ifndef _SUNGEM_H +#define _SUNGEM_H + +/* Global Registers */ +#define GREG_SEBSTATE 0x0000UL /* SEB State Register */ +#define GREG_CFG 0x0004UL /* Configuration Register */ +#define GREG_STAT 0x000CUL /* Status Register */ +#define GREG_IMASK 0x0010UL /* Interrupt Mask Register */ +#define GREG_IACK 0x0014UL /* Interrupt ACK Register */ +#define GREG_STAT2 0x001CUL /* Alias of GREG_STAT */ +#define GREG_PCIESTAT 0x1000UL /* PCI Error Status Register */ +#define GREG_PCIEMASK 0x1004UL /* PCI Error Mask Register */ +#define GREG_BIFCFG 0x1008UL /* BIF Configuration Register */ +#define GREG_BIFDIAG 0x100CUL /* BIF Diagnostics Register */ +#define GREG_SWRST 0x1010UL /* Software Reset Register */ + +/* Global SEB State Register */ +#define GREG_SEBSTATE_ARB 0x00000003 /* State of Arbiter */ +#define GREG_SEBSTATE_RXWON 0x00000004 /* RX won internal arbitration */ + +/* Global Configuration Register */ +#define GREG_CFG_IBURST 0x00000001 /* Infinite Burst */ +#define GREG_CFG_TXDMALIM 0x0000003e /* TX DMA grant limit */ +#define GREG_CFG_RXDMALIM 0x000007c0 /* RX DMA grant limit */ + +/* Global Interrupt Status Register. + * + * Reading this register automatically clears bits 0 through 6. + * This auto-clearing does not occur when the alias at GREG_STAT2 + * is read instead. The rest of the interrupt bits only clear when + * the secondary interrupt status register corresponding to that + * bit is read (ie. if GREG_STAT_PCS is set, it will be cleared by + * reading PCS_ISTAT). + */ +#define GREG_STAT_TXINTME 0x00000001 /* TX INTME frame transferred */ +#define GREG_STAT_TXALL 0x00000002 /* All TX frames transferred */ +#define GREG_STAT_TXDONE 0x00000004 /* One TX frame transferred */ +#define GREG_STAT_RXDONE 0x00000010 /* One RX frame arrived */ +#define GREG_STAT_RXNOBUF 0x00000020 /* No free RX buffers available */ +#define GREG_STAT_RXTAGERR 0x00000040 /* RX tag framing is corrupt */ +#define GREG_STAT_PCS 0x00002000 /* PCS signalled interrupt */ +#define GREG_STAT_TXMAC 0x00004000 /* TX MAC signalled interrupt */ +#define GREG_STAT_RXMAC 0x00008000 /* RX MAC signalled interrupt */ +#define GREG_STAT_MAC 0x00010000 /* MAC Control signalled irq */ +#define GREG_STAT_MIF 0x00020000 /* MIF signalled interrupt */ +#define GREG_STAT_PCIERR 0x00040000 /* PCI Error interrupt */ +#define GREG_STAT_TXNR 0xfff80000 /* == TXDMA_TXDONE reg val */ +#define GREG_STAT_TXNR_SHIFT 19 + +#define GREG_STAT_ABNORMAL (GREG_STAT_RXNOBUF | GREG_STAT_RXTAGERR | \ + GREG_STAT_PCS | GREG_STAT_TXMAC | GREG_STAT_RXMAC | \ + GREG_STAT_MAC | GREG_STAT_MIF | GREG_STAT_PCIERR) + +/* The layout of GREG_IMASK and GREG_IACK is identical to GREG_STAT. + * Bits set in GREG_IMASK will prevent that interrupt type from being + * signalled to the cpu. GREG_IACK can be used to clear specific top-level + * interrupt conditions in GREG_STAT, ie. it only works for bits 0 through 6. + * Setting the bit will clear that interrupt, clear bits will have no effect + * on GREG_STAT. + */ + +/* Global PCI Error Status Register */ +#define GREG_PCIESTAT_BADACK 0x00000001 /* No ACK64# during ABS64 cycle */ +#define GREG_PCIESTAT_DTRTO 0x00000002 /* Delayed transaction timeout */ +#define GREG_PCIESTAT_OTHER 0x00000004 /* Other PCI error, check cfg space */ + +/* The layout of the GREG_PCIEMASK is identical to that of GREG_PCIESTAT. + * Bits set in GREG_PCIEMASK will prevent that interrupt type from being + * signalled to the cpu. + */ + +/* Global BIF Configuration Register */ +#define GREG_BIFCFG_SLOWCLK 0x00000001 /* Set if PCI runs < 25Mhz */ +#define GREG_BIFCFG_B64DIS 0x00000002 /* Disable 64bit wide data cycle*/ +#define GREG_BIFCFG_M66EN 0x00000004 /* Set if on 66Mhz PCI segment */ + +/* Global BIF Diagnostics Register */ +#define GREG_BIFDIAG_BURSTSM 0x007f0000 /* PCI Burst state machine */ +#define GREG_BIFDIAG_BIFSM 0xff000000 /* BIF state machine */ + +/* Global Software Reset Register. + * + * This register is used to perform a global reset of the RX and TX portions + * of the GEM asic. Setting the RX or TX reset bit will start the reset. + * The driver _MUST_ poll these bits until they clear. One may not attempt + * to program any other part of GEM until the bits clear. + */ +#define GREG_SWRST_TXRST 0x00000001 /* TX Software Reset */ +#define GREG_SWRST_RXRST 0x00000002 /* RX Software Reset */ +#define GREG_SWRST_RSTOUT 0x00000004 /* Force RST# pin active */ + +/* TX DMA Registers */ +#define TXDMA_KICK 0x2000UL /* TX Kick Register */ +#define TXDMA_CFG 0x2004UL /* TX Configuration Register */ +#define TXDMA_DBLOW 0x2008UL /* TX Desc. Base Low */ +#define TXDMA_DBHI 0x200CUL /* TX Desc. Base High */ +#define TXDMA_FWPTR 0x2014UL /* TX FIFO Write Pointer */ +#define TXDMA_FSWPTR 0x2018UL /* TX FIFO Shadow Write Pointer */ +#define TXDMA_FRPTR 0x201CUL /* TX FIFO Read Pointer */ +#define TXDMA_FSRPTR 0x2020UL /* TX FIFO Shadow Read Pointer */ +#define TXDMA_PCNT 0x2024UL /* TX FIFO Packet Counter */ +#define TXDMA_SMACHINE 0x2028UL /* TX State Machine Register */ +#define TXDMA_DPLOW 0x2030UL /* TX Data Pointer Low */ +#define TXDMA_DPHI 0x2034UL /* TX Data Pointer High */ +#define TXDMA_TXDONE 0x2100UL /* TX Completion Register */ +#define TXDMA_FADDR 0x2104UL /* TX FIFO Address */ +#define TXDMA_FTAG 0x2108UL /* TX FIFO Tag */ +#define TXDMA_DLOW 0x210CUL /* TX FIFO Data Low */ +#define TXDMA_DHIT1 0x2110UL /* TX FIFO Data HighT1 */ +#define TXDMA_DHIT0 0x2114UL /* TX FIFO Data HighT0 */ +#define TXDMA_FSZ 0x2118UL /* TX FIFO Size */ + +/* TX Kick Register. + * + * This 13-bit register is programmed by the driver to hold the descriptor + * entry index which follows the last valid transmit descriptor. + */ + +/* TX Completion Register. + * + * This 13-bit register is updated by GEM to hold to descriptor entry index + * which follows the last descriptor already processed by GEM. Note that + * this value is mirrored in GREG_STAT which eliminates the need to even + * access this register in the driver during interrupt processing. + */ + +/* TX Configuration Register. + * + * Note that TXDMA_CFG_FTHRESH, the TX FIFO Threshold, is an obsolete feature + * that was meant to be used with jumbo packets. It should be set to the + * maximum value of 0x4ff, else one risks getting TX MAC Underrun errors. + */ +#define TXDMA_CFG_ENABLE 0x00000001 /* Enable TX DMA channel */ +#define TXDMA_CFG_RINGSZ 0x0000001e /* TX descriptor ring size */ +#define TXDMA_CFG_RINGSZ_32 0x00000000 /* 32 TX descriptors */ +#define TXDMA_CFG_RINGSZ_64 0x00000002 /* 64 TX descriptors */ +#define TXDMA_CFG_RINGSZ_128 0x00000004 /* 128 TX descriptors */ +#define TXDMA_CFG_RINGSZ_256 0x00000006 /* 256 TX descriptors */ +#define TXDMA_CFG_RINGSZ_512 0x00000008 /* 512 TX descriptors */ +#define TXDMA_CFG_RINGSZ_1K 0x0000000a /* 1024 TX descriptors */ +#define TXDMA_CFG_RINGSZ_2K 0x0000000c /* 2048 TX descriptors */ +#define TXDMA_CFG_RINGSZ_4K 0x0000000e /* 4096 TX descriptors */ +#define TXDMA_CFG_RINGSZ_8K 0x00000010 /* 8192 TX descriptors */ +#define TXDMA_CFG_PIOSEL 0x00000020 /* Enable TX FIFO PIO from cpu */ +#define TXDMA_CFG_FTHRESH 0x001ffc00 /* TX FIFO Threshold, obsolete */ +#define TXDMA_CFG_PMODE 0x00200000 /* TXALL irq means TX FIFO empty*/ + +/* TX Descriptor Base Low/High. + * + * These two registers store the 53 most significant bits of the base address + * of the TX descriptor table. The 11 least significant bits are always + * zero. As a result, the TX descriptor table must be 2K aligned. + */ + +/* The rest of the TXDMA_* registers are for diagnostics and debug, I will document + * them later. -DaveM + */ + +/* Receive DMA Registers */ +#define RXDMA_CFG 0x4000UL /* RX Configuration Register */ +#define RXDMA_DBLOW 0x4004UL /* RX Descriptor Base Low */ +#define RXDMA_DBHI 0x4008UL /* RX Descriptor Base High */ +#define RXDMA_FWPTR 0x400CUL /* RX FIFO Write Pointer */ +#define RXDMA_FSWPTR 0x4010UL /* RX FIFO Shadow Write Pointer */ +#define RXDMA_FRPTR 0x4014UL /* RX FIFO Read Pointer */ +#define RXDMA_PCNT 0x4018UL /* RX FIFO Packet Counter */ +#define RXDMA_SMACHINE 0x401CUL /* RX State Machine Register */ +#define RXDMA_PTHRESH 0x4020UL /* Pause Thresholds */ +#define RXDMA_DPLOW 0x4024UL /* RX Data Pointer Low */ +#define RXDMA_DPHI 0x4028UL /* RX Data Pointer High */ +#define RXDMA_KICK 0x4100UL /* RX Kick Register */ +#define RXDMA_DONE 0x4104UL /* RX Completion Register */ +#define RXDMA_BLANK 0x4108UL /* RX Blanking Register */ +#define RXDMA_FADDR 0x410CUL /* RX FIFO Address */ +#define RXDMA_FTAG 0x4110UL /* RX FIFO Tag */ +#define RXDMA_DLOW 0x4114UL /* RX FIFO Data Low */ +#define RXDMA_DHIT1 0x4118UL /* RX FIFO Data HighT0 */ +#define RXDMA_DHIT0 0x411CUL /* RX FIFO Data HighT1 */ +#define RXDMA_FSZ 0x4120UL /* RX FIFO Size */ + +/* RX Configuration Register. */ +#define RXDMA_CFG_ENABLE 0x00000001 /* Enable RX DMA channel */ +#define RXDMA_CFG_RINGSZ 0x0000001e /* RX descriptor ring size */ +#define RXDMA_CFG_RINGSZ_32 0x00000000 /* - 32 entries */ +#define RXDMA_CFG_RINGSZ_64 0x00000002 /* - 64 entries */ +#define RXDMA_CFG_RINGSZ_128 0x00000004 /* - 128 entries */ +#define RXDMA_CFG_RINGSZ_256 0x00000006 /* - 256 entries */ +#define RXDMA_CFG_RINGSZ_512 0x00000008 /* - 512 entries */ +#define RXDMA_CFG_RINGSZ_1K 0x0000000a /* - 1024 entries */ +#define RXDMA_CFG_RINGSZ_2K 0x0000000c /* - 2048 entries */ +#define RXDMA_CFG_RINGSZ_4K 0x0000000e /* - 4096 entries */ +#define RXDMA_CFG_RINGSZ_8K 0x00000010 /* - 8192 entries */ +#define RXDMA_CFG_RINGSZ_BDISAB 0x00000020 /* Disable RX desc batching */ +#define RXDMA_CFG_FBOFF 0x00001c00 /* Offset of first data byte */ +#define RXDMA_CFG_CSUMOFF 0x000fe000 /* Skip bytes before csum calc */ +#define RXDMA_CFG_FTHRESH 0x07000000 /* RX FIFO dma start threshold */ +#define RXDMA_CFG_FTHRESH_64 0x00000000 /* - 64 bytes */ +#define RXDMA_CFG_FTHRESH_128 0x01000000 /* - 128 bytes */ +#define RXDMA_CFG_FTHRESH_256 0x02000000 /* - 256 bytes */ +#define RXDMA_CFG_FTHRESH_512 0x03000000 /* - 512 bytes */ +#define RXDMA_CFG_FTHRESH_1K 0x04000000 /* - 1024 bytes */ +#define RXDMA_CFG_FTHRESH_2K 0x05000000 /* - 2048 bytes */ + +/* RX Descriptor Base Low/High. + * + * These two registers store the 53 most significant bits of the base address + * of the RX descriptor table. The 11 least significant bits are always + * zero. As a result, the RX descriptor table must be 2K aligned. + */ + +/* RX PAUSE Thresholds. + * + * These values determine when XOFF and XON PAUSE frames are emitted by + * GEM. The thresholds measure RX FIFO occupancy in units of 64 bytes. + */ +#define RXDMA_PTHRESH_OFF 0x000001ff /* XOFF emitted w/FIFO > this */ +#define RXDMA_PTHRESH_ON 0x001ff000 /* XON emitted w/FIFO < this */ + +/* RX Kick Register. + * + * This 13-bit register is written by the host CPU and holds the last + * valid RX descriptor number plus one. This is, if 'N' is written to + * this register, it means that all RX descriptors up to but excluding + * 'N' are valid. + * + * The hardware requires that RX descriptors are posted in increments + * of 4. This means 'N' must be a multiple of four. For the best + * performance, the first new descriptor being posted should be (PCI) + * cache line aligned. + */ + +/* RX Completion Register. + * + * This 13-bit register is updated by GEM to indicate which RX descriptors + * have already been used for receive frames. All descriptors up to but + * excluding the value in this register are ready to be processed. GEM + * updates this register value after the RX FIFO empties completely into + * the RX descriptor's buffer, but before the RX_DONE bit is set in the + * interrupt status register. + */ + +/* RX Blanking Register. */ +#define RXDMA_BLANK_IPKTS 0x000001ff /* RX_DONE asserted after this + * many packets received since + * previous RX_DONE. + */ +#define RXDMA_BLANK_ITIME 0x000ff000 /* RX_DONE asserted after this + * many clocks (measured in 2048 + * PCI clocks) were counted since + * the previous RX_DONE. + */ + +/* RX FIFO Size. + * + * This 11-bit read-only register indicates how large, in units of 64-bytes, + * the RX FIFO is. The driver uses this to properly configure the RX PAUSE + * thresholds. + */ + +/* The rest of the RXDMA_* registers are for diagnostics and debug, I will document + * them later. -DaveM + */ + +/* MAC Registers */ +#define MAC_TXRST 0x6000UL /* TX MAC Software Reset Command*/ +#define MAC_RXRST 0x6004UL /* RX MAC Software Reset Command*/ +#define MAC_SNDPAUSE 0x6008UL /* Send Pause Command Register */ +#define MAC_TXSTAT 0x6010UL /* TX MAC Status Register */ +#define MAC_RXSTAT 0x6014UL /* RX MAC Status Register */ +#define MAC_CSTAT 0x6018UL /* MAC Control Status Register */ +#define MAC_TXMASK 0x6020UL /* TX MAC Mask Register */ +#define MAC_RXMASK 0x6024UL /* RX MAC Mask Register */ +#define MAC_MCMASK 0x6028UL /* MAC Control Mask Register */ +#define MAC_TXCFG 0x6030UL /* TX MAC Configuration Register*/ +#define MAC_RXCFG 0x6034UL /* RX MAC Configuration Register*/ +#define MAC_MCCFG 0x6038UL /* MAC Control Config Register */ +#define MAC_XIFCFG 0x603CUL /* XIF Configuration Register */ +#define MAC_IPG0 0x6040UL /* InterPacketGap0 Register */ +#define MAC_IPG1 0x6044UL /* InterPacketGap1 Register */ +#define MAC_IPG2 0x6048UL /* InterPacketGap2 Register */ +#define MAC_STIME 0x604CUL /* SlotTime Register */ +#define MAC_MINFSZ 0x6050UL /* MinFrameSize Register */ +#define MAC_MAXFSZ 0x6054UL /* MaxFrameSize Register */ +#define MAC_PASIZE 0x6058UL /* PA Size Register */ +#define MAC_JAMSIZE 0x605CUL /* JamSize Register */ +#define MAC_ATTLIM 0x6060UL /* Attempt Limit Register */ +#define MAC_MCTYPE 0x6064UL /* MAC Control Type Register */ +#define MAC_ADDR0 0x6080UL /* MAC Address 0 Register */ +#define MAC_ADDR1 0x6084UL /* MAC Address 1 Register */ +#define MAC_ADDR2 0x6088UL /* MAC Address 2 Register */ +#define MAC_ADDR3 0x608CUL /* MAC Address 3 Register */ +#define MAC_ADDR4 0x6090UL /* MAC Address 4 Register */ +#define MAC_ADDR5 0x6094UL /* MAC Address 5 Register */ +#define MAC_ADDR6 0x6098UL /* MAC Address 6 Register */ +#define MAC_ADDR7 0x609CUL /* MAC Address 7 Register */ +#define MAC_ADDR8 0x60A0UL /* MAC Address 8 Register */ +#define MAC_AFILT0 0x60A4UL /* Address Filter 0 Register */ +#define MAC_AFILT1 0x60A8UL /* Address Filter 1 Register */ +#define MAC_AFILT2 0x60ACUL /* Address Filter 2 Register */ +#define MAC_AF21MSK 0x60B0UL /* Address Filter 2&1 Mask Reg */ +#define MAC_AF0MSK 0x60B4UL /* Address Filter 0 Mask Reg */ +#define MAC_HASH0 0x60C0UL /* Hash Table 0 Register */ +#define MAC_HASH1 0x60C4UL /* Hash Table 1 Register */ +#define MAC_HASH2 0x60C8UL /* Hash Table 2 Register */ +#define MAC_HASH3 0x60CCUL /* Hash Table 3 Register */ +#define MAC_HASH4 0x60D0UL /* Hash Table 4 Register */ +#define MAC_HASH5 0x60D4UL /* Hash Table 5 Register */ +#define MAC_HASH6 0x60D8UL /* Hash Table 6 Register */ +#define MAC_HASH7 0x60DCUL /* Hash Table 7 Register */ +#define MAC_HASH8 0x60E0UL /* Hash Table 8 Register */ +#define MAC_HASH9 0x60E4UL /* Hash Table 9 Register */ +#define MAC_HASH10 0x60E8UL /* Hash Table 10 Register */ +#define MAC_HASH11 0x60ECUL /* Hash Table 11 Register */ +#define MAC_HASH12 0x60F0UL /* Hash Table 12 Register */ +#define MAC_HASH13 0x60F4UL /* Hash Table 13 Register */ +#define MAC_HASH14 0x60F8UL /* Hash Table 14 Register */ +#define MAC_HASH15 0x60FCUL /* Hash Table 15 Register */ +#define MAC_NCOLL 0x6100UL /* Normal Collision Counter */ +#define MAC_FASUCC 0x6104UL /* First Attmpt. Succ Coll Ctr. */ +#define MAC_ECOLL 0x6108UL /* Excessive Collision Counter */ +#define MAC_LCOLL 0x610CUL /* Late Collision Counter */ +#define MAC_DTIMER 0x6110UL /* Defer Timer */ +#define MAC_PATMPS 0x6114UL /* Peak Attempts Register */ +#define MAC_RFCTR 0x6118UL /* Receive Frame Counter */ +#define MAC_LERR 0x611CUL /* Length Error Counter */ +#define MAC_AERR 0x6120UL /* Alignment Error Counter */ +#define MAC_FCSERR 0x6124UL /* FCS Error Counter */ +#define MAC_RXCVERR 0x6128UL /* RX code Violation Error Ctr */ +#define MAC_RANDSEED 0x6130UL /* Random Number Seed Register */ +#define MAC_SMACHINE 0x6134UL /* State Machine Register */ + +/* TX MAC Software Reset Command. */ +#define MAC_TXRST_CMD 0x00000001 /* Start sw reset, self-clears */ + +/* RX MAC Software Reset Command. */ +#define MAC_RXRST_CMD 0x00000001 /* Start sw reset, self-clears */ + +/* Send Pause Command. */ +#define MAC_SNDPAUSE_TS 0x0000ffff /* The pause_time operand used in + * Send_Pause and flow-control + * handshakes. + */ +#define MAC_SNDPAUSE_SP 0x00010000 /* Setting this bit instructs the MAC + * to send a Pause Flow Control + * frame onto the network. + */ + +/* TX MAC Status Register. */ +#define MAC_TXSTAT_XMIT 0x00000001 /* Frame Transmitted */ +#define MAC_TXSTAT_URUN 0x00000002 /* TX Underrun */ +#define MAC_TXSTAT_MPE 0x00000004 /* Max Packet Size Error */ +#define MAC_TXSTAT_NCE 0x00000008 /* Normal Collision Cntr Expire */ +#define MAC_TXSTAT_ECE 0x00000010 /* Excess Collision Cntr Expire */ +#define MAC_TXSTAT_LCE 0x00000020 /* Late Collision Cntr Expire */ +#define MAC_TXSTAT_FCE 0x00000040 /* First Collision Cntr Expire */ +#define MAC_TXSTAT_DTE 0x00000080 /* Defer Timer Expire */ +#define MAC_TXSTAT_PCE 0x00000100 /* Peak Attempts Cntr Expire */ + +/* RX MAC Status Register. */ +#define MAC_RXSTAT_RCV 0x00000001 /* Frame Received */ +#define MAC_RXSTAT_OFLW 0x00000002 /* Receive Overflow */ +#define MAC_RXSTAT_FCE 0x00000004 /* Frame Cntr Expire */ +#define MAC_RXSTAT_ACE 0x00000008 /* Align Error Cntr Expire */ +#define MAC_RXSTAT_CCE 0x00000010 /* CRC Error Cntr Expire */ +#define MAC_RXSTAT_LCE 0x00000020 /* Length Error Cntr Expire */ +#define MAC_RXSTAT_VCE 0x00000040 /* Code Violation Cntr Expire */ + +/* MAC Control Status Register. */ +#define MAC_CSTAT_PRCV 0x00000001 /* Pause Received */ +#define MAC_CSTAT_PS 0x00000002 /* Paused State */ +#define MAC_CSTAT_NPS 0x00000004 /* Not Paused State */ +#define MAC_CSTAT_PTR 0xffff0000 /* Pause Time Received */ + +/* The layout of the MAC_{TX,RX,C}MASK registers is identical to that + * of MAC_{TX,RX,C}STAT. Bits set in MAC_{TX,RX,C}MASK will prevent + * that interrupt type from being signalled to front end of GEM. For + * the interrupt to actually get sent to the cpu, it is necessary to + * properly set the appropriate GREG_IMASK_{TX,RX,}MAC bits as well. + */ + +/* TX MAC Configuration Register. + * + * NOTE: The TX MAC Enable bit must be cleared and polled until + * zero before any other bits in this register are changed. + * + * Also, enabling the Carrier Extension feature of GEM is + * a 3 step process 1) Set TX Carrier Extension 2) Set + * RX Carrier Extension 3) Set Slot Time to 0x200. This + * mode must be enabled when in half-duplex at 1Gbps, else + * it must be disabled. + */ +#define MAC_TXCFG_ENAB 0x00000001 /* TX MAC Enable */ +#define MAC_TXCFG_ICS 0x00000002 /* Ignore Carrier Sense */ +#define MAC_TXCFG_ICOLL 0x00000004 /* Ignore Collisions */ +#define MAC_TXCFG_EIPG0 0x00000008 /* Enable IPG0 */ +#define MAC_TXCFG_NGU 0x00000010 /* Never Give Up */ +#define MAC_TXCFG_NGUL 0x00000020 /* Never Give Up Limit */ +#define MAC_TXCFG_NBO 0x00000040 /* No Backoff */ +#define MAC_TXCFG_SD 0x00000080 /* Slow Down */ +#define MAC_TXCFG_NFCS 0x00000100 /* No FCS */ +#define MAC_TXCFG_TCE 0x00000200 /* TX Carrier Extension */ + +/* RX MAC Configuration Register. + * + * NOTE: The RX MAC Enable bit must be cleared and polled until + * zero before any other bits in this register are changed. + * + * Similar rules apply to the Hash Filter Enable bit when + * programming the hash table registers, and the Address Filter + * Enable bit when programming the address filter registers. + */ +#define MAC_RXCFG_ENAB 0x00000001 /* RX MAC Enable */ +#define MAC_RXCFG_SPAD 0x00000002 /* Strip Pad */ +#define MAC_RXCFG_SFCS 0x00000004 /* Strip FCS */ +#define MAC_RXCFG_PROM 0x00000008 /* Promiscuous Mode */ +#define MAC_RXCFG_PGRP 0x00000010 /* Promiscuous Group */ +#define MAC_RXCFG_HFE 0x00000020 /* Hash Filter Enable */ +#define MAC_RXCFG_AFE 0x00000040 /* Address Filter Enable */ +#define MAC_RXCFG_DDE 0x00000080 /* Disable Discard on Error */ +#define MAC_RXCFG_RCE 0x00000100 /* RX Carrier Extension */ + +/* MAC Control Config Register. */ +#define MAC_MCCFG_SPE 0x00000001 /* Send Pause Enable */ +#define MAC_MCCFG_RPE 0x00000002 /* Receive Pause Enable */ +#define MAC_MCCFG_PMC 0x00000004 /* Pass MAC Control */ + +/* XIF Configuration Register. + * + * NOTE: When leaving or entering loopback mode, a global hardware + * init of GEM should be performed. + */ +#define MAC_XIFCFG_OE 0x00000001 /* MII TX Output Driver Enable */ +#define MAC_XIFCFG_LBCK 0x00000002 /* Loopback TX to RX */ +#define MAC_XIFCFG_DISE 0x00000004 /* Disable RX path during TX */ +#define MAC_XIFCFG_GMII 0x00000008 /* Use GMII clocks + datapath */ +#define MAC_XIFCFG_MBOE 0x00000010 /* Controls MII_BUF_EN pin */ +#define MAC_XIFCFG_LLED 0x00000020 /* Force LINKLED# active (low) */ +#define MAC_XIFCFG_FLED 0x00000040 /* Force FDPLXLED# active (low) */ + +/* InterPacketGap0 Register. This 8-bit value is used as an extension + * to the InterPacketGap1 Register. Specifically it contributes to the + * timing of the RX-to-TX IPG. This value is ignored and presumed to + * be zero for TX-to-TX IPG calculations and/or when the Enable IPG0 bit + * is cleared in the TX MAC Configuration Register. + * + * This value in this register in terms of media byte time. + * + * Recommended value: 0x00 + */ + +/* InterPacketGap1 Register. This 8-bit value defines the first 2/3 + * portion of the Inter Packet Gap. + * + * This value in this register in terms of media byte time. + * + * Recommended value: 0x08 + */ + +/* InterPacketGap2 Register. This 8-bit value defines the second 1/3 + * portion of the Inter Packet Gap. + * + * This value in this register in terms of media byte time. + * + * Recommended value: 0x04 + */ + +/* Slot Time Register. This 10-bit value specifies the slot time + * parameter in units of media byte time. It determines the physical + * span of the network. + * + * Recommended value: 0x40 + */ + +/* Minimum Frame Size Register. This 10-bit register specifies the + * smallest sized frame the TXMAC will send onto the medium, and the + * RXMAC will receive from the medium. + * + * Recommended value: 0x40 + */ + +/* Maximum Frame and Burst Size Register. + * + * This register specifies two things. First it specifies the maximum + * sized frame the TXMAC will send and the RXMAC will recognize as + * valid. Second, it specifies the maximum run length of a burst of + * packets sent in half-duplex gigabit modes. + * + * Recommended value: 0x200005ee + */ +#define MAC_MAXFSZ_MFS 0x00007fff /* Max Frame Size */ +#define MAC_MAXFSZ_MBS 0x7fff0000 /* Max Burst Size */ + +/* PA Size Register. This 10-bit register specifies the number of preamble + * bytes which will be transmitted at the beginning of each frame. A + * value of two or greater should be programmed here. + * + * Recommended value: 0x07 + */ + +/* Jam Size Register. This 4-bit register specifies the duration of + * the jam in units of media byte time. + * + * Recommended value: 0x04 + */ + +/* Attempts Limit Register. This 8-bit register specifies the number + * of attempts that the TXMAC will make to transmit a frame, before it + * resets its Attempts Counter. After reaching the Attempts Limit the + * TXMAC may or may not drop the frame, as determined by the NGU + * (Never Give Up) and NGUL (Never Give Up Limit) bits in the TXMAC + * Configuration Register. + * + * Recommended value: 0x10 + */ + +/* MAX Control Type Register. This 16-bit register specifies the + * "type" field of a MAC Control frame. The TXMAC uses this field to + * encapsulate the MAC Control frame for transmission, and the RXMAC + * uses it for decoding valid MAC Control frames received from the + * network. + * + * Recommended value: 0x8808 + */ + +/* MAC Address Registers. Each of these registers specify the + * ethernet MAC of the interface, 16-bits at a time. Register + * 0 specifies bits [47:32], register 1 bits [31:16], and register + * 2 bits [15:0]. + * + * Registers 3 through and including 5 specify an alternate + * MAC address for the interface. + * + * Registers 6 through and including 8 specify the MAC Control + * Address, which must be the reserved multicast address for MAC + * Control frames. + * + * Example: To program primary station address a:b:c:d:e:f into + * the chip. + * MAC_Address_2 = (a << 8) | b + * MAC_Address_1 = (c << 8) | d + * MAC_Address_0 = (e << 8) | f + */ + +/* Address Filter Registers. Registers 0 through 2 specify bit + * fields [47:32] through [15:0], respectively, of the address + * filter. The Address Filter 2&1 Mask Register denotes the 8-bit + * nibble mask for Address Filter Registers 2 and 1. The Address + * Filter 0 Mask Register denotes the 16-bit mask for the Address + * Filter Register 0. + */ + +/* Hash Table Registers. Registers 0 through 15 specify bit fields + * [255:240] through [15:0], respectively, of the hash table. + */ + +/* Statistics Registers. All of these registers are 16-bits and + * track occurances of a specific event. GEM can be configured + * to interrupt the host cpu when any of these counters overflow. + * They should all be explicitly initialized to zero when the interface + * is brought up. + */ + +/* Random Number Seed Register. This 10-bit value is used as the + * RNG seed inside GEM for the CSMA/CD backoff algorithm. It is + * recommended to program this register to the 10 LSB of the + * interfaces MAC address. + */ + +/* Pause Timer, read-only. This 16-bit timer is used to time the pause + * interval as indicated by a received pause flow control frame. + * A non-zero value in this timer indicates that the MAC is currently in + * the paused state. + */ + +/* MIF Registers */ +#define MIF_BBCLK 0x6200UL /* MIF Bit-Bang Clock */ +#define MIF_BBDATA 0x6204UL /* MIF Bit-Band Data */ +#define MIF_BBOENAB 0x6208UL /* MIF Bit-Bang Output Enable */ +#define MIF_FRAME 0x620CUL /* MIF Frame/Output Register */ +#define MIF_CFG 0x6210UL /* MIF Configuration Register */ +#define MIF_MASK 0x6214UL /* MIF Mask Register */ +#define MIF_STATUS 0x6218UL /* MIF Status Register */ +#define MIF_SMACHINE 0x621CUL /* MIF State Machine Register */ + +/* MIF Bit-Bang Clock. This 1-bit register is used to generate the + * MDC clock waveform on the MII Management Interface when the MIF is + * programmed in the "Bit-Bang" mode. Writing a '1' after a '0' into + * this register will create a rising edge on the MDC, while writing + * a '0' after a '1' will create a falling edge. For every bit that + * is transferred on the management interface, both edges have to be + * generated. + */ + +/* MIF Bit-Bang Data. This 1-bit register is used to generate the + * outgoing data (MDO) on the MII Management Interface when the MIF + * is programmed in the "Bit-Bang" mode. The daa will be steered to the + * appropriate MDIO based on the state of the PHY_Select bit in the MIF + * Configuration Register. + */ + +/* MIF Big-Band Output Enable. THis 1-bit register is used to enable + * ('1') or disable ('0') the I-directional driver on the MII when the + * MIF is programmed in the "Bit-Bang" mode. The MDIO should be enabled + * when data bits are transferred from the MIF to the transceiver, and it + * should be disabled when the interface is idle or when data bits are + * transferred from the transceiver to the MIF (data portion of a read + * instruction). Only one MDIO will be enabled at a given time, depending + * on the state of the PHY_Select bit in the MIF Configuration Register. + */ + +/* MIF Configuration Register. This 15-bit register controls the operation + * of the MIF. + */ +#define MIF_CFG_PSELECT 0x00000001 /* Xcvr slct: 0=mdio0 1=mdio1 */ +#define MIF_CFG_POLL 0x00000002 /* Enable polling mechanism */ +#define MIF_CFG_BBMODE 0x00000004 /* 1=bit-bang 0=frame mode */ +#define MIF_CFG_PRADDR 0x000000f8 /* Xcvr poll register address */ +#define MIF_CFG_MDI0 0x00000100 /* MDIO_0 present or read-bit */ +#define MIF_CFG_MDI1 0x00000200 /* MDIO_1 present or read-bit */ +#define MIF_CFG_PPADDR 0x00007c00 /* Xcvr poll PHY address */ + +/* MIF Frame/Output Register. This 32-bit register allows the host to + * communicate with a transceiver in frame mode (as opposed to big-bang + * mode). Writes by the host specify an instrution. After being issued + * the host must poll this register for completion. Also, after + * completion this register holds the data returned by the transceiver + * if applicable. + */ +#define MIF_FRAME_ST 0xc0000000 /* STart of frame */ +#define MIF_FRAME_OP 0x30000000 /* OPcode */ +#define MIF_FRAME_PHYAD 0x0f800000 /* PHY ADdress */ +#define MIF_FRAME_REGAD 0x007c0000 /* REGister ADdress */ +#define MIF_FRAME_TAMSB 0x00020000 /* Turn Around MSB */ +#define MIF_FRAME_TALSB 0x00010000 /* Turn Around LSB */ +#define MIF_FRAME_DATA 0x0000ffff /* Instruction Payload */ + +/* MIF Status Register. This register reports status when the MIF is + * operating in the poll mode. The poll status field is auto-clearing + * on read. + */ +#define MIF_STATUS_DATA 0xffff0000 /* Live image of XCVR reg */ +#define MIF_STATUS_STAT 0x0000ffff /* Which bits have changed */ + +/* MIF Mask Register. This 16-bit register is used when in poll mode + * to say which bits of the polled register will cause an interrupt + * when changed. + */ + +/* PCS/Serialink Registers */ +#define PCS_MIICTRL 0x9000UL /* PCS MII Control Register */ +#define PCS_MIISTAT 0x9004UL /* PCS MII Status Register */ +#define PCS_MIIADV 0x9008UL /* PCS MII Advertisement Reg */ +#define PCS_MIILP 0x900CUL /* PCS MII Link Partner Ability */ +#define PCS_CFG 0x9010UL /* PCS Configuration Register */ +#define PCS_SMACHINE 0x9014UL /* PCS State Machine Register */ +#define PCS_ISTAT 0x9018UL /* PCS Interrupt Status Reg */ +#define PCS_DMODE 0x9050UL /* Datapath Mode Register */ +#define PCS_SCTRL 0x9054UL /* Serialink Control Register */ +#define PCS_SOS 0x9058UL /* Shared Output Select Reg */ +#define PCS_SSTATE 0x905CUL /* Serialink State Register */ + +/* PCD MII Control Register. */ +#define PCS_MIICTRL_SPD 0x00000040 /* Read as one, writes ignored */ +#define PCS_MIICTRL_CT 0x00000080 /* Force COL signal active */ +#define PCS_MIICTRL_DM 0x00000100 /* Duplex mode, forced low */ +#define PCS_MIICTRL_RAN 0x00000200 /* Restart auto-neg, self clear */ +#define PCS_MIICTRL_ISO 0x00000400 /* Read as zero, writes ignored */ +#define PCS_MIICTRL_PD 0x00000800 /* Read as zero, writes ignored */ +#define PCS_MIICTRL_ANE 0x00001000 /* Auto-neg enable */ +#define PCS_MIICTRL_SS 0x00002000 /* Read as zero, writes ignored */ +#define PCS_MIICTRL_WB 0x00004000 /* Wrapback, loopback at 10-bit + * input side of Serialink + */ +#define PCS_MIICTRL_RST 0x00008000 /* Resets PCS, self clearing */ + +/* PCS MII Status Register. */ +#define PCS_MIISTAT_EC 0x00000001 /* Ext Capability: Read as zero */ +#define PCS_MIISTAT_JD 0x00000002 /* Jabber Detect: Read as zero */ +#define PCS_MIISTAT_LS 0x00000004 /* Link Status: 1=up 0=down */ +#define PCS_MIISTAT_ANA 0x00000008 /* Auto-neg Ability, always 1 */ +#define PCS_MIISTAT_RF 0x00000010 /* Remote Fault */ +#define PCS_MIISTAT_ANC 0x00000020 /* Auto-neg complete */ +#define PCS_MIISTAT_ES 0x00000100 /* Extended Status, always 1 */ + +/* PCS MII Advertisement Register. */ +#define PCS_MIIADV_FD 0x00000020 /* Advertise Full Duplex */ +#define PCS_MIIADV_HD 0x00000040 /* Advertise Half Duplex */ +#define PCS_MIIADV_SP 0x00000080 /* Advertise Symmetric Pause */ +#define PCS_MIIADV_AP 0x00000100 /* Advertise Asymmetric Pause */ +#define PCS_MIIADV_RF 0x00003000 /* Remote Fault */ +#define PCS_MIIADV_ACK 0x00004000 /* Read-only */ +#define PCS_MIIADV_NP 0x00008000 /* Next-page, forced low */ + +/* PCS MII Link Partner Ability Register. This register is equivalent + * to the Link Partnet Ability Register of the standard MII register set. + * It's layout corresponds to the PCS MII Advertisement Register. + */ + +/* PCS Configuration Register. */ +#define PCS_CFG_ENABLE 0x00000001 /* Must be zero while changing + * PCS MII advertisement reg. + */ +#define PCS_CFG_SDO 0x00000002 /* Signal detect override */ +#define PCS_CFG_SDL 0x00000004 /* Signal detect active low */ +#define PCS_CFG_JS 0x00000018 /* Jitter-study: + * 0 = normal operation + * 1 = high-frequency test pattern + * 2 = low-frequency test pattern + * 3 = reserved + */ +#define PCS_CFG_TO 0x00000020 /* 10ms auto-neg timer override */ + +/* PCS Interrupt Status Register. This register is self-clearing + * when read. + */ +#define PCS_ISTAT_LSC 0x00000004 /* Link Status Change */ + +/* Datapath Mode Register. */ +#define PCS_DMODE_SM 0x00000001 /* 1 = use internal Serialink */ +#define PCS_DMODE_ESM 0x00000002 /* External SERDES mode */ +#define PCS_DMODE_MGM 0x00000004 /* MII/GMII mode */ +#define PCS_DMODE_GMOE 0x00000008 /* GMII Output Enable */ + +/* Serialink Control Register. */ +#define PCS_SCTRL_LOOP 0x00000001 /* Loopback enable */ +#define PCS_SCTRL_ESCD 0x00000002 /* Enable sync char detection */ +#define PCS_SCTRL_LOCK 0x00000004 /* Lock to reference clock */ +#define PCS_SCTRL_EMP 0x00000018 /* Output driver emphasis */ +#define PCS_SCTRL_STEST 0x000001c0 /* Self test patterns */ +#define PCS_SCTRL_PDWN 0x00000200 /* Software power-down */ +#define PCS_SCTRL_RXZ 0x00000c00 /* PLL input to Serialink */ +#define PCS_SCTRL_RXP 0x00003000 /* PLL input to Serialink */ +#define PCS_SCTRL_TXZ 0x0000c000 /* PLL input to Serialink */ +#define PCS_SCTRL_TXP 0x00030000 /* PLL input to Serialink */ + +/* Shared Output Select Register. For test and debug, allows multiplexing + * test outputs into the PROM address pins. Set to zero for normal + * operation. + */ +#define PCS_SOS_PADDR 0x00000003 /* PROM Address */ + +/* PROM Image Space */ +#define PROM_START 0x100000UL /* Expansion ROM run time access*/ +#define PROM_SIZE 0x0fffffUL /* Size of ROM */ +#define PROM_END 0x200000UL /* End of ROM */ + +/* MII phy registers */ +#define PHY_CTRL 0x00 +#define PHY_STAT 0x01 +#define PHY_ADV 0x04 +#define PHY_LPA 0x05 + +#define PHY_CTRL_FDPLX 0x0100 /* Full duplex */ +#define PHY_CTRL_ISO 0x0400 /* Isloate MII from PHY */ +#define PHY_CTRL_ANRES 0x0200 /* Auto-negotiation restart */ +#define PHY_CTRL_ANENAB 0x1000 /* Auto-negotiation enable */ +#define PHY_CTRL_SPD100 0x2000 /* Select 100Mbps */ +#define PHY_CTRL_RST 0x8000 /* Reset PHY */ + +#define PHY_STAT_LSTAT 0x0004 /* Link status */ +#define PHY_STAT_ANEGC 0x0020 /* Auto-negotiation complete */ + +#define PHY_ADV_10HALF 0x0020 +#define PHY_ADV_10FULL 0x0040 +#define PHY_ADV_100HALF 0x0080 +#define PHY_ADV_100FULL 0x0100 + +#define PHY_LPA_10HALF 0x0020 +#define PHY_LPA_10FULL 0x0040 +#define PHY_LPA_100HALF 0x0080 +#define PHY_LPA_100FULL 0x0100 +#define PHY_LPA_FAULT 0x2000 + +/* When it can, GEM internally caches 4 aligned TX descriptors + * at a time, so that it can use full cacheline DMA reads. + * + * Note that unlike HME, there is no ownership bit in the descriptor + * control word. The same functionality is obtained via the TX-Kick + * and TX-Complete registers. As a result, GEM need not write back + * updated values to the TX descriptor ring, it only performs reads. + * + * Since TX descriptors are never modified by GEM, the driver can + * use the buffer DMA address as a place to keep track of allocated + * DMA mappings for a transmitted packet. + */ +struct gem_txd { + u64 control_word; + u64 buffer; +}; + +#define TXDCTRL_BUFSZ 0x0000000000007fff /* Buffer Size */ +#define TXDCTRL_CSTART 0x00000000001f8000 /* CSUM Start Offset */ +#define TXDCTRL_COFF 0x000000001fe00000 /* CSUM Stuff Offset */ +#define TXDCTRL_CENAB 0x0000000020000000 /* CSUM Enable */ +#define TXDCTRL_EOF 0x0000000040000000 /* End of Frame */ +#define TXDCTRL_SOF 0x0000000080000000 /* Start of Frame */ +#define TXDCTRL_INTME 0x0000000100000000 /* "Interrupt Me" */ +#define TXDCTRL_NOCRC 0x0000000200000000 /* No CRC Present */ + +/* GEM requires that RX descriptors are provided four at a time, + * aligned. Also, the RX ring may not wrap around. This means that + * there will be at least 4 unused desciptor entries in the middle + * of the RX ring at all times. + * + * Similar to HME, GEM assumes that it can write garbage bytes before + * the beginning of the buffer and right after the end in order to DMA + * whole cachelines. + * + * Unlike for TX, GEM does update the status word in the RX descriptors + * when packets arrive. Therefore an ownership bit does exist in the + * RX descriptors. It is advisory, GEM clears it but does not check + * it in any way. So when buffers are posted to the RX ring (via the + * RX Kick register) by the driver it must make sure the buffers are + * truly ready and that the ownership bits are set properly. + * + * Even though GEM modifies the RX descriptors, it guarentees that the + * buffer DMA address field will stay the same when it performs these + * updates. Therefore it can be used to keep track of DMA mappings + * by the host driver just as in the TX descriptor case above. + */ +struct gem_rxd { + u64 status_word; + u64 buffer; +}; + +#define RXDCTRL_TCPCSUM 0x000000000000ffff /* TCP Pseudo-CSUM */ +#define RXDCTRL_BUFSZ 0x000000007fff0000 /* Buffer Size */ +#define RXDCTRL_OWN 0x0000000080000000 /* GEM owns this entry */ +#define RXDCTRL_HASHVAL 0x0ffff00000000000 /* Hash Value */ +#define RXDCTRL_HPASS 0x1000000000000000 /* Passed Hash Filter */ +#define RXDCTRL_ALTMAC 0x2000000000000000 /* Matched ALT MAC */ +#define RXDCTRL_BAD 0x4000000000000000 /* Frame has bad CRC */ + +#define RXDCTRL_FRESH \ + ((((RX_BUF_ALLOC_SIZE - RX_OFFSET) << 16) & RXDCTRL_BUFSZ) | \ + RXDCTRL_OWN) + +#define TX_RING_SIZE 128 +#define RX_RING_SIZE 128 + +#if TX_RING_SIZE == 32 +#define TXDMA_CFG_BASE TXDMA_CFG_RINGSZ_32 +#elif TX_RING_SIZE == 64 +#define TXDMA_CFG_BASE TXDMA_CFG_RINGSZ_64 +#elif TX_RING_SIZE == 128 +#define TXDMA_CFG_BASE TXDMA_CFG_RINGSZ_128 +#elif TX_RING_SIZE == 256 +#define TXDMA_CFG_BASE TXDMA_CFG_RINGSZ_256 +#elif TX_RING_SIZE == 512 +#define TXDMA_CFG_BASE TXDMA_CFG_RINGSZ_512 +#elif TX_RING_SIZE == 1024 +#define TXDMA_CFG_BASE TXDMA_CFG_RINGSZ_1K +#elif TX_RING_SIZE == 2048 +#define TXDMA_CFG_BASE TXDMA_CFG_RINGSZ_2K +#elif TX_RING_SIZE == 4096 +#define TXDMA_CFG_BASE TXDMA_CFG_RINGSZ_4K +#elif TX_RING_SIZE == 8192 +#define TXDMA_CFG_BASE TXDMA_CFG_RINGSZ_8K +#else +#error TX_RING_SIZE value is illegal... +#endif + +#if RX_RING_SIZE == 32 +#define RXDMA_CFG_BASE RXDMA_CFG_RINGSZ_32 +#elif RX_RING_SIZE == 64 +#define RXDMA_CFG_BASE RXDMA_CFG_RINGSZ_64 +#elif RX_RING_SIZE == 128 +#define RXDMA_CFG_BASE RXDMA_CFG_RINGSZ_128 +#elif RX_RING_SIZE == 256 +#define RXDMA_CFG_BASE RXDMA_CFG_RINGSZ_256 +#elif RX_RING_SIZE == 512 +#define RXDMA_CFG_BASE RXDMA_CFG_RINGSZ_512 +#elif RX_RING_SIZE == 1024 +#define RXDMA_CFG_BASE RXDMA_CFG_RINGSZ_1K +#elif RX_RING_SIZE == 2048 +#define RXDMA_CFG_BASE RXDMA_CFG_RINGSZ_2K +#elif RX_RING_SIZE == 4096 +#define RXDMA_CFG_BASE RXDMA_CFG_RINGSZ_4K +#elif RX_RING_SIZE == 8192 +#define RXDMA_CFG_BASE RXDMA_CFG_RINGSZ_8K +#else +#error RX_RING_SIZE is illegal... +#endif + +#define NEXT_TX(N) (((N) + 1) & (TX_RING_SIZE - 1)) +#define NEXT_RX(N) (((N) + 1) & (RX_RING_SIZE - 1)) + +#define TX_BUFFS_AVAIL(GP) \ + (((GP)->tx_old <= (GP)->tx_new) ? \ + (GP)->tx_old + (TX_RING_SIZE - 1) - (GP)->tx_new : \ + (GP)->tx_old - (GP)->tx_new - 1) + +#define RX_OFFSET 2 +#define RX_BUF_ALLOC_SIZE (1546 + RX_OFFSET + 64) + +#define RX_COPY_THRESHOLD 256 + +struct gem_init_block { + struct gem_txd txd[TX_RING_SIZE]; + struct gem_rxd rxd[RX_RING_SIZE]; +}; + +enum gem_phy_type { + phy_mii_mdio0, + phy_mii_mdio1, + phy_serialink, + phy_serdes, +}; + +enum link_state { + aneg_wait, + force_wait, +}; + +struct gem { + spinlock_t lock; + unsigned long regs; + int rx_new, rx_old; + int tx_new, tx_old; + + struct gem_init_block *init_block; + + struct sk_buff *rx_skbs[RX_RING_SIZE]; + struct sk_buff *tx_skbs[RX_RING_SIZE]; + + struct net_device_stats net_stats; + + enum gem_phy_type phy_type; + int tx_fifo_sz; + int rx_fifo_sz; + int rx_pause_off; + int rx_pause_on; + int mii_phy_addr; + + /* Diagnostic counters and state. */ + u64 pause_entered; + u16 pause_last_time_recvd; + + struct timer_list link_timer; + int timer_ticks; + enum link_state lstate; + + dma_addr_t gblock_dvma; + struct pci_dev *pdev; + struct net_device *dev; +}; + +#define ALIGNED_RX_SKB_ADDR(addr) \ + ((((unsigned long)(addr) + (64UL - 1UL)) & ~(64UL - 1UL)) - (unsigned long)(addr)) +static __inline__ struct sk_buff *gem_alloc_skb(int size, int gfp_flags) +{ + struct sk_buff *skb = alloc_skb(size + 64, gfp_flags); + + if (skb) { + int offset = (int) ALIGNED_RX_SKB_ADDR(skb->data); + if (offset) + skb_reserve(skb, offset); + } + + return skb; +} + +#endif /* _SUNGEM_H */ diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c index 445929f9d..4e03fff76 100644 --- a/drivers/net/sunlance.c +++ b/drivers/net/sunlance.c @@ -1,4 +1,4 @@ -/* $Id: sunlance.c,v 1.105 2000/10/22 16:08:38 davem Exp $ +/* $Id: sunlance.c,v 1.107 2001/02/18 08:10:21 davem Exp $ * lance.c: Linux/Sparc/Lance driver * * Written 1995, 1996 by Miguel de Icaza @@ -965,9 +965,6 @@ static int lance_open(struct net_device *dev) sbus_writew(LE_C0_INEA | LE_C0_TDMD, lp->lregs + RDP); } - if (!status) - MOD_INC_USE_COUNT; - return status; } @@ -981,7 +978,6 @@ static int lance_close(struct net_device *dev) STOP_LANCE(lp); free_irq(dev->irq, (void *) dev); - MOD_DEC_USE_COUNT; return 0; } @@ -1467,6 +1463,7 @@ no_link_test: } lp->dev = dev; + SET_MODULE_OWNER(dev); dev->open = &lance_open; dev->stop = &lance_close; dev->hard_start_xmit = &lance_start_xmit; diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c index 9643d4c1a..40ea1702c 100644 --- a/drivers/net/sunqe.c +++ b/drivers/net/sunqe.c @@ -1,4 +1,4 @@ -/* $Id: sunqe.c,v 1.47 2000/10/22 16:08:38 davem Exp $ +/* $Id: sunqe.c,v 1.50 2001/02/18 08:10:21 davem Exp $ * sunqe.c: Sparc QuadEthernet 10baseT SBUS card driver. * Once again I am out to prove that every ethernet * controller out there can be most efficiently programmed @@ -438,7 +438,7 @@ static void qe_rx(struct sunqe *qep) len, 0); skb->protocol = eth_type_trans(skb, qep->dev); netif_rx(skb); - dev->last_rx = jiffies; + qep->dev->last_rx = jiffies; qep->net_stats.rx_packets++; qep->net_stats.rx_bytes += len; } @@ -503,16 +503,11 @@ static void qec_interrupt(int irq, void *dev_id, struct pt_regs *regs) static int qe_open(struct net_device *dev) { struct sunqe *qep = (struct sunqe *) dev->priv; - int res; qep->mconfig = (MREGS_MCONFIG_TXENAB | MREGS_MCONFIG_RXENAB | MREGS_MCONFIG_MBAENAB); - res = qe_init(qep, 0); - if (!res) - MOD_INC_USE_COUNT; - - return res; + return qe_init(qep, 0); } static int qe_close(struct net_device *dev) @@ -520,7 +515,6 @@ static int qe_close(struct net_device *dev) struct sunqe *qep = (struct sunqe *) dev->priv; qe_stop(qep); - MOD_DEC_USE_COUNT; return 0; } @@ -882,6 +876,7 @@ static int __init qec_ether_init(struct net_device *dev, struct sbus_dev *sdev) } for (i = 0; i < 4; i++) { + SET_MODULE_OWNER(qe_devs[i]); qe_devs[i]->open = qe_open; qe_devs[i]->stop = qe_close; qe_devs[i]->hard_start_xmit = qe_start_xmit; diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c index e3aae9111..4881f77c8 100644 --- a/drivers/net/tlan.c +++ b/drivers/net/tlan.c @@ -7,10 +7,10 @@ * * (C) 1997-1998 Caldera, Inc. * (C) 1998 James Banks - * (C) 1999, 2000 Torben Mathiasen + * (C) 1999-2001 Torben Mathiasen * * This software may be used and distributed according to the terms - * of the GNU Public License, incorporated herein by reference. + * of the GNU General Public License, incorporated herein by reference. * ** This file is best viewed/edited with columns>=132. * @@ -136,6 +136,28 @@ * * v1.12 Oct 12, 2000 - Minor fixes (memleak, init, etc.) * + * v1.13 Nov 28, 2000 - Stop flooding console with auto-neg issues + * when link can't be established. + * - Added the bbuf option as a kernel parameter. + * - Fixed ioaddr probe bug. + * - Fixed stupid deadlock with MII interrupts. + * - Added support for speed/duplex selection with + * multiple nics. + * - Added partly fix for TX Channel lockup with + * TLAN v1.0 silicon. This needs to be investigated + * further. + * + * v1.14 Dec 16, 2000 - Added support for servicing multiple frames per. + * interrupt. Thanks goes to + * Adam Keys <adam@ti.com> + * Denis Beaudoin <dbeaudoin@ti.com> + * for providing the patch. + * - Fixed auto-neg output when using multiple + * adapters. + * - Converted to use new taskq interface. + * + * v1.14a Jan 6, 2001 - Minor adjustments (spinlocks, etc.) + * *******************************************************************************/ @@ -159,17 +181,19 @@ static struct net_device *TLan_Eisa_Devices; static int TLanDevicesInstalled; -/* Force speed, duplex and aui settings */ -static int aui; -static int duplex; -static int speed; +/* Set speed, duplex and aui settings */ +static int aui[MAX_TLAN_BOARDS]; +static int duplex[MAX_TLAN_BOARDS]; +static int speed[MAX_TLAN_BOARDS]; +static int boards_found; MODULE_AUTHOR("Maintainer: Torben Mathiasen <torben.mathiasen@compaq.com>"); MODULE_DESCRIPTION("Driver for TI ThunderLAN based ethernet PCI adapters"); -MODULE_PARM(aui, "i"); -MODULE_PARM(duplex, "i"); -MODULE_PARM(speed, "i"); +MODULE_PARM(aui, "1-" __MODULE_STRING(MAX_TLAN_BOARDS) "i"); +MODULE_PARM(duplex, "1-" __MODULE_STRING(MAX_TLAN_BOARDS) "i"); +MODULE_PARM(speed, "1-" __MODULE_STRING(MAX_TLAN_BOARDS) "i"); MODULE_PARM(debug, "i"); +MODULE_PARM(bbuf, "i"); EXPORT_NO_SYMBOLS; /* Define this to enable Link beat monitoring */ @@ -181,7 +205,7 @@ static int debug; static int bbuf; static u8 *TLanPadBuffer; static char TLanSignature[] = "TLAN"; -static const char *tlan_banner = "ThunderLAN driver v1.12\n"; +static const char *tlan_banner = "ThunderLAN driver v1.14a\n"; static int tlan_have_pci; static int tlan_have_eisa; @@ -323,17 +347,20 @@ static TLanIntVectorFunc *TLanIntVector[TLAN_INT_NUMBER_OF_INTS] = { static inline void TLan_SetTimer( struct net_device *dev, u32 ticks, u32 type ) { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); + TLanPrivateInfo *priv = dev->priv; + unsigned long flags = 0; + + if (!in_irq()) + spin_lock_irqsave(&priv->lock, flags); if ( priv->timer.function != NULL && priv->timerType != TLAN_TIMER_ACTIVITY ) { - spin_unlock_irqrestore(&priv->lock, flags); + if (!in_irq()) + spin_unlock_irqrestore(&priv->lock, flags); return; } priv->timer.function = &TLan_Timer; - spin_unlock_irqrestore(&priv->lock, flags); + if (!in_irq()) + spin_unlock_irqrestore(&priv->lock, flags); priv->timer.data = (unsigned long) dev; priv->timerSetAt = jiffies; @@ -375,8 +402,8 @@ TLan_SetTimer( struct net_device *dev, u32 ticks, u32 type ) static void __devexit tlan_remove_one( struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + struct net_device *dev = pci_get_drvdata( pdev ); + TLanPrivateInfo *priv = dev->priv; unregister_netdev( dev ); @@ -388,6 +415,7 @@ static void __devexit tlan_remove_one( struct pci_dev *pdev) kfree( dev ); + pci_set_drvdata( pdev, NULL ); } static struct pci_driver tlan_driver = { @@ -404,7 +432,7 @@ static int __init tlan_probe(void) printk(KERN_INFO "%s", tlan_banner); TLanPadBuffer = (u8 *) kmalloc(TLAN_MIN_FRAME_SIZE, - (GFP_KERNEL | GFP_DMA)); + GFP_KERNEL); if (TLanPadBuffer == NULL) { printk(KERN_ERR "TLAN: Could not allocate memory for pad buffer.\n"); @@ -426,18 +454,19 @@ static int __init tlan_probe(void) printk(KERN_INFO "TLAN: %d device%s installed, PCI: %d EISA: %d\n", TLanDevicesInstalled, TLanDevicesInstalled == 1 ? "" : "s", tlan_have_pci, tlan_have_eisa); - - return ((TLanDevicesInstalled > 0) ? 0 : -ENODEV); + if (TLanDevicesInstalled == 0) { + kfree(TLanPadBuffer); + return -ENODEV; + } + return 0; } static int __devinit tlan_init_one( struct pci_dev *pdev, const struct pci_device_id *ent) { - return TLan_probe1( pdev, pci_resource_start(pdev, 0), pdev->irq, - 0, ent); - + return TLan_probe1( pdev, -1, -1, 0, ent); } @@ -468,6 +497,10 @@ static int __devinit TLan_probe1(struct pci_dev *pdev, TLanPrivateInfo *priv; u8 pci_rev; u16 device_id; + int reg; + + if (pdev && pci_enable_device(pdev)) + return -EIO; dev = init_etherdev(NULL, sizeof(TLanPrivateInfo)); if (dev == NULL) { @@ -477,23 +510,35 @@ static int __devinit TLan_probe1(struct pci_dev *pdev, SET_MODULE_OWNER(dev); priv = dev->priv; - - dev->base_addr = ioaddr; - dev->irq = irq; - /* Is this a PCI device? */ if (pdev) { + u32 pci_io_base = 0; + priv->adapter = &board_info[ent->driver_data]; - if (pci_enable_device(pdev)) { + + pci_read_config_byte ( pdev, PCI_REVISION_ID, &pci_rev); + + for ( reg= 0; reg <= 5; reg ++ ) { + if (pci_resource_flags(pdev, reg) & IORESOURCE_IO) { + pci_io_base = pci_resource_start(pdev, reg); + TLAN_DBG( TLAN_DEBUG_GNRL, "IO mapping is available at %x.\n", + pci_io_base); + break; + } + } + if (!pci_io_base) { + printk(KERN_ERR "TLAN: No IO mappings available\n"); unregister_netdev(dev); kfree(dev); - return -1; + return -ENODEV; } - pci_read_config_byte ( pdev, PCI_REVISION_ID, &pci_rev); + + dev->base_addr = pci_io_base; + dev->irq = pdev->irq; priv->adapterRev = pci_rev; pci_set_master(pdev); - pdev->driver_data = dev; + pci_set_drvdata(pdev, dev); } else { /* EISA card */ /* This is a hack. We need to know which board structure @@ -507,6 +552,8 @@ static int __devinit TLan_probe1(struct pci_dev *pdev, priv->adapter = &board_info[14]; priv->adapterRev = 10; /* TLAN 1.0 */ } + dev->base_addr = ioaddr; + dev->irq = irq; } /* Kernel parameters */ @@ -522,21 +569,19 @@ static int __devinit TLan_probe1(struct pci_dev *pdev, } debug = priv->debug = dev->mem_end; } else { - - if ( ( duplex != 1 ) && ( duplex != 2 ) ) - duplex = 0; - - priv->duplex = duplex; - - if ( ( speed != 10 ) && ( speed != 100 ) ) - speed = 0; - - priv->aui = aui; - priv->speed = speed; + priv->aui = aui[boards_found]; + priv->speed = speed[boards_found]; + priv->duplex = duplex[boards_found]; priv->debug = debug; - } + /* This will be used when we get an adapter error from + * within our irq handler */ + INIT_LIST_HEAD(&priv->tlan_tqueue.list); + priv->tlan_tqueue.sync = 0; + priv->tlan_tqueue.routine = (void *)(void*)TLan_tx_timeout; + priv->tlan_tqueue.data = dev; + spin_lock_init(&priv->lock); if (TLan_Init(dev)) { @@ -547,6 +592,7 @@ static int __devinit TLan_probe1(struct pci_dev *pdev, } else { TLanDevicesInstalled++; + boards_found++; /* pdev is NULL if this is an EISA device */ if (pdev) @@ -576,7 +622,7 @@ static void TLan_Eisa_Cleanup(void) while( tlan_have_eisa ) { dev = TLan_Eisa_Devices; - priv = (TLanPrivateInfo *) dev->priv; + priv = dev->priv; if (priv->dmaStorage) { kfree(priv->dmaStorage); } @@ -730,7 +776,7 @@ static int TLan_Init( struct net_device *dev ) int i; TLanPrivateInfo *priv; - priv = (TLanPrivateInfo *) dev->priv; + priv = dev->priv; if (!priv->is_eisa) /* EISA devices have already requested IO */ if (!request_region( dev->base_addr, 0x10, TLanSignature )) { @@ -752,6 +798,7 @@ static int TLan_Init( struct net_device *dev ) if ( priv->dmaStorage == NULL ) { printk(KERN_ERR "TLAN: Could not allocate lists and buffers for %s.\n", dev->name ); + release_region( dev->base_addr, 0x10 ); return -ENOMEM; } memset( priv->dmaStorage, 0, dma_size ); @@ -812,7 +859,7 @@ static int TLan_Init( struct net_device *dev ) static int TLan_Open( struct net_device *dev ) { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanPrivateInfo *priv = dev->priv; int err; priv->tlanRev = TLan_DioRead8( dev->base_addr, TLAN_DEF_REVISION ); @@ -858,7 +905,7 @@ static int TLan_Open( struct net_device *dev ) static int TLan_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanPrivateInfo *priv = dev->priv; u16 *data = (u16 *)&rq->ifr_data; u32 phy = priv->phy[priv->phyNum]; @@ -901,6 +948,7 @@ static void TLan_tx_timeout(struct net_device *dev) TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Transmit timed out.\n", dev->name); /* Ok so we timed out, lets see what we can do about it...*/ + TLan_FreeLists( dev ); TLan_ResetLists( dev ); TLan_ReadAndClearStats( dev, TLAN_IGNORE ); TLan_ResetAdapter( dev ); @@ -934,7 +982,7 @@ static void TLan_tx_timeout(struct net_device *dev) static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev ) { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanPrivateInfo *priv = dev->priv; TLanList *tail_list; u8 *tail_buffer; int pad; @@ -947,7 +995,7 @@ static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev ) } tail_list = priv->txList + priv->txTail; - + if ( tail_list->cStat != TLAN_CSTAT_UNUSED ) { TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: %s is busy (Head=%d Tail=%d)\n", dev->name, priv->txHead, priv->txTail ); netif_stop_queue(dev); @@ -983,10 +1031,9 @@ static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev ) tail_list->cStat = TLAN_CSTAT_READY; if ( ! priv->txInProgress ) { priv->txInProgress = 1; - outw( 0x4, dev->base_addr + TLAN_HOST_INT ); TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Starting TX on buffer %d\n", priv->txTail ); outl( virt_to_bus( tail_list ), dev->base_addr + TLAN_CH_PARM ); - outl( TLAN_HC_GO | TLAN_HC_ACK, dev->base_addr + TLAN_HOST_CMD ); + outl( TLAN_HC_GO, dev->base_addr + TLAN_HOST_CMD ); } else { TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Adding buffer %d to TX channel\n", priv->txTail ); if ( priv->txTail == 0 ) { @@ -1040,8 +1087,8 @@ static void TLan_HandleInterrupt(int irq, void *dev_id, struct pt_regs *regs) int type; TLanPrivateInfo *priv; - dev = (struct net_device *) dev_id; - priv = (TLanPrivateInfo *) dev->priv; + dev = dev_id; + priv = dev->priv; spin_lock(&priv->lock); @@ -1081,9 +1128,10 @@ static void TLan_HandleInterrupt(int irq, void *dev_id, struct pt_regs *regs) static int TLan_Close(struct net_device *dev) { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanPrivateInfo *priv = dev->priv; netif_stop_queue(dev); + priv->neg_be_verbose = 0; TLan_ReadAndClearStats( dev, TLAN_RECORD ); outl( TLAN_HC_AD_RST, dev->base_addr + TLAN_HOST_CMD ); @@ -1120,7 +1168,7 @@ static int TLan_Close(struct net_device *dev) static struct net_device_stats *TLan_GetStats( struct net_device *dev ) { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanPrivateInfo *priv = dev->priv; int i; /* Should only read stats if open ? */ @@ -1242,7 +1290,6 @@ static void TLan_SetMulticastList( struct net_device *dev ) u32 TLan_HandleInvalid( struct net_device *dev, u16 host_int ) { - host_int = 0; /* printk( "TLAN: Invalid interrupt on %s.\n", dev->name ); */ return 0; @@ -1275,33 +1322,36 @@ u32 TLan_HandleInvalid( struct net_device *dev, u16 host_int ) u32 TLan_HandleTxEOF( struct net_device *dev, u16 host_int ) { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanPrivateInfo *priv = dev->priv; int eoc = 0; TLanList *head_list; - u32 ack = 1; - + u32 ack = 0; + u16 tmpCStat; + TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Handling TX EOF (Head=%d Tail=%d)\n", priv->txHead, priv->txTail ); - host_int = 0; head_list = priv->txList + priv->txHead; - if ( ! bbuf ) { - dev_kfree_skb_irq( (struct sk_buff *) head_list->buffer[9].address ); - head_list->buffer[9].address = 0; - } + while (((tmpCStat = head_list->cStat ) & TLAN_CSTAT_FRM_CMP) && (ack < 255)) { + ack++; + if ( ! bbuf ) { + dev_kfree_skb_any( (struct sk_buff *) head_list->buffer[9].address ); + head_list->buffer[9].address = 0; + } + + if ( tmpCStat & TLAN_CSTAT_EOC ) + eoc = 1; + + priv->stats.tx_bytes += head_list->frameSize; - if ( head_list->cStat & TLAN_CSTAT_EOC ) - eoc = 1; - if ( ! head_list->cStat & TLAN_CSTAT_FRM_CMP ) { - printk( "TLAN: Received interrupt for uncompleted TX frame.\n" ); + head_list->cStat = TLAN_CSTAT_UNUSED; + netif_start_queue(dev); + CIRC_INC( priv->txHead, TLAN_NUM_TX_LISTS ); + head_list = priv->txList + priv->txHead; } - priv->stats.tx_bytes += head_list->frameSize; - - head_list->cStat = TLAN_CSTAT_UNUSED; - - netif_start_queue(dev); + if (!ack) + printk(KERN_INFO "TLAN: Received interrupt for uncompleted TX frame.\n"); - CIRC_INC( priv->txHead, TLAN_NUM_TX_LISTS ); if ( eoc ) { TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Handling TX EOC (Head=%d Tail=%d)\n", priv->txHead, priv->txTail ); head_list = priv->txList + priv->txHead; @@ -1312,7 +1362,7 @@ u32 TLan_HandleTxEOF( struct net_device *dev, u16 host_int ) priv->txInProgress = 0; } } - + if ( priv->adapter->flags & TLAN_ADAPTER_ACTIVITY_LED ) { TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT ); if ( priv->timer.function == NULL ) { @@ -1353,7 +1403,6 @@ u32 TLan_HandleTxEOF( struct net_device *dev, u16 host_int ) u32 TLan_HandleStatOverflow( struct net_device *dev, u16 host_int ) { - host_int = 0; TLan_ReadAndClearStats( dev, TLAN_RECORD ); return 1; @@ -1384,87 +1433,95 @@ u32 TLan_HandleStatOverflow( struct net_device *dev, u16 host_int ) * of the list. If the frame was the last in the Rx * channel (EOC), the function restarts the receive channel * by sending an Rx Go command to the adapter. Then it - * activates/continues the the activity LED. + * activates/continues the activity LED. * **************************************************************/ u32 TLan_HandleRxEOF( struct net_device *dev, u16 host_int ) { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; - u32 ack = 1; + TLanPrivateInfo *priv = dev->priv; + u32 ack = 0; int eoc = 0; u8 *head_buffer; TLanList *head_list; struct sk_buff *skb; TLanList *tail_list; void *t; + u32 frameSize; + u16 tmpCStat; TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE: Handling RX EOF (Head=%d Tail=%d)\n", priv->rxHead, priv->rxTail ); - host_int = 0; head_list = priv->rxList + priv->rxHead; - tail_list = priv->rxList + priv->rxTail; - - if ( head_list->cStat & TLAN_CSTAT_EOC ) { - eoc = 1; - } + + while (((tmpCStat = head_list->cStat) & TLAN_CSTAT_FRM_CMP) && (ack < 255)) { + frameSize = head_list->frameSize; + ack++; + if (tmpCStat & TLAN_CSTAT_EOC) + eoc = 1; + + if (bbuf) { + skb = dev_alloc_skb(frameSize + 7); + if (skb == NULL) + printk(KERN_INFO "TLAN: Couldn't allocate memory for received data.\n"); + else { + head_buffer = priv->rxBuffer + (priv->rxHead * TLAN_MAX_FRAME_SIZE); + skb->dev = dev; + skb_reserve(skb, 2); + t = (void *) skb_put(skb, frameSize); + + priv->stats.rx_bytes += head_list->frameSize; - if ( ! head_list->cStat & TLAN_CSTAT_FRM_CMP ) { - printk( "TLAN: Received interrupt for uncompleted RX frame.\n" ); - } else if ( bbuf ) { - skb = dev_alloc_skb( head_list->frameSize + 7 ); - if ( skb == NULL ) { - printk( "TLAN: Couldn't allocate memory for received data.\n" ); + memcpy( t, head_buffer, frameSize ); + skb->protocol = eth_type_trans( skb, dev ); + netif_rx( skb ); + } } else { - head_buffer = priv->rxBuffer + ( priv->rxHead * TLAN_MAX_FRAME_SIZE ); - skb->dev = dev; - skb_reserve( skb, 2 ); - t = (void *) skb_put( skb, head_list->frameSize ); - - priv->stats.rx_bytes += head_list->frameSize; - - memcpy( t, head_buffer, head_list->frameSize ); - skb->protocol = eth_type_trans( skb, dev ); - netif_rx( skb ); - } - } else { - struct sk_buff *new_skb; + struct sk_buff *new_skb; - /* - * I changed the algorithm here. What we now do - * is allocate the new frame. If this fails we - * simply recycle the frame. - */ + /* + * I changed the algorithm here. What we now do + * is allocate the new frame. If this fails we + * simply recycle the frame. + */ - new_skb = dev_alloc_skb( TLAN_MAX_FRAME_SIZE + 7 ); - if ( new_skb != NULL ) { - /* If this ever happened it would be a problem */ - /* not any more - ac */ - skb = (struct sk_buff *) head_list->buffer[9].address; - head_list->buffer[9].address = 0; - skb_trim( skb, head_list->frameSize ); + new_skb = dev_alloc_skb( TLAN_MAX_FRAME_SIZE + 7 ); + + if ( new_skb != NULL ) { + /* If this ever happened it would be a problem */ + /* not any more - ac */ + skb = (struct sk_buff *) head_list->buffer[9].address; + skb_trim( skb, frameSize ); - priv->stats.rx_bytes += head_list->frameSize; + priv->stats.rx_bytes += frameSize; - skb->protocol = eth_type_trans( skb, dev ); - netif_rx( skb ); + skb->protocol = eth_type_trans( skb, dev ); + netif_rx( skb ); - new_skb->dev = dev; - skb_reserve( new_skb, 2 ); - t = (void *) skb_put( new_skb, TLAN_MAX_FRAME_SIZE ); - head_list->buffer[0].address = virt_to_bus( t ); - head_list->buffer[9].address = (u32) new_skb; + new_skb->dev = dev; + skb_reserve( new_skb, 2 ); + t = (void *) skb_put( new_skb, TLAN_MAX_FRAME_SIZE ); + head_list->buffer[0].address = virt_to_bus( t ); + head_list->buffer[8].address = (u32) t; + head_list->buffer[9].address = (u32) new_skb; + } else + printk(KERN_WARNING "TLAN: Couldn't allocate memory for received data.\n" ); } - else - printk(KERN_WARNING "TLAN: Couldn't allocate memory for received data.\n" ); + + head_list->forward = 0; + head_list->cStat = 0; + tail_list = priv->rxList + priv->rxTail; + tail_list->forward = virt_to_bus( head_list ); + + CIRC_INC( priv->rxHead, TLAN_NUM_RX_LISTS ); + CIRC_INC( priv->rxTail, TLAN_NUM_RX_LISTS ); + head_list = priv->rxList + priv->rxHead; } - head_list->forward = 0; - head_list->frameSize = TLAN_MAX_FRAME_SIZE; - head_list->buffer[0].count = TLAN_MAX_FRAME_SIZE | TLAN_LAST_BUFFER; - tail_list->forward = virt_to_bus( head_list ); + if (!ack) + printk(KERN_INFO "TLAN: Received interrupt for uncompleted RX frame.\n"); + + - CIRC_INC( priv->rxHead, TLAN_NUM_RX_LISTS ); - CIRC_INC( priv->rxTail, TLAN_NUM_RX_LISTS ); if ( eoc ) { TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE: Handling RX EOC (Head=%d Tail=%d)\n", priv->rxHead, priv->rxTail ); @@ -1489,7 +1546,7 @@ u32 TLan_HandleRxEOF( struct net_device *dev, u16 host_int ) } dev->last_rx = jiffies; - + return ack; } /* TLan_HandleRxEOF */ @@ -1516,7 +1573,6 @@ u32 TLan_HandleRxEOF( struct net_device *dev, u16 host_int ) u32 TLan_HandleDummy( struct net_device *dev, u16 host_int ) { - host_int = 0; printk( "TLAN: Test interrupt on %s.\n", dev->name ); return 1; @@ -1547,15 +1603,16 @@ u32 TLan_HandleDummy( struct net_device *dev, u16 host_int ) u32 TLan_HandleTxEOC( struct net_device *dev, u16 host_int ) { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanPrivateInfo *priv = dev->priv; TLanList *head_list; - u32 ack = 1; - + u32 ack = 1; + host_int = 0; if ( priv->tlanRev < 0x30 ) { TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Handling TX EOC (Head=%d Tail=%d) -- IRQ\n", priv->txHead, priv->txTail ); head_list = priv->txList + priv->txHead; if ( ( head_list->cStat & TLAN_CSTAT_READY ) == TLAN_CSTAT_READY ) { + netif_stop_queue(dev); outl( virt_to_bus( head_list ), dev->base_addr + TLAN_CH_PARM ); ack |= TLAN_HC_GO; } else { @@ -1592,7 +1649,7 @@ u32 TLan_HandleTxEOC( struct net_device *dev, u16 host_int ) u32 TLan_HandleStatusCheck( struct net_device *dev, u16 host_int ) { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanPrivateInfo *priv = dev->priv; u32 ack; u32 error; u8 net_sts; @@ -1602,14 +1659,16 @@ u32 TLan_HandleStatusCheck( struct net_device *dev, u16 host_int ) ack = 1; if ( host_int & TLAN_HI_IV_MASK ) { + netif_stop_queue( dev ); error = inl( dev->base_addr + TLAN_CH_PARM ); printk( "TLAN: %s: Adaptor Error = 0x%x\n", dev->name, error ); TLan_ReadAndClearStats( dev, TLAN_RECORD ); outl( TLAN_HC_AD_RST, dev->base_addr + TLAN_HOST_CMD ); - TLan_FreeLists( dev ); - TLan_ResetLists( dev ); - TLan_ResetAdapter( dev ); - netif_start_queue(dev); + + queue_task(&priv->tlan_tqueue, &tq_immediate); + mark_bh(IMMEDIATE_BH); + + netif_wake_queue(dev); ack = 0; } else { TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Status Check\n", dev->name ); @@ -1666,11 +1725,10 @@ u32 TLan_HandleStatusCheck( struct net_device *dev, u16 host_int ) u32 TLan_HandleRxEOC( struct net_device *dev, u16 host_int ) { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanPrivateInfo *priv = dev->priv; TLanList *head_list; u32 ack = 1; - host_int = 0; if ( priv->tlanRev < 0x30 ) { TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE: Handling RX EOC (Head=%d Tail=%d) -- IRQ\n", priv->rxHead, priv->rxTail ); head_list = priv->rxList + priv->rxHead; @@ -1728,7 +1786,7 @@ u32 TLan_HandleRxEOC( struct net_device *dev, u16 host_int ) void TLan_Timer( unsigned long data ) { struct net_device *dev = (struct net_device *) data; - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanPrivateInfo *priv = dev->priv; u32 elapsed; unsigned long flags = 0; @@ -1808,7 +1866,7 @@ void TLan_Timer( unsigned long data ) void TLan_ResetLists( struct net_device *dev ) { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanPrivateInfo *priv = dev->priv; int i; TLanList *list; struct sk_buff *skb; @@ -1826,6 +1884,7 @@ void TLan_ResetLists( struct net_device *dev ) } list->buffer[2].count = 0; list->buffer[2].address = 0; + list->buffer[9].address = 0; } priv->rxHead = 0; @@ -1848,6 +1907,7 @@ void TLan_ResetLists( struct net_device *dev ) t = (void *) skb_put( skb, TLAN_MAX_FRAME_SIZE ); } list->buffer[0].address = virt_to_bus( t ); + list->buffer[8].address = (u32) t; list->buffer[9].address = (u32) skb; } list->buffer[1].count = 0; @@ -1863,7 +1923,7 @@ void TLan_ResetLists( struct net_device *dev ) void TLan_FreeLists( struct net_device *dev ) { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanPrivateInfo *priv = dev->priv; int i; TLanList *list; struct sk_buff *skb; @@ -1902,7 +1962,7 @@ void TLan_FreeLists( struct net_device *dev ) * io_base Base IO port of the device of * which to print DIO registers. * - * This function prints out all the the internal (DIO) + * This function prints out all the internal (DIO) * registers of a TLAN chip. * **************************************************************/ @@ -1980,7 +2040,7 @@ void TLan_PrintList( TLanList *list, char *type, int num) void TLan_ReadAndClearStats( struct net_device *dev, int record ) { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanPrivateInfo *priv = dev->priv; u32 tx_good, tx_under; u32 rx_good, rx_over; u32 def_tx, crc, code; @@ -2056,7 +2116,7 @@ void TLan_ReadAndClearStats( struct net_device *dev, int record ) void TLan_ResetAdapter( struct net_device *dev ) { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanPrivateInfo *priv = dev->priv; int i; u32 addr; u32 data; @@ -2091,8 +2151,8 @@ TLan_ResetAdapter( struct net_device *dev ) /* 5. Load Ld_Tmr and Ld_Thr in HOST_CMD. */ - outl( TLAN_HC_LD_TMR | 0x0, dev->base_addr + TLAN_HOST_CMD ); - outl( TLAN_HC_LD_THR | 0x1, dev->base_addr + TLAN_HOST_CMD ); + outl( TLAN_HC_LD_TMR | 0x3f, dev->base_addr + TLAN_HOST_CMD ); + outl( TLAN_HC_LD_THR | 0x9, dev->base_addr + TLAN_HOST_CMD ); /* 6. Unreset the MII by setting NMRST (in NetSio) to 1. */ @@ -2108,6 +2168,7 @@ TLan_ResetAdapter( struct net_device *dev ) } TLan_PhyDetect( dev ); data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN; + if ( priv->adapter->flags & TLAN_ADAPTER_BIT_RATE_PHY ) { data |= TLAN_NET_CFG_BIT; if ( priv->aui == 1 ) { @@ -2119,6 +2180,7 @@ TLan_ResetAdapter( struct net_device *dev ) TLan_DioWrite8( dev->base_addr, TLAN_ACOMMIT, 0x08 ); } } + if ( priv->phyNum == 0 ) { data |= TLAN_NET_CFG_PHY_EN; } @@ -2138,7 +2200,7 @@ TLan_ResetAdapter( struct net_device *dev ) void TLan_FinishReset( struct net_device *dev ) { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanPrivateInfo *priv = dev->priv; u8 data; u32 phy; u8 sio; @@ -2161,7 +2223,7 @@ TLan_FinishReset( struct net_device *dev ) data |= TLAN_NET_MASK_MASK7; } TLan_DioWrite8( dev->base_addr, TLAN_NET_MASK, data ); - TLan_DioWrite16( dev->base_addr, TLAN_MAX_RX, TLAN_MAX_FRAME_SIZE ); + TLan_DioWrite16( dev->base_addr, TLAN_MAX_RX, ((1536)+7)&~7 ); TLan_MiiReadReg( dev, phy, MII_GEN_ID_HI, &tlphy_id1 ); TLan_MiiReadReg( dev, phy, MII_GEN_ID_LO, &tlphy_id2 ); @@ -2301,7 +2363,7 @@ void TLan_SetMac( struct net_device *dev, int areg, char *mac ) void TLan_PhyPrint( struct net_device *dev ) { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanPrivateInfo *priv = dev->priv; u16 i, data0, data1, data2, data3, phy; phy = priv->phy[priv->phyNum]; @@ -2350,7 +2412,7 @@ void TLan_PhyPrint( struct net_device *dev ) void TLan_PhyDetect( struct net_device *dev ) { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanPrivateInfo *priv = dev->priv; u16 control; u16 hi; u16 lo; @@ -2397,7 +2459,7 @@ void TLan_PhyDetect( struct net_device *dev ) void TLan_PhyPowerDown( struct net_device *dev ) { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanPrivateInfo *priv = dev->priv; u16 value; TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Powering down PHY(s).\n", dev->name ); @@ -2422,7 +2484,7 @@ void TLan_PhyPowerDown( struct net_device *dev ) void TLan_PhyPowerUp( struct net_device *dev ) { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanPrivateInfo *priv = dev->priv; u16 value; TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Powering up PHY.\n", dev->name ); @@ -2443,7 +2505,7 @@ void TLan_PhyPowerUp( struct net_device *dev ) void TLan_PhyReset( struct net_device *dev ) { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanPrivateInfo *priv = dev->priv; u16 phy; u16 value; @@ -2471,7 +2533,7 @@ void TLan_PhyReset( struct net_device *dev ) void TLan_PhyStartLink( struct net_device *dev ) { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanPrivateInfo *priv = dev->priv; u16 ability; u16 control; u16 data; @@ -2558,7 +2620,7 @@ void TLan_PhyStartLink( struct net_device *dev ) void TLan_PhyFinishAutoNeg( struct net_device *dev ) { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanPrivateInfo *priv = dev->priv; u16 an_adv; u16 an_lpa; u16 data; @@ -2576,7 +2638,12 @@ void TLan_PhyFinishAutoNeg( struct net_device *dev ) /* Wait for 8 sec to give the process * more time. Perhaps we should fail after a while. */ - printk( "TLAN: Giving autonegotiation more time.\n" ); + if (!priv->neg_be_verbose++) { + printk(KERN_INFO "TLAN: Giving autonegotiation more time.\n"); + printk(KERN_INFO "TLAN: Please check that your adapter has\n"); + printk(KERN_INFO "TLAN: been properly connected to a HUB or Switch.\n"); + printk(KERN_INFO "TLAN: Trying to establish link in the background...\n"); + } TLan_SetTimer( dev, (8*HZ), TLAN_TIMER_PHY_FINISH_AN ); return; } @@ -2637,7 +2704,7 @@ void TLan_PhyFinishAutoNeg( struct net_device *dev ) void TLan_PhyMonitor( struct net_device *dev ) { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanPrivateInfo *priv = dev->priv; u16 phy; u16 phy_status; @@ -2714,14 +2781,15 @@ int TLan_MiiReadReg( struct net_device *dev, u16 phy, u16 reg, u16 *val ) u32 i; int err; int minten; - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanPrivateInfo *priv = dev->priv; unsigned long flags = 0; err = FALSE; outw(TLAN_NET_SIO, dev->base_addr + TLAN_DIO_ADR); sio = dev->base_addr + TLAN_DIO_DATA + TLAN_NET_SIO; - - spin_lock_irqsave(&priv->lock, flags); + + if (!in_irq()) + spin_lock_irqsave(&priv->lock, flags); TLan_MiiSync(dev->base_addr); @@ -2767,8 +2835,9 @@ int TLan_MiiReadReg( struct net_device *dev, u16 phy, u16 reg, u16 *val ) TLan_SetBit(TLAN_NET_SIO_MINTEN, sio); *val = tmp; - - spin_unlock_irqrestore(&priv->lock, flags); + + if (!in_irq()) + spin_unlock_irqrestore(&priv->lock, flags); return err; @@ -2881,12 +2950,13 @@ void TLan_MiiWriteReg( struct net_device *dev, u16 phy, u16 reg, u16 val ) u16 sio; int minten; unsigned long flags = 0; - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanPrivateInfo *priv = dev->priv; outw(TLAN_NET_SIO, dev->base_addr + TLAN_DIO_ADR); sio = dev->base_addr + TLAN_DIO_DATA + TLAN_NET_SIO; - - spin_lock_irqsave(&priv->lock, flags); + + if (!in_irq()) + spin_lock_irqsave(&priv->lock, flags); TLan_MiiSync( dev->base_addr ); @@ -2907,8 +2977,9 @@ void TLan_MiiWriteReg( struct net_device *dev, u16 phy, u16 reg, u16 val ) if ( minten ) TLan_SetBit( TLAN_NET_SIO_MINTEN, sio ); - - spin_unlock_irqrestore(&priv->lock, flags); + + if (!in_irq()) + spin_unlock_irqrestore(&priv->lock, flags); } /* TLan_MiiWriteReg */ @@ -3106,7 +3177,7 @@ void TLan_EeReceiveByte( u16 io_base, u8 *data, int stop ) int TLan_EeReadByte( struct net_device *dev, u8 ee_addr, u8 *data ) { int err; - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanPrivateInfo *priv = dev->priv; unsigned long flags = 0; int ret=0; diff --git a/drivers/net/tlan.h b/drivers/net/tlan.h index deb96db01..09fee7a20 100644 --- a/drivers/net/tlan.h +++ b/drivers/net/tlan.h @@ -8,10 +8,10 @@ * by James Banks * * (C) 1997-1998 Caldera, Inc. - * (C) 1999-2000 Torben Mathiasen + * (C) 1999-2001 Torben Mathiasen * * This software may be used and distributed according to the terms - * of the GNU Public License, incorporated herein by reference. + * of the GNU General Public License, incorporated herein by reference. * ** This file is best viewed/edited with tabstop=4, colums>=132 * @@ -36,11 +36,11 @@ #define FALSE 0 #define TRUE 1 -#define TLAN_MIN_FRAME_SIZE 60 -#define TLAN_MAX_FRAME_SIZE 1536 +#define TLAN_MIN_FRAME_SIZE 64 +#define TLAN_MAX_FRAME_SIZE 1600 -#define TLAN_NUM_RX_LISTS 4 -#define TLAN_NUM_TX_LISTS 8 +#define TLAN_NUM_RX_LISTS 32 +#define TLAN_NUM_TX_LISTS 64 #define TLAN_IGNORE 0 #define TLAN_RECORD 1 @@ -53,7 +53,7 @@ #define TLAN_DEBUG_PROBE 0x0010 #define TX_TIMEOUT (10*HZ) /* We need time for auto-neg */ - +#define MAX_TLAN_BOARDS 8 /* Max number of boards installed at a time */ /***************************************************************** @@ -209,6 +209,8 @@ typedef struct tlan_private_tag { spinlock_t lock; u8 link; u8 is_eisa; + struct tq_struct tlan_tqueue; + u8 neg_be_verbose; } TLanPrivateInfo; diff --git a/drivers/net/tokenring/Config.in b/drivers/net/tokenring/Config.in index 9fc87041f..e087359bc 100644 --- a/drivers/net/tokenring/Config.in +++ b/drivers/net/tokenring/Config.in @@ -5,21 +5,29 @@ mainmenu_option next_comment comment 'Token Ring devices' -bool 'Token Ring driver support' CONFIG_TR +# So far, we only have PCI, ISA, and MCA token ring devices +if [ "$CONFIG_PCI" = "y" -o "$CONFIG_ISA" = "y" -o "$CONFIG_MCA" = "y" ]; then + bool 'Token Ring driver support' CONFIG_TR +else + define_bool CONFIG_TR n +fi + if [ "$CONFIG_TR" != "n" ]; then - dep_tristate ' IBM Tropic chipset based adapter support' CONFIG_IBMTR $CONFIG_TR - dep_tristate ' IBM Olympic chipset PCI adapter support' CONFIG_IBMOL $CONFIG_TR - dep_tristate ' IBM Lanstreamer chipset PCI adapter support' CONFIG_IBMLS $CONFIG_TR - dep_tristate ' Generic TMS380 Token Ring ISA/PCI adapter support' CONFIG_TMS380TR $CONFIG_TR + if [ "$CONFIG_ISA" = "y" -o "$CONFIG_MCA" = "y" ]; then + tristate ' IBM Tropic chipset based adapter support' CONFIG_IBMTR + fi + dep_tristate ' IBM Olympic chipset PCI adapter support' CONFIG_IBMOL $CONFIG_TR $CONFIG_PCI + dep_tristate ' IBM Lanstreamer chipset PCI adapter support' CONFIG_IBMLS $CONFIG_TR $CONFIG_PCI + tristate ' Generic TMS380 Token Ring ISA/PCI adapter support' CONFIG_TMS380TR if [ "$CONFIG_TMS380TR" != "n" ]; then - dep_tristate ' Generic TMS380 PCI support' CONFIG_TMSPCI $CONFIG_TMS380TR - dep_tristate ' Generic TMS380 ISA support' CONFIG_TMSISA $CONFIG_TMS380TR - dep_tristate ' Madge Smart 16/4 PCI Mk2 support' CONFIG_ABYSS $CONFIG_TMS380TR - if [ "$CONFIG_MCA" = "y" ]; then - dep_tristate ' Madge Smart 16/4 Ringnode MicroChannel' CONFIG_MADGEMC $CONFIG_TMS380TR - fi + dep_tristate ' Generic TMS380 PCI support' CONFIG_TMSPCI $CONFIG_PCI + dep_tristate ' Generic TMS380 ISA support' CONFIG_TMSISA $CONFIG_ISA + dep_tristate ' Madge Smart 16/4 PCI Mk2 support' CONFIG_ABYSS $CONFIG_PCI + dep_tristate ' Madge Smart 16/4 Ringnode MicroChannel' CONFIG_MADGEMC $CONFIG_MCA + fi + if [ "$CONFIG_ISA" = "y" -o "$CONFIG_MCA" = "y" ]; then + tristate ' SMC ISA/MCA adapter support' CONFIG_SMCTR fi - dep_tristate ' SMC ISA/MCA adapter support' CONFIG_SMCTR $CONFIG_TR fi endmenu diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c index 6f83a98a6..0f9ac4f85 100644 --- a/drivers/net/tokenring/ibmtr.c +++ b/drivers/net/tokenring/ibmtr.c @@ -255,12 +255,16 @@ static void __init HWPrtChanID (__u32 pcid, short stride) * * We expect ibmtr_probe to be called once for each device entry * which references it. + * + * Argument 'dev' should never be NULL. If we are built into + * the kernel, Space.c passed up a net_device. If we are + * -DMODULE, init_module allocates net_devices for us. */ int __init ibmtr_probe(struct net_device *dev) { int i; - int base_addr = dev ? dev->base_addr : 0; + int base_addr = dev->base_addr; if (base_addr > 0x1ff) { @@ -301,7 +305,7 @@ static int __init ibmtr_probe1(struct net_device *dev, int PIOaddr) #ifndef MODULE #ifndef PCMCIA - dev = init_trdev(dev,0); + dev = init_trdev(dev, 0); #endif #endif @@ -1877,8 +1881,11 @@ int init_module(void) mem[i] = 0; dev_ibmtr[i] = NULL; dev_ibmtr[i] = init_trdev(dev_ibmtr[i], 0); - if (dev_ibmtr[i] == NULL) - return -ENOMEM; + if (dev_ibmtr[i] == NULL) { + if (i == 0) + return -ENOMEM; + break; + } dev_ibmtr[i]->base_addr = io[i]; dev_ibmtr[i]->irq = irq[i]; diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c index e23212f38..50c42edbc 100644 --- a/drivers/net/tokenring/lanstreamer.c +++ b/drivers/net/tokenring/lanstreamer.c @@ -59,12 +59,10 @@ * 03/03/00 - Merged to kernel, indented -kr -i8 -bri0, fixed some missing * malloc free checks, reviewed code. <alan@redhat.com> * 03/13/00 - Added spinlocks for smp + * 03/08/01 - Added support for module_init() and module_exit() * * To Do: * - * 1) Test Network Monitor Mode - * 2) Add auto reset logic on adapter errors - * 3) Test with varying options * * If Problems do Occur * Most problems can be rectified by either closing and opening the interface @@ -123,7 +121,14 @@ * Official releases will only have an a.b.c version number format. */ -static char *version = "LanStreamer.c v0.3.1 03/13/99 - Mike Sullivan"; +static char *version = "LanStreamer.c v0.4.0 03/08/01 - Mike Sullivan"; + +static struct pci_device_id streamer_pci_tbl[] __initdata = { + { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_TR, PCI_ANY_ID, PCI_ANY_ID,}, + {} /* terminating entry */ +}; +MODULE_DEVICE_TABLE(pci,streamer_pci_tbl); + static char *open_maj_error[] = { "No error", "Lobe Media Test", "Physical Insertion", @@ -170,8 +175,7 @@ static int message_level[STREAMER_MAX_ADAPTERS] = { 1, }; MODULE_PARM(message_level, "1-" __MODULE_STRING(STREAMER_MAX_ADAPTERS) "i"); -static int streamer_scan(struct net_device *dev); -static int streamer_init(struct net_device *dev); +static int streamer_reset(struct net_device *dev); static int streamer_open(struct net_device *dev); static int streamer_xmit(struct sk_buff *skb, struct net_device *dev); static int streamer_close(struct net_device *dev); @@ -186,98 +190,190 @@ static void streamer_srb_bh(struct net_device *dev); static void streamer_asb_bh(struct net_device *dev); #if STREAMER_NETWORK_MONITOR #ifdef CONFIG_PROC_FS +static int streamer_proc_info(char *buffer, char **start, off_t offset, + int length, int *eof, void *data); static int sprintf_info(char *buffer, struct net_device *dev); +struct streamer_private *dev_streamer=NULL; #endif #endif -int __init streamer_probe(struct net_device *dev) +static int __devinit streamer_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) { - int cards_found; - - cards_found = streamer_scan(dev); - return cards_found ? 0 : -ENODEV; -} - -static int __init streamer_scan(struct net_device *dev) -{ - struct pci_dev *pci_device = NULL; + struct net_device *dev=NULL; struct streamer_private *streamer_priv; - int card_no = 0; - if (pci_present()) - { - while ((pci_device = pci_find_device(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_TR, pci_device))) - { - if (pci_enable_device(pci_device)) - continue; - pci_set_master(pci_device); + __u32 pio_start, pio_end, pio_flags, pio_len; + __u32 mmio_start, mmio_end, mmio_flags, mmio_len; + int rc=0; + static int card_no=-1; - /* Check to see if io has been allocated, if so, we've already done this card, - so continue on the card discovery loop */ +#if STREAMER_DEBUG + printk("lanstreamer::streamer_init_one, entry pdev %p\n",pdev); +#endif - if (check_region(pci_resource_start(pci_device,0), STREAMER_IO_SPACE)) - { card_no++; - continue; - } - - streamer_priv = kmalloc(sizeof(struct streamer_private), GFP_KERNEL); - if(streamer_priv==NULL) - { + dev=init_trdev(dev, sizeof(*streamer_priv)); + if(dev==NULL) { printk(KERN_ERR "lanstreamer: out of memory.\n"); - break; - } - memset(streamer_priv, 0, sizeof(struct streamer_private)); - init_waitqueue_head(&streamer_priv->srb_wait); - init_waitqueue_head(&streamer_priv->trb_wait); -#ifndef MODULE - dev = init_trdev(dev, 0); - if(dev==NULL) - { - kfree(streamer_priv); - printk(KERN_ERR "lanstreamer: out of memory.\n"); - break; + return -ENOMEM; } SET_MODULE_OWNER(dev); + streamer_priv=dev->priv; + +#if STREAMER_NETWORK_MONITOR +#ifdef CONFIG_PROC_FS + if (!dev_streamer) { + create_proc_read_entry("net/streamer_tr",0,0,streamer_proc_info,NULL); + } + streamer_priv->next=dev_streamer; + dev_streamer=streamer_priv; +#endif #endif - dev->priv = (void *) streamer_priv; + + if (pci_enable_device(pdev)) { + printk(KERN_ERR "lanstreamer: unable to enable pci device\n"); + rc=-EIO; + goto err_out; + } + + pci_set_master(pdev); + + pio_start = pci_resource_start(pdev, 0); + pio_end = pci_resource_end(pdev, 0); + pio_flags = pci_resource_flags(pdev, 0); + pio_len = pci_resource_len(pdev, 0); + + mmio_start = pci_resource_start(pdev, 1); + mmio_end = pci_resource_end(pdev, 1); + mmio_flags = pci_resource_flags(pdev, 1); + mmio_len = pci_resource_len(pdev, 1); + #if STREAMER_DEBUG - printk("pci_device: %p, dev:%p, dev->priv: %p\n", - pci_device, dev, dev->priv); + printk("lanstreamer: pio_start %x pio_end %x pio_len %x pio_flags %x\n", + pio_start, pio_end, pio_len, pio_flags); + printk("lanstreamer: mmio_start %x mmio_end %x mmio_len %x mmio_flags %x\n", + mmio_start, mmio_end, mmio_flags, mmio_len); #endif - dev->irq = pci_device->irq; - dev->base_addr = pci_resource_start(pci_device, 0); - dev->init = &streamer_init; - streamer_priv->streamer_card_name = (char *)pci_device->resource[0].name; - streamer_priv->streamer_mmio = - ioremap(pci_resource_start(pci_device, 1), 256); - - if ((pkt_buf_sz[card_no] < 100) || (pkt_buf_sz[card_no] > 18000)) - streamer_priv->pkt_buf_sz = PKT_BUF_SZ; - else - streamer_priv->pkt_buf_sz = pkt_buf_sz[card_no]; - - streamer_priv->streamer_ring_speed = ringspeed[card_no]; - streamer_priv->streamer_message_level = message_level[card_no]; - - if (streamer_init(dev) == -1) { - unregister_netdevice(dev); - kfree(dev->priv); - return 0; + + if (!request_region(pio_start, pio_len, "lanstreamer")) { + printk(KERN_ERR "lanstreamer: unable to get pci io addr %x\n",pio_start); + rc= -EBUSY; + goto err_out; + } + + if (!request_mem_region(mmio_start, mmio_len, "lanstreamer")) { + printk(KERN_ERR "lanstreamer: unable to get pci mmio addr %x\n",mmio_start); + rc= -EBUSY; + goto err_out_free_pio; + } + + streamer_priv->streamer_mmio=ioremap(mmio_start, mmio_len); + if (streamer_priv->streamer_mmio == NULL) { + printk(KERN_ERR "lanstreamer: unable to remap MMIO %x\n",mmio_start); + rc= -EIO; + goto err_out_free_mmio; } + init_waitqueue_head(&streamer_priv->srb_wait); + init_waitqueue_head(&streamer_priv->trb_wait); + dev->open = &streamer_open; dev->hard_start_xmit = &streamer_xmit; dev->change_mtu = &streamer_change_mtu; - dev->stop = &streamer_close; dev->do_ioctl = NULL; dev->set_multicast_list = &streamer_set_rx_mode; dev->get_stats = &streamer_get_stats; dev->set_mac_address = &streamer_set_mac_address; - return 1; + dev->irq = pdev->irq; + dev->base_addr=pio_start; + + streamer_priv->streamer_card_name = (char *)pdev->resource[0].name; + streamer_priv->pci_dev=pdev; + + if ((pkt_buf_sz[card_no] < 100) || (pkt_buf_sz[card_no] > 18000)) + streamer_priv->pkt_buf_sz = PKT_BUF_SZ; + else + streamer_priv->pkt_buf_sz = pkt_buf_sz[card_no]; + + streamer_priv->streamer_ring_speed = ringspeed[card_no]; + streamer_priv->streamer_message_level = message_level[card_no]; + + pdev->driver_data=dev; + + spin_lock_init(&streamer_priv->streamer_lock); + + printk("%s \n", version); + printk("%s: %s. I/O at %hx, MMIO at %p, using irq %d\n",dev->name, + streamer_priv->streamer_card_name, + (unsigned int) dev->base_addr, + streamer_priv->streamer_mmio, + dev->irq); + + if (!streamer_reset(dev)) { + return 0; + } + + iounmap(streamer_priv->streamer_mmio); +err_out_free_mmio: + release_mem_region(mmio_start, mmio_len); +err_out_free_pio: + release_region(pio_start, pio_len); +err_out: + unregister_trdev(dev); + kfree(dev); +#if STREAMER_DEBUG + printk("lanstreamer: Exit error %x\n",rc); +#endif + return rc; +} + +static void __devexit streamer_remove_one(struct pci_dev *pdev) { + struct net_device *dev=pdev->driver_data; + struct streamer_private *streamer_priv; + +#if STREAMER_DEBUG + printk("lanstreamer::streamer_remove_one entry pdev %p\n",pdev); +#endif + + if (dev == NULL) { + printk(KERN_ERR "lanstreamer::streamer_remove_one, ERROR dev is NULL\n"); + return; } + + streamer_priv=dev->priv; + if (streamer_priv == NULL) { + printk(KERN_ERR "lanstreamer::streamer_remove_one, ERROR dev->priv is NULL\n"); + return; } - return 0; + +#if STREAMER_NETWORK_MONITOR +#ifdef CONFIG_PROC_FS + { + struct streamer_private *slast; + struct streamer_private *scurrent; + if (streamer_priv == dev_streamer) { + dev_streamer=dev_streamer->next; + } else { + for(slast=scurrent=dev_streamer; dev_streamer; slast=scurrent, scurrent=scurrent->next) { + if (scurrent == streamer_priv) { + slast->next=scurrent->next; + break; + } + } + } + if (!dev_streamer) { + remove_proc_entry("net/streamer_tr", NULL); + } + } +#endif +#endif + + unregister_trdev(dev); + release_region(pci_resource_start(pdev, 0), pci_resource_len(pdev,0)); + release_mem_region(pci_resource_start(pdev, 1), pci_resource_len(pdev,1)); + kfree(dev); + pdev->driver_data=NULL; } @@ -424,32 +520,6 @@ static int streamer_reset(struct net_device *dev) return 0; } -static int __init streamer_init(struct net_device *dev) -{ - struct streamer_private *streamer_priv; - __u8 *streamer_mmio; - int rc; - - streamer_priv=(struct streamer_private *)dev->priv; - streamer_mmio=streamer_priv->streamer_mmio; - - spin_lock_init(&streamer_priv->streamer_lock); - - printk("%s \n", version); - printk("%s: %s. I/O at %hx, MMIO at %p, using irq %d\n",dev->name, - streamer_priv->streamer_card_name, - (unsigned int) dev->base_addr, - streamer_priv->streamer_mmio, - dev->irq); - - request_region(dev->base_addr, STREAMER_IO_SPACE, "streamer"); - - rc=streamer_reset(dev); - return rc; -} - - - static int streamer_open(struct net_device *dev) { struct streamer_private *streamer_priv = (struct streamer_private *) dev->priv; @@ -465,7 +535,7 @@ static int streamer_open(struct net_device *dev) rc=streamer_reset(dev); } - if (request_irq(dev->irq, &streamer_interrupt, SA_SHIRQ, "streamer", dev)) { + if (request_irq(dev->irq, &streamer_interrupt, SA_SHIRQ, "lanstreamer", dev)) { return -EAGAIN; } #if STREAMER_DEBUG @@ -563,7 +633,7 @@ static int streamer_open(struct net_device *dev) * timed out. */ writew(srb_open + 2, streamer_mmio + LAPA); - srb_word = ntohs(readw(streamer_mmio + LAPD)) & 0xFF; + srb_word = ntohs(readw(streamer_mmio + LAPD)) >> 8; if (srb_word == STREAMER_CLEAR_RET_CODE) { printk(KERN_WARNING "%s: Adapter Open time out or error.\n", dev->name); @@ -1618,27 +1688,24 @@ static int streamer_change_mtu(struct net_device *dev, int mtu) static int streamer_proc_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data) { + struct streamer_private *sdev=NULL; struct pci_dev *pci_device = NULL; int len = 0; off_t begin = 0; off_t pos = 0; int size; - struct device *dev; - + struct net_device *dev; size = sprintf(buffer, "IBM LanStreamer/MPC Chipset Token Ring Adapters\n"); pos += size; len += size; - while ((pci_device = pci_find_device(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_TR, pci_device))) - { + for(sdev=dev_streamer; sdev; sdev=sdev->next) { + pci_device=sdev->pci_dev; + dev=pci_device->driver_data; - for (dev = dev_base; dev != NULL; dev = dev->next) - { - if (dev->base_addr == pci_device->resource[0].start) - { /* Yep, a Streamer device */ size = sprintf_info(buffer + len, dev); len += size; pos = begin + len; @@ -1649,9 +1716,7 @@ static int streamer_proc_info(char *buffer, char **start, off_t offset, } if (pos > offset + length) break; - } /* if */ } /* for */ - } /* While */ *start = buffer + (offset - begin); /* Start of wanted data */ len -= (offset - begin); /* Start slop */ @@ -1743,66 +1808,34 @@ static int sprintf_info(char *buffer, struct net_device *dev) #endif #endif -#ifdef MODULE - -static struct net_device *dev_streamer[STREAMER_MAX_ADAPTERS]; - -int init_module(void) -{ - int i; - -#if STREAMER_NETWORK_MONITOR -#ifdef CONFIG_PROC_FS - create_proc_read_entry("net/streamer_tr",0,0,streamer_proc_info,NULL); -#endif +static void streamer_suspend(struct pci_dev *pdev) { +#if STREAMER_DEBUG + printk("lanstreamer::streamer_suspend entry pdev %p\n",pdev); #endif - for (i = 0; (i < STREAMER_MAX_ADAPTERS); i++) - { - dev_streamer[i] = NULL; - dev_streamer[i] = init_trdev(dev_streamer[i], 0); - SET_MODULE_OWNER(dev_streamer[i]); - if (dev_streamer[i] == NULL) - return -ENOMEM; - - dev_streamer[i]->init = &streamer_probe; - - if (register_trdev(dev_streamer[i]) != 0) { - kfree(dev_streamer[i]); - dev_streamer[i] = NULL; - if (i == 0) - { - printk(KERN_INFO "Streamer: No IBM LanStreamer PCI Token Ring cards found in system.\n"); - return -EIO; - } else { - printk(KERN_INFO "Streamer: %d IBM LanStreamer PCI Token Ring card(s) found in system.\n", i); - return 0; - } - } - } +} - return 0; +static void streamer_resume(struct pci_dev *pdev) { +#if STREAMER_DEBUG + printk("lanstreamer::streamer_resume entry pdev %p\n",pdev); +#endif } -void cleanup_module(void) -{ - int i; - struct streamer_private *streamer_priv; +static struct pci_driver streamer_pci_driver = { + name: "lanstreamer", + id_table: streamer_pci_tbl, + probe: streamer_init_one, + remove: streamer_remove_one, + suspend: streamer_suspend, + resume: streamer_resume, +}; - for (i = 0; i < STREAMER_MAX_ADAPTERS; i++) - if (dev_streamer[i]) { - unregister_trdev(dev_streamer[i]); - release_region(dev_streamer[i]->base_addr, STREAMER_IO_SPACE); - streamer_priv=(struct streamer_private *)dev_streamer[i]->priv; - kfree(streamer_priv->streamer_rx_ring); - kfree(streamer_priv->streamer_tx_ring); - kfree(dev_streamer[i]->priv); - kfree(dev_streamer[i]); - dev_streamer[i] = NULL; - } -#if STREAMER_NETWORK_MONITOR -#ifdef CONFIG_PROC_FS - remove_proc_entry("net/streamer_tr", NULL); -#endif -#endif +static int __init streamer_init_module(void) { + return pci_module_init(&streamer_pci_driver); } -#endif /* MODULE */ + +static void __exit streamer_cleanup_module(void) { + pci_unregister_driver(&streamer_pci_driver); +} + +module_init(streamer_init_module); +module_exit(streamer_cleanup_module); diff --git a/drivers/net/tokenring/lanstreamer.h b/drivers/net/tokenring/lanstreamer.h index 4c99f875e..717add7a0 100644 --- a/drivers/net/tokenring/lanstreamer.h +++ b/drivers/net/tokenring/lanstreamer.h @@ -257,6 +257,8 @@ struct streamer_private { __u16 arb; __u16 asb; + struct streamer_private *next; + struct pci_dev *pci_dev; __u8 *streamer_mmio; char *streamer_card_name; diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c index 4280b7193..91f699848 100644 --- a/drivers/net/tokenring/olympic.c +++ b/drivers/net/tokenring/olympic.c @@ -1,6 +1,6 @@ /* * olympic.c (c) 1999 Peter De Schrijver All Rights Reserved - * 1999 Mike Phillips (phillim@amtrak.com) + * 1999 Mike Phillips (mikep@linuxtr.net) * * Linux driver for IBM PCI tokenring cards based on the Pit/Pit-Phy/Olympic * chipset. @@ -38,10 +38,11 @@ * Fixing the hardware descriptors was another matter, * because they weren't going through read[wl](), there all * the results had to be in memory in le32 values. kdaaker - * + * 12/23/00 - Added minimal Cardbus support (Thanks Donald). * * To Do: - * + * Complete full Cardbus / hot-swap support. + * * If Problems do Occur * Most problems can be rectified by either closing and opening the interface * (ifconfig down and up) or rmmod and insmod'ing the driver (a bit difficult @@ -99,7 +100,7 @@ */ static char *version = -"Olympic.c v0.5.0 3/10/00 - Peter De Schrijver & Mike Phillips" ; +"Olympic.c v0.5.C 12/23/00 - Peter De Schrijver & Mike Phillips" ; static struct pci_device_id olympic_pci_tbl[] __initdata = { { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_TR_WAKE, PCI_ANY_ID, PCI_ANY_ID, }, @@ -191,11 +192,9 @@ static int __init olympic_scan(struct net_device *dev) if (pci_enable_device(pci_device)) continue; - /* These lines are needed by the PowerPC, it appears -that these flags - * are not being set properly for the PPC, this may -well be fixed with - * the new PCI code */ + /* These lines are needed by the PowerPC, it appears that these flags + * are not being set properly for the PPC, this may well be fixed with + * the new PCI code */ pci_read_config_word(pci_device, PCI_COMMAND, &pci_command); pci_command |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY; pci_write_config_word(pci_device, PCI_COMMAND,pci_command); @@ -216,7 +215,11 @@ well be fixed with init_waitqueue_head(&olympic_priv->srb_wait); init_waitqueue_head(&olympic_priv->trb_wait); #ifndef MODULE - dev=init_trdev(dev, 0); + dev = init_trdev(NULL, 0); + if (!dev) { + kfree(olympic_priv); + return 0; + } #endif dev->priv=(void *)olympic_priv; #if OLYMPIC_DEBUG @@ -224,8 +227,9 @@ well be fixed with #endif dev->irq=pci_device->irq; dev->base_addr=pci_resource_start(pci_device, 0); - dev->init=&olympic_init; + dev->init=&olympic_init; /* AKPM: Not needed */ olympic_priv->olympic_card_name = (char *)pci_device->resource[0].name ; + /* FIXME: check ioremap return val, handle cleanup */ olympic_priv->olympic_mmio = ioremap(pci_resource_start(pci_device,1),256); olympic_priv->olympic_lap = @@ -240,8 +244,11 @@ well be fixed with olympic_priv->olympic_message_level = message_level[card_no] ; if(olympic_init(dev)==-1) { - unregister_netdevice(dev); kfree(dev->priv); +#ifndef MODULE + unregister_netdev(dev); + kfree(dev); +#endif return 0; } @@ -288,6 +295,10 @@ static int __init olympic_init(struct net_device *dev) spin_lock_init(&olympic_priv->olympic_lock) ; + /* Needed for cardbus */ + if(!(readl(olympic_mmio+BCTL) & BCTL_MODE_INDICATOR)) + writel(readl(olympic_priv->olympic_mmio+FERMASK)|FERMASK_INT_BIT, olympic_mmio+FERMASK); + #if OLYMPIC_DEBUG printk("BCTL: %x\n",readl(olympic_mmio+BCTL)); printk("GPR: %x\n",readw(olympic_mmio+GPR)); @@ -1259,6 +1270,11 @@ static void olympic_arb_cmd(struct net_device *dev) } #endif mac_frame = dev_alloc_skb(frame_len) ; + if (!mac_frame) { + printk(KERN_WARNING "%s: Memory squeeze, dropping " + "frame.\n", dev->name); + goto drop_frame; + } /* Walk the buffer chain, creating the frame */ @@ -1281,6 +1297,7 @@ static void olympic_arb_cmd(struct net_device *dev) netif_rx(mac_frame) ; dev->last_rx = jiffies ; +drop_frame: /* Now tell the card we have dealt with the received frame */ /* Set LISR Bit 1 */ @@ -1633,8 +1650,11 @@ int init_module(void) for (i = 0; (i<OLYMPIC_MAX_ADAPTERS); i++) { dev_olympic[i] = NULL; dev_olympic[i] = init_trdev(dev_olympic[i], 0); - if (dev_olympic[i] == NULL) - return -ENOMEM; + if (dev_olympic[i] == NULL) { + if (i == 0) + return -ENOMEM; + break; + } dev_olympic[i]->init = &olympic_probe; diff --git a/drivers/net/tokenring/olympic.h b/drivers/net/tokenring/olympic.h index 2fd8c2f1b..f35706d57 100644 --- a/drivers/net/tokenring/olympic.h +++ b/drivers/net/tokenring/olympic.h @@ -1,6 +1,6 @@ /* * olympic.h (c) 1999 Peter De Schrijver All Rights Reserved - * 1999 Mike Phillips (phillim@amtrak.com) + * 1999 Mike Phillips (mikep@linuxtr.net) * * Linux driver for IBM PCI tokenring cards based on the olympic and the PIT/PHY chipset. * @@ -19,6 +19,7 @@ #define BCTL 0x70 #define BCTL_SOFTRESET (1<<15) #define BCTL_MIMREB (1<<6) +#define BCTL_MODE_INDICATOR (1<<5) #define GPR 0x4a #define GPR_OPTI_BF (1<<6) @@ -124,6 +125,9 @@ #define TXSTATQCNT_2 0xe4 #define TXCSA_1 0xc8 #define TXCSA_2 0xe8 +/* Cardbus */ +#define FERMASK 0xf4 +#define FERMASK_INT_BIT (1<<15) #define OLYMPIC_IO_SPACE 256 diff --git a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c index fd6531020..f656fc5f7 100644 --- a/drivers/net/tokenring/smctr.c +++ b/drivers/net/tokenring/smctr.c @@ -4383,7 +4383,7 @@ static int smctr_reset_adapter(struct net_device *dev) smctr_clear_trc_reset(ioaddr); mdelay(200); /* ~2 ms */ - /* Remove any latched interrupts that occured prior to reseting the + /* Remove any latched interrupts that occurred prior to reseting the * adapter or possibily caused by line glitches due to the reset. */ outb(tp->trc_mask | CSR_CLRTINT | CSR_CLRCBUSY, ioaddr + CSR); @@ -4546,20 +4546,24 @@ static int smctr_rx_frame(struct net_device *dev) struct sk_buff *skb; skb = dev_alloc_skb(rx_size); - skb_put(skb, rx_size); - - memcpy(skb->data, pbuff, rx_size); - sti(); - - /* Update Counters */ - tp->MacStat.rx_packets++; - tp->MacStat.rx_bytes += skb->len; - - /* Kick the packet on up. */ - skb->dev = dev; - skb->protocol = tr_type_trans(skb, dev); - netif_rx(skb); - dev->last_rx = jiffies; + if (skb) { + skb_put(skb, rx_size); + + memcpy(skb->data, pbuff, rx_size); + sti(); + + /* Update Counters */ + tp->MacStat.rx_packets++; + tp->MacStat.rx_bytes += skb->len; + + /* Kick the packet on up. */ + skb->dev = dev; + skb->protocol = tr_type_trans(skb, dev); + netif_rx(skb); + dev->last_rx = jiffies; + } else { + sti(); + } } else smctr_process_rx_packet((MAC_HEADER *)pbuff, diff --git a/drivers/net/tokenring/tms380tr.c b/drivers/net/tokenring/tms380tr.c index 0583a7da0..fe03c8338 100644 --- a/drivers/net/tokenring/tms380tr.c +++ b/drivers/net/tokenring/tms380tr.c @@ -2192,17 +2192,18 @@ static void tms380tr_rcv_status_irq(struct net_device *dev) } } - if(rpl->SkbStat == SKB_DATA_COPY - || rpl->SkbStat == SKB_DMA_DIRECT) + if(skb && (rpl->SkbStat == SKB_DATA_COPY + || rpl->SkbStat == SKB_DMA_DIRECT)) { if(rpl->SkbStat == SKB_DATA_COPY) - memmove(skb->data, ReceiveDataPtr, Length); + memcpy(skb->data, ReceiveDataPtr, Length); /* Deliver frame to system */ rpl->Skb = NULL; skb_trim(skb,Length); skb->protocol = tr_type_trans(skb,dev); netif_rx(skb); + dev->last_rx = jiffies; } } else /* Invalid frame */ diff --git a/drivers/net/tokenring/tms380tr.h b/drivers/net/tokenring/tms380tr.h index ef946ef4d..4dc1a37a1 100644 --- a/drivers/net/tokenring/tms380tr.h +++ b/drivers/net/tokenring/tms380tr.h @@ -395,7 +395,7 @@ typedef struct { /* OPEN Options (high-low) */ #define WRAP_INTERFACE 0x0080 /* Inserting omitted for test * purposes; transmit data appears - * as receive data. (usefull for + * as receive data. (useful for * testing; change: CLOSE necessary) */ #define DISABLE_HARD_ERROR 0x0040 /* On HARD_ERROR & TRANSMIT_BEACON diff --git a/drivers/net/tokenring/tmsisa.c b/drivers/net/tokenring/tmsisa.c index 0fea4d137..73be6bdbe 100644 --- a/drivers/net/tokenring/tmsisa.c +++ b/drivers/net/tokenring/tmsisa.c @@ -7,7 +7,7 @@ * Dedicated to my girlfriend Steffi Bopp * * This software may be used and distributed according to the terms - * of the GNU Public License, incorporated herein by reference. + * of the GNU General Public License, incorporated herein by reference. * * This driver module supports the following cards: * - SysKonnect TR4/16(+) ISA (SK-4190) diff --git a/drivers/net/tulip/ChangeLog b/drivers/net/tulip/ChangeLog index bb5b70f01..345c4d200 100644 --- a/drivers/net/tulip/ChangeLog +++ b/drivers/net/tulip/ChangeLog @@ -1,3 +1,54 @@ +2001-02-20 Jeff Garzik <jgarzik@mandrakesoft.com> + + * media.c (tulip_select_media): No need to initialize + new_csr6, all cases initialize it properly. + +2001-02-18 Manfred Spraul <manfred@colorfullife.com> + + * interrupt.c (tulip_refill_rx): Make public. + If PNIC chip stops due to lack of Rx buffers, restart it. + (tulip_interrupt): PNIC doesn't have a h/w timer, emulate + with software timers. + * pnic.c (pnic_check_duplex): New function, PNIC-specific + version of tulip_check_duplex. + (pnic_lnk_change): Call pnic_check_duplex. If we use an + external MII, then we mustn't use the internal negotiation. + (pnic_timer): Support Rx refilling on work overflow in + interrupt handler, as PNIC doesn't support a h/w timer. + * tulip_core.c (tulip_tbl[]): Modify default csr6 + +2001-02-11 Jeff Garzik <jgarzik@mandrakesoft.com> + + * tulip_core.c (tulip_init_one): Call pci_enable_device + to ensure wakeup/resource assignment before checking those + values. + (tulip_init_one): Replace PCI ids with constants from pci_id.h. + (tulip_suspend, tulip_resume, tulip_remove_one): Call + pci_power_on/off (commented out for now). + +2001-02-10 Jeff Garzik <jgarzik@mandrakesoft.com> + + * tulip.h: Add CFDD_xxx bits for Tulip power management + * tulip_core.c (tulip_set_power_state): New function, + manipulating Tulip chip power state where supported. + (tulip_up, tulip_down, tulip_init_one): Use it. + +2001-02-10 Jeff Garzik <jgarzik@mandrakesoft.com> + + * tulip_core.c (tulip_tx_timeout): Call netif_wake_queue + to ensure the next Tx is always sent to us. + +2001-01-27 Jeff Garzik <jgarzik@mandrakesoft.com> + + * tulip_core.c (tulip_remove_one): Fix mem leak by freeing + tp->media_tbl. Add check for !dev, reformat code appropriately. + +2001-01-27 Jeff Garzik <jgarzik@mandrakesoft.com> + + * tulip_tbl[]: Comment all entries to make order and chip_id + relationship more clear. + * tulip_pci_tbl[]: Add new Accton PCI id (COMET chipset). + 2001-01-16 Jeff Garzik <jgarzik@mandrakesoft.com> * tulip_core.c: static vars no longer explicitly diff --git a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c index 6cb0d7ab7..61ec93337 100644 --- a/drivers/net/tulip/interrupt.c +++ b/drivers/net/tulip/interrupt.c @@ -23,7 +23,7 @@ unsigned int tulip_max_interrupt_work; -static int tulip_refill_rx(struct net_device *dev) +int tulip_refill_rx(struct net_device *dev) { struct tulip_private *tp = (struct tulip_private *)dev->priv; int entry; @@ -50,6 +50,14 @@ static int tulip_refill_rx(struct net_device *dev) } tp->rx_ring[entry].status = cpu_to_le32(DescOwned); } + if(tp->chip_id == LC82C168) { + if(((inl(dev->base_addr + CSR5)>>17)&0x07) == 4) { + /* Rx stopped due to out of buffers, + * restart it + */ + outl(0x01, dev->base_addr + CSR2); + } + } return refilled; } @@ -332,7 +340,11 @@ void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs) /* Josip Loncaric at ICASE did extensive experimentation to develop a good interrupt mitigation setting.*/ outl(0x8b240000, ioaddr + CSR11); - } else { + } else if (tp->chip_id == LC82C168) { + /* the LC82C168 doesn't have a hw timer.*/ + outl(0x00, ioaddr + CSR7); + mod_timer(&tp->timer, RUN_AT(HZ/50)); + } else { /* Mask all interrupting sources, set timer to re-enable. */ outl(((~csr5) & 0x0001ebef) | AbnormalIntr | TimerInt, ioaddr + CSR7); @@ -355,14 +367,19 @@ void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs) if (tp->rx_buffers[entry].skb == NULL) { if (tulip_debug > 1) printk(KERN_WARNING "%s: in rx suspend mode: (%lu) (tp->cur_rx = %u, ttimer = %d, rx = %d) go/stay in suspend mode\n", dev->name, tp->nir, tp->cur_rx, tp->ttimer, rx); - if (tp->ttimer == 0 || (inl(ioaddr + CSR11) & 0xffff) == 0) { - if (tulip_debug > 1) - printk(KERN_WARNING "%s: in rx suspend mode: (%lu) set timer\n", dev->name, tp->nir); - outl(tulip_tbl[tp->chip_id].valid_intrs | TimerInt, - ioaddr + CSR7); - outl(TimerInt, ioaddr + CSR5); - outl(12, ioaddr + CSR11); - tp->ttimer = 1; + if (tp->chip_id == LC82C168) { + outl(0x00, ioaddr + CSR7); + mod_timer(&tp->timer, RUN_AT(HZ/50)); + } else { + if (tp->ttimer == 0 || (inl(ioaddr + CSR11) & 0xffff) == 0) { + if (tulip_debug > 1) + printk(KERN_WARNING "%s: in rx suspend mode: (%lu) set timer\n", dev->name, tp->nir); + outl(tulip_tbl[tp->chip_id].valid_intrs | TimerInt, + ioaddr + CSR7); + outl(TimerInt, ioaddr + CSR5); + outl(12, ioaddr + CSR11); + tp->ttimer = 1; + } } } diff --git a/drivers/net/tulip/media.c b/drivers/net/tulip/media.c index 18e0de2c1..d61a2a15f 100644 --- a/drivers/net/tulip/media.c +++ b/drivers/net/tulip/media.c @@ -148,7 +148,7 @@ void tulip_select_media(struct net_device *dev, int startup) long ioaddr = dev->base_addr; struct tulip_private *tp = (struct tulip_private *)dev->priv; struct mediatable *mtable = tp->mtable; - u32 new_csr6=0; + u32 new_csr6; int i; if (mtable) { diff --git a/drivers/net/tulip/pnic.c b/drivers/net/tulip/pnic.c index d5de39be5..c21e3991c 100644 --- a/drivers/net/tulip/pnic.c +++ b/drivers/net/tulip/pnic.c @@ -50,6 +50,61 @@ void pnic_do_nway(struct net_device *dev) } } +/* Modified version of tulip_check_duplex: + * Always update the 100mbps bit, even if the + * full duplex bit didn't change. + * Manfred Spraul <manfred@colorfullife.com> + */ +int pnic_check_duplex(struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + int mii_reg1, mii_reg5, negotiated, duplex; + int new_csr6; + + mii_reg1 = tulip_mdio_read(dev, tp->phys[0], 1); + mii_reg5 = tulip_mdio_read(dev, tp->phys[0], 5); + if (tulip_debug > 1) + printk(KERN_INFO "%s: MII status %4.4x, Link partner report " + "%4.4x.\n", dev->name, mii_reg1, mii_reg5); + if (mii_reg1 == 0xffff) + return -2; + if ((mii_reg1 & 0x0004) == 0) { + int new_reg1 = tulip_mdio_read(dev, tp->phys[0], 1); + if ((new_reg1 & 0x0004) == 0) { + if (tulip_debug > 1) + printk(KERN_INFO "%s: No link beat on the MII interface," + " status %4.4x.\n", dev->name, new_reg1); + return -1; + } + } + negotiated = mii_reg5 & tp->advertising[0]; + /* 100baseTx-FD or 10T-FD, but not 100-HD */ + duplex = ((negotiated & 0x0300) == 0x0100 + || (negotiated & 0x00C0) == 0x0040) || + tp->full_duplex_lock; + + new_csr6 = tp->csr6; + if (negotiated & 0x0380) /* 100mbps. */ + new_csr6 &= ~0x00400000; + else + new_csr6 |= 0x00400000; + if (duplex) + new_csr6 |= 0x0200; + else + new_csr6 &= ~0x0200; + if (new_csr6 != tp->csr6) { + tp->full_duplex = duplex; + tp->csr6 = new_csr6; + if (tulip_debug > 0) + printk(KERN_INFO "%s: Setting %s-duplex based on MII" + "#%d link partner capability of %4.4x.\n", + dev->name, tp->full_duplex ? "full" : "half", + tp->phys[0], mii_reg5); + tulip_restart_rxtx(tp, tp->csr6); + return 1; + } + return 0; +} void pnic_lnk_change(struct net_device *dev, int csr5) { @@ -62,6 +117,11 @@ void pnic_lnk_change(struct net_device *dev, int csr5) dev->name, phy_reg, csr5); if (inl(ioaddr + CSR5) & TPLnkFail) { outl((inl(ioaddr + CSR7) & ~TPLnkFail) | TPLnkPass, ioaddr + CSR7); + /* If we use an external MII, then we mustn't use the + * internal negotiation. + */ + if (tulip_media_cap[dev->if_port] & MediaIsMII) + return; if (! tp->nwayset || jiffies - dev->trans_start > 1*HZ) { tp->csr6 = 0x00420000 | (tp->csr6 & 0x0000fdff); tulip_outl_csr(tp, tp->csr6, CSR6); @@ -70,11 +130,18 @@ void pnic_lnk_change(struct net_device *dev, int csr5) dev->trans_start = jiffies; } } else if (inl(ioaddr + CSR5) & TPLnkPass) { - pnic_do_nway(dev); + if (tulip_media_cap[dev->if_port] & MediaIsMII) { + spin_lock(&tp->lock); + pnic_check_duplex(dev); + spin_unlock(&tp->lock); + } else { + pnic_do_nway(dev); + } outl((inl(ioaddr + CSR7) & ~TPLnkPass) | TPLnkFail, ioaddr + CSR7); } } +int tulip_refill_rx(struct net_device *dev); void pnic_timer(unsigned long data) { @@ -82,10 +149,21 @@ void pnic_timer(unsigned long data) struct tulip_private *tp = (struct tulip_private *)dev->priv; long ioaddr = dev->base_addr; int next_tick = 60*HZ; + + if(!inl(ioaddr + CSR7)) { + /* the timer was called due to a work overflow + * in the interrupt handler. Skip the connection + * checks, the nic is definitively speaking with + * his link partner. + */ + goto too_good_connection; + } if (tulip_media_cap[dev->if_port] & MediaIsMII) { - if (tulip_check_duplex(dev) > 0) + spin_lock_irq(&tp->lock); + if (pnic_check_duplex(dev) > 0) next_tick = 3*HZ; + spin_unlock_irq(&tp->lock); } else { int csr12 = inl(ioaddr + CSR12); int new_csr6 = tp->csr6 & ~0x40C40200; @@ -137,7 +215,14 @@ void pnic_timer(unsigned long data) } } } - tp->timer.expires = RUN_AT(next_tick); - add_timer(&tp->timer); +too_good_connection: + mod_timer(&tp->timer, RUN_AT(next_tick)); + if(!inl(ioaddr + CSR7)) { + if (tulip_debug > 1) + printk(KERN_INFO "%s: sw timer wakeup.\n", dev->name); + disable_irq(dev->irq); + tulip_refill_rx(dev); + enable_irq(dev->irq); + outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7); + } } - diff --git a/drivers/net/tulip/tulip.h b/drivers/net/tulip/tulip.h index 1f2343820..531cbf14b 100644 --- a/drivers/net/tulip/tulip.h +++ b/drivers/net/tulip/tulip.h @@ -18,6 +18,7 @@ #include <linux/netdevice.h> #include <linux/timer.h> #include <asm/io.h> +#include <asm/irq.h> @@ -107,7 +108,14 @@ enum tulip_offsets { CSR12 = 0x60, CSR13 = 0x68, CSR14 = 0x70, - CSR15 = 0x78 + CSR15 = 0x78, +}; + +/* register offset and bits for CFDD PCI config reg */ +enum pci_cfg_driver_reg { + CFDD = 0x40, + CFDD_Sleep = (1 << 31), + CFDD_Snooze = (1 << 30), }; diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index 06bdaf43c..25d60845f 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -28,7 +28,7 @@ #include <asm/unaligned.h> static char version[] __devinitdata = - "Linux Tulip driver version 0.9.13a (January 20, 2001)\n"; + "Linux Tulip driver version 0.9.14 (February 20, 2001)\n"; /* A few user-configurable values. */ @@ -120,37 +120,63 @@ int tulip_debug = 1; */ struct tulip_chip_table tulip_tbl[] = { + /* DC21040 */ { "Digital DC21040 Tulip", 128, 0x0001ebef, 0, tulip_timer }, + + /* DC21041 */ { "Digital DC21041 Tulip", 128, 0x0001ebef, HAS_MEDIA_TABLE | HAS_NWAY, tulip_timer }, + + /* DC21140 */ { "Digital DS21140 Tulip", 128, 0x0001ebef, HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, tulip_timer }, + + /* DC21142, DC21143 */ { "Digital DS21143 Tulip", 128, 0x0801fbff, HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY | HAS_INTR_MITIGATION, t21142_timer }, - { "Lite-On 82c168 PNIC", 256, 0x0001ebef, + + /* LC82C168 */ + { "Lite-On 82c168 PNIC", 256, 0x0001fbef, HAS_MII | HAS_PNICNWAY, pnic_timer }, + + /* MX98713 */ { "Macronix 98713 PMAC", 128, 0x0001ebef, HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer }, + + /* MX98715 */ { "Macronix 98715 PMAC", 256, 0x0001ebef, HAS_MEDIA_TABLE, mxic_timer }, + + /* MX98725 */ { "Macronix 98725 PMAC", 256, 0x0001ebef, HAS_MEDIA_TABLE, mxic_timer }, + + /* AX88140 */ { "ASIX AX88140", 128, 0x0001fbff, HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | MC_HASH_ONLY | IS_ASIX, tulip_timer }, + + /* PNIC2 */ { "Lite-On PNIC-II", 256, 0x0801fbff, HAS_MII | HAS_NWAY | HAS_8023X, t21142_timer }, + + /* COMET */ { "ADMtek Comet", 256, 0x0001abef, MC_HASH_ONLY, comet_timer }, + + /* COMPEX9881 */ { "Compex 9881 PMAC", 128, 0x0001ebef, HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer }, + + /* I21145 */ { "Intel DS21145 Tulip", 128, 0x0801fbff, HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY, t21142_timer }, + + /* DM910X */ { "Davicom DM9102/DM9102A", 128, 0x0001ebef, HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | HAS_ACPI, tulip_timer }, - {0}, }; @@ -176,6 +202,7 @@ static struct pci_device_id tulip_pci_tbl[] __devinitdata = { { 0x8086, 0x0039, PCI_ANY_ID, PCI_ANY_ID, 0, 0, I21145 }, { 0x1282, 0x9100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DM910X }, { 0x1282, 0x9102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DM910X }, + { 0x1113, 0x1216, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, { 0x1113, 0x1217, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98715 }, {0, } }; @@ -212,6 +239,24 @@ static void set_rx_mode(struct net_device *dev); +static void tulip_set_power_state (struct tulip_private *tp, + int sleep, int snooze) +{ + if (tp->flags & HAS_ACPI) { + u32 tmp, newtmp; + pci_read_config_dword (tp->pdev, CFDD, &tmp); + newtmp = tmp & ~(CFDD_Sleep | CFDD_Snooze); + if (sleep) + newtmp |= CFDD_Sleep; + else if (snooze) + newtmp |= CFDD_Snooze; + if (tmp != newtmp) + pci_write_config_dword (tp->pdev, CFDD, newtmp); + } + +} + + static void tulip_up(struct net_device *dev) { struct tulip_private *tp = (struct tulip_private *)dev->priv; @@ -222,8 +267,7 @@ static void tulip_up(struct net_device *dev) DPRINTK("ENTER\n"); /* Wake the chip from sleep/snooze mode. */ - if (tp->flags & HAS_ACPI) - pci_write_config_dword(tp->pdev, 0x40, 0); + tulip_set_power_state (tp, 0, 0); /* On some chip revs we must set the MII/SYM port before the reset!? */ if (tp->mii_cnt || (tp->mtable && tp->mtable->has_mii)) @@ -532,8 +576,9 @@ static void tulip_tx_timeout(struct net_device *dev) tp->stats.tx_errors++; out: - dev->trans_start = jiffies; spin_unlock_irqrestore (&tp->lock, flags); + dev->trans_start = jiffies; + netif_wake_queue (dev); } @@ -670,8 +715,7 @@ static void tulip_down (struct net_device *dev) dev->if_port = tp->saved_if_port; /* Leave the driver in snooze, not sleep, mode. */ - if (tp->flags & HAS_ACPI) - pci_write_config_dword (tp->pdev, 0x40, 0x40000000); + tulip_set_power_state (tp, 0, 1); } @@ -1049,7 +1093,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, * different driver (lmc driver) */ - if( pdev->subsystem_vendor == 0x1376 ){ + if (pdev->subsystem_vendor == PCI_VENDOR_ID_LMC) { printk (KERN_ERR PFX "skipping LMC card.\n"); return -ENODEV; } @@ -1080,16 +1124,24 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, thankfully its an old 486 chipset. */ - if (pci_find_device(PCI_VENDOR_ID_INTEL, 0x0483, NULL)) + if (pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82424, NULL)) csr0 = 0x00A04800; /* The dreaded SiS496 486 chipset. Same workaround as above. */ - if (pci_find_device(PCI_VENDOR_ID_SI, 0x0496, NULL)) + if (pci_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, NULL)) csr0 = 0x00A04800; /* * And back to business */ + i = pci_enable_device(pdev); + if (i) { + printk (KERN_ERR PFX + "Cannot enable tulip board #%d, aborting\n", + board_idx); + return i; + } + ioaddr = pci_resource_start (pdev, 0); irq = pdev->irq; @@ -1126,12 +1178,6 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, goto err_out_free_pio_res; } - if (pci_enable_device(pdev)) { - printk (KERN_ERR PFX "%s: Cannot enable PCI device, aborting\n", - dev->name); - goto err_out_free_mmio_res; - } - pci_set_master(pdev); pci_read_config_byte (pdev, PCI_REVISION_ID, &chip_rev); @@ -1443,8 +1489,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, } /* put the chip in snooze mode until opened */ - if (tulip_tbl[chip_idx].flags & HAS_ACPI) - pci_write_config_dword(pdev, 0x40, 0x40000000); + tulip_set_power_state (tp, 0, 1); return 0; @@ -1468,8 +1513,8 @@ static void tulip_suspend (struct pci_dev *pdev) if (dev && netif_device_present (dev)) { netif_device_detach (dev); tulip_down (dev); + /* pci_power_off(pdev, -1); */ } -// pci_set_power_state(pdev, 3); } @@ -1477,8 +1522,11 @@ static void tulip_resume(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); - pci_enable_device(pdev); +#if 1 + pci_enable_device (pdev); +#endif if (dev && !netif_device_present (dev)) { + /* pci_power_on(pdev); */ tulip_up (dev); netif_device_attach (dev); } @@ -1487,24 +1535,29 @@ static void tulip_resume(struct pci_dev *pdev) static void __devexit tulip_remove_one (struct pci_dev *pdev) { - struct net_device *dev = pci_get_drvdata(pdev); + struct net_device *dev = pci_get_drvdata (pdev); + struct tulip_private *tp; - if (dev) { - struct tulip_private *tp = (struct tulip_private *)dev->priv; - pci_free_consistent(pdev, - sizeof(struct tulip_rx_desc) * RX_RING_SIZE + - sizeof(struct tulip_tx_desc) * TX_RING_SIZE, - tp->rx_ring, - tp->rx_ring_dma); - unregister_netdev(dev); - release_mem_region (pci_resource_start (pdev, 1), - pci_resource_len (pdev, 1)); - release_region (pci_resource_start (pdev, 0), - pci_resource_len (pdev, 0)); - kfree(dev); - - pci_set_drvdata(pdev, NULL); - } + if (!dev) + return; + + tp = dev->priv; + pci_free_consistent (pdev, + sizeof (struct tulip_rx_desc) * RX_RING_SIZE + + sizeof (struct tulip_tx_desc) * TX_RING_SIZE, + tp->rx_ring, tp->rx_ring_dma); + unregister_netdev (dev); + release_mem_region (pci_resource_start (pdev, 1), + pci_resource_len (pdev, 1)); + release_region (pci_resource_start (pdev, 0), + pci_resource_len (pdev, 0)); + if (tp->mtable) + kfree (tp->mtable); + kfree (dev); + + pci_set_drvdata (pdev, NULL); + + /* pci_power_off (pdev, -1); */ } diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index a1d4629af..427b74d96 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -55,6 +55,9 @@ LK1.1.6: - Urban Widmark: merges from Beckers 1.08b version (VT6102 + mdio) set netif_running_on/off on startup, del_timer_sync + + LK1.1.7: + - Manfred Spraul: added reset into tx_timeout */ @@ -114,20 +117,22 @@ static const int multicast_filter_limit = 32; #include <linux/timer.h> #include <linux/errno.h> #include <linux/ioport.h> -#include <linux/malloc.h> +#include <linux/slab.h> #include <linux/interrupt.h> #include <linux/pci.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/skbuff.h> #include <linux/init.h> +#include <linux/delay.h> #include <asm/processor.h> /* Processor type for cache alignment. */ #include <asm/bitops.h> #include <asm/io.h> +#include <asm/irq.h> /* These identify the driver base version and may not be removed. */ static char version1[] __devinitdata = -"via-rhine.c:v1.08b-LK1.1.6 8/9/2000 Written by Donald Becker\n"; +"via-rhine.c:v1.08b-LK1.1.7 8/9/2000 Written by Donald Becker\n"; static char version2[] __devinitdata = " http://www.scyld.com/network/via-rhine.html\n"; @@ -213,7 +218,7 @@ a combined copy/checksum routine. Copying also preloads the cache, which is most useful with small frames. Since the VIA chips are only able to transfer data to buffers on 32 bit -boundaries, the the IP header at offset 14 in an ethernet frame isn't +boundaries, the IP header at offset 14 in an ethernet frame isn't longword aligned for further processing. Copying these unaligned buffers has the beneficial effect of 16-byte aligning the IP header. @@ -380,6 +385,7 @@ enum chip_cmd_bits { CmdNoTxPoll=0x0800, CmdReset=0x8000, }; +#define MAX_MII_CNT 4 struct netdev_private { /* Descriptor rings */ struct rx_desc *rx_ring; @@ -421,7 +427,8 @@ struct netdev_private { /* MII transceiver section. */ u16 advertising; /* NWay media advertisement */ - unsigned char phys[2]; /* MII device addresses. */ + unsigned char phys[MAX_MII_CNT]; /* MII device addresses. */ + unsigned int mii_cnt; /* number of MIIs found, but only the first one is used */ u16 mii_status; /* last read MII status */ }; @@ -431,7 +438,6 @@ static int via_rhine_open(struct net_device *dev); static void via_rhine_check_duplex(struct net_device *dev); static void via_rhine_timer(unsigned long data); static void via_rhine_tx_timeout(struct net_device *dev); -static void via_rhine_init_ring(struct net_device *dev); static int via_rhine_start_tx(struct sk_buff *skb, struct net_device *dev); static void via_rhine_interrupt(int irq, void *dev_instance, struct pt_regs *regs); static void via_rhine_tx(struct net_device *dev); @@ -443,6 +449,25 @@ static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static int via_rhine_close(struct net_device *dev); static inline void clear_tally_counters(long ioaddr); +static void wait_for_reset(struct net_device *dev) +{ + long ioaddr = dev->base_addr; + int i; + + i = 0; + do { + udelay(5); + i++; + if(i > 2000) { + printk(KERN_ERR "%s: reset did not complete in 10 ms.\n", + dev->name); + break; + } + } while(readw(ioaddr + ChipCmd) & CmdReset); + if (debug > 1) + printk(KERN_INFO "%s: reset finished after %d microseconds.\n", + dev->name, 5*i); +} static int __devinit via_rhine_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) @@ -451,14 +476,11 @@ static int __devinit via_rhine_init_one (struct pci_dev *pdev, struct netdev_private *np; int i, option; int chip_id = (int) ent->driver_data; - int irq = pdev->irq; static int card_idx = -1; static int did_version = 0; long ioaddr; int io_size; int pci_flags; - void *ring; - dma_addr_t ring_dma; /* print version once and once only */ if (! did_version++) { @@ -471,8 +493,11 @@ static int __devinit via_rhine_init_one (struct pci_dev *pdev, io_size = via_rhine_chip_info[chip_id].io_size; pci_flags = via_rhine_chip_info[chip_id].pci_flags; + if (pci_enable_device (pdev)) + goto err_out; + /* this should always be supported */ - if (!pci_dma_supported(pdev, 0xffffffff)) { + if (pci_set_dma_mask(pdev, 0xffffffff)) { printk(KERN_ERR "32-bit PCI DMA addresses not supported by the card!?\n"); goto err_out; } @@ -484,84 +509,48 @@ static int __devinit via_rhine_init_one (struct pci_dev *pdev, goto err_out; } - /* allocate pci dma space for rx and tx descriptor rings */ - ring = pci_alloc_consistent(pdev, - RX_RING_SIZE * sizeof(struct rx_desc) + - TX_RING_SIZE * sizeof(struct tx_desc), - &ring_dma); - if (!ring) { - printk(KERN_ERR "Could not allocate DMA memory.\n"); - goto err_out; - } - ioaddr = pci_resource_start (pdev, pci_flags & PCI_ADDR0 ? 0 : 1); - - if (pci_enable_device (pdev)) - goto err_out_free_dma; if (pci_flags & PCI_USES_MASTER) pci_set_master (pdev); - dev = init_etherdev(NULL, sizeof(*np)); + dev = alloc_etherdev(sizeof(*np)); if (dev == NULL) { printk (KERN_ERR "init_ethernet failed for card #%d\n", card_idx); - goto err_out_free_dma; + goto err_out; } SET_MODULE_OWNER(dev); - /* request all PIO and MMIO regions just to make sure - * noone else attempts to use any portion of our I/O space */ - if (!request_region (pci_resource_start (pdev, 0), - pci_resource_len (pdev, 0), dev->name)) { - printk (KERN_ERR "request_region failed for device %s, region 0x%X @ 0x%lX\n", - dev->name, io_size, - pci_resource_start (pdev, 0)); + if (pci_request_regions(pdev, "via-rhine")) goto err_out_free_netdev; - } - if (!request_mem_region (pci_resource_start (pdev, 1), - pci_resource_len (pdev, 1), dev->name)) { - printk (KERN_ERR "request_mem_region failed for device %s, region 0x%X @ 0x%lX\n", - dev->name, io_size, - pci_resource_start (pdev, 1)); - goto err_out_free_pio; - } #ifndef USE_IO ioaddr = (long) ioremap (ioaddr, io_size); if (!ioaddr) { printk (KERN_ERR "ioremap failed for device %s, region 0x%X @ 0x%X\n", - dev->name, io_size, + pdev->slot_name, io_size, pci_resource_start (pdev, 1)); - goto err_out_free_mmio; + goto err_out_free_res; } #endif - printk(KERN_INFO "%s: %s at 0x%lx, ", - dev->name, via_rhine_chip_info[chip_id].name, ioaddr); - /* Ideally we would read the EEPROM but access may be locked. */ for (i = 0; i < 6; i++) dev->dev_addr[i] = readb(ioaddr + StationAddr + i); - for (i = 0; i < 5; i++) - printk("%2.2x:", dev->dev_addr[i]); - printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); /* Reset the chip to erase previous misconfiguration. */ writew(CmdReset, ioaddr + ChipCmd); + wait_for_reset(dev); dev->base_addr = ioaddr; - dev->irq = irq; + dev->irq = pdev->irq; np = dev->priv; spin_lock_init (&np->lock); np->chip_id = chip_id; np->drv_flags = via_rhine_chip_info[chip_id].drv_flags; np->pdev = pdev; - np->rx_ring = ring; - np->tx_ring = ring + RX_RING_SIZE * sizeof(struct rx_desc); - np->rx_ring_dma = ring_dma; - np->tx_ring_dma = ring_dma + RX_RING_SIZE * sizeof(struct rx_desc); if (dev->mem_start) option = dev->mem_start; @@ -588,12 +577,22 @@ static int __devinit via_rhine_init_one (struct pci_dev *pdev, dev->tx_timeout = via_rhine_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; - pdev->driver_data = dev; + i = register_netdev(dev); + if (i) + goto err_out_unmap; + + printk(KERN_INFO "%s: %s at 0x%lx, ", + dev->name, via_rhine_chip_info[chip_id].name, ioaddr); + for (i = 0; i < 5; i++) + printk("%2.2x:", dev->dev_addr[i]); + printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], pdev->irq); + + pci_set_drvdata(pdev, dev); if (np->drv_flags & CanHaveMII) { int phy, phy_idx = 0; np->phys[0] = 1; /* Standard for this chip. */ - for (phy = 1; phy < 32 && phy_idx < 4; phy++) { + for (phy = 1; phy < 32 && phy_idx < MAX_MII_CNT; phy++) { int mii_status = mdio_read(dev, phy, 1); if (mii_status != 0xffff && mii_status != 0x0000) { np->phys[phy_idx++] = phy; @@ -610,34 +609,215 @@ static int __devinit via_rhine_init_one (struct pci_dev *pdev, netif_carrier_off(dev); } } + np->mii_cnt = phy_idx; } return 0; +err_out_unmap: #ifndef USE_IO -/* note this is ifdef'd because the ioremap is ifdef'd... - * so additional exit conditions above this must move - * release_mem_region outside of the ifdef */ -err_out_free_mmio: - release_mem_region(pci_resource_start (pdev, 1), - pci_resource_len (pdev, 1)); + iounmap((void *)ioaddr); +err_out_free_res: #endif -err_out_free_pio: - release_region(pci_resource_start (pdev, 0), - pci_resource_len (pdev, 0)); + pci_release_regions(pdev); err_out_free_netdev: - unregister_netdev (dev); kfree (dev); -err_out_free_dma: - pci_free_consistent(pdev, +err_out: + return -ENODEV; +} + +static int alloc_ring(struct net_device* dev) +{ + struct netdev_private *np = dev->priv; + void *ring; + dma_addr_t ring_dma; + + ring = pci_alloc_consistent(np->pdev, + RX_RING_SIZE * sizeof(struct rx_desc) + + TX_RING_SIZE * sizeof(struct tx_desc), + &ring_dma); + if (!ring) { + printk(KERN_ERR "Could not allocate DMA memory.\n"); + return -ENOMEM; + } + np->tx_bufs = pci_alloc_consistent(np->pdev, PKT_BUF_SZ * TX_RING_SIZE, + &np->tx_bufs_dma); + if (np->tx_bufs == NULL) { + pci_free_consistent(np->pdev, RX_RING_SIZE * sizeof(struct rx_desc) + TX_RING_SIZE * sizeof(struct tx_desc), ring, ring_dma); -err_out: - return -ENODEV; + return -ENOMEM; + } + + np->rx_ring = ring; + np->tx_ring = ring + RX_RING_SIZE * sizeof(struct rx_desc); + np->rx_ring_dma = ring_dma; + np->tx_ring_dma = ring_dma + RX_RING_SIZE * sizeof(struct rx_desc); + + + return 0; +} + +void free_ring(struct net_device* dev) +{ + struct netdev_private *np = dev->priv; + + pci_free_consistent(np->pdev, + RX_RING_SIZE * sizeof(struct rx_desc) + + TX_RING_SIZE * sizeof(struct tx_desc), + np->rx_ring, np->rx_ring_dma); + + pci_free_consistent(np->pdev, PKT_BUF_SZ * TX_RING_SIZE, + np->tx_bufs, np->tx_bufs_dma); + } +static void alloc_rbufs(struct net_device *dev) +{ + struct netdev_private *np = dev->priv; + dma_addr_t next; + int i; + + np->dirty_rx = np->cur_rx = 0; + + np->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); + np->rx_head_desc = &np->rx_ring[0]; + next = np->rx_ring_dma; + + /* Init the ring entries */ + for (i = 0; i < RX_RING_SIZE; i++) { + np->rx_ring[i].rx_status = 0; + np->rx_ring[i].desc_length = cpu_to_le32(np->rx_buf_sz); + next += sizeof(struct rx_desc); + np->rx_ring[i].next_desc = cpu_to_le32(next); + np->rx_skbuff[i] = 0; + } + /* Mark the last entry as wrapping the ring. */ + np->rx_ring[i-1].next_desc = cpu_to_le32(np->rx_ring_dma); + + /* Fill in the Rx buffers. Handle allocation failure gracefully. */ + for (i = 0; i < RX_RING_SIZE; i++) { + struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz); + np->rx_skbuff[i] = skb; + if (skb == NULL) + break; + skb->dev = dev; /* Mark as being used by this device. */ + + np->rx_skbuff_dma[i] = + pci_map_single(np->pdev, skb->tail, np->rx_buf_sz, + PCI_DMA_FROMDEVICE); + + np->rx_ring[i].addr = cpu_to_le32(np->rx_skbuff_dma[i]); + np->rx_ring[i].rx_status = cpu_to_le32(DescOwn); + } + np->dirty_rx = (unsigned int)(i - RX_RING_SIZE); +} + +static void free_rbufs(struct net_device* dev) +{ + struct netdev_private *np = dev->priv; + int i; + + /* Free all the skbuffs in the Rx queue. */ + for (i = 0; i < RX_RING_SIZE; i++) { + np->rx_ring[i].rx_status = 0; + np->rx_ring[i].addr = cpu_to_le32(0xBADF00D0); /* An invalid address. */ + if (np->rx_skbuff[i]) { + pci_unmap_single(np->pdev, + np->rx_skbuff_dma[i], + np->rx_buf_sz, PCI_DMA_FROMDEVICE); + dev_kfree_skb(np->rx_skbuff[i]); + } + np->rx_skbuff[i] = 0; + } +} + +static void alloc_tbufs(struct net_device* dev) +{ + struct netdev_private *np = dev->priv; + dma_addr_t next; + int i; + + np->dirty_tx = np->cur_tx = 0; + next = np->tx_ring_dma; + for (i = 0; i < TX_RING_SIZE; i++) { + np->tx_skbuff[i] = 0; + np->tx_ring[i].tx_status = 0; + np->tx_ring[i].desc_length = cpu_to_le32(0x00e08000); + next += sizeof(struct tx_desc); + np->tx_ring[i].next_desc = cpu_to_le32(next); + np->tx_buf[i] = &np->tx_bufs[i * PKT_BUF_SZ]; + } + np->tx_ring[i-1].next_desc = cpu_to_le32(np->tx_ring_dma); + +} + +static void free_tbufs(struct net_device* dev) +{ + struct netdev_private *np = dev->priv; + int i; + + for (i = 0; i < TX_RING_SIZE; i++) { + np->tx_ring[i].tx_status = 0; + np->tx_ring[i].desc_length = cpu_to_le32(0x00e08000); + np->tx_ring[i].addr = cpu_to_le32(0xBADF00D0); /* An invalid address. */ + if (np->tx_skbuff[i]) { + if (np->tx_skbuff_dma[i]) { + pci_unmap_single(np->pdev, + np->tx_skbuff_dma[i], + np->tx_skbuff[i]->len, PCI_DMA_TODEVICE); + } + dev_kfree_skb(np->tx_skbuff[i]); + } + np->tx_skbuff[i] = 0; + np->tx_buf[i] = 0; + } +} + +static void init_registers(struct net_device *dev) +{ + struct netdev_private *np = dev->priv; + long ioaddr = dev->base_addr; + int i; + + for (i = 0; i < 6; i++) + writeb(dev->dev_addr[i], ioaddr + StationAddr + i); + + /* Initialize other registers. */ + writew(0x0006, ioaddr + PCIBusConfig); /* Tune configuration??? */ + /* Configure the FIFO thresholds. */ + writeb(0x20, ioaddr + TxConfig); /* Initial threshold 32 bytes */ + np->tx_thresh = 0x20; + np->rx_thresh = 0x60; /* Written in via_rhine_set_rx_mode(). */ + + if (dev->if_port == 0) + dev->if_port = np->default_port; + writel(np->rx_ring_dma, ioaddr + RxRingPtr); + writel(np->tx_ring_dma, ioaddr + TxRingPtr); + + via_rhine_set_rx_mode(dev); + + /* Enable interrupts by setting the interrupt mask. */ + writew(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow| IntrRxDropped| + IntrTxDone | IntrTxAbort | IntrTxUnderrun | + IntrPCIErr | IntrStatsMax | IntrLinkChange | IntrMIIChange, + ioaddr + IntrEnable); + + np->chip_cmd = CmdStart|CmdTxOn|CmdRxOn|CmdNoTxPoll; + if (np->duplex_lock) + np->chip_cmd |= CmdFDuplex; + writew(np->chip_cmd, ioaddr + ChipCmd); + + via_rhine_check_duplex(dev); + + /* The LED outputs of various MII xcvrs should be configured. */ + /* For NS or Mison phys, turn on bit 1 in register 0x17 */ + /* For ESI phys, turn on bit 7 in register 0x17. */ + mdio_write(dev, np->phys[0], 0x17, mdio_read(dev, np->phys[0], 0x17) | + (np->drv_flags & HasESIPhy) ? 0x0080 : 0x0001); +} /* Read and write over the MII Management Data I/O (MDIO) interface. */ static int mdio_read(struct net_device *dev, int phy_id, int regnum) @@ -660,7 +840,7 @@ static int mdio_read(struct net_device *dev, int phy_id, int regnum) static void mdio_write(struct net_device *dev, int phy_id, int regnum, int value) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; int boguscnt = 1024; @@ -691,75 +871,36 @@ static void mdio_write(struct net_device *dev, int phy_id, int regnum, int value static int via_rhine_open(struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; int i; /* Reset the chip. */ writew(CmdReset, ioaddr + ChipCmd); - i = request_irq(dev->irq, &via_rhine_interrupt, SA_SHIRQ, dev->name, dev); + i = request_irq(np->pdev->irq, &via_rhine_interrupt, SA_SHIRQ, dev->name, dev); if (i) return i; if (debug > 1) printk(KERN_DEBUG "%s: via_rhine_open() irq %d.\n", - dev->name, dev->irq); - - np->tx_bufs = pci_alloc_consistent(np->pdev, PKT_BUF_SZ * TX_RING_SIZE, - &np->tx_bufs_dma); - if (np->tx_bufs == NULL) { - free_irq(dev->irq, dev); - return -ENOMEM; - } - - via_rhine_init_ring(dev); - - writel(np->rx_ring_dma, ioaddr + RxRingPtr); - writel(np->tx_ring_dma, ioaddr + TxRingPtr); - - for (i = 0; i < 6; i++) - writeb(dev->dev_addr[i], ioaddr + StationAddr + i); - - /* Initialize other registers. */ - writew(0x0006, ioaddr + PCIBusConfig); /* Tune configuration??? */ - /* Configure the FIFO thresholds. */ - writeb(0x20, ioaddr + TxConfig); /* Initial threshold 32 bytes */ - np->tx_thresh = 0x20; - np->rx_thresh = 0x60; /* Written in via_rhine_set_rx_mode(). */ - - if (dev->if_port == 0) - dev->if_port = np->default_port; - - netif_start_queue(dev); - - via_rhine_set_rx_mode(dev); - - /* Enable interrupts by setting the interrupt mask. */ - writew(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow| IntrRxDropped| - IntrTxDone | IntrTxAbort | IntrTxUnderrun | - IntrPCIErr | IntrStatsMax | IntrLinkChange | IntrMIIChange, - ioaddr + IntrEnable); - - np->chip_cmd = CmdStart|CmdTxOn|CmdRxOn|CmdNoTxPoll; - if (np->duplex_lock) - np->chip_cmd |= CmdFDuplex; - writew(np->chip_cmd, ioaddr + ChipCmd); - - via_rhine_check_duplex(dev); - - /* The LED outputs of various MII xcvrs should be configured. */ - /* For NS or Mison phys, turn on bit 1 in register 0x17 */ - /* For ESI phys, turn on bit 7 in register 0x17. */ - mdio_write(dev, np->phys[0], 0x17, mdio_read(dev, np->phys[0], 0x17) | - (np->drv_flags & HasESIPhy) ? 0x0080 : 0x0001); - + dev->name, np->pdev->irq); + + i = alloc_ring(dev); + if (i) + return i; + alloc_rbufs(dev); + alloc_tbufs(dev); + wait_for_reset(dev); + init_registers(dev); if (debug > 2) printk(KERN_DEBUG "%s: Done via_rhine_open(), status %4.4x " "MII status: %4.4x.\n", dev->name, readw(ioaddr + ChipCmd), mdio_read(dev, np->phys[0], 1)); + netif_start_queue(dev); + /* Set the timer to check for link beat. */ init_timer(&np->timer); np->timer.expires = jiffies + 2; @@ -772,7 +913,7 @@ static int via_rhine_open(struct net_device *dev) static void via_rhine_check_duplex(struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; int mii_reg5 = mdio_read(dev, np->phys[0], 5); int negotiated = mii_reg5 & np->advertising; @@ -799,7 +940,7 @@ static void via_rhine_check_duplex(struct net_device *dev) static void via_rhine_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; int next_tick = 10*HZ; int mii_status; @@ -832,92 +973,45 @@ static void via_rhine_timer(unsigned long data) static void via_rhine_tx_timeout (struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *) dev->priv; + struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; - /* Lock to protect mdio_read and access to stats. A friendly - advice to the implementor of the XXXs in this function is to be - sure not to spin too long (whatever that means :) */ - spin_lock_irq (&np->lock); - printk (KERN_WARNING "%s: Transmit timed out, status %4.4x, PHY status " "%4.4x, resetting...\n", dev->name, readw (ioaddr + IntrStatus), mdio_read (dev, np->phys[0], 1)); - /* XXX Perhaps we should reinitialize the hardware here. */ dev->if_port = 0; - /* Stop and restart the chip's Tx processes . */ - /* XXX to do */ - - /* Trigger an immediate transmit demand. */ - /* XXX to do */ + /* protect against concurrent rx interrupts */ + disable_irq(np->pdev->irq); - dev->trans_start = jiffies; - np->stats.tx_errors++; + spin_lock(&np->lock); - spin_unlock_irq (&np->lock); -} - - -/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ -static void via_rhine_init_ring(struct net_device *dev) -{ - struct netdev_private *np = (struct netdev_private *)dev->priv; - int i; - dma_addr_t next = np->rx_ring_dma; - - np->cur_rx = np->cur_tx = 0; - np->dirty_rx = np->dirty_tx = 0; - - np->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); - np->rx_head_desc = &np->rx_ring[0]; - - for (i = 0; i < RX_RING_SIZE; i++) { - np->rx_ring[i].rx_status = 0; - np->rx_ring[i].desc_length = cpu_to_le32(np->rx_buf_sz); - next += sizeof(struct rx_desc); - np->rx_ring[i].next_desc = cpu_to_le32(next); - np->rx_skbuff[i] = 0; - } - /* Mark the last entry as wrapping the ring. */ - np->rx_ring[i-1].next_desc = cpu_to_le32(np->rx_ring_dma); - - /* Fill in the Rx buffers. Handle allocation failure gracefully. */ - for (i = 0; i < RX_RING_SIZE; i++) { - struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz); - np->rx_skbuff[i] = skb; - if (skb == NULL) - break; - skb->dev = dev; /* Mark as being used by this device. */ - - np->rx_skbuff_dma[i] = - pci_map_single(np->pdev, skb->tail, np->rx_buf_sz, - PCI_DMA_FROMDEVICE); + /* Reset the chip. */ + writew(CmdReset, ioaddr + ChipCmd); - np->rx_ring[i].addr = cpu_to_le32(np->rx_skbuff_dma[i]); - np->rx_ring[i].rx_status = cpu_to_le32(DescOwn); - } - np->dirty_rx = (unsigned int)(i - RX_RING_SIZE); + /* clear all descriptors */ + free_tbufs(dev); + free_rbufs(dev); + alloc_tbufs(dev); + alloc_rbufs(dev); - next = np->tx_ring_dma; - for (i = 0; i < TX_RING_SIZE; i++) { - np->tx_skbuff[i] = 0; - np->tx_ring[i].tx_status = 0; - np->tx_ring[i].desc_length = cpu_to_le32(0x00e08000); - next += sizeof(struct tx_desc); - np->tx_ring[i].next_desc = cpu_to_le32(next); - np->tx_buf[i] = &np->tx_bufs[i * PKT_BUF_SZ]; - } - np->tx_ring[i-1].next_desc = cpu_to_le32(np->tx_ring_dma); + /* Reinitialize the hardware. */ + wait_for_reset(dev); + init_registers(dev); + + spin_unlock(&np->lock); + enable_irq(np->pdev->irq); - return; + dev->trans_start = jiffies; + np->stats.tx_errors++; + netif_wake_queue(dev); } static int via_rhine_start_tx(struct sk_buff *skb, struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; unsigned entry; /* Caution: the write order is important here, set the field @@ -972,7 +1066,7 @@ static int via_rhine_start_tx(struct sk_buff *skb, struct net_device *dev) after the Tx thread. */ static void via_rhine_interrupt(int irq, void *dev_instance, struct pt_regs *rgs) { - struct net_device *dev = (struct net_device *)dev_instance; + struct net_device *dev = dev_instance; long ioaddr; u32 intr_status; int boguscnt = max_interrupt_work; @@ -1017,7 +1111,7 @@ static void via_rhine_interrupt(int irq, void *dev_instance, struct pt_regs *rgs for clarity. */ static void via_rhine_tx(struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; int txstatus = 0, entry = np->dirty_tx % TX_RING_SIZE; spin_lock (&np->lock); @@ -1066,7 +1160,7 @@ static void via_rhine_tx(struct net_device *dev) for clarity and better register allocation. */ static void via_rhine_rx(struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; int entry = np->cur_rx % RX_RING_SIZE; int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx; @@ -1149,7 +1243,7 @@ static void via_rhine_rx(struct net_device *dev) skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); dev->last_rx = jiffies; - np->stats.rx_bytes += skb->len; + np->stats.rx_bytes += pkt_len; np->stats.rx_packets++; } entry = (++np->cur_rx) % RX_RING_SIZE; @@ -1180,7 +1274,7 @@ static void via_rhine_rx(struct net_device *dev) static void via_rhine_error(struct net_device *dev, int intr_status) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; spin_lock (&np->lock); @@ -1215,8 +1309,9 @@ static void via_rhine_error(struct net_device *dev, int intr_status) "threshold setting to %2.2x.\n", dev->name, np->tx_thresh); } if ((intr_status & ~( IntrLinkChange | IntrStatsMax | - IntrTxAbort | IntrTxAborted)) && debug > 1) { - printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n", + IntrTxAbort | IntrTxAborted))) { + if (debug > 1) + printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n", dev->name, intr_status); /* Recovery for other fault sources not known. */ writew(CmdTxDemand | np->chip_cmd, dev->base_addr + ChipCmd); @@ -1227,7 +1322,7 @@ static void via_rhine_error(struct net_device *dev, int intr_status) static struct net_device_stats *via_rhine_get_stats(struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; unsigned long flags; @@ -1273,7 +1368,7 @@ static inline u32 ether_crc(int length, unsigned char *data) static void via_rhine_set_rx_mode(struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; u32 mc_filter[2]; /* Multicast hash filter */ u8 rx_mode; /* Note: 0x02=accept runt, 0x01=accept errs */ @@ -1305,7 +1400,7 @@ static void via_rhine_set_rx_mode(struct net_device *dev) static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; u16 *data = (u16 *)&rq->ifr_data; unsigned long flags; int retval; @@ -1338,13 +1433,11 @@ static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) static int via_rhine_close(struct net_device *dev) { long ioaddr = dev->base_addr; - struct netdev_private *np = (struct netdev_private *)dev->priv; - int i; - unsigned long flags; + struct netdev_private *np = dev->priv; del_timer_sync(&np->timer); - spin_lock_irqsave(&np->lock, flags); + spin_lock_irq(&np->lock); netif_stop_queue(dev); @@ -1361,44 +1454,12 @@ static int via_rhine_close(struct net_device *dev) /* Stop the chip's Tx and Rx processes. */ writew(CmdStop, ioaddr + ChipCmd); - spin_unlock_irqrestore(&np->lock, flags); - - /* Make sure there is no irq-handler running on a different CPU. */ - synchronize_irq(); - - free_irq(dev->irq, dev); - - /* Free all the skbuffs in the Rx queue. */ - for (i = 0; i < RX_RING_SIZE; i++) { - np->rx_ring[i].rx_status = 0; - np->rx_ring[i].addr = cpu_to_le32(0xBADF00D0); /* An invalid address. */ - if (np->rx_skbuff[i]) { - pci_unmap_single(np->pdev, - np->rx_skbuff_dma[i], - np->rx_buf_sz, PCI_DMA_FROMDEVICE); - dev_kfree_skb(np->rx_skbuff[i]); - } - np->rx_skbuff[i] = 0; - } + spin_unlock_irq(&np->lock); - /* Free all the skbuffs in the Tx queue, and also any bounce buffers. */ - for (i = 0; i < TX_RING_SIZE; i++) { - np->tx_ring[i].tx_status = 0; - np->tx_ring[i].desc_length = cpu_to_le32(0x00e08000); - np->tx_ring[i].addr = cpu_to_le32(0xBADF00D0); /* An invalid address. */ - if (np->tx_skbuff[i]) { - if (np->tx_skbuff_dma[i]) { - pci_unmap_single(np->pdev, - np->tx_skbuff_dma[i], - np->tx_skbuff[i]->len, PCI_DMA_TODEVICE); - } - dev_kfree_skb(np->tx_skbuff[i]); - } - np->tx_skbuff[i] = 0; - np->tx_buf[i] = 0; - } - pci_free_consistent(np->pdev, PKT_BUF_SZ * TX_RING_SIZE, - np->tx_bufs, np->tx_bufs_dma); + free_irq(np->pdev->irq, dev); + free_rbufs(dev); + free_tbufs(dev); + free_ring(dev); return 0; } @@ -1406,15 +1467,12 @@ static int via_rhine_close(struct net_device *dev) static void __devexit via_rhine_remove_one (struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; - struct netdev_private *np = (struct netdev_private *)(dev->priv); + struct net_device *dev = pci_get_drvdata(pdev); + struct netdev_private *np = dev->priv; unregister_netdev(dev); - release_region(pci_resource_start (pdev, 0), - pci_resource_len (pdev, 0)); - release_mem_region(pci_resource_start (pdev, 1), - pci_resource_len (pdev, 1)); + pci_release_regions(pdev); #ifndef USE_IO iounmap((char *)(dev->base_addr)); @@ -1426,6 +1484,8 @@ static void __devexit via_rhine_remove_one (struct pci_dev *pdev) np->rx_ring, np->rx_ring_dma); kfree(dev); + + pci_set_drvdata(pdev, NULL); } diff --git a/drivers/net/wan/Config.in b/drivers/net/wan/Config.in index 4c8517081..58e64e7fd 100644 --- a/drivers/net/wan/Config.in +++ b/drivers/net/wan/Config.in @@ -33,6 +33,11 @@ if [ "$CONFIG_WAN" = "y" ]; then fi dep_tristate ' Support for Frame Relay on MultiGate boards' CONFIG_COMX_PROTO_FR $CONFIG_COMX fi +# +# The Etinc driver has not been tested as non-modular yet. +# + + dep_tristate ' Etinc PCISYNC serial board support (EXPERIMENTAL)' CONFIG_DSCC4 m # # Lan Media's board. Currently 1000, 1200, 5200, 5245 @@ -46,6 +51,18 @@ if [ "$CONFIG_WAN" = "y" ]; then dep_tristate ' SyncLink HDLC/SYNCPPP support' CONFIG_SYNCLINK_SYNCPPP m + tristate ' Generic HDLC driver' CONFIG_HDLC + if [ "$CONFIG_HDLC" != "n" ]; then + bool ' Synchronous Point-to-Point Protocol (PPP) support' CONFIG_HDLC_PPP + if [ "$CONFIG_LAPB" = "m" -a "$CONFIG_HDLC" = "m" -o "$CONFIG_LAPB" = "y" ]; then + bool ' X.25 protocol support' CONFIG_HDLC_X25 + else + comment ' X.25/LAPB support is disabled' + fi + dep_tristate ' SDL RISCom/N2 support' CONFIG_N2 $CONFIG_HDLC + dep_tristate ' Moxa C101 support' CONFIG_C101 $CONFIG_HDLC + fi + tristate ' Frame relay DLCI support' CONFIG_DLCI if [ "$CONFIG_DLCI" != "n" ]; then int ' Max open DLCI' CONFIG_DLCI_COUNT 24 diff --git a/drivers/net/wan/Makefile b/drivers/net/wan/Makefile index 6f37f81cb..5e005f187 100644 --- a/drivers/net/wan/Makefile +++ b/drivers/net/wan/Makefile @@ -9,7 +9,7 @@ SUB_DIRS := O_TARGET := wan.o -export-objs = z85230.o syncppp.o comx.o sdladrv.o cycx_drv.o +export-objs = z85230.o syncppp.o comx.o sdladrv.o cycx_drv.o hdlc.o list-multi = wanpipe.o cyclomx.o wanpipe-objs = sdlamain.o $(wanpipe-y) @@ -32,6 +32,7 @@ obj-$(CONFIG_COMX_PROTO_PPP) += syncppp.o comx-proto-ppp.o obj-$(CONFIG_COMX_PROTO_LAPB) += comx-proto-lapb.o obj-$(CONFIG_COMX_PROTO_FR) += comx-proto-fr.o obj-$(CONFIG_COSA) += syncppp.o cosa.o +obj-$(CONFIG_DSCC4) += dscc4.o obj-$(CONFIG_LANMEDIA) += syncppp.o obj-$(CONFIG_SYNCLINK_SYNCPPP) += syncppp.o obj-$(CONFIG_X25_ASY) += x25_asy.o @@ -48,6 +49,10 @@ obj-$(CONFIG_VENDOR_SANGOMA) += sdladrv.o wanpipe.o obj-$(CONFIG_CYCLADES_SYNC) += cycx_drv.o cyclomx.o obj-$(CONFIG_LAPBETHER) += lapbether.o obj-$(CONFIG_SBNI) += sbni.o +obj-$(CONFIG_HDLC) += hdlc.o +obj-$(CONFIG_HDLC_PPP) += syncppp.o +obj-$(CONFIG_N2) += n2.o +obj-$(CONFIG_C101) += c101.o include $(TOPDIR)/Rules.make diff --git a/drivers/net/wan/c101.c b/drivers/net/wan/c101.c new file mode 100644 index 000000000..95e322ef6 --- /dev/null +++ b/drivers/net/wan/c101.c @@ -0,0 +1,375 @@ +/* + * Moxa C101 synchronous serial card driver for Linux + * + * Copyright (C) 2000 Krzysztof Halasa <khc@pm.waw.pl> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * For information see http://hq.pm.waw.pl/hdlc/ + * + * Sources of information: + * Hitachi HD64570 SCA User's Manual + * Moxa C101 User's Manual + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/types.h> +#include <linux/string.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/netdevice.h> +#include <linux/hdlc.h> +#include <linux/delay.h> +#include <asm/io.h> + +#include "hd64570.h" + +#define DEBUG_RINGS +/* #define DEBUG_PKT */ + +static const char* version = "Moxa C101 driver revision: 1.02 for Linux 2.4"; +static const char* devname = "C101"; + +#define C101_PAGE 0x1D00 +#define C101_DTR 0x1E00 +#define C101_SCA 0x1F00 +#define C101_WINDOW_SIZE 0x2000 +#define C101_MAPPED_RAM_SIZE 0x4000 + +#define RAM_SIZE (256 * 1024) +#define CLOCK_BASE 9830400 /* 9.8304 MHz */ +#define PAGE0_ALWAYS_MAPPED + +static char *hw; /* pointer to hw=xxx command line string */ + + +typedef struct card_s { + hdlc_device hdlc; /* HDLC device struct - must be first */ + spinlock_t lock; /* TX lock */ + int clkmode; /* clock mode */ + int clkrate; /* clock speed */ + int line; /* loopback only */ + u8 *win0base; /* ISA window base address */ + u32 phy_winbase; /* ISA physical base address */ + u16 buff_offset; /* offset of first buffer of first channel */ + u8 rxs, txs, tmc; /* SCA registers */ + u8 irq; /* IRQ (3-15) */ + u8 ring_buffers; /* number of buffers in a ring */ + u8 page; + + u8 rxin; /* rx ring buffer 'in' pointer */ + u8 txin; /* tx ring buffer 'in' and 'last' pointers */ + u8 txlast; + u8 rxpart; /* partial frame received, next frame invalid*/ + + struct card_s *next_card; +}card_t; + +typedef card_t port_t; + + +#define sca_in(reg, card) readb((card)->win0base + C101_SCA + (reg)) +#define sca_out(value, reg, card) writeb(value, (card)->win0base + C101_SCA + (reg)) +#define sca_inw(reg, card) readw((card)->win0base + C101_SCA + (reg)) +#define sca_outw(value, reg, card) writew(value, (card)->win0base + C101_SCA + (reg)) + +#define port_to_card(port) (port) +#define log_node(port) (0) +#define phy_node(port) (0) +#define winsize(card) (C101_WINDOW_SIZE) +#define win0base(card) ((card)->win0base) +#define winbase(card) ((card)->win0base + 0x2000) +#define get_port(card, port) ((port) == 0 ? (card) : NULL) + + +static inline u8 sca_get_page(card_t *card) +{ + return card->page; +} + +static inline void openwin(card_t *card, u8 page) +{ + card->page = page; + writeb(page, card->win0base + C101_PAGE); +} + + +#define close_windows(card) {} /* no hardware support */ + + +#include "hd6457x.c" + + +static int c101_set_clock(port_t *port, int value) +{ + u8 msci = get_msci(port); + u8 rxs = port->rxs & CLK_BRG_MASK; + u8 txs = port->txs & CLK_BRG_MASK; + + switch(value) { + case CLOCK_EXT: + rxs |= CLK_LINE_RX; /* RXC input */ + txs |= CLK_LINE_TX; /* TXC input */ + break; + + case CLOCK_INT: + rxs |= CLK_BRG_RX; /* TX clock */ + txs |= CLK_RXCLK_TX; /* BRG output */ + break; + + case CLOCK_TXINT: + rxs |= CLK_LINE_RX; /* RXC input */ + txs |= CLK_BRG_TX; /* BRG output */ + break; + + case CLOCK_TXFROMRX: + rxs |= CLK_LINE_RX; /* RXC input */ + txs |= CLK_RXCLK_TX; /* RX clock */ + break; + + default: + return -EINVAL; + } + + port->rxs = rxs; + port->txs = txs; + sca_out(rxs, msci + RXS, port); + sca_out(txs, msci + TXS, port); + port->clkmode = value; + return 0; +} + + +static int c101_open(hdlc_device *hdlc) +{ + port_t *port = hdlc_to_port(hdlc); + + MOD_INC_USE_COUNT; + writeb(1, port->win0base + C101_DTR); + sca_out(0, MSCI1_OFFSET + CTL, port); /* RTS uses ch#2 output */ + sca_open(hdlc); + c101_set_clock(port, port->clkmode); + return 0; +} + + +static void c101_close(hdlc_device *hdlc) +{ + port_t *port = hdlc_to_port(hdlc); + + sca_close(hdlc); + writeb(0, port->win0base + C101_DTR); + sca_out(CTL_NORTS, MSCI1_OFFSET + CTL, port); + MOD_DEC_USE_COUNT; +} + + +static int c101_ioctl(hdlc_device *hdlc, struct ifreq *ifr, int cmd) +{ + int value = ifr->ifr_ifru.ifru_ivalue; + int result = 0; + port_t *port = hdlc_to_port(hdlc); + + if(!capable(CAP_NET_ADMIN)) + return -EPERM; + + switch(cmd) { + case HDLCSCLOCK: + result = c101_set_clock(port, value); + case HDLCGCLOCK: + value = port->clkmode; + break; + + case HDLCSCLOCKRATE: + port->clkrate = value; + sca_set_clock(port); + case HDLCGCLOCKRATE: + value = port->clkrate; + break; + + case HDLCSLINE: + result = sca_set_loopback(port, value); + case HDLCGLINE: + value = port->line; + break; + +#ifdef DEBUG_RINGS + case HDLCRUN: + sca_dump_rings(hdlc); + return 0; +#endif /* DEBUG_RINGS */ + + default: + return -EINVAL; + } + + ifr->ifr_ifru.ifru_ivalue = value; + return result; +} + + + +static void c101_destroy_card(card_t *card) +{ + if (card->irq) + free_irq(card->irq, card); + + if (card->win0base) { + iounmap(card->win0base); + release_mem_region(card->phy_winbase, C101_MAPPED_RAM_SIZE); + } + + kfree(card); +} + + + +static int c101_run(unsigned long irq, unsigned long winbase) +{ + card_t *card; + int result; + + if (irq<3 || irq>15 || irq == 6) /* FIXME */ { + printk(KERN_ERR "c101: invalid IRQ value\n"); + return -ENODEV; + } + + if (winbase < 0xC0000 || winbase > 0xDFFFF || (winbase & 0x3FFF) !=0) { + printk(KERN_ERR "c101: invalid RAM value\n"); + return -ENODEV; + } + + card = kmalloc(sizeof(card_t), GFP_KERNEL); + if (card == NULL) { + printk(KERN_ERR "c101: unable to allocate memory\n"); + return -ENOBUFS; + } + memset(card, 0, sizeof(card_t)); + + if (request_irq(irq, sca_intr, 0, devname, card)) { + printk(KERN_ERR "c101: could not allocate IRQ\n"); + c101_destroy_card(card); + return(-EBUSY); + } + card->irq = irq; + + if (!request_mem_region(winbase, C101_MAPPED_RAM_SIZE, devname)) { + printk(KERN_ERR "c101: could not request RAM window\n"); + c101_destroy_card(card); + return(-EBUSY); + } + card->phy_winbase = winbase; + card->win0base = ioremap(winbase, C101_MAPPED_RAM_SIZE); + if (!card->win0base) { + printk(KERN_ERR "c101: could not map I/O address\n"); + c101_destroy_card(card); + return -EBUSY; + } + + /* 2 rings required for 1 port */ + card->ring_buffers = (RAM_SIZE -C101_WINDOW_SIZE) / (2 * HDLC_MAX_MRU); + printk(KERN_DEBUG "c101: using %u packets rings\n",card->ring_buffers); + + card->buff_offset = C101_WINDOW_SIZE; /* Bytes 1D00-1FFF reserved */ + + readb(card->win0base + C101_PAGE); /* Resets SCA? */ + udelay(100); + writeb(0, card->win0base + C101_PAGE); + writeb(0, card->win0base + C101_DTR); /* Power-up for RAM? */ + + sca_init(card, 0); + + spin_lock_init(&card->lock); + hdlc_to_dev(&card->hdlc)->irq = irq; + hdlc_to_dev(&card->hdlc)->mem_start = winbase; + hdlc_to_dev(&card->hdlc)->mem_end = winbase + C101_MAPPED_RAM_SIZE - 1; + hdlc_to_dev(&card->hdlc)->tx_queue_len = 50; + card->hdlc.ioctl = c101_ioctl; + card->hdlc.open = c101_open; + card->hdlc.close = c101_close; + card->hdlc.xmit = sca_xmit; + + result = register_hdlc_device(&card->hdlc); + if (result) { + printk(KERN_WARNING "c101: unable to register hdlc device\n"); + c101_destroy_card(card); + return result; + } + + sca_init_sync_port(card); /* Set up C101 memory */ + + *new_card = card; + new_card = &card->next_card; + return 0; +} + + + +static int __init c101_init(void) +{ + if (hw == NULL) { +#ifdef MODULE + printk(KERN_INFO "c101: no card initialized\n"); +#endif + return -ENOSYS; /* no parameters specified, abort */ + } + + printk(KERN_INFO "%s\n", version); + + do { + unsigned long irq, ram; + + irq = simple_strtoul(hw, &hw, 0); + + if (*hw++ != ',') + break; + ram = simple_strtoul(hw, &hw, 0); + + if (*hw == ':' || *hw == '\x0') + c101_run(irq, ram); + + if (*hw == '\x0') + return 0; + }while(*hw++ == ':'); + + printk(KERN_ERR "c101: invalid hardware parameters\n"); + return first_card ? 0 : -ENOSYS; +} + + +#ifndef MODULE +static int __init c101_setup(char *str) +{ + hw = str; + return 1; +} + +__setup("c101=", c101_setup); +#endif + + +static void __exit c101_cleanup(void) +{ + card_t *card = first_card; + + while (card) { + card_t *ptr = card; + card = card->next_card; + unregister_hdlc_device(&ptr->hdlc); + c101_destroy_card(ptr); + } +} + + +module_init(c101_init); +module_exit(c101_cleanup); + +MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>"); +MODULE_DESCRIPTION("Moxa C101 serial port driver"); +MODULE_PARM(hw, "s"); /* hw=irq,ram:irq,... */ +EXPORT_NO_SYMBOLS; diff --git a/drivers/net/wan/comx-proto-fr.c b/drivers/net/wan/comx-proto-fr.c index c2a0a5ac4..a1f6c8bdc 100644 --- a/drivers/net/wan/comx-proto-fr.c +++ b/drivers/net/wan/comx-proto-fr.c @@ -505,9 +505,9 @@ static int fr_xmit(struct sk_buff *skb, struct net_device *dev) struct sk_buff *newskb=skb_clone(skb, GFP_ATOMIC); newskb->dev=fr->master; dev_queue_xmit(newskb); - dev_kfree_skb(skb); - ch->stats.tx_packets++; ch->stats.tx_bytes += skb->len; + ch->stats.tx_packets++; + dev_kfree_skb(skb); } else { netif_stop_queue(dev); for (; dir ; dir = dir->next) { diff --git a/drivers/net/wan/comx-proto-lapb.c b/drivers/net/wan/comx-proto-lapb.c index acbb7f112..64129018b 100644 --- a/drivers/net/wan/comx-proto-lapb.c +++ b/drivers/net/wan/comx-proto-lapb.c @@ -311,6 +311,7 @@ static void comxlapb_connected(void *token, int reason) skb->pkt_type = PACKET_HOST; netif_rx(skb); + ch->dev->last_rx = jiffies; } for (; comxdir; comxdir = comxdir->next) { @@ -350,6 +351,7 @@ static void comxlapb_disconnected(void *token, int reason) skb->pkt_type = PACKET_HOST; netif_rx(skb); + ch->dev->last_rx = jiffies; } for (; comxdir; comxdir = comxdir->next) { diff --git a/drivers/net/wan/comx-proto-ppp.c b/drivers/net/wan/comx-proto-ppp.c index 825abc776..f7025b7ed 100644 --- a/drivers/net/wan/comx-proto-ppp.c +++ b/drivers/net/wan/comx-proto-ppp.c @@ -44,7 +44,7 @@ #include <asm/uaccess.h> #include <linux/init.h> -#include "syncppp.h" +#include <net/syncppp.h> #include "comx.h" MODULE_AUTHOR("Author: Gergely Madarasz <gorgo@itc.hu>"); diff --git a/drivers/net/wan/comx.c b/drivers/net/wan/comx.c index 47ba5cc74..3382498d6 100644 --- a/drivers/net/wan/comx.c +++ b/drivers/net/wan/comx.c @@ -73,8 +73,8 @@ #error For now, COMX really needs the /proc filesystem #endif +#include <net/syncppp.h> #include "comx.h" -#include "syncppp.h" MODULE_AUTHOR("Gergely Madarasz <gorgo@itc.hu>"); MODULE_DESCRIPTION("Common code for the COMX synchronous serial adapters"); @@ -380,6 +380,7 @@ int comx_rx(struct net_device *dev, struct sk_buff *skb) } if (skb) { netif_rx(skb); + dev->last_rx = jiffies; } return 0; } diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c index 40bc8205a..96b921ee0 100644 --- a/drivers/net/wan/cosa.c +++ b/drivers/net/wan/cosa.c @@ -102,7 +102,7 @@ #include <asm/dma.h> #include <asm/byteorder.h> -#include "syncppp.h" +#include <net/syncppp.h> #include "cosa.h" /* Linux version stuff */ @@ -220,9 +220,9 @@ static int cosa_major = 117; #define COSA_MTU 2000 /* FIXME: I don't know this exactly */ -#undef DEBUG_DATA 1 /* Dump the data read or written to the channel */ -#undef DEBUG_IRQS 1 /* Print the message when the IRQ is received */ -#undef DEBUG_IO 1 /* Dump the I/O traffic */ +#undef DEBUG_DATA //1 /* Dump the data read or written to the channel */ +#undef DEBUG_IRQS //1 /* Print the message when the IRQ is received */ +#undef DEBUG_IO //1 /* Dump the I/O traffic */ #define TX_TIMEOUT (5*HZ) @@ -745,7 +745,7 @@ static int sppp_rx_done(struct channel_data *chan) chan->stats.rx_bytes += chan->cosa->rxsize; netif_rx(chan->rx_skb); chan->rx_skb = 0; - chan->pppdev.dev->trans_start = jiffies; + chan->pppdev.dev->last_rx = jiffies; return 0; } @@ -836,7 +836,7 @@ static ssize_t cosa_read(struct file *file, up(&chan->rsem); if (copy_to_user(buf, kbuf, count)) { - kfree(buf); + kfree(kbuf); return -EFAULT; } kfree(kbuf); @@ -2011,7 +2011,7 @@ again: /* ---------- I/O debugging routines ---------- */ /* * These routines can be used to monitor COSA/SRP I/O and to printk() - * the data being transfered on the data and status I/O port in a + * the data being transferred on the data and status I/O port in a * readable way. */ diff --git a/drivers/net/wan/cosa.h b/drivers/net/wan/cosa.h index 7b5a39018..a0da78023 100644 --- a/drivers/net/wan/cosa.h +++ b/drivers/net/wan/cosa.h @@ -33,7 +33,7 @@ #define SR_RX_INT_ENA 0x80 /* receiver interrupt enable bit */ /* status register - input bits */ -#define SR_USR_RQ 0x20 /* user interupt request pending */ +#define SR_USR_RQ 0x20 /* user interrupt request pending */ #define SR_TX_RDY 0x40 /* transmitter empty (ready) */ #define SR_RX_RDY 0x80 /* receiver data ready */ diff --git a/drivers/net/wan/cycx_x25.c b/drivers/net/wan/cycx_x25.c index bd0e0498f..19f257026 100644 --- a/drivers/net/wan/cycx_x25.c +++ b/drivers/net/wan/cycx_x25.c @@ -3,7 +3,7 @@ * * Author: Arnaldo Carvalho de Melo <acme@conectiva.com.br> * -* Copyright: (c) 1998-2000 Arnaldo Carvalho de Melo +* Copyright: (c) 1998-2001 Arnaldo Carvalho de Melo * * Based on sdla_x25.c by Gene Kozin <genek@compuserve.com> * @@ -12,6 +12,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * ============================================================================ +* 2001/01/12 acme use dev_kfree_skb_irq on interrupt context * 2000/04/02 acme dprintk, cycx_debug * fixed the bug introduced in get_dev_by_lcn and * get_dev_by_dte_addr by the anonymous hacker @@ -794,7 +795,7 @@ static void rx_intr (cycx_t *card, TX25Cmd *cmd) if (skb_tailroom(skb) < pktlen) { /* No room for the packet. Call off the whole thing! */ - dev_kfree_skb(skb); + dev_kfree_skb_irq(skb); chan->rx_skb = NULL; if (bitm) @@ -812,14 +813,14 @@ static void rx_intr (cycx_t *card, TX25Cmd *cmd) if (bitm) return; /* more data is coming */ - dev->last_rx = jiffies; /* timestamp */ chan->rx_skb = NULL; /* dequeue packet */ ++chan->ifstats.rx_packets; - chan->ifstats.rx_bytes += skb->len; + chan->ifstats.rx_bytes += pktlen; skb->mac.raw = skb->data; netif_rx(skb); + dev->last_rx = jiffies; /* timestamp */ } /* Connect interrupt handler. */ @@ -1459,6 +1460,7 @@ static void chan_x25_send_event(struct net_device *dev, u8 event) skb->pkt_type = PACKET_HOST; netif_rx(skb); + dev->last_rx = jiffies; /* timestamp */ } /* Convert line speed in bps to a number used by cyclom 2x code. */ diff --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c index f7ed9f37d..f14572fbc 100644 --- a/drivers/net/wan/dlci.c +++ b/drivers/net/wan/dlci.c @@ -227,8 +227,10 @@ static void dlci_receive(struct sk_buff *skb, struct net_device *dev) /* we've set up the protocol, so discard the header */ skb->mac.raw = skb->data; skb_pull(skb, header); + dlp->stats.rx_bytes += skb->len; netif_rx(skb); dlp->stats.rx_packets++; + dev->last_rx = jiffies; } else dev_kfree_skb(skb); diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c new file mode 100644 index 000000000..fe35f6cbd --- /dev/null +++ b/drivers/net/wan/dscc4.c @@ -0,0 +1,1769 @@ +/* + * drivers/net/wan/dscc4/dscc4_main.c: a DSCC4 HDLC driver for Linux + * + * This software may be used and distributed according to the terms of the + * GNU General Public License. + * + * The author may be reached as romieu@cogenit.fr. + * Specific bug reports/asian food will be welcome. + * + * Special thanks to the nice people at CS-Telecom for the hardware and the + * access to the test/measure tools. + * + * + * Theory of Operation + * + * I. Board Compatibility + * + * This device driver is designed for the Siemens PEB20534 4 ports serial + * controller as found on Etinc PCISYNC cards. The documentation for the + * chipset is available at http://www.infineon.com: + * - Data Sheet "DSCC4, DMA Supported Serial Communication Controller with + * 4 Channels, PEB 20534 Version 2.1, PEF 20534 Version 2.1"; + * - Application Hint "Management of DSCC4 on-chip FIFO resources". + * Jens David has built an adapter based on the same chipset. Take a look + * at http://www.afthd.tu-darmstadt.de/~dg1kjd/pciscc4 for a specific + * driver. + * Sample code (2 revisions) is available at Infineon. + * + * II. Board-specific settings + * + * Pcisync can transmit some clock signal to the outside world on the + * *first two* ports provided you put a quartz and a line driver on it and + * remove the jumpers. The operation is described on Etinc web site. If you + * go DCE on these ports, don't forget to use an adequate cable. + * + * Sharing of the PCI interrupt line for this board is possible. + * + * III. Driver operation + * + * The rx/tx operations are based on a linked list of descriptor. I haven't + * tried the start/stop descriptor method as this one looks like the cheapest + * in terms of PCI manipulation. + * + * Tx direction + * Once the data section of the current descriptor processed, the next linked + * descriptor is loaded if the HOLD bit isn't set in the current descriptor. + * If HOLD is met, the transmission is stopped until the host unsets it and + * signals the change via TxPOLL. + * When the tx ring is full, the xmit routine issues a call to netdev_stop. + * The device is supposed to be enabled again during an ALLS irq (we could + * use HI but as it's easy to loose events, it's fscked). + * + * Rx direction + * The received frames aren't supposed to span over multiple receiving areas. + * I may implement it some day but it isn't the highest ranked item. + * + * IV. Notes + * The chipset is buggy. Typically, under some specific load patterns (I + * wouldn't call them "high"), the irq queues and the descriptors look like + * some event has been lost. Even assuming some fancy PCI feature, it won't + * explain the reproductible missing "C" bit in the descriptors. Faking an + * irq in the periodic timer isn't really elegant but at least it seems + * reliable. + * The current error (XDU, RFO) recovery code is untested. + * So far, RDO takes his RX channel down and the right sequence to enable it + * again is still a mistery. If RDO happens, plan a reboot. More details + * in the code (NB: as this happens, TX still works). + * Don't mess the cables during operation, especially on DTE ports. I don't + * suggest it for DCE either but at least one can get some messages instead + * of a complete instant freeze. + * Tests are done on Rev. 20 of the silicium. The RDO handling changes with + * the documentation/chipset releases. An on-line errata would be welcome. + * + * TODO: + * - some trivial error lurk, + * - the stats are fscked, + * - use polling at high irq/s, + * - performance analysis, + * - endianness. + * + */ + +#include <linux/version.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/ioport.h> +#include <linux/pci.h> +#include <linux/kernel.h> +#include <linux/mm.h> + +#include <asm/system.h> +#include <asm/cache.h> +#include <asm/byteorder.h> +#include <asm/uaccess.h> +#include <asm/io.h> +#include <asm/irq.h> + +#include <linux/init.h> +#include <linux/string.h> + +#include <linux/if_arp.h> +#include <linux/netdevice.h> +#include <linux/skbuff.h> +#include <linux/delay.h> +#include <net/syncppp.h> +#include <linux/hdlc.h> + +/* Version */ +static const char * version = "$Id: dscc4.c,v 1.130 2001/02/25 15:27:34 romieu Exp $\n"; +static int debug; + + +/* Module parameters */ +MODULE_AUTHOR("Maintainer: Francois Romieu <romieu@cogenit.fr>"); +MODULE_DESCRIPTION("Siemens PEB20534 PCI Controller"); +MODULE_PARM(debug,"i"); + +/* Structures */ +struct TxFD { + u32 state; + u32 next; + u32 data; + u32 complete; + u32 jiffies; /* more hack to come :o) */ +}; + +struct RxFD { + u32 state1; + u32 next; + u32 data; + u32 state2; + u32 end; +}; + +#define DEBUG +#define DEBUG_PARANOID +#define TX_RING_SIZE 32 +#define RX_RING_SIZE 32 +#define IRQ_RING_SIZE 64 /* Keep it A multiple of 32 */ +#define TX_TIMEOUT (HZ/10) +#define BRR_DIVIDER_MAX 64*0x00008000 +#define dev_per_card 4 + +#define SOURCE_ID(flags) ((flags >> 28 ) & 0x03) +#define TO_SIZE(state) ((state >> 16) & 0x1fff) +#define TO_STATE(len) cpu_to_le32((len & TxSizeMax) << 16) +#define RX_MAX(len) ((((len) >> 5) + 1) << 5) +#define SCC_REG_START(id) SCC_START+(id)*SCC_OFFSET + +#undef DEBUG + +struct dscc4_pci_priv { + u32 *iqcfg; + int cfg_cur; + spinlock_t lock; + struct pci_dev *pdev; + + struct net_device *root; + dma_addr_t iqcfg_dma; + u32 xtal_hz; +}; + +struct dscc4_dev_priv { + struct sk_buff *rx_skbuff[RX_RING_SIZE]; + struct sk_buff *tx_skbuff[TX_RING_SIZE]; + + struct RxFD *rx_fd; + struct TxFD *tx_fd; + u32 *iqrx; + u32 *iqtx; + + u32 rx_current; + u32 tx_current; + u32 iqrx_current; + u32 iqtx_current; + + u32 tx_dirty; + int bad_tx_frame; + int bad_rx_frame; + int rx_needs_refill; + + dma_addr_t tx_fd_dma; + dma_addr_t rx_fd_dma; + dma_addr_t iqtx_dma; + dma_addr_t iqrx_dma; + + struct net_device_stats stats; + struct timer_list timer; + + struct dscc4_pci_priv *pci_priv; + spinlock_t lock; + + int dev_id; + u32 flags; + u32 timer_help; + u32 hi_expected; + + struct hdlc_device_struct hdlc; + int usecount; +}; + +/* GLOBAL registers definitions */ +#define GCMDR 0x00 +#define GSTAR 0x04 +#define GMODE 0x08 +#define IQLENR0 0x0C +#define IQLENR1 0x10 +#define IQRX0 0x14 +#define IQTX0 0x24 +#define IQCFG 0x3c +#define FIFOCR1 0x44 +#define FIFOCR2 0x48 +#define FIFOCR3 0x4c +#define FIFOCR4 0x34 +#define CH0CFG 0x50 +#define CH0BRDA 0x54 +#define CH0BTDA 0x58 + +/* SCC registers definitions */ +#define SCC_START 0x0100 +#define SCC_OFFSET 0x80 +#define CMDR 0x00 +#define STAR 0x04 +#define CCR0 0x08 +#define CCR1 0x0c +#define CCR2 0x10 +#define BRR 0x2C +#define RLCR 0x40 +#define IMR 0x54 +#define ISR 0x58 + +/* Bit masks */ +#define IntRxScc0 0x10000000 +#define IntTxScc0 0x01000000 + +#define TxPollCmd 0x00000400 +#define RxActivate 0x08000000 +#define MTFi 0x04000000 +#define Rdr 0x00400000 +#define Rdt 0x00200000 +#define Idr 0x00100000 +#define Idt 0x00080000 +#define TxSccRes 0x01000000 +#define RxSccRes 0x00010000 +#define TxSizeMax 0x1ffc +#define RxSizeMax 0x1ffc + +#define Ccr0ClockMask 0x0000003f +#define Ccr1LoopMask 0x00000200 +#define BrrExpMask 0x00000f00 +#define BrrMultMask 0x0000003f +#define EncodingMask 0x00700000 +#define Hold 0x40000000 +#define SccBusy 0x10000000 +#define FrameOk (FrameVfr | FrameCrc) +#define FrameVfr 0x80 +#define FrameRdo 0x40 +#define FrameCrc 0x20 +#define FrameAborted 0x00000200 +#define FrameEnd 0x80000000 +#define DataComplete 0x40000000 +#define LengthCheck 0x00008000 +#define SccEvt 0x02000000 +#define NoAck 0x00000200 +#define Action 0x00000001 +#define HiDesc 0x20000000 + +/* SCC events */ +#define RxEvt 0xf0000000 +#define TxEvt 0x0f000000 +#define Alls 0x00040000 +#define Xdu 0x00010000 +#define Xmr 0x00002000 +#define Xpr 0x00001000 +#define Rdo 0x00000080 +#define Rfs 0x00000040 +#define Rfo 0x00000002 +#define Flex 0x00000001 + +/* DMA core events */ +#define Cfg 0x00200000 +#define Hi 0x00040000 +#define Fi 0x00020000 +#define Err 0x00010000 +#define Arf 0x00000002 +#define ArAck 0x00000001 + +/* Misc */ +#define NeedIDR 0x00000001 +#define NeedIDT 0x00000002 +#define RdoSet 0x00000004 + +/* Functions prototypes */ +static __inline__ void dscc4_rx_irq(struct dscc4_pci_priv *, struct net_device *); +static __inline__ void dscc4_tx_irq(struct dscc4_pci_priv *, struct net_device *); +static int dscc4_found1(struct pci_dev *, unsigned long ioaddr); +static int dscc4_init_one(struct pci_dev *, const struct pci_device_id *ent); +static int dscc4_open(struct net_device *); +static int dscc4_start_xmit(struct sk_buff *, struct net_device *); +static int dscc4_close(struct net_device *); +static int dscc4_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +static int dscc4_change_mtu(struct net_device *dev, int mtu); +static int dscc4_init_ring(struct net_device *); +static void dscc4_release_ring(struct dscc4_dev_priv *); +static void dscc4_timer(unsigned long); +static void dscc4_tx_timeout(struct net_device *); +static void dscc4_irq(int irq, void *dev_id, struct pt_regs *ptregs); +static struct net_device_stats *dscc4_get_stats(struct net_device *); +static int dscc4_attach_hdlc_device(struct net_device *); +static void dscc4_unattach_hdlc_device(struct net_device *); +static int dscc4_hdlc_open(struct hdlc_device_struct *); +static void dscc4_hdlc_close(struct hdlc_device_struct *); +static int dscc4_hdlc_ioctl(struct hdlc_device_struct *, struct ifreq *, int); +static int dscc4_hdlc_xmit(hdlc_device *, struct sk_buff *); +#ifdef EXPERIMENTAL_POLLING +static int dscc4_tx_poll(struct dscc4_dev_priv *, struct net_device *); +#endif + +void inline reset_TxFD(struct TxFD *tx_fd) { + /* FIXME: test with the last arg (size specification) = 0 */ + tx_fd->state = FrameEnd | Hold | 0x00100000; + tx_fd->complete = 0x00000000; +} + +void inline dscc4_release_ring_skbuff(struct sk_buff **p, int n) +{ + for(; n > 0; n--) { + if (*p) + dev_kfree_skb(*p); + p++; + } +} + +static void dscc4_release_ring(struct dscc4_dev_priv *dpriv) +{ + struct pci_dev *pdev = dpriv->pci_priv->pdev; + + pci_free_consistent(pdev, TX_RING_SIZE*sizeof(struct TxFD), + dpriv->tx_fd, dpriv->tx_fd_dma); + pci_free_consistent(pdev, RX_RING_SIZE*sizeof(struct RxFD), + dpriv->rx_fd, dpriv->rx_fd_dma); + dscc4_release_ring_skbuff(dpriv->tx_skbuff, TX_RING_SIZE); + dscc4_release_ring_skbuff(dpriv->rx_skbuff, RX_RING_SIZE); +} + +void inline try_get_rx_skb(struct dscc4_dev_priv *priv, int cur, struct net_device *dev) +{ + struct sk_buff *skb; + + skb = dev_alloc_skb(RX_MAX(dev->mtu+2)); + priv->rx_skbuff[cur] = skb; + if (!skb) { + priv->rx_fd[cur--].data = (u32) NULL; + priv->rx_fd[cur%RX_RING_SIZE].state1 |= Hold; + priv->rx_needs_refill++; + return; + } + skb->dev = dev; + skb->protocol = htons(ETH_P_IP); + skb->mac.raw = skb->data; + priv->rx_fd[cur].data = pci_map_single(priv->pci_priv->pdev, skb->data, + skb->len, PCI_DMA_FROMDEVICE); +} + +/* + * IRQ/thread/whatever safe + */ +static int dscc4_wait_ack_cec(u32 ioaddr, struct net_device *dev, char *msg) +{ + s16 i = 0; + + while (readl(ioaddr + STAR) & SccBusy) { + if (i++ < 0) { + printk(KERN_ERR "%s: %s timeout\n", dev->name, msg); + return -1; + } + } + printk(KERN_DEBUG "%s: %s ack (%d try)\n", dev->name, msg, i); + return 0; +} + +static int dscc4_do_action(struct net_device *dev, char *msg) +{ + unsigned long ioaddr = dev->base_addr; + u32 state; + s16 i; + + writel(Action, ioaddr + GCMDR); + ioaddr += GSTAR; + for (i = 0; i >= 0; i++) { + state = readl(ioaddr); + if (state & Arf) { + printk(KERN_ERR "%s: %s failed\n", dev->name, msg); + writel(Arf, ioaddr); + return -1; + } else if (state & ArAck) { + printk(KERN_DEBUG "%s: %s ack (%d try)\n", + dev->name, msg, i); + writel(ArAck, ioaddr); + return 0; + } + } + printk(KERN_ERR "%s: %s timeout\n", dev->name, msg); + return -1; +} + +static __inline__ int dscc4_xpr_ack(struct dscc4_dev_priv *dpriv) +{ + int cur; + s16 i; + + cur = dpriv->iqtx_current%IRQ_RING_SIZE; + for (i = 0; i >= 0; i++) { + if (!(dpriv->flags & (NeedIDR | NeedIDT)) || + (dpriv->iqtx[cur] & Xpr)) + return 0; + } + printk(KERN_ERR "%s: %s timeout\n", "dscc4", "XPR"); + return -1; +} + +static __inline__ void dscc4_rx_skb(struct dscc4_dev_priv *dpriv, int cur, + struct RxFD *rx_fd, struct net_device *dev) +{ + struct pci_dev *pdev = dpriv->pci_priv->pdev; + struct sk_buff *skb; + int pkt_len; + + skb = dpriv->rx_skbuff[cur]; + pkt_len = TO_SIZE(rx_fd->state2); + pci_dma_sync_single(pdev, rx_fd->data, pkt_len, PCI_DMA_FROMDEVICE); + if((skb->data[pkt_len - 1] & FrameOk) == FrameOk) { + pci_unmap_single(pdev, rx_fd->data, skb->len, PCI_DMA_FROMDEVICE); + dpriv->stats.rx_packets++; + dpriv->stats.rx_bytes += pkt_len; + skb->tail += pkt_len; + skb->len = pkt_len; + if (netif_running(hdlc_to_dev(&dpriv->hdlc))) + hdlc_netif_rx(&dpriv->hdlc, skb); + else + netif_rx(skb); + try_get_rx_skb(dpriv, cur, dev); + } else { + if(skb->data[pkt_len - 1] & FrameRdo) + dpriv->stats.rx_fifo_errors++; + else if(!(skb->data[pkt_len - 1] | ~FrameCrc)) + dpriv->stats.rx_crc_errors++; + else if(!(skb->data[pkt_len - 1] | ~FrameVfr)) + dpriv->stats.rx_length_errors++; + else + dpriv->stats.rx_errors++; + } + rx_fd->state1 |= Hold; + rx_fd->state2 = 0x00000000; + rx_fd->end = 0xbabeface; + if (!rx_fd->data) + return; + rx_fd--; + if (!cur) + rx_fd += RX_RING_SIZE; + rx_fd->state1 &= ~Hold; +} + +static int __init dscc4_init_one (struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct dscc4_pci_priv *priv; + struct dscc4_dev_priv *dpriv; + int i; + static int cards_found = 0; + unsigned long ioaddr; + + printk(KERN_DEBUG "%s", version); + + if (pci_enable_device(pdev)) + goto err_out; + if (!request_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0), "registers")) { + printk (KERN_ERR "dscc4: can't reserve MMIO region (regs)\n"); + goto err_out; + } + if (!request_mem_region(pci_resource_start(pdev, 1), + pci_resource_len(pdev, 1), "LBI interface")) { + printk (KERN_ERR "dscc4: can't reserve MMIO region (lbi)\n"); + goto err_out_free_mmio_region0; + } + ioaddr = (unsigned long)ioremap(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + if (!ioaddr) { + printk(KERN_ERR "dscc4: cannot remap MMIO region %lx @ %lx\n", + pci_resource_len(pdev, 0), pci_resource_start(pdev, 0)); + goto err_out_free_mmio_region; + } + printk(KERN_DEBUG "Siemens DSCC4, MMIO at %#lx (regs), %#lx (lbi), IRQ %d.\n", + pci_resource_start(pdev, 0), + pci_resource_start(pdev, 1), pdev->irq); + + /* High PCI latency useless. Cf app. note. */ + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x10); + pci_set_master(pdev); + + if (dscc4_found1(pdev, ioaddr)) + goto err_out_iounmap; + + priv = (struct dscc4_pci_priv *)pci_get_drvdata(pdev); + + if (request_irq(pdev->irq, &dscc4_irq, SA_SHIRQ, "dscc4", priv->root)) { + printk(KERN_WARNING "dscc4: IRQ %d is busy\n", pdev->irq); + goto err_out_iounmap; + } + priv->pdev = pdev; + + /* power up/little endian/dma core controlled via hold bit */ + writel(0x00000000, ioaddr + GMODE); + /* Shared interrupt queue */ + { + u32 bits; + + bits = (IRQ_RING_SIZE >> 5) - 1; + bits |= bits << 4; + bits |= bits << 8; + bits |= bits << 16; + writel(bits, ioaddr + IQLENR0); + } + /* Global interrupt queue */ + writel((u32)(((IRQ_RING_SIZE >> 5) - 1) << 20), ioaddr + IQLENR1); + priv->iqcfg = (u32 *) pci_alloc_consistent(pdev, + IRQ_RING_SIZE*sizeof(u32), &priv->iqcfg_dma); + if (!priv->iqcfg) + goto err_out_free_irq; + writel(priv->iqcfg_dma, ioaddr + IQCFG); + + /* + * SCC 0-3 private rx/tx irq structures + * IQRX/TXi needs to be set soon. Learned it the hard way... + */ + for(i = 0; i < dev_per_card; i++) { + dpriv = (struct dscc4_dev_priv *)(priv->root + i)->priv; + dpriv->iqtx = (u32 *) pci_alloc_consistent(pdev, + IRQ_RING_SIZE*sizeof(u32), &dpriv->iqtx_dma); + if (!dpriv->iqtx) + goto err_out_free_iqtx; + writel(dpriv->iqtx_dma, ioaddr + IQTX0 + i*4); + } + for(i = 0; i < dev_per_card; i++) { + dpriv = (struct dscc4_dev_priv *)(priv->root + i)->priv; + dpriv->iqrx = (u32 *) pci_alloc_consistent(pdev, + IRQ_RING_SIZE*sizeof(u32), &dpriv->iqrx_dma); + if (!dpriv->iqrx) + goto err_out_free_iqrx; + writel(dpriv->iqrx_dma, ioaddr + IQRX0 + i*4); + } + + /* + * Cf application hint. Beware of hard-lock condition on + * threshold . + */ + writel(0x42104000, ioaddr + FIFOCR1); + //writel(0x9ce69800, ioaddr + FIFOCR2); + writel(0xdef6d800, ioaddr + FIFOCR2); + //writel(0x11111111, ioaddr + FIFOCR4); + writel(0x18181818, ioaddr + FIFOCR4); + // FIXME: should depend on the chipset revision + writel(0x0000000e, ioaddr + FIFOCR3); + + writel(0xff200001, ioaddr + GCMDR); + + cards_found++; + return 0; + +err_out_free_iqrx: + while (--i >= 0) { + dpriv = (struct dscc4_dev_priv *)(priv->root + i)->priv; + pci_free_consistent(pdev, IRQ_RING_SIZE*sizeof(u32), + dpriv->iqrx, dpriv->iqrx_dma); + } + i = dev_per_card; +err_out_free_iqtx: + while (--i >= 0) { + dpriv = (struct dscc4_dev_priv *)(priv->root + i)->priv; + pci_free_consistent(pdev, IRQ_RING_SIZE*sizeof(u32), + dpriv->iqtx, dpriv->iqtx_dma); + } + pci_free_consistent(pdev, IRQ_RING_SIZE*sizeof(u32), priv->iqcfg, + priv->iqcfg_dma); +err_out_free_irq: + free_irq(pdev->irq, priv->root); +err_out_iounmap: + iounmap ((void *)ioaddr); +err_out_free_mmio_region: + release_mem_region(pci_resource_start(pdev, 1), + pci_resource_len(pdev, 1)); +err_out_free_mmio_region0: + release_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); +err_out: + return -ENODEV; +}; + +static int dscc4_found1(struct pci_dev *pdev, unsigned long ioaddr) +{ + struct dscc4_pci_priv *ppriv; + struct dscc4_dev_priv *dpriv; + struct net_device *dev; + int i = 0; + + dpriv = (struct dscc4_dev_priv *) + kmalloc(dev_per_card*sizeof(struct dscc4_dev_priv), GFP_KERNEL); + if (!dpriv) { + printk(KERN_ERR "dscc4: can't allocate data\n"); + goto err_out; + } + memset(dpriv, 0, dev_per_card*sizeof(struct dscc4_dev_priv)); + + dev = (struct net_device *) + kmalloc(dev_per_card*sizeof(struct net_device), GFP_KERNEL); + if (!dev) { + printk(KERN_ERR "dscc4: can't allocate net_device\n"); + goto err_dealloc_priv; + } + memset(dev, 0, dev_per_card*sizeof(struct net_device)); + + ppriv = (struct dscc4_pci_priv *) + kmalloc(sizeof(struct dscc4_pci_priv), GFP_KERNEL); + if (!ppriv) { + printk(KERN_ERR "dscc4: can't allocate pci private data.\n"); + goto err_dealloc_dev; + } + memset(ppriv, 0, sizeof(struct dscc4_pci_priv)); + + for (i = 0; i < dev_per_card; i++) { + struct dscc4_dev_priv *p; + struct net_device *d; + + d = dev + i; + d->base_addr = ioaddr; + d->init = NULL; + d->irq = pdev->irq; + /* The card adds the crc */ + d->type = ARPHRD_RAWHDLC; + d->open = dscc4_open; + d->stop = dscc4_close; + d->hard_start_xmit = dscc4_start_xmit; + d->set_multicast_list = NULL; + d->do_ioctl = dscc4_ioctl; + d->get_stats = dscc4_get_stats; + d->change_mtu = dscc4_change_mtu; + d->mtu = HDLC_MAX_MTU; + d->flags = IFF_MULTICAST|IFF_POINTOPOINT|IFF_NOARP; + d->tx_timeout = dscc4_tx_timeout; + d->watchdog_timeo = TX_TIMEOUT; + + p = dpriv + i; + p->dev_id = i; + p->pci_priv = ppriv; + spin_lock_init(&p->lock); + d->priv = p; + + if (dev_alloc_name(d, "scc%d")<0) { + printk(KERN_ERR "dev_alloc_name failed for scc.\n"); + goto err_dealloc_dev; + } + if (register_netdev(d)) { + printk(KERN_ERR "%s: register_netdev != 0.\n", d->name); + goto err_dealloc_dev; + } + dscc4_attach_hdlc_device(d); + SET_MODULE_OWNER(d); + } + ppriv->root = dev; + ppriv->pdev = pdev; + spin_lock_init(&ppriv->lock); + pdev->driver_data = ppriv; + pci_set_drvdata(pdev, ppriv); + return 0; + +err_dealloc_dev: + while (--i >= 0) + unregister_netdev(dev + i); + kfree(dev); +err_dealloc_priv: + kfree(dpriv); +err_out: + return -1; +}; + +static void dscc4_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct dscc4_dev_priv *dpriv; + struct dscc4_pci_priv *ppriv; + + dpriv = dev->priv; + if (netif_queue_stopped(dev) && + ((jiffies - dev->trans_start) > TX_TIMEOUT)) { + ppriv = dpriv->pci_priv; + if (dpriv->iqtx[dpriv->iqtx_current%IRQ_RING_SIZE]) { + u32 flags; + + printk(KERN_DEBUG "%s: pending events\n", dev->name); + dev->trans_start = jiffies; + spin_lock_irqsave(&ppriv->lock, flags); + dscc4_tx_irq(ppriv, dev); + spin_unlock_irqrestore(&ppriv->lock, flags); + } else { + struct TxFD *tx_fd; + struct sk_buff *skb; + int i,j; + + printk(KERN_DEBUG "%s: missing events\n", dev->name); + i = dpriv->tx_dirty%TX_RING_SIZE; + j = dpriv->tx_current - dpriv->tx_dirty; + dpriv->stats.tx_dropped += j; + while(j--) { + skb = dpriv->tx_skbuff[i]; + tx_fd = dpriv->tx_fd + i; + if (skb) { + dpriv->tx_skbuff[i] = NULL; + pci_unmap_single(ppriv->pdev, tx_fd->data, skb->len, + PCI_DMA_TODEVICE); + dev_kfree_skb_irq(skb); + } else + printk(KERN_INFO "%s: hardware on drugs!\n", dev->name); + tx_fd->data = 0; /* DEBUG */ + tx_fd->complete &= ~DataComplete; + i++; + i %= TX_RING_SIZE; + } + dpriv->tx_dirty = dpriv->tx_current; + dev->trans_start = jiffies; + netif_wake_queue(dev); + printk(KERN_DEBUG "%s: re-enabled\n", dev->name); + } + } + dpriv->timer.expires = jiffies + TX_TIMEOUT; + add_timer(&dpriv->timer); +} + +static void dscc4_tx_timeout(struct net_device *dev) +{ + /* FIXME: something is missing there */ +}; + +static int dscc4_open(struct net_device *dev) +{ + struct dscc4_dev_priv *dpriv = (struct dscc4_dev_priv *)dev->priv; + struct dscc4_pci_priv *ppriv; + u32 ioaddr = 0; + + MOD_INC_USE_COUNT; + + ppriv = dpriv->pci_priv; + + if (dscc4_init_ring(dev)) + goto err_out; + + ioaddr = dev->base_addr + SCC_REG_START(dpriv->dev_id); + + /* FIXME: VIS */ + writel(readl(ioaddr + CCR0) | 0x80001000, ioaddr + CCR0); + + writel(LengthCheck | (dev->mtu >> 5), ioaddr + RLCR); + + /* no address recognition/crc-CCITT/cts enabled */ + writel(readl(ioaddr + CCR1) | 0x021c8000, ioaddr + CCR1); + + /* Ccr2.Rac = 0 */ + writel(0x00050008 & ~RxActivate, ioaddr + CCR2); + +#ifdef EXPERIMENTAL_POLLING + writel(0xfffeef7f, ioaddr + IMR); /* Interrupt mask */ +#else + /* Don't mask RDO. Ever. */ + //writel(0xfffaef7f, ioaddr + IMR); /* Interrupt mask */ + writel(0xfffaef7e, ioaddr + IMR); /* Interrupt mask */ +#endif + /* IDT+IDR during XPR */ + dpriv->flags = NeedIDR | NeedIDT; + + /* + * The following is a bit paranoid... + * + * NB: the datasheet "...CEC will stay active if the SCC is in + * power-down mode or..." and CCR2.RAC = 1 are two different + * situations. + */ + if (readl(ioaddr + STAR) & SccBusy) { + printk(KERN_ERR "%s busy. Try later\n", dev->name); + goto err_free_ring; + } + writel(TxSccRes | RxSccRes, ioaddr + CMDR); + + /* ... the following isn't */ + if (dscc4_wait_ack_cec(ioaddr, dev, "Cec")) + goto err_free_ring; + + /* + * I would expect XPR near CE completion (before ? after ?). + * At worst, this code won't see a late XPR and people + * will have to re-issue an ifconfig (this is harmless). + * WARNING, a really missing XPR usually means a hardware + * reset is needed. Suggestions anyone ? + */ + if (dscc4_xpr_ack(dpriv)) + goto err_free_ring; + + netif_start_queue(dev); + + init_timer(&dpriv->timer); + dpriv->timer.expires = jiffies + 10*HZ; + dpriv->timer.data = (unsigned long)dev; + dpriv->timer.function = &dscc4_timer; + add_timer(&dpriv->timer); + netif_carrier_on(dev); + + return 0; + +err_free_ring: + dscc4_release_ring(dpriv); +err_out: + MOD_DEC_USE_COUNT; + return -EAGAIN; +} + +#ifdef EXPERIMENTAL_POLLING +static int dscc4_tx_poll(struct dscc4_dev_priv *dpriv, struct net_device *dev) +{ + /* FIXME: it's gonna be easy (TM), for sure */ +} +#endif /* EXPERIMENTAL_POLLING */ + +static int dscc4_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct dscc4_dev_priv *dpriv = dev->priv; + struct dscc4_pci_priv *ppriv; + struct TxFD *tx_fd; + int cur, next; + + ppriv = dpriv->pci_priv; + cur = dpriv->tx_current++%TX_RING_SIZE; + next = dpriv->tx_current%TX_RING_SIZE; + dpriv->tx_skbuff[next] = skb; + tx_fd = dpriv->tx_fd + next; + tx_fd->state = FrameEnd | Hold | TO_STATE(skb->len & TxSizeMax); + tx_fd->data = pci_map_single(ppriv->pdev, skb->data, skb->len, + PCI_DMA_TODEVICE); + tx_fd->complete = 0x00000000; + mb(); // FIXME: suppress ? + +#ifdef EXPERIMENTAL_POLLING + spin_lock(&dpriv->lock); + while(dscc4_tx_poll(dpriv, dev)); + spin_unlock(&dpriv->lock); +#endif + /* + * I know there's a window for a race in the following lines but + * dscc4_timer will take good care of it. The chipset eats events + * (especially the net_dev re-enabling ones) thus there is no + * reason to try and be smart. + */ + if ((dpriv->tx_dirty + 16) < dpriv->tx_current) { + netif_stop_queue(dev); + dpriv->hi_expected = 2; + } + tx_fd = dpriv->tx_fd + cur; + tx_fd->state &= ~Hold; + mb(); // FIXME: suppress ? + + /* + * One may avoid some pci transactions during intense TX periods. + * Not sure it's worth the pain... + */ + writel((TxPollCmd << dpriv->dev_id) | NoAck, dev->base_addr + GCMDR); + dev->trans_start = jiffies; + return 0; +} + +static int dscc4_close(struct net_device *dev) +{ + struct dscc4_dev_priv *dpriv = (struct dscc4_dev_priv *)dev->priv; + u32 ioaddr = dev->base_addr; + int dev_id; + + del_timer_sync(&dpriv->timer); + netif_stop_queue(dev); + + dev_id = dpriv->dev_id; + + writel(0x00050000, ioaddr + SCC_REG_START(dev_id) + CCR2); + writel(MTFi|Rdr|Rdt, ioaddr + CH0CFG + dev_id*0x0c); /* Reset Rx/Tx */ + writel(0x00000001, ioaddr + GCMDR); + + dscc4_release_ring(dpriv); + + MOD_DEC_USE_COUNT; + return 0; +} + +static int dscc4_set_clock(struct net_device *dev, u32 *bps, u32 *state) +{ + struct dscc4_dev_priv *dpriv = (struct dscc4_dev_priv *)dev->priv; + u32 brr; + + *state &= ~Ccr0ClockMask; + if (*bps) { /* DCE */ + u32 n = 0, m = 0, divider; + int xtal; + + xtal = dpriv->pci_priv->xtal_hz; + if (!xtal) + return -1; + divider = xtal / *bps; + if (divider > BRR_DIVIDER_MAX) { + divider >>= 4; + *state |= 0x00000036; /* Clock mode 6b (BRG/16) */ + } else + *state |= 0x00000037; /* Clock mode 7b (BRG) */ + if (divider >> 22) { + n = 63; + m = 15; + } else if (divider) { + /* Extraction of the 6 highest weighted bits */ + m = 0; + while (0xffffffc0 & divider) { + m++; + divider >>= 1; + } + n = divider; + } + brr = (m << 8) | n; + divider = n << m; + if (!(*state & 0x00000001)) /* Clock mode 6b */ + divider <<= 4; + *bps = xtal / divider; + } else { /* DTE */ + /* + * "state" already reflects Clock mode 0a. + * Nothing more to be done + */ + brr = 0; + } + writel(brr, dev->base_addr + BRR + SCC_REG_START(dpriv->dev_id)); + + return 0; +} + +#ifdef LATER_PLEASE +/* + * -*- [RFC] Configuring Synchronous Interfaces in Linux -*- + */ + +// FIXME: MEDIA already defined in linux/hdlc.h +#define HDLC_MEDIA_V35 0 +#define HDLC_MEDIA_RS232 1 +#define HDLC_MEDIA_X21 2 +#define HDLC_MEDIA_E1 3 +#define HDLC_MEDIA_HSSI 4 + +#define HDLC_CODING_NRZ 0 +#define HDLC_CODING_NRZI 1 +#define HDLC_CODING_FM0 2 +#define HDLC_CODING_FM1 3 +#define HDLC_CODING_MANCHESTER 4 + +#define HDLC_CRC_NONE 0 +#define HDLC_CRC_16 1 +#define HDLC_CRC_32 2 +#define HDLC_CRC_CCITT 3 + +/* RFC: add the crc reset value ? */ +struct hdlc_physical { + u8 media; + u8 coding; + u32 rate; + u8 crc; + u8 crc_siz; /* 2 or 4 bytes */ + u8 shared_flags; /* Discouraged on the DSCC4 */ +}; + +// FIXME: PROTO already defined in linux/hdlc.h +#define HDLC_PROTO_RAW 0 +#define HDLC_PROTO_FR 1 +#define HDLC_PROTO_X25 2 +#define HDLC_PROTO_PPP 3 +#define HDLC_PROTO_CHDLC 4 + +struct hdlc_protocol { + u8 proto; + + union { + } u; +}; + +struct screq { + u16 media_group; + + union { + struct hdlc_physical hdlc_phy; + struct hdlc_protocol hdlc_proto; + } u; +}; + +// FIXME: go sub-module +static struct { + u16 coding; + u16 bits; +} map[] = { + {HDLC_CODING_NRZ, 0x00}, + {HDLC_CODING_NRZI, 0x20}, + {HDLC_CODING_FM0, 0x40}, + {HDLC_CODING_FM1, 0x50}, + {HDLC_CODING_MANCHESTER, 0x60}, + {65535, 0x00} +}; +#endif /* LATER_PLEASE */ + +static int dscc4_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + struct dscc4_dev_priv *dpriv = dev->priv; + u32 state, ioaddr; + + if (dev->flags & IFF_UP) + return -EBUSY; + + switch (cmd) { + /* Set built-in quartz frequency */ + case SIOCDEVPRIVATE: { + u32 hz; + + hz = ifr->ifr_ifru.ifru_ivalue; + if (hz >= 33000000) /* 33 MHz */ + return -EOPNOTSUPP; + dpriv->pci_priv->xtal_hz = hz; + return 0; + } + /* Set/unset loopback */ + case SIOCDEVPRIVATE+1: { + u32 flags; + + ioaddr = dev->base_addr + CCR1 + + SCC_REG_START(dpriv->dev_id); + state = readl(ioaddr); + flags = ifr->ifr_ifru.ifru_ivalue; + if (flags & 0x00000001) { + printk(KERN_DEBUG "%s: loopback\n", dev->name); + state |= 0x00000100; + } else { + printk(KERN_DEBUG "%s: normal\n", dev->name); + state &= ~0x00000100; + } + writel(state, ioaddr); + return 0; + } + +#ifdef LATER_PLEASE + case SIOCDEVPRIVATE+2: { + { + struct screq scr; + + err = copy_from_user(&scr, ifr->ifr_ifru.ifru_data, sizeof(struct screq)); + if (err) + return err; + do { + if (scr.u.hdlc_phy.coding == map[i].coding) + break; + } while (map[++i].coding != 65535); + if (!map[i].coding) + return -EOPNOTSUPP; + + ioaddr = dev->base_addr + CCR0 + + SCC_REG_START(dpriv->dev_id); + state = readl(ioaddr) & ~EncodingMask; + state |= (u32)map[i].bits << 16; + writel(state, ioaddr); + printk("state: %08x\n", state); /* DEBUG */ + return 0; + } + case SIOCDEVPRIVATE+3: { + struct screq *scr = (struct screq *)ifr->ifr_ifru.ifru_data; + + ioaddr = dev->base_addr + CCR0 + + SCC_REG_START(dpriv->dev_id); + state = (readl(ioaddr) & EncodingMask) >> 16; + do { + if (state == map[i].bits) + break; + } while (map[++i].coding); + return put_user(map[i].coding, (u16 *)scr->u.hdlc_phy.coding); + } +#endif /* LATER_PLEASE */ + + case HDLCSCLOCKRATE: + { + u32 state, bps; + + bps = ifr->ifr_ifru.ifru_ivalue; + ioaddr = dev->base_addr + CCR0 + + SCC_REG_START(dpriv->dev_id); + state = readl(ioaddr); + if(dscc4_set_clock(dev, &bps, &state) < 0) + return -EOPNOTSUPP; + if (bps) { /* DCE */ + printk(KERN_DEBUG "%s: generated RxClk (DCE)\n", + dev->name); + ifr->ifr_ifru.ifru_ivalue = bps; + } else { /* DTE */ + state = 0x80001000; + printk(KERN_DEBUG "%s: external RxClk (DTE)\n", + dev->name); + } + writel(state, ioaddr); + return 0; + } + case HDLCGCLOCKRATE: { + u32 brr; + int bps; + + brr = readl(dev->base_addr + BRR + + SCC_REG_START(dpriv->dev_id)); + bps = dpriv->pci_priv->xtal_hz >> (brr >> 8); + bps /= (brr & 0x3f) + 1; + ifr->ifr_ifru.ifru_ivalue = bps; + return 0; + } + + default: + return -EOPNOTSUPP; + } +} + +static int dscc4_change_mtu(struct net_device *dev, int mtu) +{ + /* FIXME: chainsaw coded... */ + if ((mtu <= 3) || (mtu > 65531)) + return -EINVAL; + if(dev->flags & IFF_UP) + return -EBUSY; + dev->mtu = mtu; + return(0); +} + +static void dscc4_irq(int irq, void *dev_instance, struct pt_regs *ptregs) +{ + struct net_device *dev = dev_instance; + struct dscc4_pci_priv *priv; + u32 ioaddr, state; + unsigned long flags; + int i; + + priv = ((struct dscc4_dev_priv *)dev->priv)->pci_priv; + /* + * FIXME: shorten the protected area (set some bit telling we're + * in an interrupt or increment some work-to-do counter etc...) + */ + spin_lock_irqsave(&priv->lock, flags); + + ioaddr = dev->base_addr; + + state = readl(ioaddr + GSTAR); + if (!state) + goto out; + writel(state, ioaddr + GSTAR); + + if (state & Arf) { + printk(KERN_ERR "%s: failure (Arf). Harass the maintener\n", + dev->name); + goto out; + } + state &= ~ArAck; + if (state & Cfg) { + if (debug) + printk(KERN_DEBUG "CfgIV\n"); + if (priv->iqcfg[priv->cfg_cur++%IRQ_RING_SIZE] & Arf) + printk(KERN_ERR "%s: %s failed\n", dev->name, "CFG"); + if (!(state &= ~Cfg)) + goto out; + } + if (state & RxEvt) { + i = dev_per_card - 1; + do { + dscc4_rx_irq(priv, dev + i); + } while (--i >= 0); + state &= ~RxEvt; + } + if (state & TxEvt) { + i = dev_per_card - 1; + do { + dscc4_tx_irq(priv, dev + i); + } while (--i >= 0); + state &= ~TxEvt; + } +out: + spin_unlock_irqrestore(&priv->lock, flags); +} + +static __inline__ void dscc4_tx_irq(struct dscc4_pci_priv *ppriv, + struct net_device *dev) +{ + struct dscc4_dev_priv *dpriv = dev->priv; + u32 state; + int cur, loop = 0; + +try: + cur = dpriv->iqtx_current%IRQ_RING_SIZE; + state = dpriv->iqtx[cur]; + if (!state) { +#ifdef DEBUG + if (loop > 1) + printk(KERN_DEBUG "%s: Tx irq loop=%d\n", dev->name, loop); +#endif + if (loop && netif_queue_stopped(dev)) + if ((dpriv->tx_dirty + 8) >= dpriv->tx_current) + netif_wake_queue(dev); + return; + } + loop++; + dpriv->iqtx[cur] = 0; + dpriv->iqtx_current++; + +#ifdef DEBUG_PARANOID + if (SOURCE_ID(state) != dpriv->dev_id) { + printk(KERN_DEBUG "%s (Tx): Source Id=%d, state=%08x\n", + dev->name, SOURCE_ID(state), state ); + return; + } + if (state & 0x0df80c01) { + printk(KERN_DEBUG "%s (Tx): state=%08x (UFO alert)\n", + dev->name, state); + return; + } +#endif + // state &= 0x0fffffff; /* Tracking the analyzed bits */ + if (state & SccEvt) { + if (state & Alls) { + struct TxFD *tx_fd; + struct sk_buff *skb; + + cur = dpriv->tx_dirty%TX_RING_SIZE; + tx_fd = dpriv->tx_fd + cur; + + skb = dpriv->tx_skbuff[cur]; + + /* XXX: hideous kludge - to be removed "later" */ + if (!skb) { + printk(KERN_ERR "%s: NULL skb in tx_irq at index %d\n", dev->name, cur); + goto try; + } + dpriv->tx_dirty++; // MUST be after skb test + + /* Happens sometime. Don't know what triggers it */ + if (!(tx_fd->complete & DataComplete)) { + u32 ioaddr, isr; + + ioaddr = dev->base_addr + + SCC_REG_START(dpriv->dev_id) + ISR; + isr = readl(ioaddr); + printk(KERN_DEBUG + "%s: DataComplete=0 cur=%d isr=%08x state=%08x\n", + dev->name, cur, isr, state); + writel(isr, ioaddr); + dpriv->stats.tx_dropped++; + } else { + tx_fd->complete &= ~DataComplete; + if (tx_fd->state & FrameEnd) { + dpriv->stats.tx_packets++; + dpriv->stats.tx_bytes += skb->len; + } + } + + dpriv->tx_skbuff[cur] = NULL; + pci_unmap_single(ppriv->pdev, tx_fd->data, skb->len, + PCI_DMA_TODEVICE); + tx_fd->data = 0; /* DEBUG */ + dev_kfree_skb_irq(skb); +{ // DEBUG + cur = (dpriv->tx_dirty-1)%TX_RING_SIZE; + tx_fd = dpriv->tx_fd + cur; + tx_fd->state |= Hold; +} + if (!(state &= ~Alls)) + goto try; + } + /* + * Transmit Data Underrun + */ + if (state & Xdu) { + printk(KERN_ERR "dscc4: XDU. Contact maintainer\n"); + dpriv->flags = NeedIDT; + /* Tx reset */ + writel(MTFi | Rdt, + dev->base_addr + 0x0c*dpriv->dev_id + CH0CFG); + writel(0x00000001, dev->base_addr + GCMDR); + return; + } + if (state & Xmr) { + /* Frame needs to be sent again - FIXME */ + //dscc4_start_xmit(dpriv->tx_skbuff[dpriv->tx_dirty], dev); + if (!(state &= ~0x00002000)) /* DEBUG */ + goto try; + } + if (state & Xpr) { + unsigned long ioaddr = dev->base_addr; + unsigned long scc_offset; + u32 scc_addr; + + scc_offset = ioaddr + SCC_REG_START(dpriv->dev_id); + scc_addr = ioaddr + 0x0c*dpriv->dev_id; + if (readl(scc_offset + STAR) & SccBusy) + printk(KERN_DEBUG "%s busy. Fatal\n", + dev->name); + /* + * Keep this order: IDT before IDR + */ + if (dpriv->flags & NeedIDT) { + writel(MTFi | Idt, scc_addr + CH0CFG); + writel(dpriv->tx_fd_dma + + (dpriv->tx_dirty%TX_RING_SIZE)* + sizeof(struct TxFD), scc_addr + CH0BTDA); + if(dscc4_do_action(dev, "IDT")) + goto err_xpr; + dpriv->flags &= ~NeedIDT; + mb(); + } + if (dpriv->flags & NeedIDR) { + writel(MTFi | Idr, scc_addr + CH0CFG); + writel(dpriv->rx_fd_dma + + (dpriv->rx_current%RX_RING_SIZE)* + sizeof(struct RxFD), scc_addr + CH0BRDA); + if(dscc4_do_action(dev, "IDR")) + goto err_xpr; + dpriv->flags &= ~NeedIDR; + mb(); + /* Activate receiver and misc */ + writel(0x08050008, scc_offset + CCR2); + } + err_xpr: + if (!(state &= ~Xpr)) + goto try; + } + } else { /* ! SccEvt */ + if (state & Hi) { +#ifdef EXPERIMENTAL_POLLING + while(!dscc4_tx_poll(dpriv, dev)); +#endif + state &= ~Hi; + } + /* + * FIXME: it may be avoided. Re-re-re-read the manual. + */ + if (state & Err) { + printk(KERN_ERR "%s: Tx ERR\n", dev->name); + dpriv->stats.tx_errors++; + state &= ~Err; + } + } + goto try; +} + +static __inline__ void dscc4_rx_irq(struct dscc4_pci_priv *priv, struct net_device *dev) +{ + struct dscc4_dev_priv *dpriv = dev->priv; + u32 state; + int cur; + +try: + cur = dpriv->iqrx_current%IRQ_RING_SIZE; + state = dpriv->iqrx[cur]; + if (!state) + return; + dpriv->iqrx[cur] = 0; + dpriv->iqrx_current++; + +#ifdef DEBUG_PARANOID + if (SOURCE_ID(state) != dpriv->dev_id) { + printk(KERN_DEBUG "%s (Rx): Source Id=%d, state=%08x\n", + dev->name, SOURCE_ID(state), state); + goto try; + } + if (state & 0x0df80c01) { + printk(KERN_DEBUG "%s (Rx): state=%08x (UFO alert)\n", + dev->name, state); + goto try; + } +#endif + if (!(state & SccEvt)){ + struct RxFD *rx_fd; + + state &= 0x00ffffff; + if (state & Err) { /* Hold or reset */ + printk(KERN_DEBUG "%s (Rx): ERR\n", dev->name); + cur = dpriv->rx_current; + rx_fd = dpriv->rx_fd + cur; + /* + * Presume we're not facing a DMAC receiver reset. + * As We use the rx size-filtering feature of the + * DSCC4, the beginning of a new frame is waiting in + * the rx fifo. I bet a Receive Data Overflow will + * happen most of time but let's try and avoid it. + * Btw (as for RDO) if one experiences ERR whereas + * the system looks rather idle, there may be a + * problem with latency. In this case, increasing + * RX_RING_SIZE may help. + */ + while (dpriv->rx_needs_refill) { + while(!(rx_fd->state1 & Hold)) { + rx_fd++; + cur++; + if (!(cur = cur%RX_RING_SIZE)) + rx_fd = dpriv->rx_fd; + } + dpriv->rx_needs_refill--; + try_get_rx_skb(dpriv, cur, dev); + if (!rx_fd->data) + goto try; + rx_fd->state1 &= ~Hold; + rx_fd->state2 = 0x00000000; + rx_fd->end = 0xbabeface; + } + goto try; + } + if (state & Fi) { + cur = dpriv->rx_current%RX_RING_SIZE; + rx_fd = dpriv->rx_fd + cur; + dscc4_rx_skb(dpriv, cur, rx_fd, dev); + dpriv->rx_current++; + goto try; + } + if (state & Hi ) { /* HI bit */ + state &= ~Hi; + goto try; + } + } else { /* ! SccEvt */ +#ifdef DEBUG_PARANOIA + int i; + static struct { + u32 mask; + const char *irq_name; + } evts[] = { + { 0x00008000, "TIN"}, + { 0x00004000, "CSC"}, + { 0x00000020, "RSC"}, + { 0x00000010, "PCE"}, + { 0x00000008, "PLLA"}, + { 0x00000004, "CDSC"}, + { 0, NULL} + }; +#endif /* DEBUG_PARANOIA */ + state &= 0x00ffffff; +#ifdef DEBUG_PARANOIA + for (i = 0; evts[i].irq_name; i++) { + if (state & evts[i].mask) { + printk(KERN_DEBUG "dscc4(%s): %s\n", + dev->name, evts[i].irq_name); + if (!(state &= ~evts[i].mask)) + goto try; + } + } +#endif /* DEBUG_PARANOIA */ + /* + * Receive Data Overflow (FIXME: untested) + */ + if (state & Rdo) { + u32 ioaddr, scc_offset, scc_addr; + struct RxFD *rx_fd; + int cur; + + //if (debug) + // dscc4_rx_dump(dpriv); + ioaddr = dev->base_addr; + scc_addr = ioaddr + 0x0c*dpriv->dev_id; + scc_offset = ioaddr + SCC_REG_START(dpriv->dev_id); + + writel(readl(scc_offset + CCR2) & ~RxActivate, + scc_offset + CCR2); + /* + * This has no effect. Why ? + * ORed with TxSccRes, one sees the CFG ack (for + * the TX part only). + */ + writel(RxSccRes, scc_offset + CMDR); + dpriv->flags |= RdoSet; + + /* + * Let's try and save something in the received data. + * rx_current must be incremented at least once to + * avoid HOLD in the BRDA-to-be-pointed desc. + */ + do { + cur = dpriv->rx_current++%RX_RING_SIZE; + rx_fd = dpriv->rx_fd + cur; + if (!(rx_fd->state2 & DataComplete)) + break; + if (rx_fd->state2 & FrameAborted) { + dpriv->stats.rx_over_errors++; + rx_fd->state1 |= Hold; + rx_fd->state2 = 0x00000000; + rx_fd->end = 0xbabeface; + } else + dscc4_rx_skb(dpriv, cur, rx_fd, dev); + } while (1); + + if (debug) { + if (dpriv->flags & RdoSet) + printk(KERN_DEBUG + "dscc4: no RDO in Rx data\n"); + } +#ifdef DSCC4_RDO_EXPERIMENTAL_RECOVERY + /* + * FIXME: must the reset be this violent ? + */ + writel(dpriv->rx_fd_dma + + (dpriv->rx_current%RX_RING_SIZE)* + sizeof(struct RxFD), scc_addr + CH0BRDA); + writel(MTFi|Rdr|Idr, scc_addr + CH0CFG); + if(dscc4_do_action(dev, "RDR")) { + printk(KERN_ERR "%s: RDO recovery failed(%s)\n", + dev->name, "RDR"); + goto rdo_end; + } + writel(MTFi|Idr, scc_addr + CH0CFG); + if(dscc4_do_action(dev, "IDR")) { + printk(KERN_ERR "%s: RDO recovery failed(%s)\n", + dev->name, "IDR"); + goto rdo_end; + } + rdo_end: +#endif + writel(readl(scc_offset + CCR2) | RxActivate, + scc_offset + CCR2); + goto try; + } + /* These will be used later */ + if (state & Rfs) { + if (!(state &= ~Rfs)) + goto try; + } + if (state & Rfo) { + if (!(state &= ~Rfo)) + goto try; + } + if (state & Flex) { + if (!(state &= ~Flex)) + goto try; + } + } +} + +static int dscc4_init_ring(struct net_device *dev) +{ + struct dscc4_dev_priv *dpriv = (struct dscc4_dev_priv *)dev->priv; + struct TxFD *tx_fd; + struct RxFD *rx_fd; + int i; + + tx_fd = (struct TxFD *) pci_alloc_consistent(dpriv->pci_priv->pdev, + TX_RING_SIZE*sizeof(struct TxFD), &dpriv->tx_fd_dma); + if (!tx_fd) + goto err_out; + rx_fd = (struct RxFD *) pci_alloc_consistent(dpriv->pci_priv->pdev, + RX_RING_SIZE*sizeof(struct RxFD), &dpriv->rx_fd_dma); + if (!rx_fd) + goto err_free_dma_tx; + + dpriv->tx_fd = tx_fd; + dpriv->rx_fd = rx_fd; + dpriv->rx_current = 0; + dpriv->tx_current = 0; + dpriv->tx_dirty = 0; + + /* the dma core of the dscc4 will be locked on the first desc */ + for(i = 0; i < TX_RING_SIZE; ) { + reset_TxFD(tx_fd); + /* FIXME: NULL should be ok - to be tried */ + tx_fd->data = dpriv->tx_fd_dma; + dpriv->tx_skbuff[i] = NULL; + i++; + tx_fd->next = (u32)(dpriv->tx_fd_dma + i*sizeof(struct TxFD)); + tx_fd++; + } + (--tx_fd)->next = (u32)dpriv->tx_fd_dma; +{ + /* + * XXX: I would expect the following to work for the first descriptor + * (tx_fd->state = 0xc0000000) + * - Hold=1 (don't try and branch to the next descripto); + * - No=0 (I want an empty data section, i.e. size=0); + * - Fe=1 (required by No=0 or we got an Err irq and must reset). + * Alas, it fails (and locks solid). Thus the introduction of a dummy + * skb to avoid No=0 (choose one: Ugly [ ] Tasteless [ ] VMS [ ]). + * TODO: fiddle the tx threshold when time permits. + */ + struct sk_buff *skb; + + skb = dev_alloc_skb(32); + if (!skb) + goto err_free_dma_tx; + skb->len = 32; + memset(skb->data, 0xaa, 16); + tx_fd -= (TX_RING_SIZE - 1); + tx_fd->state = 0xc0000000; + tx_fd->state |= ((u32)(skb->len & TxSizeMax)) << 16; + tx_fd->data = pci_map_single(dpriv->pci_priv->pdev, skb->data, + skb->len, PCI_DMA_TODEVICE); + dpriv->tx_skbuff[0] = skb; +} + for (i = 0; i < RX_RING_SIZE;) { + /* size set by the host. Multiple of 4 bytes please */ + rx_fd->state1 = HiDesc; /* Hi, no Hold */ + rx_fd->state2 = 0x00000000; + rx_fd->end = 0xbabeface; + rx_fd->state1 |= ((u32)(dev->mtu & RxSizeMax)) << 16; + try_get_rx_skb(dpriv, i, dev); + i++; + rx_fd->next = (u32)(dpriv->rx_fd_dma + i*sizeof(struct RxFD)); + rx_fd++; + } + (--rx_fd)->next = (u32)dpriv->rx_fd_dma; + rx_fd->state1 |= 0x40000000; /* Hold */ + + return 0; + +err_free_dma_tx: + pci_free_consistent(dpriv->pci_priv->pdev, TX_RING_SIZE*sizeof(*tx_fd), + tx_fd, dpriv->tx_fd_dma); +err_out: + return -1; +} + +static struct net_device_stats *dscc4_get_stats(struct net_device *dev) +{ + struct dscc4_dev_priv *priv = (struct dscc4_dev_priv *)dev->priv; + + return &priv->stats; +} + +static void __exit dscc4_remove_one(struct pci_dev *pdev) +{ + struct dscc4_pci_priv *ppriv; + struct net_device *root; + int i; + + ppriv = pci_get_drvdata(pdev); + root = ppriv->root; + + free_irq(pdev->irq, root); + pci_free_consistent(pdev, IRQ_RING_SIZE*sizeof(u32), ppriv->iqcfg, + ppriv->iqcfg_dma); + for (i=0; i < dev_per_card; i++) { + struct dscc4_dev_priv *dpriv; + struct net_device *dev; + + dev = ppriv->root + i; + dscc4_unattach_hdlc_device(dev); + + dpriv = (struct dscc4_dev_priv *)dev->priv; + pci_free_consistent(pdev, IRQ_RING_SIZE*sizeof(u32), + dpriv->iqrx, dpriv->iqrx_dma); + pci_free_consistent(pdev, IRQ_RING_SIZE*sizeof(u32), + dpriv->iqtx, dpriv->iqtx_dma); + unregister_netdev(dev); + } + kfree(root->priv); + + iounmap((void *)root->base_addr); + kfree(root); + + kfree(ppriv); + + release_mem_region(pci_resource_start(pdev, 1), + pci_resource_len(pdev, 1)); + release_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); +} + +static int dscc4_hdlc_ioctl(struct hdlc_device_struct *hdlc, struct ifreq *ifr, int cmd) +{ + struct net_device *dev = (struct net_device *)hdlc->netdev.base_addr; + int result; + + /* FIXME: locking ? */ + result = dscc4_ioctl(dev, ifr, cmd); + return result; +} + +static int dscc4_hdlc_open(struct hdlc_device_struct *hdlc) +{ + struct net_device *dev = (struct net_device *)(hdlc->netdev.base_addr); + + if (netif_running(dev)) { + printk(KERN_DEBUG "%s: already running\n", dev->name); // DEBUG + return 0; + } + return dscc4_open(dev); +} + +static int dscc4_hdlc_xmit(hdlc_device *hdlc, struct sk_buff *skb) +{ + struct net_device *dev = (struct net_device *)hdlc->netdev.base_addr; + + return dscc4_start_xmit(skb, dev); +} + +static void dscc4_hdlc_close(struct hdlc_device_struct *hdlc) +{ + struct net_device *dev = (struct net_device *)hdlc->netdev.base_addr; + struct dscc4_dev_priv *dpriv; + + dpriv = dev->priv; + --dpriv->usecount; +} + +/* Operated under dev lock */ +static int dscc4_attach_hdlc_device(struct net_device *dev) +{ + struct dscc4_dev_priv *dpriv = dev->priv; + struct hdlc_device_struct *hdlc; + int result; + + hdlc = &dpriv->hdlc; + /* XXX: Don't look at the next line */ + hdlc->netdev.base_addr = (unsigned long)dev; + // FIXME: set hdlc->set_mode ? + hdlc->open = dscc4_hdlc_open; + hdlc->close = dscc4_hdlc_close; + hdlc->ioctl = dscc4_hdlc_ioctl; + hdlc->xmit = dscc4_hdlc_xmit; + + result = register_hdlc_device(hdlc); + if (!result) + dpriv->usecount++; + return result; +} + +/* Operated under dev lock */ +static void dscc4_unattach_hdlc_device(struct net_device *dev) +{ + struct dscc4_dev_priv *dpriv = dev->priv; + + unregister_hdlc_device(&dpriv->hdlc); + dpriv->usecount--; +} + +static struct pci_device_id dscc4_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_SIEMENS, PCI_DEVICE_ID_SIEMENS_DSCC4, + PCI_ANY_ID, PCI_ANY_ID, }, + { 0,} +}; +MODULE_DEVICE_TABLE(pci, dscc4_pci_tbl); + +static struct pci_driver dscc4_driver = { + name: "dscc4", + id_table: dscc4_pci_tbl, + probe: dscc4_init_one, + remove: dscc4_remove_one, +}; + +static int __init dscc4_init_module(void) +{ + return pci_module_init(&dscc4_driver); +} + +static void __exit dscc4_cleanup_module(void) +{ + pci_unregister_driver(&dscc4_driver); +} + +module_init(dscc4_init_module); +module_exit(dscc4_cleanup_module); diff --git a/drivers/net/wan/hd64570.h b/drivers/net/wan/hd64570.h new file mode 100644 index 000000000..9d22122da --- /dev/null +++ b/drivers/net/wan/hd64570.h @@ -0,0 +1,234 @@ +#ifndef __HD64570_H +#define __HD64570_H + +/* SCA HD64570 register definitions - all addresses for mode 0 (8086 MPU) + and 1 (64180 MPU). For modes 2 and 3, XOR the address with 0x01. + + Source: HD64570 SCA User's Manual +*/ + + + +/* SCA Control Registers */ +#define LPR 0x00 /* Low Power */ + +/* Wait controller registers */ +#define PABR0 0x02 /* Physical Address Boundary 0 */ +#define PABR1 0x03 /* Physical Address Boundary 1 */ +#define WCRL 0x04 /* Wait Control L */ +#define WCRM 0x05 /* Wait Control M */ +#define WCRH 0x06 /* Wait Control H */ + +#define PCR 0x08 /* DMA Priority Control */ +#define DMER 0x09 /* DMA Master Enable */ + + +/* Interrupt registers */ +#define ISR0 0x10 /* Interrupt Status 0 */ +#define ISR1 0x11 /* Interrupt Status 1 */ +#define ISR2 0x12 /* Interrupt Status 2 */ + +#define IER0 0x14 /* Interrupt Enable 0 */ +#define IER1 0x15 /* Interrupt Enable 1 */ +#define IER2 0x16 /* Interrupt Enable 2 */ + +#define ITCR 0x18 /* Interrupt Control */ +#define IVR 0x1A /* Interrupt Vector */ +#define IMVR 0x1C /* Interrupt Modified Vector */ + + + +/* MSCI channel (port) 0 registers - offset 0x20 + MSCI channel (port) 1 registers - offset 0x40 */ + +#define MSCI0_OFFSET 0x20 +#define MSCI1_OFFSET 0x40 + +#define TRBL 0x00 /* TX/RX buffer L */ +#define TRBH 0x01 /* TX/RX buffer H */ +#define ST0 0x02 /* Status 0 */ +#define ST1 0x03 /* Status 1 */ +#define ST2 0x04 /* Status 2 */ +#define ST3 0x05 /* Status 3 */ +#define FST 0x06 /* Frame Status */ +#define IE0 0x08 /* Interrupt Enable 0 */ +#define IE1 0x09 /* Interrupt Enable 1 */ +#define IE2 0x0A /* Interrupt Enable 2 */ +#define FIE 0x0B /* Frame Interrupt Enable */ +#define CMD 0x0C /* Command */ +#define MD0 0x0E /* Mode 0 */ +#define MD1 0x0F /* Mode 1 */ +#define MD2 0x10 /* Mode 2 */ +#define CTL 0x11 /* Control */ +#define SA0 0x12 /* Sync/Address 0 */ +#define SA1 0x13 /* Sync/Address 1 */ +#define IDL 0x14 /* Idle Pattern */ +#define TMC 0x15 /* Time Constant */ +#define RXS 0x16 /* RX Clock Source */ +#define TXS 0x17 /* TX Clock Source */ +#define TRC0 0x18 /* TX Ready Control 0 */ +#define TRC1 0x19 /* TX Ready Control 1 */ +#define RRC 0x1A /* RX Ready Control */ +#define CST0 0x1C /* Current Status 0 */ +#define CST1 0x1D /* Current Status 1 */ + + +/* Timer channel 0 (port 0 RX) registers - offset 0x60 + Timer channel 1 (port 0 TX) registers - offset 0x68 + Timer channel 2 (port 1 RX) registers - offset 0x70 + Timer channel 3 (port 1 TX) registers - offset 0x78 +*/ + +#define TIMER0RX_OFFSET 0x60 +#define TIMER0TX_OFFSET 0x68 +#define TIMER1RX_OFFSET 0x70 +#define TIMER1TX_OFFSET 0x78 + +#define TCNTL 0x00 /* Up-counter L */ +#define TCNTH 0x01 /* Up-counter H */ +#define TCONRL 0x02 /* Constant L */ +#define TCONRH 0x03 /* Constant H */ +#define TCSR 0x04 /* Control/Status */ +#define TEPR 0x05 /* Expand Prescale */ + + + +/* DMA channel 0 (port 0 RX) registers - offset 0x80 + DMA channel 1 (port 0 TX) registers - offset 0xA0 + DMA channel 2 (port 1 RX) registers - offset 0xC0 + DMA channel 3 (port 1 TX) registers - offset 0xE0 +*/ + +#define DMAC0RX_OFFSET 0x80 +#define DMAC0TX_OFFSET 0xA0 +#define DMAC1RX_OFFSET 0xC0 +#define DMAC1TX_OFFSET 0xE0 + +#define BARL 0x00 /* Buffer Address L (chained block) */ +#define BARH 0x01 /* Buffer Address H (chained block) */ +#define BARB 0x02 /* Buffer Address B (chained block) */ + +#define DARL 0x00 /* RX Destination Addr L (single block) */ +#define DARH 0x01 /* RX Destination Addr H (single block) */ +#define DARB 0x02 /* RX Destination Addr B (single block) */ + +#define SARL 0x04 /* TX Source Address L (single block) */ +#define SARH 0x05 /* TX Source Address H (single block) */ +#define SARB 0x06 /* TX Source Address B (single block) */ + +#define CPB 0x06 /* Chain Pointer Base (chained block) */ + +#define CDAL 0x08 /* Current Descriptor Addr L (chained block) */ +#define CDAH 0x09 /* Current Descriptor Addr H (chained block) */ +#define EDAL 0x0A /* Error Descriptor Addr L (chained block) */ +#define EDAH 0x0B /* Error Descriptor Addr H (chained block) */ +#define BFLL 0x0C /* RX Receive Buffer Length L (chained block)*/ +#define BFLH 0x0D /* RX Receive Buffer Length H (chained block)*/ +#define BCRL 0x0E /* Byte Count L */ +#define BCRH 0x0F /* Byte Count H */ +#define DSR 0x10 /* DMA Status */ +#define DSR_RX(node) (DSR + (node ? DMAC1RX_OFFSET : DMAC0RX_OFFSET)) +#define DSR_TX(node) (DSR + (node ? DMAC1TX_OFFSET : DMAC0TX_OFFSET)) +#define DMR 0x11 /* DMA Mode */ +#define DMR_RX(node) (DMR + (node ? DMAC1RX_OFFSET : DMAC0RX_OFFSET)) +#define DMR_TX(node) (DMR + (node ? DMAC1TX_OFFSET : DMAC0TX_OFFSET)) +#define FCT 0x13 /* Frame End Interrupt Counter */ +#define FCT_RX(node) (FCT + (node ? DMAC1RX_OFFSET : DMAC0RX_OFFSET)) +#define FCT_TX(node) (FCT + (node ? DMAC1TX_OFFSET : DMAC0TX_OFFSET)) +#define DIR 0x14 /* DMA Interrupt Enable */ +#define DIR_RX(node) (DIR + (node ? DMAC1RX_OFFSET : DMAC0RX_OFFSET)) +#define DIR_TX(node) (DIR + (node ? DMAC1TX_OFFSET : DMAC0TX_OFFSET)) +#define DCR 0x15 /* DMA Command */ +#define DCR_RX(node) (DCR + (node ? DMAC1RX_OFFSET : DMAC0RX_OFFSET)) +#define DCR_TX(node) (DCR + (node ? DMAC1TX_OFFSET : DMAC0TX_OFFSET)) + + + + +/* Descriptor Structure */ + +typedef struct { + u16 cp; /* Chain Pointer */ + u32 bp; /* Buffer Pointer (24 bits) */ + u16 len; /* Data Length */ + u8 stat; /* Status */ + u8 unused2; +}__attribute__ ((packed)) pkt_desc; + + +/* Packet Descriptor Status bits */ + +#define ST_TX_EOM 0x80 /* End of frame */ +#define ST_TX_EOT 0x01 /* End of transmition */ + +#define ST_RX_EOM 0x80 /* End of frame */ +#define ST_RX_SHORT 0x40 /* Short frame */ +#define ST_RX_ABORT 0x20 /* Abort */ +#define ST_RX_RESBIT 0x10 /* Residual bit */ +#define ST_RX_OVERRUN 0x08 /* Overrun */ +#define ST_RX_CRC 0x04 /* CRC */ + +#define ST_ERROR_MASK 0x7C + +#define DIR_EOTE 0x80 /* Transfer completed */ +#define DIR_EOME 0x40 /* Frame Transfer Completed (chained-block) */ +#define DIR_BOFE 0x20 /* Buffer Overflow/Underflow (chained-block)*/ +#define DIR_COFE 0x10 /* Counter Overflow (chained-block) */ + + +#define DSR_EOT 0x80 /* Transfer completed */ +#define DSR_EOM 0x40 /* Frame Transfer Completed (chained-block) */ +#define DSR_BOF 0x20 /* Buffer Overflow/Underflow (chained-block)*/ +#define DSR_COF 0x10 /* Counter Overflow (chained-block) */ +#define DSR_DE 0x02 /* DMA Enable */ +#define DSR_DWE 0x01 /* DMA Write Disable */ + +/* DMA Master Enable Register (DMER) bits */ +#define DMER_DME 0x80 /* DMA Master Enable */ + + +#define CMD_RESET 0x21 /* Reset Channel */ +#define CMD_TX_ENABLE 0x02 /* Start transmitter */ +#define CMD_RX_ENABLE 0x12 /* Start receiver */ + +#define MD0_HDLC 0x80 /* Bit-sync HDLC mode */ +#define MD0_CRC_ENA 0x04 /* Enable CRC code calculation */ +#define MD0_CRC_CCITT 0x02 /* CCITT CRC instead of CRC-16 */ +#define MD0_CRC_PR1 0x01 /* Initial all-ones instead of all-zeros */ + +#define MD0_CRC_NONE 0x00 +#define MD0_CRC_16_0 0x04 +#define MD0_CRC_16 0x05 +#define MD0_CRC_ITU_0 0x06 +#define MD0_CRC_ITU 0x07 + +#define MD2_NRZI 0x20 /* NRZI mode */ +#define MD2_LOOPBACK 0x03 /* Local data Loopback */ + +#define CTL_NORTS 0x01 +#define CTL_IDLE 0x10 /* Transmit an idle pattern */ +#define CTL_UDRNC 0x20 /* Idle after CRC or FCS+flag transmition */ + +#define ST0_TXRDY 0x02 /* TX ready */ +#define ST0_RXRDY 0x01 /* RX ready */ + +#define ST1_UDRN 0x80 /* MSCI TX underrun */ + +#define ST3_CTS 0x08 /* modem input - /CTS */ +#define ST3_DCD 0x04 /* modem input - /DCD */ + +#define IE0_TXINT 0x80 /* TX INT MSCI interrupt enable */ +#define IE1_UDRN 0x80 /* TX underrun MSCI interrupt enable */ + +#define DCR_ABORT 0x01 /* Software abort command */ +#define DCR_CLEAR_EOF 0x02 /* Clear EOF interrupt */ + +/* TX and RX Clock Source - RXS and TXS */ +#define CLK_BRG_MASK 0x0F +#define CLK_LINE_RX 0x00 /* TX/RX clock line input */ +#define CLK_LINE_TX 0x00 /* TX/RX line input */ +#define CLK_BRG_RX 0x40 /* internal baud rate generator */ +#define CLK_BRG_TX 0x40 /* internal baud rate generator */ +#define CLK_RXCLK_TX 0x60 /* TX clock from RX clock */ + +#endif diff --git a/drivers/net/wan/hd6457x.c b/drivers/net/wan/hd6457x.c new file mode 100644 index 000000000..ff9764389 --- /dev/null +++ b/drivers/net/wan/hd6457x.c @@ -0,0 +1,757 @@ +/* + * Hitachi SCA HD64570 and HD64572 common driver for Linux + * + * Copyright (C) 1998-2000 Krzysztof Halasa <khc@pm.waw.pl> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Sources of information: + * Hitachi HD64570 SCA User's Manual + * Hitachi HD64572 SCA-II User's Manual + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/sched.h> +#include <linux/types.h> +#include <linux/fcntl.h> +#include <linux/interrupt.h> +#include <linux/in.h> +#include <linux/string.h> +#include <linux/timer.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/ioport.h> + +#include <asm/system.h> +#include <asm/bitops.h> +#include <asm/uaccess.h> +#include <asm/io.h> + +#include <linux/netdevice.h> +#include <linux/skbuff.h> + +#include <linux/hdlc.h> + +#if (!defined (__HD64570_H) && !defined (__HD64572_H)) || \ + (defined (__HD64570_H) && defined (__HD64572_H)) +#error Either hd64570.h or hd64572.h must be included +#endif + + +static card_t *first_card; +static card_t **new_card = &first_card; + + +/* Maximum events to handle at each interrupt - should I increase it? */ +#define INTR_WORK 4 + +#define get_msci(port) (phy_node(port) ? MSCI1_OFFSET : MSCI0_OFFSET) +#define get_dmac_rx(port) (phy_node(port) ? DMAC1RX_OFFSET : DMAC0RX_OFFSET) +#define get_dmac_tx(port) (phy_node(port) ? DMAC1TX_OFFSET : DMAC0TX_OFFSET) + +#define SCA_INTR_MSCI(node) (node ? 0x10 : 0x01) +#define SCA_INTR_DMAC_RX(node) (node ? 0x20 : 0x02) +#define SCA_INTR_DMAC_TX(node) (node ? 0x40 : 0x04) + +#ifdef __HD64570_H /* HD64570 */ +#define sca_outa(value, reg, card) sca_outw(value, reg, card) +#define sca_ina(reg, card) sca_inw(reg, card) +#define writea(value, ptr) writew(value, ptr) + +static inline int sca_intr_status(card_t *card) +{ + u8 isr0 = sca_in(ISR0, card); + u8 isr1 = sca_in(ISR1, card); + u8 result = 0; + + if (isr1 & 0x03) result |= SCA_INTR_DMAC_RX(0); + if (isr1 & 0x0C) result |= SCA_INTR_DMAC_TX(0); + if (isr1 & 0x30) result |= SCA_INTR_DMAC_RX(1); + if (isr1 & 0xC0) result |= SCA_INTR_DMAC_TX(1); + if (isr0 & 0x0F) result |= SCA_INTR_MSCI(0); + if (isr0 & 0xF0) result |= SCA_INTR_MSCI(1); + + return result; +} + +#else /* HD64572 */ +#define sca_outa(value, reg, card) sca_outl(value, reg, card) +#define sca_ina(reg, card) sca_inl(reg, card) +#define writea(value, ptr) writel(value, ptr) + + +static inline int sca_intr_status(card_t *card) +{ + u32 isr0 = sca_inl(ISR0, card); + u8 result = 0; + + if (isr0 & 0x0000000F) result |= SCA_INTR_DMAC_RX(0); + if (isr0 & 0x000000F0) result |= SCA_INTR_DMAC_TX(0); + if (isr0 & 0x00000F00) result |= SCA_INTR_DMAC_RX(1); + if (isr0 & 0x0000F000) result |= SCA_INTR_DMAC_TX(1); + if (isr0 & 0x003E0000) result |= SCA_INTR_MSCI(0); + if (isr0 & 0x3E000000) result |= SCA_INTR_MSCI(1); + + return result; +} + +#endif /* HD64570 vs HD64572 */ + + + + +static inline port_t* hdlc_to_port(hdlc_device *hdlc) +{ + return (port_t*)hdlc; +} + + + +static inline port_t* dev_to_port(struct net_device *dev) +{ + return hdlc_to_port(dev_to_hdlc(dev)); +} + + + +static inline u8 next_desc(port_t *port, u8 desc) +{ + return (desc + 1) % port_to_card(port)->ring_buffers; +} + + + +static inline u16 desc_offset(port_t *port, u8 desc, u8 transmit) +{ + /* Descriptor offset always fits in 16 bytes */ + u8 buffs = port_to_card(port)->ring_buffers; + return ((log_node(port) * 2 + transmit) * buffs + (desc % buffs)) * + sizeof(pkt_desc); +} + + + +static inline pkt_desc* desc_address(port_t *port, u8 desc, u8 transmit) +{ +#ifdef PAGE0_ALWAYS_MAPPED + return (pkt_desc*)(win0base(port_to_card(port)) + + desc_offset(port, desc, transmit)); +#else + return (pkt_desc*)(winbase(port_to_card(port)) + + desc_offset(port, desc, transmit)); +#endif +} + + + +static inline u32 buffer_offset(port_t *port, u8 desc, u8 transmit) +{ + u8 buffs = port_to_card(port)->ring_buffers; + return port_to_card(port)->buff_offset + + ((log_node(port) * 2 + transmit) * buffs + (desc % buffs)) * + (u32)HDLC_MAX_MRU; +} + + + +static void sca_init_sync_port(port_t *port) +{ + card_t *card = port_to_card(port); + u8 transmit, i; + u16 dmac, buffs = card->ring_buffers; + + port->rxin = 0; + port->txin = 0; + port->txlast = 0; + +#if !defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED) + openwin(card, 0); +#endif + + for (transmit = 0; transmit < 2; transmit++) { + for (i = 0; i < buffs; i++) { + pkt_desc* desc = desc_address(port, i, transmit); + u16 chain_off = desc_offset(port, i + 1, transmit); + u32 buff_off = buffer_offset(port, i, transmit); + + writea(chain_off, &desc->cp); + writel(buff_off, &desc->bp); + writew(0, &desc->len); + writeb(0, &desc->stat); + } + + dmac = transmit ? get_dmac_tx(port) : get_dmac_rx(port); + /* DMA disable - to halt state */ + sca_out(0, transmit ? DSR_TX(phy_node(port)) : + DSR_RX(phy_node(port)), card); + /* software ABORT - to initial state */ + sca_out(DCR_ABORT, transmit ? DCR_TX(phy_node(port)) : + DCR_RX(phy_node(port)), card); + +#ifdef __HD64570_H + sca_out(0, dmac + CPB, card); /* pointer base */ +#endif + /* current desc addr */ + sca_outa(desc_offset(port, 0, transmit), dmac + CDAL, card); + if (!transmit) + sca_outa(desc_offset(port, buffs - 1, transmit), + dmac + EDAL, card); + else + sca_outa(desc_offset(port, 0, transmit), dmac + EDAL, + card); + + /* clear frame end interrupt counter */ + sca_out(DCR_CLEAR_EOF, transmit ? DCR_TX(phy_node(port)) : + DCR_RX(phy_node(port)), card); + + if (!transmit) { /* Receive */ + /* set buffer length */ + sca_outw(HDLC_MAX_MRU, dmac + BFLL, card); + /* Chain mode, Multi-frame */ + sca_out(0x14, DMR_RX(phy_node(port)), card); + sca_out(DIR_EOME | DIR_BOFE, DIR_RX(phy_node(port)), + card); + /* DMA enable */ + sca_out(DSR_DE, DSR_RX(phy_node(port)), card); + } else { /* Transmit */ + /* Chain mode, Multi-frame */ + sca_out(0x14, DMR_TX(phy_node(port)), card); + /* enable underflow interrupts */ + sca_out(DIR_BOFE, DIR_TX(phy_node(port)), card); + } + } +} + + + +/* MSCI interrupt service */ +static inline void sca_msci_intr(port_t *port) +{ + u16 msci = get_msci(port); + card_t* card = port_to_card(port); + u8 stat = sca_in(msci + ST1, card); /* read MSCI ST1 status */ + + /* printk(KERN_DEBUG "MSCI INT: ST1=%02X ILAR=%02X\n", + stat, sca_in(ILAR, card)); */ + + /* Reset MSCI TX underrun status bit */ + sca_out(stat & ST1_UDRN, msci + ST1, card); + + if (stat & ST1_UDRN) { + port->hdlc.stats.tx_errors++; /* TX Underrun error detected */ + port->hdlc.stats.tx_fifo_errors++; + } +} + + + +static inline void sca_rx(card_t *card, port_t *port, pkt_desc *desc, + u8 rxin) +{ + struct sk_buff *skb; + u16 len; + u32 buff; +#ifndef ALL_PAGES_ALWAYS_MAPPED + u32 maxlen; + u8 page; +#endif + + len = readw(&desc->len); + skb = dev_alloc_skb(len); + if (!skb) { + port->hdlc.stats.rx_dropped++; + return; + } + + buff = buffer_offset(port, rxin, 0); +#ifndef ALL_PAGES_ALWAYS_MAPPED + page = buff / winsize(card); + buff = buff % winsize(card); + maxlen = winsize(card) - buff; + + openwin(card, page); + + if (len > maxlen) { + memcpy_fromio(skb->data, winbase(card) + buff, maxlen); + openwin(card, page + 1); + memcpy_fromio(skb->data + maxlen, winbase(card), len - maxlen); + } else +#endif + memcpy_fromio(skb->data, winbase(card) + buff, len); + +#if !defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED) + /* select pkt_desc table page back */ + openwin(card, 0); +#endif + skb_put(skb, len); +#ifdef DEBUG_PKT + printk(KERN_DEBUG "%s RX(%i):", hdlc_to_name(&port->hdlc), skb->len); + debug_frame(skb); +#endif + port->hdlc.stats.rx_packets++; + port->hdlc.stats.rx_bytes += skb->len; + hdlc_netif_rx(&port->hdlc, skb); +} + + + +/* Receive DMA interrupt service */ +static inline void sca_rx_intr(port_t *port) +{ + u16 dmac = get_dmac_rx(port); + card_t *card = port_to_card(port); + u8 stat = sca_in(DSR_RX(phy_node(port)), card); /* read DMA Status */ + struct net_device_stats *stats = &port->hdlc.stats; + + /* Reset DSR status bits */ + sca_out((stat & (DSR_EOT | DSR_EOM | DSR_BOF | DSR_COF)) | DSR_DWE, + DSR_RX(phy_node(port)), card); + + if (stat & DSR_BOF) + stats->rx_over_errors++; /* Dropped one or more frames */ + + while (1) { + u32 desc_off = desc_offset(port, port->rxin, 0); + pkt_desc *desc; + u32 cda = sca_ina(dmac + CDAL, card); + + if (cda == desc_off) + break; /* No frame received */ + +#ifdef __HD64572_H + if (cda == desc_off + 8) + break; /* SCA-II updates CDA in 2 steps */ +#endif + + desc = desc_address(port, port->rxin, 0); + stat = readb(&desc->stat); + if (!(stat & ST_RX_EOM)) + port->rxpart = 1; /* partial frame received */ + else if ((stat & ST_ERROR_MASK) || port->rxpart) { + stats->rx_errors++; + if (stat & ST_RX_OVERRUN) stats->rx_fifo_errors++; + else if ((stat & (ST_RX_SHORT | ST_RX_ABORT | + ST_RX_RESBIT)) || port->rxpart) + stats->rx_frame_errors++; + else if (stat & ST_RX_CRC) stats->rx_crc_errors++; + if (stat & ST_RX_EOM) + port->rxpart = 0; /* received last fragment */ + } else + sca_rx(card, port, desc, port->rxin); + + /* Set new error descriptor address */ + sca_outa(desc_off, dmac + EDAL, card); + port->rxin = next_desc(port, port->rxin); + } + + /* make sure RX DMA is enabled */ + sca_out(DSR_DE, DSR_RX(phy_node(port)), card); +} + + + +/* Transmit DMA interrupt service */ +static inline void sca_tx_intr(port_t *port) +{ + u16 dmac = get_dmac_tx(port); + card_t* card = port_to_card(port); + u8 stat; + + spin_lock(&port->lock); + + stat = sca_in(DSR_TX(phy_node(port)), card); /* read DMA Status */ + + /* Reset DSR status bits */ + sca_out((stat & (DSR_EOT | DSR_EOM | DSR_BOF | DSR_COF)) | DSR_DWE, + DSR_TX(phy_node(port)), card); + + while (1) { + u32 desc_off = desc_offset(port, port->txlast, 1); + pkt_desc *desc; + u16 len; + + if (sca_ina(dmac + CDAL, card) == desc_off) + break; /* Transmitter is/will_be sending this frame */ + + desc = desc_address(port, port->txlast, 1); + len = readw(&desc->len); + + port->hdlc.stats.tx_packets++; + port->hdlc.stats.tx_bytes += len; + writeb(0, &desc->stat); /* Free descriptor */ + + port->txlast = (port->txlast + 1) % + port_to_card(port)->ring_buffers; + } + + netif_wake_queue(hdlc_to_dev(&port->hdlc)); + spin_unlock(&port->lock); +} + + + +static void sca_intr(int irq, void* dev_id, struct pt_regs *regs) +{ + card_t *card = dev_id; + int boguscnt = INTR_WORK; + int i; + u8 stat; + +#ifndef ALL_PAGES_ALWAYS_MAPPED + u8 page = sca_get_page(card); +#endif + + while((stat = sca_intr_status(card)) != 0) { + for (i = 0; i < 2; i++) { + port_t *port = get_port(card, i); + if (port) { + if (stat & SCA_INTR_MSCI(i)) + sca_msci_intr(port); + + if (stat & SCA_INTR_DMAC_RX(i)) + sca_rx_intr(port); + + if (stat & SCA_INTR_DMAC_TX(i)) + sca_tx_intr(port); + } + + if (--boguscnt < 0) { + printk(KERN_ERR "%s: too much work at " + "interrupt\n", + hdlc_to_name(&port->hdlc)); + goto exit; + } + } + } + + exit: +#ifndef ALL_PAGES_ALWAYS_MAPPED + openwin(card, page); /* Restore original page */ +#endif +} + + + +static inline int sca_set_loopback(port_t *port, int line) +{ + card_t* card = port_to_card(port); + u8 msci = get_msci(port); + u8 md2 = sca_in(msci + MD2, card); + + switch(line) { + case LINE_DEFAULT: + md2 &= ~MD2_LOOPBACK; + port->line &= ~LINE_LOOPBACK; + break; + + case LINE_LOOPBACK: + md2 |= MD2_LOOPBACK; + port->line |= LINE_LOOPBACK; + break; + + default: + return -EINVAL; + } + + sca_out(md2, msci + MD2, card); + return 0; +} + + + +static void sca_set_clock(port_t *port) +{ + card_t *card = port_to_card(port); + u8 msci = get_msci(port); + unsigned int tmc, br = 10, brv = 1024; + + if (port->clkrate > 0) { + /* Try lower br for better accuracy*/ + do { + br--; + brv >>= 1; /* brv = 2^9 = 512 max in specs */ + + /* Baud Rate = CLOCK_BASE / TMC / 2^BR */ + tmc = CLOCK_BASE / (brv * port->clkrate); + }while(br > 1 && tmc <= 128); + + if (tmc < 1) { + tmc = 1; + br = 0; /* For baud=CLOCK_BASE we use tmc=1 br=0 */ + brv = 1; + } else if (tmc > 255) + tmc = 256; /* tmc=0 means 256 - low baud rates */ + + port->clkrate = CLOCK_BASE / (brv * tmc); + } else { + br = 9; /* Minimum clock rate */ + tmc = 256; /* 8bit = 0 */ + port->clkrate = CLOCK_BASE / (256 * 512); + } + + port->rxs = (port->rxs & ~CLK_BRG_MASK) | br; + port->txs = (port->txs & ~CLK_BRG_MASK) | br; + port->tmc = tmc; + + /* baud divisor - time constant*/ +#ifdef __HD64570_H + sca_out(port->tmc, msci + TMC, card); +#else + sca_out(port->tmc, msci + TMCR, card); + sca_out(port->tmc, msci + TMCT, card); +#endif + + /* Set BRG bits */ + sca_out(port->rxs, msci + RXS, card); + sca_out(port->txs, msci + TXS, card); +} + + + +static void sca_set_hdlc_mode(port_t *port, u8 idle, u8 crc, u8 nrzi) +{ + card_t* card = port_to_card(port); + u8 msci = get_msci(port); + u8 md2 = (nrzi ? MD2_NRZI : 0) | + ((port->line & LINE_LOOPBACK) ? MD2_LOOPBACK : 0); + u8 ctl = (idle ? CTL_IDLE : 0); +#ifdef __HD64572_H + ctl |= CTL_URCT | CTL_URSKP; /* Skip the rest of underrun frame */ +#endif + + sca_out(CMD_RESET, msci + CMD, card); + sca_out(MD0_HDLC | crc, msci + MD0, card); + sca_out(0x00, msci + MD1, card); /* no address field check */ + sca_out(md2, msci + MD2, card); + sca_out(0x7E, msci + IDL, card); /* flag character 0x7E */ + sca_out(ctl, msci + CTL, card); + +#ifdef __HD64570_H + /* Allow at least 8 bytes before requesting RX DMA operation */ + /* TX with higher priority and possibly with shorter transfers */ + sca_out(0x07, msci + RRC, card); /* +1=RXRDY/DMA activation condition*/ + sca_out(0x10, msci + TRC0, card); /* = TXRDY/DMA activation condition*/ + sca_out(0x14, msci + TRC1, card); /* +1=TXRDY/DMA deactiv condition */ +#else + sca_out(0x0F, msci + RNR, card); /* +1=RX DMA activation condition */ + /* Setting than to larger value may cause Illegal Access */ + sca_out(0x20, msci + TNR0, card); /* =TX DMA activation condition */ + sca_out(0x30, msci + TNR1, card); /* +1=TX DMA deactivation condition*/ + sca_out(0x04, msci + TCR, card); /* =Critical TX DMA activ condition */ +#endif + + +#ifdef __HD64570_H + /* MSCI TX INT IRQ enable */ + sca_out(IE0_TXINT, msci + IE0, card); + sca_out(IE1_UDRN, msci + IE1, card); /* TX underrun IRQ */ + sca_out(sca_in(IER0, card) | (phy_node(port) ? 0x80 : 0x08), + IER0, card); + /* DMA IRQ enable */ + sca_out(sca_in(IER1, card) | (phy_node(port) ? 0xF0 : 0x0F), + IER1, card); +#else + /* MSCI TX INT and underrrun IRQ enable */ + sca_outl(IE0_TXINT | IE0_UDRN, msci + IE0, card); + /* DMA & MSCI IRQ enable */ + sca_outl(sca_in(IER0, card) | + (phy_node(port) ? 0x02006600 : 0x00020066), IER0, card); +#endif + +#ifdef __HD64570_H + sca_out(port->tmc, msci + TMC, card); /* Restore registers */ +#else + sca_out(port->tmc, msci + TMCR, card); + sca_out(port->tmc, msci + TMCT, card); +#endif + sca_out(port->rxs, msci + RXS, card); + sca_out(port->txs, msci + TXS, card); + sca_out(CMD_TX_ENABLE, msci + CMD, card); + sca_out(CMD_RX_ENABLE, msci + CMD, card); +} + + + +#ifdef DEBUG_RINGS +static void sca_dump_rings(hdlc_device *hdlc) +{ + port_t *port = hdlc_to_port(hdlc); + card_t *card = port_to_card(port); + u16 cnt; +#if !defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED) + u8 page; +#endif + +#if !defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED) + page = sca_get_page(card); + openwin(card, 0); +#endif + + printk(KERN_ERR "RX ring: CDA=%u EDA=%u DSR=%02X in=%u " + "%sactive", + sca_ina(get_dmac_rx(port) + CDAL, card), + sca_ina(get_dmac_rx(port) + EDAL, card), + sca_in(DSR_RX(phy_node(port)), card), + port->rxin, + sca_in(DSR_RX(phy_node(port)), card) & DSR_DE?"":"in"); + for (cnt = 0; cnt<port_to_card(port)->ring_buffers; cnt++) + printk(" %02X", + readb(&(desc_address(port, cnt, 0)->stat))); + + printk("\n" KERN_ERR "TX ring: CDA=%u EDA=%u DSR=%02X in=%u " + "last=%u %sactive", + sca_ina(get_dmac_tx(port) + CDAL, card), + sca_ina(get_dmac_tx(port) + EDAL, card), + sca_in(DSR_TX(phy_node(port)), card), port->txin, + port->txlast, + sca_in(DSR_TX(phy_node(port)), card) & DSR_DE ? "" : "in"); + + for (cnt = 0; cnt<port_to_card(port)->ring_buffers; cnt++) + printk(" %02X", + readb(&(desc_address(port, cnt, 1)->stat))); + printk("\n"); + + printk(KERN_ERR "MSCI: MD: %02x %02x %02x, " + "ST: %02x %02x %02x %02x" +#ifdef __HD64572_H + " %02x" +#endif + ", FST: %02x CST: %02x %02x\n", + sca_in(get_msci(port) + MD0, card), + sca_in(get_msci(port) + MD1, card), + sca_in(get_msci(port) + MD2, card), + sca_in(get_msci(port) + ST0, card), + sca_in(get_msci(port) + ST1, card), + sca_in(get_msci(port) + ST2, card), + sca_in(get_msci(port) + ST3, card), +#ifdef __HD64572_H + sca_in(get_msci(port) + ST4, card), +#endif + sca_in(get_msci(port) + FST, card), + sca_in(get_msci(port) + CST0, card), + sca_in(get_msci(port) + CST1, card)); + +#ifdef __HD64572_H + printk(KERN_ERR "ILAR: %02x\n", sca_in(ILAR, card)); +#endif + +#if !defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED) + openwin(card, page); /* Restore original page */ +#endif +} +#endif /* DEBUG_RINGS */ + + + +static void sca_open(hdlc_device *hdlc) +{ + port_t *port = hdlc_to_port(hdlc); + + sca_set_hdlc_mode(port, 1, MD0_CRC_ITU, 0); + netif_start_queue(hdlc_to_dev(hdlc)); +} + + +static void sca_close(hdlc_device *hdlc) +{ + port_t *port = hdlc_to_port(hdlc); + + /* reset channel */ + netif_stop_queue(hdlc_to_dev(hdlc)); + sca_out(CMD_RESET, get_msci(port) + CMD, port_to_card(port)); +} + + + +static int sca_xmit(hdlc_device *hdlc, struct sk_buff *skb) +{ + port_t *port = hdlc_to_port(hdlc); + struct net_device *dev = hdlc_to_dev(hdlc); + card_t *card = port_to_card(port); + pkt_desc *desc; + u32 buff, len; +#ifndef ALL_PAGES_ALWAYS_MAPPED + u8 page; + u32 maxlen; +#endif + + spin_lock_irq(&port->lock); + + desc = desc_address(port, port->txin + 1, 1); + if (readb(&desc->stat)) { /* allow 1 packet gap */ + /* should never happen - previous xmit should stop queue */ +#ifdef DEBUG_PKT + printk(KERN_DEBUG "%s: transmitter buffer full\n", dev->name); +#endif + netif_stop_queue(dev); + spin_unlock_irq(&port->lock); + return 1; /* request packet to be queued */ + } + +#ifdef DEBUG_PKT + printk(KERN_DEBUG "%s TX(%i):", hdlc_to_name(hdlc), skb->len); + debug_frame(skb); +#endif + + desc = desc_address(port, port->txin, 1); + buff = buffer_offset(port, port->txin, 1); + len = skb->len; +#ifndef ALL_PAGES_ALWAYS_MAPPED + page = buff / winsize(card); + buff = buff % winsize(card); + maxlen = winsize(card) - buff; + + openwin(card, page); + if (len > maxlen) { + memcpy_toio(winbase(card) + buff, skb->data, maxlen); + openwin(card, page + 1); + memcpy_toio(winbase(card), skb->data + maxlen, len - maxlen); + } + else +#endif + memcpy_toio(winbase(card) + buff, skb->data, len); + +#if !defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED) + openwin(card, 0); /* select pkt_desc table page back */ +#endif + writew(len, &desc->len); + writeb(ST_TX_EOM, &desc->stat); + dev->trans_start = jiffies; + + port->txin = next_desc(port, port->txin); + sca_outa(desc_offset(port, port->txin, 1), + get_dmac_tx(port) + EDAL, card); + + sca_out(DSR_DE, DSR_TX(phy_node(port)), card); /* Enable TX DMA */ + + desc = desc_address(port, port->txin + 1, 1); + if (readb(&desc->stat)) /* allow 1 packet gap */ + netif_stop_queue(hdlc_to_dev(&port->hdlc)); + + spin_unlock_irq(&port->lock); + + dev_kfree_skb(skb); + return 0; +} + + +static void sca_init(card_t *card, int wait_states) +{ + sca_out(wait_states, WCRL, card); /* Wait Control */ + sca_out(wait_states, WCRM, card); + sca_out(wait_states, WCRH, card); + + sca_out(0, DMER, card); /* DMA Master disable */ + sca_out(0x03, PCR, card); /* DMA priority */ + sca_out(0, IER1, card); /* DMA interrupt disable */ + sca_out(0, DSR_RX(0), card); /* DMA disable - to halt state */ + sca_out(0, DSR_TX(0), card); + sca_out(0, DSR_RX(1), card); + sca_out(0, DSR_TX(1), card); + sca_out(DMER_DME, DMER, card); /* DMA Master enable */ +} diff --git a/drivers/net/wan/hdlc.c b/drivers/net/wan/hdlc.c new file mode 100644 index 000000000..1a1cb8405 --- /dev/null +++ b/drivers/net/wan/hdlc.c @@ -0,0 +1,1454 @@ +/* + * Generic HDLC support routines for Linux + * + * Copyright (C) 1999, 2000 Krzysztof Halasa <khc@pm.waw.pl> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Current status: + * - this is work in progress + * - not heavily tested on SMP + * - currently supported: + * * raw IP-in-HDLC + * * Cisco HDLC + * * Frame Relay with ANSI or CCITT LMI (both user and network side) + * * PPP (using syncppp.c) + * * X.25 + * + * Use sethdlc utility to set line parameters, protocol and PVCs + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/poll.h> +#include <linux/sched.h> +#include <linux/errno.h> +#include <linux/if_arp.h> +#include <linux/init.h> +#include <linux/skbuff.h> +#include <linux/pkt_sched.h> +#include <linux/inetdevice.h> +#include <linux/lapb.h> +#include <linux/rtnetlink.h> +#include <linux/hdlc.h> + +/* #define DEBUG_PKT */ +/* #define DEBUG_HARD_HEADER */ +/* #define DEBUG_FECN */ +/* #define DEBUG_BECN */ + +static const char* version = "HDLC support module revision 1.02 for Linux 2.4"; + + +#define CISCO_MULTICAST 0x8F /* Cisco multicast address */ +#define CISCO_UNICAST 0x0F /* Cisco unicast address */ +#define CISCO_KEEPALIVE 0x8035 /* Cisco keepalive protocol */ +#define CISCO_SYS_INFO 0x2000 /* Cisco interface/system info */ +#define CISCO_ADDR_REQ 0 /* Cisco address request */ +#define CISCO_ADDR_REPLY 1 /* Cisco address reply */ +#define CISCO_KEEPALIVE_REQ 2 /* Cisco keepalive request */ + +static int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); + +/******************************************************** + * + * Cisco HDLC support + * + *******************************************************/ + +static int cisco_hard_header(struct sk_buff *skb, struct net_device *dev, + u16 type, void *daddr, void *saddr, + unsigned int len) +{ + hdlc_header *data; +#ifdef DEBUG_HARD_HEADER + printk(KERN_DEBUG "%s: cisco_hard_header called\n", dev->name); +#endif + + skb_push(skb, sizeof(hdlc_header)); + data = (hdlc_header*)skb->data; + if (type == CISCO_KEEPALIVE) + data->address = CISCO_MULTICAST; + else + data->address = CISCO_UNICAST; + data->control = 0; + data->protocol = htons(type); + + return sizeof(hdlc_header); +} + + + +static void cisco_keepalive_send(hdlc_device *hdlc, u32 type, + u32 par1, u32 par2) +{ + struct sk_buff *skb; + cisco_packet *data; + + skb = dev_alloc_skb(sizeof(hdlc_header)+sizeof(cisco_packet)); + if (!skb) { + printk(KERN_WARNING "%s: Memory squeeze on cisco_keepalive_send()\n", + hdlc_to_name(hdlc)); + return; + } + skb_reserve(skb, 4); + cisco_hard_header(skb, hdlc_to_dev(hdlc), CISCO_KEEPALIVE, + NULL, NULL, 0); + data = (cisco_packet*)skb->tail; + + data->type = htonl(type); + data->par1 = htonl(par1); + data->par2 = htonl(par2); + data->rel = 0xFFFF; + data->time = htonl(jiffies * 1000 / HZ); + + skb_put(skb, sizeof(cisco_packet)); + skb->priority = TC_PRIO_CONTROL; + skb->dev = hdlc_to_dev(hdlc); + + dev_queue_xmit(skb); +} + + + +static void cisco_netif(hdlc_device *hdlc, struct sk_buff *skb) +{ + hdlc_header *data = (hdlc_header*)skb->data; + cisco_packet *cisco_data; + struct in_device *in_dev; + u32 addr, mask; + + if (skb->len<sizeof(hdlc_header)) + goto rx_error; + + if (data->address != CISCO_MULTICAST && + data->address != CISCO_UNICAST) + goto rx_error; + + skb_pull(skb, sizeof(hdlc_header)); + + switch(ntohs(data->protocol)) { + case ETH_P_IP: + case ETH_P_IPX: + case ETH_P_IPV6: + skb->protocol = data->protocol; + skb->dev = hdlc_to_dev(hdlc); + netif_rx(skb); + return; + + case CISCO_SYS_INFO: + /* Packet is not needed, drop it. */ + dev_kfree_skb_any(skb); + return; + + case CISCO_KEEPALIVE: + if (skb->len != CISCO_PACKET_LEN && + skb->len != CISCO_BIG_PACKET_LEN) { + printk(KERN_INFO "%s: Invalid length of Cisco " + "control packet (%d bytes)\n", + hdlc_to_name(hdlc), skb->len); + goto rx_error; + } + + cisco_data = (cisco_packet*)skb->data; + + switch(ntohl (cisco_data->type)) { + case CISCO_ADDR_REQ: /* Stolen from syncppp.c :-) */ + in_dev = hdlc_to_dev(hdlc)->ip_ptr; + addr = 0; + mask = ~0; /* is the mask correct? */ + + if (in_dev != NULL) { + struct in_ifaddr **ifap = &in_dev->ifa_list; + + while (*ifap != NULL) { + if (strcmp(hdlc_to_name(hdlc), + (*ifap)->ifa_label) == 0) { + addr = (*ifap)->ifa_local; + mask = (*ifap)->ifa_mask; + break; + } + ifap = &(*ifap)->ifa_next; + } + + cisco_keepalive_send(hdlc, CISCO_ADDR_REPLY, + addr, mask); + } + dev_kfree_skb_any(skb); + return; + + case CISCO_ADDR_REPLY: + printk(KERN_INFO "%s: Unexpected Cisco IP address " + "reply\n", hdlc_to_name(hdlc)); + goto rx_error; + + case CISCO_KEEPALIVE_REQ: + hdlc->lmi.rxseq = ntohl(cisco_data->par1); + if (ntohl(cisco_data->par2) == hdlc->lmi.txseq) { + hdlc->lmi.last_poll = jiffies; + if (!(hdlc->lmi.state & LINK_STATE_RELIABLE)) { + u32 sec, min, hrs, days; + sec = ntohl(cisco_data->time) / 1000; + min = sec / 60; sec -= min * 60; + hrs = min / 60; min -= hrs * 60; + days = hrs / 24; hrs -= days * 24; + printk(KERN_INFO "%s: Link up (peer " + "uptime %ud%uh%um%us)\n", + hdlc_to_name(hdlc), days, hrs, + min, sec); + } + hdlc->lmi.state |= LINK_STATE_RELIABLE; + } + + dev_kfree_skb_any(skb); + return; + } /* switch(keepalive type) */ + } /* switch(protocol) */ + + printk(KERN_INFO "%s: Unsupported protocol %x\n", hdlc_to_name(hdlc), + data->protocol); + dev_kfree_skb_any(skb); + return; + + rx_error: + hdlc->stats.rx_errors++; /* Mark error */ + dev_kfree_skb_any(skb); +} + + + +static void cisco_timer(unsigned long arg) +{ + hdlc_device *hdlc = (hdlc_device*)arg; + + if ((hdlc->lmi.state & LINK_STATE_RELIABLE) && + (jiffies - hdlc->lmi.last_poll >= hdlc->lmi.T392 * HZ)) { + hdlc->lmi.state &= ~LINK_STATE_RELIABLE; + printk(KERN_INFO "%s: Link down\n", hdlc_to_name(hdlc)); + } + + cisco_keepalive_send(hdlc, CISCO_KEEPALIVE_REQ, ++hdlc->lmi.txseq, + hdlc->lmi.rxseq); + hdlc->timer.expires = jiffies + hdlc->lmi.T391*HZ; + + hdlc->timer.function = cisco_timer; + hdlc->timer.data = arg; + add_timer(&hdlc->timer); +} + + + +/****************************************************************** + * + * generic Frame Relay routines + * + *****************************************************************/ + + +static int fr_hard_header(struct sk_buff *skb, struct net_device *dev, + u16 type, void *daddr, void *saddr, unsigned int len) +{ + u16 head_len; + + if (!daddr) + daddr = dev->broadcast; + +#ifdef DEBUG_HARD_HEADER + printk(KERN_DEBUG "%s: fr_hard_header called\n", dev->name); +#endif + + switch(type) { + case ETH_P_IP: + head_len = 4; + skb_push(skb, head_len); + skb->data[3] = NLPID_IP; + break; + + case ETH_P_IPV6: + head_len = 4; + skb_push(skb, head_len); + skb->data[3] = NLPID_IPV6; + break; + + case LMI_PROTO: + head_len = 4; + skb_push(skb, head_len); + skb->data[3] = LMI_PROTO; + break; + + default: + head_len = 10; + skb_push(skb, head_len); + skb->data[3] = FR_PAD; + skb->data[4] = NLPID_SNAP; + skb->data[5] = FR_PAD; + skb->data[6] = FR_PAD; + skb->data[7] = FR_PAD; + skb->data[8] = type>>8; + skb->data[9] = (u8)type; + } + + memcpy(skb->data, daddr, 2); + skb->data[2] = FR_UI; + + return head_len; +} + + + +static inline void fr_log_dlci_active(pvc_device *pvc) +{ + printk(KERN_INFO "%s: %sactive%s\n", pvc_to_name(pvc), + pvc->state & PVC_STATE_ACTIVE ? "" : "in", + pvc->state & PVC_STATE_NEW ? " new" : ""); +} + + + +static inline u8 fr_lmi_nextseq(u8 x) +{ + x++; + return x ? x : 1; +} + + + +static void fr_lmi_send(hdlc_device *hdlc, int fullrep) +{ + struct sk_buff *skb; + pvc_device *pvc = hdlc->first_pvc; + int len = mode_is(hdlc, MODE_FR_ANSI) ? LMI_ANSI_LENGTH : LMI_LENGTH; + int stat_len = 3; + u8 *data; + int i = 0; + + if (mode_is(hdlc, MODE_DCE) && fullrep) { + len += hdlc->pvc_count * (2 + stat_len); + if (len > HDLC_MAX_MTU) { + printk(KERN_WARNING "%s: Too many PVCs while sending " + "LMI full report\n", hdlc_to_name(hdlc)); + return; + } + } + + skb = dev_alloc_skb(len); + if (!skb) { + printk(KERN_WARNING "%s: Memory squeeze on fr_lmi_send()\n", + hdlc_to_name(hdlc)); + return; + } + memset(skb->data, 0, len); + skb_reserve(skb, 4); + fr_hard_header(skb, hdlc_to_dev(hdlc), LMI_PROTO, NULL, NULL, 0); + data = skb->tail; + data[i++] = LMI_CALLREF; + data[i++] = mode_is(hdlc, MODE_DCE) ? LMI_STATUS : LMI_STATUS_ENQUIRY; + if (mode_is(hdlc, MODE_FR_ANSI)) + data[i++] = LMI_ANSI_LOCKSHIFT; + data[i++] = mode_is(hdlc, MODE_FR_CCITT) ? LMI_CCITT_REPTYPE : + LMI_REPTYPE; + data[i++] = LMI_REPT_LEN; + data[i++] = fullrep ? LMI_FULLREP : LMI_INTEGRITY; + + data[i++] = mode_is(hdlc, MODE_FR_CCITT) ? LMI_CCITT_ALIVE : LMI_ALIVE; + data[i++] = LMI_INTEG_LEN; + data[i++] = hdlc->lmi.txseq = fr_lmi_nextseq(hdlc->lmi.txseq); + data[i++] = hdlc->lmi.rxseq; + + if (mode_is(hdlc, MODE_DCE) && fullrep) { + while (pvc) { + data[i++] = mode_is(hdlc, MODE_FR_CCITT) ? + LMI_CCITT_PVCSTAT:LMI_PVCSTAT; + data[i++] = stat_len; + + if ((hdlc->lmi.state & LINK_STATE_RELIABLE) && + (pvc->netdev.flags & IFF_UP) && + !(pvc->state & (PVC_STATE_ACTIVE|PVC_STATE_NEW))) { + pvc->state |= PVC_STATE_NEW; + fr_log_dlci_active(pvc); + } + + dlci_to_status(hdlc, netdev_dlci(&pvc->netdev), + data+i, pvc->state); + i += stat_len; + pvc = pvc->next; + } + } + + skb_put(skb, i); + skb->priority = TC_PRIO_CONTROL; + skb->dev = hdlc_to_dev(hdlc); + + dev_queue_xmit(skb); +} + + + +static void fr_timer(unsigned long arg) +{ + hdlc_device *hdlc = (hdlc_device*)arg; + int i, cnt = 0, reliable; + u32 list; + + if (mode_is(hdlc, MODE_DCE)) + reliable = (jiffies - hdlc->lmi.last_poll < hdlc->lmi.T392*HZ); + else { + hdlc->lmi.last_errors <<= 1; /* Shift the list */ + if (hdlc->lmi.state & LINK_STATE_REQUEST) { + printk(KERN_INFO "%s: No LMI status reply received\n", + hdlc_to_name(hdlc)); + hdlc->lmi.last_errors |= 1; + } + + for (i = 0, list = hdlc->lmi.last_errors; i < hdlc->lmi.N393; + i++, list >>= 1) + cnt += (list & 1); /* errors count */ + + reliable = (cnt < hdlc->lmi.N392); + } + + if ((hdlc->lmi.state & LINK_STATE_RELIABLE) != + (reliable ? LINK_STATE_RELIABLE : 0)) { + pvc_device *pvc = hdlc->first_pvc; + + while (pvc) {/* Deactivate all PVCs */ + pvc->state &= ~(PVC_STATE_NEW | PVC_STATE_ACTIVE); + pvc = pvc->next; + } + + hdlc->lmi.state ^= LINK_STATE_RELIABLE; + printk(KERN_INFO "%s: Link %sreliable\n", hdlc_to_name(hdlc), + reliable ? "" : "un"); + + if (reliable) { + hdlc->lmi.N391cnt = 0; /* Request full status */ + hdlc->lmi.state |= LINK_STATE_CHANGED; + } + } + + if (mode_is(hdlc, MODE_DCE)) + hdlc->timer.expires = jiffies + hdlc->lmi.T392*HZ; + else { + if (hdlc->lmi.N391cnt) + hdlc->lmi.N391cnt--; + + fr_lmi_send(hdlc, hdlc->lmi.N391cnt == 0); + + hdlc->lmi.state |= LINK_STATE_REQUEST; + hdlc->timer.expires = jiffies + hdlc->lmi.T391*HZ; + } + + hdlc->timer.function = fr_timer; + hdlc->timer.data = arg; + add_timer(&hdlc->timer); +} + + + +static int fr_lmi_recv(hdlc_device *hdlc, struct sk_buff *skb) +{ + int stat_len; + pvc_device *pvc; + int reptype = -1, error; + u8 rxseq, txseq; + int i; + + if (skb->len < (mode_is(hdlc, MODE_FR_ANSI) ? + LMI_ANSI_LENGTH : LMI_LENGTH)) { + printk(KERN_INFO "%s: Short LMI frame\n", hdlc_to_name(hdlc)); + return 1; + } + + if (skb->data[5] != (!mode_is(hdlc, MODE_DCE) ? + LMI_STATUS : LMI_STATUS_ENQUIRY)) { + printk(KERN_INFO "%s: LMI msgtype=%x, Not LMI status %s\n", + hdlc_to_name(hdlc), skb->data[2], + mode_is(hdlc, MODE_DCE) ? "enquiry" : "reply"); + return 1; + } + + i = mode_is(hdlc, MODE_FR_ANSI) ? 7 : 6; + + if (skb->data[i] != + (mode_is(hdlc, MODE_FR_CCITT) ? LMI_CCITT_REPTYPE : LMI_REPTYPE)) { + printk(KERN_INFO "%s: Not a report type=%x\n", + hdlc_to_name(hdlc), skb->data[i]); + return 1; + } + i++; + + i++; /* Skip length field */ + + reptype = skb->data[i++]; + + if (skb->data[i]!= + (mode_is(hdlc, MODE_FR_CCITT) ? LMI_CCITT_ALIVE : LMI_ALIVE)) { + printk(KERN_INFO "%s: Unsupported status element=%x\n", + hdlc_to_name(hdlc), skb->data[i]); + return 1; + } + i++; + + i++; /* Skip length field */ + + hdlc->lmi.rxseq = skb->data[i++]; /* TX sequence from peer */ + rxseq = skb->data[i++]; /* Should confirm our sequence */ + + txseq = hdlc->lmi.txseq; + + if (mode_is(hdlc, MODE_DCE)) { + if (reptype != LMI_FULLREP && reptype != LMI_INTEGRITY) { + printk(KERN_INFO "%s: Unsupported report type=%x\n", + hdlc_to_name(hdlc), reptype); + return 1; + } + } + + error = 0; + if (!(hdlc->lmi.state & LINK_STATE_RELIABLE)) + error = 1; + + if (rxseq == 0 || rxseq != txseq) { + hdlc->lmi.N391cnt = 0; /* Ask for full report next time */ + error = 1; + } + + if (mode_is(hdlc, MODE_DCE)) { + if ((hdlc->lmi.state & LINK_STATE_FULLREP_SENT) && !error) { +/* Stop sending full report - the last one has been confirmed by DTE */ + hdlc->lmi.state &= ~LINK_STATE_FULLREP_SENT; + pvc = hdlc->first_pvc; + while (pvc) { + if (pvc->state & PVC_STATE_NEW) { + pvc->state &= ~PVC_STATE_NEW; + pvc->state |= PVC_STATE_ACTIVE; + fr_log_dlci_active(pvc); + +/* Tell DTE that new PVC is now active */ + hdlc->lmi.state |= LINK_STATE_CHANGED; + } + pvc = pvc->next; + } + } + + if (hdlc->lmi.state & LINK_STATE_CHANGED) { + reptype = LMI_FULLREP; + hdlc->lmi.state |= LINK_STATE_FULLREP_SENT; + hdlc->lmi.state &= ~LINK_STATE_CHANGED; + } + + fr_lmi_send(hdlc, reptype == LMI_FULLREP ? 1 : 0); + return 0; + } + + /* DTE */ + + if (reptype != LMI_FULLREP || error) + return 0; + + stat_len = 3; + pvc = hdlc->first_pvc; + + while (pvc) { + pvc->newstate = 0; + pvc = pvc->next; + } + + while (skb->len >= i + 2 + stat_len) { + u16 dlci; + u8 state = 0; + + if (skb->data[i] != (mode_is(hdlc, MODE_FR_CCITT) ? + LMI_CCITT_PVCSTAT : LMI_PVCSTAT)) { + printk(KERN_WARNING "%s: Invalid PVCSTAT ID: %x\n", + hdlc_to_name(hdlc), skb->data[i]); + return 1; + } + i++; + + if (skb->data[i] != stat_len) { + printk(KERN_WARNING "%s: Invalid PVCSTAT length: %x\n", + hdlc_to_name(hdlc), skb->data[i]); + return 1; + } + i++; + + dlci = status_to_dlci(hdlc, skb->data+i, &state); + pvc = find_pvc(hdlc, dlci); + + if (pvc) + pvc->newstate = state; + else if (state == PVC_STATE_NEW) + printk(KERN_INFO "%s: new PVC available, DLCI=%u\n", + hdlc_to_name(hdlc), dlci); + + i += stat_len; + } + + pvc = hdlc->first_pvc; + + while (pvc) { + if (pvc->newstate == PVC_STATE_NEW) + pvc->newstate = PVC_STATE_ACTIVE; + + pvc->newstate |= (pvc->state & + ~(PVC_STATE_NEW|PVC_STATE_ACTIVE)); + if (pvc->state != pvc->newstate) { + pvc->state = pvc->newstate; + fr_log_dlci_active(pvc); + } + pvc = pvc->next; + } + + /* Next full report after N391 polls */ + hdlc->lmi.N391cnt = hdlc->lmi.N391; + + return 0; +} + + + +static void fr_netif(hdlc_device *hdlc, struct sk_buff *skb) +{ + fr_hdr *fh = (fr_hdr*)skb->data; + u8 *data = skb->data; + u16 dlci; + pvc_device *pvc; + + if (skb->len<4 || fh->ea1 || data[2] != FR_UI) + goto rx_error; + + dlci = q922_to_dlci(skb->data); + + if (dlci == LMI_DLCI) { + if (data[3] == LMI_PROTO) { + if (fr_lmi_recv(hdlc, skb)) + goto rx_error; + else { + /* No request pending */ + hdlc->lmi.state &= ~LINK_STATE_REQUEST; + hdlc->lmi.last_poll = jiffies; + dev_kfree_skb_any(skb); + return; + } + } + + printk(KERN_INFO "%s: Received non-LMI frame with LMI DLCI\n", + hdlc_to_name(hdlc)); + goto rx_error; + } + + pvc = find_pvc(hdlc, dlci); + if (!pvc) { +#ifdef DEBUG_PKT + printk(KERN_INFO "%s: No PVC for received frame's DLCI %d\n", + hdlc_to_name(hdlc), dlci); +#endif + goto rx_error; + } + + if ((pvc->netdev.flags & IFF_UP) == 0) { +#ifdef DEBUG_PKT + printk(KERN_INFO "%s: PVC for received frame's DLCI %d is down\n", + hdlc_to_name(hdlc), dlci); +#endif + goto rx_error; + } + + pvc->stats.rx_packets++; /* PVC traffic */ + pvc->stats.rx_bytes += skb->len; + + if ((pvc->state & PVC_STATE_FECN) != (fh->fecn ? PVC_STATE_FECN : 0)) { +#ifdef DEBUG_FECN + printk(KERN_DEBUG "%s: FECN O%s\n", pvc_to_name(pvc), + fh->fecn ? "N" : "FF"); +#endif + pvc->state ^= PVC_STATE_FECN; + } + + if ((pvc->state & PVC_STATE_BECN) != (fh->becn ? PVC_STATE_BECN : 0)) { +#ifdef DEBUG_FECN + printk(KERN_DEBUG "%s: BECN O%s\n", pvc_to_name(pvc), + fh->becn ? "N" : "FF"); +#endif + pvc->state ^= PVC_STATE_BECN; + } + + if (pvc->state & PVC_STATE_BECN) + pvc->stats.rx_compressed++; + + if (data[3] == NLPID_IP) { + skb_pull(skb, 4); /* Remove 4-byte header (hdr, UI, NLPID) */ + skb->protocol = htons(ETH_P_IP); + skb->dev = &pvc->netdev; + netif_rx(skb); + return; + } + + + if (data[3] == NLPID_IPV6) { + skb_pull(skb, 4); /* Remove 4-byte header (hdr, UI, NLPID) */ + skb->protocol = htons(ETH_P_IPV6); + skb->dev = &pvc->netdev; + netif_rx(skb); + return; + } + + if (data[3] == FR_PAD && data[4] == NLPID_SNAP && data[5] == FR_PAD && + data[6] == FR_PAD && data[7] == FR_PAD && + ((data[8]<<8) | data[9]) == ETH_P_ARP) { + skb_pull(skb, 10); + skb->protocol = htons(ETH_P_ARP); + skb->dev = &pvc->netdev; + netif_rx(skb); + return; + } + + printk(KERN_INFO "%s: Unusupported protocol %x\n", + hdlc_to_name(hdlc), data[3]); + dev_kfree_skb_any(skb); + return; + + rx_error: + hdlc->stats.rx_errors++; /* Mark error */ + dev_kfree_skb_any(skb); +} + + + +static void fr_cisco_open(hdlc_device *hdlc) +{ + hdlc->lmi.state = LINK_STATE_CHANGED; + hdlc->lmi.txseq = hdlc->lmi.rxseq = 0; + hdlc->lmi.last_errors = 0xFFFFFFFF; + hdlc->lmi.N391cnt = 0; + + init_timer(&hdlc->timer); + hdlc->timer.expires = jiffies + HZ; /* First poll after 1 second */ + hdlc->timer.function = mode_is(hdlc, MODE_FR) ? fr_timer : cisco_timer; + hdlc->timer.data = (unsigned long)hdlc; + add_timer(&hdlc->timer); +} + + + +static void fr_cisco_close(hdlc_device *hdlc) +{ + pvc_device *pvc = hdlc->first_pvc; + + del_timer_sync(&hdlc->timer); + + while(pvc) { /* NULL in Cisco mode */ + dev_close(&pvc->netdev); /* Shutdown all PVCs for this FRAD */ + pvc = pvc->next; + } +} + + + +/****************************************************************** + * + * generic HDLC routines + * + *****************************************************************/ + + + +static int hdlc_change_mtu(struct net_device *dev, int new_mtu) +{ + if ((new_mtu < 68) || (new_mtu > HDLC_MAX_MTU)) + return -EINVAL; + dev->mtu = new_mtu; + return 0; +} + + + +/******************************************************** + * + * PVC device routines + * + *******************************************************/ + +static int pvc_open(struct net_device *dev) +{ + pvc_device *pvc = dev_to_pvc(dev); + int result = 0; + + if ((hdlc_to_dev(pvc->master)->flags & IFF_UP) == 0) + return -EIO; /* Master must be UP in order to activate PVC */ + + memset(&(pvc->stats), 0, sizeof(struct net_device_stats)); + pvc->state = 0; + + if (!mode_is(pvc->master, MODE_SOFT) && pvc->master->open_pvc) + result = pvc->master->open_pvc(pvc); + if (result) + return result; + + pvc->master->lmi.state |= LINK_STATE_CHANGED; + return 0; +} + + + +static int pvc_close(struct net_device *dev) +{ + pvc_device *pvc = dev_to_pvc(dev); + pvc->state = 0; + + if (!mode_is(pvc->master, MODE_SOFT) && pvc->master->close_pvc) + pvc->master->close_pvc(pvc); + + pvc->master->lmi.state |= LINK_STATE_CHANGED; + return 0; +} + + + +static int pvc_xmit(struct sk_buff *skb, struct net_device *dev) +{ + pvc_device *pvc = dev_to_pvc(dev); + + if (pvc->state & PVC_STATE_ACTIVE) { + skb->dev = hdlc_to_dev(pvc->master); + pvc->stats.tx_bytes += skb->len; + pvc->stats.tx_packets++; + if (pvc->state & PVC_STATE_FECN) + pvc->stats.tx_compressed++; /* TX Congestion counter */ + dev_queue_xmit(skb); + } else { + pvc->stats.tx_dropped++; + dev_kfree_skb(skb); + } + + return 0; +} + + + +static struct net_device_stats *pvc_get_stats(struct net_device *dev) +{ + pvc_device *pvc = dev_to_pvc(dev); + return &pvc->stats; +} + + + +static int pvc_change_mtu(struct net_device *dev, int new_mtu) +{ + if ((new_mtu < 68) || (new_mtu > HDLC_MAX_MTU)) + return -EINVAL; + dev->mtu = new_mtu; + return 0; +} + + + +static void destroy_pvc_list(hdlc_device *hdlc) +{ + pvc_device *pvc = hdlc->first_pvc; + while(pvc) { + pvc_device *next = pvc->next; + unregister_netdevice(&pvc->netdev); + kfree(pvc); + pvc = next; + } + + hdlc->first_pvc = NULL; /* All PVCs destroyed */ + hdlc->pvc_count = 0; + hdlc->lmi.state |= LINK_STATE_CHANGED; +} + + + +/******************************************************** + * + * X.25 protocol support routines + * + *******************************************************/ + +#ifdef CONFIG_HDLC_X25 +/* These functions are callbacks called by LAPB layer */ + +void x25_connect_disconnect(void *token, int reason, int code) +{ + hdlc_device *hdlc = token; + struct sk_buff *skb; + unsigned char *ptr; + + if ((skb = dev_alloc_skb(1)) == NULL) { + printk(KERN_ERR "%s: out of memory\n", hdlc_to_name(hdlc)); + return; + } + + ptr = skb_put(skb, 1); + *ptr = code; + + skb->dev = hdlc_to_dev(hdlc); + skb->protocol = htons(ETH_P_X25); + skb->mac.raw = skb->data; + skb->pkt_type = PACKET_HOST; + + netif_rx(skb); +} + +void x25_connected(void *token, int reason) +{ + x25_connect_disconnect(token, reason, 1); +} + +void x25_disconnected(void *token, int reason) +{ + x25_connect_disconnect(token, reason, 2); +} + + +int x25_data_indication(void *token, struct sk_buff *skb) +{ + hdlc_device *hdlc = token; + unsigned char *ptr; + + ptr = skb_push(skb, 1); + *ptr = 0; + + skb->dev = hdlc_to_dev(hdlc); + skb->protocol = htons(ETH_P_X25); + skb->mac.raw = skb->data; + skb->pkt_type = PACKET_HOST; + + return netif_rx(skb); +} + + +void x25_data_transmit(void *token, struct sk_buff *skb) +{ + hdlc_device *hdlc = token; + hdlc->xmit(hdlc, skb); /* Ignore return value :-( */ +} +#endif /* CONFIG_HDLC_X25 */ + + +/******************************************************** + * + * HDLC device routines + * + *******************************************************/ + +static int hdlc_open(struct net_device *dev) +{ + hdlc_device *hdlc = dev_to_hdlc(dev); + int result; + + if (hdlc->mode == MODE_NONE) + return -ENOSYS; + + memset(&(hdlc->stats), 0, sizeof(struct net_device_stats)); + + if (mode_is(hdlc, MODE_FR | MODE_SOFT) || + mode_is(hdlc, MODE_CISCO | MODE_SOFT)) + fr_cisco_open(hdlc); +#ifdef CONFIG_HDLC_PPP + else if (mode_is(hdlc, MODE_PPP | MODE_SOFT)) { + sppp_attach(&hdlc->pppdev); + /* sppp_attach nukes them. We don't need syncppp's ioctl */ + dev->do_ioctl = hdlc_ioctl; + hdlc->pppdev.sppp.pp_flags &= ~PP_CISCO; + dev->type = ARPHRD_PPP; + result = sppp_open(dev); + if (result) { + sppp_detach(dev); + return result; + } + } +#endif +#ifdef CONFIG_HDLC_X25 + else if (mode_is(hdlc, MODE_X25)) { + struct lapb_register_struct cb; + + cb.connect_confirmation = x25_connected; + cb.connect_indication = x25_connected; + cb.disconnect_confirmation = x25_disconnected; + cb.disconnect_indication = x25_disconnected; + cb.data_indication = x25_data_indication; + cb.data_transmit = x25_data_transmit; + + result = lapb_register(hdlc, &cb); + if (result != LAPB_OK) + return result; + } +#endif + result = hdlc->open(hdlc); + if (result) { + if (mode_is(hdlc, MODE_FR | MODE_SOFT) || + mode_is(hdlc, MODE_CISCO | MODE_SOFT)) + fr_cisco_close(hdlc); +#ifdef CONFIG_HDLC_PPP + else if (mode_is(hdlc, MODE_PPP | MODE_SOFT)) { + sppp_close(dev); + sppp_detach(dev); + dev->rebuild_header = NULL; + dev->change_mtu = hdlc_change_mtu; + dev->mtu = HDLC_MAX_MTU; + dev->hard_header_len = 16; + } +#endif +#ifdef CONFIG_HDLC_X25 + else if (mode_is(hdlc, MODE_X25)) + lapb_unregister(hdlc); +#endif + } + + return result; +} + + + +static int hdlc_close(struct net_device *dev) +{ + hdlc_device *hdlc = dev_to_hdlc(dev); + + hdlc->close(hdlc); + + if (mode_is(hdlc, MODE_FR | MODE_SOFT) || + mode_is(hdlc, MODE_CISCO | MODE_SOFT)) + fr_cisco_close(hdlc); +#ifdef CONFIG_HDLC_PPP + else if (mode_is(hdlc, MODE_PPP | MODE_SOFT)) { + sppp_close(dev); + sppp_detach(dev); + dev->rebuild_header = NULL; + dev->change_mtu = hdlc_change_mtu; + dev->mtu = HDLC_MAX_MTU; + dev->hard_header_len = 16; + } +#endif +#ifdef CONFIG_HDLC_X25 + else if (mode_is(hdlc, MODE_X25)) + lapb_unregister(hdlc); +#endif + return 0; +} + + + +static int hdlc_xmit(struct sk_buff *skb, struct net_device *dev) +{ + hdlc_device *hdlc = dev_to_hdlc(dev); + +#ifdef CONFIG_HDLC_X25 + if (mode_is(hdlc, MODE_X25 | MODE_SOFT)) { + int result; + + + /* X.25 to LAPB */ + switch (skb->data[0]) { + case 0: /* Data to be transmitted */ + skb_pull(skb, 1); + if ((result = lapb_data_request(hdlc, skb)) != LAPB_OK) + dev_kfree_skb(skb); + return 0; + + case 1: + if ((result = lapb_connect_request(hdlc))!= LAPB_OK) { + if (result == LAPB_CONNECTED) { + /* Send connect confirm. msg to level 3 */ + x25_connected(hdlc, 0); + } else { + printk(KERN_ERR "%s: LAPB connect " + "request failed, error code = " + "%i\n", hdlc_to_name(hdlc), + result); + } + } + break; + + case 2: + if ((result=lapb_disconnect_request(hdlc))!=LAPB_OK) { + if (result == LAPB_NOTCONNECTED) { + /* Send disconnect confirm. msg to level 3 */ + x25_disconnected(hdlc, 0); + } else { + printk(KERN_ERR "%s: LAPB disconnect " + "request failed, error code = " + "%i\n", hdlc_to_name(hdlc), + result); + } + } + break; + + default: /* to be defined */ + } + + dev_kfree_skb(skb); + return 0; + } /* MODE_X25 */ +#endif /* CONFIG_HDLC_X25 */ + + return hdlc->xmit(hdlc, skb); +} + + + +void hdlc_netif_rx(hdlc_device *hdlc, struct sk_buff *skb) +{ +/* skb contains raw HDLC frame, in both hard- and software modes */ + skb->mac.raw = skb->data; + + switch(hdlc->mode & MODE_MASK) { + case MODE_HDLC: + skb->protocol = htons(ETH_P_IP); + skb->dev = hdlc_to_dev(hdlc); + netif_rx(skb); + return; + + case MODE_FR: + fr_netif(hdlc, skb); + return; + + case MODE_CISCO: + cisco_netif(hdlc, skb); + return; + +#ifdef CONFIG_HDLC_PPP + case MODE_PPP: +#if 0 + sppp_input(hdlc_to_dev(hdlc), skb); +#else + skb->protocol = htons(ETH_P_WAN_PPP); + skb->dev = hdlc_to_dev(hdlc); + netif_rx(skb); +#endif + return; +#endif +#ifdef CONFIG_HDLC_X25 + case MODE_X25: + skb->dev = hdlc_to_dev(hdlc); + if (lapb_data_received(hdlc, skb) == LAPB_OK) + return; + break; +#endif + } + + hdlc->stats.rx_errors++; + dev_kfree_skb_any(skb); +} + + + +static struct net_device_stats *hdlc_get_stats(struct net_device *dev) +{ + return &dev_to_hdlc(dev)->stats; +} + + + +static int hdlc_set_mode(hdlc_device *hdlc, int mode) +{ + int result = -1; /* Default to soft modes */ + struct net_device *dev = hdlc_to_dev(hdlc); + + if(!capable(CAP_NET_ADMIN)) + return -EPERM; + + if(dev->flags & IFF_UP) + return -EBUSY; + + dev->addr_len = 0; + dev->hard_header = NULL; + hdlc->mode = MODE_NONE; + + if (!(mode & MODE_SOFT)) + switch(mode & MODE_MASK) { + case MODE_HDLC: + result = hdlc->set_mode ? + hdlc->set_mode(hdlc, MODE_HDLC) : 0; + break; + + case MODE_CISCO: /* By card */ +#ifdef CONFIG_HDLC_PPP + case MODE_PPP: +#endif +#ifdef CONFIG_HDLC_X25 + case MODE_X25: +#endif + case MODE_FR: + result = hdlc->set_mode ? + hdlc->set_mode(hdlc, mode) : -ENOSYS; + break; + + default: + return -EINVAL; + } + + if (result) { + mode |= MODE_SOFT; /* Try "host software" protocol */ + + switch(mode & MODE_MASK) { + case MODE_CISCO: + dev->hard_header = cisco_hard_header; + break; + +#ifdef CONFIG_HDLC_PPP + case MODE_PPP: + break; +#endif +#ifdef CONFIG_HDLC_X25 + case MODE_X25: + break; +#endif + + case MODE_FR: + dev->hard_header = fr_hard_header; + dev->addr_len = 2; + *(u16*)dev->dev_addr = htons(LMI_DLCI); + dlci_to_q922(dev->broadcast, LMI_DLCI); + break; + + default: + return -EINVAL; + } + + result = hdlc->set_mode ? + hdlc->set_mode(hdlc, MODE_HDLC) : 0; + } + + if (result) + return result; + + hdlc->mode = mode; + switch(mode & MODE_MASK) { +#ifdef CONFIG_HDLC_PPP + case MODE_PPP: dev->type = ARPHRD_PPP; break; +#endif +#ifdef CONFIG_HDLC_X25 + case MODE_X25: dev->type = ARPHRD_X25; break; +#endif + case MODE_FR: dev->type = ARPHRD_FRAD; break; + case MODE_CISCO: dev->type = ARPHRD_CISCO; break; + default: dev->type = ARPHRD_RAWHDLC; + } + + memset(&(hdlc->stats), 0, sizeof(struct net_device_stats)); + destroy_pvc_list(hdlc); + return 0; +} + + + +static int hdlc_fr_pvc(hdlc_device *hdlc, int dlci) +{ + pvc_device **pvc_p = &hdlc->first_pvc; + pvc_device *pvc; + int result, create = 1; /* Create or delete PVC */ + + if(!capable(CAP_NET_ADMIN)) + return -EPERM; + + if(dlci<0) { + dlci = -dlci; + create = 0; + } + + if(dlci <= 0 || dlci >= 1024) + return -EINVAL; /* Only 10 bits for DLCI, DLCI=0 is reserved */ + + if(!mode_is(hdlc, MODE_FR)) + return -EINVAL; /* Only meaningfull on FR */ + + while(*pvc_p) { + if (netdev_dlci(&(*pvc_p)->netdev) == dlci) + break; + pvc_p = &(*pvc_p)->next; + } + + if (create) { /* Create PVC */ + if (*pvc_p != NULL) + return -EEXIST; + + pvc = *pvc_p = kmalloc(sizeof(pvc_device), GFP_KERNEL); + if (!pvc) { + printk(KERN_WARNING "%s: Memory squeeze on " + "hdlc_fr_pvc()\n", hdlc_to_name(hdlc)); + return -ENOBUFS; + } + memset(pvc, 0, sizeof(pvc_device)); + + pvc->netdev.hard_start_xmit = pvc_xmit; + pvc->netdev.get_stats = pvc_get_stats; + pvc->netdev.open = pvc_open; + pvc->netdev.stop = pvc_close; + pvc->netdev.change_mtu = pvc_change_mtu; + pvc->netdev.mtu = HDLC_MAX_MTU; + + pvc->netdev.type = ARPHRD_DLCI; + pvc->netdev.hard_header_len = 16; + pvc->netdev.hard_header = fr_hard_header; + pvc->netdev.tx_queue_len = 0; + pvc->netdev.flags = IFF_POINTOPOINT; + + dev_init_buffers(&pvc->netdev); + + pvc->master = hdlc; + *(u16*)pvc->netdev.dev_addr = htons(dlci); + dlci_to_q922(pvc->netdev.broadcast, dlci); + pvc->netdev.addr_len = 2; + pvc->netdev.irq = hdlc_to_dev(hdlc)->irq; + + result = dev_alloc_name(&pvc->netdev, "pvc%d"); + if (result < 0) { + kfree(pvc); + *pvc_p = NULL; + return result; + } + + if (register_netdevice(&pvc->netdev) != 0) { + kfree(pvc); + *pvc_p = NULL; + return -EIO; + } + + if (!mode_is(hdlc, MODE_SOFT) && hdlc->create_pvc) { + result = hdlc->create_pvc(pvc); + if (result) { + unregister_netdevice(&pvc->netdev); + kfree(pvc); + *pvc_p = NULL; + return result; + } + } + + hdlc->lmi.state |= LINK_STATE_CHANGED; + hdlc->pvc_count++; + return 0; + } + + if (*pvc_p == NULL) /* Delete PVC */ + return -ENOENT; + + pvc = *pvc_p; + + if (pvc->netdev.flags & IFF_UP) + return -EBUSY; /* PVC in use */ + + if (!mode_is(hdlc, MODE_SOFT) && hdlc->destroy_pvc) + hdlc->destroy_pvc(pvc); + + hdlc->lmi.state |= LINK_STATE_CHANGED; + hdlc->pvc_count--; + *pvc_p = pvc->next; + unregister_netdevice(&pvc->netdev); + kfree(pvc); + return 0; +} + + + +static int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + hdlc_device *hdlc = dev_to_hdlc(dev); + + switch(cmd) { + case HDLCGMODE: + ifr->ifr_ifru.ifru_ivalue = hdlc->mode; + return 0; + + case HDLCSMODE: + return hdlc_set_mode(hdlc, ifr->ifr_ifru.ifru_ivalue); + + case HDLCPVC: + return hdlc_fr_pvc(hdlc, ifr->ifr_ifru.ifru_ivalue); + + default: + if (hdlc->ioctl != NULL) + return hdlc->ioctl(hdlc, ifr, cmd); + } + + return -EINVAL; +} + + + +static int hdlc_init(struct net_device *dev) +{ + hdlc_device *hdlc = dev_to_hdlc(dev); + + memset(&(hdlc->stats), 0, sizeof(struct net_device_stats)); + + dev->get_stats = hdlc_get_stats; + dev->open = hdlc_open; + dev->stop = hdlc_close; + dev->hard_start_xmit = hdlc_xmit; + dev->do_ioctl = hdlc_ioctl; + dev->change_mtu = hdlc_change_mtu; + dev->mtu = HDLC_MAX_MTU; + + dev->type = ARPHRD_RAWHDLC; + dev->hard_header_len = 16; + + dev->flags = IFF_POINTOPOINT | IFF_NOARP; + + dev_init_buffers(dev); + return 0; +} + + + +int register_hdlc_device(hdlc_device *hdlc) +{ + int result; + struct net_device *dev = hdlc_to_dev(hdlc); + + dev->init = hdlc_init; + dev->priv = &hdlc->syncppp_ptr; + hdlc->syncppp_ptr = &hdlc->pppdev; + hdlc->pppdev.dev = dev; + hdlc->mode = MODE_NONE; + hdlc->lmi.T391 = 10; /* polling verification timer */ + hdlc->lmi.T392 = 15; /* link integrity verification polling timer */ + hdlc->lmi.N391 = 6; /* full status polling counter */ + hdlc->lmi.N392 = 3; /* error threshold */ + hdlc->lmi.N393 = 4; /* monitored events count */ + + result = dev_alloc_name(dev, "hdlc%d"); + if (result<0) + return result; + + result = register_netdev(dev); + if (result != 0) + return -EIO; + + dev_init_buffers(dev); + MOD_INC_USE_COUNT; + return 0; +} + + + +void unregister_hdlc_device(hdlc_device *hdlc) +{ + destroy_pvc_list(hdlc); + unregister_netdev(hdlc_to_dev(hdlc)); + MOD_DEC_USE_COUNT; +} + +MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>"); +MODULE_DESCRIPTION("HDLC support module"); + +EXPORT_SYMBOL(hdlc_netif_rx); +EXPORT_SYMBOL(register_hdlc_device); +EXPORT_SYMBOL(unregister_hdlc_device); + +static int __init hdlc_module_init(void) +{ + printk(KERN_INFO "%s\n", version); + return 0; +} + + +module_init(hdlc_module_init); diff --git a/drivers/net/wan/hostess_sv11.c b/drivers/net/wan/hostess_sv11.c index 4c7bf4bf4..cdea3804d 100644 --- a/drivers/net/wan/hostess_sv11.c +++ b/drivers/net/wan/hostess_sv11.c @@ -34,7 +34,7 @@ #include <asm/io.h> #include <asm/dma.h> #include <asm/byteorder.h> -#include "syncppp.h" +#include <net/syncppp.h> #include "z85230.h" static int dma; @@ -59,7 +59,7 @@ static void hostess_input(struct z8530_channel *c, struct sk_buff *skb) { /* Drop the CRC - its not a good idea to try and negotiate it ;) */ skb_trim(skb, skb->len-2); - skb->protocol=htons(ETH_P_WAN_PPP); + skb->protocol=__constant_htons(ETH_P_WAN_PPP); skb->mac.raw=skb->data; skb->dev=c->netdevice; /* @@ -67,6 +67,7 @@ static void hostess_input(struct z8530_channel *c, struct sk_buff *skb) * it right now. */ netif_rx(skb); + c->netdevice->last_rx = jiffies; } /* diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c index eb327f0f9..a87f8b249 100644 --- a/drivers/net/wan/lmc/lmc_main.c +++ b/drivers/net/wan/lmc/lmc_main.c @@ -67,7 +67,7 @@ #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/skbuff.h> -#include "../syncppp.h" +#include <net/syncppp.h> #include <linux/inet.h> #if LINUX_VERSION_CODE >= 0x20200 @@ -77,15 +77,7 @@ #define ARPHRD_HDLC 513 #endif -#ifdef MODULE -#ifdef MODVERSIONS -#include <linux/modversions.h> -#endif #include <linux/module.h> -#else -#define MOD_INC_USE_COUNT -#define MOD_DEC_USE_COUNT -#endif #define DRIVER_MAJOR_VERSION 1 #define DRIVER_MINOR_VERSION 34 @@ -166,7 +158,7 @@ int lmc_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) /*fold00*/ /* * Most functions mess with the structure - * Disable interupts while we do the polling + * Disable interrupts while we do the polling */ spin_lock_irqsave(&sc->lmc_lock, flags); @@ -546,7 +538,7 @@ int lmc_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) /*fold00*/ udelay(50); /* - * Clear reset and activate programing lines + * Clear reset and activate programming lines * Reset: Input * DP: Input * Clock: Output @@ -584,7 +576,7 @@ int lmc_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) /*fold00*/ sc->lmc_gpio |= LMC_GEP_DATA; /* Data is 1 */ break; default: - printk(KERN_WARNING "%s Bad data in xilinx programing data at %d, got %d wanted 0 or 1\n", dev->name, pos, data[pos]); + printk(KERN_WARNING "%s Bad data in xilinx programming data at %d, got %d wanted 0 or 1\n", dev->name, pos, data[pos]); sc->lmc_gpio |= LMC_GEP_DATA; /* Assume it's 1 */ } sc->lmc_gpio &= ~LMC_GEP_CLK; /* Clock to zero */ @@ -598,13 +590,13 @@ int lmc_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) /*fold00*/ udelay(1); } if((LMC_CSR_READ(sc, csr_gp) & LMC_GEP_INIT) == 0){ - printk(KERN_WARNING "%s: Reprograming FAILED. Needs to be reprogramed. (corrupted data)\n", dev->name); + printk(KERN_WARNING "%s: Reprogramming FAILED. Needs to be reprogrammed. (corrupted data)\n", dev->name); } else if((LMC_CSR_READ(sc, csr_gp) & LMC_GEP_DP) == 0){ - printk(KERN_WARNING "%s: Reprograming FAILED. Needs to be reprogramed. (done)\n", dev->name); + printk(KERN_WARNING "%s: Reprogramming FAILED. Needs to be reprogrammed. (done)\n", dev->name); } else { - printk(KERN_DEBUG "%s: Done reprograming Xilinx, %d bits, good luck!\n", dev->name, pos); + printk(KERN_DEBUG "%s: Done reprogramming Xilinx, %d bits, good luck!\n", dev->name, pos); } lmc_gpio_mkinput(sc, 0xff); @@ -662,12 +654,13 @@ static void lmc_watchdog (unsigned long data) /*fold00*/ if(sc->check != 0xBEAFCAFE){ printk("LMC: Corrupt net_device stuct, breaking out\n"); + spin_unlock_irqrestore(&sc->lmc_lock, flags); return; } /* Make sure the tx jabber and rx watchdog are off, - * and the transmit and recieve processes are running. + * and the transmit and receive processes are running. */ LMC_CSR_WRITE (sc, csr_15, 0x00000011); @@ -793,7 +786,7 @@ static void lmc_watchdog (unsigned long data) /*fold00*/ if(sc->failed_recv_alloc == 1){ /* * We failed to alloc mem in the - * interupt halder, go through the rings + * interrupt handler, go through the rings * and rebuild them */ sc->failed_recv_alloc = 0; @@ -1356,7 +1349,7 @@ static int lmc_ifdown (struct net_device *dev) /*fold00*/ /* Stop Tx and Rx on the chip */ csr6 = LMC_CSR_READ (sc, csr_command); csr6 &= ~LMC_DEC_ST; /* Turn off the Transmission bit */ - csr6 &= ~LMC_DEC_SR; /* Turn off the Recieve bit */ + csr6 &= ~LMC_DEC_SR; /* Turn off the Receive bit */ LMC_CSR_WRITE (sc, csr_command, csr6); dev->flags &= ~IFF_RUNNING; @@ -1425,7 +1418,7 @@ static void lmc_interrupt (int irq, void *dev_instance, struct pt_regs *regs) /* spin_lock(&sc->lmc_lock); /* - * Read the csr to find what interupts we have (if any) + * Read the csr to find what interrupts we have (if any) */ csr = LMC_CSR_READ (sc, csr_status); @@ -1441,7 +1434,7 @@ static void lmc_interrupt (int irq, void *dev_instance, struct pt_regs *regs) /* /* always go through this loop at least once */ while (csr & sc->lmc_intrmask) { /* - * Clear interupt bits, we handle all case below + * Clear interrupt bits, we handle all case below */ LMC_CSR_WRITE (sc, csr_status, csr); @@ -1464,7 +1457,7 @@ static void lmc_interrupt (int irq, void *dev_instance, struct pt_regs *regs) /* } if (csr & TULIP_STS_RXINTR){ - lmc_trace(dev, "rx interupt"); + lmc_trace(dev, "rx interrupt"); lmc_rx (dev); } @@ -1588,7 +1581,7 @@ static void lmc_interrupt (int irq, void *dev_instance, struct pt_regs *regs) /* /* * Get current csr status to make sure - * we've cleared all interupts + * we've cleared all interrupts */ csr = LMC_CSR_READ (sc, csr_status); } /* end interrupt loop */ @@ -1599,8 +1592,6 @@ lmc_int_fail_out: spin_unlock(&sc->lmc_lock); lmc_trace(dev, "lmc_interrupt out"); - - return; } static int lmc_start_xmit (struct sk_buff *skb, struct net_device *dev) /*fold00*/ @@ -1843,6 +1834,7 @@ static int lmc_rx (struct net_device *dev) /*fold00*/ dev->last_rx = jiffies; sc->stats.rx_packets++; + sc->stats.rx_bytes += len; LMC_CONSOLE_LOG("recv", skb->data, len); @@ -1879,12 +1871,12 @@ static int lmc_rx (struct net_device *dev) /*fold00*/ sc->lmc_rxq[i] = nsb; nsb->dev = dev; sc->lmc_rxring[i].buffer1 = virt_to_bus (nsb->tail); - /* Transfered to 21140 below */ + /* Transferred to 21140 below */ } else { /* * We've run out of memory, stop trying to allocate - * memory and exit the interupt handler + * memory and exit the interrupt handler * * The chip may run out of receivers and stop * in which care we'll try to allocate the buffer @@ -2129,7 +2121,7 @@ static void lmc_softreset (lmc_softc_t * const sc) /*fold00*/ lmc_trace(sc->lmc_device, "lmc_softreset in"); - /* Initialize the recieve rings and buffers. */ + /* Initialize the receive rings and buffers. */ sc->lmc_txfull = 0; sc->lmc_next_rx = 0; sc->lmc_next_tx = 0; @@ -2138,7 +2130,7 @@ static void lmc_softreset (lmc_softc_t * const sc) /*fold00*/ /* * Setup each one of the receiver buffers - * allocate an skbuff for each one, setup the the descriptor table + * allocate an skbuff for each one, setup the descriptor table * and point each buffer at the next one */ diff --git a/drivers/net/wan/lmc/lmc_media.c b/drivers/net/wan/lmc/lmc_media.c index e8fd6b617..1a02f6a27 100644 --- a/drivers/net/wan/lmc/lmc_media.c +++ b/drivers/net/wan/lmc/lmc_media.c @@ -29,7 +29,7 @@ #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/skbuff.h> -#include "../syncppp.h" +#include <net/syncppp.h> #include <linux/inet.h> #if LINUX_VERSION_CODE >= 0x20200 diff --git a/drivers/net/wan/lmc/lmc_proto.c b/drivers/net/wan/lmc/lmc_proto.c index 3760c2585..a9d2f42f7 100644 --- a/drivers/net/wan/lmc/lmc_proto.c +++ b/drivers/net/wan/lmc/lmc_proto.c @@ -43,7 +43,7 @@ #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/skbuff.h> -#include "../syncppp.h" +#include <net/syncppp.h> #include <linux/inet.h> #include <linux/tqueue.h> #include <linux/proc_fs.h> @@ -61,7 +61,6 @@ * compiled without referencing any of the sync ppp routines. */ #ifdef SPPPSTUB -#define SYNC_PPP_init() (void)0 #define SPPP_detach(d) (void)0 #define SPPP_open(d) 0 #define SPPP_reopen(d) (void)0 @@ -70,7 +69,6 @@ #define SPPP_do_ioctl(d,i,c) -EOPNOTSUPP #else #if LINUX_VERSION_CODE < 0x20363 -#define SYNC_PPP_init sync_ppp_init #define SPPP_attach(x) sppp_attach((struct ppp_device *)(x)->lmc_device) #define SPPP_detach(x) sppp_detach((x)->lmc_device) #define SPPP_open(x) sppp_open((x)->lmc_device) @@ -78,7 +76,6 @@ #define SPPP_close(x) sppp_close((x)->lmc_device) #define SPPP_do_ioctl(x, y, z) sppp_do_ioctl((x)->lmc_device, (y), (z)) #else -#define SYNC_PPP_init sync_ppp_init #define SPPP_attach(x) sppp_attach((x)->pd) #define SPPP_detach(x) sppp_detach((x)->pd->dev) #define SPPP_open(x) sppp_open((x)->pd->dev) @@ -88,21 +85,19 @@ #endif #endif -static int lmc_first_ppp_load = 0; - // init void lmc_proto_init(lmc_softc_t *sc) /*FOLD00*/ { lmc_trace(sc->lmc_device, "lmc_proto_init in"); switch(sc->if_type){ case LMC_PPP: - if(lmc_first_ppp_load == 0) -#ifndef MODULE - SYNC_PPP_init(); -#endif #if LINUX_VERSION_CODE >= 0x20363 sc->pd = kmalloc(sizeof(struct ppp_device), GFP_KERNEL); + if (!sc->pd) { + printk("lmc_proto_init(): kmalloc failure!\n"); + return; + } sc->pd->dev = sc->lmc_device; #endif sc->if_ptr = sc->pd; diff --git a/drivers/net/wan/lmc/lmc_var.h b/drivers/net/wan/lmc/lmc_var.h index f4e92e432..ee022f373 100644 --- a/drivers/net/wan/lmc/lmc_var.h +++ b/drivers/net/wan/lmc/lmc_var.h @@ -482,10 +482,10 @@ struct lmc___softc { #define TULIP_STS_NORMALINTR 0x00010000L /* (RW) Normal Interrupt */ #define TULIP_STS_ABNRMLINTR 0x00008000L /* (RW) Abnormal Interrupt */ -#define TULIP_STS_ERI 0x00004000L /* (RW) Early Receive Interupt */ +#define TULIP_STS_ERI 0x00004000L /* (RW) Early Receive Interrupt */ #define TULIP_STS_SYSERROR 0x00002000L /* (RW) System Error */ #define TULIP_STS_GTE 0x00000800L /* (RW) General Pupose Timer Exp */ -#define TULIP_STS_ETI 0x00000400L /* (RW) Early Transmit Interupt */ +#define TULIP_STS_ETI 0x00000400L /* (RW) Early Transmit Interrupt */ #define TULIP_STS_RXWT 0x00000200L /* (RW) Receiver Watchdog Timeout */ #define TULIP_STS_RXSTOPPED 0x00000100L /* (RW) Receiver Process Stopped */ #define TULIP_STS_RXNOBUF 0x00000080L /* (RW) Receive Buf Unavail */ diff --git a/drivers/net/wan/n2.c b/drivers/net/wan/n2.c new file mode 100644 index 000000000..e64eed867 --- /dev/null +++ b/drivers/net/wan/n2.c @@ -0,0 +1,590 @@ +/* + * SDL Inc. RISCom/N2 synchronous serial card driver for Linux + * + * Copyright (C) 1998-2000 Krzysztof Halasa <khc@pm.waw.pl> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * For information see http://hq.pm.waw.pl/hdlc/ + * + * Note: integrated CSU/DSU/DDS are not supported by this driver + * + * Sources of information: + * Hitachi HD64570 SCA User's Manual + * SDL Inc. PPP/HDLC/CISCO driver + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/sched.h> +#include <linux/types.h> +#include <linux/fcntl.h> +#include <linux/in.h> +#include <linux/string.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/ioport.h> +#include <linux/netdevice.h> +#include <linux/hdlc.h> +#include <asm/io.h> +#include "hd64570.h" + +#define DEBUG_RINGS +/* #define DEBUG_PKT */ + +static const char* version = "SDL RISCom/N2 driver revision: 1.02 for Linux 2.4"; +static const char* devname = "RISCom/N2"; + +#define USE_WINDOWSIZE 16384 +#define USE_BUS16BITS 1 +#define CLOCK_BASE 9830400 /* 9.8304 MHz */ + +#define N2_IOPORTS 0x10 + +static char *hw = NULL; /* pointer to hw=xxx command line string */ + +/* RISCom/N2 Board Registers */ + +/* PC Control Register */ +#define N2_PCR 0 +#define PCR_RUNSCA 1 /* Run 64570 */ +#define PCR_VPM 2 /* Enable VPM - needed if using RAM above 1 MB */ +#define PCR_ENWIN 4 /* Open window */ +#define PCR_BUS16 8 /* 16-bit bus */ + + +/* Memory Base Address Register */ +#define N2_BAR 2 + + +/* Page Scan Register */ +#define N2_PSR 4 +#define WIN16K 0x00 +#define WIN32K 0x20 +#define WIN64K 0x40 +#define PSR_WINBITS 0x60 +#define PSR_DMAEN 0x80 +#define PSR_PAGEBITS 0x0F + + +/* Modem Control Reg */ +#define N2_MCR 6 +#define CLOCK_OUT_PORT1 0x80 +#define CLOCK_OUT_PORT0 0x40 +#define TX422_PORT1 0x20 +#define TX422_PORT0 0x10 +#define DSR_PORT1 0x08 +#define DSR_PORT0 0x04 +#define DTR_PORT1 0x02 +#define DTR_PORT0 0x01 + + +typedef struct port_s { + hdlc_device hdlc; /* HDLC device struct - must be first */ + struct card_s *card; + spinlock_t lock; /* TX lock */ + int clkmode; /* clock mode */ + int clkrate; /* clock rate */ + int line; /* loopback only */ + u8 rxs, txs, tmc; /* SCA registers */ + u8 valid; /* port enabled */ + u8 phy_node; /* physical port # - 0 or 1 */ + u8 log_node; /* logical port # */ + u8 rxin; /* rx ring buffer 'in' pointer */ + u8 txin; /* tx ring buffer 'in' and 'last' pointers */ + u8 txlast; + u8 rxpart; /* partial frame received, next frame invalid*/ +}port_t; + + + +typedef struct card_s { + u8 *winbase; /* ISA window base address */ + u32 phy_winbase; /* ISA physical base address */ + u32 ram_size; /* number of bytes */ + u16 io; /* IO Base address */ + u16 buff_offset; /* offset of first buffer of first channel */ + u8 irq; /* IRQ (3-15) */ + u8 ring_buffers; /* number of buffers in a ring */ + + port_t ports[2]; + struct card_s *next_card; +}card_t; + + + +#define sca_reg(reg, card) (0x8000 | (card)->io | \ + ((reg) & 0x0F) | (((reg) & 0xF0) << 6)) +#define sca_in(reg, card) inb(sca_reg(reg, card)) +#define sca_out(value, reg, card) outb(value, sca_reg(reg, card)) +#define sca_inw(reg, card) inw(sca_reg(reg, card)) +#define sca_outw(value, reg, card) outw(value, sca_reg(reg, card)) + +#define port_to_card(port) ((port)->card) +#define log_node(port) ((port)->log_node) +#define phy_node(port) ((port)->phy_node) +#define winsize(card) (USE_WINDOWSIZE) +#define winbase(card) ((card)->winbase) +#define get_port(card, port) ((card)->ports[port].valid ? \ + &(card)->ports[port] : NULL) + + + +static __inline__ u8 sca_get_page(card_t *card) +{ + return inb(card->io + N2_PSR) & PSR_PAGEBITS; +} + + +static __inline__ void openwin(card_t *card, u8 page) +{ + u8 psr = inb(card->io + N2_PSR); + outb((psr & ~PSR_PAGEBITS) | page, card->io + N2_PSR); +} + + +static __inline__ void close_windows(card_t *card) +{ + outb(inb(card->io + N2_PCR) & ~PCR_ENWIN, card->io + N2_PCR); +} + + +#include "hd6457x.c" + + + +static int n2_set_clock(port_t *port, int value) +{ + card_t *card = port->card; + int io = card->io; + u8 mcr = inb(io + N2_MCR); + u8 msci = get_msci(port); + u8 rxs = port->rxs & CLK_BRG_MASK; + u8 txs = port->txs & CLK_BRG_MASK; + + switch(value) { + case CLOCK_EXT: + mcr &= port->phy_node ? ~CLOCK_OUT_PORT1 : ~CLOCK_OUT_PORT0; + rxs |= CLK_LINE_RX; /* RXC input */ + txs |= CLK_LINE_TX; /* TXC input */ + break; + + case CLOCK_INT: + mcr |= port->phy_node ? CLOCK_OUT_PORT1 : CLOCK_OUT_PORT0; + rxs |= CLK_BRG_RX; /* BRG output */ + txs |= CLK_RXCLK_TX; /* RX clock */ + break; + + case CLOCK_TXINT: + mcr |= port->phy_node ? CLOCK_OUT_PORT1 : CLOCK_OUT_PORT0; + rxs |= CLK_LINE_RX; /* RXC input */ + txs |= CLK_BRG_TX; /* BRG output */ + break; + + case CLOCK_TXFROMRX: + mcr |= port->phy_node ? CLOCK_OUT_PORT1 : CLOCK_OUT_PORT0; + rxs |= CLK_LINE_RX; /* RXC input */ + txs |= CLK_RXCLK_TX; /* RX clock */ + break; + + default: + return -EINVAL; + } + + outb(mcr, io + N2_MCR); + port->rxs = rxs; + port->txs = txs; + sca_out(rxs, msci + RXS, card); + sca_out(txs, msci + TXS, card); + port->clkmode = value; + return 0; +} + + + +static int n2_open(hdlc_device *hdlc) +{ + port_t *port = hdlc_to_port(hdlc); + int io = port->card->io; + u8 mcr = inb(io + N2_MCR) | (port->phy_node ? TX422_PORT1 : TX422_PORT0); + + MOD_INC_USE_COUNT; + mcr &= port->phy_node ? ~DTR_PORT1 : ~DTR_PORT0; /* set DTR ON */ + outb(mcr, io + N2_MCR); + + outb(inb(io + N2_PCR) | PCR_ENWIN, io + N2_PCR); /* open window */ + outb(inb(io + N2_PSR) | PSR_DMAEN, io + N2_PSR); /* enable dma */ + sca_open(hdlc); + n2_set_clock(port, port->clkmode); + return 0; +} + + + +static void n2_close(hdlc_device *hdlc) +{ + port_t *port = hdlc_to_port(hdlc); + int io = port->card->io; + u8 mcr = inb(io+N2_MCR) | (port->phy_node ? TX422_PORT1 : TX422_PORT0); + + sca_close(hdlc); + mcr |= port->phy_node ? DTR_PORT1 : DTR_PORT0; /* set DTR OFF */ + outb(mcr, io + N2_MCR); + MOD_DEC_USE_COUNT; +} + + + +static int n2_ioctl(hdlc_device *hdlc, struct ifreq *ifr, int cmd) +{ + int value = ifr->ifr_ifru.ifru_ivalue; + int result = 0; + port_t *port = hdlc_to_port(hdlc); + + if(!capable(CAP_NET_ADMIN)) + return -EPERM; + + switch(cmd) { + case HDLCSCLOCK: + result = n2_set_clock(port, value); + case HDLCGCLOCK: + value = port->clkmode; + break; + + case HDLCSCLOCKRATE: + port->clkrate = value; + sca_set_clock(port); + case HDLCGCLOCKRATE: + value = port->clkrate; + break; + + case HDLCSLINE: + result = sca_set_loopback(port, value); + case HDLCGLINE: + value = port->line; + break; + +#ifdef DEBUG_RINGS + case HDLCRUN: + sca_dump_rings(hdlc); + return 0; +#endif /* DEBUG_RINGS */ + + default: + return -EINVAL; + } + + ifr->ifr_ifru.ifru_ivalue = value; + return result; +} + + + +static u8 n2_count_page(card_t *card) +{ + u8 page; + int i, bcount = USE_WINDOWSIZE, wcount = USE_WINDOWSIZE/2; + u16 *dp = (u16*)card->winbase; + u8 *bp = (u8*)card->winbase; + u8 psr = inb(card->io + N2_PSR) & PSR_WINBITS; + + + for (page = 0; page < 16; page++) { + outb(psr | page, card->io + N2_PSR); /* select a page */ + writeb(page, dp); + if (readb(dp) != page) + break; /* If can't read back, no good memory */ + + outb(psr, card->io + N2_PSR); /* goto page 0 */ + if (readb(dp)) + break; /* If page 0 changed, then wrapped around */ + + outb(psr | page, card->io + N2_PSR); /* select page again */ + + /* first do byte tests */ + for (i = 0; i < bcount; i++) + writeb(i, bp + i); + for (i = 0; i < bcount; i++) + if (readb(bp + i) != (i & 0xff)) + return 0; + + for (i = 0; i < bcount; i++) + writeb(~i, bp + i); + for (i = 0; i < bcount; i++) + if (readb(bp + i) != (~i & 0xff)) + return 0; + + /* next do 16-bit tests */ + for (i = 0; i < wcount; i++) + writew(0x55AA, dp + i); + for (i = 0; i < wcount; i++) + if (readw(dp + i) != 0x55AA) + return 0; + + for (i = 0; i < wcount; i++) + writew(0xAA55, dp + i); + for (i = 0; i < wcount; i++) + if (readw(dp + i) != 0xAA55) + return 0; + + for (i = 0; i < wcount; i++) + writew(page, dp + i); + } + + return page; +} + + + +static void n2_destroy_card(card_t *card) +{ + int cnt; + + for (cnt = 0; cnt < 2; cnt++) + if (card->ports[cnt].card) + unregister_hdlc_device(&card->ports[cnt].hdlc); + + if (card->irq) + free_irq(card->irq, card); + + if (card->winbase) { + iounmap(card->winbase); + release_mem_region(card->phy_winbase, USE_WINDOWSIZE); + } + + if (card->io) + release_region(card->io, N2_IOPORTS); + kfree(card); +} + + + +static int n2_run(unsigned long io, unsigned long irq, unsigned long winbase, + long valid0, long valid1) +{ + card_t *card; + u8 cnt, pcr; + + if (io < 0x200 || io > 0x3FF || (io % N2_IOPORTS) != 0) { + printk(KERN_ERR "n2: invalid I/O port value\n"); + return -ENODEV; + } + + if (irq < 3 || irq > 15 || irq == 6) /* FIXME */ { + printk(KERN_ERR "n2: invalid IRQ value\n"); + return -ENODEV; + } + + if (winbase < 0xA0000 || winbase > 0xFFFFF || (winbase & 0xFFF) != 0) { + printk(KERN_ERR "n2: invalid RAM value\n"); + return -ENODEV; + } + + card = kmalloc(sizeof(card_t), GFP_KERNEL); + if (card == NULL) { + printk(KERN_ERR "n2: unable to allocate memory\n"); + return -ENOBUFS; + } + memset(card, 0, sizeof(card_t)); + + if (!request_region(io, N2_IOPORTS, devname)) { + printk(KERN_ERR "n2: I/O port region in use\n"); + n2_destroy_card(card); + return -EBUSY; + } + card->io = io; + + if (request_irq(irq, &sca_intr, 0, devname, card)) { + printk(KERN_ERR "n2: could not allocate IRQ\n"); + n2_destroy_card(card); + return(-EBUSY); + } + card->irq = irq; + + if (!request_mem_region(winbase, USE_WINDOWSIZE, devname)) { + printk(KERN_ERR "n2: could not request RAM window\n"); + n2_destroy_card(card); + return(-EBUSY); + } + card->phy_winbase = winbase; + card->winbase = ioremap(winbase, USE_WINDOWSIZE); + + outb(0, io + N2_PCR); + outb(winbase >> 12, io + N2_BAR); + + switch (USE_WINDOWSIZE) { + case 16384: + outb(WIN16K, io + N2_PSR); + break; + + case 32768: + outb(WIN32K, io + N2_PSR); + break; + + case 65536: + outb(WIN64K, io + N2_PSR); + break; + + default: + printk(KERN_ERR "n2: invalid window size\n"); + n2_destroy_card(card); + return -ENODEV; + } + + pcr = PCR_ENWIN | PCR_VPM | (USE_BUS16BITS ? PCR_BUS16 : 0); + outb(pcr, io + N2_PCR); + + cnt = n2_count_page(card); + if (!cnt) { + printk(KERN_ERR "n2: memory test failed.\n"); + n2_destroy_card(card); + return -EIO; + } + + card->ram_size = cnt * USE_WINDOWSIZE; + + /* 4 rings required for 2 ports, 2 rings for one port */ + card->ring_buffers = card->ram_size / + ((valid0 + valid1) * 2 * (sizeof(pkt_desc) + HDLC_MAX_MRU)); + + card->buff_offset = (valid0 + valid1) * 2 * (sizeof(pkt_desc)) + * card->ring_buffers; + + printk(KERN_DEBUG "n2: RISCom/N2 %u KB RAM, IRQ%u, " + "using %u packets rings\n", card->ram_size / 1024, card->irq, + card->ring_buffers); + + pcr |= PCR_RUNSCA; /* run SCA */ + outb(pcr, io + N2_PCR); + outb(0, io + N2_MCR); + + sca_init(card, 0); + for (cnt = 0; cnt < 2; cnt++) { + port_t *port = &card->ports[cnt]; + + if ((cnt == 0 && !valid0) || (cnt == 1 && !valid1)) + continue; + + port->phy_node = cnt; + port->valid = 1; + + if ((cnt == 1) && valid0) + port->log_node = 1; + + spin_lock_init(&port->lock); + hdlc_to_dev(&port->hdlc)->irq = irq; + hdlc_to_dev(&port->hdlc)->mem_start = winbase; + hdlc_to_dev(&port->hdlc)->mem_end = winbase + USE_WINDOWSIZE-1; + hdlc_to_dev(&port->hdlc)->tx_queue_len = 50; + port->hdlc.ioctl = n2_ioctl; + port->hdlc.open = n2_open; + port->hdlc.close = n2_close; + port->hdlc.xmit = sca_xmit; + + if (register_hdlc_device(&port->hdlc)) { + printk(KERN_WARNING "n2: unable to register hdlc " + "device\n"); + n2_destroy_card(card); + return -ENOBUFS; + } + port->card = card; + sca_init_sync_port(port); /* Set up SCA memory */ + + printk(KERN_INFO "%s: RISCom/N2 node %d\n", + hdlc_to_name(&port->hdlc), port->phy_node); + } + + *new_card = card; + new_card = &card->next_card; + + return 0; +} + + + +static int __init n2_init(void) +{ + if (hw==NULL) { +#ifdef MODULE + printk(KERN_INFO "n2: no card initialized\n"); +#endif + return -ENOSYS; /* no parameters specified, abort */ + } + + printk(KERN_INFO "%s\n", version); + + do { + unsigned long io, irq, ram; + long valid[2] = { 0, 0 }; /* Default = both ports disabled */ + + io = simple_strtoul(hw, &hw, 0); + + if (*hw++ != ',') + break; + irq = simple_strtoul(hw, &hw, 0); + + if (*hw++ != ',') + break; + ram = simple_strtoul(hw, &hw, 0); + + if (*hw++ != ',') + break; + while(1) { + if (*hw == '0' && !valid[0]) + valid[0] = 1; /* Port 0 enabled */ + else if (*hw == '1' && !valid[1]) + valid[1] = 1; /* Port 1 enabled */ + else + break; + hw++; + } + + if (!valid[0] && !valid[1]) + break; /* at least one port must be used */ + + if (*hw == ':' || *hw == '\x0') + n2_run(io, irq, ram, valid[0], valid[1]); + + if (*hw == '\x0') + return 0; + }while(*hw++ == ':'); + + printk(KERN_ERR "n2: invalid hardware parameters\n"); + return first_card ? 0 : -ENOSYS; +} + + +#ifndef MODULE +static int __init n2_setup(char *str) +{ + hw = str; + return 1; +} + +__setup("n2=", n2_setup); +#endif + + +static void __exit n2_cleanup(void) +{ + card_t *card = first_card; + + while (card) { + card_t *ptr = card; + card = card->next_card; + n2_destroy_card(ptr); + } +} + + +module_init(n2_init); +module_exit(n2_cleanup); + +MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>"); +MODULE_DESCRIPTION("RISCom/N2 serial port driver"); +MODULE_PARM(hw, "s"); /* hw=io,irq,ram,ports:io,irq,... */ +EXPORT_NO_SYMBOLS; diff --git a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c index 9ca0e84e8..278e63230 100644 --- a/drivers/net/wan/sbni.c +++ b/drivers/net/wan/sbni.c @@ -283,7 +283,7 @@ int sbni_header_cache(struct neighbour *neigh, struct hh_cache *hh) struct net_device *dev = neigh->dev; - if (type == __constant_htons(ETH_P_802_3)) + if (type == htons(ETH_P_802_3)) return -1; sbni->h_proto = type; @@ -742,7 +742,7 @@ static inline unsigned short sbni_recv(struct net_device *dev) */ DP( printk("%s: sbni_recv SendComplete\n",dev->name); ); /* - * We sucessfully sent current packet + * We successfully sent current packet */ if(lp->waitack) @@ -1014,6 +1014,8 @@ static inline void sbni_get_packet(struct net_device* dev) skb_pull(skb,SBNI_HH_SZ); + skb->dev->last_rx = jiffies; + lp->stats.rx_bytes += skb->len; netif_rx(skb); lp->stats.rx_packets++; } @@ -1148,7 +1150,7 @@ static void sbni_drop_tx_queue(struct net_device *dev) lp->waitack=0; netif_wake_queue(dev); - DP( printk("%s: queue dropping stoped\n",dev->name); ); + DP( printk("%s: queue dropping stopped\n",dev->name); ); } /* diff --git a/drivers/net/wan/sdla_chdlc.c b/drivers/net/wan/sdla_chdlc.c index dd4f43e10..6efea1155 100644 --- a/drivers/net/wan/sdla_chdlc.c +++ b/drivers/net/wan/sdla_chdlc.c @@ -932,7 +932,7 @@ static int if_send (struct sk_buff* skb, struct net_device* dev) if(test_and_set_bit(0, (void*)&card->wandev.critical)) { - printk(KERN_INFO "%s: Critical in if_send: %x\n", + printk(KERN_INFO "%s: Critical in if_send: %lx\n", card->wandev.name,card->wandev.critical); ++card->wandev.stats.tx_dropped; #ifdef LINUX_2_1 @@ -1497,7 +1497,7 @@ STATIC void wpc_isr (sdla_t* card) */ if(card->hw.type != SDLA_S514) { if(test_and_set_bit(0, (void*)&card->wandev.critical)) { - printk(KERN_INFO "%s: Critical while in ISR: %x\n", + printk(KERN_INFO "%s: Critical while in ISR: %lx\n", card->devname, card->wandev.critical); card->in_isr = 0; return; diff --git a/drivers/net/wan/sdla_fr.c b/drivers/net/wan/sdla_fr.c index 93c9cf933..90e353f33 100644 --- a/drivers/net/wan/sdla_fr.c +++ b/drivers/net/wan/sdla_fr.c @@ -1654,7 +1654,7 @@ static void fr_isr (sdla_t* card) ++card->statistics.isr_intr_test; break; - case FR_INTR_DLC: /* Event interrupt occured */ + case FR_INTR_DLC: /* Event interrupt occurred */ mbox->cmd.command = FR_READ_STATUS; mbox->cmd.length = 0; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; @@ -1691,7 +1691,7 @@ static void fr_isr (sdla_t* card) /*============================================================================ * Receive interrupt handler. * When a receive interrupt occurs do the following: - * 1- Find the structure for the dlci that the interrupt occured on + * 1- Find the structure for the dlci that the interrupt occurred on * 2- If it doesn't exist then print appropriate msg and goto step 8. * 3- If it exist then copy data to a skb. * 4- If skb contains Sangoma UDP data then process them diff --git a/drivers/net/wan/sdla_ppp.c b/drivers/net/wan/sdla_ppp.c index 8216db813..acda7cfa8 100644 --- a/drivers/net/wan/sdla_ppp.c +++ b/drivers/net/wan/sdla_ppp.c @@ -897,7 +897,7 @@ static int if_send (struct sk_buff *skb, struct net_device *dev) if (test_and_set_bit(0, (void*)&card->wandev.critical)) { - printk(KERN_INFO "%s: Critical in if_send: %x\n", + printk(KERN_INFO "%s: Critical in if_send: %lx\n", card->wandev.name,card->wandev.critical); dev_kfree_skb(skb); @@ -1686,8 +1686,6 @@ static void rx_intr(sdla_t *card) card->devname); ++card->wandev.stats.rx_dropped; ++ppp_priv_area->rx_intr_stat.rx_intr_no_socket; - - dev_kfree_skb(skb); } } else { @@ -2589,8 +2587,6 @@ static void process_udp_mgmt_pkt(sdla_t *card, struct net_device *dev, } ppp_priv_area->udp_pkt_lgth = 0; - - return; } /*============================================================================= @@ -2753,7 +2749,7 @@ static int remove_route( sdla_t *card ) card->devname, err); return err; }else - printk (KERN_INFO "%s: PPP Deleting dynamic route %s successfuly\n", + printk (KERN_INFO "%s: PPP Deleting dynamic route %s successfully\n", card->devname, in_ntoa(ip_addr)); diff --git a/drivers/net/wan/sdla_x25.c b/drivers/net/wan/sdla_x25.c index 9afd8ae91..4095687f5 100644 --- a/drivers/net/wan/sdla_x25.c +++ b/drivers/net/wan/sdla_x25.c @@ -929,7 +929,7 @@ static void wpx_isr (sdla_t* card) * * Notes: * 1. When allocating a socket buffer, if M-bit is set then more data is - * comming and we have to allocate buffer for the maximum IP packet size + * coming and we have to allocate buffer for the maximum IP packet size * expected on this channel. * 2. If something goes wrong and X.25 packet has to be dropped (e.g. no * socket buffers available) the whole packet sequence must be discarded. @@ -1001,7 +1001,7 @@ static void rx_intr (sdla_t* card) memcpy(bufptr, rxmb->data, len); if (qdm & 0x01) - return; /* more data is comming */ + return; /* more data is coming */ dev->last_rx = jiffies; /* timestamp */ chan->rx_skb = NULL; /* dequeue packet */ @@ -1153,7 +1153,7 @@ static void poll_connecting (sdla_t* card) { wanpipe_set_state(card, WAN_CONNECTED); x25_set_intr_mode(card, 0x83); /* enable Rx interrupts */ - status->imask &= ~0x2; /* mask Tx interupts */ + status->imask &= ~0x2; /* mask Tx interrupts */ } else if ((jiffies - card->state_tick) > CONNECT_TIMEOUT) disconnect(card); diff --git a/drivers/net/wan/sdladrv.c b/drivers/net/wan/sdladrv.c index 89951542e..6ffe5eb90 100644 --- a/drivers/net/wan/sdladrv.c +++ b/drivers/net/wan/sdladrv.c @@ -195,6 +195,12 @@ static unsigned short checksum (unsigned char* buf, unsigned len); * Note: All data must be explicitly initialized!!! */ +static struct pci_device_id sdladrv_pci_tbl[] __initdata = { + { V3_VENDOR_ID, V3_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(pci, sdladrv_pci_tbl); + /* private data */ static char modname[] = "sdladrv"; static char fullname[] = "SDLA Support Module"; diff --git a/drivers/net/wan/sdlamain.c b/drivers/net/wan/sdlamain.c index cbbe2b351..cf136d7e0 100644 --- a/drivers/net/wan/sdlamain.c +++ b/drivers/net/wan/sdlamain.c @@ -635,7 +635,7 @@ static int ioctl (wan_device_t* wandev, unsigned cmd, unsigned long arg) * o verify user buffer * o copy adapter memory image to user buffer * - * Note: when dumping memory, this routine switches curent dual-port memory + * Note: when dumping memory, this routine switches current dual-port memory * vector, so care must be taken to avoid racing conditions. */ static int ioctl_dump (sdla_t* card, sdla_dump_t* u_dump) diff --git a/drivers/net/wan/sealevel.c b/drivers/net/wan/sealevel.c index 2128a386e..422464f7c 100644 --- a/drivers/net/wan/sealevel.c +++ b/drivers/net/wan/sealevel.c @@ -26,7 +26,7 @@ #include <asm/io.h> #include <asm/dma.h> #include <asm/byteorder.h> -#include "syncppp.h" +#include <net/syncppp.h> #include "z85230.h" @@ -67,6 +67,7 @@ static void sealevel_input(struct z8530_channel *c, struct sk_buff *skb) * it right now. */ netif_rx(skb); + c->netdevice->last_rx = jiffies; } /* diff --git a/drivers/net/wan/syncppp.c b/drivers/net/wan/syncppp.c index 8a62cc8ed..de422f8ee 100644 --- a/drivers/net/wan/syncppp.c +++ b/drivers/net/wan/syncppp.c @@ -42,6 +42,7 @@ #include <linux/kernel.h> #include <linux/errno.h> #include <linux/sched.h> +#include <linux/init.h> #include <linux/if_arp.h> #include <linux/skbuff.h> #include <linux/route.h> @@ -51,7 +52,7 @@ #include <linux/pkt_sched.h> #include <asm/byteorder.h> #include <linux/spinlock.h> -#include "syncppp.h" +#include <net/syncppp.h> #define MAXALIVECNT 6 /* max. alive packets */ @@ -147,7 +148,6 @@ static void sppp_print_bytes (u8 *p, u16 len); static int debug = 0; -MODULE_PARM(debug,"1i"); /* * Interface down stub @@ -208,7 +208,7 @@ void sppp_input (struct net_device *dev, struct sk_buff *skb) skb->dev=dev; skb->mac.raw=skb->data; - + if (dev->flags & IFF_RUNNING) { /* Count received bytes, add FCS and one flag */ @@ -1391,28 +1391,25 @@ struct packet_type sppp_packet_type= }; -void sync_ppp_init(void) + +static int __init sync_ppp_init(void) { + if(debug) + debug=PP_DEBUG; printk(KERN_INFO "Cronyx Ltd, Synchronous PPP and CISCO HDLC (c) 1994\n"); printk(KERN_INFO "Linux port (c) 1998 Building Number Three Ltd & Jan \"Yenya\" Kasprzak.\n"); spin_lock_init(&spppq_lock); sppp_packet_type.type=htons(ETH_P_WAN_PPP); dev_add_pack(&sppp_packet_type); -} - -#ifdef MODULE - -int init_module(void) -{ - if(debug) - debug=PP_DEBUG; - sync_ppp_init(); return 0; } -void cleanup_module(void) + +static void __exit sync_ppp_cleanup(void) { dev_remove_pack(&sppp_packet_type); } -#endif +module_init(sync_ppp_init); +module_exit(sync_ppp_cleanup); +MODULE_PARM(debug,"1i"); diff --git a/drivers/net/wan/syncppp.h b/drivers/net/wan/syncppp.h deleted file mode 100644 index 8f6ed5c1f..000000000 --- a/drivers/net/wan/syncppp.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Defines for synchronous PPP/Cisco link level subroutines. - * - * Copyright (C) 1994 Cronyx Ltd. - * Author: Serge Vakulenko, <vak@zebub.msk.su> - * - * This software is distributed with NO WARRANTIES, not even the implied - * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Authors grant any other persons or organizations permission to use - * or modify this software as long as this message is kept with the software, - * all derivative works or modified versions. - * - * Version 1.7, Wed Jun 7 22:12:02 MSD 1995 - * - * - * - */ - -#ifndef _SYNCPPP_H_ -#define _SYNCPPP_H_ 1 - -#ifdef __KERNEL__ -struct slcp { - u16 state; /* state machine */ - u32 magic; /* local magic number */ - u_char echoid; /* id of last keepalive echo request */ - u_char confid; /* id of last configuration request */ -}; - -struct sipcp { - u16 state; /* state machine */ - u_char confid; /* id of last configuration request */ -}; - -struct sppp -{ - struct sppp * pp_next; /* next interface in keepalive list */ - u32 pp_flags; /* use Cisco protocol instead of PPP */ - u16 pp_alivecnt; /* keepalive packets counter */ - u16 pp_loopcnt; /* loopback detection counter */ - u32 pp_seq; /* local sequence number */ - u32 pp_rseq; /* remote sequence number */ - struct slcp lcp; /* LCP params */ - struct sipcp ipcp; /* IPCP params */ - u32 ibytes,obytes; /* Bytes in/out */ - u32 ipkts,opkts; /* Packets in/out */ - struct timer_list pp_timer; - struct net_device *pp_if; - char pp_link_state; /* Link status */ -}; - -struct ppp_device -{ - struct net_device *dev; /* Network device pointer */ - struct sppp sppp; /* Synchronous PPP */ -}; - -#define sppp_of(dev) \ - (&((struct ppp_device *)(*(unsigned long *)((dev)->priv)))->sppp) - -#define PP_KEEPALIVE 0x01 /* use keepalive protocol */ -#define PP_CISCO 0x02 /* use Cisco protocol instead of PPP */ -#define PP_TIMO 0x04 /* cp_timeout routine active */ -#define PP_DEBUG 0x08 - -#define PPP_MTU 1500 /* max. transmit unit */ - -#define LCP_STATE_CLOSED 0 /* LCP state: closed (conf-req sent) */ -#define LCP_STATE_ACK_RCVD 1 /* LCP state: conf-ack received */ -#define LCP_STATE_ACK_SENT 2 /* LCP state: conf-ack sent */ -#define LCP_STATE_OPENED 3 /* LCP state: opened */ - -#define IPCP_STATE_CLOSED 0 /* IPCP state: closed (conf-req sent) */ -#define IPCP_STATE_ACK_RCVD 1 /* IPCP state: conf-ack received */ -#define IPCP_STATE_ACK_SENT 2 /* IPCP state: conf-ack sent */ -#define IPCP_STATE_OPENED 3 /* IPCP state: opened */ - -#define SPPP_LINK_DOWN 0 /* link down - no keepalive */ -#define SPPP_LINK_UP 1 /* link is up - keepalive ok */ - -void sppp_attach (struct ppp_device *pd); -void sppp_detach (struct net_device *dev); -void sppp_input (struct net_device *dev, struct sk_buff *m); -int sppp_do_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd); -struct sk_buff *sppp_dequeue (struct net_device *dev); -int sppp_isempty (struct net_device *dev); -void sppp_flush (struct net_device *dev); -int sppp_open (struct net_device *dev); -int sppp_reopen (struct net_device *dev); -int sppp_close (struct net_device *dev); -void sync_ppp_init (void); -#endif - -#define SPPPIOCCISCO (SIOCDEVPRIVATE) -#define SPPPIOCPPP (SIOCDEVPRIVATE+1) -#define SPPPIOCDEBUG (SIOCDEVPRIVATE+2) - -#endif /* _SYNCPPP_H_ */ diff --git a/drivers/net/wan/z85230.c b/drivers/net/wan/z85230.c index c45e6f7ae..940de522a 100644 --- a/drivers/net/wan/z85230.c +++ b/drivers/net/wan/z85230.c @@ -42,14 +42,15 @@ #include <linux/if_arp.h> #include <linux/delay.h> #include <linux/ioport.h> +#include <linux/init.h> #include <asm/dma.h> #include <asm/io.h> #define RT_LOCK #define RT_UNLOCK #include <linux/spinlock.h> +#include <net/syncppp.h> #include "z85230.h" -#include "syncppp.h" static spinlock_t z8530_buffer_lock = SPIN_LOCK_UNLOCKED; @@ -70,7 +71,7 @@ static spinlock_t z8530_buffer_lock = SPIN_LOCK_UNLOCKED; * 5uS delay rule. */ -extern __inline__ int z8530_read_port(unsigned long p) +static inline int z8530_read_port(unsigned long p) { u8 r=inb(Z8530_PORT_OF(p)); if(p&Z8530_PORT_SLEEP) /* gcc should figure this out efficiently ! */ @@ -94,7 +95,7 @@ extern __inline__ int z8530_read_port(unsigned long p) */ -extern __inline__ void z8530_write_port(unsigned long p, u8 d) +static inline void z8530_write_port(unsigned long p, u8 d) { outb(d,Z8530_PORT_OF(p)); if(p&Z8530_PORT_SLEEP) @@ -119,7 +120,7 @@ static void z8530_tx_done(struct z8530_channel *c); * operation. */ -extern inline u8 read_zsreg(struct z8530_channel *c, u8 reg) +static inline u8 read_zsreg(struct z8530_channel *c, u8 reg) { u8 r; unsigned long flags; @@ -140,7 +141,7 @@ extern inline u8 read_zsreg(struct z8530_channel *c, u8 reg) * have all the 5uS delays to worry about. */ -extern inline u8 read_zsdata(struct z8530_channel *c) +static inline u8 read_zsdata(struct z8530_channel *c) { u8 r; r=z8530_read_port(c->dataio); @@ -158,7 +159,7 @@ extern inline u8 read_zsdata(struct z8530_channel *c) * being fast to access. */ -extern inline void write_zsreg(struct z8530_channel *c, u8 reg, u8 val) +static inline void write_zsreg(struct z8530_channel *c, u8 reg, u8 val) { unsigned long flags; save_flags(flags); @@ -177,7 +178,7 @@ extern inline void write_zsreg(struct z8530_channel *c, u8 reg, u8 val) * Write directly to the control register on the Z8530 */ -extern inline void write_zsctrl(struct z8530_channel *c, u8 val) +static inline void write_zsctrl(struct z8530_channel *c, u8 val) { z8530_write_port(c->ctrlio, val); } @@ -191,7 +192,7 @@ extern inline void write_zsctrl(struct z8530_channel *c, u8 val) */ -extern inline void write_zsdata(struct z8530_channel *c, u8 val) +static inline void write_zsdata(struct z8530_channel *c, u8 val) { z8530_write_port(c->dataio, val); } @@ -441,7 +442,7 @@ static void z8530_tx(struct z8530_channel *c) * z8530_status - Handle a PIO status exception * @chan: Z8530 channel to process * - * A status event occured in PIO synchronous mode. There are several + * A status event occurred in PIO synchronous mode. There are several * reasons the chip will bother us here. A transmit underrun means we * failed to feed the chip fast enough and just broke a packet. A DCD * change is a line up or down. We communicate that back to the protocol @@ -555,7 +556,7 @@ static void z8530_dma_tx(struct z8530_channel *chan) * z8530_dma_status - Handle a DMA status exception * @chan: Z8530 channel to process * - * A status event occured on the Z8530. We receive these for two reasons + * A status event occurred on the Z8530. We receive these for two reasons * when in DMA mode. Firstly if we finished a packet transfer we get one * and kick the next packet out. Secondly we may see a DCD change and * have to poke the protocol layer. @@ -1654,7 +1655,7 @@ static void z8530_rx_done(struct z8530_channel *c) * thing can only DMA within a 64K block not across the edges of it. */ -extern inline int spans_boundary(struct sk_buff *skb) +static inline int spans_boundary(struct sk_buff *skb) { unsigned long a=(unsigned long)skb->data; a^=(a+skb->len); @@ -1735,20 +1736,19 @@ struct net_device_stats *z8530_get_stats(struct z8530_channel *c) EXPORT_SYMBOL(z8530_get_stats); -#ifdef MODULE - /* * Module support */ - -int init_module(void) +static const char banner[] __initdata = KERN_INFO "Generic Z85C30/Z85230 interface driver v0.02\n"; + +static int __init z85230_init_driver(void) { - printk(KERN_INFO "Generic Z85C30/Z85230 interface driver v0.02\n"); + printk(banner); return 0; } +module_init(z85230_init_driver); -void cleanup_module(void) +static void __exit z85230_cleanup_driver(void) { } - -#endif +module_exit(z85230_cleanup_driver); diff --git a/drivers/net/wavelan.c b/drivers/net/wavelan.c index be85118d3..2777201eb 100644 --- a/drivers/net/wavelan.c +++ b/drivers/net/wavelan.c @@ -3686,7 +3686,7 @@ static void wavelan_interrupt(int irq, void *dev_id, struct pt_regs *regs) * the spinlock. */ spin_lock(&lp->spinlock); - /* Check modem interupt */ + /* Check modem interrupt */ if ((hasr = hasr_read(ioaddr)) & HASR_MMC_INTR) { u8 dce_status; @@ -3913,8 +3913,6 @@ static int wavelan_open(device * dev) } wv_splx(lp, &flags); - MOD_INC_USE_COUNT; - #ifdef DEBUG_CALLBACK_TRACE printk(KERN_DEBUG "%s: <-wavelan_open()\n", dev->name); #endif @@ -3947,8 +3945,6 @@ static int wavelan_close(device * dev) free_irq(dev->irq, dev); - MOD_DEC_USE_COUNT; - #ifdef DEBUG_CALLBACK_TRACE printk(KERN_DEBUG "%s: <-wavelan_close()\n", dev->name); #endif @@ -4019,8 +4015,10 @@ static int __init wavelan_config(device * dev) /* Initialize device structures */ dev->priv = kmalloc(sizeof(net_local), GFP_KERNEL); - if (dev->priv == NULL) + if (dev->priv == NULL) { + release_region(ioaddr, sizeof(ha_t)); return -ENOMEM; + } memset(dev->priv, 0x00, sizeof(net_local)); lp = (net_local *) dev->priv; @@ -4045,6 +4043,7 @@ static int __init wavelan_config(device * dev) */ ether_setup(dev); + SET_MODULE_OWNER(dev); dev->open = wavelan_open; dev->stop = wavelan_close; dev->hard_start_xmit = wavelan_packet_xmit; @@ -4287,7 +4286,7 @@ void cleanup_module(void) /* * This software may only be used and distributed - * according to the terms of the GNU Public License. + * according to the terms of the GNU General Public License. * * This software was developed as a component of the * Linux operating system. diff --git a/drivers/net/wavelan.p.h b/drivers/net/wavelan.p.h index 874b8e355..749b7039b 100644 --- a/drivers/net/wavelan.p.h +++ b/drivers/net/wavelan.p.h @@ -420,7 +420,8 @@ #undef DEBUG_RX_INFO /* header of the received packet */ #undef DEBUG_RX_FAIL /* Normal failure conditions */ #define DEBUG_RX_ERROR /* Unexpected conditions */ -#undef DEBUG_PACKET_DUMP 32 /* Dump packet on the screen. */ + +#undef DEBUG_PACKET_DUMP /* Dump packet on the screen if defined to 32. */ #undef DEBUG_IOCTL_TRACE /* misc. call by Linux */ #undef DEBUG_IOCTL_INFO /* various debugging info */ #define DEBUG_IOCTL_ERROR /* what's going wrong */ diff --git a/drivers/net/winbond-840.c b/drivers/net/winbond-840.c index eeec287ce..d27ad0c36 100644 --- a/drivers/net/winbond-840.c +++ b/drivers/net/winbond-840.c @@ -1,6 +1,6 @@ /* winbond-840.c: A Linux PCI network adapter skeleton device driver. */ /* - Written 1998-2000 by Donald Becker. + Written 1998-2001 by Donald Becker. This software may be used and distributed according to the terms of the GNU General Public License (GPL), incorporated herein by reference. @@ -198,7 +198,8 @@ enum pci_id_flags_bits { PCI_ADDR0=0<<4, PCI_ADDR1=1<<4, PCI_ADDR2=2<<4, PCI_ADDR3=3<<4, PCI_ADDR_64BITS=0x100, PCI_NO_ACPI_WAKE=0x200, PCI_NO_MIN_LATENCY=0x400, }; -enum chip_capability_flags {CanHaveMII=1, HasBrokenTx=2}; +enum chip_capability_flags { + CanHaveMII=1, HasBrokenTx=2, AlwaysFDX=4, FDXOnNoMII=8,}; #ifdef USE_IO_OPS #define W840_FLAGS (PCI_USES_IO | PCI_ADDR0 | PCI_USES_MASTER) #else @@ -206,8 +207,9 @@ enum chip_capability_flags {CanHaveMII=1, HasBrokenTx=2}; #endif static struct pci_device_id w840_pci_tbl[] __devinitdata = { - { 0x1050, 0x0840, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { 0x11f6, 0x2011, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 }, + { 0x1050, 0x0840, PCI_ANY_ID, 0x8153, 0, 0, 0 }, + { 0x1050, 0x0840, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 }, + { 0x11f6, 0x2011, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 }, { 0, } }; MODULE_DEVICE_TABLE(pci, w840_pci_tbl); @@ -223,6 +225,9 @@ struct pci_id_info { int drv_flags; /* Driver use, intended as capability flags. */ }; static struct pci_id_info pci_id_tbl[] = { + {"Winbond W89c840", /* Sometime a Level-One switch card. */ + { 0x08401050, 0xffffffff, 0x81530000, 0xffff0000 }, + W840_FLAGS, 128, CanHaveMII | HasBrokenTx | FDXOnNoMII}, {"Winbond W89c840", { 0x08401050, 0xffffffff, }, W840_FLAGS, 128, CanHaveMII | HasBrokenTx}, {"Compex RL100-ATX", { 0x201111F6, 0xffffffff,}, @@ -305,21 +310,17 @@ struct w840_tx_desc { enum desc_status_bits { DescOwn=0x80000000, DescEndRing=0x02000000, DescUseLink=0x01000000, DescWholePkt=0x60000000, DescStartPkt=0x20000000, DescEndPkt=0x40000000, -}; - -/* Bits in w840_tx_desc.length */ -enum desc_length_bits { DescIntr=0x80000000, }; #define PRIV_ALIGN 15 /* Required alignment mask */ +#define MII_CNT 1 /* winbond only supports one MII */ struct netdev_private { struct w840_rx_desc *rx_ring; dma_addr_t rx_addr[RX_RING_SIZE]; struct w840_tx_desc *tx_ring; dma_addr_t tx_addr[RX_RING_SIZE]; dma_addr_t ring_dma_addr; - struct pci_dev *pdev; /* The addresses of receive-in-place skbuffs. */ struct sk_buff* rx_skbuff[RX_RING_SIZE]; /* The saved address of a sent-in-place packet/buffer, for later free(). */ @@ -329,6 +330,7 @@ struct netdev_private { /* Frequently used values: keep some adjacent for cache effect. */ spinlock_t lock; int chip_id, drv_flags; + struct pci_dev *pci_dev; int csr6; struct w840_rx_desc *rx_head_desc; unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ @@ -344,7 +346,7 @@ struct netdev_private { /* MII transceiver section. */ int mii_cnt; /* MII device addresses. */ u16 advertising; /* NWay media advertisement */ - unsigned char phys[2]; /* MII device addresses. */ + unsigned char phys[MII_CNT]; /* MII device addresses, but only the first is used */ }; static int eeprom_read(long ioaddr, int location); @@ -377,48 +379,43 @@ static int __devinit w840_probe1 (struct pci_dev *pdev, struct netdev_private *np; static int find_cnt; int chip_idx = ent->driver_data; - int irq = pdev->irq; + int irq; int i, option = find_cnt < MAX_UNITS ? options[find_cnt] : 0; long ioaddr; - if (pci_enable_device(pdev)) - return -EIO; + i = pci_enable_device(pdev); + if (i) return i; + pci_set_master(pdev); - if(!pci_dma_supported(pdev,0xFFFFffff)) { + irq = pdev->irq; + + if (pci_set_dma_mask(pdev,0xFFFFffff)) { printk(KERN_WARNING "Winbond-840: Device %s disabled due to DMA limitations.\n", - pdev->name); + pdev->slot_name); return -EIO; } - dev = init_etherdev(NULL, sizeof(*np)); + dev = alloc_etherdev(sizeof(*np)); if (!dev) return -ENOMEM; SET_MODULE_OWNER(dev); + if (pci_request_regions(pdev, "winbond-840")) + goto err_out_netdev; + #ifdef USE_IO_OPS ioaddr = pci_resource_start(pdev, 0); - if (!request_region(ioaddr, pci_id_tbl[chip_idx].io_size, dev->name)) - goto err_out_netdev; #else ioaddr = pci_resource_start(pdev, 1); - if (!request_mem_region(ioaddr, pci_id_tbl[chip_idx].io_size, dev->name)) - goto err_out_netdev; ioaddr = (long) ioremap (ioaddr, pci_id_tbl[chip_idx].io_size); if (!ioaddr) - goto err_out_iomem; + goto err_out_free_res; #endif - printk(KERN_INFO "%s: %s at 0x%lx, ", - dev->name, pci_id_tbl[chip_idx].name, ioaddr); - /* Warning: broken for big-endian machines. */ for (i = 0; i < 3; i++) ((u16 *)dev->dev_addr)[i] = le16_to_cpu(eeprom_read(ioaddr, i)); - for (i = 0; i < 5; i++) - printk("%2.2x:", dev->dev_addr[i]); - printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); - /* Reset the chip to erase previous misconfiguration. No hold time required! */ writel(0x00000001, ioaddr + PCIBusCfg); @@ -427,12 +424,12 @@ static int __devinit w840_probe1 (struct pci_dev *pdev, dev->irq = irq; np = dev->priv; + np->pci_dev = pdev; np->chip_id = chip_idx; np->drv_flags = pci_id_tbl[chip_idx].drv_flags; - np->pdev = pdev; spin_lock_init(&np->lock); - pdev->driver_data = dev; + pci_set_drvdata(pdev, dev); if (dev->mem_start) option = dev->mem_start; @@ -461,9 +458,19 @@ static int __devinit w840_probe1 (struct pci_dev *pdev, dev->tx_timeout = &tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; + i = register_netdev(dev); + if (i) + goto err_out_cleardev; + + printk(KERN_INFO "%s: %s at 0x%lx, ", + dev->name, pci_id_tbl[chip_idx].name, ioaddr); + for (i = 0; i < 5; i++) + printk("%2.2x:", dev->dev_addr[i]); + printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); + if (np->drv_flags & CanHaveMII) { int phy, phy_idx = 0; - for (phy = 1; phy < 32 && phy_idx < 4; phy++) { + for (phy = 1; phy < 32 && phy_idx < MII_CNT; phy++) { int mii_status = mdio_read(dev, phy, 1); if (mii_status != 0xffff && mii_status != 0x0000) { np->phys[phy_idx++] = phy; @@ -483,13 +490,14 @@ static int __devinit w840_probe1 (struct pci_dev *pdev, find_cnt++; return 0; +err_out_cleardev: + pci_set_drvdata(pdev, NULL); #ifndef USE_IO_OPS -err_out_iomem: - release_mem_region(pci_resource_start(pdev, 1), - pci_id_tbl[chip_idx].io_size); + iounmap((void *)ioaddr); +err_out_free_res: #endif + pci_release_regions(pdev); err_out_netdev: - unregister_netdev (dev); kfree (dev); return -ENODEV; } @@ -535,6 +543,7 @@ static int eeprom_read(long addr, int location) eeprom_delay(ee_addr); } writel(EE_ChipSelect, ee_addr); + eeprom_delay(ee_addr); for (i = 16; i > 0; i--) { writel(EE_ChipSelect | EE_ShiftClk, ee_addr); @@ -612,7 +621,7 @@ static int mdio_read(struct net_device *dev, int phy_id, int location) static void mdio_write(struct net_device *dev, int phy_id, int location, int value) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; long mdio_addr = dev->base_addr + MIICtrl; int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value; int i; @@ -645,7 +654,7 @@ static void mdio_write(struct net_device *dev, int phy_id, int location, int val static int netdev_open(struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; int i; @@ -680,7 +689,7 @@ static int netdev_open(struct net_device *dev) static void check_duplex(struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; int mii_reg5 = mdio_read(dev, np->phys[0], 5); int negotiated = mii_reg5 & np->advertising; int duplex; @@ -702,7 +711,7 @@ static void check_duplex(struct net_device *dev) static void netdev_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; int next_tick = 10*HZ; int old_csr6 = np->csr6; @@ -725,7 +734,7 @@ static void netdev_timer(unsigned long data) static void init_rxtx_rings(struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; int i; np->rx_head_desc = &np->rx_ring[0]; @@ -747,7 +756,7 @@ static void init_rxtx_rings(struct net_device *dev) if (skb == NULL) break; skb->dev = dev; /* Mark as being used by this device. */ - np->rx_addr[i] = pci_map_single(np->pdev,skb->tail, + np->rx_addr[i] = pci_map_single(np->pci_dev,skb->tail, skb->len,PCI_DMA_FROMDEVICE); np->rx_ring[i].buffer1 = cpu_to_le32(np->rx_addr[i]); @@ -778,7 +787,7 @@ static void free_rxtx_rings(struct netdev_private* np) for (i = 0; i < RX_RING_SIZE; i++) { np->rx_ring[i].status = 0; if (np->rx_skbuff[i]) { - pci_unmap_single(np->pdev, + pci_unmap_single(np->pci_dev, np->rx_addr[i], np->rx_skbuff[i]->len, PCI_DMA_FROMDEVICE); @@ -788,7 +797,7 @@ static void free_rxtx_rings(struct netdev_private* np) } for (i = 0; i < TX_RING_SIZE; i++) { if (np->tx_skbuff[i]) { - pci_unmap_single(np->pdev, + pci_unmap_single(np->pci_dev, np->tx_addr[i], np->tx_skbuff[i]->len, PCI_DMA_TODEVICE); @@ -800,7 +809,7 @@ static void free_rxtx_rings(struct netdev_private* np) static void init_registers(struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; int i; @@ -832,7 +841,7 @@ static void init_registers(struct net_device *dev) if (x86 <= 4) printk(KERN_INFO "%s: This is a 386/486 PCI system, setting cache " "alignment to %x.\n", dev->name, - (x86 <= 4 ? 0x4810 : 0x8010)); + (x86 <= 4 ? 0x4810 : 0xE010)); #endif #else writel(0xE010, ioaddr + PCIBusCfg); @@ -857,7 +866,7 @@ static void init_registers(struct net_device *dev) static void tx_timeout(struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; printk(KERN_WARNING "%s: Transmit timed out, status %8.8x," @@ -905,11 +914,11 @@ static void tx_timeout(struct net_device *dev) /* Initialize the Rx and Tx rings, along with various 'dev' bits. */ static int alloc_ring(struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; np->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); - np->rx_ring = pci_alloc_consistent(np->pdev, + np->rx_ring = pci_alloc_consistent(np->pci_dev, sizeof(struct w840_rx_desc)*RX_RING_SIZE + sizeof(struct w840_tx_desc)*TX_RING_SIZE, &np->ring_dma_addr); @@ -922,7 +931,7 @@ static int alloc_ring(struct net_device *dev) static int start_tx(struct sk_buff *skb, struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; unsigned entry; int len1, len2; @@ -933,7 +942,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) entry = np->cur_tx % TX_RING_SIZE; np->tx_skbuff[entry] = skb; - np->tx_addr[entry] = pci_map_single(np->pdev, + np->tx_addr[entry] = pci_map_single(np->pci_dev, skb->data,skb->len, PCI_DMA_TODEVICE); np->tx_ring[entry].buffer1 = cpu_to_le32(np->tx_addr[entry]); len2 = 0; @@ -987,7 +996,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) { struct net_device *dev = (struct net_device *)dev_instance; - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; int work_limit = max_interrupt_work; @@ -1040,7 +1049,7 @@ static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) np->stats.tx_packets++; } /* Free the original skb. */ - pci_unmap_single(np->pdev,np->tx_addr[entry], + pci_unmap_single(np->pci_dev,np->tx_addr[entry], np->tx_skbuff[entry]->len, PCI_DMA_TODEVICE); np->tx_q_bytes -= np->tx_skbuff[entry]->len; @@ -1082,7 +1091,7 @@ static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) for clarity and better register allocation. */ static int netdev_rx(struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; int entry = np->cur_rx % RX_RING_SIZE; int work_limit = np->dirty_rx + RX_RING_SIZE - np->cur_rx; @@ -1136,7 +1145,7 @@ static int netdev_rx(struct net_device *dev) && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { skb->dev = dev; skb_reserve(skb, 2); /* 16 byte align the IP header */ - pci_dma_sync_single(np->pdev,np->rx_addr[entry], + pci_dma_sync_single(np->pci_dev,np->rx_addr[entry], np->rx_skbuff[entry]->len, PCI_DMA_FROMDEVICE); /* Call copy + cksum if available. */ @@ -1148,7 +1157,7 @@ static int netdev_rx(struct net_device *dev) pkt_len); #endif } else { - pci_unmap_single(np->pdev,np->rx_addr[entry], + pci_unmap_single(np->pci_dev,np->rx_addr[entry], np->rx_skbuff[entry]->len, PCI_DMA_FROMDEVICE); skb_put(skb = np->rx_skbuff[entry], pkt_len); @@ -1187,7 +1196,7 @@ static int netdev_rx(struct net_device *dev) if (skb == NULL) break; /* Better luck next round. */ skb->dev = dev; /* Mark as being used by this device. */ - np->rx_addr[entry] = pci_map_single(np->pdev, + np->rx_addr[entry] = pci_map_single(np->pci_dev, skb->tail, skb->len, PCI_DMA_FROMDEVICE); np->rx_ring[entry].buffer1 = cpu_to_le32(np->rx_addr[entry]); @@ -1202,7 +1211,7 @@ static int netdev_rx(struct net_device *dev) static void netdev_error(struct net_device *dev, int intr_status) { long ioaddr = dev->base_addr; - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; if (debug > 2) printk(KERN_DEBUG "%s: Abnormal event, %8.8x.\n", @@ -1243,7 +1252,7 @@ static void netdev_error(struct net_device *dev, int intr_status) static struct net_device_stats *get_stats(struct net_device *dev) { long ioaddr = dev->base_addr; - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; /* The chip only need report frame silently dropped. */ if (netif_running(dev)) @@ -1270,7 +1279,7 @@ static inline u32 ether_crc(int length, unsigned char *data) static void set_rx_mode(struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; u32 mc_filter[2]; /* Multicast hash filter */ u32 rx_mode; @@ -1328,7 +1337,7 @@ static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) static int netdev_close(struct net_device *dev) { long ioaddr = dev->base_addr; - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; int i; netif_stop_queue(dev); @@ -1379,23 +1388,19 @@ static int netdev_close(struct net_device *dev) static void __devexit w840_remove1 (struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; + struct net_device *dev = pci_get_drvdata(pdev); /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ if (dev) { - struct netdev_private *np = (void *)(dev->priv); unregister_netdev(dev); -#ifdef USE_IO_OPS - release_region(dev->base_addr, pci_id_tbl[np->chip_id].io_size); -#else - release_mem_region(pci_resource_start(pdev, 1), - pci_id_tbl[np->chip_id].io_size); + pci_release_regions(pdev); +#ifndef USE_IO_OPS iounmap((char *)(dev->base_addr)); #endif kfree(dev); } - pdev->driver_data = NULL; + pci_set_drvdata(pdev, NULL); } static struct pci_driver w840_driver = { diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c index 9cda23333..a6ca25b55 100644 --- a/drivers/net/yellowfin.c +++ b/drivers/net/yellowfin.c @@ -1,33 +1,54 @@ /* yellowfin.c: A Packet Engines G-NIC ethernet driver for linux. */ /* - Written 1997-1999 by Donald Becker. + Written 1997-2001 by Donald Becker. - This software may be used and distributed according to the terms - of the GNU Public License, incorporated herein by reference. + This software may be used and distributed according to the terms of + the GNU General Public License (GPL), incorporated herein by reference. + Drivers based on or derived from this code fall under the GPL and must + retain the authorship, copyright and license notice. This file is not + a complete program and may only be used when the entire operating + system is licensed under the GPL. This driver is for the Packet Engines G-NIC PCI Gigabit Ethernet adapter. It also supports the Symbios Logic version of the same chip core. - 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 + The author may be reached as becker@scyld.com, or C/O + Scyld Computing Corporation + 410 Severn Ave., Suite 210 + Annapolis MD 21403 Support and updates available at - http://cesdis.gsfc.nasa.gov/linux/drivers/yellowfin.html + http://www.scyld.com/network/yellowfin.html + + + Linux kernel changelog: + ----------------------- + + LK1.1.1 (jgarzik): Port to 2.4 kernel + + LK1.1.2 (jgarzik): + * Merge in becker version 1.05 + */ -static const char *version = -"yellowfin.c:v1.03a 7/30/99 Written by Donald Becker, becker@cesdis.edu\n" -" http://cesdis.gsfc.nasa.gov/linux/drivers/yellowfin.html\n"; +/* These identify the driver base version and may not be removed. */ +static const char version1[] = +"yellowfin.c:v1.05 1/09/2001 Written by Donald Becker <becker@scyld.com>\n"; +static const char version2[] = +" http://www.scyld.com/network/yellowfin.html\n"; +static const char version3[] = +" (unofficial 2.4.x port, LK1.1.2, January 11, 2001)\n"; -/* A few user-configurable values. */ +/* The user-configurable values. + These may be modified when a driver module is loaded.*/ -static int debug = 1; +static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ +/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ static int max_interrupt_work = 20; -static int mtu = 0; +static int mtu; #ifdef YF_PROTOTYPE /* Support for prototype hardware errata. */ /* System-wide count of bogus-rx frames. */ -static int bogus_rx = 0; +static int bogus_rx; static int dma_ctrl = 0x004A0263; /* Constrained by errata */ static int fifo_cfg = 0x0020; /* Bypass external Tx FIFO. */ #elif YF_NEW /* A future perfect board :->. */ @@ -40,7 +61,7 @@ static int fifo_cfg = 0x0020; /* Bypass external Tx FIFO. */ /* Set the copy breakpoint for the copy-only-tiny-frames scheme. Setting to > 1514 effectively disables this feature. */ -static int rx_copybreak = 0; +static int rx_copybreak; /* Used to pass the media type, etc. No media types are currently defined. These exist for driver @@ -51,12 +72,12 @@ static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; /* Do ugly workaround for GX server chipset errata. */ -static int gx_fix = 0; +static int gx_fix; /* Operational parameters that are set at compile time. */ /* Keep the ring sizes a power of two for efficiency. - Making the Tx queue too long decreases the effectiveness of channel + Making the Tx ring too long decreases the effectiveness of channel bonding and packet priority. There are no ill effects from too-large receive rings. */ #define TX_RING_SIZE 16 @@ -66,57 +87,61 @@ static int gx_fix = 0; /* Operational parameters that usually are not changed. */ /* Time in jiffies before concluding the transmitter is hung. */ #define TX_TIMEOUT (2*HZ) +#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ #define yellowfin_debug debug -#if !defined(__OPTIMIZE__) || !defined(__KERNEL__) +#if !defined(__OPTIMIZE__) #warning You must compile this file with the correct options! #warning See the last lines of the source file. #error You must compile this driver with "-O". #endif -#include <linux/version.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/string.h> #include <linux/timer.h> #include <linux/errno.h> #include <linux/ioport.h> -#include <linux/malloc.h> +#include <linux/slab.h> #include <linux/interrupt.h> #include <linux/pci.h> #include <linux/init.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> #include <asm/processor.h> /* Processor type for cache alignment. */ #include <asm/unaligned.h> #include <asm/bitops.h> #include <asm/io.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/skbuff.h> - -/* Condensed operations for readability. - Compatibility defines are now in drv_compat.h */ - +/* Condensed operations for readability. */ #define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr)) #define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr)) - -#ifdef USE_IO_OPS -#define YF_INB inb -#define YF_INW inw -#define YF_INL inl -#define YF_OUTB outb -#define YF_OUTW outw -#define YF_OUTL outl -#else -#define YF_INB readb -#define YF_INW readw -#define YF_INL readl -#define YF_OUTB writeb -#define YF_OUTW writew -#define YF_OUTL writel -#endif +#ifndef USE_IO_OPS +#undef inb +#undef inw +#undef inl +#undef outb +#undef outw +#undef outl +#define inb readb +#define inw readw +#define inl readl +#define outb writeb +#define outw writew +#define outl writel +#endif /* !USE_IO_OPS */ +MODULE_AUTHOR("Donald Becker <becker@scyld.com>"); +MODULE_DESCRIPTION("Packet Engines Yellowfin G-NIC Gigabit Ethernet driver"); +MODULE_PARM(max_interrupt_work, "i"); +MODULE_PARM(mtu, "i"); +MODULE_PARM(debug, "i"); +MODULE_PARM(rx_copybreak, "i"); +MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(gx_fix, "i"); /* Theory of Operation @@ -193,50 +218,53 @@ http://cesdis.gsfc.nasa.gov/linux/misc/100mbps.html IVc. Errata See Packet Engines confidential appendix (prototype chips only). - */ - -/* A few values that may be tweaked. */ -#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ -/* The rest of these values should never change. */ + +enum pci_id_flags_bits { + /* Set PCI command register bits before calling probe1(). */ + PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4, + /* Read and map the single following PCI BAR. */ + PCI_ADDR0=0<<4, PCI_ADDR1=1<<4, PCI_ADDR2=2<<4, PCI_ADDR3=3<<4, + PCI_ADDR_64BITS=0x100, PCI_NO_ACPI_WAKE=0x200, PCI_NO_MIN_LATENCY=0x400, + PCI_UNUSED_IRQ=0x800, +}; enum capability_flags { HasMII=1, FullTxStatus=2, IsGigabit=4, HasMulticastBug=8, FullRxStatus=16, - HasMACAddrBug=32, /* Really only on early revs. */ + HasMACAddrBug=32, /* Only on early revs. */ }; - - /* The PCI I/O space extent. */ #define YELLOWFIN_SIZE 0x100 +#ifdef USE_IO_OPS +#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_IO | PCI_ADDR0) +#else +#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR1) +#endif -#define YELLOWFIN_MODULE_NAME "yellowfin" -#define PFX YELLOWFIN_MODULE_NAME ": " - - -typedef enum { - YELLOWFIN_GNIC, - SYM83C885, -} chip_t; - - -struct chip_info { - const char *name; - int flags; +struct pci_id_info { + const char *name; + struct match_info { + int pci, pci_mask, subsystem, subsystem_mask; + int revision, revision_mask; /* Only 8 bits. */ + } id; + enum pci_id_flags_bits pci_flags; + int io_size; /* Needed for I/O region check or ioremap(). */ + int drv_flags; /* Driver use, intended as capability flags. */ }; - -/* index by chip_t */ -static struct chip_info chip_info[] = { - {"Yellowfin G-NIC Gigabit Ethernet", +static struct pci_id_info pci_id_tbl[] = { + {"Yellowfin G-NIC Gigabit Ethernet", { 0x07021000, 0xffffffff}, + PCI_IOTYPE, YELLOWFIN_SIZE, FullTxStatus | IsGigabit | HasMulticastBug | HasMACAddrBug}, - {"Symbios SYM83C885", HasMII }, + {"Symbios SYM83C885", { 0x07011000, 0xffffffff}, + PCI_IOTYPE, YELLOWFIN_SIZE, HasMII }, + {0,}, }; - static struct pci_device_id yellowfin_pci_tbl[] __devinitdata = { - { 0x1000, 0x0702, PCI_ANY_ID, PCI_ANY_ID, 0, 0, YELLOWFIN_GNIC }, - { 0x1000, 0x0701, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SYM83C885 }, + { 0x1000, 0x0702, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { 0x1000, 0x0701, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 }, { 0, } }; MODULE_DEVICE_TABLE (pci, yellowfin_pci_tbl); @@ -300,21 +328,22 @@ enum intr_status_bits { IntrEarlyRx=0x100, IntrWakeup=0x200, }; #define PRIV_ALIGN 31 /* Required alignment mask */ +#define MII_CNT 4 struct yellowfin_private { - /* Descriptor rings first for alignment. Tx requires a second descriptor - for status. */ + /* Descriptor rings first for alignment. + Tx requires a second descriptor for status. */ struct yellowfin_desc rx_ring[RX_RING_SIZE]; struct yellowfin_desc tx_ring[TX_RING_SIZE*2]; /* The addresses of receive-in-place skbuffs. */ struct sk_buff* rx_skbuff[RX_RING_SIZE]; - /* The saved address of a sent-in-place packet/buffer, for skfree(). */ + /* The saved address of a sent-in-place packet/buffer, for later free(). */ struct sk_buff* tx_skbuff[TX_RING_SIZE]; struct tx_status_words tx_status[TX_RING_SIZE]; struct timer_list timer; /* Media selection timer. */ struct net_device_stats stats; /* Frequently used and paired value: keep adjacent for cache effect. */ + int chip_id, drv_flags; struct pci_dev *pci_dev; - int chip_id, flags; struct yellowfin_desc *rx_head_desc; unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ unsigned int rx_buf_sz; /* Based on MTU+slack. */ @@ -329,29 +358,14 @@ struct yellowfin_private { /* MII transceiver section. */ int mii_cnt; /* MII device addresses. */ u16 advertising; /* NWay media advertisement */ - unsigned char phys[2]; /* MII device addresses. */ - u32 pad[4]; /* Used for 32-byte alignment */ + unsigned char phys[MII_CNT]; /* MII device addresses, only first one used */ spinlock_t lock; }; - -MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>"); -MODULE_DESCRIPTION("Packet Engines Yellowfin G-NIC Gigabit Ethernet driver"); -MODULE_PARM(max_interrupt_work, "i"); -MODULE_PARM(mtu, "i"); -MODULE_PARM(debug, "i"); -MODULE_PARM(rx_copybreak, "i"); -MODULE_PARM(gx_fix, "i"); -MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); -MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); - - static int read_eeprom(long ioaddr, int location); static int mdio_read(long ioaddr, int phy_id, int location); static void mdio_write(long ioaddr, int phy_id, int location, int value); -#ifdef HAVE_PRIVATE_IOCTL static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -#endif static int yellowfin_open(struct net_device *dev); static void yellowfin_timer(unsigned long data); static void yellowfin_tx_timeout(struct net_device *dev); @@ -365,15 +379,147 @@ static struct net_device_stats *yellowfin_get_stats(struct net_device *dev); static void set_rx_mode(struct net_device *dev); +static int __devinit yellowfin_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct net_device *dev; + struct yellowfin_private *np; + int irq; + int chip_idx = ent->driver_data; + static int find_cnt = 0; + long ioaddr, real_ioaddr; + int i, option = find_cnt < MAX_UNITS ? options[find_cnt] : 0; + int drv_flags = pci_id_tbl[chip_idx].drv_flags; + + i = pci_enable_device(pdev); + if (i) return i; + + dev = alloc_etherdev(sizeof(*np)); + if (!dev) { + printk (KERN_ERR "yellowfin: cannot allocate ethernet device\n"); + return -ENOMEM; + } + SET_MODULE_OWNER(dev); + + np = dev->priv; + + if (pci_request_regions(pdev, dev->name)) + goto err_out_free_netdev; + + pci_set_master (pdev); + +#ifdef USE_IO_OPS + real_ioaddr = ioaddr = pci_resource_start (pdev, 0); +#else + real_ioaddr = ioaddr = pci_resource_start (pdev, 1); + ioaddr = (long) ioremap(ioaddr, YELLOWFIN_SIZE); + if (!ioaddr) + goto err_out_free_res; +#endif + irq = pdev->irq; + + if (drv_flags & IsGigabit) + for (i = 0; i < 6; i++) + dev->dev_addr[i] = inb(ioaddr + StnAddr + i); + else { + int ee_offset = (read_eeprom(ioaddr, 6) == 0xff ? 0x100 : 0); + for (i = 0; i < 6; i++) + dev->dev_addr[i] = read_eeprom(ioaddr, ee_offset + i); + } + + /* Reset the chip. */ + outl(0x80000000, ioaddr + DMACtrl); + + dev->base_addr = ioaddr; + dev->irq = irq; + + pci_set_drvdata(pdev, dev); + np->lock = SPIN_LOCK_UNLOCKED; + + np->pci_dev = pdev; + np->chip_id = chip_idx; + np->drv_flags = drv_flags; + + if (dev->mem_start) + option = dev->mem_start; + + /* The lower four bits are the media type. */ + if (option > 0) { + if (option & 0x200) + np->full_duplex = 1; + np->default_port = option & 15; + if (np->default_port) + np->medialock = 1; + } + if (find_cnt < MAX_UNITS && full_duplex[find_cnt] > 0) + np->full_duplex = 1; + + if (np->full_duplex) + np->duplex_lock = 1; + + /* The Yellowfin-specific entries in the device structure. */ + dev->open = &yellowfin_open; + dev->hard_start_xmit = &yellowfin_start_xmit; + dev->stop = &yellowfin_close; + dev->get_stats = &yellowfin_get_stats; + dev->set_multicast_list = &set_rx_mode; + dev->do_ioctl = &mii_ioctl; + dev->tx_timeout = yellowfin_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + + if (mtu) + dev->mtu = mtu; + + i = register_netdev(dev); + if (i) + goto err_out_cleardev; + + printk(KERN_INFO "%s: %s type %8x at 0x%lx, ", + dev->name, pci_id_tbl[chip_idx].name, inl(ioaddr + ChipRev), ioaddr); + for (i = 0; i < 5; i++) + printk("%2.2x:", dev->dev_addr[i]); + printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); + + if (np->drv_flags & HasMII) { + int phy, phy_idx = 0; + for (phy = 0; phy < 32 && phy_idx < MII_CNT; phy++) { + int mii_status = mdio_read(ioaddr, phy, 1); + if (mii_status != 0xffff && mii_status != 0x0000) { + np->phys[phy_idx++] = phy; + np->advertising = mdio_read(ioaddr, phy, 4); + printk(KERN_INFO "%s: MII PHY found at address %d, status " + "0x%4.4x advertising %4.4x.\n", + dev->name, phy, mii_status, np->advertising); + } + } + np->mii_cnt = phy_idx; + } + + find_cnt++; + + return 0; + +err_out_cleardev: + pci_set_drvdata(pdev, NULL); +#ifndef USE_IO_OPS + iounmap((void *)ioaddr); +err_out_free_res: +#endif + pci_release_regions(pdev); +err_out_free_netdev: + kfree (dev); + return -ENODEV; +} + static int __devinit read_eeprom(long ioaddr, int location) { int bogus_cnt = 10000; /* Typical 33Mhz: 1050 ticks */ - YF_OUTB(location, ioaddr + EEAddr); - YF_OUTB(0x30 | ((location >> 8) & 7), ioaddr + EECtrl); - while ((YF_INB(ioaddr + EEStatus) & 0x80) && --bogus_cnt > 0) + outb(location, ioaddr + EEAddr); + outb(0x30 | ((location >> 8) & 7), ioaddr + EECtrl); + while ((inb(ioaddr + EEStatus) & 0x80) && --bogus_cnt > 0) ; - return YF_INB(ioaddr + EERead); + return inb(ioaddr + EERead); } /* MII Managemen Data I/O accesses. @@ -384,24 +530,24 @@ static int mdio_read(long ioaddr, int phy_id, int location) { int i; - YF_OUTW((phy_id<<8) + location, ioaddr + MII_Addr); - YF_OUTW(1, ioaddr + MII_Cmd); + outw((phy_id<<8) + location, ioaddr + MII_Addr); + outw(1, ioaddr + MII_Cmd); for (i = 10000; i >= 0; i--) - if ((YF_INW(ioaddr + MII_Status) & 1) == 0) + if ((inw(ioaddr + MII_Status) & 1) == 0) break; - return YF_INW(ioaddr + MII_Rd_Data); + return inw(ioaddr + MII_Rd_Data); } static void mdio_write(long ioaddr, int phy_id, int location, int value) { int i; - YF_OUTW((phy_id<<8) + location, ioaddr + MII_Addr); - YF_OUTW(value, ioaddr + MII_Wr_Data); + outw((phy_id<<8) + location, ioaddr + MII_Addr); + outw(value, ioaddr + MII_Wr_Data); /* Wait for the command to finish. */ for (i = 10000; i >= 0; i--) - if ((YF_INW(ioaddr + MII_Status) & 1) == 0) + if ((inw(ioaddr + MII_Status) & 1) == 0) break; return; } @@ -409,15 +555,15 @@ static void mdio_write(long ioaddr, int phy_id, int location, int value) static int yellowfin_open(struct net_device *dev) { - struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv; + struct yellowfin_private *yp = dev->priv; long ioaddr = dev->base_addr; int i; /* Reset the chip. */ - YF_OUTL(0x80000000, ioaddr + DMACtrl); + outl(0x80000000, ioaddr + DMACtrl); - if (request_irq(dev->irq, &yellowfin_interrupt, SA_SHIRQ, dev->name, dev)) - return -EAGAIN; + i = request_irq(dev->irq, &yellowfin_interrupt, SA_SHIRQ, dev->name, dev); + if (i) return i; if (yellowfin_debug > 1) printk(KERN_DEBUG "%s: yellowfin_open() irq %d.\n", @@ -425,58 +571,59 @@ static int yellowfin_open(struct net_device *dev) yellowfin_init_ring(dev); - YF_OUTL(virt_to_bus(yp->rx_ring), ioaddr + RxPtr); - YF_OUTL(virt_to_bus(yp->tx_ring), ioaddr + TxPtr); + outl(virt_to_bus(yp->rx_ring), ioaddr + RxPtr); + outl(virt_to_bus(yp->tx_ring), ioaddr + TxPtr); for (i = 0; i < 6; i++) - YF_OUTB(dev->dev_addr[i], ioaddr + StnAddr + i); + outb(dev->dev_addr[i], ioaddr + StnAddr + i); /* Set up various condition 'select' registers. There are no options here. */ - YF_OUTL(0x00800080, ioaddr + TxIntrSel); /* Interrupt on Tx abort */ - YF_OUTL(0x00800080, ioaddr + TxBranchSel); /* Branch on Tx abort */ - YF_OUTL(0x00400040, ioaddr + TxWaitSel); /* Wait on Tx status */ - YF_OUTL(0x00400040, ioaddr + RxIntrSel); /* Interrupt on Rx done */ - YF_OUTL(0x00400040, ioaddr + RxBranchSel); /* Branch on Rx error */ - YF_OUTL(0x00400040, ioaddr + RxWaitSel); /* Wait on Rx done */ + outl(0x00800080, ioaddr + TxIntrSel); /* Interrupt on Tx abort */ + outl(0x00800080, ioaddr + TxBranchSel); /* Branch on Tx abort */ + outl(0x00400040, ioaddr + TxWaitSel); /* Wait on Tx status */ + outl(0x00400040, ioaddr + RxIntrSel); /* Interrupt on Rx done */ + outl(0x00400040, ioaddr + RxBranchSel); /* Branch on Rx error */ + outl(0x00400040, ioaddr + RxWaitSel); /* Wait on Rx done */ /* Initialize other registers: with so many this eventually this will converted to an offset/value list. */ - YF_OUTL(dma_ctrl, ioaddr + DMACtrl); - YF_OUTW(fifo_cfg, ioaddr + FIFOcfg); + outl(dma_ctrl, ioaddr + DMACtrl); + outw(fifo_cfg, ioaddr + FIFOcfg); /* Enable automatic generation of flow control frames, period 0xffff. */ - YF_OUTL(0x0030FFFF, ioaddr + FlowCtrl); + outl(0x0030FFFF, ioaddr + FlowCtrl); yp->tx_threshold = 32; - YF_OUTL(yp->tx_threshold, ioaddr + TxThreshold); + outl(yp->tx_threshold, ioaddr + TxThreshold); if (dev->if_port == 0) dev->if_port = yp->default_port; - netif_start_queue (dev); + netif_start_queue(dev); /* Setting the Rx mode will start the Rx process. */ - if (yp->flags & IsGigabit) { + if (yp->drv_flags & IsGigabit) { /* We are always in full-duplex mode with gigabit! */ yp->full_duplex = 1; - YF_OUTW(0x01CF, ioaddr + Cnfg); + outw(0x01CF, ioaddr + Cnfg); } else { - YF_OUTW(0x0018, ioaddr + FrameGap0); /* 0060/4060 for non-MII 10baseT */ - YF_OUTW(0x1018, ioaddr + FrameGap1); - YF_OUTW(0x101C | (yp->full_duplex ? 2 : 0), ioaddr + Cnfg); + outw(0x0018, ioaddr + FrameGap0); /* 0060/4060 for non-MII 10baseT */ + outw(0x1018, ioaddr + FrameGap1); + outw(0x101C | (yp->full_duplex ? 2 : 0), ioaddr + Cnfg); } set_rx_mode(dev); /* Enable interrupts by setting the interrupt mask. */ - YF_OUTW(0x81ff, ioaddr + IntrEnb); /* See enum intr_status_bits */ - YF_OUTW(0x0000, ioaddr + EventStatus); /* Clear non-interrupting events */ - YF_OUTL(0x80008000, ioaddr + RxCtrl); /* Start Rx and Tx channels. */ - YF_OUTL(0x80008000, ioaddr + TxCtrl); + outw(0x81ff, ioaddr + IntrEnb); /* See enum intr_status_bits */ + outw(0x0000, ioaddr + EventStatus); /* Clear non-interrupting events */ + outl(0x80008000, ioaddr + RxCtrl); /* Start Rx and Tx channels. */ + outl(0x80008000, ioaddr + TxCtrl); if (yellowfin_debug > 2) { printk(KERN_DEBUG "%s: Done yellowfin_open().\n", dev->name); } + /* Set the timer to check for link beat. */ init_timer(&yp->timer); yp->timer.expires = jiffies + 3*HZ; @@ -490,13 +637,13 @@ static int yellowfin_open(struct net_device *dev) static void yellowfin_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; - struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv; + struct yellowfin_private *yp = dev->priv; long ioaddr = dev->base_addr; int next_tick = 60*HZ; if (yellowfin_debug > 3) { printk(KERN_DEBUG "%s: Yellowfin timer tick, status %8.8x.\n", - dev->name, YF_INW(ioaddr + IntrStatus)); + dev->name, inw(ioaddr + IntrStatus)); } if (yp->mii_cnt) { @@ -513,7 +660,7 @@ static void yellowfin_timer(unsigned long data) || (negotiated & 0x00C0) == 0x0040)) { yp->full_duplex = 1; } - YF_OUTW(0x101C | (yp->full_duplex ? 2 : 0), ioaddr + Cnfg); + outw(0x101C | (yp->full_duplex ? 2 : 0), ioaddr + Cnfg); if (mii_reg1 & 0x0004) next_tick = 60*HZ; @@ -527,13 +674,13 @@ static void yellowfin_timer(unsigned long data) static void yellowfin_tx_timeout(struct net_device *dev) { - struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv; + struct yellowfin_private *yp = dev->priv; long ioaddr = dev->base_addr; printk(KERN_WARNING "%s: Yellowfin transmit timed out at %d/%d Tx " "status %4.4x, Rx status %4.4x, resetting...\n", dev->name, yp->cur_tx, yp->dirty_tx, - YF_INL(ioaddr + TxStatus), YF_INL(ioaddr + RxStatus)); + inl(ioaddr + TxStatus), inl(ioaddr + RxStatus)); /* Note: these should be KERN_DEBUG. */ if (yellowfin_debug) { @@ -553,19 +700,18 @@ static void yellowfin_tx_timeout(struct net_device *dev) dev->if_port = 0; /* Wake the potentially-idle transmit channel. */ - YF_OUTL(0x10001000, dev->base_addr + TxCtrl); + outl(0x10001000, dev->base_addr + TxCtrl); if (yp->cur_tx - yp->dirty_tx < TX_QUEUE_SIZE) netif_wake_queue (dev); /* Typical path */ dev->trans_start = jiffies; yp->stats.tx_errors++; - return; } /* Initialize the Rx and Tx rings, along with various 'dev' bits. */ static void yellowfin_init_ring(struct net_device *dev) { - struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv; + struct yellowfin_private *yp = dev->priv; int i; yp->tx_full = 0; @@ -637,13 +783,13 @@ static void yellowfin_init_ring(struct net_device *dev) static int yellowfin_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv; + struct yellowfin_private *yp = dev->priv; unsigned entry; netif_stop_queue (dev); - /* Caution: the write order is important here, set the base address - with the "ownership" bits last. */ + /* Note: Ordering is important here, set the field with the + "ownership" bit last, and only then increment cur_tx. */ /* Calculate the next Tx descriptor entry. */ entry = yp->cur_tx % TX_RING_SIZE; @@ -691,7 +837,7 @@ static int yellowfin_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Non-x86 Todo: explicitly flush cache lines here. */ /* Wake the potentially-idle transmit channel. */ - YF_OUTL(0x10001000, dev->base_addr + TxCtrl); + outl(0x10001000, dev->base_addr + TxCtrl); if (yp->cur_tx - yp->dirty_tx < TX_QUEUE_SIZE) netif_start_queue (dev); /* Typical path */ @@ -710,9 +856,10 @@ static int yellowfin_start_xmit(struct sk_buff *skb, struct net_device *dev) after the Tx thread. */ static void yellowfin_interrupt(int irq, void *dev_instance, struct pt_regs *regs) { - struct net_device *dev = (struct net_device *)dev_instance; + struct net_device *dev = dev_instance; struct yellowfin_private *yp; - long ioaddr, boguscnt = max_interrupt_work; + long ioaddr; + int boguscnt = max_interrupt_work; #ifndef final_version /* Can never occur. */ if (dev == NULL) { @@ -722,12 +869,12 @@ static void yellowfin_interrupt(int irq, void *dev_instance, struct pt_regs *reg #endif ioaddr = dev->base_addr; - yp = (struct yellowfin_private *)dev->priv; + yp = dev->priv; spin_lock (&yp->lock); do { - u16 intr_status = YF_INW(ioaddr + IntrClear); + u16 intr_status = inw(ioaddr + IntrClear); if (yellowfin_debug > 4) printk(KERN_DEBUG "%s: Yellowfin interrupt, status %4.4x.\n", @@ -738,7 +885,7 @@ static void yellowfin_interrupt(int irq, void *dev_instance, struct pt_regs *reg if (intr_status & (IntrRxDone | IntrEarlyRx)) { yellowfin_rx(dev); - YF_OUTL(0x10001000, ioaddr + RxCtrl); /* Wake Rx engine. */ + outl(0x10001000, ioaddr + RxCtrl); /* Wake Rx engine. */ } #ifdef NO_TXSTATS @@ -746,8 +893,8 @@ static void yellowfin_interrupt(int irq, void *dev_instance, struct pt_regs *reg int entry = yp->dirty_tx % TX_RING_SIZE; if (yp->tx_ring[entry].result_status == 0) break; - yp->stats.tx_bytes += yp->tx_skbuff[entry]->len; yp->stats.tx_packets++; + yp->stats.tx_bytes += yp->tx_skbuff[entry]->len; /* Free the original skb. */ dev_kfree_skb_irq(yp->tx_skbuff[entry]); yp->tx_skbuff[entry] = 0; @@ -756,11 +903,8 @@ static void yellowfin_interrupt(int irq, void *dev_instance, struct pt_regs *reg && yp->cur_tx - yp->dirty_tx < TX_QUEUE_SIZE - 4) { /* The ring is no longer full, clear tbusy. */ yp->tx_full = 0; - } - if (yp->tx_full) - netif_stop_queue(dev); - else netif_wake_queue(dev); + } #else if (intr_status & IntrTxDone || yp->tx_tail_desc->tx_errs) { @@ -831,11 +975,8 @@ static void yellowfin_interrupt(int irq, void *dev_instance, struct pt_regs *reg && yp->cur_tx - dirty_tx < TX_QUEUE_SIZE - 2) { /* The ring is no longer full, clear tbusy. */ yp->tx_full = 0; - } - if (yp->tx_full) - netif_stop_queue(dev); - else netif_wake_queue(dev); + } yp->dirty_tx = dirty_tx; yp->tx_tail_desc = &yp->tx_status[dirty_tx % TX_RING_SIZE]; @@ -847,7 +988,8 @@ static void yellowfin_interrupt(int irq, void *dev_instance, struct pt_regs *reg yellowfin_error(dev, intr_status); if (--boguscnt < 0) { - printk(KERN_WARNING "%s: Too much work at interrupt, status=0x%4.4x.\n", + printk(KERN_WARNING "%s: Too much work at interrupt, " + "status=0x%4.4x.\n", dev->name, intr_status); break; } @@ -855,28 +997,19 @@ static void yellowfin_interrupt(int irq, void *dev_instance, struct pt_regs *reg if (yellowfin_debug > 3) printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n", - dev->name, YF_INW(ioaddr + IntrStatus)); - - /* Code that should never be run! Perhaps remove after testing.. */ - { - static int stopit = 10; - if ((!(netif_running(dev))) && --stopit < 0) { - printk(KERN_ERR "%s: Emergency stop, looping startup interrupt.\n", - dev->name); - free_irq(irq, dev); - } - } + dev->name, inw(ioaddr + IntrStatus)); spin_unlock (&yp->lock); + return; } /* This routine is logically part of the interrupt handler, but separated for clarity and better register allocation. */ static int yellowfin_rx(struct net_device *dev) { - struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv; + struct yellowfin_private *yp = dev->priv; int entry = yp->cur_rx % RX_RING_SIZE; - int boguscnt = 20; + int boguscnt = yp->dirty_rx + RX_RING_SIZE - yp->cur_rx; if (yellowfin_debug > 4) { printk(KERN_DEBUG " In yellowfin_rx(), entry %d status %8.8x.\n", @@ -905,7 +1038,7 @@ static int yellowfin_rx(struct net_device *dev) printk(KERN_WARNING "%s: Oversized Ethernet frame spanned multiple buffers," " status %4.4x!\n", dev->name, desc_status); yp->stats.rx_length_errors++; - } else if ((yp->flags & IsGigabit) && (frame_status & 0x0038)) { + } else if ((yp->drv_flags & IsGigabit) && (frame_status & 0x0038)) { /* There was a error. */ if (yellowfin_debug > 3) printk(KERN_DEBUG " yellowfin_rx() Rx error was %4.4x.\n", @@ -915,7 +1048,7 @@ static int yellowfin_rx(struct net_device *dev) if (frame_status & 0x0008) yp->stats.rx_frame_errors++; if (frame_status & 0x0010) yp->stats.rx_crc_errors++; if (frame_status < 0) yp->stats.rx_dropped++; - } else if ( !(yp->flags & IsGigabit) && + } else if ( !(yp->drv_flags & IsGigabit) && ((buf_addr[data_size-1] & 0x85) || buf_addr[data_size-2] & 0xC0)) { u8 status1 = buf_addr[data_size-2]; u8 status2 = buf_addr[data_size-1]; @@ -952,21 +1085,22 @@ static int yellowfin_rx(struct net_device *dev) without copying to a properly sized skbuff. */ if (pkt_len > rx_copybreak) { char *temp = skb_put(skb = yp->rx_skbuff[entry], pkt_len); -#ifndef final_verison /* Remove after testing. */ + yp->rx_skbuff[entry] = NULL; +#ifndef final_version /* Remove after testing. */ if (le32desc_to_virt(yp->rx_ring[entry].addr) != temp) - printk(KERN_WARNING "%s: Warning -- the skbuff addresses " + printk(KERN_ERR "%s: Internal fault: The skbuff addresses " "do not match in yellowfin_rx: %p vs. %p / %p.\n", - dev->name, le32desc_to_virt(yp->rx_ring[entry].addr), + dev->name, + le32desc_to_virt(yp->rx_ring[entry].addr), skb->head, temp); #endif - yp->rx_skbuff[entry] = NULL; } else { skb = dev_alloc_skb(pkt_len + 2); if (skb == NULL) break; skb->dev = dev; - skb_reserve(skb, 2); /* 16 byte align the data fields */ -#if 1 || USE_IP_CSUM + skb_reserve(skb, 2); /* 16 byte align the IP header */ +#if HAS_IP_COPYSUM eth_copy_and_sum(skb, yp->rx_skbuff[entry]->tail, pkt_len, 0); skb_put(skb, pkt_len); #else @@ -989,9 +1123,9 @@ static int yellowfin_rx(struct net_device *dev) entry = yp->dirty_rx % RX_RING_SIZE; if (yp->rx_skbuff[entry] == NULL) { struct sk_buff *skb = dev_alloc_skb(yp->rx_buf_sz); - if (skb == NULL) - break; /* Better luck next round. */ yp->rx_skbuff[entry] = skb; + if (skb == NULL) + break; /* Better luck next round. */ skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ yp->rx_ring[entry].addr = virt_to_le32desc(skb->tail); @@ -1012,7 +1146,7 @@ static int yellowfin_rx(struct net_device *dev) static void yellowfin_error(struct net_device *dev, int intr_status) { - struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv; + struct yellowfin_private *yp = dev->priv; printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n", dev->name, intr_status); @@ -1026,35 +1160,36 @@ static void yellowfin_error(struct net_device *dev, int intr_status) static int yellowfin_close(struct net_device *dev) { long ioaddr = dev->base_addr; - struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv; + struct yellowfin_private *yp = dev->priv; int i; netif_stop_queue (dev); if (yellowfin_debug > 1) { - printk(KERN_DEBUG "%s: Shutting down ethercard, status was Tx %4.4x Rx %4.4x Int %2.2x.\n", - dev->name, YF_INW(ioaddr + TxStatus), - YF_INW(ioaddr + RxStatus), - YF_INW(ioaddr + IntrStatus)); + printk(KERN_DEBUG "%s: Shutting down ethercard, status was Tx %4.4x " + "Rx %4.4x Int %2.2x.\n", + dev->name, inw(ioaddr + TxStatus), + inw(ioaddr + RxStatus), inw(ioaddr + IntrStatus)); printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d, Rx %d / %d.\n", dev->name, yp->cur_tx, yp->dirty_tx, yp->cur_rx, yp->dirty_rx); } /* Disable interrupts by clearing the interrupt mask. */ - YF_OUTW(0x0000, ioaddr + IntrEnb); + outw(0x0000, ioaddr + IntrEnb); /* Stop the chip's Tx and Rx processes. */ - YF_OUTL(0x80000000, ioaddr + RxCtrl); - YF_OUTL(0x80000000, ioaddr + TxCtrl); + outl(0x80000000, ioaddr + RxCtrl); + outl(0x80000000, ioaddr + TxCtrl); del_timer(&yp->timer); -#if !defined(final_version) && defined(__i386__) +#if defined(__i386__) if (yellowfin_debug > 2) { - printk("\n"KERN_DEBUG" Tx ring at %8.8x:\n", (int)virt_to_bus(yp->tx_ring)); + printk("\n"KERN_DEBUG" Tx ring at %8.8x:\n", + (int)virt_to_bus(yp->tx_ring)); for (i = 0; i < TX_RING_SIZE*2; i++) printk(" %c #%d desc. %8.8x %8.8x %8.8x %8.8x.\n", - YF_INL(ioaddr + TxPtr) == (long)&yp->tx_ring[i] ? '>' : ' ', + inl(ioaddr + TxPtr) == (long)&yp->tx_ring[i] ? '>' : ' ', i, yp->tx_ring[i].dbdma_cmd, yp->tx_ring[i].addr, yp->tx_ring[i].branch_addr, yp->tx_ring[i].result_status); printk(KERN_DEBUG " Tx status %p:\n", yp->tx_status); @@ -1063,10 +1198,11 @@ static int yellowfin_close(struct net_device *dev) i, yp->tx_status[i].tx_cnt, yp->tx_status[i].tx_errs, yp->tx_status[i].total_tx_cnt, yp->tx_status[i].paused); - printk("\n"KERN_DEBUG " Rx ring %8.8x:\n", (int)virt_to_bus(yp->rx_ring)); + printk("\n"KERN_DEBUG " Rx ring %8.8x:\n", + (int)virt_to_bus(yp->rx_ring)); for (i = 0; i < RX_RING_SIZE; i++) { printk(KERN_DEBUG " %c #%d desc. %8.8x %8.8x %8.8x\n", - YF_INL(ioaddr + RxPtr) == (long)&yp->rx_ring[i] ? '>' : ' ', + inl(ioaddr + RxPtr) == (long)&yp->rx_ring[i] ? '>' : ' ', i, yp->rx_ring[i].dbdma_cmd, yp->rx_ring[i].addr, yp->rx_ring[i].result_status); if (yellowfin_debug > 6) { @@ -1105,12 +1241,13 @@ static int yellowfin_close(struct net_device *dev) dev->name, bogus_rx); } #endif + return 0; } static struct net_device_stats *yellowfin_get_stats(struct net_device *dev) { - struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv; + struct yellowfin_private *yp = dev->priv; return &yp->stats; } @@ -1141,19 +1278,19 @@ static inline unsigned ether_crc_le(int length, unsigned char *data) static void set_rx_mode(struct net_device *dev) { - struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv; + struct yellowfin_private *yp = dev->priv; long ioaddr = dev->base_addr; - u16 cfg_value = YF_INW(ioaddr + Cnfg); + u16 cfg_value = inw(ioaddr + Cnfg); /* Stop the Rx process to change any value. */ - YF_OUTW(cfg_value & ~0x1000, ioaddr + Cnfg); + outw(cfg_value & ~0x1000, ioaddr + Cnfg); if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ /* Unconditionally log net taps. */ printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name); - YF_OUTW(0x000F, ioaddr + AddrMode); + outw(0x000F, ioaddr + AddrMode); } else if ((dev->mc_count > 64) || (dev->flags & IFF_ALLMULTI)) { /* Too many to filter well, or accept all multicasts. */ - YF_OUTW(0x000B, ioaddr + AddrMode); + outw(0x000B, ioaddr + AddrMode); } else if (dev->mc_count > 0) { /* Must use the multicast hash table. */ struct dev_mc_list *mclist; u16 hash_table[4]; @@ -1163,7 +1300,7 @@ static void set_rx_mode(struct net_device *dev) i++, mclist = mclist->next) { /* Due to a bug in the early chip versions, multiple filter slots must be set for each address. */ - if (yp->flags & HasMulticastBug) { + if (yp->drv_flags & HasMulticastBug) { set_bit((ether_crc_le(3, mclist->dmi_addr) >> 3) & 0x3f, hash_table); set_bit((ether_crc_le(4, mclist->dmi_addr) >> 3) & 0x3f, @@ -1176,24 +1313,24 @@ static void set_rx_mode(struct net_device *dev) } /* Copy the hash table to the chip. */ for (i = 0; i < 4; i++) - YF_OUTW(hash_table[i], ioaddr + HashTbl + i*2); - YF_OUTW(0x0003, ioaddr + AddrMode); + outw(hash_table[i], ioaddr + HashTbl + i*2); + outw(0x0003, ioaddr + AddrMode); } else { /* Normal, unicast/broadcast-only mode. */ - YF_OUTW(0x0001, ioaddr + AddrMode); + outw(0x0001, ioaddr + AddrMode); } /* Restart the Rx process. */ - YF_OUTW(cfg_value | 0x1000, ioaddr + Cnfg); + outw(cfg_value | 0x1000, ioaddr + Cnfg); } -#ifdef HAVE_PRIVATE_IOCTL static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { + struct yellowfin_private *np = dev->priv; long ioaddr = dev->base_addr; u16 *data = (u16 *)&rq->ifr_data; switch(cmd) { case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ - data[0] = ((struct yellowfin_private *)dev->priv)->phys[0] & 0x1f; + data[0] = np->phys[0] & 0x1f; /* Fall Through */ case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f); @@ -1201,155 +1338,30 @@ static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) case SIOCDEVPRIVATE+2: /* Write the specified MII register */ if (!capable(CAP_NET_ADMIN)) return -EPERM; + if (data[0] == np->phys[0]) { + u16 value = data[2]; + switch (data[1]) { + case 0: + /* Check for autonegotiation on or reset. */ + np->medialock = (value & 0x9000) ? 0 : 1; + if (np->medialock) + np->full_duplex = (value & 0x0100) ? 1 : 0; + break; + case 4: np->advertising = value; break; + } + /* Perhaps check_duplex(dev), depending on chip semantics. */ + } mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]); return 0; default: return -EOPNOTSUPP; } } -#endif /* HAVE_PRIVATE_IOCTL */ - - -static int __devinit yellowfin_init_one(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - struct net_device *dev; - struct yellowfin_private *yp; - int option, i, irq; - int flags, chip_idx; - static int find_cnt = 0; - long ioaddr, real_ioaddr; - - chip_idx = ent->driver_data; - flags = chip_info[chip_idx].flags; - - dev = init_etherdev(NULL, sizeof(*yp)); - if (!dev) { - printk (KERN_ERR PFX "cannot allocate ethernet device\n"); - return -ENOMEM; - } - SET_MODULE_OWNER(dev); - - yp = dev->priv; - - if (!request_region (pci_resource_start (pdev, 0), - YELLOWFIN_SIZE, YELLOWFIN_MODULE_NAME)) { - printk (KERN_ERR PFX "cannot obtain I/O port region\n"); - goto err_out_free_netdev; - } - if (!request_mem_region (pci_resource_start (pdev, 1), - YELLOWFIN_SIZE, YELLOWFIN_MODULE_NAME)) { - printk (KERN_ERR PFX "cannot obtain MMIO region\n"); - goto err_out_free_pio_region; - } - - if (pci_enable_device (pdev)) - goto err_out_free_mmio_region; - pci_set_master (pdev); - -#ifdef USE_IO_OPS - real_ioaddr = ioaddr = pci_resource_start (pdev, 0); -#else - real_ioaddr = ioaddr = pci_resource_start (pdev, 1); - ioaddr = (long) ioremap(ioaddr, YELLOWFIN_SIZE); - if (!ioaddr) - goto err_out_free_mmio_region; -#endif - irq = pdev->irq; - - printk(KERN_INFO "%s: %s type %8x at 0x%lx, ", - dev->name, chip_info[chip_idx].name, - YF_INL(ioaddr + ChipRev), real_ioaddr); - - if (flags & IsGigabit) - for (i = 0; i < 6; i++) - dev->dev_addr[i] = YF_INB(ioaddr + StnAddr + i); - else { - int ee_offset = (read_eeprom(ioaddr, 6) == 0xff ? 0x100 : 0); - for (i = 0; i < 6; i++) - dev->dev_addr[i] = read_eeprom(ioaddr, ee_offset + i); - } - for (i = 0; i < 5; i++) - printk("%2.2x:", dev->dev_addr[i]); - printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); - - /* Reset the chip. */ - YF_OUTL(0x80000000, ioaddr + DMACtrl); - - dev->base_addr = ioaddr; - dev->irq = irq; - - pdev->driver_data = dev; - yp->chip_id = chip_idx; - yp->flags = flags; - yp->lock = SPIN_LOCK_UNLOCKED; - - option = find_cnt < MAX_UNITS ? options[find_cnt] : 0; - if (dev->mem_start) - option = dev->mem_start; - - /* The lower four bits are the media type. */ - if (option > 0) { - if (option & 0x200) - yp->full_duplex = 1; - yp->default_port = option & 15; - if (yp->default_port) - yp->medialock = 1; - } - if (find_cnt < MAX_UNITS && full_duplex[find_cnt] > 0) - yp->full_duplex = 1; - - if (yp->full_duplex) - yp->duplex_lock = 1; - - /* The Yellowfin-specific entries in the device structure. */ - dev->open = &yellowfin_open; - dev->hard_start_xmit = &yellowfin_start_xmit; - dev->stop = &yellowfin_close; - dev->get_stats = &yellowfin_get_stats; - dev->set_multicast_list = &set_rx_mode; -#ifdef HAVE_PRIVATE_IOCTL - dev->do_ioctl = &mii_ioctl; -#endif - dev->tx_timeout = yellowfin_tx_timeout; - dev->watchdog_timeo = TX_TIMEOUT; - if (mtu) - dev->mtu = mtu; - - if (yp->flags & HasMII) { - int phy, phy_idx = 0; - for (phy = 0; phy < 32 && phy_idx < 4; phy++) { - int mii_status = mdio_read(ioaddr, phy, 1); - if (mii_status != 0xffff && - mii_status != 0x0000) { - yp->phys[phy_idx++] = phy; - yp->advertising = mdio_read(ioaddr, phy, 4); - printk(KERN_INFO "%s: MII PHY found at address %d, status " - "0x%4.4x advertising %4.4x.\n", - dev->name, phy, mii_status, yp->advertising); - } - } - yp->mii_cnt = phy_idx; - } - - find_cnt++; - - return 0; - -err_out_free_mmio_region: - release_mem_region (pci_resource_start (pdev, 1), YELLOWFIN_SIZE); -err_out_free_pio_region: - release_region (pci_resource_start (pdev, 0), YELLOWFIN_SIZE); -err_out_free_netdev: - unregister_netdev (dev); - kfree (dev); - return -ENODEV; -} static void __devexit yellowfin_remove_one (struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; + struct net_device *dev = pci_get_drvdata(pdev); struct yellowfin_private *np; if (!dev) @@ -1358,19 +1370,19 @@ static void __devexit yellowfin_remove_one (struct pci_dev *pdev) unregister_netdev (dev); - release_region (dev->base_addr, YELLOWFIN_SIZE); - release_mem_region (dev->base_addr, YELLOWFIN_SIZE); + pci_release_regions (pdev); #ifndef USE_IO_OPS iounmap ((void *) dev->base_addr); #endif kfree (dev); + pci_set_drvdata(pdev, NULL); } static struct pci_driver yellowfin_driver = { - name: YELLOWFIN_MODULE_NAME, + name: "yellowfin", id_table: yellowfin_pci_tbl, probe: yellowfin_init_one, remove: yellowfin_remove_one, @@ -1380,7 +1392,8 @@ static struct pci_driver yellowfin_driver = { static int __init yellowfin_init (void) { if (debug) /* Emit version even if no cards detected. */ - printk(KERN_INFO "%s", version); + printk(KERN_INFO "%s" KERN_INFO "%s" KERN_INFO "%s", + version1, version2, version3); return pci_module_init (&yellowfin_driver); } @@ -1394,12 +1407,12 @@ static void __exit yellowfin_cleanup (void) module_init(yellowfin_init); module_exit(yellowfin_cleanup); - - + /* * Local variables: - * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c yellowfin.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" - * compile-command-alphaLX: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O2 -c yellowfin.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS` -fomit-frame-pointer -fno-strength-reduce -mno-fp-regs -Wa,-m21164a -DBWX_USABLE -DBWIO_ENABLED" + * compile-command: "gcc -DMODULE -Wall -Wstrict-prototypes -O6 -c yellowfin.c" + * compile-command-alphaLX: "gcc -DMODULE -Wall -Wstrict-prototypes -O2 -c yellowfin.c -fomit-frame-pointer -fno-strength-reduce -mno-fp-regs -Wa,-m21164a -DBWX_USABLE -DBWIO_ENABLED" + * simple-compile-command: "gcc -DMODULE -O6 -c yellowfin.c" * c-indent-level: 4 * c-basic-offset: 4 * tab-width: 4 diff --git a/drivers/net/zlib.c b/drivers/net/zlib.c index 6595b3e41..ca443ea3c 100644 --- a/drivers/net/zlib.c +++ b/drivers/net/zlib.c @@ -433,7 +433,7 @@ typedef struct deflate_state { int nice_match; /* Stop searching when current match exceeds this */ /* used by trees.c: */ - /* Didn't use ct_data typedef below to supress compiler warning */ + /* Didn't use ct_data typedef below to suppress compiler warning */ struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ @@ -689,7 +689,7 @@ struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ /* =========================================================================== * Update a hash value with the given input byte - * IN assertion: all calls to to UPDATE_HASH are made with consecutive + * IN assertion: all calls to UPDATE_HASH are made with consecutive * input characters, so that a running hash key can be computed from the * previous key instead of complete recalculation each time. */ @@ -700,7 +700,7 @@ struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ * Insert string str in the dictionary and set match_head to the previous head * of the hash chain (the most recent string with same hash key). Return * the previous length of the hash chain. - * IN assertion: all calls to to INSERT_STRING are made with consecutive + * IN assertion: all calls to INSERT_STRING are made with consecutive * input characters and the first MIN_MATCH bytes of str are valid * (except for the last MIN_MATCH-1 bytes of the input file). */ |