diff options
Diffstat (limited to 'drivers/net')
37 files changed, 4542 insertions, 1182 deletions
diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index 08c92ace9..da4e4bfe4 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -310,9 +310,11 @@ int el3_probe(struct net_device *dev) with "nopnp=1" before, does not harm if not. */ idev->deactivate(idev); idev->activate(idev); - if (!idev->resource[0].start || check_region(idev->resource[0].start,16)) + if (!idev->resource[0].start || check_region(idev->resource[0].start, EL3_IO_EXTENT)) continue; ioaddr = idev->resource[0].start; + if (!request_region(ioaddr, EL3_IO_EXTENT, "3c509 PnP")) + return -EBUSY; irq = idev->irq_resource[0].start; if (el3_debug > 3) printk ("ISAPnP reports %s at i/o 0x%x, irq %d\n", diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c index d8a5e12af..4aeee0a2e 100644 --- a/drivers/net/3c515.c +++ b/drivers/net/3c515.c @@ -490,7 +490,7 @@ static int corkscrew_scan(struct net_device *dev) if (inw(ioaddr + Wn0EepromData) != 0x6d50) continue; } - printk(KERN_INFO "3c515 Resource configuraiton register %#4.4x, DCR %4.4x.\n", + printk(KERN_INFO "3c515 Resource configuration register %#4.4x, DCR %4.4x.\n", inl(ioaddr + 0x2002), inw(ioaddr + 0x2000)); /* irq = inw(ioaddr + 0x2002) & 15; */ /* Use the irq from isapnp */ corkscrew_isapnp_phys_addr[pnp_cards] = ioaddr; @@ -533,7 +533,7 @@ no_pnp: if (inw(ioaddr + Wn0EepromData) != 0x6d50) continue; } - printk(KERN_INFO "3c515 Resource configuraiton register %#4.4x, DCR %4.4x.\n", + printk(KERN_INFO "3c515 Resource configuration register %#4.4x, DCR %4.4x.\n", inl(ioaddr + 0x2002), inw(ioaddr + 0x2000)); irq = inw(ioaddr + 0x2002) & 15; corkscrew_found_device(dev, ioaddr, irq, CORKSCREW_ID, dev diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 31e8c79b8..ebaeb68ba 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -21,8 +21,6 @@ */ -static char *version = -"3c59x.c:v0.99H+lk1.0 Feb 9, 2000 The Linux Kernel Team http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n"; /* "Knobs" that adjust features and parameters. */ /* Set the copy breakpoint for the copy-only-tiny-frames scheme. @@ -85,6 +83,9 @@ static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0, rx_csumhits; #define PCI_SUPPORT_VER2 #define DEV_FREE_SKB(skb) dev_kfree_skb(skb); +static char *version __initdata = +"3c59x.c:v0.99H+lk1.0 Feb 9, 2000 The Linux Kernel Team http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n"; + MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>"); MODULE_DESCRIPTION("3Com 3c590/3c900 series Vortex/Boomerang driver"); MODULE_PARM(debug, "i"); diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index 6169eb742..336a66949 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -1838,7 +1838,7 @@ static void rtl8139_set_rx_mode (struct net_device *dev) void *ioaddr = tp->mmio_addr; u32 mc_filter[2]; /* Multicast hash filter */ int i, rx_mode; - unsigned long flags; + unsigned long flags=0; DPRINTK ("ENTER\n"); diff --git a/drivers/net/8390.c b/drivers/net/8390.c index 65246369c..9ce1cf4af 100644 --- a/drivers/net/8390.c +++ b/drivers/net/8390.c @@ -114,8 +114,8 @@ static void NS8390_trigger_send(struct net_device *dev, unsigned int length, static void set_multicast_list(struct net_device *dev); static void do_set_multicast_list(struct net_device *dev); -/* - * SMP and the 8390 setup. +/** + * DOC: SMP and the 8390 setup. * * The 8390 isnt exactly designed to be multithreaded on RX/TX. There is * a page register that controls bank and packet buffer access. We guard @@ -142,10 +142,14 @@ static void do_set_multicast_list(struct net_device *dev); -/* Open/initialize the board. This routine goes all-out, setting everything - up anew at each open, even though many of these registers should only - need to be set once at boot. - */ +/** + * ei_open - Open/initialize the board. + * @dev: network device to initialize + * + * This routine goes all-out, setting everything + * up anew at each open, even though many of these registers should only + * need to be set once at boot. + */ int ei_open(struct net_device *dev) { unsigned long flags; @@ -173,7 +177,12 @@ int ei_open(struct net_device *dev) return 0; } -/* Opposite of above. Only used when "ifconfig <devname> down" is done. */ +/** + * ei_close - shut down network device + * @dev: network device to close + * + * Opposite of ei_open. Only used when "ifconfig <devname> down" is done. + */ int ei_close(struct net_device *dev) { struct ei_device *ei_local = (struct ei_device *) dev->priv; @@ -190,6 +199,14 @@ int ei_close(struct net_device *dev) return 0; } +/** + * ei_start_xmit - begin packet transmission + * @skb: packet to be sent + * @dev: network device to which packet is sent + * + * Sends a packet to an 8390 network device. + */ + static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev) { long e8390_base = dev->base_addr; @@ -389,8 +406,15 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev) return 0; } -/* The typical workload of the driver: - Handle the ether interface interrupts. */ +/** + * ei_interrupt - + * @irq: + * @dev_id: + * @regs: + * + * The typical workload of the driver: + * Handle the ether interface interrupts. + */ void ei_interrupt(int irq, void *dev_id, struct pt_regs * regs) { @@ -492,7 +516,10 @@ void ei_interrupt(int irq, void *dev_id, struct pt_regs * regs) return; } -/* +/** + * ei_tx_err - handle transmitter error + * @dev: network device which threw the exception + * * A transmitter error has happened. Most likely excess collisions (which * is a fairly normal condition). If the error is one where the Tx will * have been aborted, we try and send another one right away, instead of @@ -538,8 +565,13 @@ static void ei_tx_err(struct net_device *dev) } } -/* We have finished a transmit: check for errors and then trigger the next - packet to be sent. Called with lock held */ +/** + * ei_tx_intr - transmit interrupt handler + * @dev: network device for which tx intr is handled + * + * We have finished a transmit: check for errors and then trigger the next + * packet to be sent. Called with lock held + */ static void ei_tx_intr(struct net_device *dev) { @@ -625,8 +657,13 @@ static void ei_tx_intr(struct net_device *dev) netif_wake_queue(dev); } -/* We have a good packet(s), get it/them out of the buffers. - Called with lock held */ +/** + * ei_receive - receive some packets + * @dev: network device with which receive will be run + * + * We have a good packet(s), get it/them out of the buffers. + * Called with lock held + */ static void ei_receive(struct net_device *dev) { @@ -751,7 +788,10 @@ static void ei_receive(struct net_device *dev) return; } -/* +/** + * ei_rx_overrun - handle receiver overrun + * @dev: network device which threw exception + * * We have a receiver overrun: we have to kick the 8390 to get it started * again. Problem is that you have to kick it exactly as NS prescribes in * the updated datasheets, or "the NIC may act in an unpredictable manner." @@ -900,7 +940,10 @@ static inline void make_mc_bits(u8 *bits, struct net_device *dev) } } -/* +/** + * do_set_multicast_list - set/clear multicast filter + * @dev: net device for which multicast filter is adjusted + * * Set or clear the multicast filter for this adaptor. May be called * from a BH in 2.1.x. Must be called with lock held. */ @@ -970,7 +1013,10 @@ static void set_multicast_list(struct net_device *dev) spin_unlock_irqrestore(&ei_local->page_lock, flags); } -/* +/** + * ethdev_init - init rest of 8390 device struct + * @dev: network device structure to init + * * Initialize the rest of the 8390 device structure. Do NOT __init * this, as it is used by 8390 based modular drivers too. */ @@ -1006,7 +1052,11 @@ int ethdev_init(struct net_device *dev) /* This page of functions should be 8390 generic */ /* Follow National Semi's recommendations for initializing the "NIC". */ -/* +/** + * NS8390_init - initialize 8390 hardware + * @dev: network device to initialize + * @startp: boolean. non-zero value to initiate chip processing + * * Must be called with lock held. */ @@ -1066,7 +1116,6 @@ void NS8390_init(struct net_device *dev, int startp) outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR); /* rx on, */ do_set_multicast_list(dev); /* (re)load the mcast table */ } - return; } /* Trigger a transmit start, assuming the length is valid. diff --git a/drivers/net/Config.in b/drivers/net/Config.in index b62986f83..057f2f704 100644 --- a/drivers/net/Config.in +++ b/drivers/net/Config.in @@ -124,9 +124,7 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then bool ' EISA, VLB, PCI and on board controllers' CONFIG_NET_PCI if [ "$CONFIG_NET_PCI" = "y" ]; then tristate ' AMD PCnet32 (VLB and PCI) support' CONFIG_PCNET32 - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate ' Adaptec Starfire support (EXPERIMENTAL)' CONFIG_ADAPTEC_STARFIRE - fi + dep_tristate ' Adaptec Starfire support (EXPERIMENTAL)' CONFIG_ADAPTEC_STARFIRE $CONFIG_PCI $CONFIG_EXPERIMENTAL if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate ' Ansel Communications EISA 3200 support (EXPERIMENTAL)' CONFIG_AC3200 fi @@ -134,12 +132,12 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then tristate ' Apricot Xen-II on board Ethernet' CONFIG_APRICOT tristate ' CS89x0 support' CONFIG_CS89x0 tristate ' Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5 - tristate ' DECchip Tulip (dc21x4x) PCI support' CONFIG_TULIP + dep_tristate ' DECchip Tulip (dc21x4x) PCI support' CONFIG_TULIP $CONFIG_PCI tristate ' Digi Intl. RightSwitch SE-X support' CONFIG_DGRS if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate ' DM9102 PCI Fast Ethernet Adapter support (EXPERIMENTAL)' CONFIG_DM9102 fi - tristate ' EtherExpressPro/100 support' CONFIG_EEPRO100 + dep_tristate ' EtherExpressPro/100 support' CONFIG_EEPRO100 $CONFIG_PCI if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then if [ "$CONFIG_EEPRO100" = "y" -o "$CONFIG_EEPRO100" = "m" ]; then bool ' Enable Power Management (EXPERIMENTAL)' CONFIG_EEPRO100_PM @@ -147,7 +145,7 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then tristate ' Mylex EISA LNE390A/B support (EXPERIMENTAL)' CONFIG_LNE390 tristate ' Novell/Eagle/Microdyne NE3210 EISA support (EXPERIMENTAL)' CONFIG_NE3210 fi - tristate ' PCI NE2000 support' CONFIG_NE2K_PCI + dep_tristate ' PCI NE2000 support' CONFIG_NE2K_PCI $CONFIG_PCI # tristate ' Sundance Alta support' CONFIG_ALTA if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate ' RealTek 8129 (not 8019/8029!) support (EXPERIMENTAL)' CONFIG_RTL8129 @@ -166,7 +164,9 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then fi bool ' Pocket and portable adapters' CONFIG_NET_POCKET if [ "$CONFIG_NET_POCKET" = "y" ]; then - tristate ' AT-LAN-TEC/RealTek pocket adapter support' CONFIG_ATP + if [ "$CONFIG_X86" = "y" ]; then + tristate ' AT-LAN-TEC/RealTek pocket adapter support' CONFIG_ATP + fi tristate ' D-Link DE600 pocket adapter support' CONFIG_DE600 tristate ' D-Link DE620 pocket adapter support' CONFIG_DE620 fi diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c index b3851ef09..91aeaced9 100644 --- a/drivers/net/defxx.c +++ b/drivers/net/defxx.c @@ -3495,6 +3495,6 @@ void dfx_xmt_flush( /* * Local variables: - * kernel-compile-command: "gcc -D__KERNEL__ -I/root/linux/include -Wall -Wstrict-prototypes -O2 -pipe -fomit-frame-pointer -fno-strength-reduce -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DCPU=586 -c defxx.c" + * kernel-compile-command: "gcc -D__KERNEL__ -I/root/linux/include -Wall -Wstrict-prototypes -O2 -pipe -fomit-frame-pointer -fno-strength-reduce -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -c defxx.c" * End: */ diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c index f855d1978..2832775ae 100644 --- a/drivers/net/epic100.c +++ b/drivers/net/epic100.c @@ -1099,6 +1099,12 @@ static int __devinit epic100_init_one (struct pci_dev *pdev, struct net_device *dev; long ioaddr; static int card_idx = -1; + static int printed_version = 0; + + if (!printed_version) { + printk (KERN_INFO "%s", version); + printed_version = 1; + } chip_idx = ent->driver_data; @@ -1280,13 +1286,7 @@ static struct pci_driver epic100_driver = { static int __init epic100_init (void) { - printk (KERN_INFO "%s", version); - - if (pci_register_driver (&epic100_driver) > 0) - return 0; - - pci_unregister_driver (&epic100_driver); - return -ENODEV; + return pci_module_init (&epic100_driver); } diff --git a/drivers/net/irda/irport.c b/drivers/net/irda/irport.c index bf001d83d..03944f066 100644 --- a/drivers/net/irda/irport.c +++ b/drivers/net/irda/irport.c @@ -941,10 +941,14 @@ static int irport_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) switch (cmd) { case SIOCSBANDWIDTH: /* Set bandwidth */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; irda_task_execute(self, __irport_change_speed, NULL, NULL, (void *) irq->ifr_baudrate); break; case SIOCSDONGLE: /* Set dongle */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; /* Initialize dongle */ dongle = irda_device_dongle_init(dev, irq->ifr_dongle); if (!dongle) @@ -965,12 +969,16 @@ static int irport_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) NULL); break; case SIOCSMEDIABUSY: /* Set media busy */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; irda_device_set_media_busy(self->netdev, TRUE); break; case SIOCGRECEIVING: /* Check if we are receiving right now */ irq->ifr_receiving = irport_is_receiving(self); break; case SIOCSDTRRTS: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; irport_set_dtr_rts(dev, irq->ifr_dtr, irq->ifr_rts); break; default: diff --git a/drivers/net/irda/irtty.c b/drivers/net/irda/irtty.c index 931ae9c4c..1fd3acda9 100644 --- a/drivers/net/irda/irtty.c +++ b/drivers/net/irda/irtty.c @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli <dagb@cs.uit.no> * Created at: Tue Dec 9 21:18:38 1997 - * Modified at: Fri Jan 14 21:02:27 2000 + * Modified at: Sat Mar 11 07:43:30 2000 * Modified by: Dag Brattli <dagb@cs.uit.no> * Sources: slip.c by Laurence Culhane, <loz@holmes.demon.co.uk> * Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org> @@ -962,10 +962,14 @@ static int irtty_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) switch (cmd) { case SIOCSBANDWIDTH: /* Set bandwidth */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; irda_task_execute(self, irtty_change_speed, NULL, NULL, (void *) irq->ifr_baudrate); break; case SIOCSDONGLE: /* Set dongle */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; /* Initialize dongle */ dongle = irda_device_dongle_init(dev, irq->ifr_dongle); if (!dongle) @@ -986,15 +990,21 @@ static int irtty_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) NULL); break; case SIOCSMEDIABUSY: /* Set media busy */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; irda_device_set_media_busy(self->netdev, TRUE); break; case SIOCGRECEIVING: /* Check if we are receiving right now */ irq->ifr_receiving = irtty_is_receiving(self); break; case SIOCSDTRRTS: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; irtty_set_dtr_rts(dev, irq->ifr_dtr, irq->ifr_rts); break; case SIOCSMODE: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; irtty_set_mode(dev, irq->ifr_mode); break; default: diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c index 2dd149bf1..df9c63621 100644 --- a/drivers/net/irda/nsc-ircc.c +++ b/drivers/net/irda/nsc-ircc.c @@ -1947,9 +1947,13 @@ static int nsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) switch (cmd) { case SIOCSBANDWIDTH: /* Set bandwidth */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; nsc_ircc_change_speed(self, irq->ifr_baudrate); break; case SIOCSMEDIABUSY: /* Set media busy */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; irda_device_set_media_busy(self->netdev, TRUE); break; case SIOCGRECEIVING: /* Check if we are receiving right now */ diff --git a/drivers/net/irda/toshoboe.c b/drivers/net/irda/toshoboe.c index 951b08d8f..387208e2f 100644 --- a/drivers/net/irda/toshoboe.c +++ b/drivers/net/irda/toshoboe.c @@ -603,11 +603,15 @@ static int toshoboe_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) switch (cmd) { case SIOCSBANDWIDTH: /* Set bandwidth */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; /* toshoboe_setbaud(self, irq->ifr_baudrate); */ /* Just change speed once - inserted by Paul Bristow */ self->new_speed = irq->ifr_baudrate; break; case SIOCSMEDIABUSY: /* Set media busy */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; irda_device_set_media_busy(self->netdev, TRUE); break; case SIOCGRECEIVING: /* Check if we are receiving right now */ diff --git a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c index 239120e51..2456e012d 100644 --- a/drivers/net/irda/w83977af_ir.c +++ b/drivers/net/irda/w83977af_ir.c @@ -1332,9 +1332,13 @@ static int w83977af_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) switch (cmd) { case SIOCSBANDWIDTH: /* Set bandwidth */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; w83977af_change_speed(self, irq->ifr_baudrate); break; case SIOCSMEDIABUSY: /* Set media busy */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; irda_device_set_media_busy(self->netdev, TRUE); break; case SIOCGRECEIVING: /* Check if we are receiving right now */ diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c index f6929905e..743812346 100644 --- a/drivers/net/ne2k-pci.c +++ b/drivers/net/ne2k-pci.c @@ -71,28 +71,55 @@ enum { STOP_PG_0x60=0x100, }; -/* This will eventually be converted to the standard PCI probe table. */ + +enum ne2k_pci_chipsets { + CH_RealTek_RTL_8029 = 0, + CH_Winbond_89C940, + CH_Compex_RL2000, + CH_KTI_ET32P2, + CH_NetVin_NV5000SC, + CH_Via_86C926, + CH_SureCom_NE34, + CH_Winbond_W89C940F, + CH_Holtek_HT80232, + CH_Holtek_HT80229, +}; + static struct { - unsigned short vendor, dev_id; char *name; int flags; -} -pci_clone_list[] __initdata = { - {0x10ec, 0x8029, "RealTek RTL-8029", 0}, - {0x1050, 0x0940, "Winbond 89C940", 0}, - {0x11f6, 0x1401, "Compex RL2000", 0}, - {0x8e2e, 0x3000, "KTI ET32P2", 0}, - {0x4a14, 0x5000, "NetVin NV5000SC", 0}, - {0x1106, 0x0926, "Via 86C926", ONLY_16BIT_IO}, - {0x10bd, 0x0e34, "SureCom NE34", 0}, - {0x1050, 0x5a5a, "Winbond W89C940F", 0}, - {0x12c3, 0x0058, "Holtek HT80232", ONLY_16BIT_IO | HOLTEK_FDX}, - {0x12c3, 0x5598, "Holtek HT80229", - ONLY_32BIT_IO | HOLTEK_FDX | STOP_PG_0x60 }, +} pci_clone_list[] __devinitdata = { + {"RealTek RTL-8029", 0}, + {"Winbond 89C940", 0}, + {"Compex RL2000", 0}, + {"KTI ET32P2", 0}, + {"NetVin NV5000SC", 0}, + {"Via 86C926", ONLY_16BIT_IO}, + {"SureCom NE34", 0}, + {"Winbond W89C940F", 0}, + {"Holtek HT80232", ONLY_16BIT_IO | HOLTEK_FDX}, + {"Holtek HT80229", ONLY_32BIT_IO | HOLTEK_FDX | STOP_PG_0x60 }, {0,} }; + +static struct pci_device_id ne2k_pci_tbl[] __devinitdata = { + { 0x10ec, 0x8029, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_RealTek_RTL_8029 }, + { 0x1050, 0x0940, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Winbond_89C940 }, + { 0x11f6, 0x1401, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Compex_RL2000 }, + { 0x8e2e, 0x3000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_KTI_ET32P2 }, + { 0x4a14, 0x5000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_NetVin_NV5000SC }, + { 0x1106, 0x0926, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Via_86C926 }, + { 0x10bd, 0x0e34, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_SureCom_NE34 }, + { 0x1050, 0x5a5a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Winbond_W89C940F }, + { 0x12c3, 0x0058, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Holtek_HT80232 }, + { 0x12c3, 0x5598, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Holtek_HT80229 }, + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, ne2k_pci_tbl); + + /* ---- No user-serviceable parts below ---- */ #define NE_BASE (dev->base_addr) @@ -104,8 +131,6 @@ pci_clone_list[] __initdata = { #define NESM_START_PG 0x40 /* First page of TX buffer */ #define NESM_STOP_PG 0x80 /* Last page +1 of RX ring */ -static int ne2k_pci_probe(void); -static struct net_device *ne2k_pci_probe1(long ioaddr, int irq, int chip_idx); static int ne2k_pci_open(struct net_device *dev); static int ne2k_pci_close(struct net_device *dev); @@ -122,47 +147,11 @@ static void ne2k_pci_block_output(struct net_device *dev, const int count, /* No room in the standard 8390 structure for extra info we need. */ struct ne2k_pci_card { - struct ne2k_pci_card *next; struct net_device *dev; struct pci_dev *pci_dev; }; -/* A list of all installed devices, for removing the driver module. */ -static struct ne2k_pci_card *ne2k_card_list = NULL; -static int __init ne2k_pci_init_module(void) -{ - /* We must emit version information. */ - if (debug) - printk(KERN_INFO "%s", version); - if (ne2k_pci_probe()) { - printk(KERN_NOTICE "ne2k-pci.c: No useable cards found, driver NOT installed.\n"); - return -ENODEV; - } - lock_8390_module(); - return 0; -} - -static void __exit ne2k_pci_cleanup_module(void) -{ - struct net_device *dev; - struct ne2k_pci_card *this_card; - - /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ - while (ne2k_card_list) { - dev = ne2k_card_list->dev; - unregister_netdev(dev); - release_region(dev->base_addr, NE_IO_EXTENT); - kfree(dev); - this_card = ne2k_card_list; - ne2k_card_list = ne2k_card_list->next; - kfree(this_card); - } - unlock_8390_module(); -} - -module_init(ne2k_pci_init_module); -module_exit(ne2k_pci_cleanup_module); /* NEx000-clone boards have a Station Address (SA) PROM (SAPROM) in the packet @@ -177,96 +166,42 @@ module_exit(ne2k_pci_cleanup_module); in the 'dev' and 'ei_status' structures. */ -#ifdef HAVE_DEVLIST -struct netdev_entry netcard_drv = -{"ne2k_pci", ne2k_pci_probe1, NE_IO_EXTENT, 0}; -#endif -static int __init ne2k_pci_probe(void) +static int __devinit ne2k_pci_init_one (struct pci_dev *pdev, + const struct pci_device_id *ent) { - struct pci_dev *pdev = NULL; - int cards_found = 0; - int i; struct net_device *dev; + int i, irq, reg0, start_page, stop_page; + unsigned char SA_prom[32]; + int chip_idx = ent->driver_data; + static unsigned version_printed = 0; + long ioaddr; + + if (version_printed++ == 0) + printk(KERN_INFO "%s", version); - if ( ! pci_present()) + ioaddr = pci_resource_start (pdev, 0); + irq = pdev->irq; + + if (!ioaddr || ((pci_resource_flags (pdev, 0) & IORESOURCE_IO) == 0)) { + printk (KERN_ERR "ne2k-pci: no I/O resource at PCI BAR #0\n"); return -ENODEV; - - while ((pdev = pci_find_class(PCI_CLASS_NETWORK_ETHERNET << 8, pdev)) != NULL) { - int pci_irq_line; - u16 pci_command, new_command; - unsigned long pci_ioaddr; - - /* Note: some vendor IDs (RealTek) have non-NE2k cards as well. */ - for (i = 0; pci_clone_list[i].vendor != 0; i++) - if (pci_clone_list[i].vendor == pdev->vendor - && pci_clone_list[i].dev_id == pdev->device) - break; - if (pci_clone_list[i].vendor == 0) - continue; - - pci_ioaddr = pdev->resource[0].start; - pci_irq_line = pdev->irq; - pci_read_config_word(pdev, PCI_COMMAND, &pci_command); - - /* Avoid already found cards from previous calls */ - if (check_region(pci_ioaddr, NE_IO_EXTENT)) - continue; - - { - static unsigned version_printed = 0; - if (version_printed++ == 0) - printk(KERN_INFO "%s", version); - } - - /* Activate the card: fix for brain-damaged Win98 BIOSes. */ - new_command = pci_command | PCI_COMMAND_IO; - if (pci_command != new_command) { - printk(KERN_INFO " The PCI BIOS has not enabled this" - " NE2k clone! Updating PCI command %4.4x->%4.4x.\n", - pci_command, new_command); - pci_write_config_word(pdev, PCI_COMMAND, new_command); - } -#ifndef __sparc__ - if (pci_irq_line <= 0 || pci_irq_line >= NR_IRQS) - printk(KERN_WARNING " WARNING: The PCI BIOS assigned this PCI NE2k" - " card to IRQ %d, which is unlikely to work!.\n" - KERN_WARNING " You should use the PCI BIOS setup to assign" - " a valid IRQ line.\n", pci_irq_line); -#endif - printk("ne2k-pci.c: PCI NE2000 clone '%s' at I/O %#lx, IRQ %d.\n", - pci_clone_list[i].name, pci_ioaddr, pci_irq_line); - dev = ne2k_pci_probe1(pci_ioaddr, pci_irq_line, i); - if (dev == 0) { - /* Should not happen. */ - printk(KERN_ERR "ne2k-pci: Probe of PCI card at %#lx failed.\n", - pci_ioaddr); - continue; - } else { - struct ne2k_pci_card *ne2k_card = - kmalloc(sizeof(struct ne2k_pci_card), GFP_KERNEL); - ne2k_card->next = ne2k_card_list; - ne2k_card_list = ne2k_card; - ne2k_card->dev = dev; - ne2k_card->pci_dev = pdev; - } - - cards_found++; } - - return cards_found ? 0 : -ENODEV; -} - -static struct net_device __init *ne2k_pci_probe1(long ioaddr, int irq, int chip_idx) -{ - struct net_device *dev; - int i; - unsigned char SA_prom[32]; - int start_page, stop_page; - int reg0 = inb(ioaddr); - + + if (pci_enable_device (pdev)) { + printk (KERN_ERR "ne2k-pci: cannot enable device\n"); + return -EIO; + } + + if (request_region (ioaddr, NE_IO_EXTENT, "ne2k-pci") == NULL) { + printk (KERN_ERR "ne2k-pci: I/O resource 0x%x @ 0x%lx busy\n", + NE_IO_EXTENT, ioaddr); + return -EBUSY; + } + + reg0 = inb(ioaddr); if (reg0 == 0xFF) - return 0; + goto err_out_free_res; /* Do a preliminary verification that we have a 8390. */ { @@ -279,12 +214,16 @@ static struct net_device __init *ne2k_pci_probe1(long ioaddr, int irq, int chip_ if (inb(ioaddr + EN0_COUNTER0) != 0) { outb(reg0, ioaddr); outb(regd, ioaddr + 0x0d); /* Restore the old values. */ - return 0; + goto err_out_free_res; } } dev = init_etherdev(NULL, 0); - + if (!dev) { + printk (KERN_ERR "ne2k-pci: cannot allocate ethernet device\n"); + goto err_out_free_res; + } + /* Reset card. Who knows what dain-bramaged state it was left in. */ { unsigned long reset_start_time = jiffies; @@ -298,14 +237,15 @@ static struct net_device __init *ne2k_pci_probe1(long ioaddr, int irq, int chip_ /* Limit wait: '2' avoids jiffy roll-over. */ if (jiffies - reset_start_time > 2) { printk("ne2k-pci: Card failure (no reset ack).\n"); - return 0; + goto err_out_free_netdev; } outb(0xff, ioaddr + EN0_ISR); /* Ack all intr. */ } if (load_8390_module("ne2k-pci.c")) { - return 0; + printk (KERN_ERR "ne2k-pci: cannot load 8390 module\n"); + goto err_out_free_netdev; } /* Read the 16 bytes of station address PROM. @@ -355,12 +295,10 @@ static struct net_device __init *ne2k_pci_probe1(long ioaddr, int irq, int chip_ /* Allocate dev->priv and fill in 8390 specific dev fields. */ if (ethdev_init(dev)) { - printk ("%s: unable to get memory for dev->priv.\n", dev->name); - return 0; + printk (KERN_ERR "%s: unable to get memory for dev->priv.\n", dev->name); + goto err_out_free_netdev; } - request_region(ioaddr, NE_IO_EXTENT, dev->name); - 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++) { @@ -387,16 +325,26 @@ static struct net_device __init *ne2k_pci_probe1(long ioaddr, int irq, int chip_ dev->open = &ne2k_pci_open; dev->stop = &ne2k_pci_close; NS8390_init(dev, 0); - return dev; + return 0; + +err_out_free_netdev: + unregister_netdev (dev); + kfree (dev); +err_out_free_res: + release_region (ioaddr, NE_IO_EXTENT); + return -ENODEV; + } static int ne2k_pci_open(struct net_device *dev) { - if (request_irq(dev->irq, ei_interrupt, SA_SHIRQ, dev->name, dev)) + MOD_INC_USE_COUNT; + if (request_irq(dev->irq, ei_interrupt, SA_SHIRQ, dev->name, dev)) { + MOD_DEC_USE_COUNT; return -EAGAIN; + } ei_open(dev); - MOD_INC_USE_COUNT; return 0; } @@ -589,6 +537,58 @@ ne2k_pci_block_output(struct net_device *dev, int count, return; } + +static void __devexit ne2k_pci_remove_one (struct pci_dev *pdev) +{ + struct net_device *dev = pdev->driver_data; + + if (!dev) { + printk (KERN_ERR "bug! ne2k_pci_remove_one called w/o net_device\n"); + return; + } + + unregister_netdev (dev); + release_region (dev->base_addr, NE_IO_EXTENT); + kfree (dev); +} + + +static struct pci_driver ne2k_driver = { + name: "ne2k-pci", + probe: ne2k_pci_init_one, + remove: ne2k_pci_remove_one, + id_table: ne2k_pci_tbl, +}; + + +static int __init ne2k_pci_init(void) +{ + int rc; + + MOD_INC_USE_COUNT; + lock_8390_module(); + + rc = pci_module_init (&ne2k_driver); + + /* XXX should this test CONFIG_HOTPLUG like pci_module_init? */ + if (rc <= 0) + unlock_8390_module(); + + MOD_DEC_USE_COUNT; + + return rc; +} + + +static void __exit ne2k_pci_cleanup(void) +{ + pci_unregister_driver (&ne2k_driver); + unlock_8390_module(); +} + +module_init(ne2k_pci_init); +module_exit(ne2k_pci_cleanup); + /* * Local variables: diff --git a/drivers/net/net_init.c b/drivers/net/net_init.c index f2976e562..214341b53 100644 --- a/drivers/net/net_init.c +++ b/drivers/net/net_init.c @@ -1,4 +1,4 @@ -/* netdrv_init.c: Initialization for network devices. */ +/* net_init.c: Initialization for network devices. */ /* Written 1993,1994,1995 by Donald Becker. @@ -27,6 +27,8 @@ 08/11/99 - Alan Cox: Got fed up of the mess in this file and cleaned it 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 + */ #include <linux/config.h> @@ -139,14 +141,22 @@ static struct net_device *init_netdev(struct net_device *dev, int sizeof_priv, c return dev; } -/* Fill in the fields of the device structure with ethernet-generic values. - - If no device structure is passed, a new one is constructed, complete with - a SIZEOF_PRIVATE 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. The passed string area should be 8 bytes - long. +/** + * init_etherdev - Register ethernet device + * @dev: An ethernet 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 ethernet-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. The passed string area should be 8 bytes + * long. */ struct net_device *init_etherdev(struct net_device *dev, int sizeof_priv) diff --git a/drivers/net/pcmcia/3c575_cb.c b/drivers/net/pcmcia/3c575_cb.c index e98e1eda8..bff7bc9ed 100644 --- a/drivers/net/pcmcia/3c575_cb.c +++ b/drivers/net/pcmcia/3c575_cb.c @@ -12,10 +12,16 @@ 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 + + Linux Kernel Additions: + + LK1.1.2 (March 19, 2000) + * New PCI interface (jgarzik) + */ static char *version = -"3c59x.c:v0.99L 5/28/99 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n"; +"3c575_cb.c:v0.99L+LK1.1.2 3/19/2000 Donald Becker and others http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n"; /* "Knobs" that adjust features and parameters. */ /* Set the copy breakpoint for the copy-only-tiny-frames scheme. @@ -64,6 +70,7 @@ static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0, rx_csumhits; #include <linux/malloc.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> @@ -85,9 +92,6 @@ MODULE_PARM(options, "1-" __MODULE_STRING(8) "i"); MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i"); MODULE_PARM(rx_copybreak, "i"); MODULE_PARM(max_interrupt_work, "i"); -MODULE_PARM(compaq_ioaddr, "i"); -MODULE_PARM(compaq_irq, "i"); -MODULE_PARM(compaq_device_id, "i"); /* Operational parameter that usually are not changed. */ @@ -103,6 +107,10 @@ MODULE_PARM(compaq_device_id, "i"); code size of a per-interface flag is not worthwhile. */ static char mii_preamble_required = 0; +#define PFX "3c575_cb: " + + + /* Theory of Operation @@ -186,76 +194,134 @@ 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 drv_flags, io_size; - struct net_device *(*probe1)(struct pci_dev *pdev, struct net_device *dev, - long ioaddr, int irq, int chip_idx, int fnd_cnt); -}; enum { IS_VORTEX=1, IS_BOOMERANG=2, IS_CYCLONE=4, HAS_PWR_CTRL=0x10, HAS_MII=0x20, HAS_NWAY=0x40, HAS_CB_FNS=0x80, }; -static struct net_device *vortex_probe1(struct pci_dev *pdev, - struct net_device *dev, long ioaddr, - int irq, int dev_id, int card_idx); -static struct pci_id_info pci_tbl[] = { - {"3c590 Vortex 10Mbps", 0x10B7, 0x5900, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, vortex_probe1}, - {"3c595 Vortex 100baseTx", 0x10B7, 0x5950, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, vortex_probe1}, - {"3c595 Vortex 100baseT4", 0x10B7, 0x5951, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, vortex_probe1}, - {"3c595 Vortex 100base-MII", 0x10B7, 0x5952, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, vortex_probe1}, - {"3Com Vortex", 0x10B7, 0x5900, 0xff00, - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, vortex_probe1}, - {"3c900 Boomerang 10baseT", 0x10B7, 0x9000, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, vortex_probe1}, - {"3c900 Boomerang 10Mbps Combo", 0x10B7, 0x9001, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, vortex_probe1}, - {"3c900 Cyclone 10Mbps Combo", 0x10B7, 0x9005, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1}, - {"3c900B-FL Cyclone 10base-FL", 0x10B7, 0x900A, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1}, - {"3c905 Boomerang 100baseTx", 0x10B7, 0x9050, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1}, - {"3c905 Boomerang 100baseT4", 0x10B7, 0x9051, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1}, - {"3c905B Cyclone 100baseTx", 0x10B7, 0x9055, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, vortex_probe1}, - {"3c905B Cyclone 10/100/BNC", 0x10B7, 0x9058, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, vortex_probe1}, - {"3c905B-FX Cyclone 100baseFx", 0x10B7, 0x905A, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1}, - {"3c905C Tornado", 0x10B7, 0x9200, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1}, - {"3c980 Cyclone", 0x10B7, 0x9800, 0xfff0, - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1}, - {"3cSOHO100-TX Hurricane", 0x10B7, 0x7646, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1}, - {"3c555 Laptop Hurricane", 0x10B7, 0x5055, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1}, - {"3c575 Boomerang CardBus", 0x10B7, 0x5057, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1}, - {"3CCFE575 Cyclone CardBus", 0x10B7, 0x5157, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS, - 128, vortex_probe1}, - {"3CCFE575CT Cyclone CardBus", 0x10B7, 0x5257, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS, - 128, vortex_probe1}, - {"3CCFE656 Cyclone CardBus", 0x10B7, 0x6560, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS, - 128, vortex_probe1}, - {"3CCFEM656 Cyclone CardBus", 0x10B7, 0x6562, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS, - 128, vortex_probe1}, - {"3c575 series CardBus (unknown version)", 0x10B7, 0x5057, 0xf0ff, - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1}, - {"3Com Boomerang (unknown version)", 0x10B7, 0x9000, 0xff00, - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, vortex_probe1}, + + +enum vortex_chips { + CH_3C590 = 0, + CH_3C595_1, + CH_3C595_2, + CH_3C595_3, + CH_VORTEX, + CH_3C900_1, + CH_3C900_2, + CH_3C900_3, + CH_3C900B_FL, + CH_3C905_1, + CH_3C905_2, + CH_3C905B_1, + CH_3C905B_2, + CH_3C905B_FX, + CH_3C905C, + CH_3C980, + CH_3CSOHO100_TX, + CH_3C555, + CH_3C575_1, + CH_3CCFE575, + CH_3CCFE575CT, + CH_3CCFE656, + CH_3CCFEM656, + CH_3C575_2, + CH_BOOMERANG, +}; + + +/* note: this array directly indexed by above enums, and MUST + * be kept in sync with both the enums above, and the PCI device + * table below + */ +static struct vortex_chip_info { + const char *name; + int flags; + int drv_flags; + int io_size; +} vortex_info_tbl[] = { + {"3c590 Vortex 10Mbps", + PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, }, + {"3c595 Vortex 100baseTx", + PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, }, + {"3c595 Vortex 100baseT4", + PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, }, + {"3c595 Vortex 100base-MII", + PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, }, + {"3Com Vortex", + PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, }, + {"3c900 Boomerang 10baseT", + PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, }, + {"3c900 Boomerang 10Mbps Combo", + PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, }, + {"3c900 Cyclone 10Mbps Combo", + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, + {"3c900B-FL Cyclone 10base-FL", + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 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, }, + {"3c905B Cyclone 10/100/BNC", + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, }, + {"3c905B-FX Cyclone 100baseFx", + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, + {"3c905C Tornado", + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, + {"3c980 Cyclone", + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, + {"3cSOHO100-TX Hurricane", + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, + {"3c555 Laptop Hurricane", + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, + {"3c575 Boomerang CardBus", + PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, }, + {"3CCFE575 Cyclone CardBus", + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS, 128, }, + {"3CCFE575CT Cyclone CardBus", + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS, 128, }, + {"3CCFE656 Cyclone CardBus", + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS, 128, }, + {"3CCFEM656 Cyclone CardBus", + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS, 128, }, + {"3c575 series CardBus (unknown version)", + PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, }, + {"3Com Boomerang (unknown version)", + PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, }, + {0,}, /* 0 terminated list. */ +}; + + +static struct pci_device_id vortex_pci_tbl[] __devinit = { + { 0x10B7, 0x5900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C590 }, + { 0x10B7, 0x5950, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C595_1 }, + { 0x10B7, 0x5951, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C595_2 }, + { 0x10B7, 0x5952, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C595_3 }, + { 0x10B7, 0x5900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_VORTEX }, + { 0x10B7, 0x9000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_1 }, + { 0x10B7, 0x9001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_2 }, + { 0x10B7, 0x9005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_3 }, + { 0x10B7, 0x900A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900B_FL }, + { 0x10B7, 0x9050, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905_1 }, + { 0x10B7, 0x9051, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905_2 }, + { 0x10B7, 0x9055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905B_1 }, + { 0x10B7, 0x9058, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905B_2 }, + { 0x10B7, 0x905A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905B_FX }, + { 0x10B7, 0x9200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905C }, + { 0x10B7, 0x9800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C980 }, + { 0x10B7, 0x7646, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CSOHO100_TX }, + { 0x10B7, 0x5055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C555 }, + { 0x10B7, 0x5057, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C575_1 }, + { 0x10B7, 0x5157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE575 }, + { 0x10B7, 0x5257, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE575CT }, + { 0x10B7, 0x6560, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE656 }, + { 0x10B7, 0x6562, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFEM656 }, + { 0x10B7, 0x5057, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C575_2 }, + { 0x10B7, 0x9000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_BOOMERANG }, {0,}, /* 0 terminated list. */ }; +MODULE_DEVICE_TABLE(pci, vortex_pci_tbl); + /* Operational definitions. These are not used by other compilation units and thus are not @@ -400,7 +466,7 @@ struct vortex_private { /* The addresses of transmit- and receive-in-place skbuffs. */ struct sk_buff* rx_skbuff[RX_RING_SIZE]; struct sk_buff* tx_skbuff[TX_RING_SIZE]; - struct net_device *next_module; + struct net_device *next_module; /* NULL if PCI device */ void *priv_addr; unsigned int cur_rx, cur_tx; /* The next free ring entry */ unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ @@ -463,9 +529,8 @@ static struct media_table { { "Default", 0, 0xFF, XCVR_10baseT, 10000}, }; -#ifndef CARDBUS -static int vortex_scan(struct net_device *dev, struct pci_id_info pci_tbl[]); -#endif +static int vortex_probe1(struct pci_dev *pdev, long ioaddr, int irq, + int chip_idx, int card_idx); static void vortex_up(struct net_device *dev); static void vortex_down(struct net_device *dev); static int vortex_open(struct net_device *dev); @@ -484,7 +549,6 @@ static struct net_device_stats *vortex_get_stats(struct net_device *dev); static void set_rx_mode(struct net_device *dev); static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static void vortex_tx_timeout(struct net_device *dev); -static void acpi_wake(struct pci_dev *pdev); static void acpi_set_WOL(struct net_device *dev); /* This driver uses 'options' to pass the media type, full-duplex flag, etc. */ @@ -492,280 +556,181 @@ 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}; -/* A list of all installed Vortex devices, for removing the driver module. */ -static struct net_device *root_vortex_dev = NULL; -#ifdef MODULE -#ifndef CARDBUS -/* Variables to work-around the Compaq PCI BIOS32 problem. */ -static int compaq_ioaddr = 0, compaq_irq = 0, compaq_device_id = 0x5900; -#endif -#ifdef CARDBUS +/* A list of all installed Vortex EISA devices, for removing the driver module. */ +static struct net_device *root_vortex_eisa_dev = NULL; -#include <pcmcia/driver_ops.h> +static int vortex_cards_found = 0; -static void vortex_reap(void) -{ - struct net_device **devp, **next; - printk(KERN_DEBUG "vortex_reap()\n"); - for (devp = &root_vortex_dev; *devp; devp = next) { - struct vortex_private *vp = (*devp)->priv; - next = &vp->next_module; - if (vp->open || !vp->reap) continue; - unregister_netdev(*devp); - if (vp->cb_fn_base) iounmap(vp->cb_fn_base); - kfree(*devp); - kfree(vp->priv_addr); - *devp = *next; next = devp; - } -} -static dev_node_t *vortex_attach(dev_locator_t *loc) -{ - u16 dev_id, vendor_id; - u32 io; - u8 irq; - struct net_device *dev; - int chip_idx; - struct pci_dev *pdev; - vortex_reap(); - if (loc->bus != LOC_PCI) return NULL; - pdev = pci_find_slot (loc->b.pci.bus, loc->b.pci.devfn); - if (!pdev) return NULL; - io = pci_resource_start (pdev, 0); - irq = pdev->irq; - vendor_id = pdev->vendor; - dev_id = pdev->device; - printk(KERN_INFO "vortex_attach(bus %d, function %d, device %4.4x)\n", - pdev->bus->number, pdev->devfn, dev_id); - if (io == 0 || irq == 0) { - printk(KERN_ERR "The 3Com CardBus Ethernet interface was not " - "assigned an %s.\n" KERN_ERR " It will not be activated.\n", - io == 0 ? "I/O address" : "IRQ"); - return NULL; - } - for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++) - if (vendor_id == pci_tbl[chip_idx].vendor_id - && (dev_id & pci_tbl[chip_idx].device_id_mask) == - pci_tbl[chip_idx].device_id) - break; - if (pci_tbl[chip_idx].vendor_id == 0) { /* Compiled out! */ - printk(KERN_INFO "Unable to match chip type %4.4x %4.4x in " - "vortex_attach().\n", vendor_id, dev_id); - return NULL; - } - dev = vortex_probe1(pdev, NULL, io, irq, chip_idx, MAX_UNITS+1); - if (dev) { - dev_node_t *node = kmalloc(sizeof(dev_node_t), GFP_KERNEL); - strcpy(node->dev_name, dev->name); - node->major = node->minor = 0; - node->next = NULL; - MOD_INC_USE_COUNT; - return node; - } - return NULL; -} -static void vortex_detach(dev_node_t *node) +static void vortex_suspend (struct pci_dev *pdev) { - struct net_device *dev, *next; - printk(KERN_DEBUG "vortex_detach(%s)\n", node->dev_name); - for (dev = root_vortex_dev; dev; dev = next) { - next = ((struct vortex_private *)dev->priv)->next_module; - if (strcmp(dev->name, node->dev_name) == 0) break; - } - if (dev && dev->priv) { - struct vortex_private *vp = dev->priv; - if (vp->open) vortex_down(dev); - vp->reap = 1; - kfree(node); - MOD_DEC_USE_COUNT; - } -} + struct net_device *dev = pdev->driver_data; + + printk(KERN_DEBUG "vortex_suspend(%s)\n", dev->name); -static void vortex_suspend(dev_node_t *node) -{ - struct net_device *dev, *next; - printk(KERN_DEBUG "vortex_suspend(%s)\n", node->dev_name); - for (dev = root_vortex_dev; dev; dev = next) { - next = ((struct vortex_private *)dev->priv)->next_module; - if (strcmp(dev->name, node->dev_name) == 0) break; - } if (dev && dev->priv) { struct vortex_private *vp = (struct vortex_private *)dev->priv; - if (vp->open) vortex_down(dev); + if (vp->open) { + netif_device_detach(dev); + vortex_down(dev); + } } } -static void vortex_resume(dev_node_t *node) + +static void vortex_resume (struct pci_dev *pdev) { - struct net_device *dev, *next; - printk(KERN_DEBUG "vortex_resume(%s)\n", node->dev_name); - for (dev = root_vortex_dev; dev; dev = next) { - next = ((struct vortex_private *)dev->priv)->next_module; - if (strcmp(dev->name, node->dev_name) == 0) break; - } + struct net_device *dev = pdev->driver_data; + + printk(KERN_DEBUG "vortex_resume(%s)\n", dev->name); + if (dev && dev->priv) { struct vortex_private *vp = (struct vortex_private *)dev->priv; - if (vp->open) vortex_up(dev); + if (vp->open) { + vortex_up(dev); + netif_device_attach(dev); + } } } -struct driver_operations vortex_ops = { - "3c575_cb", vortex_attach, vortex_suspend, vortex_resume, vortex_detach -}; -#endif /* Cardbus support */ - -int init_module(void) +/* returns count found (>= 0), or negative on error */ +static int __init vortex_eisa_init (void) { - if (vortex_debug) - printk(KERN_INFO "%s", version); -#ifdef CARDBUS - register_driver(&vortex_ops); - return 0; -#else - return vortex_scan(0, pci_tbl); -#endif -} - -#else -int tc59x_probe(struct net_device *dev) -{ - static int did_version = -1; - if (++did_version <= 0) - printk(KERN_INFO "%s", version); - return vortex_scan(dev, pci_tbl); -} -#endif /* not MODULE */ - -#ifndef CARDBUS -static int vortex_scan(struct net_device *dev, struct pci_id_info pci_tbl[]) -{ - int cards_found = 0; + long ioaddr; + int rc; + int orig_cards_found = vortex_cards_found; - /* Allow an EISA-only driver. */ - struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn); - ioaddr = pdev->base_address[0] & ~3; - irq = pdev->irq; - } + /* Now check all slots of the EISA bus. */ + if (!EISA_bus) + return 0; - if (ioaddr == 0) { - printk(KERN_WARNING " A 3Com network adapter has been found, " - "however it has not been assigned an I/O address.\n" - " You may need to power-cycle the machine for this " - "device to work!\n"); - continue; - } + for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) { + int device_id; - /* Activate the card. */ - pcibios_read_config_word(pci_bus, pci_device_fn, - PCI_COMMAND, &pci_command); - new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO; - 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); - } + if (request_region(ioaddr, VORTEX_TOTAL_SIZE, "vortex") == NULL) + continue; - dev = vortex_probe1(pci_bus, pci_device_fn, dev, ioaddr, irq, - chip_idx, cards_found); - - if (dev) { - /* Get and check the latency values. On the 3c590 series - the latency timer must be set to the maximum value to avoid - data corruption that occurs when the timer expires during - a transfer -- a bug in the Vortex chip only. */ - u8 pci_latency; - u8 new_latency = (device & 0xff00) == 0x5900 ? 248 : 32; - - pcibios_read_config_byte(pci_bus, pci_device_fn, - PCI_LATENCY_TIMER, &pci_latency); - if (pci_latency < new_latency) { - printk(KERN_INFO "%s: Overriding PCI latency" - " timer (CFLT) setting of %d, new value is %d.\n", - dev->name, pci_latency, new_latency); - pcibios_write_config_byte(pci_bus, pci_device_fn, - PCI_LATENCY_TIMER, new_latency); - } - dev = 0; - cards_found++; - } + /* Check the standard EISA ID register for an encoded '3Com'. */ + if (inw(ioaddr + 0xC80) != 0x6d50) { + release_region (ioaddr, VORTEX_TOTAL_SIZE); + continue; } - } - /* Now check all slots of the EISA bus. */ - if (EISA_bus) { - static long ioaddr = 0x1000; - for ( ; ioaddr < 0x9000; ioaddr += 0x1000) { - int device_id; - if (check_region(ioaddr, VORTEX_TOTAL_SIZE)) - continue; - /* Check the standard EISA ID register for an encoded '3Com'. */ - if (inw(ioaddr + 0xC80) != 0x6d50) - continue; - /* Check for a product that we support, 3c59{2,7} any rev. */ - device_id = (inb(ioaddr + 0xC82)<<8) + inb(ioaddr + 0xC83); - if ((device_id & 0xFF00) != 0x5900) - continue; - vortex_probe1(0, 0, dev, ioaddr, inw(ioaddr + 0xC88) >> 12, - 4, cards_found); - dev = 0; - cards_found++; + /* Check for a product that we support, 3c59{2,7} any rev. */ + device_id = (inb(ioaddr + 0xC82)<<8) + inb(ioaddr + 0xC83); + if ((device_id & 0xFF00) != 0x5900) { + release_region (ioaddr, VORTEX_TOTAL_SIZE); + continue; } - } -#ifdef MODULE - /* Special code to work-around the Compaq PCI BIOS32 problem. */ - if (compaq_ioaddr) { - vortex_probe1(0, 0, dev, compaq_ioaddr, compaq_irq, - compaq_device_id, cards_found++); - dev = 0; + rc = vortex_probe1(NULL, ioaddr, inw(ioaddr + 0xC88) >> 12, + 4, /* XXX is 4 correct eisa idx? */ + vortex_cards_found); + if (rc == 0) + vortex_cards_found++; + else + release_region (ioaddr, VORTEX_TOTAL_SIZE); } -#endif - return cards_found ? 0 : -ENODEV; + return vortex_cards_found - orig_cards_found; +} + + +/* returns count (>= 0), or negative on error */ +static int __devinit vortex_init_one (struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + int rc; + + rc = vortex_probe1 (pdev, pci_resource_start (pdev, 0), pdev->irq, + ent->driver_data, vortex_cards_found); + if (rc == 0) + vortex_cards_found++; + + return rc; } -#endif /* ! Cardbus */ -static struct net_device *vortex_probe1(struct pci_dev *pdev, - struct net_device *dev, long ioaddr, - int irq, int chip_idx, int card_idx) + +/* NOTE: pdev can be NULL, for the case of an EISA driver */ +static int __devinit vortex_probe1(struct pci_dev *pdev, + long ioaddr, int irq, + int chip_idx, int card_idx) { struct vortex_private *vp; int option; unsigned int eeprom[0x40], checksum = 0; /* EEPROM contents */ int i; + struct net_device *dev; + static int printed_version = 0; + + if (!printed_version) { + printk (KERN_INFO "%s", version); + printed_version = 1; + } - dev = init_etherdev(dev, 0); - - printk(KERN_INFO "%s: 3Com %s at 0x%lx, ", - dev->name, pci_tbl[chip_idx].name, ioaddr); - + dev = init_etherdev(NULL, sizeof(*vp)); + if (!dev) { + printk (KERN_ERR PFX "unable to allocate etherdev, aborting\n"); + return -ENOMEM; + } + + printk(KERN_INFO "%s: 3Com %s %s at 0x%lx, ", + dev->name, + pdev ? "PCI" : "EISA", + vortex_info_tbl[chip_idx].name, + ioaddr); + + /* private struct aligned and zeroed by init_etherdev */ + vp = dev->priv; + vp->priv_addr = vp; dev->base_addr = ioaddr; dev->irq = irq; dev->mtu = mtu; - /* Make certain the descriptor lists are aligned. */ - { - void *mem = kmalloc(sizeof(*vp) + 15, GFP_KERNEL); - vp = (void *)(((long)mem + 15) & ~15); - memset(vp, 0, sizeof(*vp)); - vp->priv_addr = mem; + /* module list only for EISA devices */ + if (pdev == NULL) { + vp->next_module = root_vortex_eisa_dev; + root_vortex_eisa_dev = dev; } - dev->priv = vp; + + /* PCI-only startup logic */ + if (pdev) { + /* EISA resources already marked, so only PCI needs to do this here */ + if (!request_region (ioaddr, vortex_info_tbl[chip_idx].io_size, + dev->name)) { + printk (KERN_ERR "%s: Cannot reserve I/O resource 0x%x @ 0x%lx, aborting\n", + dev->name, vortex_info_tbl[chip_idx].io_size, ioaddr); + kfree (dev); + return -EBUSY; + } + + /* wake up and enable device */ + if (pci_enable_device (pdev)) { + printk (KERN_ERR "%s: Cannot enable device, aborting\n", dev->name); + release_region (ioaddr, vortex_info_tbl[chip_idx].io_size); + kfree (dev); + return -EIO; + } - vp->next_module = root_vortex_dev; - root_vortex_dev = dev; + /* enable bus-mastering if necessary */ + if (vortex_info_tbl[chip_idx].flags & PCI_USES_MASTER) + pci_set_master (pdev); + } vp->lock = SPIN_LOCK_UNLOCKED; vp->chip_id = chip_idx; vp->pdev = 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; + /* The lower four bits are the media type. */ if (dev->mem_start) option = dev->mem_start; @@ -793,7 +758,7 @@ static struct net_device *vortex_probe1(struct pci_dev *pdev, EL3WINDOW(0); for (i = 0; i < 0x40; i++) { int timer; -#ifdef CARDBUS +#if 1 /* ifdef CARDBUS */ outw(0x230 + i, ioaddr + Wn0EepromCmd); #else outw(EEPROM_Read + i, ioaddr + Wn0EepromCmd); @@ -835,7 +800,7 @@ static struct net_device *vortex_probe1(struct pci_dev *pdev, dev->irq); #endif - if (pci_tbl[vp->chip_id].drv_flags & HAS_CB_FNS) { + if (pdev && vortex_info_tbl[vp->chip_id].drv_flags & HAS_CB_FNS) { u32 fn_st_addr; /* Cardbus function status space */ fn_st_addr = pci_resource_start (pdev, 2); if (fn_st_addr) @@ -922,9 +887,6 @@ static struct net_device *vortex_probe1(struct pci_dev *pdev, vp->full_bus_master_rx = (vp->info2 & 1) ? 1 : 2; } - /* We do a request_region() to register /proc/ioports info. */ - request_region(ioaddr, pci_tbl[chip_idx].io_size, dev->name); - /* The 3c59x-specific entries in the device structure. */ dev->open = &vortex_open; dev->hard_start_xmit = &vortex_start_xmit; @@ -932,10 +894,10 @@ static struct net_device *vortex_probe1(struct pci_dev *pdev, 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->tx_timeout = &vortex_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; - return dev; + return 0; } static void wait_for_completion(struct net_device *dev, int cmd) @@ -956,11 +918,13 @@ vortex_up(struct net_device *dev) long ioaddr = dev->base_addr; struct vortex_private *vp = (struct vortex_private *)dev->priv; union wn3_config config; - int i; - - /* Should be if(HAS_ACPI) */ - acpi_wake(vp->pdev); + int i, device_id; + if (vp->pdev) + device_id = vp->pdev->device; + else + device_id = 0x5900; /* EISA */ + /* Before initializing select the active media port. */ EL3WINDOW(3); config.i = inl(ioaddr + Wn3_Config); @@ -972,7 +936,7 @@ vortex_up(struct net_device *dev) media_tbl[vp->media_override].name); dev->if_port = vp->media_override; } else if (vp->autoselect) { - if (pci_tbl[vp->chip_id].drv_flags & HAS_NWAY) + if (vortex_info_tbl[vp->chip_id].drv_flags & HAS_NWAY) dev->if_port = XCVR_NWAY; else { /* Find first available media type, starting with 100baseTx. */ @@ -995,7 +959,7 @@ vortex_up(struct net_device *dev) vp->full_duplex = vp->force_fd; config.u.xcvr = dev->if_port; - if ( ! (pci_tbl[vp->chip_id].drv_flags & HAS_NWAY)) + if ( ! (vortex_info_tbl[vp->chip_id].drv_flags & HAS_NWAY)) outl(config.i, ioaddr + Wn3_Config); if (dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) { @@ -1045,12 +1009,11 @@ vortex_up(struct net_device *dev) if (vp->cb_fn_base) { u_short n = inw(ioaddr + Wn2_ResetOptions); /* Inverted LED polarity */ - if (pci_tbl[vp->chip_id].device_id != 0x5257) + if (device_id != 0x5257) n |= 0x0010; /* Inverted polarity of MII power bit */ - if ((pci_tbl[vp->chip_id].device_id == 0x6560) || - (pci_tbl[vp->chip_id].device_id == 0x6562) || - (pci_tbl[vp->chip_id].device_id == 0x5257)) + if ((device_id == 0x6560) || (device_id == 0x6562) || + (device_id == 0x5257)) n |= 0x4000; outw(n, ioaddr + Wn2_ResetOptions); } @@ -2088,66 +2051,107 @@ static void acpi_set_WOL(struct net_device *dev) /* Change the power state to D3; RxEnable doesn't take effect. */ pci_write_config_word(vp->pdev, 0xe0, 0x8103); } -/* Change from D3 (sleep) to D0 (active). - Problem: The Cyclone forgets all PCI config info during the transition! */ -static void acpi_wake(struct pci_dev *pdev) + + +static void __devexit vortex_remove_one (struct pci_dev *pdev) { - u32 base0, base1, romaddr; - u16 pci_command, pwr_command; - u8 pci_latency, pci_cacheline, irq; + struct net_device *dev = pdev->driver_data; + struct vortex_private *vp; - pci_read_config_word(pdev, 0xe0, &pwr_command); - if ((pwr_command & 3) == 0) + if (!dev) return; - pci_read_config_word( pdev, PCI_COMMAND, &pci_command); - pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &base0); - pci_read_config_dword(pdev, PCI_BASE_ADDRESS_1, &base1); - pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &romaddr); - pci_read_config_byte( pdev, PCI_LATENCY_TIMER, &pci_latency); - pci_read_config_byte( pdev, PCI_CACHE_LINE_SIZE, &pci_cacheline); - pci_read_config_byte( pdev, PCI_INTERRUPT_LINE, &irq); - - pci_write_config_word( pdev, 0xe0, 0x0000); - pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, base0); - pci_write_config_dword(pdev, PCI_BASE_ADDRESS_1, base1); - pci_write_config_dword(pdev, PCI_ROM_ADDRESS, romaddr); - pci_write_config_byte( pdev, PCI_INTERRUPT_LINE, irq); - pci_write_config_byte( pdev, PCI_LATENCY_TIMER, pci_latency); - pci_write_config_byte( pdev, PCI_CACHE_LINE_SIZE, pci_cacheline); - pci_write_config_word( pdev, PCI_COMMAND, pci_command | 5); + + vp = (void *)(dev->priv); + + /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ + unregister_netdev(dev); + outw(TotalReset, dev->base_addr + EL3_CMD); + release_region(dev->base_addr, vortex_info_tbl[vp->chip_id].io_size); + kfree(dev); } -#ifdef MODULE -void cleanup_module(void) + +static struct pci_driver vortex_driver = { + name: "3c575_cb", + probe: vortex_init_one, + remove: vortex_remove_one, + suspend: vortex_suspend, + resume: vortex_resume, + id_table: vortex_pci_tbl, +}; + + +static int vortex_have_pci = 0; +static int vortex_have_eisa = 0; + + +static int __init vortex_init (void) { - struct net_device *next_dev; + int rc; + + MOD_INC_USE_COUNT; + + rc = pci_module_init (&vortex_driver); + if (rc < 0) + goto out; + if (rc > 0) + vortex_have_pci = 1; + + rc = vortex_eisa_init (); + if (rc < 0) + goto out; + if (rc > 0) + vortex_have_eisa = 1; + +out: + MOD_DEC_USE_COUNT; + return rc; +} -#ifdef CARDBUS - unregister_driver(&vortex_ops); - vortex_reap(); -#endif - /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ - while (root_vortex_dev) { - struct vortex_private *vp=(void *)(root_vortex_dev->priv); - next_dev = vp->next_module; - unregister_netdev(root_vortex_dev); - outw(TotalReset, root_vortex_dev->base_addr + EL3_CMD); - release_region(root_vortex_dev->base_addr, - pci_tbl[vp->chip_id].io_size); - kfree(root_vortex_dev); - kfree(vp->priv_addr); - root_vortex_dev = next_dev; +static void __exit vortex_eisa_cleanup (void) +{ + struct net_device *dev, *tmp; + struct vortex_private *vp; + long ioaddr; + + dev = root_vortex_eisa_dev; + + while (dev) { + vp = dev->priv; + ioaddr = dev->base_addr; + + unregister_netdev (dev); + outw (TotalReset, ioaddr + EL3_CMD); + release_region (ioaddr, VORTEX_TOTAL_SIZE); + + tmp = dev; + dev = vp->next_module; + + kfree (tmp); } } -#endif /* MODULE */ + +static void __exit vortex_cleanup (void) +{ + if (vortex_have_pci) + pci_unregister_driver (&vortex_driver); + if (vortex_have_eisa) + vortex_eisa_cleanup (); +} + + +module_init(vortex_init); +module_exit(vortex_cleanup); + + /* * Local variables: - * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" - * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c" - * cardbus-compile-command: "gcc -DCARDBUS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c -o 3c575_cb.o -I/usr/src/linux/pcmcia-cs-3.0.9/include/" + * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c575_cb.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" + * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c575_cb.c" + * cardbus-compile-command: "gcc -DCONFIG_HOTPLUG -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c575_cb.c -o 3c575_cb.o -I/usr/src/linux/pcmcia-cs-3.0.9/include/" * c-indent-level: 4 * c-basic-offset: 4 * tab-width: 4 diff --git a/drivers/net/pcmcia/Config.in b/drivers/net/pcmcia/Config.in index 534a4bdbd..936abfed8 100644 --- a/drivers/net/pcmcia/Config.in +++ b/drivers/net/pcmcia/Config.in @@ -18,6 +18,7 @@ if [ "$CONFIG_NET_PCMCIA" = "y" ]; then if [ "$CONFIG_CARDBUS" = "y" ]; then dep_tristate ' 3Com 3c575 CardBus support' CONFIG_PCMCIA_3C575 m + tristate ' Xircom Tulip-like CardBus support' CONFIG_PCMCIA_XIRTULIP fi bool 'Pcmcia Wireless LAN' CONFIG_NET_PCMCIA_RADIO diff --git a/drivers/net/pcmcia/Makefile b/drivers/net/pcmcia/Makefile index 5d0d36f4a..65938d96d 100644 --- a/drivers/net/pcmcia/Makefile +++ b/drivers/net/pcmcia/Makefile @@ -19,8 +19,6 @@ obj- := # Things that need to export symbols export-objs := ray_cs.o -CFLAGS_3c575_cb.o = -DCARDBUS -DMODULE - # 16-bit client drivers obj-$(CONFIG_PCMCIA_3C589) += 3c589_cs.o obj-$(CONFIG_PCMCIA_3C574) += 3c574_cs.o @@ -39,6 +37,7 @@ obj-$(CONFIG_AIRONET4500_CS) += aironet4500_cs.o # Cardbus client drivers obj-$(CONFIG_PCMCIA_3C575) += 3c575_cb.o +obj-$(CONFIG_PCMCIA_XIRTULIP) += xircom_tulip_cb.o O_OBJS := $(filter-out $(export-objs), $(obj-y)) OX_OBJS := $(filter $(export-objs), $(obj-y)) diff --git a/drivers/net/pcmcia/xircom_tulip_cb.c b/drivers/net/pcmcia/xircom_tulip_cb.c new file mode 100644 index 000000000..c1cb7629f --- /dev/null +++ b/drivers/net/pcmcia/xircom_tulip_cb.c @@ -0,0 +1,3153 @@ +/* tulip.c: A DEC 21040-family ethernet driver for Linux. */ +/* + Written/copyright 1994-1999 by Donald Becker. + + This software may be used and distributed according to the terms + of the GNU Public License, incorporated herein by reference. + + This driver is for the Digital "Tulip" Ethernet adapter interface. + It should work with most DEC 21*4*-based chips/ethercards, as well as + with work-alike chips from Lite-On (PNIC) and Macronix (MXIC) and ASIX. + + 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/tulip.html +*/ + +#define SMP_CHECK +#define CARDBUS 1 +static const char version[] = "xircom_tulip_cb.c:v0.91 4/14/99 becker@cesdis.gsfc.nasa.gov (modified by danilo@cs.uni-magdeburg.de for XIRCOM CBE, fixed by Doug Ledford)\n"; + +/* A few user-configurable values. */ + +/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ +static int max_interrupt_work = 25; + +#define MAX_UNITS 8 +/* Used to pass the full-duplex flag, etc. */ +static int full_duplex[MAX_UNITS] = {0, }; +static int options[MAX_UNITS] = {0, }; +static int mtu[MAX_UNITS] = {0, }; /* Jumbo MTU for interfaces. */ + +/* The possible media types that can be set in options[] are: */ +static const char * const medianame[] = { + "10baseT", "10base2", "AUI", "100baseTx", + "10baseT-FD", "100baseTx-FD", "100baseT4", "100baseFx", + "100baseFx-FD", "MII 10baseT", "MII 10baseT-FD", "MII", + "10baseT(forced)", "MII 100baseTx", "MII 100baseTx-FD", "MII 100baseT4", +}; + +/* Keep the ring sizes a power of two for efficiency. + Making the Tx ring too large decreases the effectiveness of channel + bonding and packet priority. + There are no ill effects from too-large receive rings. */ +#define TX_RING_SIZE 16 +#define RX_RING_SIZE 32 + +/* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */ +#ifdef __alpha__ +static int rx_copybreak = 1518; +#else +static int rx_copybreak = 100; +#endif + +/* + Set the bus performance register. + Typical: Set 16 longword cache alignment, no burst limit. + Cache alignment bits 15:14 Burst length 13:8 + 0000 No alignment 0x00000000 unlimited 0800 8 longwords + 4000 8 longwords 0100 1 longword 1000 16 longwords + 8000 16 longwords 0200 2 longwords 2000 32 longwords + C000 32 longwords 0400 4 longwords + Warning: many older 486 systems are broken and require setting 0x00A04800 + 8 longword cache alignment, 8 longword burst. + ToDo: Non-Intel setting could be better. +*/ + +#if defined(__alpha__) +static int csr0 = 0x01A00000 | 0xE000; +#elif defined(__powerpc__) +static int csr0 = 0x01B00000 | 0x8000; +#elif defined(__sparc__) +static int csr0 = 0x01B00080 | 0x8000; +#elif defined(__i386__) +static int csr0 = 0x01A00000 | 0x8000; +#else +#warning Processor architecture undefined! +static int csr0 = 0x00A00000 | 0x4800; +#endif + +/* Operational parameters that usually are not changed. */ +/* Time in jiffies before concluding the transmitter is hung. */ +#define TX_TIMEOUT (4*HZ) +#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ +/* This is a mysterious value that can be written to CSR11 in the 21040 (only) + to support a pre-NWay full-duplex signaling mechanism using short frames. + No one knows what it should be, but if left at its default value some + 10base2(!) packets trigger a full-duplex-request interrupt. */ +#define FULL_DUPLEX_MAGIC 0x6969 + +#if !defined(__OPTIMIZE__) || !defined(__KERNEL__) +#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/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/pci.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <asm/processor.h> /* Processor type for cache alignment. */ +#include <asm/bitops.h> +#include <asm/io.h> +#include <asm/unaligned.h> + +/* Kernel compatibility defines, some common to David Hinds' PCMCIA package. + This is only in the support-all-kernels source code. */ + +MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>"); +MODULE_DESCRIPTION("Digital 21*4* Tulip ethernet driver"); +MODULE_PARM(debug, "i"); +MODULE_PARM(max_interrupt_work, "i"); +MODULE_PARM(reverse_probe, "i"); +MODULE_PARM(rx_copybreak, "i"); +MODULE_PARM(csr0, "i"); +MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); + +#define RUN_AT(x) (jiffies + (x)) + +#define tulip_debug debug +#ifdef TULIP_DEBUG +static int tulip_debug = TULIP_DEBUG; +#else +static int tulip_debug = 1; +#endif + +/* + Theory of Operation + +I. Board Compatibility + +This device driver is designed for the DECchip "Tulip", Digital's +single-chip ethernet controllers for PCI. Supported members of the family +are the 21040, 21041, 21140, 21140A, 21142, and 21143. Similar work-alike +chips from Lite-On, Macronics, ASIX, Compex and other listed below are also +supported. + +These chips are used on at least 140 unique PCI board designs. The great +number of chips and board designs supported is the reason for the +driver size and complexity. Almost of the increasing complexity is in the +board configuration and media selection code. There is very little +increasing in the operational critical path length. + +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 preferably should assign the +PCI INTA signal to an otherwise unused system IRQ line. + +Some boards have EEPROMs tables with default media entry. The factory default +is usually "autoselect". This should only be overridden when using +transceiver connections without link beat e.g. 10base2 or AUI, or (rarely!) +for forcing full-duplex when used with old link partners that do not do +autonegotiation. + +III. Driver operation + +IIIa. Ring buffers + +The Tulip can use either ring buffers or lists of Tx and Rx descriptors. +This driver uses statically allocated rings of Rx and Tx descriptors, set at +compile time by RX/TX_RING_SIZE. This version of the driver allocates skbuffs +for the Rx ring buffers at open() time and passes the skb->data field to the +Tulip as receive data buffers. When an incoming frame is less than +RX_COPYBREAK bytes long, a fresh skbuff is allocated and the frame is +copied to the new skbuff. When the incoming frame is larger, the skbuff is +passed directly up the protocol stack and replaced by a newly allocated +skbuff. + +The RX_COPYBREAK value is chosen to trade-off the memory wasted by +using a full-sized skbuff for small frames vs. the copying costs of larger +frames. For small frames the copying cost is negligible (esp. considering +that we are pre-loading the cache with immediately useful header +information). For large frames the copying cost is non-trivial, and the +larger copy might flush the cache of useful data. A subtle aspect of this +choice is that the Tulip only receives into longword aligned buffers, thus +the IP header at offset 14 isn't longword aligned for further processing. +Copied frames are put into the new skbuff at an offset of "+2", thus copying +has the beneficial effect of aligning the IP header and preloading the +cache. + +IIIC. Synchronization +The driver runs as two independent, single-threaded flows of control. One +is the send-packet routine, which enforces single-threaded use by the +dev->tbusy flag. The other thread is the interrupt handler, which is single +threaded by the hardware and other 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 otherwise it sets +the 'tp->tx_full' flag. + +The interrupt handler has exclusive control over the Rx ring and records stats +from the Tx ring. (The Tx-done interrupt can't be selectively turned off, so +we can't avoid the interrupt overhead by having the Tx routine reap the Tx +stats.) After reaping the stats, it marks the queue entry as empty by setting +the 'base' to zero. Iff the 'tp->tx_full' flag is set, it clears both the +tx_full and tbusy flags. + +IV. Notes + +Thanks to Duke Kamstra of SMC for long ago providing an EtherPower board. +Greg LaPolla at Linksys provided PNIC and other Linksys boards. +Znyx provided a four-port card for testing. + +IVb. References + +http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html +http://www.digital.com (search for current 21*4* datasheets and "21X4 SROM") +http://www.national.com/pf/DP/DP83840A.html +http://www.asix.com.tw/pmac.htm +http://www.admtek.com.tw/ + +IVc. Errata + +The old DEC databooks were light on details. +The 21040 databook claims that CSR13, CSR14, and CSR15 should each be the last +register of the set CSR12-15 written. Hmmm, now how is that possible? + +The DEC SROM format is very badly designed not precisely defined, leading to +part of the media selection junkheap below. Some boards do not have EEPROM +media tables and need to be patched up. Worse, other boards use the DEC +design kit media table when it isn't correct for their board. + +We cannot use MII interrupts because there is no defined GPIO pin to attach +them. The MII transceiver status is polled using an kernel timer. + +*/ + +/* This table use during operation for capabilities and media timer. */ + +static void tulip_timer(unsigned long data); +static void t21142_timer(unsigned long data); +static void mxic_timer(unsigned long data); +static void pnic_timer(unsigned long data); +static void comet_timer(unsigned long data); + +enum tbl_flag { + HAS_MII=1, HAS_MEDIA_TABLE=2, CSR12_IN_SROM=4, ALWAYS_CHECK_MII=8, + HAS_ACPI=0x10, MC_HASH_ONLY=0x20, /* Hash-only multicast filter. */ + HAS_NWAY143=0x40, /* Uses 21143-like internal NWay. */ +}; +static struct tulip_chip_table { + char *chip_name; + int io_size; + int valid_intrs; /* CSR7 interrupt enable settings */ + int flags; + void (*media_timer)(unsigned long data); +} tulip_tbl[] = { + { "Digital DC21040 Tulip", 128, 0x0001ebef, 0, tulip_timer }, + { "Digital DC21041 Tulip", 128, 0x0001ebef, HAS_MEDIA_TABLE, tulip_timer }, + { "Digital DS21140 Tulip", 128, 0x0001ebef, + HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, tulip_timer }, + { "Digital DS21143 Tulip", 128, 0x0801fbff, + HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY143, t21142_timer }, + { "Lite-On 82c168 PNIC", 256, 0x0001ebef, + HAS_MII, pnic_timer }, + { "Macronix 98713 PMAC", 128, 0x0001ebef, + HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer }, + { "Macronix 98715 PMAC", 256, 0x0001ebef, + HAS_MEDIA_TABLE, mxic_timer }, + { "Macronix 98725 PMAC", 256, 0x0001ebef, + HAS_MEDIA_TABLE, mxic_timer }, + { "ASIX AX88140", 128, 0x0001fbff, + HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | MC_HASH_ONLY, tulip_timer }, + { "Lite-On PNIC-II", 256, 0x0001ebef, + HAS_MII | HAS_NWAY143, pnic_timer }, + { "ADMtek Comet", 256, 0x0001abef, + MC_HASH_ONLY, comet_timer }, + { "Compex 9881 PMAC", 128, 0x0001ebef, + HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer }, + { "Xircom Cardbus Adapter (DEC 21143 compatible mode)", 128, 0x0801fbff, + HAS_MII | HAS_ACPI, tulip_timer }, + {0}, +}; +/* This matches the table above. Note 21142 == 21143. */ +enum chips { + DC21040=0, DC21041=1, DC21140=2, DC21142=3, DC21143=3, + LC82C168, MX98713, MX98715, MX98725, AX88140, PNIC2, COMET, COMPEX9881, + X3201_3, +}; + +/* A full-duplex map for media types. */ +enum MediaIs { + MediaIsFD = 1, MediaAlwaysFD=2, MediaIsMII=4, MediaIsFx=8, + MediaIs100=16}; +static const char media_cap[] = +{0,0,0,16, 3,19,16,24, 27,4,7,5, 0,20,23,20 }; +static u8 t21040_csr13[] = {2,0x0C,8,4, 4,0,0,0, 0,0,0,0, 4,0,0,0}; +/* 21041 transceiver register settings: 10-T, 10-2, AUI, 10-T, 10T-FD*/ +static u16 t21041_csr13[] = { 0xEF05, 0xEF09, 0xEF09, 0xEF01, 0xEF09, }; +static u16 t21041_csr14[] = { 0x7F3F, 0xF7FD, 0xF7FD, 0x7F3F, 0x7F3D, }; +static u16 t21041_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, }; + +static u16 t21142_csr13[] = { 0x0001, 0x0009, 0x0009, 0x0000, 0x0001, }; +static u16 t21142_csr14[] = { 0xFFFF, 0x0705, 0x0705, 0x0000, 0x7F3D, }; +static u16 t21142_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, }; + +/* Offsets to the Command and Status Registers, "CSRs". All accesses + must be longword instructions and quadword aligned. */ +enum tulip_offsets { + CSR0=0, CSR1=0x08, CSR2=0x10, CSR3=0x18, CSR4=0x20, CSR5=0x28, + CSR6=0x30, CSR7=0x38, CSR8=0x40, CSR9=0x48, CSR10=0x50, CSR11=0x58, + CSR12=0x60, CSR13=0x68, CSR14=0x70, CSR15=0x78 }; + +/* The bits in the CSR5 status registers, mostly interrupt sources. */ +enum status_bits { + TimerInt=0x800, TPLnkFail=0x1000, TPLnkPass=0x10, + NormalIntr=0x10000, AbnormalIntr=0x8000, + RxJabber=0x200, RxDied=0x100, RxNoBuf=0x80, RxIntr=0x40, + TxFIFOUnderflow=0x20, TxJabber=0x08, TxNoBuf=0x04, TxDied=0x02, TxIntr=0x01, +}; + +/* The Tulip Rx and Tx buffer descriptors. */ +struct tulip_rx_desc { + s32 status; + s32 length; + u32 buffer1, buffer2; +}; + +struct tulip_tx_desc { + s32 status; + s32 length; + u32 buffer1, buffer2; /* We use only buffer 1. */ +}; + +enum desc_status_bits { + DescOwned=0x80000000, RxDescFatalErr=0x8000, RxWholePkt=0x0300, +}; + +/* Ring-wrap flag in length field, use for last ring entry. + 0x01000000 means chain on buffer2 address, + 0x02000000 means use the ring start address in CSR2/3. + Note: Some work-alike chips do not function correctly in chained mode. + The ASIX chip works only in chained mode. + Thus we indicates ring mode, but always write the 'next' field for + chained mode as well. +*/ +#define DESC_RING_WRAP 0x02000000 + +#ifdef CARDBUS +#define EEPROM_ADDRLEN (chip_rev == 65 ? 8 : 6) +#else +#define EEPROM_ADDRLEN 6 +#endif +#define EEPROM_SIZE 128 /* 2 << EEPROM_ADDRLEN */ + +struct medialeaf { + u8 type; + u8 media; + unsigned char *leafdata; +}; + +struct mediatable { + u16 defaultmedia; + u8 leafcount, csr12dir; /* General purpose pin directions. */ + unsigned has_mii:1, has_nonmii:1, has_reset:6; + u32 csr15dir, csr15val; /* 21143 NWay setting. */ + struct medialeaf mleaf[0]; +}; + +struct mediainfo { + struct mediainfo *next; + int info_type; + int index; + unsigned char *info; +}; + +struct tulip_private { + char devname[8]; /* Used only for kernel debugging. */ + const char *product_name; + struct tulip_rx_desc rx_ring[RX_RING_SIZE]; + struct tulip_tx_desc tx_ring[TX_RING_SIZE]; + /* The saved address of a sent-in-place packet/buffer, for skfree(). */ + struct sk_buff* tx_skbuff[TX_RING_SIZE]; +#ifdef CARDBUS + /* The X3201-3 requires double word aligned tx bufs */ + struct sk_buff* tx_aligned_skbuff[TX_RING_SIZE]; +#endif + /* The addresses of receive-in-place skbuffs. */ + struct sk_buff* rx_skbuff[RX_RING_SIZE]; + char *rx_buffs; /* Address of temporary Rx buffers. */ + u8 setup_buf[96*sizeof(u16) + 7]; + u16 *setup_frame; /* Pseudo-Tx frame to init address table. */ + int chip_id; + int revision; + struct net_device_stats stats; + struct timer_list timer; /* Media selection timer. */ + int interrupt; /* In-interrupt flag. */ + unsigned int cur_rx, cur_tx; /* The next free ring entry */ + unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ + unsigned int tx_full:1; /* The Tx queue is full. */ + unsigned int full_duplex:1; /* Full-duplex operation requested. */ + unsigned int full_duplex_lock:1; + unsigned int fake_addr:1; /* Multiport board faked address. */ + 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. */ + unsigned int nway:1, nwayset:1; /* 21143 internal NWay. */ + unsigned int open:1; + unsigned int csr0; /* CSR0 setting. */ + unsigned int csr6; /* Current CSR6 control settings. */ + unsigned char eeprom[EEPROM_SIZE]; /* Serial EEPROM contents. */ + u16 to_advertise; /* NWay capabilities advertised. */ + u16 lpar; /* 21143 Link partner ability. */ + u16 advertising[4]; + signed char phys[4], mii_cnt; /* MII device addresses. */ + struct mediatable *mtable; + int cur_index; /* Current media index. */ + int saved_if_port; + struct pci_dev *pdev; + spinlock_t lock; + int pad0, pad1; /* Used for 8-byte alignment */ +}; + +static void parse_eeprom(struct net_device *dev); +static int read_eeprom(long ioaddr, int location, int addr_len); +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 void select_media(struct net_device *dev, int startup); +static void tulip_up(struct net_device *dev); +static void tulip_down(struct net_device *dev); +static int tulip_open(struct net_device *dev); +static void tulip_timer(unsigned long data); +static void t21142_start_nway(struct net_device *dev); +static void tulip_tx_timeout(struct net_device *dev); +static void tulip_init_ring(struct net_device *dev); +static int tulip_start_xmit(struct sk_buff *skb, struct net_device *dev); +static int tulip_rx(struct net_device *dev); +static void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs); +static int tulip_close(struct net_device *dev); +static struct net_device_stats *tulip_get_stats(struct net_device *dev); +#ifdef HAVE_PRIVATE_IOCTL +static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +#endif +static void set_rx_mode(struct net_device *dev); + +/* The Xircom cards are picky about when certain bits in CSR6 can be + manipulated. Keith Owens <kaos@ocs.com.au>. */ + +static void outl_CSR6 (u32 newcsr6, long ioaddr, int chip_idx) +{ + const int strict_bits = 0x0060e202; + int csr5, csr5_22_20, csr5_19_17, currcsr6, attempts = 200; + long flags; + save_flags(flags); + cli(); + if (chip_idx != X3201_3) { + outl(newcsr6, ioaddr + CSR6); + restore_flags(flags); + return; + } + newcsr6 &= 0x726cfeca; /* mask out the reserved CSR6 bits that always */ + /* read 0 on the Xircom cards */ + newcsr6 |= 0x320c0000; /* or in the reserved bits that always read 1 */ + currcsr6 = inl(ioaddr + CSR6); + if (((newcsr6 & strict_bits) == (currcsr6 & strict_bits)) || + ((currcsr6 & ~0x2002) == 0)) { + outl(newcsr6, ioaddr + CSR6); /* safe */ + restore_flags(flags); + return; + } + /* make sure the transmitter and receiver are stopped first */ + currcsr6 &= ~0x2002; + while (1) { + csr5 = inl(ioaddr + CSR5); + if (csr5 == 0xffffffff) + break; /* cannot read csr5, card removed? */ + csr5_22_20 = csr5 & 0x700000; + csr5_19_17 = csr5 & 0x0e0000; + if ((csr5_22_20 == 0 || csr5_22_20 == 0x600000) && + (csr5_19_17 == 0 || csr5_19_17 == 0x80000 || csr5_19_17 == 0xc0000)) + break; /* both are stopped or suspended */ + if (!--attempts) { + printk(KERN_INFO "tulip.c: outl_CSR6 too many attempts," + "csr5=0x%08x\n", csr5); + outl(newcsr6, ioaddr + CSR6); /* unsafe but do it anyway */ + restore_flags(flags); + return; + } + outl(currcsr6, ioaddr + CSR6); + udelay(1); + } + /* now it is safe to change csr6 */ + outl(newcsr6, ioaddr + CSR6); + restore_flags(flags); +} + +static struct net_device *tulip_probe1(struct pci_dev *pdev, + struct net_device *dev, long ioaddr, int irq, + int chip_idx, int board_idx) +{ + static int did_version = 0; /* Already printed version info. */ + struct tulip_private *tp; + /* See note below on the multiport cards. */ + static unsigned char last_phys_addr[6] = {0x00, 'L', 'i', 'n', 'u', 'x'}; + static int last_irq = 0; + static int multiport_cnt = 0; /* For four-port boards w/one EEPROM */ + u8 chip_rev; + int i; + unsigned short sum; + + if (tulip_debug > 0 && did_version++ == 0) + printk(KERN_INFO "%s", version); + + dev = init_etherdev(dev, 0); + + pci_read_config_byte(pdev, PCI_REVISION_ID, &chip_rev); + /* Bring the 21143 out of sleep mode. + Caution: Snooze mode does not work with some boards! */ + 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. + */ + sum = 0; + if (chip_idx == DC21040) { + outl(0, ioaddr + CSR9); /* Reset the pointer with a dummy write. */ + for (i = 0; i < 6; i++) { + int value, boguscnt = 100000; + do + value = inl(ioaddr + CSR9); + while (value < 0 && --boguscnt > 0); + dev->dev_addr[i] = value; + sum += value & 0xff; + } + } else if (chip_idx == LC82C168) { + for (i = 0; i < 3; i++) { + int value, boguscnt = 100000; + outl(0x600 | i, ioaddr + 0x98); + do + value = inl(ioaddr + CSR9); + while (value < 0 && --boguscnt > 0); + put_unaligned(le16_to_cpu(value), ((u16*)dev->dev_addr) + i); + sum += value & 0xffff; + } + } else if (chip_idx == COMET) { + /* No need to read the EEPROM. */ + put_unaligned(inl(ioaddr + 0xA4), (u32 *)dev->dev_addr); + put_unaligned(inl(ioaddr + 0xA8), (u16 *)(dev->dev_addr + 4)); + for (i = 0; i < 6; i ++) + sum += dev->dev_addr[i]; + } else if (chip_idx == X3201_3) { + /* Xircom has its address stored in the CIS + * we access it through the boot rom interface for now + * this might not work, as the CIS is not parsed but I + * (danilo) use the offset I found on my card's CIS !!! + * + * Doug Ledford: I changed this routine around so that it + * walks the CIS memory space, parsing the config items, and + * finds the proper lan_node_id tuple and uses the data + * stored there. + */ + unsigned char j, tuple, link, data_id, data_count; + outl(1<<12, ioaddr + CSR9); /* enable boot rom access */ + for (i = 0x100; i < 0x1f7; i += link+2) { + outl(i, ioaddr + CSR10); + tuple = inl(ioaddr + CSR9) & 0xff; + outl(i + 1, ioaddr + CSR10); + link = inl(ioaddr + CSR9) & 0xff; + outl(i + 2, ioaddr + CSR10); + data_id = inl(ioaddr + CSR9) & 0xff; + outl(i + 3, ioaddr + CSR10); + data_count = inl(ioaddr + CSR9) & 0xff; + if ( (tuple == 0x22) && + (data_id == 0x04) && (data_count == 0x06) ) { + /* + * This is it. We have the data we want. + */ + for (j = 0; j < 6; j++) { + outl(i + j + 4, ioaddr + CSR10); + dev->dev_addr[j] = inl(ioaddr + CSR9) & 0xff; + } + break; + } else if (link == 0) { + break; + } + } + sum = 1; // to make check below fail! + } else { /* Must be a new chip, with a serial EEPROM interface. */ + /* We read the whole EEPROM, and sort it out later. DEC has a + specification _Digital Semiconductor 21X4 Serial ROM Format_ + but early vendor boards just put the address in the first six + EEPROM locations. */ + unsigned char ee_data[EEPROM_SIZE]; + int sa_offset = 0; + + for (i = 0; i < sizeof(ee_data)/2; i++) + ((u16 *)ee_data)[i] = + le16_to_cpu(read_eeprom(ioaddr, i, EEPROM_ADDRLEN)); + + /* Detect the simple EEPROM format by the duplicated station addr. */ + for (i = 0; i < 8; i ++) + if (ee_data[i] != ee_data[16+i]) + sa_offset = 20; + if (ee_data[0] == 0xff && ee_data[1] == 0xff && ee_data[2] == 0) { + sa_offset = 2; /* Grrr, damn Matrox boards. */ + multiport_cnt = 4; + } + for (i = 0; i < 6; i ++) { + dev->dev_addr[i] = ee_data[i + sa_offset]; + sum += ee_data[i + sa_offset]; + } + } + /* Lite-On boards have the address byte-swapped. */ + if ((dev->dev_addr[0] == 0xA0 || dev->dev_addr[0] == 0xC0) + && dev->dev_addr[1] == 0x00) + for (i = 0; i < 6; i+=2) { + char tmp = dev->dev_addr[i]; + dev->dev_addr[i] = dev->dev_addr[i+1]; + dev->dev_addr[i+1] = tmp; + } + /* On the Zynx 315 Etherarray and other multiport boards only the + first Tulip has an EEPROM. + The addresses of the subsequent ports are derived from the first. + Many PCI BIOSes also incorrectly report the IRQ line, so we correct + that here as well. */ + if (sum == 0 || sum == 6*0xff) { + printk(" EEPROM not present,"); + for (i = 0; i < 5; i++) + dev->dev_addr[i] = last_phys_addr[i]; + dev->dev_addr[i] = last_phys_addr[i] + 1; +#if defined(__i386__) /* Patch up x86 BIOS bug. */ + if (last_irq) + irq = last_irq; +#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); + + dev->base_addr = ioaddr; + dev->irq = irq; + + /* Make certain the data structures are quadword aligned. */ + tp = (void *)(((long)kmalloc(sizeof(*tp), GFP_KERNEL | GFP_DMA) + 7) & ~7); + memset(tp, 0, sizeof(*tp)); + dev->priv = tp; + + tp->lock = SPIN_LOCK_UNLOCKED; + tp->pdev = pdev; + tp->chip_id = chip_idx; + tp->revision = chip_rev; + tp->csr0 = csr0; + tp->setup_frame = (u16 *)(((unsigned long)tp->setup_buf + 7) & ~7); + + /* BugFixes: The 21143-TD hangs with PCI Write-and-Invalidate cycles. + And the ASIX must have a burst limit or horrible things happen. */ + if ( (chip_idx == DC21143 && chip_rev == 65) || + (chip_idx == X3201_3) ) + tp->csr0 &= ~0x01000000; + 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; + if ((options[board_idx] & 0x90) || full_duplex[board_idx] > 0) + tp->full_duplex = 1; + if (mtu[board_idx] > 0) + dev->mtu = mtu[board_idx]; + } + if (dev->mem_start) + tp->default_port = dev->mem_start; + if (tp->default_port) { + tp->medialock = 1; + if (media_cap[tp->default_port] & MediaAlwaysFD) + tp->full_duplex = 1; + } + if (tp->full_duplex) + tp->full_duplex_lock = 1; + + /* This is logically part of probe1(), but too complex to write inline. */ + if (tulip_tbl[chip_idx].flags & HAS_MEDIA_TABLE) + parse_eeprom(dev); + + if (media_cap[tp->default_port] & MediaIsMII) { + u16 media2advert[] = { 0x20, 0x40, 0x03e0, 0x60, 0x80, 0x100, 0x200 }; + tp->to_advertise = media2advert[tp->default_port - 9]; + } else + tp->to_advertise = 0x03e1; + + if ((tulip_tbl[chip_idx].flags & ALWAYS_CHECK_MII) || + (tp->mtable && tp->mtable->has_mii) || + ( ! tp->mtable && (tulip_tbl[chip_idx].flags & HAS_MII))) { + int phy, phy_idx; + if (tp->mtable && tp->mtable->has_mii) { + for (i = 0; i < tp->mtable->leafcount; i++) + if (tp->mtable->mleaf[i].media == 11) { + tp->cur_index = i; + tp->saved_if_port = dev->if_port; + select_media(dev, 1); + dev->if_port = tp->saved_if_port; + break; + } + } + /* Find the connected MII xcvrs. + Doing this in open() would allow detecting external xcvrs later, + but takes much time. */ + 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 & 0x8301) == 0x8001 || + ((mii_status & 0x8000) == 0 && (mii_status & 0x7800) != 0)) { + int mii_reg0 = mdio_read(dev, phy, 0); + int mii_advert = mdio_read(dev, phy, 4); + 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 " + "config %4.4x status %4.4x advertising %4.4x.\n", + dev->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," + " previously advertising %4.4x.\n", + dev->name, reg4, phy, mii_advert); + mdio_write(dev, phy, 4, reg4); + } + /* Enable autonegotiation: some boards default to off. */ + mdio_write(dev, phy, 0, mii_reg0 | + (tp->full_duplex ? 0x1100 : 0x1000) | + (media_cap[tp->default_port]&MediaIs100 ? 0x2000:0)); + } + } + 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); + tp->phys[0] = 1; + } + } + + /* The Tulip-specific entries in the device structure. */ + dev->open = &tulip_open; + dev->hard_start_xmit = &tulip_start_xmit; + dev->stop = &tulip_close; + dev->get_stats = &tulip_get_stats; +#ifdef HAVE_PRIVATE_IOCTL + dev->do_ioctl = &private_ioctl; +#endif +#ifdef HAVE_MULTICAST + dev->set_multicast_list = &set_rx_mode; +#endif + dev->tx_timeout = tulip_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + + /* 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 + * chipset time to reset the actual hardware + * on the PCMCIA card + */ + outl(0xa8050000, ioaddr + CSR15); + udelay(5); + outl(0xa00f0000, ioaddr + CSR15); + 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; + } + + return dev; +} + +/* Serial EEPROM section. */ +/* The main routine to parse the very complicated SROM structure. + Search www.digital.com for "21X4 SROM" to get details. + This code is very complex, and will require changes to support + additional cards, so I'll be verbose about what is going on. + */ + +/* Known cards that have old-style EEPROMs. */ +static struct fixups { + char *name; + unsigned char addr0, addr1, addr2; + u16 newtable[32]; /* Max length below. */ +} eeprom_fixups[] = { + {"Asante", 0, 0, 0x94, {0x1e00, 0x0000, 0x0800, 0x0100, 0x018c, + 0x0000, 0x0000, 0xe078, 0x0001, 0x0050, 0x0018 }}, + {"SMC9332DST", 0, 0, 0xC0, { 0x1e00, 0x0000, 0x0800, 0x021f, + 0x0000, 0x009E, /* 10baseT */ + 0x0903, 0x006D, /* 100baseTx */ }}, + {"Cogent EM100", 0, 0, 0x92, { 0x1e00, 0x0000, 0x0800, 0x033f, + 0x0107, 0x8021, /* 100baseFx */ + 0x0108, 0x8021, /* 100baseFx-FD */ + 0x0103, 0x006D, /* 100baseTx */ }}, + {"Maxtech NX-110", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x0313, + 0x1001, 0x009E, /* 10base2, CSR12 0x10*/ + 0x0000, 0x009E, /* 10baseT */ + 0x0303, 0x006D, /* 100baseTx, CSR12 0x03 */ }}, + {"Accton EN1207", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x031F, + 0x1B01, 0x0000, /* 10base2, CSR12 0x1B */ + 0x1B03, 0x006D, /* 100baseTx, CSR12 0x1B */ + 0x0B00, 0x009E, /* 10baseT, CSR12 0x0B */ + }}, + {0, 0, 0, 0, {}}}; + +static const char * block_name[] = {"21140 non-MII", "21140 MII PHY", + "21142 Serial PHY", "21142 MII PHY", "21143 SYM PHY", "21143 reset method"}; + +#if defined(__i386__) /* AKA get_unaligned() */ +#define get_u16(ptr) (*(u16 *)(ptr)) +#else +#define get_u16(ptr) (((u8*)(ptr))[0] + (((u8*)(ptr))[1]<<8)) +#endif + +static void parse_eeprom(struct net_device *dev) +{ + /* The last media info list parsed, for multiport boards. */ + static struct mediatable *last_mediatable = NULL; + static unsigned char *last_ee_data = NULL; + static int controller_index = 0; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + unsigned char *ee_data = tp->eeprom; + int i; +#ifdef CARDBUS + int chip_rev = tp->revision; +#endif + + tp->mtable = 0; + for (i = 0; i < EEPROM_SIZE/2; i++) + ((u16 *)ee_data)[i] = + le16_to_cpu(read_eeprom(ioaddr, i, EEPROM_ADDRLEN)); + + /* Detect an old-style (SA only) EEPROM layout: + memcmp(eedata, eedata+16, 8). */ + for (i = 0; i < 8; i ++) + if (ee_data[i] != ee_data[16+i]) + break; + if (i >= 8) { + if (ee_data[0] == 0xff) { + if (last_mediatable) { + controller_index++; + printk(KERN_INFO "%s: Controller %d of multiport board.\n", + dev->name, controller_index); + tp->mtable = last_mediatable; + ee_data = last_ee_data; + goto subsequent_board; + } else + printk(KERN_INFO "%s: Missing EEPROM, this interface may " + "not work correctly!\n", + dev->name); + return; + } + /* Do a fix-up based on the vendor half of the station address prefix. */ + for (i = 0; eeprom_fixups[i].name; i++) { + if (dev->dev_addr[0] == eeprom_fixups[i].addr0 + && dev->dev_addr[1] == eeprom_fixups[i].addr1 + && dev->dev_addr[2] == eeprom_fixups[i].addr2) { + if (dev->dev_addr[2] == 0xE8 && ee_data[0x1a] == 0x55) + i++; /* An Accton EN1207, not an outlaw Maxtech. */ + memcpy(ee_data + 26, eeprom_fixups[i].newtable, + sizeof(eeprom_fixups[i].newtable)); + printk(KERN_INFO "%s: Old format EEPROM on '%s' board. Using" + " substitute media control info.\n", + dev->name, eeprom_fixups[i].name); + break; + } + } + if (eeprom_fixups[i].name == NULL) { /* No fixup found. */ + printk(KERN_INFO "%s: Old style EEPROM with no media selection " + "information.\n", + dev->name); + return; + } + } + + controller_index = 0; + if (ee_data[19] > 1) { /* Multiport board. */ + last_ee_data = ee_data; + } +subsequent_board: + + if (ee_data[27] == 0) { /* No valid media table. */ + } else if (tp->chip_id == DC21041) { + unsigned char *p = (void *)ee_data + ee_data[27 + controller_index*3]; + short media; + int count; + + media = get_u16(p); + p += 2; + count = *p++; + + printk(KERN_INFO "%s:21041 Media information at %d, default media " + "%4.4x (%s).\n", dev->name, ee_data[27], media, + media & 0x0800 ? "Autosense" : medianame[media & 15]); + for (i = 0; i < count; i++) { + unsigned char media_code = *p++; + u16 csrvals[3]; + int idx; + for (idx = 0; idx < 3; idx++) { + csrvals[idx] = get_u16(p); + p += 2; + } + if (media_code & 0x40) { + printk(KERN_INFO "%s: 21041 media %2.2x (%s)," + " csr13 %4.4x csr14 %4.4x csr15 %4.4x.\n", + dev->name, media_code & 15, medianame[media_code & 15], + csrvals[0], csrvals[1], csrvals[2]); + } else + printk(KERN_INFO "%s: 21041 media #%d, %s.\n", + dev->name, media_code & 15, medianame[media_code & 15]); + } + } else { + unsigned char *p = (void *)ee_data + ee_data[27]; + unsigned char csr12dir = 0; + int count; + struct mediatable *mtable; + u16 media = get_u16(p); + + p += 2; + if (tulip_tbl[tp->chip_id].flags & CSR12_IN_SROM) + csr12dir = *p++; + count = *p++; + mtable = (struct mediatable *) + kmalloc(sizeof(struct mediatable) + count*sizeof(struct medialeaf), + GFP_KERNEL); + if (mtable == NULL) + return; /* Horrible, impossible failure. */ + last_mediatable = tp->mtable = mtable; + mtable->defaultmedia = media; + mtable->leafcount = count; + mtable->csr12dir = csr12dir; + mtable->has_nonmii = mtable->has_mii = mtable->has_reset = 0; + mtable->csr15dir = mtable->csr15val = 0; + + printk(KERN_INFO "%s: EEPROM default media type %s.\n", dev->name, + media & 0x0800 ? "Autosense" : medianame[media & 15]); + for (i = 0; i < count; i++) { + struct medialeaf *leaf = &mtable->mleaf[i]; + + if ((p[0] & 0x80) == 0) { /* 21140 Compact block. */ + leaf->type = 0; + leaf->media = p[0] & 0x3f; + leaf->leafdata = p; + if ((p[2] & 0x61) == 0x01) /* Bogus, but Znyx boards do it. */ + mtable->has_mii = 1; + p += 4; + } else { + leaf->type = p[1]; + if (p[1] == 0x05) { + mtable->has_reset = i; + leaf->media = p[2] & 0x0f; + } else if (p[1] & 1) { + mtable->has_mii = 1; + leaf->media = 11; + } else { + mtable->has_nonmii = 1; + leaf->media = p[2] & 0x0f; + if (p[1] == 2) { + if (leaf->media == 0) { + mtable->csr15dir = get_unaligned((u16*)&p[3])<<16; + mtable->csr15val = get_unaligned((u16*)&p[5])<<16; + } else if (leaf->media == 0x40) { + u32 base15 = get_unaligned((u16*)&p[7]); + mtable->csr15dir = + (get_unaligned((u16*)&p[9])<<16) + base15; + mtable->csr15val = + (get_unaligned((u16*)&p[11])<<16) + base15; + } + } + } + leaf->leafdata = p + 2; + p += (p[0] & 0x3f) + 1; + } + if (tulip_debug > 1 && leaf->media == 11) { + unsigned char *bp = leaf->leafdata; + printk(KERN_INFO "%s: MII interface PHY %d, setup/reset " + "sequences %d/%d long, capabilities %2.2x %2.2x.\n", + dev->name, bp[0], bp[1], bp[1 + bp[1]*2], + bp[5 + bp[2 + bp[1]*2]*2], bp[4 + bp[2 + bp[1]*2]*2]); + } + printk(KERN_INFO "%s: Index #%d - Media %s (#%d) described " + "by a %s (%d) block.\n", + dev->name, i, medianame[leaf->media], leaf->media, + block_name[leaf->type], leaf->type); + } + } +} +/* Reading a serial EEPROM is a "bit" grungy, but we work our way through:->.*/ + +/* EEPROM_Ctrl bits. */ +#define EE_SHIFT_CLK 0x02 /* EEPROM shift clock. */ +#define EE_CS 0x01 /* EEPROM chip select. */ +#define EE_DATA_WRITE 0x04 /* EEPROM chip data in. */ +#define EE_WRITE_0 0x01 +#define EE_WRITE_1 0x05 +#define EE_DATA_READ 0x08 /* EEPROM chip data out. */ +#define EE_ENB (0x4800 | EE_CS) + +/* Delay between EEPROM clock transitions. + Even at 33Mhz current PCI implementations don't overrun the EEPROM clock. + We add a bus turn-around to insure that this remains true. */ +#define eeprom_delay() inl(ee_addr) + +/* The EEPROM commands include the alway-set leading bit. */ +#define EE_WRITE_CMD (5 << addr_len) +#define EE_READ_CMD (6 << addr_len) +#define EE_ERASE_CMD (7 << addr_len) + +static int read_eeprom(long ioaddr, int location, int addr_len) +{ + int i; + unsigned short retval = 0; + long ee_addr = ioaddr + CSR9; + int read_cmd = location | EE_READ_CMD; + + outl(EE_ENB & ~EE_CS, ee_addr); + outl(EE_ENB, ee_addr); + + /* Shift the read command bits out. */ + for (i = 4 + addr_len; i >= 0; i--) { + short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; + outl(EE_ENB | dataval, ee_addr); + eeprom_delay(); + outl(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr); + eeprom_delay(); + } + outl(EE_ENB, ee_addr); + + for (i = 16; i > 0; i--) { + outl(EE_ENB | EE_SHIFT_CLK, ee_addr); + eeprom_delay(); + retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0); + outl(EE_ENB, ee_addr); + eeprom_delay(); + } + + /* Terminate the EEPROM access. */ + outl(EE_ENB & ~EE_CS, ee_addr); + return retval; +} + +/* MII transceiver control section. + Read and write the MII registers using software-generated serial + MDIO protocol. See the MII specifications or DP83840A data sheet + for details. */ + +/* 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 or future 66Mhz PCI. */ +#define mdio_delay() inl(mdio_addr) + +/* Read and write the MII registers using software-generated serial + MDIO protocol. It is just different enough from the EEPROM protocol + to not share code. The maxium data clock rate is 2.5 Mhz. */ +#define MDIO_SHIFT_CLK 0x10000 +#define MDIO_DATA_WRITE0 0x00000 +#define MDIO_DATA_WRITE1 0x20000 +#define MDIO_ENB 0x00000 /* Ignore the 0x02000 databook setting. */ +#define MDIO_ENB_IN 0x40000 +#define MDIO_DATA_READ 0x80000 + +static int mdio_read(struct net_device *dev, int phy_id, int location) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + int i; + int read_cmd = (0xf6 << 10) | (phy_id << 5) | location; + int retval = 0; + long ioaddr = dev->base_addr; + long mdio_addr = ioaddr + CSR9; + + if (tp->chip_id == LC82C168) { + int i = 1000; + outl(0x60020000 + (phy_id<<23) + (location<<18), ioaddr + 0xA0); + inl(ioaddr + 0xA0); + inl(ioaddr + 0xA0); + while (--i > 0) + if ( ! ((retval = inl(ioaddr + 0xA0)) & 0x80000000)) + return retval & 0xffff; + return 0xffff; + } + + if (tp->chip_id == COMET) { + if (phy_id == 1) { + if (location < 7) + return inl(ioaddr + 0xB4 + (location<<2)); + else if (location == 17) + return inl(ioaddr + 0xD0); + else if (location >= 29 && location <= 31) + return inl(ioaddr + 0xD4 + ((location-29)<<2)); + } + return 0xffff; + } + + /* Establish sync by sending at least 32 logic ones. */ + for (i = 32; i >= 0; i--) { + outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr); + mdio_delay(); + outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr); + mdio_delay(); + } + /* Shift the read command bits out. */ + for (i = 15; i >= 0; i--) { + int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0; + + outl(MDIO_ENB | dataval, mdio_addr); + mdio_delay(); + outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr); + mdio_delay(); + } + /* Read the two transition, 16 data, and wire-idle bits. */ + for (i = 19; i > 0; i--) { + outl(MDIO_ENB_IN, mdio_addr); + mdio_delay(); + retval = (retval << 1) | ((inl(mdio_addr) & MDIO_DATA_READ) ? 1 : 0); + outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); + mdio_delay(); + } + return (retval>>1) & 0xffff; +} + +static void mdio_write(struct net_device *dev, int phy_id, int location, int value) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + int i; + int cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value; + long ioaddr = dev->base_addr; + long mdio_addr = ioaddr + CSR9; + + if (tp->chip_id == LC82C168) { + int i = 1000; + outl(cmd, ioaddr + 0xA0); + do + if ( ! (inl(ioaddr + 0xA0) & 0x80000000)) + break; + while (--i > 0); + return; + } + + if (tp->chip_id == COMET) { + if (phy_id != 1) + return; + if (location < 7) + outl(value, ioaddr + 0xB4 + (location<<2)); + else if (location == 17) + outl(value, ioaddr + 0xD0); + else if (location >= 29 && location <= 31) + outl(value, ioaddr + 0xD4 + ((location-29)<<2)); + return; + } + + /* Establish sync by sending 32 logic ones. */ + for (i = 32; i >= 0; i--) { + outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr); + mdio_delay(); + outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr); + mdio_delay(); + } + /* Shift the command bits out. */ + for (i = 31; i >= 0; i--) { + int dataval = (cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0; + outl(MDIO_ENB | dataval, mdio_addr); + mdio_delay(); + outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr); + mdio_delay(); + } + /* Clear out extra bits. */ + for (i = 2; i > 0; i--) { + outl(MDIO_ENB_IN, mdio_addr); + mdio_delay(); + outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); + mdio_delay(); + } + return; +} + +static void +tulip_up(struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + int i; + + /* On some chip revs we must set the MII/SYM port before the reset!? */ + if (tp->mii_cnt || (tp->mtable && tp->mtable->has_mii)) + outl_CSR6(0x00040000, ioaddr, tp->chip_id); + + /* Reset the chip, holding bit 0 set at least 50 PCI cycles. */ + outl(0x00000001, ioaddr + CSR0); + + /* Deassert reset. */ + outl(tp->csr0, ioaddr + CSR0); + udelay(2); + + if (tulip_tbl[tp->chip_id].flags & HAS_ACPI) + pci_write_config_dword(tp->pdev, 0x40, 0x00000000); + + /* Clear the tx ring */ + for (i = 0; i < TX_RING_SIZE; i++) { + tp->tx_skbuff[i] = 0; + tp->tx_ring[i].status = 0x00000000; + } + + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: tulip_open() irq %d.\n", dev->name, dev->irq); + + if (tulip_tbl[tp->chip_id].flags & MC_HASH_ONLY) { + u32 addr_low = cpu_to_le32(get_unaligned((u32 *)dev->dev_addr)); + u32 addr_high = cpu_to_le32(get_unaligned((u16 *)(dev->dev_addr+4))); + if (tp->chip_id == AX88140) { + outl(0, ioaddr + CSR13); + outl(addr_low, ioaddr + CSR14); + outl(1, ioaddr + CSR13); + outl(addr_high, ioaddr + CSR14); + } else if (tp->chip_id == COMET) { + outl(addr_low, ioaddr + 0xA4); + outl(addr_high, ioaddr + 0xA8); + outl(0, ioaddr + 0xAC); + outl(0, ioaddr + 0xB0); + } + } else if (tp->chip_id != X3201_3) { + /* This is set_rx_mode(), but without starting the transmitter. */ + u16 *eaddrs = (u16 *)dev->dev_addr; + u16 *setup_frm = &tp->setup_frame[15*6]; + + /* 21140 bug: you must add the broadcast address. */ + memset(tp->setup_frame, 0xff, 96*sizeof(u16)); + /* Fill the final entry of the table with our physical address. */ + *setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0]; + *setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1]; + *setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2]; + /* Put the setup frame on the Tx list. */ + tp->tx_ring[0].length = 0x08000000 | 192; + tp->tx_ring[0].buffer1 = virt_to_bus(tp->setup_frame); + tp->tx_ring[0].status = DescOwned; + + tp->cur_tx++; + } else { /* X3201_3 */ + u16 *eaddrs = (u16 *)dev->dev_addr; + u16 *setup_frm = &tp->setup_frame[0*6]; + + /* fill the table with the broadcast address */ + memset(tp->setup_frame, 0xff, 96*sizeof(u16)); + /* re-fill the first 14 table entries with our address */ + for(i=0; i<14; i++) { + *setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0]; + *setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1]; + *setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2]; + } + + /* Put the setup frame on the Tx list. */ + tp->tx_ring[0].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) + 4); + tp->tx_ring[0].status = DescOwned; + + tp->cur_tx++; + } + outl(virt_to_bus(tp->rx_ring), ioaddr + CSR3); + outl(virt_to_bus(tp->tx_ring), ioaddr + CSR4); + + tp->saved_if_port = dev->if_port; + if (dev->if_port == 0) + dev->if_port = tp->default_port; + if (tp->chip_id == DC21041 && dev->if_port > 4) + /* Invalid: Select initial TP, autosense, autonegotiate. */ + dev->if_port = 4; + + /* Allow selecting a default media. */ + i = 0; + if (tp->mtable == NULL) + goto media_picked; + if (dev->if_port) { + int looking_for = media_cap[dev->if_port] & MediaIsMII ? 11 : + (dev->if_port == 12 ? 0 : dev->if_port); + for (i = 0; i < tp->mtable->leafcount; i++) + if (tp->mtable->mleaf[i].media == looking_for) { + printk(KERN_INFO "%s: Using user-specified media %s.\n", + dev->name, medianame[dev->if_port]); + goto media_picked; + } + } + if ((tp->mtable->defaultmedia & 0x0800) == 0) { + int looking_for = tp->mtable->defaultmedia & 15; + for (i = 0; i < tp->mtable->leafcount; i++) + if (tp->mtable->mleaf[i].media == looking_for) { + printk(KERN_INFO "%s: Using EEPROM-set media %s.\n", + dev->name, medianame[looking_for]); + goto media_picked; + } + } + /* Start sensing first non-full-duplex media. */ + for (i = tp->mtable->leafcount - 1; + (media_cap[tp->mtable->mleaf[i].media] & MediaAlwaysFD) && i > 0; i--) + ; +media_picked: + + tp->csr6 = 0; + tp->cur_index = i; + if (dev->if_port == 0 && tp->chip_id == DC21142) { + if (tp->mii_cnt) { + select_media(dev, 1); + if (tulip_debug > 1) + printk(KERN_INFO "%s: Using MII transceiver %d, status " + "%4.4x.\n", + dev->name, tp->phys[0], mdio_read(dev, tp->phys[0], 1)); + outl_CSR6(0x82020000, ioaddr, tp->chip_id); + tp->csr6 = 0x820E0000; + dev->if_port = 11; + outl(0x0000, ioaddr + CSR13); + outl(0x0000, ioaddr + CSR14); + } else + t21142_start_nway(dev); + } else if ((tp->chip_id == LC82C168 || tp->chip_id == PNIC2) + && tp->mii_cnt && ! tp->medialock) { + dev->if_port = 11; + tp->csr6 = 0x814C0000 | (tp->full_duplex ? 0x0200 : 0); + outl(0x0001, ioaddr + CSR15); + } else if ((tp->chip_id == MX98713 || tp->chip_id == COMPEX9881) + && ! tp->medialock) { + dev->if_port = 0; + tp->csr6 = 0x01880000 | (tp->full_duplex ? 0x0200 : 0); + outl(0x0f370000 | inw(ioaddr + 0x80), ioaddr + 0x80); + } else if (tp->chip_id == MX98715 || tp->chip_id == MX98725) { + /* Provided by BOLO, Macronix - 12/10/1998. */ + dev->if_port = 0; + tp->csr6 = 0x01880200; + outl(0x0f370000 | inw(ioaddr + 0x80), ioaddr + 0x80); + outl(0x11000 | inw(ioaddr + 0xa0), ioaddr + 0xa0); + } else if (tp->chip_id == DC21143 && + media_cap[dev->if_port] & MediaIsMII) { + /* We must reset the media CSRs when we force-select MII mode. */ + outl(0x0000, ioaddr + CSR13); + outl(0x0000, ioaddr + CSR14); + outl(0x0008, ioaddr + CSR15); + } else if (tp->chip_id == X3201_3) { + outl(0x0008, ioaddr + CSR15); + udelay(5); + outl(0xa8050000, ioaddr + CSR15); + udelay(5); + outl(0xa00f0000, ioaddr + CSR15); + udelay(5); + tp->csr6 = 0x32400000; + } else if (tp->chip_id == COMET) { + dev->if_port = 0; + tp->csr6 = 0x00040000; + } else + select_media(dev, 1); + + /* Start the chip's Tx to process setup frame. */ + outl_CSR6(tp->csr6, ioaddr, tp->chip_id); + outl_CSR6(tp->csr6 | 0x2000, ioaddr, tp->chip_id); + + /* Enable interrupts by setting the interrupt mask. */ + outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR5); + outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7); + outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id); + outl(0, ioaddr + CSR2); /* Rx poll demand */ + + netif_start_queue (dev); + + if (tulip_debug > 2) { + printk(KERN_DEBUG "%s: Done tulip_open(), CSR0 %8.8x, CSR5 %8.8x CSR6 %8.8x.\n", + dev->name, inl(ioaddr + CSR0), inl(ioaddr + CSR5), + inl(ioaddr + CSR6)); + } + /* 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(5*HZ); + tp->timer.data = (unsigned long)dev; + tp->timer.function = tulip_tbl[tp->chip_id].media_timer; + add_timer(&tp->timer); +} + +static int +tulip_open(struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + + if (request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ, dev->name, dev)) + return -EAGAIN; + + tulip_init_ring(dev); + + tulip_up(dev); + tp->open = 1; + MOD_INC_USE_COUNT; + + return 0; +} + +/* Set up the transceiver control registers for the selected media type. */ +static void 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; + int i; + + if (mtable) { + struct medialeaf *mleaf = &mtable->mleaf[tp->cur_index]; + unsigned char *p = mleaf->leafdata; + switch (mleaf->type) { + case 0: /* 21140 non-MII xcvr. */ + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Using a 21140 non-MII transceiver" + " with control setting %2.2x.\n", + dev->name, p[1]); + dev->if_port = p[0]; + if (startup) + outl(mtable->csr12dir | 0x100, ioaddr + CSR12); + outl(p[1], ioaddr + CSR12); + new_csr6 = 0x02000000 | ((p[2] & 0x71) << 18); + break; + case 2: case 4: { + u16 setup[5]; + u32 csr13val, csr14val, csr15dir, csr15val; + for (i = 0; i < 5; i++) + setup[i] = get_u16(&p[i*2 + 1]); + + dev->if_port = p[0] & 15; + if (media_cap[dev->if_port] & MediaAlwaysFD) + tp->full_duplex = 1; + + if (startup && mtable->has_reset) { + struct medialeaf *rleaf = &mtable->mleaf[mtable->has_reset]; + unsigned char *rst = rleaf->leafdata; + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Resetting the transceiver.\n", + dev->name); + for (i = 0; i < rst[0]; i++) + outl(get_u16(rst + 1 + (i<<1)) << 16, ioaddr + CSR15); + } + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: 21143 non-MII %s transceiver control " + "%4.4x/%4.4x.\n", + dev->name, medianame[dev->if_port], setup[0], setup[1]); + if (p[0] & 0x40) { /* SIA (CSR13-15) setup values are provided. */ + csr13val = setup[0]; + csr14val = setup[1]; + csr15dir = (setup[3]<<16) | setup[2]; + csr15val = (setup[4]<<16) | setup[2]; + outl(0, ioaddr + CSR13); + outl(csr14val, ioaddr + CSR14); + outl(csr15dir, ioaddr + CSR15); /* Direction */ + outl(csr15val, ioaddr + CSR15); /* Data */ + outl(csr13val, ioaddr + CSR13); + } else { + csr13val = 1; + csr14val = 0x0003FF7F; + csr15dir = (setup[0]<<16) | 0x0008; + csr15val = (setup[1]<<16) | 0x0008; + if (dev->if_port <= 4) + csr14val = t21142_csr14[dev->if_port]; + if (startup) { + outl(0, ioaddr + CSR13); + outl(csr14val, ioaddr + CSR14); + } + outl(csr15dir, ioaddr + CSR15); /* Direction */ + outl(csr15val, ioaddr + CSR15); /* Data */ + if (startup) outl(csr13val, ioaddr + CSR13); + } + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Setting CSR15 to %8.8x/%8.8x.\n", + dev->name, csr15dir, csr15val); + if (mleaf->type == 4) + new_csr6 = 0x82020000 | ((setup[2] & 0x71) << 18); + else + new_csr6 = 0x82420000; + break; + } + case 1: case 3: { + int phy_num = p[0]; + int init_length = p[1]; + u16 *misc_info; + u16 to_advertise; + + dev->if_port = 11; + new_csr6 = 0x020E0000; + if (mleaf->type == 3) { /* 21142 */ + u16 *init_sequence = (u16*)(p+2); + u16 *reset_sequence = &((u16*)(p+3))[init_length]; + int reset_length = p[2 + init_length*2]; + misc_info = reset_sequence + reset_length; + if (startup) + for (i = 0; i < reset_length; i++) + outl(get_u16(&reset_sequence[i]) << 16, ioaddr + CSR15); + for (i = 0; i < init_length; i++) + outl(get_u16(&init_sequence[i]) << 16, ioaddr + CSR15); + } else { + u8 *init_sequence = p + 2; + u8 *reset_sequence = p + 3 + init_length; + int reset_length = p[2 + init_length]; + misc_info = (u16*)(reset_sequence + reset_length); + if (startup) { + outl(mtable->csr12dir | 0x100, ioaddr + CSR12); + for (i = 0; i < reset_length; i++) + outl(reset_sequence[i], ioaddr + CSR12); + } + for (i = 0; i < init_length; i++) + outl(init_sequence[i], ioaddr + CSR12); + } + to_advertise = (get_u16(&misc_info[1]) & tp->to_advertise) | 1; + tp->advertising[phy_num] = to_advertise; + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Advertising %4.4x on PHY %d (%d).\n", + dev->name, to_advertise, phy_num, tp->phys[phy_num]); + /* Bogus: put in by a committee? */ + mdio_write(dev, tp->phys[phy_num], 4, to_advertise); + break; + } + default: + printk(KERN_DEBUG "%s: Invalid media table selection %d.\n", + dev->name, mleaf->type); + new_csr6 = 0x020E0000; + } + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Using media type %s, CSR12 is %2.2x.\n", + dev->name, medianame[dev->if_port], + inl(ioaddr + CSR12) & 0xff); + } else if (tp->chip_id == DC21041) { + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: 21041 using media %s, CSR12 is %4.4x.\n", + dev->name, medianame[dev->if_port & 15], + inl(ioaddr + CSR12) & 0xffff); + outl(0x00000000, ioaddr + CSR13); /* Reset the serial interface */ + outl(t21041_csr14[dev->if_port], ioaddr + CSR14); + outl(t21041_csr15[dev->if_port], ioaddr + CSR15); + outl(t21041_csr13[dev->if_port], ioaddr + CSR13); + new_csr6 = 0x80020000; + } else if (tp->chip_id == LC82C168 || tp->chip_id == PNIC2) { + if (startup && ! tp->medialock) + dev->if_port = tp->mii_cnt ? 11 : 0; + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: PNIC PHY status is %3.3x, CSR12 %4.4x," + " media %s.\n", + dev->name, inl(ioaddr + 0xB8), inl(ioaddr + CSR12), + medianame[dev->if_port]); + if (tp->mii_cnt) { + new_csr6 = 0x810C0000; + outl(0x0001, ioaddr + CSR15); + outl(0x0201B07A, ioaddr + 0xB8); + } else if (startup) { + /* Start with 10mbps to do autonegotiation. */ + outl(0x32, ioaddr + CSR12); + new_csr6 = 0x00420000; + outl(0x0001B078, ioaddr + 0xB8); + outl(0x0201B078, ioaddr + 0xB8); + } else if (dev->if_port == 3 || dev->if_port == 5) { + outl(0x33, ioaddr + CSR12); + new_csr6 = 0x01860000; + if (startup) + outl(0x0201F868, ioaddr + 0xB8); /* Trigger autonegotiation. */ + else + outl(0x1F868, ioaddr + 0xB8); + } else { + outl(0x32, ioaddr + CSR12); + new_csr6 = 0x00420000; + outl(0x1F078, ioaddr + 0xB8); + } + } else if (tp->chip_id == DC21040) { /* 21040 */ + /* Turn on the xcvr interface. */ + int csr12 = inl(ioaddr + CSR12); + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: 21040 media type is %s, CSR12 is %2.2x.\n", + dev->name, medianame[dev->if_port], csr12); + if (media_cap[dev->if_port] & MediaAlwaysFD) + tp->full_duplex = 1; + new_csr6 = 0x20000; + /* Set the full duplux match frame. */ + outl(FULL_DUPLEX_MAGIC, ioaddr + CSR11); + outl(0x00000000, ioaddr + CSR13); /* Reset the serial interface */ + if (t21040_csr13[dev->if_port] & 8) { + outl(0x0705, ioaddr + CSR14); + outl(0x0006, ioaddr + CSR15); + } else { + outl(0xffff, ioaddr + CSR14); + outl(0x0000, ioaddr + CSR15); + } + outl(0x8f01 | t21040_csr13[dev->if_port], ioaddr + CSR13); + } else if (tp->chip_id == X3201_3) { /* Xircom */ + if (tp->default_port == 0) + dev->if_port = tp->mii_cnt ? 11 : 3; +/* Someone is on crack, the Xircom only does MII, no Fx */ +/* if (media_cap[dev->if_port] & MediaIsMII) { + new_csr6 = 0x020E0000; + } else if (media_cap[dev->if_port] & MediaIsFx) { + new_csr6 = 0x028600000; + } else + new_csr6 = 0x038600000;*/ + new_csr6 = 0x324c0000; + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Xircom CardBus Adapter: " + "%s transceiver, CSR12 %2.2x.\n", + dev->name, medianame[dev->if_port], + inl(ioaddr + CSR12)); + } else { /* Unknown chip type with no media table. */ + if (tp->default_port == 0) + dev->if_port = tp->mii_cnt ? 11 : 3; + if (media_cap[dev->if_port] & MediaIsMII) { + new_csr6 = 0x020E0000; + } else if (media_cap[dev->if_port] & MediaIsFx) { + new_csr6 = 0x028600000; + } else + new_csr6 = 0x038600000; + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: No media description table, assuming " + "%s transceiver, CSR12 %2.2x.\n", + dev->name, medianame[dev->if_port], + inl(ioaddr + CSR12)); + } + + tp->csr6 = new_csr6 | (tp->csr6 & 0xfdff) | (tp->full_duplex ? 0x0200 : 0); + return; +} + +/* + Check the MII negotiated duplex, and change the CSR6 setting if + required. + Return 0 if everything is OK. + Return < 0 if the transceiver is missing or has no link beat. + */ +static int check_duplex(struct net_device *dev) +{ + long ioaddr = dev->base_addr; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + int mii_reg1, mii_reg5, negotiated, duplex; + + if (tp->full_duplex_lock) + return 0; + mii_reg1 = mdio_read(dev, tp->phys[0], 1); + mii_reg5 = 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 = 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]; + duplex = ((negotiated & 0x0300) == 0x0100 + || (negotiated & 0x00C0) == 0x0040); + /* 100baseTx-FD or 10T-FD, but not 100-HD */ + if (tp->full_duplex != duplex) { + tp->full_duplex = duplex; + if (tp->full_duplex) tp->csr6 |= 0x0200; + else tp->csr6 &= ~0x0200; + outl_CSR6(tp->csr6 | 0x0002, ioaddr, tp->chip_id); + outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id); + 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); + } + return 0; +} + +static void tulip_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + u32 csr12 = inl(ioaddr + CSR12); + int next_tick = 2*HZ; + + if (tulip_debug > 2) { + printk(KERN_DEBUG "%s: Media selection tick, status %8.8x mode %8.8x " + "SIA %8.8x %8.8x %8.8x %8.8x.\n", + dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR6), + csr12, inl(ioaddr + CSR13), + inl(ioaddr + CSR14), inl(ioaddr + CSR15)); + } + switch (tp->chip_id) { + case DC21040: + if (!tp->medialock && csr12 & 0x0002) { /* Network error */ + printk(KERN_INFO "%s: No link beat found.\n", + dev->name); + dev->if_port = (dev->if_port == 2 ? 0 : 2); + select_media(dev, 0); + dev->trans_start = jiffies; + } + break; + case DC21041: + if (tulip_debug > 2) + printk(KERN_DEBUG "%s: 21041 media tick CSR12 %8.8x.\n", + dev->name, csr12); + switch (dev->if_port) { + case 0: case 3: case 4: + if (csr12 & 0x0004) { /*LnkFail */ + /* 10baseT is dead. Check for activity on alternate port. */ + tp->mediasense = 1; + if (csr12 & 0x0200) + dev->if_port = 2; + else + dev->if_port = 1; + printk(KERN_INFO "%s: No 21041 10baseT link beat, Media switched to %s.\n", + dev->name, medianame[dev->if_port]); + outl(0, ioaddr + CSR13); /* Reset */ + outl(t21041_csr14[dev->if_port], ioaddr + CSR14); + outl(t21041_csr15[dev->if_port], ioaddr + CSR15); + outl(t21041_csr13[dev->if_port], ioaddr + CSR13); + next_tick = 10*HZ; /* 2.4 sec. */ + } else + next_tick = 30*HZ; + break; + case 1: /* 10base2 */ + case 2: /* AUI */ + if (csr12 & 0x0100) { + next_tick = (30*HZ); /* 30 sec. */ + tp->mediasense = 0; + } else if ((csr12 & 0x0004) == 0) { + printk(KERN_INFO "%s: 21041 media switched to 10baseT.\n", + dev->name); + dev->if_port = 0; + select_media(dev, 0); + next_tick = (24*HZ)/10; /* 2.4 sec. */ + } else if (tp->mediasense || (csr12 & 0x0002)) { + dev->if_port = 3 - dev->if_port; /* Swap ports. */ + select_media(dev, 0); + next_tick = 20*HZ; + } else { + next_tick = 20*HZ; + } + break; + } + break; + case DC21140: case DC21142: case MX98713: case COMPEX9881: default: { + struct medialeaf *mleaf; + unsigned char *p; + if (tp->mtable == NULL) { /* No EEPROM info, use generic code. */ + /* Not much that can be done. + Assume this a generic MII or SYM transceiver. */ + next_tick = 60*HZ; + if (tulip_debug > 2) + printk(KERN_DEBUG "%s: network media monitor CSR6 %8.8x " + "CSR12 0x%2.2x.\n", + dev->name, inl(ioaddr + CSR6), csr12 & 0xff); + break; + } + mleaf = &tp->mtable->mleaf[tp->cur_index]; + p = mleaf->leafdata; + switch (mleaf->type) { + case 0: case 4: { + /* Type 0 serial or 4 SYM transceiver. Check the link beat bit. */ + int offset = mleaf->type == 4 ? 5 : 2; + s8 bitnum = p[offset]; + if (p[offset+1] & 0x80) { + if (tulip_debug > 1) + printk(KERN_DEBUG"%s: Transceiver monitor tick " + "CSR12=%#2.2x, no media sense.\n", + dev->name, csr12); + if (mleaf->type == 4) { + if (mleaf->media == 3 && (csr12 & 0x02)) + goto select_next_media; + } + break; + } + if (tulip_debug > 2) + printk(KERN_DEBUG "%s: Transceiver monitor tick: CSR12=%#2.2x" + " bit %d is %d, expecting %d.\n", + dev->name, csr12, (bitnum >> 1) & 7, + (csr12 & (1 << ((bitnum >> 1) & 7))) != 0, + (bitnum >= 0)); + /* Check that the specified bit has the proper value. */ + if ((bitnum < 0) != + ((csr12 & (1 << ((bitnum >> 1) & 7))) != 0)) { + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Link beat detected for %s.\n", dev->name, + medianame[mleaf->media]); + if ((p[2] & 0x61) == 0x01) /* Bogus Znyx board. */ + goto actually_mii; + break; + } + if (tp->medialock) + break; + select_next_media: + if (--tp->cur_index < 0) { + /* We start again, but should instead look for default. */ + tp->cur_index = tp->mtable->leafcount - 1; + } + dev->if_port = tp->mtable->mleaf[tp->cur_index].media; + if (media_cap[dev->if_port] & MediaIsFD) + goto select_next_media; /* Skip FD entries. */ + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: No link beat on media %s," + " trying transceiver type %s.\n", + dev->name, medianame[mleaf->media & 15], + medianame[tp->mtable->mleaf[tp->cur_index].media]); + select_media(dev, 0); + /* Restart the transmit process. */ + outl_CSR6(tp->csr6 | 0x0002, ioaddr, tp->chip_id); + outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id); + next_tick = (24*HZ)/10; + break; + } + case 1: case 3: /* 21140, 21142 MII */ + actually_mii: + check_duplex(dev); + next_tick = 60*HZ; + break; + case 2: /* 21142 serial block has no link beat. */ + default: + break; + } + } + break; + } + tp->timer.expires = RUN_AT(next_tick); + add_timer(&tp->timer); +} + +/* Handle the 21143 uniquely: do autoselect with NWay, not the EEPROM list + of available transceivers. */ +static void t21142_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + int csr12 = inl(ioaddr + CSR12); + int next_tick = 60*HZ; + int new_csr6 = 0; + + if ((tulip_debug > 2) && !(media_cap[dev->if_port] & MediaIsMII)) + printk(KERN_INFO"%s: 21143 negotiation status %8.8x, %s.\n", + dev->name, csr12, medianame[dev->if_port]); + if (media_cap[dev->if_port] & MediaIsMII) { + check_duplex(dev); + next_tick = 60*HZ; + } else if (tp->nwayset) { + /* Don't screw up a negotiated session! */ + if (tulip_debug > 1) + printk(KERN_INFO"%s: Using NWay-set %s media, csr12 %8.8x.\n", + dev->name, medianame[dev->if_port], csr12); + } else if (tp->medialock) { + ; + } else if (dev->if_port == 3) { + if (csr12 & 2) { /* No 100mbps link beat, revert to 10mbps. */ + if (tulip_debug > 1) + printk(KERN_INFO"%s: No 21143 100baseTx link beat, %8.8x, " + "trying NWay.\n", dev->name, csr12); + t21142_start_nway(dev); + next_tick = 3*HZ; + } + } else if (((csr12 & 0x7000) != 0x5000) + && tp->chip_id != X3201_3) { + /* Negotiation failed. Search media types. */ + if (tulip_debug > 1) + printk(KERN_INFO"%s: 21143 negotiation failed, status %8.8x.\n", + dev->name, csr12); + if (!(csr12 & 4)) { /* 10mbps link beat good. */ + new_csr6 = 0x82420000; + dev->if_port = 0; + outl(0, ioaddr + CSR13); + outl(0x0003FFFF, ioaddr + CSR14); + outw(t21142_csr15[dev->if_port], ioaddr + CSR15); + outl(t21142_csr13[dev->if_port], ioaddr + CSR13); + } else { + /* Select 100mbps port to check for link beat. */ + new_csr6 = 0x83860000; + dev->if_port = 3; + outl(0, ioaddr + CSR13); + outl(0x0003FF7F, ioaddr + CSR14); + outw(8, ioaddr + CSR15); + outl(1, ioaddr + CSR13); + } + if (tulip_debug > 1) + printk(KERN_INFO"%s: Testing new 21143 media %s.\n", + dev->name, medianame[dev->if_port]); + if (new_csr6 != (tp->csr6 & ~0x00D5)) { + tp->csr6 &= 0x00D5; + tp->csr6 |= new_csr6; + outl(0x0301, ioaddr + CSR12); + outl_CSR6(tp->csr6 | 0x0002, ioaddr, tp->chip_id); + outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id); + } + next_tick = 3*HZ; + } + if (tp->cur_tx - tp->dirty_tx > 0 && + jiffies - dev->trans_start > TX_TIMEOUT) { + printk(KERN_WARNING "%s: Tx hung, %d vs. %d.\n", + dev->name, tp->cur_tx, tp->dirty_tx); + tulip_tx_timeout(dev); + } + + tp->timer.expires = RUN_AT(next_tick); + add_timer(&tp->timer); +} + +static void t21142_start_nway(struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + int csr14 = ((tp->to_advertise & 0x0180) << 9) | + ((tp->to_advertise&0x0020)<<1) | 0xffbf; + + dev->if_port = 0; + tp->nway = tp->mediasense = 1; + tp->nwayset = tp->lpar = 0; + if (debug > 1) + printk(KERN_DEBUG "%s: Restarting 21143 autonegotiation, %8.8x.\n", + dev->name, csr14); + outl(0x0001, ioaddr + CSR13); + outl(csr14, ioaddr + CSR14); + tp->csr6 = 0x82420000 | (tp->to_advertise & 0x0040 ? 0x0200 : 0); + outl_CSR6(tp->csr6, ioaddr, tp->chip_id); + if (tp->mtable && tp->mtable->csr15dir) { + outl(tp->mtable->csr15dir, ioaddr + CSR15); + outl(tp->mtable->csr15val, ioaddr + CSR15); + } else + outw(0x0008, ioaddr + CSR15); + outl(0x1301, ioaddr + CSR12); /* Trigger NWAY. */ +} + +static void t21142_lnk_change(struct net_device *dev, int csr5) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + int csr12 = inl(ioaddr + CSR12); + + if (tulip_debug > 1) + printk(KERN_INFO"%s: 21143 link status interrupt %8.8x, CSR5 %x, " + "%8.8x.\n", dev->name, csr12, csr5, inl(ioaddr + CSR14)); + + /* If NWay finished and we have a negotiated partner capability. */ + if (tp->nway && !tp->nwayset && (csr12 & 0x7000) == 0x5000) { + int setup_done = 0; + tp->lpar = csr12 >> 16; + tp->nwayset = 1; + if (csr12 & 0x01000000) dev->if_port = 5; + else if (csr12 & 0x00800000) dev->if_port = 3; + else if (csr12 & 0x00400000) dev->if_port = 4; + else if (csr12 & 0x00200000) dev->if_port = 0; + else { + tp->nwayset = 0; + if ( ! (csr12 & 2)) dev->if_port = 3; + else if ( ! (csr12 & 4)) dev->if_port = 0; + } + tp->full_duplex = (media_cap[tp->default_port] & MediaAlwaysFD) ? 1:0; + + if (tulip_debug > 1) { + if (tp->nwayset) + printk(KERN_INFO "%s: Switching to %s based on link partner " + "advertisement %4.4x.\n", + dev->name, medianame[dev->if_port], tp->lpar); + else + printk(KERN_INFO "%s: Switching to %s based on link beat " + "status of %4.4x.\n", + dev->name, medianame[dev->if_port], csr12); + } + + if (tp->mtable) { + int i; + for (i = 0; i < tp->mtable->leafcount; i++) + if (tp->mtable->mleaf[i].media == dev->if_port) { + tp->cur_index = i; + select_media(dev, 0); + setup_done = 1; + break; + } + } + if ( ! setup_done) { + tp->csr6 = dev->if_port & 1 ? 0x83860000 : 0x82420000; + if (tp->full_duplex) + tp->csr6 |= 0x0200; + outw(0x0000, ioaddr + CSR13); + outw(0x0000, ioaddr + CSR14); + } + outl_CSR6(tp->csr6 | 0x0000, ioaddr, tp->chip_id); + if (debug > 2) + printk(KERN_DEBUG "%s: Restarting Tx and Rx, CSR5 is %8.8x.\n", + dev->name, inl(ioaddr + CSR5)); + outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id); + } else if ((tp->nwayset && (csr5 & 0x08000000) + && (dev->if_port == 3 || dev->if_port == 5) + && (csr12 & 2) == 2) || + (tp->nway && (csr5 & (TPLnkFail)))) { + /* Link blew? Maybe restart NWay. */ + del_timer(&tp->timer); + t21142_start_nway(dev); + tp->timer.expires = RUN_AT(3*HZ); + add_timer(&tp->timer); + } else if (dev->if_port == 3 || dev->if_port == 5) { + if (tulip_debug > 1) + printk(KERN_INFO"%s: 21143 %s link beat %s.\n", + dev->name, medianame[dev->if_port], + (csr12 & 2) ? "failed" : "good"); + if ((csr12 & 2) && ! tp->medialock) { + del_timer(&tp->timer); + t21142_start_nway(dev); + tp->timer.expires = RUN_AT(3*HZ); + add_timer(&tp->timer); + } + } else if (dev->if_port == 0 || dev->if_port == 4) { + if ((csr12 & 4) == 0) + printk(KERN_INFO"%s: 21143 10baseT link beat good.\n", + dev->name); + } else if (!(csr12 & 4)) { /* 10mbps link beat good. */ + if (tulip_debug) + printk(KERN_INFO"%s: 21143 10mbps sensed media.\n", + dev->name); + dev->if_port = 0; + } else if (tp->nwayset) { + if (tulip_debug) + printk(KERN_INFO"%s: 21143 using NWay-set %s, csr6 %8.8x.\n", + dev->name, medianame[dev->if_port], tp->csr6); + } else { /* 100mbps link beat good. */ + if (tulip_debug) + printk(KERN_INFO"%s: 21143 100baseTx sensed media.\n", + dev->name); + dev->if_port = 3; + tp->csr6 = 0x83860000; + outl(0x0003FF7F, ioaddr + CSR14); + outl(0x0301, ioaddr + CSR12); + outl_CSR6(tp->csr6 | 0x0002, ioaddr, tp->chip_id); + outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id); + } +} + +static void mxic_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + int next_tick = 60*HZ; + + if (tulip_debug > 3) { + printk(KERN_INFO"%s: MXIC negotiation status %8.8x.\n", dev->name, + inl(ioaddr + CSR12)); + } + if (next_tick) { + tp->timer.expires = RUN_AT(next_tick); + add_timer(&tp->timer); + } +} + +static void pnic_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + int csr12 = inl(ioaddr + CSR12); + int next_tick = 60*HZ; + int new_csr6 = tp->csr6 & ~0x40C40200; + + if (media_cap[dev->if_port] & MediaIsMII) { + int negotiated = mdio_read(dev, tp->phys[0], 5) & tp->advertising[0]; + + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: PNIC negotiated capability %8.8x, " + "CSR5 %8.8x.\n", + dev->name, negotiated, inl(ioaddr + CSR5)); + + if (negotiated & 0x0380) /* 10 vs 100mbps */ + new_csr6 |= 0x810E0000; + else + new_csr6 |= 0x814E0000; + if (((negotiated & 0x0300) == 0x0100) /* Duplex */ + || (negotiated & 0x00C0) == 0x0040 + || tp->full_duplex_lock) { + tp->full_duplex = 1; + new_csr6 |= 0x0200; + } + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: PNIC MII PHY status %4.4x, Link " + "partner report %4.4x, csr6 %8.8x/%8.8x.\n", + dev->name, mdio_read(dev, tp->phys[0], 1), negotiated, + tp->csr6, inl(ioaddr + CSR6)); + } else { + int phy_reg = inl(ioaddr + 0xB8); + int csr5 = inl(ioaddr + CSR5); + + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: PNIC PHY status %8.8x, CSR5 %8.8x.\n", + dev->name, phy_reg, csr5); + + if (phy_reg & 0x04000000) { /* Remote link fault */ + /*outl(0x0201F078, ioaddr + 0xB8);*/ + next_tick = 3*HZ; + } + if (inl(ioaddr + CSR5) & TPLnkFail) { /* 100baseTx link beat */ + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: %s link beat failed, CSR12 %4.4x, " + "CSR5 %8.8x, PHY %3.3x.\n", + dev->name, medianame[dev->if_port], csr12, + inl(ioaddr + CSR5), inl(ioaddr + 0xB8)); + if (tp->medialock) { + } else if (dev->if_port == 0) { + dev->if_port = 3; + outl(0x33, ioaddr + CSR12); + new_csr6 = 0x01860000; + outl(0x1F868, ioaddr + 0xB8); + } else { + dev->if_port = 0; + outl(0x32, ioaddr + CSR12); + new_csr6 = 0x00420000; + outl(0x1F078, ioaddr + 0xB8); + } + new_csr6 |= (tp->csr6 & 0xfdff); + next_tick = 3*HZ; + } else + new_csr6 = tp->csr6; + if (tp->full_duplex_lock || (phy_reg & 0x30000000) != 0) { + tp->full_duplex = 1; + new_csr6 |= 0x00000200; + } + } + if (tp->csr6 != new_csr6) { + tp->csr6 = new_csr6; + outl_CSR6(tp->csr6 | 0x0002, ioaddr, tp->chip_id); /* Restart Tx */ + outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id); + dev->trans_start = jiffies; + if (tulip_debug > 1) + printk(KERN_INFO "%s: Changing PNIC configuration to %s-duplex, " + "CSR6 %8.8x.\n", + dev->name, tp->full_duplex ? "full" : "half", new_csr6); + } + tp->timer.expires = RUN_AT(next_tick); + add_timer(&tp->timer); +} + +static void comet_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + int next_tick = 60*HZ; + + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Comet link status %4.4x partner capability " + "%4.4x.\n", + dev->name, inl(ioaddr + 0xB8), inl(ioaddr + 0xC8)); + tp->timer.expires = RUN_AT(next_tick); + add_timer(&tp->timer); +} + +static void tulip_tx_timeout(struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + + if (media_cap[dev->if_port] & MediaIsMII) { + /* Do nothing -- the media monitor should handle this. */ + if (tulip_debug > 1) + printk(KERN_WARNING "%s: Transmit timeout using MII device.\n", + dev->name); + } else if (tp->chip_id == DC21040) { + if ( !tp->medialock && inl(ioaddr + CSR12) & 0x0002) { + dev->if_port = (dev->if_port == 2 ? 0 : 2); + printk(KERN_INFO "%s: transmit timed out, switching to " + "%s.\n", + dev->name, medianame[dev->if_port]); + select_media(dev, 0); + } + dev->trans_start = jiffies; + return; + } else if (tp->chip_id == DC21041) { + int csr12 = inl(ioaddr + CSR12); + + printk(KERN_WARNING "%s: 21041 transmit timed out, status %8.8x, " + "CSR12 %8.8x, CSR13 %8.8x, CSR14 %8.8x, resetting...\n", + dev->name, inl(ioaddr + CSR5), csr12, + inl(ioaddr + CSR13), inl(ioaddr + CSR14)); + tp->mediasense = 1; + if ( ! tp->medialock) { + if (dev->if_port == 1 || dev->if_port == 2) + if (csr12 & 0x0004) { + dev->if_port = 2 - dev->if_port; + } else + dev->if_port = 0; + else + dev->if_port = 1; + select_media(dev, 0); + } + } else if (tp->chip_id == DC21140 || tp->chip_id == DC21142 + || tp->chip_id == MX98713 || tp->chip_id == COMPEX9881) { + printk(KERN_WARNING "%s: 21140 transmit timed out, status %8.8x, " + "SIA %8.8x %8.8x %8.8x %8.8x, resetting...\n", + dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12), + inl(ioaddr + CSR13), inl(ioaddr + CSR14), inl(ioaddr + CSR15)); + if ( ! tp->medialock && tp->mtable) { + do + --tp->cur_index; + while (tp->cur_index >= 0 + && (media_cap[tp->mtable->mleaf[tp->cur_index].media] + & MediaIsFD)); + if (--tp->cur_index < 0) { + /* We start again, but should instead look for default. */ + tp->cur_index = tp->mtable->leafcount - 1; + } + select_media(dev, 0); + printk(KERN_WARNING "%s: transmit timed out, switching to %s " + "media.\n", dev->name, medianame[dev->if_port]); + } + } else { + printk(KERN_WARNING "%s: Transmit timed out, status %8.8x, CSR12 " + "%8.8x, resetting...\n", + dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12)); + dev->if_port = 0; + } + +#if defined(way_too_many_messages) + if (tulip_debug > 3) { + int i; + for (i = 0; i < RX_RING_SIZE; i++) { + u8 *buf = (u8 *)(tp->rx_ring[i].buffer1); + int j; + printk(KERN_DEBUG "%2d: %8.8x %8.8x %8.8x %8.8x " + "%2.2x %2.2x %2.2x.\n", + i, (unsigned int)tp->rx_ring[i].status, + (unsigned int)tp->rx_ring[i].length, + (unsigned int)tp->rx_ring[i].buffer1, + (unsigned int)tp->rx_ring[i].buffer2, + buf[0], buf[1], buf[2]); + for (j = 0; buf[j] != 0xee && j < 1600; j++) + if (j < 100) printk(" %2.2x", buf[j]); + printk(" j=%d.\n", j); + } + printk(KERN_DEBUG " Rx ring %8.8x: ", (int)tp->rx_ring); + for (i = 0; i < RX_RING_SIZE; i++) + printk(" %8.8x", (unsigned int)tp->rx_ring[i].status); + printk("\n" KERN_DEBUG " Tx ring %8.8x: ", (int)tp->tx_ring); + for (i = 0; i < TX_RING_SIZE; i++) + printk(" %8.8x", (unsigned int)tp->tx_ring[i].status); + printk("\n"); + } +#endif + + /* Stop and restart the chip's Tx processes . */ + outl_CSR6(tp->csr6 | 0x0002, ioaddr, tp->chip_id); + outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id); + /* Trigger an immediate transmit demand. */ + outl(0, ioaddr + CSR1); + + dev->trans_start = jiffies; + netif_wake_queue (dev); + tp->stats.tx_errors++; +} + +/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ +static void tulip_init_ring(struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + int i; + + tp->tx_full = 0; + tp->cur_rx = tp->cur_tx = 0; + tp->dirty_rx = tp->dirty_tx = 0; + + for (i = 0; i < RX_RING_SIZE; i++) { + tp->rx_ring[i].status = 0x00000000; + tp->rx_ring[i].length = PKT_BUF_SZ; + tp->rx_ring[i].buffer2 = virt_to_bus(&tp->rx_ring[i+1]); + tp->rx_skbuff[i] = NULL; + } + /* Mark the last entry as wrapping the ring. */ + tp->rx_ring[i-1].length = PKT_BUF_SZ | DESC_RING_WRAP; + tp->rx_ring[i-1].buffer2 = virt_to_bus(&tp->rx_ring[0]); + + for (i = 0; i < RX_RING_SIZE; i++) { + /* Note the receive buffer must be longword aligned. + dev_alloc_skb() provides 16 byte alignment. But do *not* + use skb_reserve() to align the IP header! */ + struct sk_buff *skb = dev_alloc_skb(PKT_BUF_SZ); + tp->rx_skbuff[i] = skb; + if (skb == NULL) + break; + skb->dev = dev; /* Mark as being used by this device. */ + tp->rx_ring[i].status = DescOwned; /* Owned by Tulip chip */ + tp->rx_ring[i].buffer1 = virt_to_bus(skb->tail); + } + tp->dirty_rx = (unsigned int)(i - RX_RING_SIZE); + + /* The Tx buffer descriptor is filled in as needed, but we + do need to clear the ownership bit. */ + for (i = 0; i < TX_RING_SIZE; i++) { + tp->tx_skbuff[i] = 0; + tp->tx_ring[i].status = 0x00000000; + tp->tx_ring[i].buffer2 = virt_to_bus(&tp->tx_ring[i+1]); +#ifdef CARDBUS + if (tp->chip_id == X3201_3) + tp->tx_aligned_skbuff[i] = dev_alloc_skb(PKT_BUF_SZ); +#endif CARDBUS + } + tp->tx_ring[i-1].buffer2 = virt_to_bus(&tp->tx_ring[0]); +} + +static int +tulip_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + int entry; + u32 flag; + + /* Caution: the write order is important here, set the base address + with the "ownership" bits last. */ + + /* Calculate the next Tx descriptor entry. */ + entry = tp->cur_tx % TX_RING_SIZE; + + tp->tx_skbuff[entry] = skb; +#ifdef CARDBUS + if (tp->chip_id == X3201_3) { + memcpy(tp->tx_aligned_skbuff[entry]->data,skb->data,skb->len); + tp->tx_ring[entry].buffer1 = virt_to_bus(tp->tx_aligned_skbuff[entry]->data); + } else +#endif + tp->tx_ring[entry].buffer1 = virt_to_bus(skb->data); + + if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE/2) {/* Typical path */ + flag = 0x60000000; /* No interrupt */ + } else if (tp->cur_tx - tp->dirty_tx == TX_RING_SIZE/2) { + flag = 0xe0000000; /* Tx-done intr. */ + } else if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE - 2) { + flag = 0x60000000; /* No Tx-done intr. */ + } else { + /* Leave room for set_rx_mode() to fill entries. */ + flag = 0xe0000000; /* Tx-done intr. */ + tp->tx_full = 1; + } + if (entry == TX_RING_SIZE-1) + flag |= 0xe0000000 | DESC_RING_WRAP; + + tp->tx_ring[entry].length = skb->len | flag; + tp->tx_ring[entry].status = DescOwned; /* Pass ownership to the chip. */ + tp->cur_tx++; + if (tp->tx_full) + netif_stop_queue (dev); + else + netif_wake_queue (dev); + + /* Trigger an immediate transmit demand. */ + outl(0, dev->base_addr + CSR1); + + dev->trans_start = jiffies; + + return 0; +} + +/* The interrupt handler does all of the Rx thread work and cleans up + after the Tx thread. */ +static void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *)dev_instance; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + int csr5, work_budget = max_interrupt_work; + + spin_lock (&tp->lock); + + do { + csr5 = inl(ioaddr + CSR5); + /* Acknowledge all of the current interrupt sources ASAP. */ + outl(csr5 & 0x0001ffff, ioaddr + CSR5); + + if (tulip_debug > 4) + printk(KERN_DEBUG "%s: interrupt csr5=%#8.8x new csr5=%#8.8x.\n", + dev->name, csr5, inl(dev->base_addr + CSR5)); + + if (csr5 == 0xffffffff) + break; /* all bits set, assume PCMCIA card removed */ + + if ((csr5 & (NormalIntr|AbnormalIntr)) == 0) + break; + + if (csr5 & (RxIntr | RxNoBuf)) + work_budget -= tulip_rx(dev); + + if (csr5 & (TxNoBuf | TxDied | TxIntr)) { + unsigned int dirty_tx; + + for (dirty_tx = tp->dirty_tx; tp->cur_tx - dirty_tx > 0; + dirty_tx++) { + int entry = dirty_tx % TX_RING_SIZE; + int status = tp->tx_ring[entry].status; + + if (status < 0) + break; /* It still hasn't been Txed */ + /* Check for Rx filter setup frames. */ + if (tp->tx_skbuff[entry] == NULL) + continue; + + if (status & 0x8000) { + /* There was an major error, log it. */ +#ifndef final_version + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n", + dev->name, status); +#endif + tp->stats.tx_errors++; + if (status & 0x4104) tp->stats.tx_aborted_errors++; + if (status & 0x0C00) tp->stats.tx_carrier_errors++; + if (status & 0x0200) tp->stats.tx_window_errors++; + if (status & 0x0002) tp->stats.tx_fifo_errors++; + if ((status & 0x0080) && tp->full_duplex == 0) + tp->stats.tx_heartbeat_errors++; +#ifdef ETHER_STATS + if (status & 0x0100) tp->stats.collisions16++; +#endif + } else { +#ifdef ETHER_STATS + if (status & 0x0001) tp->stats.tx_deferred++; +#endif + tp->stats.tx_bytes += tp->tx_ring[entry].length & 0x7ff; + tp->stats.collisions += (status >> 3) & 15; + tp->stats.tx_packets++; + } + + /* Free the original skb. */ + dev_kfree_skb_irq(tp->tx_skbuff[entry]); + tp->tx_skbuff[entry] = 0; + } + +#ifndef final_version + if (tp->cur_tx - dirty_tx > TX_RING_SIZE) { + 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 += TX_RING_SIZE; + } +#endif + + if (tp->tx_full && + tp->cur_tx - dirty_tx < TX_RING_SIZE - 2) + /* The ring is no longer full */ + tp->tx_full = 0; + + if (tp->tx_full) + netif_stop_queue (dev); + else + netif_wake_queue (dev); + + tp->dirty_tx = dirty_tx; + if (csr5 & TxDied) { + if (tulip_debug > 2) + printk(KERN_WARNING "%s: The transmitter stopped." + " CSR5 is %x, CSR6 %x, new CSR6 %x.\n", + dev->name, csr5, inl(ioaddr + CSR6), tp->csr6); + outl_CSR6(tp->csr6 | 0x0002, ioaddr, tp->chip_id); + outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id); + } + } + + /* Log errors. */ + if (csr5 & AbnormalIntr) { /* Abnormal error summary bit. */ + if (csr5 == 0xffffffff) + break; + if (csr5 & TxJabber) tp->stats.tx_errors++; + if (csr5 & TxFIFOUnderflow) { + if ((tp->csr6 & 0xC000) != 0xC000) + tp->csr6 += 0x4000; /* Bump up the Tx threshold */ + else + tp->csr6 |= 0x00200000; /* Store-n-forward. */ + /* Restart the transmit process. */ + outl_CSR6(tp->csr6 | 0x0002, ioaddr, tp->chip_id); + outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id); + } + if (csr5 & RxDied) { /* Missed a Rx frame. */ + tp->stats.rx_errors++; + tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff; + outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id); + } + if (csr5 & TimerInt) { + if (tulip_debug > 2) + printk(KERN_ERR "%s: Re-enabling interrupts, %8.8x.\n", + dev->name, csr5); + outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7); + } + if (csr5 & (TPLnkPass | TPLnkFail | 0x08000000)) { + if ( tp->chip_id == DC21142) + t21142_lnk_change(dev, csr5); + } + /* Clear all error sources, included undocumented ones! */ + outl(0x0800f7ba, ioaddr + CSR5); + } + if (--work_budget < 0) { + if (tulip_debug > 1) + printk(KERN_WARNING "%s: Too much work during an interrupt, " + "csr5=0x%8.8x.\n", dev->name, csr5); + /* Acknowledge all interrupt sources. */ + outl(0x8001ffff, ioaddr + CSR5); +#ifdef notdef + /* Clear all but standard interrupt sources. */ + outl((~csr5) & 0x0001ebef, ioaddr + CSR7); +#endif + break; + } + } while (1); + + if (tulip_debug > 3) + printk(KERN_DEBUG "%s: exiting interrupt, csr5=%#4.4x.\n", + dev->name, inl(ioaddr + CSR5)); + + spin_unlock (&tp->lock); +} + +static int +tulip_rx(struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + int entry = tp->cur_rx % RX_RING_SIZE; + int rx_work_limit = tp->dirty_rx + RX_RING_SIZE - tp->cur_rx; + int work_done = 0; + + if (tulip_debug > 4) + printk(KERN_DEBUG " In tulip_rx(), entry %d %8.8x.\n", entry, + tp->rx_ring[entry].status); + /* If we own the next entry, it's a new packet. Send it up. */ + while (tp->rx_ring[entry].status >= 0) { + s32 status = tp->rx_ring[entry].status; + + if (tulip_debug > 5) + printk(KERN_DEBUG " In tulip_rx(), entry %d %8.8x.\n", entry, + tp->rx_ring[entry].status); + if (--rx_work_limit < 0) + break; + if ((status & 0x38008300) != 0x0300) { + if ((status & 0x38000300) != 0x0300) { + /* Ingore earlier buffers. */ + if ((status & 0xffff) != 0x7fff) { + if (tulip_debug > 1) + printk(KERN_WARNING "%s: Oversized Ethernet frame " + "spanned multiple buffers, status %8.8x!\n", + dev->name, status); + tp->stats.rx_length_errors++; + } + } else if (status & RxDescFatalErr) { + /* There was a fatal error. */ + if (tulip_debug > 2) + printk(KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n", + dev->name, status); + tp->stats.rx_errors++; /* end of a packet.*/ + if (status & 0x0890) tp->stats.rx_length_errors++; + if (status & 0x0004) tp->stats.rx_frame_errors++; + if (status & 0x0002) tp->stats.rx_crc_errors++; + if (status & 0x0001) tp->stats.rx_fifo_errors++; + } + } else { + /* Omit the four octet CRC from the length. */ + short pkt_len = ((status >> 16) & 0x7ff) - 4; + struct sk_buff *skb; + +#ifndef final_version + if (pkt_len > 1518) { + printk(KERN_WARNING "%s: Bogus packet size of %d (%#x).\n", + dev->name, pkt_len, pkt_len); + pkt_len = 1518; + tp->stats.rx_length_errors++; + } +#endif + /* Check if the packet is long enough to accept without copying + to a minimally-sized skbuff. */ + if (pkt_len < rx_copybreak + && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { + skb->dev = dev; + skb_reserve(skb, 2); /* 16 byte align the IP header */ +#if ! defined(__alpha__) + eth_copy_and_sum(skb, bus_to_virt(tp->rx_ring[entry].buffer1), + pkt_len, 0); + skb_put(skb, pkt_len); +#else + memcpy(skb_put(skb, pkt_len), + bus_to_virt(tp->rx_ring[entry].buffer1), pkt_len); +#endif + work_done++; + } else { /* Pass up the skb already on the Rx ring. */ + char *temp = skb_put(skb = tp->rx_skbuff[entry], pkt_len); + tp->rx_skbuff[entry] = NULL; +#ifndef final_version + if (bus_to_virt(tp->rx_ring[entry].buffer1) != temp) + printk(KERN_ERR "%s: Internal fault: The skbuff addresses " + "do not match in tulip_rx: %p vs. %p / %p.\n", + dev->name, bus_to_virt(tp->rx_ring[entry].buffer1), + skb->head, temp); +#endif + } + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); + dev->last_rx = jiffies; + tp->stats.rx_packets++; + tp->stats.rx_bytes += pkt_len; + } + entry = (++tp->cur_rx) % RX_RING_SIZE; + } + + /* Refill the Rx ring buffers. */ + for (; tp->cur_rx - tp->dirty_rx > 0; tp->dirty_rx++) { + entry = tp->dirty_rx % RX_RING_SIZE; + if (tp->rx_skbuff[entry] == NULL) { + struct sk_buff *skb; + skb = tp->rx_skbuff[entry] = dev_alloc_skb(PKT_BUF_SZ); + if (skb == NULL) + break; + skb->dev = dev; /* Mark as being used by this device. */ + tp->rx_ring[entry].buffer1 = virt_to_bus(skb->tail); + work_done++; + } + tp->rx_ring[entry].status = DescOwned; + } + + return work_done; +} + +static void +tulip_down(struct net_device *dev) +{ + long ioaddr = dev->base_addr; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + + /* Disable interrupts by clearing the interrupt mask. */ + outl(0x00000000, ioaddr + CSR7); + /* Stop the chip's Tx and Rx processes. */ + outl_CSR6(inl(ioaddr + CSR6) & ~0x2002, ioaddr, tp->chip_id); + /* 21040 -- Leave the card in 10baseT state. */ + if (tp->chip_id == DC21040) + outl(0x00000004, ioaddr + CSR13); + + if (inl(ioaddr + CSR6) != 0xffffffff) + tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff; + + dev->if_port = tp->saved_if_port; +} + +static int +tulip_close(struct net_device *dev) +{ + long ioaddr = dev->base_addr; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + int i; + + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n", + dev->name, inl(ioaddr + CSR5)); + + netif_stop_queue(dev); + + if (netif_device_present(dev)) + tulip_down(dev); + + del_timer(&tp->timer); + + free_irq(dev->irq, dev); + + /* Free all the skbuffs in the Rx queue. */ + for (i = 0; i < RX_RING_SIZE; i++) { + struct sk_buff *skb = tp->rx_skbuff[i]; + tp->rx_skbuff[i] = 0; + tp->rx_ring[i].status = 0; /* Not owned by Tulip chip. */ + tp->rx_ring[i].length = 0; + tp->rx_ring[i].buffer1 = 0xBADF00D0; /* An invalid address. */ + if (skb) { + dev_kfree_skb(skb); + } + } + for (i = 0; i < TX_RING_SIZE; i++) { + if (tp->tx_skbuff[i]) + dev_kfree_skb(tp->tx_skbuff[i]); + tp->tx_skbuff[i] = 0; + } + + MOD_DEC_USE_COUNT; + tp->open = 0; + return 0; +} + +static struct net_device_stats *tulip_get_stats(struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + + if (netif_device_present(dev)) + tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff; + + return &tp->stats; +} + +#ifdef HAVE_PRIVATE_IOCTL +/* Provide ioctl() calls to examine the MII xcvr state. */ +static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + u16 *data = (u16 *)&rq->ifr_data; + int phy = tp->phys[0] & 0x1f; + long flags; + + switch(cmd) { + case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ + if (tp->mii_cnt) + data[0] = phy; + else if (tp->chip_id == DC21142) /* 21142 pseudo-MII */ + data[0] = 32; + else if (tp->chip_id == PNIC2) + data[0] = 32; + else if (tp->chip_id == COMET) + data[0] = 1; + else + return -ENODEV; + return 0; + case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ + if (data[0] == 32 && + (tp->chip_id == DC21142 || tp->chip_id == PNIC2)) { + int csr12 = inl(ioaddr + CSR12); + int csr14 = inl(ioaddr + CSR14); + switch (data[1]) { + case 0: { + data[3] = (csr14<<5) & 0x1000; + break; } + case 1: + data[3] = 0x7848 + ((csr12&0x7000) == 0x5000 ? 0x20 : 0) + + (csr12&0x06 ? 0x04 : 0); + break; + case 4: { + data[3] = ((csr14>>9)&0x0380) + + ((inl(ioaddr + CSR6)>>3)&0x0040) +((csr14>>1)&0x20) + 1; + break; + } + case 5: data[3] = csr12 >> 16; break; + default: data[3] = 0; break; + } + } else { + save_flags(flags); + cli(); + data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f); + restore_flags(flags); + } + return 0; + case SIOCDEVPRIVATE+2: /* Write the specified MII register */ +#if defined(CAP_NET_ADMIN) + if (!capable(CAP_NET_ADMIN)) + return -EPERM; +#else + if (!suser()) + return -EPERM; +#endif + if (data[0] == 32 && tp->chip_id == DC21142) { + if (data[1] == 5) + tp->to_advertise = data[2]; + } else { + save_flags(flags); + cli(); + mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]); + restore_flags(flags); + } + return 0; + default: + return -EOPNOTSUPP; + } + + return -EOPNOTSUPP; +} +#endif /* HAVE_PRIVATE_IOCTL */ + +/* Set or clear the multicast filter for this adaptor. + Note that we only use exclusion around actually queueing the + new frame, not around filling tp->setup_frame. This is non-deterministic + when re-entered but still correct. */ + +/* The little-endian AUTODIN32 ethernet CRC calculation. + N.B. Do not use for bulk data, use a table-based routine instead. + This is common code and should be moved to net/core/crc.c */ +static unsigned const ethernet_polynomial_le = 0xedb88320U; +static inline u32 ether_crc_le(int length, unsigned char *data) +{ + u32 crc = 0xffffffff; /* Initial value. */ + while(--length >= 0) { + unsigned char current_octet = *data++; + int bit; + for (bit = 8; --bit >= 0; current_octet >>= 1) { + if ((crc ^ current_octet) & 1) { + crc >>= 1; + crc ^= ethernet_polynomial_le; + } else + crc >>= 1; + } + } + return crc; +} +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; +} + +static void set_rx_mode(struct net_device *dev) +{ + long ioaddr = dev->base_addr; + int csr6 = inl(ioaddr + CSR6) & ~0x00D5; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + + tp->csr6 &= ~0x00D5; + if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ + tp->csr6 |= 0x00C0; + csr6 |= 0x00C0; + /* Unconditionally log net taps. */ + printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name); + } else if ((dev->mc_count > 1000) || (dev->flags & IFF_ALLMULTI)) { + /* Too many to filter well -- accept all multicasts. */ + tp->csr6 |= 0x0080; + csr6 |= 0x0080; + } else if (tulip_tbl[tp->chip_id].flags & MC_HASH_ONLY) { + /* Some work-alikes have only a 64-entry hash filter table. */ + /* Should verify correctness on big-endian/__powerpc__ */ + struct dev_mc_list *mclist; + int i; + u32 mc_filter[2]; /* Multicast hash filter */ + if (dev->mc_count > 64) { /* Arbitrary non-effective limit. */ + tp->csr6 |= 0x0080; + csr6 |= 0x0080; + } else { + 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); + if (tp->chip_id == AX88140) { + outl(2, ioaddr + CSR13); + outl(mc_filter[0], ioaddr + CSR14); + outl(3, ioaddr + CSR13); + outl(mc_filter[1], ioaddr + CSR14); + } else if (tp->chip_id == COMET) { /* Has a simple hash filter. */ + outl(mc_filter[0], ioaddr + 0xAC); + outl(mc_filter[1], ioaddr + 0xB0); + } + } + } else { + u16 *eaddrs, *setup_frm = tp->setup_frame; + struct dev_mc_list *mclist; + u32 tx_flags = 0x08000000 | 192; + int i; + + /* Note that only the low-address shortword of setup_frame is valid! + The values are doubled for big-endian architectures. */ + if ((dev->mc_count > 14) || ((dev->mc_count > 6) && (tp->chip_id == X3201_3))) { /* Must use a multicast hash table. */ + u16 hash_table[32]; + tx_flags = 0x08400000 | 192; /* Use hash filter. */ + memset(hash_table, 0, sizeof(hash_table)); + set_bit(255, hash_table); /* Broadcast entry */ + /* This should work on big-endian machines as well. */ + for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + i++, mclist = mclist->next) + set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x1ff, + hash_table); + for (i = 0; i < 32; i++) { + *setup_frm++ = hash_table[i]; + *setup_frm++ = hash_table[i]; + } + setup_frm = &tp->setup_frame[13*6]; + } else if(tp->chip_id != X3201_3) { + /* We have <= 14 addresses so we can use the wonderful + 16 address perfect filtering of the Tulip. */ + for (i = 0, mclist = dev->mc_list; i < dev->mc_count; + i++, mclist = mclist->next) { + eaddrs = (u16 *)mclist->dmi_addr; + *setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0]; + *setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1]; + *setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2]; + } + /* Fill the unused entries with the broadcast address. */ + memset(setup_frm, 0xff, (15-i)*12); + setup_frm = &tp->setup_frame[15*6]; + } else { + /* fill the first two table entries with our address */ + eaddrs = (u16 *)dev->dev_addr; + for(i=0; i<2; i++) { + *setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0]; + *setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1]; + *setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2]; + } + /* Double fill each entry to accomodate chips that */ + /* don't like to parse these correctly */ + for (i=0, mclist=dev->mc_list; i<dev->mc_count; + i++, mclist=mclist->next) { + eaddrs = (u16 *)mclist->dmi_addr; + *setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0]; + *setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1]; + *setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2]; + *setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0]; + *setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1]; + *setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2]; + } + i=((i+1)*2); + /* Fill the unused entries with the broadcast address. */ + memset(setup_frm, 0xff, (15-i)*12); + setup_frm = &tp->setup_frame[15*6]; + } + + /* Fill the final entry with our physical address. */ + eaddrs = (u16 *)dev->dev_addr; + *setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0]; + *setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1]; + *setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2]; + /* Now add this frame to the Tx list. */ + if (tp->cur_tx - tp->dirty_tx > TX_RING_SIZE - 2) { + /* Same setup recently queued, we need not add it. */ + } else { + unsigned long flags; + unsigned int entry, dummy = -1; + + save_flags(flags); cli(); + entry = tp->cur_tx++ % TX_RING_SIZE; + + if (entry != 0) { + /* Avoid a chip errata by prefixing a dummy entry. */ + tp->tx_skbuff[entry] = 0; + tp->tx_ring[entry].length = + (entry == TX_RING_SIZE-1) ? DESC_RING_WRAP : 0; + tp->tx_ring[entry].buffer1 = 0; + /* race with chip, set DescOwned later */ + dummy = entry; + entry = tp->cur_tx++ % TX_RING_SIZE; + } + + tp->tx_skbuff[entry] = 0; + /* Put the setup frame on the Tx list. */ + if (entry == TX_RING_SIZE-1) + tx_flags |= DESC_RING_WRAP; /* Wrap ring. */ + tp->tx_ring[entry].length = tx_flags; + if(tp->chip_id == X3201_3) + tp->tx_ring[entry].buffer1 = (virt_to_bus(tp->setup_frame) + 4); + else + tp->tx_ring[entry].buffer1 = virt_to_bus(tp->setup_frame); + tp->tx_ring[entry].status = DescOwned; + if (tp->cur_tx - tp->dirty_tx >= TX_RING_SIZE - 2) { + tp->tx_full = 1; + netif_stop_queue (dev); + } + if (dummy >= 0) + tp->tx_ring[dummy].status = DescOwned; + restore_flags(flags); + /* Trigger an immediate transmit demand. */ + outl(0, ioaddr + CSR1); + } + } + outl_CSR6(csr6 | 0x0000, ioaddr, tp->chip_id); +} + +static struct pci_device_id tulip_pci_table[] __devinitdata = { +#if 0 /* these entries conflict with regular tulip driver */ + { 0x1011, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21040 }, + { 0x1011, 0x0014, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21041 }, + { 0x1011, 0x0009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21140 }, + { 0x1011, 0x0019, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21142 }, + { 0x11AD, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, LC82C168 }, + { 0x10d9, 0x0512, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98713 }, + { 0x10d9, 0x0531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98715 }, + { 0x10d9, 0x0531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98725 }, + { 0x125B, 0x1400, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AX88140 }, + { 0x11AD, 0xc115, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PNIC2 }, + { 0x1317, 0x0981, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, + { 0x11F6, 0x9881, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMPEX9881 }, +#endif + { 0x115D, 0x0003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, X3201_3 }, + {0}, +}; + +MODULE_DEVICE_TABLE(pci, tulip_pci_table); + +static int __devinit tulip_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct net_device *dev; + static int board_idx = 0; + + printk(KERN_INFO "tulip_attach(%s)\n", pdev->slot_name); + + pci_enable_device (pdev); + pci_set_master (pdev); + dev = tulip_probe1(pdev, NULL, + pci_resource_start (pdev, 0), pdev->irq, + id->driver_data, board_idx++); + if (dev) { + pdev->driver_data = dev; + return 0; + } + return -ENODEV; +} + +static void tulip_suspend(struct pci_dev *pdev) +{ + struct net_device *dev = pdev->driver_data; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + printk(KERN_INFO "tulip_suspend(%s)\n", dev->name); + if (tp->open) tulip_down(dev); +} + +static void tulip_resume(struct pci_dev *pdev) +{ + struct net_device *dev = pdev->driver_data; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + printk(KERN_INFO "tulip_resume(%s)\n", dev->name); + if (tp->open) tulip_up(dev); +} + +static void __devexit tulip_remove(struct pci_dev *pdev) +{ + struct net_device *dev = pdev->driver_data; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + + printk(KERN_INFO "tulip_detach(%s)\n", dev->name); + unregister_netdev(dev); + kfree(dev); + kfree(tp); +} + +static struct pci_driver tulip_ops = { + name: "tulip_cb", + id_table: tulip_pci_table, + probe: tulip_pci_probe, + remove: tulip_remove, + suspend: tulip_suspend, + resume: tulip_resume +}; + +static int __init tulip_init(void) +{ + pci_register_driver(&tulip_ops); + return 0; +} + +static __exit void tulip_exit(void) +{ + pci_unregister_driver(&tulip_ops); +} + +module_init(tulip_init) +module_exit(tulip_exit) + + +/* + * Local variables: + * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c tulip.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" + * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c tulip.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" + * cardbus-compile-command: "gcc -DCARDBUS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c tulip.c -o tulip_cb.o -I/usr/src/pcmcia-cs-3.0.9/include/" + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ diff --git a/drivers/net/plip.c b/drivers/net/plip.c index 64fafa17f..6508c56c2 100644 --- a/drivers/net/plip.c +++ b/drivers/net/plip.c @@ -1325,7 +1325,7 @@ static void __exit plip_cleanup_module (void) static int parport_ptr = 0; -static void __init plip_setup(char *str) +static int __init plip_setup(char *str) { int ints[4]; @@ -1350,6 +1350,7 @@ static void __init plip_setup(char *str) ints[1]); } } + return 1; } __setup("plip=", plip_setup); diff --git a/drivers/net/rrunner.c b/drivers/net/rrunner.c index 8e8236e92..8ad1a2a16 100644 --- a/drivers/net/rrunner.c +++ b/drivers/net/rrunner.c @@ -1650,6 +1650,6 @@ static int rr_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) /* * Local variables: - * compile-command: "gcc -D__SMP__ -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -pipe -fomit-frame-pointer -fno-strength-reduce -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DCPU=686 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -c rrunner.c" + * compile-command: "gcc -D__SMP__ -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -pipe -fomit-frame-pointer -fno-strength-reduce -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -c rrunner.c" * End: */ diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c index 213905c3a..c7cb98318 100644 --- a/drivers/net/sgiseeq.c +++ b/drivers/net/sgiseeq.c @@ -1,4 +1,4 @@ -/* $Id: sgiseeq.c,v 1.16 2000/03/26 22:57:54 ralf Exp $ +/* $Id: sgiseeq.c,v 1.17 2000/03/27 23:02:57 ralf Exp $ * * sgiseeq.c: Seeq8003 ethernet driver for SGI machines. * @@ -32,6 +32,7 @@ #include <linux/skbuff.h> #include <asm/sgi/sgihpc.h> +#include <asm/sgi/sgint23.h> #include <asm/sgialib.h> #include "sgiseeq.h" diff --git a/drivers/net/shaper.c b/drivers/net/shaper.c index c3a552b43..41e15ff36 100644 --- a/drivers/net/shaper.c +++ b/drivers/net/shaper.c @@ -485,20 +485,24 @@ static void shaper_cache_update(struct hh_cache *hh, struct net_device *dev, static int shaper_neigh_setup(struct neighbour *n) { +#ifdef CONFIG_INET if (n->nud_state == NUD_NONE) { n->ops = &arp_broken_ops; n->output = n->ops->output; } +#endif return 0; } static int shaper_neigh_setup_dev(struct net_device *dev, struct neigh_parms *p) { +#ifdef CONFIG_INET if (p->tbl->family == AF_INET) { p->neigh_setup = shaper_neigh_setup; p->ucast_probes = 0; p->mcast_probes = 0; } +#endif return 0; } diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index de0856020..5036b01af 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -12,10 +12,16 @@ Support and updates available at http://cesdis.gsfc.nasa.gov/linux/drivers/starfire.html + + LK1.1.1 (jgarzik): + - Use PCI driver interface + - Fix MOD_xxx races + - softnet fixups + */ static const char *versionA = -"starfire.c:v0.12 5/28/99 Written by Donald Becker\n", +"starfire.c:v0.12+LK1.1.1 3/19/2000 Written by Donald Becker and others\n", *versionB =" Undates and info at http://www.beowulf.org/linux/drivers.html\n"; /* A few user-configurable values. These may be modified when a driver @@ -26,7 +32,6 @@ static int interrupt_mitigation = 0x0; static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ static int max_interrupt_work = 20; -static int min_pci_latency = 64; static int mtu = 0; /* Maximum number of multicast addresses to filter (vs. rx-all-multicast). The Starfire has a 512 element hash table based on the Ethernet CRC. */ @@ -62,6 +67,9 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; #define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ +#define PFX "starfire: " + + #if !defined(__OPTIMIZE__) || !defined(__KERNEL__) #warning You must compile this file with the correct options! #warning See the last lines of the source file. @@ -94,7 +102,6 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>"); MODULE_DESCRIPTION("Adaptec Starfire Ethernet driver"); MODULE_PARM(max_interrupt_work, "i"); -MODULE_PARM(min_pci_latency, "i"); MODULE_PARM(mtu, "i"); MODULE_PARM(debug, "i"); MODULE_PARM(rx_copybreak, "i"); @@ -196,38 +203,33 @@ 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 *starfire_probe1(struct pci_dev *pdev, int pci_bus, - int pci_devfn, long ioaddr, - int irq, int chp_idx, int fnd_cnt); #if 0 #define ADDR_64BITS 1 /* This chip uses 64 bit addresses. */ #endif #define MEM_ADDR_SZ 0x80000 /* And maps in 0.5MB(!). */ -static struct pci_id_info pci_tbl[] = { - { "Adaptec Starfire 6915", - 0x9004, 0x6915, 0xffff, PCI_USES_MASTER, 128, starfire_probe1}, - {0,}, /* 0 terminated list. */ + +enum chipset { + CH_6915 = 0, }; -/* A chip capabilities table, matching the entries in pci_tbl[] above. */ +static struct pci_device_id starfire_pci_tbl[] __devinitdata = { + { 0x9004, 0x6915, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_6915 }, + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, starfire_pci_tbl); + + +/* A chip capabilities table, matching the CH_xxx entries in xxx_pci_tbl[] above. */ enum chip_capability_flags {CanHaveMII=1, }; -struct chip_info { +static struct chip_info { char *chip_name; int io_size; int flags; - void (*media_timer)(unsigned long data); -} static skel_netdrv_tbl[] = { - {"Adaptec Starfire 6915", 128, CanHaveMII, 0, }, +} netdrv_tbl[] = { + { "Adaptec Starfire 6915", 128, CanHaveMII }, }; @@ -322,8 +324,6 @@ struct netdev_private { struct starfire_tx_desc *tx_ring; dma_addr_t rx_ring_dma; dma_addr_t tx_ring_dma; - struct net_device *next_module; /* Link for devices of this type. */ - const char *product_name; /* The addresses of rx/tx-in-place skbuffs. */ struct ring_info rx_info[RX_RING_SIZE]; struct ring_info tx_info[TX_RING_SIZE]; @@ -340,7 +340,6 @@ struct netdev_private { /* Frequently used values: keep some adjacent for cache effect. */ int chip_id; struct pci_dev *pdev; - unsigned char pci_bus, pci_devfn; unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ unsigned int cur_tx, dirty_tx; unsigned int rx_buf_sz; /* Based on MTU+slack. */ @@ -378,107 +377,62 @@ static struct net_device_stats *get_stats(struct net_device *dev); static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static int netdev_close(struct net_device *dev); - -/* A list of our installed devices, for removing the driver module. */ -static struct net_device *root_net_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 - cards we know about in slot order. */ - -static int pci_etherdev_probe(struct pci_id_info pci_tbl[]) +static int __devinit starfire_init_one (struct pci_dev *pdev, + const struct pci_device_id *ent) { - int cards_found = 0; - int pci_index = 0; - unsigned char pci_bus, pci_device_fn; + struct netdev_private *np; + int i, irq, option, chip_id = ent->driver_data; struct net_device *dev; - - for (;pci_index < 0xff; pci_index++) { - struct pci_dev *pdev; - u16 vendor, device, pci_command, new_command; - int chip_idx, irq; - long pciaddr; - long ioaddr; - - if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pci_index, - &pci_bus, &pci_device_fn) - != PCIBIOS_SUCCESSFUL) - break; - pdev = pci_find_slot (pci_bus, pci_device_fn); - if (!pdev) continue; - vendor = pdev->vendor; - device = pdev->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; - - pciaddr = pdev->resource[0].start; -#if defined(ADDR_64BITS) && defined(__alpha__) - pciaddr |= ((long)pdev->base_address[1]) << 32; -#endif - irq = pdev->irq; - - if (debug > 2) - printk(KERN_INFO "Found %s at PCI address %#lx, IRQ %d.\n", - pci_tbl[chip_idx].name, pciaddr, irq); - - if ((pci_tbl[chip_idx].flags & PCI_USES_IO)) { - if (check_region(pciaddr, pci_tbl[chip_idx].io_size)) - continue; - ioaddr = pciaddr; - } else if ((ioaddr = (long)ioremap(pciaddr&~0xf, MEM_ADDR_SZ)) == 0) { - printk(KERN_INFO "Failed to map PCI address %#lx.\n", - pciaddr); - continue; - } - - pci_read_config_word(pdev, 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); - pci_write_config_word(pdev, 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; - pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency); - if (pci_latency < min_pci_latency) { - printk(KERN_INFO " PCI latency timer (CFLT) is " - "unreasonably low at %d. Setting to %d clocks.\n", - pci_latency, min_pci_latency); - pci_write_config_byte(pdev, PCI_LATENCY_TIMER, min_pci_latency); - } - } - cards_found++; + static int card_idx = 0; + static int printed_version = 0; + long ioaddr; + int io_size = netdrv_tbl[chip_id].io_size; + + ioaddr = pci_resource_start (pdev, 0); + if (!ioaddr || ((pci_resource_flags (pdev, 0) & IORESOURCE_MEM) == 0)) { + printk (KERN_ERR PFX "no PCI MEM resources, aborting\n"); + return -ENODEV; + } + + dev = init_etherdev(NULL, sizeof(*np)); + if (!dev) { + printk (KERN_ERR PFX "cannot alloc etherdev, aborting\n"); + return -ENOMEM; + } + + irq = pdev->irq; + + if (request_mem_region (ioaddr, io_size, dev->name) == NULL) { + printk (KERN_ERR PFX "resource 0x%x @ 0x%lx busy, aborting\n", + io_size, ioaddr); + goto err_out_free_netdev; + } + + if (pci_enable_device (pdev)) { + printk (KERN_ERR PFX "cannot enable PCI device, aborting\n"); + goto err_out_free_res; + } + + ioaddr = (long) ioremap (ioaddr, io_size); + if (!ioaddr) { + printk (KERN_ERR PFX "cannot remap 0x%x @ 0x%lx, aborting\n", + io_size, ioaddr); + goto err_out_free_res; } - return cards_found ? 0 : -ENODEV; -} - -static struct net_device * -starfire_probe1(struct pci_dev *pdev, int pci_bus, int pci_devfn, long ioaddr, int irq, int chip_id, int card_idx) -{ - struct netdev_private *np; - int i, option = card_idx < MAX_UNITS ? options[card_idx] : 0; - struct net_device *dev = init_etherdev(NULL, 0); - - if (!dev) - return NULL; + pci_set_master (pdev); + + option = card_idx < MAX_UNITS ? options[card_idx] : 0; + card_idx++; + + if (!printed_version) { + printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB); + printed_version = 1; + } - printk(KERN_INFO "%s: %s at 0x%lx, ", - dev->name, skel_netdrv_tbl[chip_id].chip_name, ioaddr); + printk (KERN_INFO "%s: %s at 0x%lx, ", + dev->name, netdrv_tbl[chip_id].chip_name, ioaddr); /* Serial EEPROM reads are hidden by the hardware. */ for (i = 0; i < 6; i++) @@ -500,18 +454,13 @@ starfire_probe1(struct pci_dev *pdev, int pci_bus, int pci_devfn, long ioaddr, i dev->base_addr = ioaddr; dev->irq = irq; - /* Make certain the descriptor lists are aligned. */ - np = (void *)(((long)kmalloc(sizeof(*np), GFP_KERNEL) + 15) & ~15); - memset(np, 0, sizeof(*np)); - dev->priv = np; - - np->next_module = root_net_dev; - root_net_dev = dev; + /* private struct aligned and zeroed by init_etherdev */ + np = dev->priv; np->pdev = pdev; - np->pci_bus = pci_bus; - np->pci_devfn = pci_devfn; np->chip_id = chip_id; + + pdev->driver_data = dev; if (dev->mem_start) option = dev->mem_start; @@ -533,7 +482,7 @@ starfire_probe1(struct pci_dev *pdev, int pci_bus, int pci_devfn, long ioaddr, i /* The chip-specific entries in the device structure. */ dev->open = &netdev_open; dev->hard_start_xmit = &start_tx; - dev->tx_timeout = tx_timeout; + dev->tx_timeout = &tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; dev->stop = &netdev_close; dev->get_stats = &get_stats; @@ -543,7 +492,7 @@ starfire_probe1(struct pci_dev *pdev, int pci_bus, int pci_devfn, long ioaddr, i if (mtu) dev->mtu = mtu; - if (skel_netdrv_tbl[np->chip_id].flags & CanHaveMII) { + if (netdrv_tbl[np->chip_id].flags & CanHaveMII) { int phy, phy_idx = 0; for (phy = 0; phy < 32 && phy_idx < 4; phy++) { int mii_status = mdio_read(dev, phy, 1); @@ -558,7 +507,14 @@ starfire_probe1(struct pci_dev *pdev, int pci_bus, int pci_devfn, long ioaddr, i np->mii_cnt = phy_idx; } - return dev; + return 0; + +err_out_free_res: + release_mem_region (ioaddr, io_size); +err_out_free_netdev: + unregister_netdev (dev); + kfree (dev); + return -ENODEV; } @@ -590,10 +546,13 @@ static int netdev_open(struct net_device *dev) long ioaddr = dev->base_addr; int i; + MOD_INC_USE_COUNT; /* Do we need to reset the chip??? */ - if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev)) - return -EAGAIN; + if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev)) { + MOD_DEC_USE_COUNT; + return -EBUSY; + } /* Disable the Rx and Tx, and reset the chip. */ writel(0, ioaddr + GenCtrl); @@ -624,11 +583,10 @@ static int netdev_open(struct net_device *dev) if (np->rx_ring) pci_free_consistent(np->pdev, PAGE_SIZE, np->rx_ring, np->rx_ring_dma); + MOD_DEC_USE_COUNT; return -ENOMEM; } - MOD_INC_USE_COUNT; - init_ring(dev); /* Set the size of the Rx buffers. */ writel((np->rx_buf_sz<<16) | 0xA000, ioaddr + RxDescQCtrl); @@ -691,6 +649,8 @@ static int netdev_open(struct net_device *dev) /* Enable the Rx and Tx units. */ writel(0x000F, ioaddr + GenCtrl); + netif_start_queue(dev); + if (debug > 2) printk(KERN_DEBUG "%s: Done netdev_open().\n", dev->name); @@ -762,6 +722,7 @@ static void netdev_timer(unsigned long data) add_timer(&np->timer); } + static void tx_timeout(struct net_device *dev) { struct netdev_private *np = (struct netdev_private *)dev->priv; @@ -783,15 +744,16 @@ static void tx_timeout(struct net_device *dev) } #endif - /* Perhaps we should reinitialize the hardware here. */ - dev->if_port = 0; - /* Stop and restart the chip's Tx processes . */ + /* Perhaps we should reinitialize the hardware here. */ + dev->if_port = 0; + + /* Stop and restart the chip's Tx processes . */ + /* XXX todo */ - /* Trigger an immediate transmit demand. */ + /* Trigger an immediate transmit demand. */ + /* XXX todo */ - netif_wake_queue(dev); - np->stats.tx_errors++; - return; + np->stats.tx_errors++; } @@ -849,8 +811,6 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) struct netdev_private *np = (struct netdev_private *)dev->priv; unsigned entry; - netif_stop_queue(dev); - /* Caution: the write order is important here, set the field with the "ownership" bits last. */ @@ -883,10 +843,10 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) /* Update the producer index. */ writel(++entry, dev->base_addr + TxProducerIdx); - if (np->cur_tx - np->dirty_tx >= TX_RING_SIZE - 1) + if (np->cur_tx - np->dirty_tx >= TX_RING_SIZE - 1) { np->tx_full = 1; - if (! np->tx_full) - netif_start_queue(dev); + netif_stop_queue(dev); + } dev->trans_start = jiffies; if (debug > 4) { @@ -1347,56 +1307,69 @@ static int netdev_close(struct net_device *dev) return 0; } -static int __init starfire_init_module (void) + +static void __devexit starfire_remove_one (struct pci_dev *pdev) { - if (debug) /* Emit version even if no cards detected. */ - printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB); -#ifdef CARDBUS - register_driver(ðerdev_ops); - return 0; -#else - if (pci_etherdev_probe(pci_tbl)) { - printk(KERN_INFO " No Starfire adapters detected, driver not loaded.\n"); - return -ENODEV; + struct net_device *dev = pdev->driver_data; + struct netdev_private *np; + + if (!dev) { + printk (KERN_WARNING "bug: removing starfire pci dev without driver\n"); + return; } - return 0; -#endif + + np = dev->priv; + + unregister_netdev(dev); + iounmap((char *)dev->base_addr); + + if (np->tx_done_q) + pci_free_consistent(np->pdev, PAGE_SIZE, + np->tx_done_q, np->tx_done_q_dma); + if (np->rx_done_q) + pci_free_consistent(np->pdev, PAGE_SIZE, + np->rx_done_q, np->rx_done_q_dma); + if (np->tx_ring) + pci_free_consistent(np->pdev, PAGE_SIZE, + np->tx_ring, np->tx_ring_dma); + if (np->rx_ring) + pci_free_consistent(np->pdev, PAGE_SIZE, + np->rx_ring, np->rx_ring_dma); + + kfree(dev); } -static void __exit starfire_cleanup_module (void) + +static struct pci_driver starfire_driver = { + name: "starfire", + probe: starfire_init_one, + remove: starfire_remove_one, + id_table: starfire_pci_tbl, +}; + + +static int __init starfire_init (void) { - struct net_device *next_dev; + int rc; + + MOD_INC_USE_COUNT; + + rc = pci_module_init (&starfire_driver); + + MOD_DEC_USE_COUNT; + + return rc; +} -#ifdef CARDBUS - unregister_driver(ðerdev_ops); -#endif - /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ - while (root_net_dev) { - struct netdev_private *np = - (struct netdev_private *)root_net_dev->priv; - next_dev = np->next_module; - unregister_netdev(root_net_dev); - iounmap((char *)root_net_dev->base_addr); - if (np->tx_done_q) - pci_free_consistent(np->pdev, PAGE_SIZE, - np->tx_done_q, np->tx_done_q_dma); - if (np->rx_done_q) - pci_free_consistent(np->pdev, PAGE_SIZE, - np->rx_done_q, np->rx_done_q_dma); - if (np->tx_ring) - pci_free_consistent(np->pdev, PAGE_SIZE, - np->tx_ring, np->tx_ring_dma); - if (np->rx_ring) - pci_free_consistent(np->pdev, PAGE_SIZE, - np->rx_ring, np->rx_ring_dma); - kfree(root_net_dev); - root_net_dev = next_dev; - } +static void __exit starfire_cleanup (void) +{ + pci_unregister_driver (&starfire_driver); } -module_init(starfire_init_module); -module_exit(starfire_cleanup_module); + +module_init(starfire_init); +module_exit(starfire_cleanup); /* diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c index a699391da..5c466ecf0 100644 --- a/drivers/net/tlan.c +++ b/drivers/net/tlan.c @@ -66,6 +66,12 @@ * network cleanup in 2.3.43pre7 (Tigran & myself) * - Minor stuff. * + * v1.5 March 22, 2000 - Fixed another timer bug that would hang the driver + * if no cable/link were present. + * - Cosmetic changes. + * - TODO: Port completely to new PCI/DMA API + * Auto-Neg fallback. + * *******************************************************************************/ @@ -106,7 +112,7 @@ static int bbuf = 0; static u8 *TLanPadBuffer; static char TLanSignature[] = "TLAN"; static int TLanVersionMajor = 1; -static int TLanVersionMinor = 4; +static int TLanVersionMinor = 5; static TLanAdapterEntry TLanAdapterList[] __initdata = { @@ -430,7 +436,8 @@ static int __init tlan_probe(void) } - printk(KERN_INFO "TLAN: %d device(s) installed\n", TLanDevicesInstalled); + printk(KERN_INFO "TLAN: %d device%s installed\n", + TLanDevicesInstalled, TLanDevicesInstalled == 1 ? "" : "s"); return ((TLanDevicesInstalled > 0) ? 0 : -ENODEV); } @@ -839,8 +846,10 @@ static int TLan_Close(struct net_device *dev) TLan_ReadAndClearStats( dev, TLAN_RECORD ); outl( TLAN_HC_AD_RST, dev->base_addr + TLAN_HOST_CMD ); - if ( priv->timer.function != NULL ) + if ( priv->timer.function != NULL ) { del_timer( &priv->timer ); + priv->timer.function = NULL; + } free_irq( dev->irq, dev ); TLan_FreeLists( dev ); TLAN_DBG( TLAN_DEBUG_GNRL, "Device %s closed.\n", dev->name ); diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c index e0a339bfa..1714d34d1 100644 --- a/drivers/net/tokenring/lanstreamer.c +++ b/drivers/net/tokenring/lanstreamer.c @@ -58,6 +58,7 @@ * First release to the public * 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 * * To Do: * @@ -105,6 +106,7 @@ #include <linux/stddef.h> #include <linux/init.h> #include <linux/pci.h> +#include <linux/spinlock.h> #include <net/checksum.h> #include <asm/io.h> @@ -121,7 +123,7 @@ * Official releases will only have an a.b.c version number format. */ -static char *version = "LanStreamer.c v0.1.0 12/10/99 - Mike Sullivan"; +static char *version = "LanStreamer.c v0.3.1 03/13/99 - Mike Sullivan"; static char *open_maj_error[] = { "No error", "Lobe Media Test", "Physical Insertion", @@ -210,7 +212,7 @@ static int __init streamer_scan(struct net_device *dev) /* Check to see if io has been allocated, if so, we've already done this card, so continue on the card discovery loop */ - if (check_region(pci_device->resource[0].start, STREAMER_IO_SPACE)) + if (check_region(pci_device->resource[0].start & (~3), STREAMER_IO_SPACE)) { card_no++; continue; @@ -223,6 +225,8 @@ static int __init streamer_scan(struct net_device *dev) 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) @@ -238,11 +242,11 @@ static int __init streamer_scan(struct net_device *dev) pci_device, dev, dev->priv); #endif dev->irq = pci_device->irq; - dev->base_addr = pci_device->resource[0].start; + dev->base_addr = pci_device->resource[0].start & (~3); dev->init = &streamer_init; + streamer_priv->streamer_card_name = (char *)pci_device->resource[0].name; streamer_priv->streamer_mmio = ioremap(pci_device->resource[1].start, 256); - init_waitqueue_head(&streamer_priv->srb_wait); - init_waitqueue_head(&streamer_priv->trb_wait); + if ((pkt_buf_sz[card_no] < 100) || (pkt_buf_sz[card_no] > 18000)) streamer_priv->pkt_buf_sz = PKT_BUF_SZ; else @@ -250,7 +254,6 @@ static int __init streamer_scan(struct net_device *dev) streamer_priv->streamer_ring_speed = ringspeed[card_no]; streamer_priv->streamer_message_level = message_level[card_no]; - streamer_priv->streamer_multicast_set = 0; if (streamer_init(dev) == -1) { unregister_netdevice(dev); @@ -274,7 +277,7 @@ static int __init streamer_scan(struct net_device *dev) } -static int __init streamer_init(struct net_device *dev) +static int streamer_reset(struct net_device *dev) { struct streamer_private *streamer_priv; __u8 *streamer_mmio; @@ -286,12 +289,6 @@ static int __init streamer_init(struct net_device *dev) streamer_priv = (struct streamer_private *) dev->priv; streamer_mmio = streamer_priv->streamer_mmio; - printk("%s \n", version); - printk(KERN_INFO "%s: IBM PCI tokenring card. I/O at %hx, MMIO at %p, using irq %d\n", - dev->name, (unsigned int) dev->base_addr, - streamer_priv->streamer_mmio, dev->irq); - - request_region(dev->base_addr, STREAMER_IO_SPACE, "streamer"); writew(readw(streamer_mmio + BCTL) | BCTL_SOFTRESET, streamer_mmio + BCTL); t = jiffies; /* Hold soft reset bit for a while */ @@ -330,11 +327,16 @@ static int __init streamer_init(struct net_device *dev) printk(KERN_INFO "%s: skb allocation for diagnostics failed...proceeding\n", dev->name); } else { - streamer_priv->streamer_rx_ring[0].forward = 0; - streamer_priv->streamer_rx_ring[0].status = 0; - streamer_priv->streamer_rx_ring[0].buffer = virt_to_bus(skb->data); - streamer_priv->streamer_rx_ring[0].framelen_buflen = 512; /* streamer_priv->pkt_buf_sz; */ - writel(virt_to_bus(&streamer_priv->streamer_rx_ring[0]), streamer_mmio + RXBDA); + struct streamer_rx_desc *rx_ring; + u8 *data; + + rx_ring=(struct streamer_rx_desc *)skb->data; + data=((u8 *)skb->data)+sizeof(struct streamer_rx_desc); + rx_ring->forward=0; + rx_ring->status=0; + rx_ring->buffer=virt_to_bus(data); + rx_ring->framelen_buflen=512; + writel(virt_to_bus(rx_ring),streamer_mmio+RXBDA); } #if STREAMER_DEBUG @@ -382,7 +384,7 @@ static int __init streamer_init(struct net_device *dev) writew(readw(streamer_mmio + LAPWWO) + 6, streamer_mmio + LAPA); if (readw(streamer_mmio + LAPD)) { printk(KERN_INFO "tokenring card intialization failed. errorcode : %x\n", - readw(streamer_mmio + LAPD)); + ntohs(readw(streamer_mmio + LAPD))); release_region(dev->base_addr, STREAMER_IO_SPACE); return -1; } @@ -398,17 +400,14 @@ static int __init streamer_init(struct net_device *dev) #endif /* setup uaa area for access with LAPD */ - writew(uaa_addr, streamer_mmio + LAPA); - - /* setup uaa area for access with LAPD */ { int i; __u16 addr; writew(uaa_addr, streamer_mmio + LAPA); for (i = 0; i < 6; i += 2) { - addr = readw(streamer_mmio + LAPDINC); - dev->dev_addr[i] = addr & 0xff; - dev->dev_addr[i + 1] = (addr >> 8) & 0xff; + addr=ntohs(readw(streamer_mmio+LAPDINC)); + dev->dev_addr[i]= (addr >> 8) & 0xff; + dev->dev_addr[i+1]= addr & 0xff; } #if STREAMER_DEBUG printk("Adapter address: "); @@ -421,6 +420,32 @@ static int __init streamer_init(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; @@ -430,7 +455,11 @@ static int streamer_open(struct net_device *dev) int i, open_finished = 1; __u16 srb_word; __u16 srb_open; + int rc; + if (readw(streamer_mmio+BMCTL_SUM) & BMCTL_RX_ENABLED) { + rc=streamer_reset(dev); + } if (request_irq(dev->irq, &streamer_interrupt, SA_SHIRQ, "streamer", dev)) { return -EAGAIN; @@ -461,23 +490,27 @@ static int streamer_open(struct net_device *dev) writew(0, streamer_mmio + LAPDINC); } - writew(readw(streamer_mmio + LAPWWO), streamer_mmio + LAPA); - writew(SRB_OPEN_ADAPTER, streamer_mmio + LAPDINC); /* open */ + writew(readw(streamer_mmio+LAPWWO),streamer_mmio+LAPA); + writew(htons(SRB_OPEN_ADAPTER<<8),streamer_mmio+LAPDINC) ; /* open */ + writew(htons(STREAMER_CLEAR_RET_CODE<<8),streamer_mmio+LAPDINC); writew(STREAMER_CLEAR_RET_CODE, streamer_mmio + LAPDINC); writew(readw(streamer_mmio + LAPWWO) + 8, streamer_mmio + LAPA); #if STREAMER_NETWORK_MONITOR /* If Network Monitor, instruct card to copy MAC frames through the ARB */ - writew(ntohs(OPEN_ADAPTER_ENABLE_FDX | OPEN_ADAPTER_PASS_ADC_MAC | OPEN_ADAPTER_PASS_ATT_MAC | OPEN_ADAPTER_PASS_BEACON), streamer_mmio + LAPDINC); /* offset 8 word contains open options */ + writew(htons(OPEN_ADAPTER_ENABLE_FDX | OPEN_ADAPTER_PASS_ADC_MAC | OPEN_ADAPTER_PASS_ATT_MAC | OPEN_ADAPTER_PASS_BEACON), streamer_mmio + LAPDINC); /* offset 8 word contains open options */ #else - writew(ntohs(OPEN_ADAPTER_ENABLE_FDX), streamer_mmio + LAPDINC); /* Offset 8 word contains Open.Options */ + writew(htons(OPEN_ADAPTER_ENABLE_FDX), streamer_mmio + LAPDINC); /* Offset 8 word contains Open.Options */ #endif if (streamer_priv->streamer_laa[0]) { writew(readw(streamer_mmio + LAPWWO) + 12, streamer_mmio + LAPA); - writew(((__u16 *) (streamer_priv->streamer_laa))[0], streamer_mmio + LAPDINC); /* offset 12 word */ - writew(((__u16 *) (streamer_priv->streamer_laa))[2], streamer_mmio + LAPDINC); /* offset 14 word */ - writew(((__u16 *) (streamer_priv->streamer_laa))[4], streamer_mmio + LAPDINC); /* offset 16 word */ + writew(htons((streamer_priv->streamer_laa[0] << 8) | + streamer_priv->streamer_laa[1]),streamer_mmio+LAPDINC); + writew(htons((streamer_priv->streamer_laa[2] << 8) | + streamer_priv->streamer_laa[3]),streamer_mmio+LAPDINC); + writew(htons((streamer_priv->streamer_laa[4] << 8) | + streamer_priv->streamer_laa[5]),streamer_mmio+LAPDINC); memcpy(dev->dev_addr, streamer_priv->streamer_laa, dev->addr_len); } @@ -526,7 +559,7 @@ static int streamer_open(struct net_device *dev) * timed out. */ writew(srb_open + 2, streamer_mmio + LAPA); - srb_word = readw(streamer_mmio + LAPD) & 0xFF; + srb_word = ntohs(readw(streamer_mmio + LAPD)) & 0xFF; if (srb_word == STREAMER_CLEAR_RET_CODE) { printk(KERN_WARNING "%s: Adapter Open time out or error.\n", dev->name); @@ -574,7 +607,7 @@ static int streamer_open(struct net_device *dev) } while (!(open_finished)); /* Will only loop if ring speed mismatch re-open attempted && autosense is on */ writew(srb_open + 18, streamer_mmio + LAPA); - srb_word = readw(streamer_mmio + LAPD) & 0xFF; + srb_word=ntohs(readw(streamer_mmio+LAPD)) >> 8; if (srb_word & (1 << 3)) if (streamer_priv->streamer_message_level) printk(KERN_INFO "%s: Opened in FDX Mode\n", dev->name); @@ -604,6 +637,14 @@ static int streamer_open(struct net_device *dev) writew(~BMCTL_RX_DIS, streamer_mmio + BMCTL_RUM); /* setup rx descriptors */ + streamer_priv->streamer_rx_ring= + kmalloc( sizeof(struct streamer_rx_desc)* + STREAMER_RX_RING_SIZE,GFP_KERNEL); + if (!streamer_priv->streamer_rx_ring) { + printk(KERN_WARNING "%s ALLOC of streamer rx ring FAILED!!\n",dev->name); + return -EIO; + } + for (i = 0; i < STREAMER_RX_RING_SIZE; i++) { struct sk_buff *skb; @@ -638,6 +679,13 @@ static int streamer_open(struct net_device *dev) /* setup tx ring */ + streamer_priv->streamer_tx_ring=kmalloc(sizeof(struct streamer_tx_desc)* + STREAMER_TX_RING_SIZE,GFP_KERNEL); + if (!streamer_priv->streamer_tx_ring) { + printk(KERN_WARNING "%s ALLOC of streamer_tx_ring FAILED\n",dev->name); + return -EIO; + } + writew(~BMCTL_TX2_DIS, streamer_mmio + BMCTL_RUM); /* Enables TX channel 2 */ for (i = 0; i < STREAMER_TX_RING_SIZE; i++) { streamer_priv->streamer_tx_ring[i].forward = virt_to_bus(&streamer_priv->streamer_tx_ring[i + 1]); @@ -776,7 +824,7 @@ static void streamer_rx(struct net_device *dev) memcpy(skb_put(skb, length),bus_to_virt(rx_desc->buffer), length); /* copy this fragment */ streamer_priv->streamer_rx_ring[rx_ring_last_received].status = 0; streamer_priv->streamer_rx_ring[rx_ring_last_received].framelen_buflen = streamer_priv->pkt_buf_sz; - streamer_priv->streamer_rx_ring[rx_ring_last_received].buffer = virt_to_bus(skb->data); + /* give descriptor back to the adapter */ writel(virt_to_bus(&streamer_priv->streamer_rx_ring[rx_ring_last_received]), streamer_mmio + RXLBDA); @@ -828,10 +876,14 @@ static void streamer_interrupt(int irq, void *dev_id, struct pt_regs *regs) misr = readw(streamer_mmio + MISR_RUM); writew(~misr, streamer_mmio + MISR_RUM); - if (!sisr) { /* Interrupt isn't for us */ + if (!sisr) + { /* Interrupt isn't for us */ + writew(~misr,streamer_mmio+MISR_RUM); return; } + spin_lock(&streamer_priv->streamer_lock); + if ((sisr & (SISR_SRB_REPLY | SISR_ADAPTER_CHECK | SISR_ASB_FREE | SISR_ARB_CMD | SISR_TRB_REPLY)) || (misr & (MISR_TX2_EOF | MISR_RX_NOBUF | MISR_RX_EOF))) { if (sisr & SISR_SRB_REPLY) { @@ -868,9 +920,9 @@ static void streamer_interrupt(int irq, void *dev_id, struct pt_regs *regs) writel(readl(streamer_mmio + LAPWWO), streamer_mmio + LAPA); printk(KERN_WARNING "%s: Words %x:%x:%x:%x:\n", dev->name, readw(streamer_mmio + LAPDINC), - readw(streamer_mmio + LAPDINC), - readw(streamer_mmio + LAPDINC), - readw(streamer_mmio + LAPDINC)); + ntohs(readw(streamer_mmio + LAPDINC)), + ntohs(readw(streamer_mmio + LAPDINC)), + ntohs(readw(streamer_mmio + LAPDINC))); free_irq(dev->irq, dev); } @@ -907,17 +959,19 @@ static void streamer_interrupt(int irq, void *dev_id, struct pt_regs *regs) } /* One if the interrupts we want */ writew(SISR_MI, streamer_mmio + SISR_MASK_SUM); + spin_unlock(&streamer_priv->streamer_lock) ; } - static int streamer_xmit(struct sk_buff *skb, struct net_device *dev) { struct streamer_private *streamer_priv = (struct streamer_private *) dev->priv; __u8 *streamer_mmio = streamer_priv->streamer_mmio; + unsigned long flags ; + spin_lock_irqsave(&streamer_priv->streamer_lock, flags); netif_stop_queue(dev); - + if (streamer_priv->free_tx_ring_entries) { streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].status = 0; streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].bufcnt_framelen = 0x00010000 | skb->len; @@ -941,9 +995,11 @@ static int streamer_xmit(struct sk_buff *skb, struct net_device *dev) writel(virt_to_bus (&streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free]),streamer_mmio + TX2LFDA); streamer_priv->tx_ring_free = (streamer_priv->tx_ring_free + 1) & (STREAMER_TX_RING_SIZE - 1); - netif_start_queue(dev); + netif_wake_queue(dev); + spin_unlock_irqrestore(&streamer_priv->streamer_lock,flags); return 0; } else { + spin_unlock_irqrestore(&streamer_priv->streamer_lock,flags); return 1; } } @@ -957,9 +1013,10 @@ static int streamer_close(struct net_device *dev) unsigned long flags; int i; + netif_stop_queue(dev); writew(streamer_priv->srb, streamer_mmio + LAPA); - writew(SRB_CLOSE_ADAPTER, streamer_mmio + LAPDINC); - writew(STREAMER_CLEAR_RET_CODE, streamer_mmio + LAPDINC); + writew(htons(SRB_CLOSE_ADAPTER << 8),streamer_mmio+LAPDINC); + writew(htons(STREAMER_CLEAR_RET_CODE << 8), streamer_mmio+LAPDINC); save_flags(flags); cli(); @@ -987,7 +1044,9 @@ static int streamer_close(struct net_device *dev) streamer_priv->rx_ring_last_received = (streamer_priv->rx_ring_last_received + 1) & (STREAMER_RX_RING_SIZE - 1); for (i = 0; i < STREAMER_RX_RING_SIZE; i++) { - dev_kfree_skb(streamer_priv->rx_ring_skb[streamer_priv->rx_ring_last_received]); + if (streamer_priv->rx_ring_skb[streamer_priv->rx_ring_last_received]) { + dev_kfree_skb(streamer_priv->rx_ring_skb[streamer_priv->rx_ring_last_received]); + } streamer_priv->rx_ring_last_received = (streamer_priv->rx_ring_last_received + 1) & (STREAMER_RX_RING_SIZE - 1); } @@ -1003,11 +1062,10 @@ static int streamer_close(struct net_device *dev) writew(streamer_priv->srb, streamer_mmio + LAPA); printk("srb): "); for (i = 0; i < 2; i++) { - printk("%x ", htons(readw(streamer_mmio + LAPDINC))); + printk("%x ", ntohs(readw(streamer_mmio + LAPDINC))); } printk("\n"); #endif - netif_stop_queue(dev); free_irq(dev->irq, dev); MOD_DEC_USE_COUNT; @@ -1019,9 +1077,10 @@ static void streamer_set_rx_mode(struct net_device *dev) struct streamer_private *streamer_priv = (struct streamer_private *) dev->priv; __u8 *streamer_mmio = streamer_priv->streamer_mmio; - __u8 options = 0, set_mc_list = 0; - __u16 ata1, ata2; + __u8 options = 0; struct dev_mc_list *dmi; + unsigned char dev_mc_address[5]; + int i; writel(streamer_priv->srb, streamer_mmio + LAPA); options = streamer_priv->streamer_copy_all_options; @@ -1031,23 +1090,17 @@ static void streamer_set_rx_mode(struct net_device *dev) else options &= ~(3 << 5); - if (dev->mc_count) { - set_mc_list = 1; - } - /* Only issue the srb if there is a change in options */ if ((options ^ streamer_priv->streamer_copy_all_options)) { /* Now to issue the srb command to alter the copy.all.options */ - - writew(SRB_MODIFY_RECEIVE_OPTIONS, - streamer_mmio + LAPDINC); - writew(STREAMER_CLEAR_RET_CODE, streamer_mmio + LAPDINC); - writew(streamer_priv->streamer_receive_options | (options << 8), streamer_mmio + LAPDINC); - writew(0x414a, streamer_mmio + LAPDINC); - writew(0x454d, streamer_mmio + LAPDINC); - writew(0x2053, streamer_mmio + LAPDINC); + writew(htons(SRB_MODIFY_RECEIVE_OPTIONS << 8), streamer_mmio+LAPDINC); + writew(htons(STREAMER_CLEAR_RET_CODE << 8), streamer_mmio+LAPDINC); + writew(htons((streamer_priv->streamer_receive_options << 8) | options),streamer_mmio+LAPDINC); + writew(htons(0x4a41),streamer_mmio+LAPDINC); + writew(htons(0x4d45),streamer_mmio+LAPDINC); + writew(htons(0x5320),streamer_mmio+LAPDINC); writew(0x2020, streamer_mmio + LAPDINC); streamer_priv->srb_queued = 2; /* Can't sleep, use srb_bh */ @@ -1058,54 +1111,25 @@ static void streamer_set_rx_mode(struct net_device *dev) return; } - if (set_mc_list ^ streamer_priv->streamer_multicast_set) - { /* Multicast options have changed */ - dmi = dev->mc_list; - - writel(streamer_priv->streamer_addr_table_addr, streamer_mmio + LAPA); - ata1 = readw(streamer_mmio + LAPDINC); - ata2 = readw(streamer_mmio + LAPD); - - writel(streamer_priv->srb, streamer_mmio + LAPA); - - if (set_mc_list) - { - /* Turn multicast on */ - - /* RFC 1469 Says we must support using the functional address C0 00 00 04 00 00 - * We do this with a set functional address mask. - */ - - if (!(ata1 & 0x0400)) { /* need to set functional mask */ - writew(SRB_SET_FUNC_ADDRESS, streamer_mmio + LAPDINC); - writew(STREAMER_CLEAR_RET_CODE, streamer_mmio + LAPDINC); - writew(0, streamer_mmio + LAPDINC); - writew(ata1 | 0x0400, streamer_mmio + LAPDINC); - writew(ata2, streamer_mmio + LAPD); - - streamer_priv->srb_queued = 2; - writel(LISR_SRB_CMD, streamer_mmio + LISR_SUM); - - streamer_priv->streamer_multicast_set = 1; - } - - } else { /* Turn multicast off */ - - if ((ata1 & 0x0400)) { /* Hmmm, need to reset the functional mask */ - writew(SRB_SET_FUNC_ADDRESS, streamer_mmio + LAPDINC); - writew(STREAMER_CLEAR_RET_CODE, streamer_mmio + LAPDINC); - writew(0, streamer_mmio + LAPDINC); - writew(ata1 & ~0x0400, streamer_mmio + LAPDINC); - writew(ata2, streamer_mmio + LAPD); - - streamer_priv->srb_queued = 2; - writel(LISR_SRB_CMD, streamer_mmio + LISR_SUM); - - streamer_priv->streamer_multicast_set = 0; - } - } - + /* Set the functional addresses we need for multicast */ + writel(streamer_priv->srb,streamer_mmio+LAPA); + dev_mc_address[0] = dev_mc_address[1] = dev_mc_address[2] = dev_mc_address[3] = 0 ; + + for (i=0,dmi=dev->mc_list;i < dev->mc_count; i++,dmi = dmi->next) + { + dev_mc_address[0] |= dmi->dmi_addr[2] ; + dev_mc_address[1] |= dmi->dmi_addr[3] ; + dev_mc_address[2] |= dmi->dmi_addr[4] ; + dev_mc_address[3] |= dmi->dmi_addr[5] ; } + + writew(htons(SRB_SET_FUNC_ADDRESS << 8),streamer_mmio+LAPDINC); + writew(htons(STREAMER_CLEAR_RET_CODE << 8), streamer_mmio+LAPDINC); + writew(0,streamer_mmio+LAPDINC); + writew(htons( (dev_mc_address[0] << 8) | dev_mc_address[1]),streamer_mmio+LAPDINC); + writew(htons( (dev_mc_address[2] << 8) | dev_mc_address[3]),streamer_mmio+LAPDINC); + streamer_priv->srb_queued = 2 ; + writel(LISR_SRB_CMD,streamer_mmio+LISR_SUM); } static void streamer_srb_bh(struct net_device *dev) @@ -1115,7 +1139,7 @@ static void streamer_srb_bh(struct net_device *dev) __u16 srb_word; writew(streamer_priv->srb, streamer_mmio + LAPA); - srb_word = readw(streamer_mmio + LAPDINC) & 0xFF; + srb_word=ntohs(readw(streamer_mmio+LAPDINC)) >> 8; switch (srb_word) { @@ -1125,7 +1149,8 @@ static void streamer_srb_bh(struct net_device *dev) */ case SRB_MODIFY_RECEIVE_OPTIONS: - srb_word = readw(streamer_mmio + LAPDINC) & 0xFF; + srb_word=ntohs(readw(streamer_mmio+LAPDINC)) >> 8; + switch (srb_word) { case 0x01: printk(KERN_WARNING "%s: Unrecognized srb command\n", dev->name); @@ -1147,11 +1172,10 @@ static void streamer_srb_bh(struct net_device *dev) /* SRB_SET_GROUP_ADDRESS - Multicast group setting */ case SRB_SET_GROUP_ADDRESS: - srb_word = readw(streamer_mmio + LAPDINC) & 0xFF; + srb_word=ntohs(readw(streamer_mmio+LAPDINC)) >> 8; switch (srb_word) { case 0x00: - streamer_priv->streamer_multicast_set = 1; - break; + break; case 0x01: printk(KERN_WARNING "%s: Unrecognized srb command \n",dev->name); break; @@ -1176,11 +1200,10 @@ static void streamer_srb_bh(struct net_device *dev) /* SRB_RESET_GROUP_ADDRESS - Remove a multicast address from group list */ case SRB_RESET_GROUP_ADDRESS: - srb_word = readw(streamer_mmio + LAPDINC) & 0xFF; + srb_word=ntohs(readw(streamer_mmio+LAPDINC)) >> 8; switch (srb_word) { case 0x00: - streamer_priv->streamer_multicast_set = 0; - break; + break; case 0x01: printk(KERN_WARNING "%s: Unrecognized srb command \n", dev->name); break; @@ -1200,7 +1223,7 @@ static void streamer_srb_bh(struct net_device *dev) */ case SRB_SET_FUNC_ADDRESS: - srb_word = readw(streamer_mmio + LAPDINC) & 0xFF; + srb_word=ntohs(readw(streamer_mmio+LAPDINC)) >> 8; switch (srb_word) { case 0x00: if (streamer_priv->streamer_message_level) @@ -1221,7 +1244,7 @@ static void streamer_srb_bh(struct net_device *dev) */ case SRB_READ_LOG: - srb_word = readw(streamer_mmio + LAPDINC) & 0xFF; + srb_word=ntohs(readw(streamer_mmio+LAPDINC)) >> 8; switch (srb_word) { case 0x00: { @@ -1250,7 +1273,7 @@ static void streamer_srb_bh(struct net_device *dev) /* SRB_READ_SR_COUNTERS - Read and reset the source routing bridge related counters */ case SRB_READ_SR_COUNTERS: - srb_word = readw(streamer_mmio + LAPDINC) & 0xFF; + srb_word=ntohs(readw(streamer_mmio+LAPDINC)) >> 8; switch (srb_word) { case 0x00: if (streamer_priv->streamer_message_level) @@ -1285,9 +1308,10 @@ static int streamer_set_mac_address(struct net_device *dev, void *addr) struct sockaddr *saddr = addr; struct streamer_private *streamer_priv = (struct streamer_private *) dev->priv; - if (netif_running(dev)) { + if (netif_running(dev)) + { printk(KERN_WARNING "%s: Cannot set mac/laa address while card is open\n", dev->name); - return -EBUSY; + return -EIO; } memcpy(streamer_priv->streamer_laa, saddr->sa_data, dev->addr_len); @@ -1324,12 +1348,12 @@ static void streamer_arb_cmd(struct net_device *dev) #endif writew(streamer_priv->arb, streamer_mmio + LAPA); - arb_word = readw(streamer_mmio + LAPD) & 0xFF; - + arb_word=ntohs(readw(streamer_mmio+LAPD)) >> 8; + if (arb_word == ARB_RECEIVE_DATA) { /* Receive.data, MAC frames */ writew(streamer_priv->arb + 6, streamer_mmio + LAPA); streamer_priv->mac_rx_buffer = buff_off = ntohs(readw(streamer_mmio + LAPDINC)); - header_len = readw(streamer_mmio + LAPDINC) & 0xff; /* 802.5 Token-Ring Header Length */ + header_len=ntohs(readw(streamer_mmio+LAPDINC)) >> 8; /* 802.5 Token-Ring Header Length */ frame_len = ntohs(readw(streamer_mmio + LAPDINC)); #if STREAMER_DEBUG @@ -1340,7 +1364,7 @@ static void streamer_arb_cmd(struct net_device *dev) __u16 len; writew(ntohs(buff_off), streamer_mmio + LAPA); /*setup window to frame data */ - next = ntohs(readw(streamer_mmio + LAPDINC)); + next = htons(readw(streamer_mmio + LAPDINC)); status = ntohs(readw(streamer_mmio + LAPDINC)) & 0xff; len = ntohs(readw(streamer_mmio + LAPDINC)); @@ -1364,7 +1388,7 @@ static void streamer_arb_cmd(struct net_device *dev) int i; __u16 rx_word; - writew(ntohs(buff_off), streamer_mmio + LAPA); /* setup window to frame data */ + writew(htons(buff_off), streamer_mmio + LAPA); /* setup window to frame data */ next_ptr = ntohs(readw(streamer_mmio + LAPDINC)); readw(streamer_mmio + LAPDINC); /* read thru status word */ buffer_len = ntohs(readw(streamer_mmio + LAPDINC)); @@ -1374,9 +1398,9 @@ static void streamer_arb_cmd(struct net_device *dev) i = 0; while (i < buffer_len) { - rx_word = readw(streamer_mmio + LAPDINC); - frame_data[i] = rx_word & 0xff; - frame_data[i + 1] = (rx_word >> 8) & 0xff; + rx_word=ntohs(readw(streamer_mmio+LAPDINC)); + frame_data[i]=rx_word >> 8; + frame_data[i+1]=rx_word & 0xff; i += 2; } @@ -1420,10 +1444,10 @@ static void streamer_arb_cmd(struct net_device *dev) writew(streamer_priv->asb, streamer_mmio + LAPA); - writew(ASB_RECEIVE_DATA, streamer_mmio + LAPDINC); /* Receive data */ - writew(STREAMER_CLEAR_RET_CODE, streamer_mmio + LAPDINC); /* Necessary ?? */ + writew(htons(ASB_RECEIVE_DATA << 8), streamer_mmio+LAPDINC); + writew(htons(STREAMER_CLEAR_RET_CODE << 8), streamer_mmio+LAPDINC); writew(0, streamer_mmio + LAPDINC); - writew(ntohs(streamer_priv->mac_rx_buffer), streamer_mmio + LAPD); + writew(htons(streamer_priv->mac_rx_buffer), streamer_mmio + LAPD); writel(LISR_ASB_REPLY | LISR_ASB_FREE_REQ, streamer_priv->streamer_mmio + LISR_SUM); @@ -1433,12 +1457,13 @@ static void streamer_arb_cmd(struct net_device *dev) } else if (arb_word == ARB_LAN_CHANGE_STATUS) { /* Lan.change.status */ writew(streamer_priv->arb + 6, streamer_mmio + LAPA); lan_status = ntohs(readw(streamer_mmio + LAPDINC)); - fdx_prot_error = readw(streamer_mmio + LAPD) & 0xFF; - + fdx_prot_error = ntohs(readw(streamer_mmio+LAPD)) >> 8; + /* Issue ARB Free */ writew(LISR_ARB_FREE, streamer_priv->streamer_mmio + LISR_SUM); - lan_status_diff = streamer_priv->streamer_lan_status ^ lan_status; + lan_status_diff = (streamer_priv->streamer_lan_status ^ lan_status) & + lan_status; if (lan_status_diff & (LSC_LWF | LSC_ARW | LSC_FPE | LSC_RR)) { @@ -1489,8 +1514,8 @@ static void streamer_arb_cmd(struct net_device *dev) /* Issue READ.LOG command */ writew(streamer_priv->srb, streamer_mmio + LAPA); - writew(SRB_READ_LOG, streamer_mmio + LAPDINC); - writew(STREAMER_CLEAR_RET_CODE, streamer_mmio + LAPDINC); + writew(htons(SRB_READ_LOG << 8),streamer_mmio+LAPDINC); + writew(htons(STREAMER_CLEAR_RET_CODE << 8), streamer_mmio+LAPDINC); writew(0, streamer_mmio + LAPDINC); streamer_priv->srb_queued = 2; /* Can't sleep, use srb_bh */ @@ -1503,10 +1528,10 @@ static void streamer_arb_cmd(struct net_device *dev) /* Issue a READ.SR.COUNTERS */ writew(streamer_priv->srb, streamer_mmio + LAPA); - writew(SRB_READ_SR_COUNTERS, - streamer_mmio + LAPDINC); - writew(STREAMER_CLEAR_RET_CODE, - streamer_mmio + LAPDINC); + writew(htons(SRB_READ_SR_COUNTERS << 8), + streamer_mmio+LAPDINC); + writew(htons(STREAMER_CLEAR_RET_CODE << 8), + streamer_mmio+LAPDINC); streamer_priv->srb_queued = 2; /* Can't sleep, use srb_bh */ writew(LISR_SRB_CMD, streamer_mmio + LISR_SUM); @@ -1528,10 +1553,10 @@ static void streamer_asb_bh(struct net_device *dev) /* Dropped through the first time */ writew(streamer_priv->asb, streamer_mmio + LAPA); - writew(ASB_RECEIVE_DATA, streamer_mmio + LAPDINC); /* Receive data */ - writew(STREAMER_CLEAR_RET_CODE, streamer_mmio + LAPDINC); /* Necessary ?? */ + writew(htons(ASB_RECEIVE_DATA << 8),streamer_mmio+LAPDINC); + writew(htons(STREAMER_CLEAR_RET_CODE << 8), streamer_mmio+LAPDINC); writew(0, streamer_mmio + LAPDINC); - writew(ntohs(streamer_priv->mac_rx_buffer), streamer_mmio + LAPD); + writew(htons(streamer_priv->mac_rx_buffer), streamer_mmio + LAPD); writel(LISR_ASB_REPLY | LISR_ASB_FREE_REQ, streamer_priv->streamer_mmio + LISR_SUM); streamer_priv->asb_queued = 2; @@ -1542,7 +1567,7 @@ static void streamer_asb_bh(struct net_device *dev) if (streamer_priv->asb_queued == 2) { __u8 rc; writew(streamer_priv->asb + 2, streamer_mmio + LAPA); - rc = readw(streamer_mmio + LAPD) & 0xff; + rc=ntohs(readw(streamer_mmio+LAPD)) >> 8; switch (rc) { case 0x01: printk(KERN_WARNING "%s: Unrecognized command code \n", dev->name); @@ -1594,7 +1619,7 @@ static int streamer_proc_info(char *buffer, char **start, off_t offset, off_t pos = 0; int size; - struct net_device *dev; + struct device *dev; size = sprintf(buffer, "IBM LanStreamer/MPC Chipset Token Ring Adapters\n"); @@ -1607,8 +1632,8 @@ static int streamer_proc_info(char *buffer, char **start, off_t offset, for (dev = dev_base; dev != NULL; dev = dev->next) { - if (dev->base_addr == (pci_device->base_address[0] & (~3))) - { /* Yep, a Streamer device */ + if (dev->base_addr == pci_device->resource[0].start) + { /* Yep, a Streamer device */ size = sprintf_info(buffer + len, dev); len += size; pos = begin + len; @@ -1644,17 +1669,17 @@ static int sprintf_info(char *buffer, struct net_device *dev) for (i = 0; i < 14; i += 2) { __u16 io_word; __u8 *datap = (__u8 *) & sat; - io_word = readw(streamer_mmio + LAPDINC); - datap[size] = io_word & 0xff; - datap[size + 1] = (io_word >> 8) & 0xff; + io_word=ntohs(readw(streamer_mmio+LAPDINC)); + datap[size]=io_word >> 8; + datap[size+1]=io_word & 0xff; } writew(streamer_priv->streamer_parms_addr, streamer_mmio + LAPA); for (i = 0; i < 68; i += 2) { __u16 io_word; __u8 *datap = (__u8 *) & spt; - io_word = readw(streamer_mmio + LAPDINC); - datap[size] = io_word & 0xff; - datap[size + 1] = (io_word >> 8) & 0xff; + io_word=ntohs(readw(streamer_mmio+LAPDINC)); + datap[size]=io_word >> 8; + datap[size+1]=io_word & 0xff; } @@ -1723,10 +1748,7 @@ int init_module(void) #if STREAMER_NETWORK_MONITOR #ifdef CONFIG_PROC_FS - struct proc_dir_entry *ent; - - ent = create_proc_entry("net/streamer_tr", 0, 0); - ent->read_proc = &streamer_proc_info; + create_proc_read_entry("net/streamer_tr",0,0,streamer_proc_info,NULL); #endif #endif for (i = 0; (i < STREAMER_MAX_ADAPTERS); i++) @@ -1758,11 +1780,17 @@ int init_module(void) void cleanup_module(void) { int i; + struct streamer_private *streamer_priv; 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_s(streamer_priv->streamer_rx_ring, + sizeof(struct streamer_rx_desc)*STREAMER_RX_RING_SIZE); + kfree_s(streamer_priv->streamer_tx_ring, + sizeof(struct streamer_tx_desc)*STREAMER_TX_RING_SIZE); kfree_s(dev_streamer[i]->priv, sizeof(struct streamer_private)); kfree_s(dev_streamer[i], sizeof(struct net_device)); dev_streamer[i] = NULL; diff --git a/drivers/net/tokenring/lanstreamer.h b/drivers/net/tokenring/lanstreamer.h index 7ba86dfe5..4c99f875e 100644 --- a/drivers/net/tokenring/lanstreamer.h +++ b/drivers/net/tokenring/lanstreamer.h @@ -132,6 +132,7 @@ #define BMCTL_TX1_DIS (1<<14) #define BMCTL_TX2_DIS (1<<10) #define BMCTL_RX_DIS (1<<6) +#define BMCTL_RX_ENABLED (1<<5) #define RXLBDA 0x90 #define RXBDA 0x94 @@ -257,6 +258,9 @@ struct streamer_private { __u16 asb; __u8 *streamer_mmio; + char *streamer_card_name; + + spinlock_t streamer_lock; volatile int srb_queued; /* True if an SRB is still posted */ wait_queue_head_t srb_wait; @@ -264,10 +268,10 @@ struct streamer_private { volatile int asb_queued; /* True if an ASB is posted */ volatile int trb_queued; /* True if a TRB is posted */ - wait_queue_head_t trb_wait; + wait_queue_head_t trb_wait; - struct streamer_rx_desc streamer_rx_ring[STREAMER_RX_RING_SIZE]; - struct streamer_tx_desc streamer_tx_ring[STREAMER_TX_RING_SIZE]; + struct streamer_rx_desc *streamer_rx_ring; + struct streamer_tx_desc *streamer_tx_ring; struct sk_buff *tx_ring_skb[STREAMER_TX_RING_SIZE], *rx_ring_skb[STREAMER_RX_RING_SIZE]; int tx_ring_free, tx_ring_last_status, rx_ring_last_received, @@ -279,7 +283,6 @@ struct streamer_private { __u16 pkt_buf_sz; __u8 streamer_receive_options, streamer_copy_all_options, streamer_message_level; - __u8 streamer_multicast_set; __u16 streamer_addr_table_addr, streamer_parms_addr; __u16 mac_rx_buffer; __u8 streamer_laa[6]; diff --git a/drivers/net/tulip/21142.c b/drivers/net/tulip/21142.c index 57b3aa252..f244874e4 100644 --- a/drivers/net/tulip/21142.c +++ b/drivers/net/tulip/21142.c @@ -14,7 +14,6 @@ */ #include "tulip.h" -#include <asm/io.h> static u16 t21142_csr13[] = { 0x0001, 0x0009, 0x0009, 0x0000, 0x0001, }; diff --git a/drivers/net/tulip/eeprom.c b/drivers/net/tulip/eeprom.c index b009a8a4b..27ea89232 100644 --- a/drivers/net/tulip/eeprom.c +++ b/drivers/net/tulip/eeprom.c @@ -15,7 +15,6 @@ #include "tulip.h" #include <linux/init.h> -#include <asm/io.h> #include <asm/unaligned.h> @@ -30,31 +29,31 @@ /* Known cards that have old-style EEPROMs. */ static struct eeprom_fixup eeprom_fixups[] __devinitdata = { {"Asante", 0, 0, 0x94, {0x1e00, 0x0000, 0x0800, 0x0100, 0x018c, - 0x0000, 0x0000, 0xe078, 0x0001, 0x0050, 0x0018 }}, + 0x0000, 0x0000, 0xe078, 0x0001, 0x0050, 0x0018 }}, {"SMC9332DST", 0, 0, 0xC0, { 0x1e00, 0x0000, 0x0800, 0x041f, - 0x0000, 0x009E, /* 10baseT */ - 0x0004, 0x009E, /* 10baseT-FD */ - 0x0903, 0x006D, /* 100baseTx */ - 0x0905, 0x006D, /* 100baseTx-FD */ }}, + 0x0000, 0x009E, /* 10baseT */ + 0x0004, 0x009E, /* 10baseT-FD */ + 0x0903, 0x006D, /* 100baseTx */ + 0x0905, 0x006D, /* 100baseTx-FD */ }}, {"Cogent EM100", 0, 0, 0x92, { 0x1e00, 0x0000, 0x0800, 0x063f, - 0x0107, 0x8021, /* 100baseFx */ - 0x0108, 0x8021, /* 100baseFx-FD */ - 0x0100, 0x009E, /* 10baseT */ - 0x0104, 0x009E, /* 10baseT-FD */ - 0x0103, 0x006D, /* 100baseTx */ - 0x0105, 0x006D, /* 100baseTx-FD */ }}, + 0x0107, 0x8021, /* 100baseFx */ + 0x0108, 0x8021, /* 100baseFx-FD */ + 0x0100, 0x009E, /* 10baseT */ + 0x0104, 0x009E, /* 10baseT-FD */ + 0x0103, 0x006D, /* 100baseTx */ + 0x0105, 0x006D, /* 100baseTx-FD */ }}, {"Maxtech NX-110", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x0513, - 0x1001, 0x009E, /* 10base2, CSR12 0x10*/ - 0x0000, 0x009E, /* 10baseT */ - 0x0004, 0x009E, /* 10baseT-FD */ - 0x0303, 0x006D, /* 100baseTx, CSR12 0x03 */ - 0x0305, 0x006D, /* 100baseTx-FD CSR12 0x03 */}}, + 0x1001, 0x009E, /* 10base2, CSR12 0x10*/ + 0x0000, 0x009E, /* 10baseT */ + 0x0004, 0x009E, /* 10baseT-FD */ + 0x0303, 0x006D, /* 100baseTx, CSR12 0x03 */ + 0x0305, 0x006D, /* 100baseTx-FD CSR12 0x03 */}}, {"Accton EN1207", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x051F, - 0x1B01, 0x0000, /* 10base2, CSR12 0x1B */ - 0x0B00, 0x009E, /* 10baseT, CSR12 0x0B */ - 0x0B04, 0x009E, /* 10baseT-FD,CSR12 0x0B */ - 0x1B03, 0x006D, /* 100baseTx, CSR12 0x1B */ - 0x1B05, 0x006D, /* 100baseTx-FD CSR12 0x1B */ + 0x1B01, 0x0000, /* 10base2, CSR12 0x1B */ + 0x0B00, 0x009E, /* 10baseT, CSR12 0x0B */ + 0x0B04, 0x009E, /* 10baseT-FD,CSR12 0x0B */ + 0x1B03, 0x006D, /* 100baseTx, CSR12 0x1B */ + 0x1B05, 0x006D, /* 100baseTx-FD CSR12 0x1B */ }}, {"NetWinder", 0x00, 0x10, 0x57, /* Default media = MII diff --git a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c index 12b7af968..0a48a27f0 100644 --- a/drivers/net/tulip/interrupt.c +++ b/drivers/net/tulip/interrupt.c @@ -14,7 +14,6 @@ */ #include "tulip.h" -#include <asm/io.h> #include <linux/etherdevice.h> #include <linux/pci.h> @@ -211,9 +210,12 @@ void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs) if (status < 0) break; /* It still has not been Txed */ + /* Check for Rx filter setup frames. */ if (tp->tx_buffers[entry].skb == NULL) { - pci_unmap_single(tp->pdev, + /* test because dummy frames not mapped */ + if (tp->tx_buffers[entry].mapping) + pci_unmap_single(tp->pdev, tp->tx_buffers[entry].mapping, sizeof(tp->setup_frame), PCI_DMA_TODEVICE); diff --git a/drivers/net/tulip/media.c b/drivers/net/tulip/media.c index 1d4c3b2e4..e704c6c7d 100644 --- a/drivers/net/tulip/media.c +++ b/drivers/net/tulip/media.c @@ -14,7 +14,6 @@ */ #include "tulip.h" -#include <asm/io.h> /* This is a mysterious value that can be written to CSR11 in the 21040 (only) diff --git a/drivers/net/tulip/pnic.c b/drivers/net/tulip/pnic.c index 445d4a440..2f408684f 100644 --- a/drivers/net/tulip/pnic.c +++ b/drivers/net/tulip/pnic.c @@ -15,7 +15,6 @@ #include <linux/kernel.h> #include "tulip.h" -#include <asm/io.h> void pnic_do_nway(struct net_device *dev) diff --git a/drivers/net/tulip/timer.c b/drivers/net/tulip/timer.c index 796fdd136..0a40abb48 100644 --- a/drivers/net/tulip/timer.c +++ b/drivers/net/tulip/timer.c @@ -14,7 +14,6 @@ */ #include "tulip.h" -#include <asm/io.h> void tulip_timer(unsigned long data) @@ -87,7 +86,11 @@ void tulip_timer(unsigned long data) break; } break; - case DC21140: case DC21142: case MX98713: case COMPEX9881: default: { + case DC21140: + case DC21142: + case MX98713: + case COMPEX9881: + default: { struct medialeaf *mleaf; unsigned char *p; if (tp->mtable == NULL) { /* No EEPROM info, use generic code. */ diff --git a/drivers/net/tulip/tulip.h b/drivers/net/tulip/tulip.h index 8196723ae..22260591f 100644 --- a/drivers/net/tulip/tulip.h +++ b/drivers/net/tulip/tulip.h @@ -17,7 +17,7 @@ #include <linux/spinlock.h> #include <linux/netdevice.h> #include <linux/timer.h> - +#include <asm/io.h> struct tulip_chip_table { char *chip_name; @@ -36,8 +36,10 @@ enum tbl_flag { HAS_ACPI = 0x10, MC_HASH_ONLY = 0x20, /* Hash-only multicast filter. */ HAS_PNICNWAY = 0x80, - HAS_NWAY143 = 0x40, /* Uses internal NWay xcvr. */ - HAS_8023X = 0x100, + HAS_NWAY = 0x40, /* Uses internal NWay xcvr. */ + HAS_INTR_MITIGATION = 0x100, + IS_ASIX = 0x200, + HAS_8023X = 0x400, }; @@ -58,7 +60,6 @@ enum chips { COMET, COMPEX9881, I21145, - X3201_3, }; @@ -137,6 +138,17 @@ enum desc_status_bits { }; +enum t21041_csr13_bits { + csr13_eng = (0xEF0<<4), /* for eng. purposes only, hardcode at EF0h */ + csr13_aui = (1<<3), /* clear to force 10bT, set to force AUI/BNC */ + csr13_cac = (1<<2), /* CSR13/14/15 autoconfiguration */ + csr13_srl = (1<<0), /* When reset, resets all SIA functions, machines */ + + csr13_mask_auibnc = (csr13_eng | csr13_aui | csr13_cac | csr13_srl), + csr13_mask_10bt = (csr13_eng | csr13_cac | csr13_srl), +}; + + /* Keep the ring sizes a power of two for efficiency. Making the Tx ring too large decreases the effectiveness of channel bonding and packet priority. @@ -334,7 +346,14 @@ extern u8 t21040_csr13[]; extern u16 t21041_csr13[]; extern u16 t21041_csr14[]; extern u16 t21041_csr15[]; -void tulip_outl_CSR6 (struct tulip_private *tp, u32 newcsr6); + + +extern inline void tulip_outl_CSR6 (struct tulip_private *tp, u32 newcsr6) +{ + long ioaddr = tp->base_addr; + + outl (newcsr6, ioaddr + CSR6); +} #endif /* __NET_TULIP_H__ */ diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index 6881093ea..196dcf7f6 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -19,7 +19,7 @@ */ -static const char version[] = "Linux Tulip driver version 0.9.4 (Feb 28, 2000)\n"; +static const char version[] = "Linux Tulip driver version 0.9.4.2 (Mar 21, 2000)\n"; #include <linux/module.h> #include "tulip.h" @@ -27,7 +27,6 @@ static const char version[] = "Linux Tulip driver version 0.9.4 (Feb 28, 2000)\n #include <linux/init.h> #include <linux/etherdevice.h> #include <linux/delay.h> -#include <asm/io.h> #include <asm/unaligned.h> @@ -92,9 +91,6 @@ static int csr0 = 0x00A00000 | 0x4800; #define TX_TIMEOUT (4*HZ) -/* Kernel compatibility defines, some common to David Hind's PCMCIA package. - This is only in the support-all-kernels source code. */ - MODULE_AUTHOR("The Linux Kernel Team"); MODULE_DESCRIPTION("Digital 21*4* Tulip ethernet driver"); MODULE_PARM(tulip_debug, "i"); @@ -123,12 +119,13 @@ int tulip_debug = 1; struct tulip_chip_table tulip_tbl[] = { { "Digital DC21040 Tulip", 128, 0x0001ebef, 0, tulip_timer }, - { "Digital DC21041 Tulip", 128, 0x0001ebff, HAS_MEDIA_TABLE, tulip_timer }, + { "Digital DC21041 Tulip", 128, 0x0001ebef, + HAS_MEDIA_TABLE | HAS_NWAY, tulip_timer }, { "Digital DS21140 Tulip", 128, 0x0001ebef, HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, tulip_timer }, { "Digital DS21143 Tulip", 128, 0x0801fbff, - HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY143, - t21142_timer }, + HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY + | HAS_INTR_MITIGATION, t21142_timer }, { "Lite-On 82c168 PNIC", 256, 0x0001ebef, HAS_MII | HAS_PNICNWAY, pnic_timer }, { "Macronix 98713 PMAC", 128, 0x0001ebef, @@ -138,18 +135,15 @@ struct tulip_chip_table tulip_tbl[] = { { "Macronix 98725 PMAC", 256, 0x0001ebef, HAS_MEDIA_TABLE, mxic_timer }, { "ASIX AX88140", 128, 0x0001fbff, - HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | MC_HASH_ONLY, tulip_timer }, + HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | MC_HASH_ONLY | IS_ASIX, tulip_timer }, { "Lite-On PNIC-II", 256, 0x0801fbff, - HAS_MII | HAS_NWAY143 | HAS_8023X, t21142_timer }, + HAS_MII | HAS_NWAY | HAS_8023X, t21142_timer }, { "ADMtek Comet", 256, 0x0001abef, MC_HASH_ONLY, comet_timer }, { "Compex 9881 PMAC", 128, 0x0001ebef, HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer }, { "Intel DS21145 Tulip", 128, 0x0801fbff, - HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_NWAY143, - t21142_timer }, - { "Xircom tulip work-alike", 128, 0x0801fbff, - HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY143, + HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY, t21142_timer }, {0}, }; @@ -163,16 +157,20 @@ static struct pci_device_id tulip_pci_tbl[] __devinitdata = { { 0x11AD, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, LC82C168 }, { 0x10d9, 0x0512, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98713 }, { 0x10d9, 0x0531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98715 }, - { 0x10d9, 0x0531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98725 }, +/* { 0x10d9, 0x0531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98725 },*/ { 0x125B, 0x1400, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AX88140 }, { 0x11AD, 0xc115, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PNIC2 }, { 0x1317, 0x0981, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, + { 0x1317, 0x0985, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, + { 0x1317, 0x1985, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, { 0x11F6, 0x9881, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMPEX9881 }, { 0x8086, 0x0039, PCI_ANY_ID, PCI_ANY_ID, 0, 0, I21145 }, - { 0x115d, 0x0003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, X3201_3 }, + { 0x1282, 0x9100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21140 }, + { 0x1282, 0x9102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21140 }, + { 0x1113, 0x1217, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98715 }, {0}, }; -MODULE_DEVICE_TABLE(pci,tulip_pci_tbl); +MODULE_DEVICE_TABLE(pci, tulip_pci_tbl); /* A full-duplex map for media types. */ @@ -181,7 +179,13 @@ const char tulip_media_cap[] = u8 t21040_csr13[] = {2,0x0C,8,4, 4,0,0,0, 0,0,0,0, 4,0,0,0}; /* 21041 transceiver register settings: 10-T, 10-2, AUI, 10-T, 10T-FD*/ -u16 t21041_csr13[] = { 0xEF01, 0xEF09, 0xEF09, 0xEF01, 0xEF09, }; +u16 t21041_csr13[] = { + csr13_mask_10bt, /* 10-T */ + csr13_mask_auibnc, /* 10-2 */ + csr13_mask_auibnc, /* AUI */ + csr13_mask_10bt, /* 10-T */ + csr13_mask_10bt, /* 10T-FD */ +}; u16 t21041_csr14[] = { 0xFFFF, 0xF7FD, 0xF7FD, 0x7F3F, 0x7F3D, }; u16 t21041_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, }; @@ -198,54 +202,6 @@ static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static void set_rx_mode(struct net_device *dev); -/* The Xircom cards are picky about when certain bits in CSR6 can be - manipulated. Keith Owens <kaos@ocs.com.au>. */ - -void tulip_outl_CSR6 (struct tulip_private *tp, u32 newcsr6) -{ - long ioaddr = tp->base_addr; - const int strict_bits = 0x0060e202; - int csr5, csr5_22_20, csr5_19_17, currcsr6, attempts = 200; - - /* common path */ - if (tp->chip_id != X3201_3) { - outl (newcsr6, ioaddr + CSR6); - return; - } - - newcsr6 &= 0x726cfeca; /* mask out the reserved CSR6 bits that always */ - /* read 0 on the Xircom cards */ - newcsr6 |= 0x320c0000; /* or in the reserved bits that always read 1 */ - currcsr6 = inl (ioaddr + CSR6); - if (((newcsr6 & strict_bits) == (currcsr6 & strict_bits)) || - ((currcsr6 & ~0x2002) == 0)) - goto out_write; - - /* make sure the transmitter and receiver are stopped first */ - currcsr6 &= ~0x2002; - while (1) { - csr5 = inl (ioaddr + CSR5); - if (csr5 == 0xffffffff) - break; /* cannot read csr5, card removed? */ - csr5_22_20 = csr5 & 0x700000; - csr5_19_17 = csr5 & 0x0e0000; - if ((csr5_22_20 == 0 || csr5_22_20 == 0x600000) && - (csr5_19_17 == 0 || csr5_19_17 == 0x80000 || csr5_19_17 == 0xc0000)) - break; /* both are stopped or suspended */ - if (!--attempts) { - printk (KERN_INFO "tulip.c: tulip_outl_CSR6 too many attempts," - "csr5=0x%08x\n", csr5); - goto out_write; - } - outl (currcsr6, ioaddr + CSR6); - udelay (1); - } - -out_write: - /* now it is safe to change csr6 */ - outl (newcsr6, ioaddr + CSR6); -} - static void tulip_up(struct net_device *dev) { @@ -264,11 +220,13 @@ static void tulip_up(struct net_device *dev) /* Reset the chip, holding bit 0 set at least 50 PCI cycles. */ outl(0x00000001, ioaddr + CSR0); + udelay(100); /* Deassert reset. Wait the specified 50 PCI cycles after a reset by initializing Tx and Rx queues and the address filter list. */ outl(tp->csr0, ioaddr + CSR0); + udelay(100); if (tulip_debug > 1) printk(KERN_DEBUG "%s: tulip_up(), irq==%d.\n", dev->name, dev->irq); @@ -561,7 +519,6 @@ static void tulip_tx_timeout(struct net_device *dev) out: dev->trans_start = jiffies; - netif_start_queue (dev); spin_unlock_irqrestore (&tp->lock, flags); } @@ -786,14 +743,14 @@ static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ if (tp->mii_cnt) data[0] = phy; - else if (tp->flags & HAS_NWAY143) + else if (tp->flags & HAS_NWAY) data[0] = 32; else if (tp->chip_id == COMET) data[0] = 1; else return -ENODEV; case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ - if (data[0] == 32 && (tp->flags & HAS_NWAY143)) { + if (data[0] == 32 && (tp->flags & HAS_NWAY)) { int csr12 = inl(ioaddr + CSR12); int csr14 = inl(ioaddr + CSR14); switch (data[1]) { @@ -821,7 +778,7 @@ static int private_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] == 32 && (tp->flags & HAS_NWAY143)) { + if (data[0] == 32 && (tp->flags & HAS_NWAY)) { if (data[1] == 5) tp->to_advertise = data[2]; } else { @@ -1108,9 +1065,13 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, /* Clear the missed-packet counter. */ (volatile int)inl(ioaddr + CSR8); - if (chip_idx == DC21041 && inl(ioaddr + CSR9) & 0x8000) { - printk(" 21040 compatible mode,"); - chip_idx = DC21040; + 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 @@ -1307,7 +1268,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, dev->do_ioctl = private_ioctl; dev->set_multicast_list = set_rx_mode; - if ((tp->flags & HAS_NWAY143) || tp->chip_id == DC21041) + if ((tp->flags & HAS_NWAY) || tp->chip_id == DC21041) tp->link_change = t21142_lnk_change; else if (tp->flags & HAS_PNICNWAY) tp->link_change = pnic_lnk_change; diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index 4c52f055c..a9988e77b 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -27,16 +27,19 @@ LK1.1.1: - Justin Guyett: softnet and locking fixes - Jeff Garzik: use PCI interface - -*/ -static const char *versionA = -"via-rhine.c:v1.01-LK1.1.1 3/2/2000 Written by Donald Becker\n"; -static const char *versionB = -" http://cesdis.gsfc.nasa.gov/linux/drivers/via-rhine.html\n"; + LK1.1.2: + - Urban Widmark: minor cleanups, merges from Becker 1.03a/1.04 versions + + LK1.1.3: + - Urban Widmark: use PCI DMA interface (with thanks to the eepro100.c code) + update "Theory of Operation" with softnet/locking changes + - Dave Miller: PCI DMA and endian fixups + - Jeff Garzik: MOD_xxx race fixes, updated PCI resource allocation +*/ /* A few user-configurable values. These may be modified when a driver - module is loaded.*/ + module is loaded. */ static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ static int max_interrupt_work = 20; @@ -58,6 +61,7 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; The Rhine has a 64 element 8390-like hash table. */ static const int multicast_filter_limit = 32; + /* Operational parameters that are set at compile time. */ /* Keep the ring sizes a power of two for compile efficiency. @@ -68,12 +72,21 @@ static const int multicast_filter_limit = 32; #define TX_RING_SIZE 8 #define RX_RING_SIZE 16 + /* 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.*/ + +#if !defined(__OPTIMIZE__) || !defined(__KERNEL__) +#warning You must compile this file with the correct options! +#warning See the last lines of the source file. +#error See the last lines of the source file for the proper compile-command. +#endif + #include <linux/module.h> #include <linux/kernel.h> #include <linux/string.h> @@ -91,15 +104,20 @@ static const int multicast_filter_limit = 32; #include <asm/bitops.h> #include <asm/io.h> -/* This driver was written to use PCI memory space, however some x86 - motherboards only configure I/O space accesses correctly. */ -#if defined(__i386__) && !defined(VIA_USE_MEMORY) -#define VIA_USE_IO -#endif -#if defined(__alpha__) -#define VIA_USE_IO -#endif -#ifdef VIA_USE_IO +static const char *versionA __devinitdata = +"via-rhine.c:v1.03a-LK1.1.3 3/23/2000 Written by Donald Becker\n"; +static const char *versionB __devinitdata = +" http://cesdis.gsfc.nasa.gov/linux/drivers/via-rhine.html\n"; + + + +/* This driver was written to use PCI memory space, however most versions + of the Rhine only work correctly with I/O space accesses. */ +#if defined(VIA_USE_MEMORY) +#warning Many adapters using the VIA Rhine chip are not configured to work +#warning with PCI memory space accesses. +#else +#define USE_IO #undef readb #undef readw #undef readl @@ -114,9 +132,6 @@ static const int multicast_filter_limit = 32; #define writel outl #endif -/* 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)) MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>"); @@ -186,18 +201,17 @@ IIId. Synchronization The driver runs as two independent, single-threaded flows of control. One is the send-packet routine, which enforces single-threaded use by the -dev->tbusy flag. The other thread is the interrupt handler, which is single -threaded by the hardware and interrupt handling software. +dev->priv->lock spinlock. The other thread is the interrupt handler, which +is single 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 otherwise it sets -the 'lp->tx_full' flag. +The send packet thread has partial control over the Tx ring. It locks the +dev->priv->lock whenever it's queuing a Tx packet. If the next slot in the ring +is not available it stops the transmit queue by calling netif_stop_queue. 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 the 'lp->tx_full' flag is set, it -clears both the tx_full and tbusy flags. +empty by incrementing the dirty_tx mark. If at least half of the entries in +the Rx ring are available the transmit queue is woken up if it was stopped. IV. Notes @@ -231,57 +245,49 @@ enum pci_flags_bit { }; enum via_rhine_chips { - vt86c100a = 0, - vt3043, + VT86C100A = 0, + VT3043, }; struct via_rhine_chip_info { const char *name; - u16 flags; + u16 pci_flags; int io_size; + int drv_flags; }; +enum chip_capability_flags {CanHaveMII=1, }; + +#if defined(VIA_USE_MEMORY) +#define RHINE_IOTYPE (PCI_USES_MEM | PCI_USES_MASTER | PCI_ADDR1) +#else +#define RHINE_IOTYPE (PCI_USES_IO | PCI_USES_MASTER | PCI_ADDR0) +#endif + /* directly indexed by enum via_rhine_chips, above */ static struct via_rhine_chip_info via_rhine_chip_info[] __devinitdata = { - {"VIA VT86C100A Rhine-II", - PCI_USES_MEM | PCI_USES_IO | PCI_USES_MEM | PCI_USES_MASTER, - 128,}, - {"VIA VT3043 Rhine", - PCI_USES_IO | PCI_USES_MEM | PCI_USES_MASTER, - 128,}, + { "VIA VT86C100A Rhine-II", RHINE_IOTYPE, 128, CanHaveMII }, + { "VIA VT3043 Rhine", RHINE_IOTYPE, 128, CanHaveMII } }; static struct pci_device_id via_rhine_pci_tbl[] __devinitdata = { - {0x1106, 0x6100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt86c100a}, - {0x1106, 0x3043, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt3043}, + {0x1106, 0x6100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT86C100A}, + {0x1106, 0x3043, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT3043}, {0,}, /* terminate list */ }; MODULE_DEVICE_TABLE(pci, via_rhine_pci_tbl); - -/* A chip capabilities table, matching the entries in pci_tbl[] above. */ -enum chip_capability_flags {CanHaveMII=1, }; -struct chip_info { - int io_size; - int flags; -} static cap_tbl[] = { - {128, CanHaveMII, }, - {128, CanHaveMII, }, -}; - - -/* Offsets to the device registers. -*/ +/* Offsets to the device registers. */ enum register_offsets { StationAddr=0x00, RxConfig=0x06, TxConfig=0x07, ChipCmd=0x08, IntrStatus=0x0C, IntrEnable=0x0E, MulticastFilter0=0x10, MulticastFilter1=0x14, RxRingPtr=0x18, TxRingPtr=0x1C, - MIIPhyAddr=0x6C, MIIStatus=0x6D, PCIConfig=0x6E, + MIIPhyAddr=0x6C, MIIStatus=0x6D, PCIBusConfig=0x6E, MIICmd=0x70, MIIRegAddr=0x71, MIIData=0x72, Config=0x78, RxMissed=0x7C, RxCRCErrs=0x7E, }; @@ -295,21 +301,19 @@ enum intr_status_bits { IntrRxOverflow=0x0400, IntrRxDropped=0x0800, IntrRxNoBuf=0x1000, IntrTxAborted=0x2000, IntrLinkChange=0x4000, IntrRxWakeUp=0x8000, - IntrNormalSummary=0x0003, IntrAbnormalSummary=0x8260, + IntrNormalSummary=0x0003, IntrAbnormalSummary=0xC260, }; /* The Rx and Tx buffer descriptors. */ struct rx_desc { - u16 rx_status; - u16 rx_length; + s32 rx_status; u32 desc_length; u32 addr; u32 next_desc; }; struct tx_desc { - u16 tx_status; - u16 tx_own; + s32 tx_status; u32 desc_length; u32 addr; u32 next_desc; @@ -317,9 +321,11 @@ struct tx_desc { /* Bits in *_desc.status */ enum rx_status_bits { - RxDescOwn=0x80000000, RxOK=0x8000, RxWholePkt=0x0300, RxErr=0x008F}; + RxOK=0x8000, RxWholePkt=0x0300, RxErr=0x008F +}; + enum desc_status_bits { - DescOwn=0x8000, DescEndPacket=0x4000, DescIntr=0x1000, + DescOwn=0x80000000, DescEndPacket=0x4000, DescIntr=0x1000, }; /* Bits in ChipCmd. */ @@ -331,32 +337,42 @@ enum chip_cmd_bits { }; struct netdev_private { - /* Descriptor rings first for alignment. */ - struct rx_desc rx_ring[RX_RING_SIZE]; - struct tx_desc tx_ring[TX_RING_SIZE]; + /* Descriptor rings */ + struct rx_desc *rx_ring; + struct tx_desc *tx_ring; + dma_addr_t rx_ring_dma; + dma_addr_t tx_ring_dma; + /* The addresses of receive-in-place skbuffs. */ - struct sk_buff* rx_skbuff[RX_RING_SIZE]; + struct sk_buff *rx_skbuff[RX_RING_SIZE]; + dma_addr_t rx_skbuff_dma[RX_RING_SIZE]; + /* The saved address of a sent-in-place packet/buffer, for later free(). */ - struct sk_buff* tx_skbuff[TX_RING_SIZE]; + struct sk_buff *tx_skbuff[TX_RING_SIZE]; + dma_addr_t tx_skbuff_dma[TX_RING_SIZE]; unsigned char *tx_buf[TX_RING_SIZE]; /* Tx bounce buffers */ - unsigned char *tx_bufs; /* Tx bounce buffer region. */ + + struct pci_dev *pdev; struct net_device_stats stats; struct timer_list timer; /* Media monitoring timer. */ spinlock_t lock; + /* Frequently used values: keep some adjacent for cache effect. */ int chip_id; struct rx_desc *rx_head_desc; - unsigned short int cur_rx, dirty_rx; /* Producer/consumer ring indices */ - unsigned short int cur_tx, dirty_tx; + unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ + unsigned int cur_tx, dirty_tx; unsigned int rx_buf_sz; /* Based on MTU+slack. */ u16 chip_cmd; /* Current setting for ChipCmd */ unsigned int tx_full:1; /* The Tx queue is full. */ + /* These values are keep track of the transceiver/media in use. */ unsigned int full_duplex:1; /* Full-duplex operation requested. */ unsigned int duplex_lock:1; unsigned int medialock:1; /* Do not sense media. */ unsigned int default_port:4; /* Last dev->if_port value. */ u8 tx_thresh, rx_thresh; + /* MII transceiver section. */ int mii_cnt; /* MII device addresses. */ u16 advertising; /* NWay media advertisement */ @@ -393,6 +409,9 @@ static int __devinit via_rhine_init_one (struct pci_dev *pdev, 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++) { @@ -403,44 +422,67 @@ static int __devinit via_rhine_init_one (struct pci_dev *pdev, card_idx++; option = card_idx < MAX_UNITS ? options[card_idx] : 0; io_size = via_rhine_chip_info[chip_id].io_size; + pci_flags = via_rhine_chip_info[chip_id].pci_flags; + + /* this should always be supported */ + if (!pci_dma_supported(pdev, 0xffffffff)) { + printk(KERN_ERR "32-bit PCI DMA addresses not supported by the card!?\n"); + goto err_out; + } + + /* sanity check */ + if ((pci_resource_len (pdev, 0) < io_size) || + (pci_resource_len (pdev, 1) < io_size)) { + printk (KERN_ERR "Insufficient PCI resources, aborting\n"); + 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; + } -#ifdef VIA_USE_IO - ioaddr = pci_resource_start (pdev, 0); -#else - ioaddr = pci_resource_start (pdev, 1); -#endif + ioaddr = pci_resource_start (pdev, pci_flags & PCI_ADDR0 ? 0 : 1); if (pci_enable_device (pdev)) { printk (KERN_ERR "unable to init PCI device (card #%d)\n", card_idx); - goto err_out; + goto err_out_free_dma; } - if (via_rhine_chip_info[chip_id].flags & PCI_USES_MASTER) + if (pci_flags & PCI_USES_MASTER) pci_set_master (pdev); dev = init_etherdev(NULL, sizeof(*np)); if (dev == NULL) { printk (KERN_ERR "init_ethernet failed for card #%d\n", card_idx); - goto err_out; + goto err_out_free_dma; } - if (!request_region(pci_resource_start (pdev, 0), io_size, dev->name)) { + /* 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)); goto err_out_free_netdev; } - if (!request_mem_region(pci_resource_start (pdev, 1), io_size, dev->name)) { + 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 VIA_USE_IO +#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", @@ -469,6 +511,11 @@ static int __devinit via_rhine_init_one (struct pci_dev *pdev, np = dev->priv; spin_lock_init (&np->lock); np->chip_id = chip_id; + 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; @@ -499,7 +546,7 @@ static int __devinit via_rhine_init_one (struct pci_dev *pdev, pdev->driver_data = dev; - if (cap_tbl[np->chip_id].flags & CanHaveMII) { + if (via_rhine_chip_info[chip_id].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++) { @@ -518,18 +565,25 @@ static int __devinit via_rhine_init_one (struct pci_dev *pdev, return 0; -#ifndef VIA_USE_IO +#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), io_size, dev->name)); + release_mem_region(pci_resource_start (pdev, 1), + pci_resource_len (pdev, 1)); #endif err_out_free_pio: - release_region(pci_resource_start (pdev, 0), io_size); + release_region(pci_resource_start (pdev, 0), + pci_resource_len (pdev, 0)); err_out_free_netdev: unregister_netdev (dev); kfree (dev); +err_out_free_dma: + pci_free_consistent(pdev, + RX_RING_SIZE * sizeof(struct rx_desc) + + TX_RING_SIZE * sizeof(struct tx_desc), + ring, ring_dma); err_out: return -ENODEV; } @@ -557,9 +611,12 @@ 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; long ioaddr = dev->base_addr; int boguscnt = 1024; + if (phy_id == np->phys[0] && regnum == 4) + np->advertising = value; /* Wait for a previous command to complete. */ while ((readb(ioaddr + MIICmd) & 0x60) && --boguscnt > 0) ; @@ -578,32 +635,34 @@ static int via_rhine_open(struct net_device *dev) long ioaddr = dev->base_addr; int i; + MOD_INC_USE_COUNT; + /* Reset the chip. */ writew(CmdReset, ioaddr + ChipCmd); - if (request_irq(dev->irq, &via_rhine_interrupt, SA_SHIRQ, dev->name, dev)) - return -EAGAIN; + if (request_irq(dev->irq, &via_rhine_interrupt, SA_SHIRQ, dev->name, dev)) { + MOD_DEC_USE_COUNT; + return -EBUSY; + } if (debug > 1) printk(KERN_DEBUG "%s: via_rhine_open() irq %d.\n", dev->name, dev->irq); - MOD_INC_USE_COUNT; - via_rhine_init_ring(dev); - writel(virt_to_bus(np->rx_ring), ioaddr + RxRingPtr); - writel(virt_to_bus(np->tx_ring), ioaddr + TxRingPtr); + 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 + PCIConfig); /* Tune configuration??? */ + 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(). */ + np->rx_thresh = 0x60; /* Written in via_rhine_set_rx_mode(). */ if (dev->if_port == 0) dev->if_port = np->default_port; @@ -666,6 +725,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; @@ -677,12 +737,14 @@ static void via_rhine_timer(unsigned long data) printk(KERN_DEBUG "%s: VIA Rhine monitor tick, status %4.4x.\n", dev->name, readw(ioaddr + IntrStatus)); } + via_rhine_check_duplex(dev); np->timer.expires = RUN_AT(next_tick); add_timer(&np->timer); } + static void via_rhine_tx_timeout (struct net_device *dev) { struct netdev_private *np = (struct netdev_private *) dev->priv; @@ -693,16 +755,17 @@ static void via_rhine_tx_timeout (struct net_device *dev) dev->name, readw (ioaddr + IntrStatus), mdio_read (dev, np->phys[0], 1)); - /* Perhaps we should reinitialize the hardware here. */ + /* 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 */ dev->trans_start = jiffies; np->stats.tx_errors++; - - netif_start_queue (dev); } @@ -720,13 +783,13 @@ static void via_rhine_init_ring(struct net_device *dev) for (i = 0; i < RX_RING_SIZE; i++) { np->rx_ring[i].rx_status = 0; - np->rx_ring[i].rx_length = 0; - np->rx_ring[i].desc_length = np->rx_buf_sz; - np->rx_ring[i].next_desc = virt_to_bus(&np->rx_ring[i+1]); + np->rx_ring[i].desc_length = cpu_to_le32(np->rx_buf_sz); + np->rx_ring[i].next_desc = + cpu_to_le32(np->rx_ring_dma + sizeof(struct rx_desc)*(i+1)); np->rx_skbuff[i] = 0; } /* Mark the last entry as wrapping the ring. */ - np->rx_ring[i-1].next_desc = virt_to_bus(&np->rx_ring[0]); + np->rx_ring[i-1].next_desc = cpu_to_le32(np->rx_ring_dma); /* Fill in the Rx buffers. */ for (i = 0; i < RX_RING_SIZE; i++) { @@ -734,20 +797,25 @@ static void via_rhine_init_ring(struct net_device *dev) np->rx_skbuff[i] = skb; if (skb == NULL) break; - skb->dev = dev; /* Mark as being used by this device. */ - np->rx_ring[i].addr = virt_to_bus(skb->tail); - np->rx_ring[i].rx_status = 0; - np->rx_ring[i].rx_length = DescOwn; + 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); } for (i = 0; i < TX_RING_SIZE; i++) { np->tx_skbuff[i] = 0; - np->tx_ring[i].tx_own = 0; - np->tx_ring[i].desc_length = 0x00e08000; - np->tx_ring[i].next_desc = virt_to_bus(&np->tx_ring[i+1]); + np->tx_ring[i].tx_status = 0; + np->tx_ring[i].desc_length = cpu_to_le32(0x00e08000); + np->tx_ring[i].next_desc = + cpu_to_le32(np->tx_ring_dma + sizeof(struct tx_desc)*(i+1)); np->tx_buf[i] = kmalloc(PKT_BUF_SZ, GFP_KERNEL); } - np->tx_ring[i-1].next_desc = virt_to_bus(&np->tx_ring[0]); + np->tx_ring[i-1].next_desc = cpu_to_le32(np->tx_ring_dma); return; } @@ -771,16 +839,24 @@ static int via_rhine_start_tx(struct sk_buff *skb, struct net_device *dev) if ((long)skb->data & 3) { /* Must use alignment buffer. */ if (np->tx_buf[entry] == NULL && - (np->tx_buf[entry] = kmalloc(PKT_BUF_SZ, GFP_KERNEL)) == NULL) + (np->tx_buf[entry] = kmalloc(PKT_BUF_SZ, GFP_KERNEL)) == NULL) { + spin_unlock_irqrestore (&np->lock, flags); return 1; + } memcpy(np->tx_buf[entry], skb->data, skb->len); - np->tx_ring[entry].addr = virt_to_bus(np->tx_buf[entry]); - } else - np->tx_ring[entry].addr = virt_to_bus(skb->data); + np->tx_skbuff_dma[entry] = + pci_map_single(np->pdev, np->tx_buf[entry], skb->len, + PCI_DMA_TODEVICE); + } else { + np->tx_skbuff_dma[entry] = + pci_map_single(np->pdev, skb->data, skb->len, + PCI_DMA_TODEVICE); + } + np->tx_ring[entry].addr = cpu_to_le32(np->tx_skbuff_dma[entry]); - np->tx_ring[entry].desc_length = 0x00E08000 | - (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN); - np->tx_ring[entry].tx_own = DescOwn; + np->tx_ring[entry].desc_length = + cpu_to_le32(0x00E08000 | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN)); + np->tx_ring[entry].tx_status = cpu_to_le32(DescOwn); np->cur_tx++; @@ -848,7 +924,7 @@ static void via_rhine_interrupt(int irq, void *dev_instance, struct pt_regs *rgs } /* This routine is logically part of the interrupt handler, but isolated - for clarity and better register allocation. */ + for clarity. */ static void via_rhine_tx(struct net_device *dev) { struct netdev_private *np = (struct netdev_private *)dev->priv; @@ -858,15 +934,15 @@ static void via_rhine_tx(struct net_device *dev) /* if tx_full is set, they're all dirty, not clean */ while (np->dirty_tx != np->cur_tx) { - if (np->tx_ring[entry].tx_own) /* transmit request pending */ + txstatus = le32_to_cpu(np->tx_ring[entry].tx_status); + if (txstatus & DescOwn) break; - txstatus = np->tx_ring[entry].tx_status; if (debug > 6) - printk(KERN_DEBUG " Tx scavenge %d status %4.4x.\n", + printk(KERN_DEBUG " Tx scavenge %d status %8.8x.\n", entry, txstatus); if (txstatus & 0x8000) { if (debug > 1) - printk(KERN_DEBUG "%s: Transmit error, Tx status %4.4x.\n", + printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n", dev->name, txstatus); np->stats.tx_errors++; if (txstatus & 0x0400) np->stats.tx_carrier_errors++; @@ -877,12 +953,15 @@ static void via_rhine_tx(struct net_device *dev) /* Transmitter restarted in 'abnormal' handler. */ } else { np->stats.collisions += (txstatus >> 3) & 15; - np->stats.tx_bytes += np->tx_ring[entry].desc_length & 0x7ff; + np->stats.tx_bytes += le32_to_cpu(np->tx_ring[entry].desc_length) & 0x7ff; np->stats.tx_packets++; - } - /* Free the original skb. */ - dev_kfree_skb_irq(np->tx_skbuff[entry]); - np->tx_skbuff[entry] = NULL; + } + /* Free the original skb. */ + pci_unmap_single(np->pdev, + le32_to_cpu(np->tx_ring[entry].addr), + np->tx_skbuff[entry]->len, PCI_DMA_TODEVICE); + dev_kfree_skb_irq(np->tx_skbuff[entry]); + np->tx_skbuff[entry] = NULL; entry = (++np->dirty_tx) % TX_RING_SIZE; } if ((np->cur_tx - np->dirty_tx) <= TX_RING_SIZE/2) @@ -896,33 +975,32 @@ static void via_rhine_tx(struct net_device *dev) static void via_rhine_rx(struct net_device *dev) { struct netdev_private *np = (struct netdev_private *)dev->priv; - int entry = (np->dirty_rx = np->cur_rx) % RX_RING_SIZE; - int boguscnt = RX_RING_SIZE; + int entry = np->cur_rx % RX_RING_SIZE; + int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx; if (debug > 4) { - printk(KERN_DEBUG " In via_rhine_rx(), entry %d status %4.4x.\n", - entry, np->rx_head_desc->rx_length); + printk(KERN_DEBUG " In via_rhine_rx(), entry %d status %8.8x.\n", + entry, le32_to_cpu(np->rx_head_desc->rx_status)); } /* If EOP is set on the next entry, it's a new packet. Send it up. */ - while ( ! (np->rx_head_desc->rx_length & DescOwn)) { + while ( ! (np->rx_head_desc->rx_status & cpu_to_le32(DescOwn))) { struct rx_desc *desc = np->rx_head_desc; - int data_size = desc->rx_length; - u16 desc_status = desc->rx_status; + u32 desc_status = le32_to_cpu(desc->rx_status); + int data_size = desc_status >> 16; if (debug > 4) - printk(KERN_DEBUG " via_rhine_rx() status is %4.4x.\n", + printk(KERN_DEBUG " via_rhine_rx() status is %8.8x.\n", desc_status); if (--boguscnt < 0) break; if ( (desc_status & (RxWholePkt | RxErr)) != RxWholePkt) { if ((desc_status & RxWholePkt) != RxWholePkt) { printk(KERN_WARNING "%s: Oversized Ethernet frame spanned " - "multiple buffers, entry %#x length %d status %4.4x!\n", + "multiple buffers, entry %#x length %d status %8.8x!\n", dev->name, entry, data_size, desc_status); printk(KERN_WARNING "%s: Oversized Ethernet frame %p vs %p.\n", - dev->name, np->rx_head_desc, - &np->rx_ring[entry]); + dev->name, np->rx_head_desc, &np->rx_ring[entry]); np->stats.rx_length_errors++; } else if (desc_status & RxErr) { /* There was a error. */ @@ -942,25 +1020,35 @@ static void via_rhine_rx(struct net_device *dev) /* Check if the packet is long enough to accept without copying to a minimally-sized skbuff. */ - if (pkt_len < rx_copybreak - && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { + if (pkt_len < rx_copybreak && + (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_skbuff_dma[entry], + np->rx_buf_sz, PCI_DMA_FROMDEVICE); #if ! defined(__alpha__) || USE_IP_COPYSUM /* Avoid misaligned on Alpha */ - eth_copy_and_sum(skb, bus_to_virt(desc->addr), - pkt_len, 0); + eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0); skb_put(skb, pkt_len); #else - memcpy(skb_put(skb,pkt_len), bus_to_virt(desc->addr), pkt_len); + memcpy(skb_put(skb, pkt_len), np->rx_skbuff[entry]->tail, + pkt_len); #endif } else { - skb_put(skb = np->rx_skbuff[entry], pkt_len); + skb = np->rx_skbuff[entry]; + if (skb == NULL) { + printk(KERN_ERR "%s: Inconsistent Rx descriptor chain.\n", + dev->name); + break; + } np->rx_skbuff[entry] = NULL; + skb_put(skb, pkt_len); + pci_unmap_single(np->pdev, np->rx_skbuff_dma[entry], + np->rx_buf_sz, PCI_DMA_FROMDEVICE); } skb->protocol = eth_type_trans(skb, dev); - np->stats.rx_bytes+=skb->len; netif_rx(skb); dev->last_rx = jiffies; + np->stats.rx_bytes += skb->len; np->stats.rx_packets++; } entry = (++np->cur_rx) % RX_RING_SIZE; @@ -968,19 +1056,21 @@ static void via_rhine_rx(struct net_device *dev) } /* Refill the Rx ring buffers. */ - while (np->dirty_rx != np->cur_rx) { + for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) { struct sk_buff *skb; - entry = np->dirty_rx++ % RX_RING_SIZE; + entry = np->dirty_rx % RX_RING_SIZE; if (np->rx_skbuff[entry] == NULL) { skb = dev_alloc_skb(np->rx_buf_sz); np->rx_skbuff[entry] = skb; if (skb == NULL) break; /* Better luck next round. */ skb->dev = dev; /* Mark as being used by this device. */ - np->rx_ring[entry].addr = virt_to_bus(skb->tail); + np->rx_skbuff_dma[entry] = + pci_map_single(np->pdev, skb->tail, np->rx_buf_sz, + PCI_DMA_FROMDEVICE); + np->rx_ring[entry].addr = cpu_to_le32(np->rx_skbuff_dma[entry]); } - np->rx_ring[entry].rx_status = 0; - np->rx_ring[entry].rx_length = DescOwn; + np->rx_ring[entry].rx_status = cpu_to_le32(DescOwn); } /* Pre-emptively restart Rx engine. */ @@ -1020,7 +1110,8 @@ static void via_rhine_error(struct net_device *dev, int intr_status) printk(KERN_INFO "%s: Transmitter underrun, increasing Tx " "threshold setting to %2.2x.\n", dev->name, np->tx_thresh); } - if ((intr_status & ~(IntrLinkChange|IntrStatsMax|IntrTxAbort)) && debug > 1) { + if ((intr_status & ~( IntrLinkChange | IntrStatsMax | + IntrTxAbort | IntrTxAborted)) && debug > 1) { printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n", dev->name, intr_status); /* Recovery for other fault sources not known. */ @@ -1076,6 +1167,8 @@ static void via_rhine_set_rx_mode(struct net_device *dev) } else if ((dev->mc_count > multicast_filter_limit) || (dev->flags & IFF_ALLMULTI)) { /* Too many to match, or accept all multicasts. */ + writel(0xffffffff, ioaddr + MulticastFilter0); + writel(0xffffffff, ioaddr + MulticastFilter1); rx_mode = 0x0C; } else { struct dev_mc_list *mclist; @@ -1083,12 +1176,11 @@ static void via_rhine_set_rx_mode(struct net_device *dev) memset(mc_filter, 0, sizeof(mc_filter)); 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); + set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26, mc_filter); } writel(mc_filter[0], ioaddr + MulticastFilter0); writel(mc_filter[1], ioaddr + MulticastFilter1); - rx_mode = 0x08; + rx_mode = 0x0C; } writeb(np->rx_thresh | rx_mode, ioaddr + RxConfig); } @@ -1138,13 +1230,17 @@ static int via_rhine_close(struct net_device *dev) /* Free all the skbuffs in the Rx queue. */ for (i = 0; i < RX_RING_SIZE; i++) { - np->rx_ring[i].rx_length = 0; - np->rx_ring[i].addr = 0xBADF00D0; /* An invalid address. */ + 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; } + for (i = 0; i < TX_RING_SIZE; i++) { if (np->tx_skbuff[i]) dev_kfree_skb(np->tx_skbuff[i]); @@ -1165,14 +1261,19 @@ static void __devexit via_rhine_remove_one (struct pci_dev *pdev) unregister_netdev(dev); release_region(pci_resource_start (pdev, 0), - via_rhine_chip_info[np->chip_id].io_size); + pci_resource_len (pdev, 0)); release_mem_region(pci_resource_start (pdev, 1), - via_rhine_chip_info[np->chip_id].io_size); + pci_resource_len (pdev, 1)); -#ifndef VIA_USE_IO +#ifndef USE_IO iounmap((char *)(dev->base_addr)); #endif + pci_free_consistent(pdev, + RX_RING_SIZE * sizeof(struct rx_desc) + + TX_RING_SIZE * sizeof(struct tx_desc), + np->rx_ring, np->rx_ring_dma); + kfree(dev); } @@ -1187,7 +1288,15 @@ static struct pci_driver via_rhine_driver = { static int __init via_rhine_init (void) { - return pci_module_init (&via_rhine_driver); + int rc; + + MOD_INC_USE_COUNT; + + rc = pci_module_init (&via_rhine_driver); + + MOD_DEC_USE_COUNT; + + return rc; } diff --git a/drivers/net/wan/Config.in b/drivers/net/wan/Config.in index e0a6f5e8f..4ffe0730f 100644 --- a/drivers/net/wan/Config.in +++ b/drivers/net/wan/Config.in @@ -55,9 +55,11 @@ if [ "$CONFIG_WAN" = "y" ]; then if [ "$CONFIG_VENDOR_SANGOMA" != "n" ]; then int ' Maximum number of cards' CONFIG_WANPIPE_CARDS 1 bool ' WANPIPE Cisco HDLC support' CONFIG_WANPIPE_CHDLC - bool ' WANPIPE Frame Relay support' CONFIG_WANPIPE_FR + if [ "$CONFIG_OBSOLETE" = "y" ]; then + bool ' WANPIPE Frame Relay support' CONFIG_WANPIPE_FR + bool ' WANPIPE X.25 support' CONFIG_WANPIPE_X25 + fi bool ' WANPIPE PPP support' CONFIG_WANPIPE_PPP - bool ' WANPIPE X.25 support' CONFIG_WANPIPE_X25 fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then dep_tristate ' Cyclom 2X(tm) cards (EXPERIMENTAL)' CONFIG_CYCLADES_SYNC $CONFIG_WAN_ROUTER_DRIVERS |