bk://gkernel.bkbits.net/netdev-2.6 jgarzik@redhat.com|ChangeSet|20040504205405|50491 jgarzik # This is a BitKeeper generated diff -Nru style patch. # # ChangeSet # 2004/05/04 16:50:21-04:00 jgarzik@redhat.com # [netdrvr b44] use miilib for MII ioctl handling # # drivers/net/b44.h # 2004/05/04 16:50:16-04:00 jgarzik@redhat.com +2 -0 # [netdrvr b44] use miilib for MII ioctl handling # # drivers/net/b44.c # 2004/05/04 16:50:16-04:00 jgarzik@redhat.com +34 -31 # [netdrvr b44] use miilib for MII ioctl handling # # ChangeSet # 2004/05/04 16:36:29-04:00 jgarzik@redhat.com # [netdrvr b44] use netdev_priv # # drivers/net/b44.c # 2004/05/04 16:36:24-04:00 jgarzik@redhat.com +16 -14 # [netdrvr b44] use netdev_priv # # ChangeSet # 2004/05/04 16:33:55-04:00 jgarzik@redhat.com # [netdrvr b44] ethtool_ops support # # drivers/net/b44.c # 2004/05/04 16:33:50-04:00 jgarzik@redhat.com +195 -210 # [netdrvr b44] ethtool_ops support # # ChangeSet # 2004/04/21 23:30:47-04:00 romieu@fr.zoreil.com # [PATCH] epic100: code removal in irq handler # # The loop in the irq handler is not needed any more as the high frequency # events have been deferred due to napi usage. # # drivers/net/epic100.c # 2004/04/19 18:37:16-04:00 romieu@fr.zoreil.com +52 -64 # 2.6.6-rc1-mm1 - code removal in the epic100 irq handler # # ChangeSet # 2004/04/21 23:30:40-04:00 romieu@fr.zoreil.com # [PATCH] epic100: spin_unlock_irqrestore avoidance # # This patch avoids to duplicate a spin_unlock: # - it is mostly an artifact due to wild goto; # - it makes the generated code smaller. # # drivers/net/epic100.c # 2004/04/19 18:37:05-04:00 romieu@fr.zoreil.com +16 -10 # 2.6.6-rc1-mm1 - spin_unlock_irqrestore avoidance in epic100 # # ChangeSet # 2004/04/21 21:34:03-04:00 pavel@ucw.cz # [PATCH] Cleanups for b44 # # Hi! # # During some unrelated work I was confused by b44_init_hw. Its return # is checked in _open() but nowhere else. I started adding missing # checks, but then I found why its so: it only ever returns 0. # # So this turns it into void. Killed #if 0-ed piece of code and fixed # indentation at one point. Please apply, # Pavel # # drivers/net/b44.c # 2004/04/20 19:24:14-04:00 pavel@ucw.cz +4 -13 # Cleanups for b44 # # ChangeSet # 2004/04/21 20:53:56-04:00 brazilnut@us.ibm.com # [PATCH] pcnet32 timer to free tx skbs for 79C971/972 # # At the next opportunity to add new code to 2.6.6, please apply the following: # # This patch uses an on-chip timer to free completed transmit skb's for the # 79C971 and 972 versions which currently will leave completed transmit # skb's on the transmit ring until new transmit traffic occurs. # # drivers/net/pcnet32.c # 2004/04/20 11:48:49-04:00 brazilnut@us.ibm.com +43 -8 # pcnet32 timer to free tx skbs for 79C971/972 # # ChangeSet # 2004/04/21 20:53:46-04:00 brazilnut@us.ibm.com # [PATCH] pcnet32 add register dump capability # # At the next opportunity to add new code to 2.6.6, please apply the following # patch to include the capability to dump chip registers. Ethtool -d support. # # drivers/net/pcnet32.c # 2004/04/20 11:43:34-04:00 brazilnut@us.ibm.com +76 -3 # pcnet32 add register dump capability # # ChangeSet # 2004/04/21 20:40:33-04:00 vda@port.imtp.ilyichevsk.odessa.ua # [PATCH] fealnx #11: cleanup and coding style # # drivers/net/fealnx.c # 2004/04/05 15:54:35-04:00 vda@port.imtp.ilyichevsk.odessa.ua +22 -26 # 2.6 fealnx.c #11: cleanup and coding style # # ChangeSet # 2004/04/21 20:40:25-04:00 vda@port.imtp.ilyichevsk.odessa.ua # [PATCH] fealnx #10: replace local delay functions with udelay # # drivers/net/fealnx.c # 2004/04/05 15:54:32-04:00 vda@port.imtp.ilyichevsk.odessa.ua +6 -43 # 2.6 fealnx.c #10: replace local delay functions with udelay # # ChangeSet # 2004/04/21 20:40:18-04:00 vda@port.imtp.ilyichevsk.odessa.ua # [PATCH] fealnx #9: fix locking for set_rx_mode # # drivers/net/fealnx.c # 2004/04/05 15:54:30-04:00 vda@port.imtp.ilyichevsk.odessa.ua +16 -2 # 2.6 fealnx.c #9: fix locking for set_rx_mode # # ChangeSet # 2004/04/21 20:40:10-04:00 vda@port.imtp.ilyichevsk.odessa.ua # [PATCH] fealnx #8: rework error handling # # Add reset timer, fire it 1/2 sec after 'Too much work in interrupt' # Move reset code from tx_timeout into two separate routines: # reset_and_disable_rxtx() and enable_rxtx() # New function reset_tx_descriptors(): clean up tx ring # after tx_timeout. tx_timeout now does: # reset_and_disable_rxtx() # reset_tx_descriptors() # enable_rxtx() # netif_wake_queue() # Absense of netif_wake_queue() call was probably the cause of # tx_timeout() stalling all future tx. # Remove stop_nic_tx(), not used anymore # # drivers/net/fealnx.c # 2004/04/05 15:54:59-04:00 vda@port.imtp.ilyichevsk.odessa.ua +142 -41 # 2.6 fealnx.c #8: rework error handling # # ChangeSet # 2004/04/21 20:40:03-04:00 vda@port.imtp.ilyichevsk.odessa.ua # [PATCH] fealnx #7: Garzik fix (IIRC): add locking to tx_timeout # # drivers/net/fealnx.c # 2004/04/05 15:54:55-04:00 vda@port.imtp.ilyichevsk.odessa.ua +8 -3 # 2.6 fealnx.c #7: Garzik fix (IIRC): add locking to tx_timeout # # ChangeSet # 2004/04/21 20:39:55-04:00 vda@port.imtp.ilyichevsk.odessa.ua # [PATCH] fealnx #6: Francois' fixes for low memory handling; remove free_one_rx_descriptor (not used anymore) # # drivers/net/fealnx.c # 2004/04/05 15:54:52-04:00 vda@port.imtp.ilyichevsk.odessa.ua +26 -47 # 2.6 fealnx.c #6: Francois' fixes for low memory handling; remove free_one_rx_descriptor (not used anymore) # # ChangeSet # 2004/04/21 20:39:48-04:00 vda@port.imtp.ilyichevsk.odessa.ua # [PATCH] fealnx #5: introduce stop_nic_rxtx(), use it where makes sense # # drivers/net/fealnx.c # 2004/04/05 14:16:24-04:00 vda@port.imtp.ilyichevsk.odessa.ua +15 -6 # 2.6 fealnx.c #5: introduce stop_nic_rxtx(), use it where makes sense # # ChangeSet # 2004/04/21 20:39:40-04:00 vda@port.imtp.ilyichevsk.odessa.ua # [PATCH] fealnx #4: stop doing stop_nic_rx/writel(np->crvalue) in reset_rx_descriptors # # this can inadvertently (re)enable tx and/or rx. # # drivers/net/fealnx.c # 2004/04/05 11:16:51-04:00 vda@port.imtp.ilyichevsk.odessa.ua +8 -4 # 2.6 fealnx.c #4: stop doing stop_nic_rx/writel(np->crvalue) in reset_rx_descriptors # # ChangeSet # 2004/04/21 20:39:33-04:00 vda@port.imtp.ilyichevsk.odessa.ua # [PATCH] fealnx #3: fix pointer substraction bug # # drivers/net/fealnx.c # 2004/04/05 11:08:07-04:00 vda@port.imtp.ilyichevsk.odessa.ua +5 -5 # 2.6 fealnx.c #3: fix pointer substraction bug # # ChangeSet # 2004/04/21 20:39:25-04:00 vda@port.imtp.ilyichevsk.odessa.ua # [PATCH] fealnx #2: add 'static'; fix wrapped comment # # drivers/net/fealnx.c # 2004/04/05 11:01:53-04:00 vda@port.imtp.ilyichevsk.odessa.ua +6 -9 # 2.6 fealnx.c #2: add 'static'; fix wrapped comment # # ChangeSet # 2004/04/21 20:39:18-04:00 vda@port.imtp.ilyichevsk.odessa.ua # [PATCH] fealnx #1: replace magic constants with enums # # drivers/net/fealnx.c # 2004/04/05 10:58:48-04:00 vda@port.imtp.ilyichevsk.odessa.ua +42 -33 # 2.6 fealnx.c #1: replace magic constants with enums # # ChangeSet # 2004/04/21 20:39:10-04:00 vda@port.imtp.ilyichevsk.odessa.ua # [PATCH] fealnx #0: replace dev->base_addr with ioaddr # # drivers/net/fealnx.c # 2004/04/05 10:23:40-04:00 vda@port.imtp.ilyichevsk.odessa.ua +8 -10 # 2.6 fealnx.c #0: replace dev->base_addr with ioaddr # # ChangeSet # 2004/04/21 08:29:19-04:00 jgarzik@redhat.com # Merge redhat.com:/spare/repo/netdev-2.6/8139too # into redhat.com:/spare/repo/netdev-2.6/ALL # # drivers/net/8139too.c # 2004/04/21 08:29:16-04:00 jgarzik@redhat.com +0 -0 # Auto merged # # ChangeSet # 2004/04/21 08:24:06-04:00 jgarzik@redhat.com # [netdrvr e1000] Eliminate code duplicating ethtool_op_xxx helpers # # drivers/net/e1000/e1000_ethtool.c # 2004/04/21 08:24:01-04:00 jgarzik@redhat.com +4 -33 # [netdrvr e1000] Eliminate code duplicating ethtool_op_xxx helpers # # ChangeSet # 2004/04/21 08:19:08-04:00 jgarzik@redhat.com # Manual merge of e1000 upstream changes. # # drivers/net/e1000/e1000_ethtool.c # 2004/04/21 08:19:04-04:00 jgarzik@redhat.com +0 -3 # Manual merge of e1000 upstream changes. # # ChangeSet # 2004/04/19 12:33:23-04:00 shemminger@osdl.org # [PATCH] e1000 ethtool_ops support # # Okay, here is a first cut at ethtool ops integration for e1000. # # It has been touch tested for the basic operations on a card on # a lab machine. Please review before including in the 2.6.6 kernel. # # drivers/net/e1000/e1000_main.c # 2004/04/16 11:50:02-04:00 shemminger@osdl.org +7 -28 # e1000 ethtool_ops support # # drivers/net/e1000/e1000_ethtool.c # 2004/04/16 11:50:02-04:00 shemminger@osdl.org +234 -382 # e1000 ethtool_ops support # # ChangeSet # 2004/04/06 08:37:52-04:00 hirofumi@mail.parknet.co.jp # [PATCH] 8139too: more useful debug info for tx_timeout # # Hi, # # I think this patch is useful for looking whether it's the real driver # bug or other bug. # # What do you think of this? If ok, please apply. # -- # OGAWA Hirofumi # # # # [PATCH] 8139too: more useful debug info for tx_timeout # # /* disable Tx ASAP, if not already */ # tmp8 = RTL_R8 (ChipCmd); # if (tmp8 & CmdTxEnb) # RTL_W8 (ChipCmd, CmdRxEnb); # # The above will clear the Tx Descs. So, this prints the debugging info # before rtl8139_tx_timeout() does it. And IntrStatus etc. also prints # anytime for the debug. # # drivers/net/8139too.c # 2004/04/05 12:35:48-04:00 hirofumi@mail.parknet.co.jp +11 -15 # 8139too: more useful debug info for tx_timeout # # ChangeSet # 2004/04/06 08:01:31-04:00 hch@lst.de # [PATCH] convert acenic to pci_driver API # # drivers/net/acenic.c # 2004/04/06 04:01:26-04:00 hch@lst.de +257 -313 # [PATCH] convert acenic to pci_driver API # # ChangeSet # 2004/04/06 08:01:18-04:00 hch@lst.de # [PATCH] kill acient compat cruft from acenic # # Kills lots of really old cruft and adds a little cruft to actually # make the driver work with recent 2.4 again. # # drivers/net/acenic.c # 2004/04/06 03:59:41-04:00 hch@lst.de +4 -225 # [PATCH] kill acient compat cruft from acenic # # Kills lots of really old cruft and adds a little cruft to actually # make the driver work with recent 2.4 again. # # ChangeSet # 2004/03/25 23:52:21-05:00 romieu@fr.zoreil.com # [netdrvr epic100] napi fixes # # Multiple invocation of __netif_rx_schedule() in epic_interrupt() while # epic_poll loops over __netif_rx_complete() leads to serious device # refcount leak. # # drivers/net/epic100.c # 2004/03/25 23:52:16-05:00 romieu@fr.zoreil.com +18 -15 # [netdrvr epic100] napi fixes # # Multiple invocation of __netif_rx_schedule() in epic_interrupt() while # epic_poll loops over __netif_rx_complete() leads to serious device # refcount leak. # # ChangeSet # 2004/03/22 19:07:18-05:00 romieu@fr.zoreil.com # [netdrvr epic100] napi 3/3 - transmit path # # drivers/net/epic100.c # 2004/03/22 18:18:40-05:00 romieu@fr.zoreil.com +9 -11 # 2.6.5-rc2 - epic100 napi # # ChangeSet # 2004/03/22 19:07:11-05:00 romieu@fr.zoreil.com # [netdrvr epic100] napi 2/3 - receive path # # drivers/net/epic100.c # 2004/03/22 18:18:33-05:00 romieu@fr.zoreil.com +116 -21 # 2.6.5-rc2 - epic100 napi # # ChangeSet # 2004/03/22 19:07:03-05:00 romieu@fr.zoreil.com # [netdrvr epic100] napi 1/3 - just shuffle some code around # # Isolate the classical TX part of epic_interrupt. Innocent code shuffling. # # drivers/net/epic100.c # 2004/03/22 16:53:18-05:00 romieu@fr.zoreil.com +76 -61 # 2.6.5-rc2 - epic100 napi # # ChangeSet # 2004/03/22 19:06:56-05:00 romieu@fr.zoreil.com # [netdrvr epic100] minor cleanups # # - extra pci_disable_device() to balance invocation of pci_enable_device() # in epic_init_one() (-> error path + epic_remove_one()); # - lazy return status in epic_init_one(), tsss...; # - memory dedicated to Rx descriptors was not freed after failure of # register_netdev() in epic_init_one(); # - use of epic_pause() in epic_close() offers a small window for a late # interruption just before the final free_irq(). Let's close the window to # avoid two epic_rx() threads racing with each other. # # drivers/net/epic100.c # 2004/03/22 16:53:16-05:00 romieu@fr.zoreil.com +40 -19 # 2.6.5-rc2 - epic100 fixup # diff -Nru a/drivers/net/8139too.c b/drivers/net/8139too.c --- a/drivers/net/8139too.c Tue May 4 22:12:59 2004 +++ b/drivers/net/8139too.c Tue May 4 22:12:59 2004 @@ -1677,11 +1677,17 @@ u8 tmp8; unsigned long flags; - DPRINTK ("%s: Transmit timeout, status %2.2x %4.4x " - "media %2.2x.\n", dev->name, - RTL_R8 (ChipCmd), - RTL_R16 (IntrStatus), - RTL_R8 (MediaStatus)); + printk (KERN_DEBUG "%s: Transmit timeout, status %2.2x %4.4x %4.4x " + "media %2.2x.\n", dev->name, RTL_R8 (ChipCmd), + RTL_R16(IntrStatus), RTL_R16(IntrMask), RTL_R8(MediaStatus)); + /* Emit info to figure out what went wrong. */ + printk (KERN_DEBUG "%s: Tx queue start entry %ld dirty entry %ld.\n", + dev->name, tp->cur_tx, tp->dirty_tx); + for (i = 0; i < NUM_TX_DESC; i++) + printk (KERN_DEBUG "%s: Tx descriptor %d is %8.8lx.%s\n", + dev->name, i, RTL_R32 (TxStatus0 + (i * 4)), + i == tp->dirty_tx % NUM_TX_DESC ? + " (queue head)" : ""); tp->xstats.tx_timeouts++; @@ -1694,15 +1700,6 @@ /* Disable interrupts by clearing the interrupt mask. */ RTL_W16 (IntrMask, 0x0000); - /* Emit info to figure out what went wrong. */ - printk (KERN_DEBUG "%s: Tx queue start entry %ld dirty entry %ld.\n", - dev->name, tp->cur_tx, tp->dirty_tx); - for (i = 0; i < NUM_TX_DESC; i++) - printk (KERN_DEBUG "%s: Tx descriptor %d is %8.8lx.%s\n", - dev->name, i, RTL_R32 (TxStatus0 + (i * 4)), - i == tp->dirty_tx % NUM_TX_DESC ? - " (queue head)" : ""); - /* Stop a shared interrupt from scavenging while we are. */ spin_lock_irqsave (&tp->lock, flags); rtl8139_tx_clear (tp); @@ -1714,7 +1711,6 @@ netif_wake_queue (dev); } spin_unlock(&tp->rx_lock); - } diff -Nru a/drivers/net/acenic.c b/drivers/net/acenic.c --- a/drivers/net/acenic.c Tue May 4 22:12:59 2004 +++ b/drivers/net/acenic.c Tue May 4 22:12:59 2004 @@ -131,7 +131,6 @@ #define PCI_DEVICE_ID_SGI_ACENIC 0x0009 #endif -#if LINUX_VERSION_CODE >= 0x20400 static struct pci_device_id acenic_pci_tbl[] = { { PCI_VENDOR_ID_ALTEON, PCI_DEVICE_ID_ALTEON_ACENIC_FIBRE, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, }, @@ -156,37 +155,6 @@ { } }; MODULE_DEVICE_TABLE(pci, acenic_pci_tbl); -#endif - - -#ifndef MODULE_LICENSE -#define MODULE_LICENSE(a) -#endif - -#ifndef wmb -#define wmb() mb() -#endif - -#ifndef __exit -#define __exit -#endif - -#ifndef __devinit -#define __devinit __init -#endif - -#ifndef SMP_CACHE_BYTES -#define SMP_CACHE_BYTES L1_CACHE_BYTES -#endif - -#ifndef SET_MODULE_OWNER -#define SET_MODULE_OWNER(dev) do{} while(0) -#define ACE_MOD_INC_USE_COUNT MOD_INC_USE_COUNT -#define ACE_MOD_DEC_USE_COUNT MOD_DEC_USE_COUNT -#else -#define ACE_MOD_INC_USE_COUNT do{} while(0) -#define ACE_MOD_DEC_USE_COUNT do{} while(0) -#endif #ifndef SET_NETDEV_DEV #define SET_NETDEV_DEV(net, pdev) do{} while(0) @@ -198,151 +166,8 @@ #define ace_sync_irq(irq) synchronize_irq() #endif -#if LINUX_VERSION_CODE < 0x2051e -#define local_irq_save(flags) do{__save_flags(flags) ; \ - __cli();} while(0) -#define local_irq_restore(flags) __restore_flags(flags) -#endif - -#if (LINUX_VERSION_CODE < 0x02030d) -#define pci_resource_start(dev, bar) dev->base_address[bar] -#elif (LINUX_VERSION_CODE < 0x02032c) -#define pci_resource_start(dev, bar) dev->resource[bar].start -#endif - -#if (LINUX_VERSION_CODE < 0x02030e) -#define net_device device -#endif - - -#if (LINUX_VERSION_CODE < 0x02032a) -typedef u32 dma_addr_t; - -static inline void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, - dma_addr_t *dma_handle) -{ - void *virt_ptr; - - virt_ptr = kmalloc(size, GFP_KERNEL); - if (!virt_ptr) - return NULL; - *dma_handle = virt_to_bus(virt_ptr); - return virt_ptr; -} - -#define pci_free_consistent(cookie, size, ptr, dma_ptr) kfree(ptr) -#define pci_map_page(cookie, page, off, size, dir) \ - virt_to_bus(page_address(page)+(off)) -#define pci_unmap_page(cookie, address, size, dir) -#define pci_set_dma_mask(dev, mask) \ - (((u64)(mask) & 0xffffffff00000000) == 0 ? 0 : -EIO) -#define pci_dma_supported(dev, mask) \ - (((u64)(mask) & 0xffffffff00000000) == 0 ? 1 : 0) - -#elif (LINUX_VERSION_CODE < 0x02040d) - -/* - * 2.4.13 introduced pci_map_page()/pci_unmap_page() - for 2.4.12 and prior, - * fall back on pci_map_single()/pci_unnmap_single(). - * - * We are guaranteed that the page is mapped at this point since - * pci_map_page() is only used upon valid struct skb's. - */ -static inline dma_addr_t -pci_map_page(struct pci_dev *cookie, struct page *page, unsigned long off, - size_t size, int dir) -{ - void *page_virt; - - page_virt = page_address(page); - if (!page_virt) - BUG(); - return pci_map_single(cookie, (page_virt + off), size, dir); -} -#define pci_unmap_page(cookie, dma_addr, size, dir) \ - pci_unmap_single(cookie, dma_addr, size, dir) -#endif - -#if (LINUX_VERSION_CODE < 0x020412) -#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) -#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) -#define pci_unmap_addr(PTR, ADDR_NAME) 0 -#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL) do{} while(0) -#define pci_unmap_len(PTR, LEN_NAME) 0 -#define pci_unmap_len_set(PTR, LEN_NAME, VAL) do{} while(0) -#endif - - -#if (LINUX_VERSION_CODE < 0x02032b) -/* - * SoftNet - * - * For pre-softnet kernels we need to tell the upper layer not to - * re-enter start_xmit() while we are in there. However softnet - * guarantees not to enter while we are in there so there is no need - * to do the netif_stop_queue() dance unless the transmit queue really - * gets stuck. This should also improve performance according to tests - * done by Aman Singla. - */ -#define dev_kfree_skb_irq(a) dev_kfree_skb(a) -#define netif_wake_queue(dev) clear_bit(0, &dev->tbusy) -#define netif_stop_queue(dev) set_bit(0, &dev->tbusy) -#define late_stop_netif_stop_queue(dev) do{} while(0) -#define early_stop_netif_stop_queue(dev) test_and_set_bit(0,&dev->tbusy) -#define early_stop_netif_wake_queue(dev) netif_wake_queue(dev) - -static inline void netif_start_queue(struct net_device *dev) -{ - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; -} - -#define ace_mark_net_bh() mark_bh(NET_BH) -#define netif_queue_stopped(dev) dev->tbusy -#define netif_running(dev) dev->start -#define ace_if_down(dev) do{dev->start = 0;} while(0) - -#define tasklet_struct tq_struct -static inline void tasklet_schedule(struct tasklet_struct *tasklet) -{ - queue_task(tasklet, &tq_immediate); - mark_bh(IMMEDIATE_BH); -} - -static inline void tasklet_init(struct tasklet_struct *tasklet, - void (*func)(unsigned long), - unsigned long data) -{ - tasklet->next = NULL; - tasklet->sync = 0; - tasklet->routine = (void (*)(void *))func; - tasklet->data = (void *)data; -} -#define tasklet_kill(tasklet) do{} while(0) -#else -#define late_stop_netif_stop_queue(dev) netif_stop_queue(dev) -#define early_stop_netif_stop_queue(dev) 0 -#define early_stop_netif_wake_queue(dev) do{} while(0) -#define ace_mark_net_bh() do{} while(0) -#define ace_if_down(dev) do{} while(0) -#endif - -#if (LINUX_VERSION_CODE >= 0x02031b) -#define NEW_NETINIT -#define ACE_PROBE_ARG void -#else -#define ACE_PROBE_ARG struct net_device *dev -#endif - -#ifndef min_t -#define min_t(type,a,b) (((a)<(b))?(a):(b)) -#endif - -#ifndef ARCH_HAS_PREFETCHW -#ifndef prefetchw -#define prefetchw(x) do{} while(0) -#endif +#ifndef offset_in_page +#define offset_in_page(ptr) ((unsigned long)(ptr) & ~PAGE_MASK) #endif #define ACE_MAX_MOD_PARMS 8 @@ -595,407 +420,323 @@ static int tx_ratio[ACE_MAX_MOD_PARMS]; static int dis_pci_mem_inval[ACE_MAX_MOD_PARMS] = {1, 1, 1, 1, 1, 1, 1, 1}; +MODULE_AUTHOR("Jes Sorensen "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("AceNIC/3C985/GA620 Gigabit Ethernet driver"); +MODULE_PARM(link, "1-" __MODULE_STRING(8) "i"); +MODULE_PARM(trace, "1-" __MODULE_STRING(8) "i"); +MODULE_PARM(tx_coal_tick, "1-" __MODULE_STRING(8) "i"); +MODULE_PARM(max_tx_desc, "1-" __MODULE_STRING(8) "i"); +MODULE_PARM(rx_coal_tick, "1-" __MODULE_STRING(8) "i"); +MODULE_PARM(max_rx_desc, "1-" __MODULE_STRING(8) "i"); +MODULE_PARM(tx_ratio, "1-" __MODULE_STRING(8) "i"); +MODULE_PARM_DESC(link, "AceNIC/3C985/NetGear link state"); +MODULE_PARM_DESC(trace, "AceNIC/3C985/NetGear firmware trace level"); +MODULE_PARM_DESC(tx_coal_tick, "AceNIC/3C985/GA620 max clock ticks to wait from first tx descriptor arrives"); +MODULE_PARM_DESC(max_tx_desc, "AceNIC/3C985/GA620 max number of transmit descriptors to wait"); +MODULE_PARM_DESC(rx_coal_tick, "AceNIC/3C985/GA620 max clock ticks to wait from first rx descriptor arrives"); +MODULE_PARM_DESC(max_rx_desc, "AceNIC/3C985/GA620 max number of receive descriptors to wait"); +MODULE_PARM_DESC(tx_ratio, "AceNIC/3C985/GA620 ratio of NIC memory used for TX/RX descriptors (range 0-63)"); + + static char version[] __initdata = "acenic.c: v0.92 08/05/2002 Jes Sorensen, linux-acenic@SunSITE.dk\n" " http://home.cern.ch/~jes/gige/acenic.html\n"; -static struct net_device *root_dev; - -static int probed __initdata = 0; - - -int __devinit acenic_probe (ACE_PROBE_ARG) +static int __devinit acenic_probe_one(struct pci_dev *pdev, + const struct pci_device_id *id) { -#ifdef NEW_NETINIT struct net_device *dev; -#endif struct ace_private *ap; - struct pci_dev *pdev = NULL; - int boards_found = 0; - int version_disp; - - if (probed) - return -ENODEV; - probed++; - - version_disp = 0; - - while ((pdev = pci_find_class(PCI_CLASS_NETWORK_ETHERNET<<8, pdev))) { - - if (!((pdev->vendor == PCI_VENDOR_ID_ALTEON) && - ((pdev->device == PCI_DEVICE_ID_ALTEON_ACENIC_FIBRE) || - (pdev->device == PCI_DEVICE_ID_ALTEON_ACENIC_COPPER)))&& - !((pdev->vendor == PCI_VENDOR_ID_3COM) && - (pdev->device == PCI_DEVICE_ID_3COM_3C985)) && - !((pdev->vendor == PCI_VENDOR_ID_NETGEAR) && - ((pdev->device == PCI_DEVICE_ID_NETGEAR_GA620) || - (pdev->device == PCI_DEVICE_ID_NETGEAR_GA620T))) && - /* - * Farallon used the DEC vendor ID on their cards by - * mistake for a while - */ - !((pdev->vendor == PCI_VENDOR_ID_DEC) && - (pdev->device == PCI_DEVICE_ID_FARALLON_PN9000SX)) && - !((pdev->vendor == PCI_VENDOR_ID_ALTEON) && - (pdev->device == PCI_DEVICE_ID_FARALLON_PN9100T)) && - !((pdev->vendor == PCI_VENDOR_ID_SGI) && - (pdev->device == PCI_DEVICE_ID_SGI_ACENIC))) - continue; - - dev = alloc_etherdev(sizeof(struct ace_private)); - if (dev == NULL) { - printk(KERN_ERR "acenic: Unable to allocate " - "net_device structure!\n"); - break; - } + static int boards_found; - SET_MODULE_OWNER(dev); - SET_NETDEV_DEV(dev, &pdev->dev); + dev = alloc_etherdev(sizeof(struct ace_private)); + if (dev == NULL) { + printk(KERN_ERR "acenic: Unable to allocate " + "net_device structure!\n"); + return -ENOMEM; + } + + SET_MODULE_OWNER(dev); + SET_NETDEV_DEV(dev, &pdev->dev); - ap = dev->priv; - ap->pdev = pdev; + ap = dev->priv; + ap->pdev = pdev; - dev->open = &ace_open; - dev->hard_start_xmit = &ace_start_xmit; - dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; + dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; #if ACENIC_DO_VLAN - dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; - dev->vlan_rx_register = ace_vlan_rx_register; - dev->vlan_rx_kill_vid = ace_vlan_rx_kill_vid; -#endif - if (1) { - static void ace_watchdog(struct net_device *dev); - dev->tx_timeout = &ace_watchdog; - dev->watchdog_timeo = 5*HZ; - } - dev->stop = &ace_close; - dev->get_stats = &ace_get_stats; - dev->set_multicast_list = &ace_set_multicast_list; - dev->do_ioctl = &ace_ioctl; - dev->set_mac_address = &ace_set_mac_addr; - dev->change_mtu = &ace_change_mtu; + dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; + dev->vlan_rx_register = ace_vlan_rx_register; + dev->vlan_rx_kill_vid = ace_vlan_rx_kill_vid; +#endif + if (1) { + static void ace_watchdog(struct net_device *dev); + dev->tx_timeout = &ace_watchdog; + dev->watchdog_timeo = 5*HZ; + } - /* display version info if adapter is found */ - if (!version_disp) - { - /* set display flag to TRUE so that */ - /* we only display this string ONCE */ - version_disp = 1; - printk(version); - } + dev->open = &ace_open; + dev->stop = &ace_close; + dev->hard_start_xmit = &ace_start_xmit; + dev->get_stats = &ace_get_stats; + dev->set_multicast_list = &ace_set_multicast_list; + dev->do_ioctl = &ace_ioctl; + dev->set_mac_address = &ace_set_mac_addr; + dev->change_mtu = &ace_change_mtu; - if (pci_enable_device(pdev)) { - free_netdev(dev); - continue; - } + /* we only display this string ONCE */ + if (!boards_found) + printk(version); - /* - * Enable master mode before we start playing with the - * pci_command word since pci_set_master() will modify - * it. - */ - pci_set_master(pdev); + if (pci_enable_device(pdev)) + goto fail_free_netdev; - pci_read_config_word(pdev, PCI_COMMAND, &ap->pci_command); + /* + * Enable master mode before we start playing with the + * pci_command word since pci_set_master() will modify + * it. + */ + pci_set_master(pdev); - /* OpenFirmware on Mac's does not set this - DOH.. */ - if (!(ap->pci_command & PCI_COMMAND_MEMORY)) { - printk(KERN_INFO "%s: Enabling PCI Memory Mapped " - "access - was not enabled by BIOS/Firmware\n", - dev->name); - ap->pci_command = ap->pci_command | PCI_COMMAND_MEMORY; - pci_write_config_word(ap->pdev, PCI_COMMAND, - ap->pci_command); - wmb(); - } + pci_read_config_word(pdev, PCI_COMMAND, &ap->pci_command); - pci_read_config_byte(pdev, PCI_LATENCY_TIMER, - &ap->pci_latency); - if (ap->pci_latency <= 0x40) { - ap->pci_latency = 0x40; - pci_write_config_byte(pdev, PCI_LATENCY_TIMER, - ap->pci_latency); - } + /* OpenFirmware on Mac's does not set this - DOH.. */ + if (!(ap->pci_command & PCI_COMMAND_MEMORY)) { + printk(KERN_INFO "%s: Enabling PCI Memory Mapped " + "access - was not enabled by BIOS/Firmware\n", + dev->name); + ap->pci_command = ap->pci_command | PCI_COMMAND_MEMORY; + pci_write_config_word(ap->pdev, PCI_COMMAND, + ap->pci_command); + wmb(); + } - /* - * Remap the regs into kernel space - this is abuse of - * dev->base_addr since it was means for I/O port - * addresses but who gives a damn. - */ - dev->base_addr = pci_resource_start(pdev, 0); - ap->regs = (struct ace_regs *)ioremap(dev->base_addr, 0x4000); - if (!ap->regs) { - printk(KERN_ERR "%s: Unable to map I/O register, " - "AceNIC %i will be disabled.\n", - dev->name, boards_found); - break; - } + pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &ap->pci_latency); + if (ap->pci_latency <= 0x40) { + ap->pci_latency = 0x40; + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, ap->pci_latency); + } - switch(pdev->vendor) { - case PCI_VENDOR_ID_ALTEON: - if (pdev->device == PCI_DEVICE_ID_FARALLON_PN9100T) { - strncpy(ap->name, "Farallon PN9100-T " - "Gigabit Ethernet", sizeof (ap->name)); - printk(KERN_INFO "%s: Farallon PN9100-T ", - dev->name); - } else { - strncpy(ap->name, "AceNIC Gigabit Ethernet", - sizeof (ap->name)); - printk(KERN_INFO "%s: Alteon AceNIC ", - dev->name); - } - break; - case PCI_VENDOR_ID_3COM: - strncpy(ap->name, "3Com 3C985 Gigabit Ethernet", - sizeof (ap->name)); - printk(KERN_INFO "%s: 3Com 3C985 ", dev->name); - break; - case PCI_VENDOR_ID_NETGEAR: - strncpy(ap->name, "NetGear GA620 Gigabit Ethernet", - sizeof (ap->name)); - printk(KERN_INFO "%s: NetGear GA620 ", dev->name); - break; - case PCI_VENDOR_ID_DEC: - if (pdev->device == PCI_DEVICE_ID_FARALLON_PN9000SX) { - strncpy(ap->name, "Farallon PN9000-SX " - "Gigabit Ethernet", sizeof (ap->name)); - printk(KERN_INFO "%s: Farallon PN9000-SX ", - dev->name); - break; - } - case PCI_VENDOR_ID_SGI: - strncpy(ap->name, "SGI AceNIC Gigabit Ethernet", + /* + * Remap the regs into kernel space - this is abuse of + * dev->base_addr since it was means for I/O port + * addresses but who gives a damn. + */ + dev->base_addr = pci_resource_start(pdev, 0); + ap->regs = (struct ace_regs *)ioremap(dev->base_addr, 0x4000); + if (!ap->regs) { + printk(KERN_ERR "%s: Unable to map I/O register, " + "AceNIC %i will be disabled.\n", + dev->name, boards_found); + goto fail_free_netdev; + } + + switch(pdev->vendor) { + case PCI_VENDOR_ID_ALTEON: + if (pdev->device == PCI_DEVICE_ID_FARALLON_PN9100T) { + strncpy(ap->name, "Farallon PN9100-T " + "Gigabit Ethernet", sizeof (ap->name)); + printk(KERN_INFO "%s: Farallon PN9100-T ", + dev->name); + } else { + strncpy(ap->name, "AceNIC Gigabit Ethernet", sizeof (ap->name)); - printk(KERN_INFO "%s: SGI AceNIC ", dev->name); - break; - default: - strncpy(ap->name, "Unknown AceNIC based Gigabit " - "Ethernet", sizeof (ap->name)); - printk(KERN_INFO "%s: Unknown AceNIC ", dev->name); + printk(KERN_INFO "%s: Alteon AceNIC ", + dev->name); + } + break; + case PCI_VENDOR_ID_3COM: + strncpy(ap->name, "3Com 3C985 Gigabit Ethernet", + sizeof (ap->name)); + printk(KERN_INFO "%s: 3Com 3C985 ", dev->name); + break; + case PCI_VENDOR_ID_NETGEAR: + strncpy(ap->name, "NetGear GA620 Gigabit Ethernet", + sizeof (ap->name)); + printk(KERN_INFO "%s: NetGear GA620 ", dev->name); + break; + case PCI_VENDOR_ID_DEC: + if (pdev->device == PCI_DEVICE_ID_FARALLON_PN9000SX) { + strncpy(ap->name, "Farallon PN9000-SX " + "Gigabit Ethernet", sizeof (ap->name)); + printk(KERN_INFO "%s: Farallon PN9000-SX ", + dev->name); break; } - ap->name [sizeof (ap->name) - 1] = '\0'; - printk("Gigabit Ethernet at 0x%08lx, ", dev->base_addr); + case PCI_VENDOR_ID_SGI: + strncpy(ap->name, "SGI AceNIC Gigabit Ethernet", + sizeof (ap->name)); + printk(KERN_INFO "%s: SGI AceNIC ", dev->name); + break; + default: + strncpy(ap->name, "Unknown AceNIC based Gigabit " + "Ethernet", sizeof (ap->name)); + printk(KERN_INFO "%s: Unknown AceNIC ", dev->name); + break; + } + + ap->name [sizeof (ap->name) - 1] = '\0'; + printk("Gigabit Ethernet at 0x%08lx, ", dev->base_addr); #ifdef __sparc__ - printk("irq %s\n", __irq_itoa(pdev->irq)); + printk("irq %s\n", __irq_itoa(pdev->irq)); #else - printk("irq %i\n", pdev->irq); + printk("irq %i\n", pdev->irq); #endif #ifdef CONFIG_ACENIC_OMIT_TIGON_I - if ((readl(&ap->regs->HostCtrl) >> 28) == 4) { - printk(KERN_ERR "%s: Driver compiled without Tigon I" - " support - NIC disabled\n", dev->name); - ace_init_cleanup(dev); - free_netdev(dev); - continue; - } + if ((readl(&ap->regs->HostCtrl) >> 28) == 4) { + printk(KERN_ERR "%s: Driver compiled without Tigon I" + " support - NIC disabled\n", dev->name); + goto fail_uninit; + } #endif - if (ace_allocate_descriptors(dev)) { - /* - * ace_allocate_descriptors() calls - * ace_init_cleanup() on error. - */ - free_netdev(dev); - continue; - } + if (ace_allocate_descriptors(dev)) + goto fail_free_netdev; #ifdef MODULE - if (boards_found >= ACE_MAX_MOD_PARMS) - ap->board_idx = BOARD_IDX_OVERFLOW; - else - ap->board_idx = boards_found; + if (boards_found >= ACE_MAX_MOD_PARMS) + ap->board_idx = BOARD_IDX_OVERFLOW; + else + ap->board_idx = boards_found; #else - ap->board_idx = BOARD_IDX_STATIC; + ap->board_idx = BOARD_IDX_STATIC; #endif - if (ace_init(dev)) { - /* - * ace_init() calls ace_init_cleanup() on error. - */ - free_netdev(dev); - continue; - } + if (ace_init(dev)) + goto fail_free_netdev; - if (register_netdev(dev)) { - printk(KERN_ERR "acenic: device registration failed\n"); - ace_init_cleanup(dev); - free_netdev(dev); - continue; - } - - if (ap->pci_using_dac) - dev->features |= NETIF_F_HIGHDMA; - - boards_found++; + if (register_netdev(dev)) { + printk(KERN_ERR "acenic: device registration failed\n"); + goto fail_uninit; } - /* - * If we're at this point we're going through ace_probe() for - * the first time. Return success (0) if we've initialized 1 - * or more boards. Otherwise, return failure (-ENODEV). - */ - - if (boards_found > 0) - return 0; - else - return -ENODEV; -} + if (ap->pci_using_dac) + dev->features |= NETIF_F_HIGHDMA; + pci_set_drvdata(pdev, dev); -#ifdef MODULE -MODULE_AUTHOR("Jes Sorensen "); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("AceNIC/3C985/GA620 Gigabit Ethernet driver"); -MODULE_PARM(link, "1-" __MODULE_STRING(8) "i"); -MODULE_PARM(trace, "1-" __MODULE_STRING(8) "i"); -MODULE_PARM(tx_coal_tick, "1-" __MODULE_STRING(8) "i"); -MODULE_PARM(max_tx_desc, "1-" __MODULE_STRING(8) "i"); -MODULE_PARM(rx_coal_tick, "1-" __MODULE_STRING(8) "i"); -MODULE_PARM(max_rx_desc, "1-" __MODULE_STRING(8) "i"); -MODULE_PARM(tx_ratio, "1-" __MODULE_STRING(8) "i"); -MODULE_PARM_DESC(link, "AceNIC/3C985/NetGear link state"); -MODULE_PARM_DESC(trace, "AceNIC/3C985/NetGear firmware trace level"); -MODULE_PARM_DESC(tx_coal_tick, "AceNIC/3C985/GA620 max clock ticks to wait from first tx descriptor arrives"); -MODULE_PARM_DESC(max_tx_desc, "AceNIC/3C985/GA620 max number of transmit descriptors to wait"); -MODULE_PARM_DESC(rx_coal_tick, "AceNIC/3C985/GA620 max clock ticks to wait from first rx descriptor arrives"); -MODULE_PARM_DESC(max_rx_desc, "AceNIC/3C985/GA620 max number of receive descriptors to wait"); -MODULE_PARM_DESC(tx_ratio, "AceNIC/3C985/GA620 ratio of NIC memory used for TX/RX descriptors (range 0-63)"); -#endif + boards_found++; + return 0; + fail_uninit: + ace_init_cleanup(dev); + fail_free_netdev: + free_netdev(dev); + return -ENODEV; +} -static void __exit ace_module_cleanup(void) +static void __devexit acenic_remove_one(struct pci_dev *pdev) { - struct ace_private *ap; - struct ace_regs *regs; - struct net_device *next; + struct net_device *dev = pci_get_drvdata(pdev); + struct ace_private *ap = dev->priv; + struct ace_regs *regs = ap->regs; short i; - while (root_dev) { - ap = root_dev->priv; - next = ap->next; - unregister_netdev(root_dev); - - regs = ap->regs; + unregister_netdev(dev); - writel(readl(®s->CpuCtrl) | CPU_HALT, ®s->CpuCtrl); - if (ap->version >= 2) - writel(readl(®s->CpuBCtrl) | CPU_HALT, - ®s->CpuBCtrl); - /* - * This clears any pending interrupts - */ - writel(1, ®s->Mb0Lo); - readl(®s->CpuCtrl); /* flush */ + writel(readl(®s->CpuCtrl) | CPU_HALT, ®s->CpuCtrl); + if (ap->version >= 2) + writel(readl(®s->CpuBCtrl) | CPU_HALT, ®s->CpuBCtrl); + + /* + * This clears any pending interrupts + */ + writel(1, ®s->Mb0Lo); + readl(®s->CpuCtrl); /* flush */ - /* - * Make sure no other CPUs are processing interrupts - * on the card before the buffers are being released. - * Otherwise one might experience some `interesting' - * effects. - * - * Then release the RX buffers - jumbo buffers were - * already released in ace_close(). - */ - ace_sync_irq(root_dev->irq); + /* + * Make sure no other CPUs are processing interrupts + * on the card before the buffers are being released. + * Otherwise one might experience some `interesting' + * effects. + * + * Then release the RX buffers - jumbo buffers were + * already released in ace_close(). + */ + ace_sync_irq(dev->irq); - for (i = 0; i < RX_STD_RING_ENTRIES; i++) { - struct sk_buff *skb = ap->skb->rx_std_skbuff[i].skb; + for (i = 0; i < RX_STD_RING_ENTRIES; i++) { + struct sk_buff *skb = ap->skb->rx_std_skbuff[i].skb; - if (skb) { - struct ring_info *ringp; - dma_addr_t mapping; + if (skb) { + struct ring_info *ringp; + dma_addr_t mapping; - ringp = &ap->skb->rx_std_skbuff[i]; - mapping = pci_unmap_addr(ringp, mapping); - pci_unmap_page(ap->pdev, mapping, - ACE_STD_BUFSIZE - (2 + 16), - PCI_DMA_FROMDEVICE); + ringp = &ap->skb->rx_std_skbuff[i]; + mapping = pci_unmap_addr(ringp, mapping); + pci_unmap_page(ap->pdev, mapping, + ACE_STD_BUFSIZE - (2 + 16), + PCI_DMA_FROMDEVICE); - ap->rx_std_ring[i].size = 0; - ap->skb->rx_std_skbuff[i].skb = NULL; - dev_kfree_skb(skb); - } - } - if (ap->version >= 2) { - for (i = 0; i < RX_MINI_RING_ENTRIES; i++) { - struct sk_buff *skb = ap->skb->rx_mini_skbuff[i].skb; - - if (skb) { - struct ring_info *ringp; - dma_addr_t mapping; - - ringp = &ap->skb->rx_mini_skbuff[i]; - mapping = pci_unmap_addr(ringp,mapping); - pci_unmap_page(ap->pdev, mapping, - ACE_MINI_BUFSIZE - (2 + 16), - PCI_DMA_FROMDEVICE); - - ap->rx_mini_ring[i].size = 0; - ap->skb->rx_mini_skbuff[i].skb = NULL; - dev_kfree_skb(skb); - } - } + ap->rx_std_ring[i].size = 0; + ap->skb->rx_std_skbuff[i].skb = NULL; + dev_kfree_skb(skb); } - for (i = 0; i < RX_JUMBO_RING_ENTRIES; i++) { - struct sk_buff *skb = ap->skb->rx_jumbo_skbuff[i].skb; + } + + if (ap->version >= 2) { + for (i = 0; i < RX_MINI_RING_ENTRIES; i++) { + struct sk_buff *skb = ap->skb->rx_mini_skbuff[i].skb; + if (skb) { struct ring_info *ringp; dma_addr_t mapping; - ringp = &ap->skb->rx_jumbo_skbuff[i]; - mapping = pci_unmap_addr(ringp, mapping); + ringp = &ap->skb->rx_mini_skbuff[i]; + mapping = pci_unmap_addr(ringp,mapping); pci_unmap_page(ap->pdev, mapping, - ACE_JUMBO_BUFSIZE - (2 + 16), + ACE_MINI_BUFSIZE - (2 + 16), PCI_DMA_FROMDEVICE); - ap->rx_jumbo_ring[i].size = 0; - ap->skb->rx_jumbo_skbuff[i].skb = NULL; + ap->rx_mini_ring[i].size = 0; + ap->skb->rx_mini_skbuff[i].skb = NULL; dev_kfree_skb(skb); } } - - ace_init_cleanup(root_dev); - free_netdev(root_dev); - root_dev = next; } -} + for (i = 0; i < RX_JUMBO_RING_ENTRIES; i++) { + struct sk_buff *skb = ap->skb->rx_jumbo_skbuff[i].skb; + if (skb) { + struct ring_info *ringp; + dma_addr_t mapping; -int __init ace_module_init(void) -{ - int status; + ringp = &ap->skb->rx_jumbo_skbuff[i]; + mapping = pci_unmap_addr(ringp, mapping); + pci_unmap_page(ap->pdev, mapping, + ACE_JUMBO_BUFSIZE - (2 + 16), + PCI_DMA_FROMDEVICE); - root_dev = NULL; + ap->rx_jumbo_ring[i].size = 0; + ap->skb->rx_jumbo_skbuff[i].skb = NULL; + dev_kfree_skb(skb); + } + } -#ifdef NEW_NETINIT - status = acenic_probe(); -#else - status = acenic_probe(NULL); -#endif - return status; + ace_init_cleanup(dev); + free_netdev(dev); } +static struct pci_driver acenic_pci_driver = { + .name = "acenic", + .id_table = acenic_pci_tbl, + .probe = acenic_probe_one, + .remove = __devexit_p(acenic_remove_one), +}; -#if (LINUX_VERSION_CODE < 0x02032a) -#ifdef MODULE -int init_module(void) +static int __init acenic_init(void) { - return ace_module_init(); + return pci_module_init(&acenic_pci_driver); } - -void cleanup_module(void) +static void __exit acenic_exit(void) { - ace_module_cleanup(); + pci_unregister_driver(&acenic_pci_driver); } -#endif -#else -module_init(ace_module_init); -module_exit(ace_module_cleanup); -#endif +module_init(acenic_init); +module_exit(acenic_exit); static void ace_free_descriptors(struct net_device *dev) { @@ -1462,13 +1203,6 @@ } else dev->irq = pdev->irq; - /* - * Register the device here to be able to catch allocated - * interrupt handlers in case the firmware doesn't come up. - */ - ap->next = root_dev; - root_dev = dev; - #ifdef INDEX_DEBUG spin_lock_init(&ap->debug_lock); ap->last_tx = ACE_TX_RING_ENTRIES(ap) - 1; @@ -2642,8 +2376,6 @@ netif_start_queue(dev); - ACE_MOD_INC_USE_COUNT; - /* * Setup the bottom half rx ring refill handler */ @@ -2660,8 +2392,6 @@ unsigned long flags; short i; - ace_if_down(dev); - /* * Without (or before) releasing irq and stopping hardware, this * is an absolute non-sense, by the way. It will be reset instantly @@ -2733,7 +2463,6 @@ ace_unmask_irq(dev); local_irq_restore(flags); - ACE_MOD_DEC_USE_COUNT; return 0; } @@ -2789,12 +2518,6 @@ struct ace_regs *regs = ap->regs; struct tx_desc *desc; u32 idx, flagsize; - - /* - * This only happens with pre-softnet, ie. 2.2.x kernels. - */ - if (early_stop_netif_stop_queue(dev)) - return 1; restart: idx = ap->tx_prd; diff -Nru a/drivers/net/b44.c b/drivers/net/b44.c --- a/drivers/net/b44.c Tue May 4 22:12:59 2004 +++ b/drivers/net/b44.c Tue May 4 22:12:59 2004 @@ -27,8 +27,8 @@ #define DRV_MODULE_NAME "b44" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "0.93" -#define DRV_MODULE_RELDATE "Mar, 2004" +#define DRV_MODULE_VERSION "0.94" +#define DRV_MODULE_RELDATE "May 4, 2004" #define B44_DEF_MSG_ENABLE \ (NETIF_MSG_DRV | \ @@ -96,7 +96,7 @@ static void b44_halt(struct b44 *); static void b44_init_rings(struct b44 *); -static int b44_init_hw(struct b44 *); +static void b44_init_hw(struct b44 *); static int b44_wait_bit(struct b44 *bp, unsigned long reg, u32 bit, unsigned long timeout, const int clear) @@ -331,6 +331,29 @@ return b44_wait_bit(bp, B44_EMAC_ISTAT, EMAC_INT_MII, 100, 0); } +/* miilib interface */ +/* FIXME FIXME: phy_id is ignored, bp->phy_addr use is unconditional + * due to code existing before miilib use was added to this driver. + * Someone should remove this artificial driver limitation in + * b44_{read,write}phy. bp->phy_addr itself is fine (and needed). + */ +static int b44_mii_read(struct net_device *dev, int phy_id, int location) +{ + u32 val; + struct b44 *bp = netdev_priv(dev); + int rc = b44_readphy(bp, location, &val); + if (rc) + return 0xffffffff; + return val; +} + +static void b44_mii_write(struct net_device *dev, int phy_id, int location, + int val) +{ + struct b44 *bp = netdev_priv(dev); + b44_writephy(bp, location, val); +} + static int b44_phy_reset(struct b44 *bp) { u32 val; @@ -771,7 +794,7 @@ static int b44_poll(struct net_device *netdev, int *budget) { - struct b44 *bp = netdev->priv; + struct b44 *bp = netdev_priv(netdev); int done; spin_lock_irq(&bp->lock); @@ -821,7 +844,7 @@ static irqreturn_t b44_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = dev_id; - struct b44 *bp = dev->priv; + struct b44 *bp = netdev_priv(dev); unsigned long flags; u32 istat, imask; int handled = 0; @@ -858,7 +881,7 @@ static void b44_tx_timeout(struct net_device *dev) { - struct b44 *bp = dev->priv; + struct b44 *bp = netdev_priv(dev); printk(KERN_ERR PFX "%s: transmit timed out, resetting\n", dev->name); @@ -878,7 +901,7 @@ static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct b44 *bp = dev->priv; + struct b44 *bp = netdev_priv(dev); dma_addr_t mapping; u32 len, entry, ctrl; @@ -932,7 +955,7 @@ static int b44_change_mtu(struct net_device *dev, int new_mtu) { - struct b44 *bp = dev->priv; + struct b44 *bp = netdev_priv(dev); if (new_mtu < B44_MIN_MTU || new_mtu > B44_MAX_MTU) return -EINVAL; @@ -1161,7 +1184,7 @@ static int b44_set_mac_addr(struct net_device *dev, void *p) { - struct b44 *bp = dev->priv; + struct b44 *bp = netdev_priv(dev); struct sockaddr *addr = p; if (netif_running(dev)) @@ -1180,7 +1203,7 @@ * packet processing. Invoked with bp->lock held. */ static void __b44_set_rx_mode(struct net_device *); -static int b44_init_hw(struct b44 *bp) +static void b44_init_hw(struct b44 *bp) { u32 val; @@ -1212,13 +1235,11 @@ val = br32(B44_ENET_CTRL); bw32(B44_ENET_CTRL, (val | ENET_CTRL_ENABLE)); - - return 0; } static int b44_open(struct net_device *dev) { - struct b44 *bp = dev->priv; + struct b44 *bp = netdev_priv(dev); int err; err = b44_alloc_consistent(bp); @@ -1232,9 +1253,7 @@ spin_lock_irq(&bp->lock); b44_init_rings(bp); - err = b44_init_hw(bp); - if (err) - goto err_out_noinit; + b44_init_hw(bp); bp->flags |= B44_FLAG_INIT_COMPLETE; spin_unlock_irq(&bp->lock); @@ -1249,11 +1268,6 @@ return 0; -err_out_noinit: - b44_halt(bp); - b44_free_rings(bp); - spin_unlock_irq(&bp->lock); - free_irq(dev->irq, dev); err_out_free: b44_free_consistent(bp); return err; @@ -1273,7 +1287,7 @@ static int b44_close(struct net_device *dev) { - struct b44 *bp = dev->priv; + struct b44 *bp = netdev_priv(dev); netif_stop_queue(dev); @@ -1300,7 +1314,7 @@ static struct net_device_stats *b44_get_stats(struct net_device *dev) { - struct b44 *bp = dev->priv; + struct b44 *bp = netdev_priv(dev); struct net_device_stats *nstat = &bp->stats; struct b44_hw_stats *hwstat = &bp->hw_stats; @@ -1351,7 +1365,7 @@ static void __b44_set_rx_mode(struct net_device *dev) { - struct b44 *bp = dev->priv; + struct b44 *bp = netdev_priv(dev); u32 val; val = br32(B44_RXCONFIG); @@ -1375,295 +1389,252 @@ static void b44_set_rx_mode(struct net_device *dev) { - struct b44 *bp = dev->priv; + struct b44 *bp = netdev_priv(dev); spin_lock_irq(&bp->lock); __b44_set_rx_mode(dev); spin_unlock_irq(&bp->lock); } -static int b44_ethtool_ioctl (struct net_device *dev, void __user *useraddr) +static u32 b44_get_msglevel(struct net_device *dev) { - struct b44 *bp = dev->priv; - struct pci_dev *pci_dev = bp->pdev; - u32 ethcmd; + struct b44 *bp = netdev_priv(dev); + return bp->msg_enable; +} - if (copy_from_user (ðcmd, useraddr, sizeof (ethcmd))) - return -EFAULT; +static void b44_set_msglevel(struct net_device *dev, u32 value) +{ + struct b44 *bp = netdev_priv(dev); + bp->msg_enable = value; +} - switch (ethcmd) { - case ETHTOOL_GDRVINFO:{ - struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; - strcpy (info.driver, DRV_MODULE_NAME); - strcpy (info.version, DRV_MODULE_VERSION); - memset(&info.fw_version, 0, sizeof(info.fw_version)); - strcpy (info.bus_info, pci_name(pci_dev)); - info.eedump_len = 0; - info.regdump_len = 0; - if (copy_to_user (useraddr, &info, sizeof (info))) - return -EFAULT; - return 0; - } +static void b44_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *info) +{ + struct b44 *bp = netdev_priv(dev); + struct pci_dev *pci_dev = bp->pdev; - case ETHTOOL_GSET: { - struct ethtool_cmd cmd = { ETHTOOL_GSET }; + strcpy (info->driver, DRV_MODULE_NAME); + strcpy (info->version, DRV_MODULE_VERSION); + strcpy (info->bus_info, pci_name(pci_dev)); +} - if (!(bp->flags & B44_FLAG_INIT_COMPLETE)) - return -EAGAIN; - cmd.supported = (SUPPORTED_Autoneg); - cmd.supported |= (SUPPORTED_100baseT_Half | - SUPPORTED_100baseT_Full | - SUPPORTED_10baseT_Half | - SUPPORTED_10baseT_Full | - SUPPORTED_MII); +static int b44_nway_reset(struct net_device *dev) +{ + struct b44 *bp = netdev_priv(dev); + u32 bmcr; + int r; - cmd.advertising = 0; - if (bp->flags & B44_FLAG_ADV_10HALF) - cmd.advertising |= ADVERTISE_10HALF; - if (bp->flags & B44_FLAG_ADV_10FULL) - cmd.advertising |= ADVERTISE_10FULL; - if (bp->flags & B44_FLAG_ADV_100HALF) - cmd.advertising |= ADVERTISE_100HALF; - if (bp->flags & B44_FLAG_ADV_100FULL) - cmd.advertising |= ADVERTISE_100FULL; - cmd.advertising |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; - cmd.speed = (bp->flags & B44_FLAG_100_BASE_T) ? - SPEED_100 : SPEED_10; - cmd.duplex = (bp->flags & B44_FLAG_FULL_DUPLEX) ? - DUPLEX_FULL : DUPLEX_HALF; - cmd.port = 0; - cmd.phy_address = bp->phy_addr; - cmd.transceiver = (bp->flags & B44_FLAG_INTERNAL_PHY) ? - XCVR_INTERNAL : XCVR_EXTERNAL; - cmd.autoneg = (bp->flags & B44_FLAG_FORCE_LINK) ? - AUTONEG_DISABLE : AUTONEG_ENABLE; - cmd.maxtxpkt = 0; - cmd.maxrxpkt = 0; - if (copy_to_user(useraddr, &cmd, sizeof(cmd))) - return -EFAULT; - return 0; + spin_lock_irq(&bp->lock); + b44_readphy(bp, MII_BMCR, &bmcr); + b44_readphy(bp, MII_BMCR, &bmcr); + r = -EINVAL; + if (bmcr & BMCR_ANENABLE) { + b44_writephy(bp, MII_BMCR, + bmcr | BMCR_ANRESTART); + r = 0; } - case ETHTOOL_SSET: { - struct ethtool_cmd cmd; + spin_unlock_irq(&bp->lock); - if (!(bp->flags & B44_FLAG_INIT_COMPLETE)) - return -EAGAIN; + return r; +} - if (copy_from_user(&cmd, useraddr, sizeof(cmd))) - return -EFAULT; +static int b44_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct b44 *bp = netdev_priv(dev); - /* We do not support gigabit. */ - if (cmd.autoneg == AUTONEG_ENABLE) { - if (cmd.advertising & - (ADVERTISED_1000baseT_Half | - ADVERTISED_1000baseT_Full)) - return -EINVAL; - } else if ((cmd.speed != SPEED_100 && - cmd.speed != SPEED_10) || - (cmd.duplex != DUPLEX_HALF && - cmd.duplex != DUPLEX_FULL)) { - return -EINVAL; - } + if (!(bp->flags & B44_FLAG_INIT_COMPLETE)) + return -EAGAIN; + cmd->supported = (SUPPORTED_Autoneg); + cmd->supported |= (SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_MII); + + cmd->advertising = 0; + if (bp->flags & B44_FLAG_ADV_10HALF) + cmd->advertising |= ADVERTISE_10HALF; + if (bp->flags & B44_FLAG_ADV_10FULL) + cmd->advertising |= ADVERTISE_10FULL; + if (bp->flags & B44_FLAG_ADV_100HALF) + cmd->advertising |= ADVERTISE_100HALF; + if (bp->flags & B44_FLAG_ADV_100FULL) + cmd->advertising |= ADVERTISE_100FULL; + cmd->advertising |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; + cmd->speed = (bp->flags & B44_FLAG_100_BASE_T) ? + SPEED_100 : SPEED_10; + cmd->duplex = (bp->flags & B44_FLAG_FULL_DUPLEX) ? + DUPLEX_FULL : DUPLEX_HALF; + cmd->port = 0; + cmd->phy_address = bp->phy_addr; + cmd->transceiver = (bp->flags & B44_FLAG_INTERNAL_PHY) ? + XCVR_INTERNAL : XCVR_EXTERNAL; + cmd->autoneg = (bp->flags & B44_FLAG_FORCE_LINK) ? + AUTONEG_DISABLE : AUTONEG_ENABLE; + cmd->maxtxpkt = 0; + cmd->maxrxpkt = 0; + return 0; +} - spin_lock_irq(&bp->lock); +static int b44_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct b44 *bp = netdev_priv(dev); - if (cmd.autoneg == AUTONEG_ENABLE) { - bp->flags &= ~B44_FLAG_FORCE_LINK; - bp->flags &= ~(B44_FLAG_ADV_10HALF | - B44_FLAG_ADV_10FULL | - B44_FLAG_ADV_100HALF | - B44_FLAG_ADV_100FULL); - if (cmd.advertising & ADVERTISE_10HALF) - bp->flags |= B44_FLAG_ADV_10HALF; - if (cmd.advertising & ADVERTISE_10FULL) - bp->flags |= B44_FLAG_ADV_10FULL; - if (cmd.advertising & ADVERTISE_100HALF) - bp->flags |= B44_FLAG_ADV_100HALF; - if (cmd.advertising & ADVERTISE_100FULL) - bp->flags |= B44_FLAG_ADV_100FULL; - } else { - bp->flags |= B44_FLAG_FORCE_LINK; - if (cmd.speed == SPEED_100) - bp->flags |= B44_FLAG_100_BASE_T; - if (cmd.duplex == DUPLEX_FULL) - bp->flags |= B44_FLAG_FULL_DUPLEX; - } + if (!(bp->flags & B44_FLAG_INIT_COMPLETE)) + return -EAGAIN; - b44_setup_phy(bp); + /* We do not support gigabit. */ + if (cmd->autoneg == AUTONEG_ENABLE) { + if (cmd->advertising & + (ADVERTISED_1000baseT_Half | + ADVERTISED_1000baseT_Full)) + return -EINVAL; + } else if ((cmd->speed != SPEED_100 && + cmd->speed != SPEED_10) || + (cmd->duplex != DUPLEX_HALF && + cmd->duplex != DUPLEX_FULL)) { + return -EINVAL; + } - spin_unlock_irq(&bp->lock); + spin_lock_irq(&bp->lock); - return 0; + if (cmd->autoneg == AUTONEG_ENABLE) { + bp->flags &= ~B44_FLAG_FORCE_LINK; + bp->flags &= ~(B44_FLAG_ADV_10HALF | + B44_FLAG_ADV_10FULL | + B44_FLAG_ADV_100HALF | + B44_FLAG_ADV_100FULL); + if (cmd->advertising & ADVERTISE_10HALF) + bp->flags |= B44_FLAG_ADV_10HALF; + if (cmd->advertising & ADVERTISE_10FULL) + bp->flags |= B44_FLAG_ADV_10FULL; + if (cmd->advertising & ADVERTISE_100HALF) + bp->flags |= B44_FLAG_ADV_100HALF; + if (cmd->advertising & ADVERTISE_100FULL) + bp->flags |= B44_FLAG_ADV_100FULL; + } else { + bp->flags |= B44_FLAG_FORCE_LINK; + if (cmd->speed == SPEED_100) + bp->flags |= B44_FLAG_100_BASE_T; + if (cmd->duplex == DUPLEX_FULL) + bp->flags |= B44_FLAG_FULL_DUPLEX; } - case ETHTOOL_GMSGLVL: { - struct ethtool_value edata = { ETHTOOL_GMSGLVL }; - edata.data = bp->msg_enable; - if (copy_to_user(useraddr, &edata, sizeof(edata))) - return -EFAULT; - return 0; - } - case ETHTOOL_SMSGLVL: { - struct ethtool_value edata; - if (copy_from_user(&edata, useraddr, sizeof(edata))) - return -EFAULT; - bp->msg_enable = edata.data; - return 0; - } - case ETHTOOL_NWAY_RST: { - u32 bmcr; - int r; + b44_setup_phy(bp); - spin_lock_irq(&bp->lock); - b44_readphy(bp, MII_BMCR, &bmcr); - b44_readphy(bp, MII_BMCR, &bmcr); - r = -EINVAL; - if (bmcr & BMCR_ANENABLE) { - b44_writephy(bp, MII_BMCR, - bmcr | BMCR_ANRESTART); - r = 0; - } - spin_unlock_irq(&bp->lock); + spin_unlock_irq(&bp->lock); - return r; - } - case ETHTOOL_GLINK: { - struct ethtool_value edata = { ETHTOOL_GLINK }; - edata.data = netif_carrier_ok(bp->dev) ? 1 : 0; - if (copy_to_user(useraddr, &edata, sizeof(edata))) - return -EFAULT; - return 0; - } - case ETHTOOL_GRINGPARAM: { - struct ethtool_ringparam ering = { ETHTOOL_GRINGPARAM }; + return 0; +} - ering.rx_max_pending = B44_RX_RING_SIZE - 1; - ering.rx_pending = bp->rx_pending; +static void b44_get_ringparam(struct net_device *dev, + struct ethtool_ringparam *ering) +{ + struct b44 *bp = netdev_priv(dev); - /* XXX ethtool lacks a tx_max_pending, oops... */ + ering->rx_max_pending = B44_RX_RING_SIZE - 1; + ering->rx_pending = bp->rx_pending; - if (copy_to_user(useraddr, &ering, sizeof(ering))) - return -EFAULT; - return 0; - } - case ETHTOOL_SRINGPARAM: { - struct ethtool_ringparam ering; + /* XXX ethtool lacks a tx_max_pending, oops... */ +} - if (copy_from_user(&ering, useraddr, sizeof(ering))) - return -EFAULT; +static int b44_set_ringparam(struct net_device *dev, + struct ethtool_ringparam *ering) +{ + struct b44 *bp = netdev_priv(dev); - if ((ering.rx_pending > B44_RX_RING_SIZE - 1) || - (ering.rx_mini_pending != 0) || - (ering.rx_jumbo_pending != 0) || - (ering.tx_pending > B44_TX_RING_SIZE - 1)) - return -EINVAL; + if ((ering->rx_pending > B44_RX_RING_SIZE - 1) || + (ering->rx_mini_pending != 0) || + (ering->rx_jumbo_pending != 0) || + (ering->tx_pending > B44_TX_RING_SIZE - 1)) + return -EINVAL; - spin_lock_irq(&bp->lock); + spin_lock_irq(&bp->lock); - bp->rx_pending = ering.rx_pending; - bp->tx_pending = ering.tx_pending; + bp->rx_pending = ering->rx_pending; + bp->tx_pending = ering->tx_pending; - b44_halt(bp); - b44_init_rings(bp); - b44_init_hw(bp); - netif_wake_queue(bp->dev); - spin_unlock_irq(&bp->lock); + b44_halt(bp); + b44_init_rings(bp); + b44_init_hw(bp); + netif_wake_queue(bp->dev); + spin_unlock_irq(&bp->lock); - b44_enable_ints(bp); - - return 0; - } - case ETHTOOL_GPAUSEPARAM: { - struct ethtool_pauseparam epause = { ETHTOOL_GPAUSEPARAM }; + b44_enable_ints(bp); + + return 0; +} - epause.autoneg = - (bp->flags & B44_FLAG_PAUSE_AUTO) != 0; - epause.rx_pause = - (bp->flags & B44_FLAG_RX_PAUSE) != 0; - epause.tx_pause = - (bp->flags & B44_FLAG_TX_PAUSE) != 0; - if (copy_to_user(useraddr, &epause, sizeof(epause))) - return -EFAULT; - return 0; - } - case ETHTOOL_SPAUSEPARAM: { - struct ethtool_pauseparam epause; +static void b44_get_pauseparam(struct net_device *dev, + struct ethtool_pauseparam *epause) +{ + struct b44 *bp = netdev_priv(dev); - if (copy_from_user(&epause, useraddr, sizeof(epause))) - return -EFAULT; + epause->autoneg = + (bp->flags & B44_FLAG_PAUSE_AUTO) != 0; + epause->rx_pause = + (bp->flags & B44_FLAG_RX_PAUSE) != 0; + epause->tx_pause = + (bp->flags & B44_FLAG_TX_PAUSE) != 0; +} - spin_lock_irq(&bp->lock); - if (epause.autoneg) - bp->flags |= B44_FLAG_PAUSE_AUTO; - else - bp->flags &= ~B44_FLAG_PAUSE_AUTO; - if (epause.rx_pause) - bp->flags |= B44_FLAG_RX_PAUSE; - else - bp->flags &= ~B44_FLAG_RX_PAUSE; - if (epause.tx_pause) - bp->flags |= B44_FLAG_TX_PAUSE; - else - bp->flags &= ~B44_FLAG_TX_PAUSE; - if (bp->flags & B44_FLAG_PAUSE_AUTO) { - b44_halt(bp); - b44_init_rings(bp); - b44_init_hw(bp); - } else { - __b44_set_flow_ctrl(bp, bp->flags); - } - spin_unlock_irq(&bp->lock); +static int b44_set_pauseparam(struct net_device *dev, + struct ethtool_pauseparam *epause) +{ + struct b44 *bp = netdev_priv(dev); - b44_enable_ints(bp); - - return 0; + spin_lock_irq(&bp->lock); + if (epause->autoneg) + bp->flags |= B44_FLAG_PAUSE_AUTO; + else + bp->flags &= ~B44_FLAG_PAUSE_AUTO; + if (epause->rx_pause) + bp->flags |= B44_FLAG_RX_PAUSE; + else + bp->flags &= ~B44_FLAG_RX_PAUSE; + if (epause->tx_pause) + bp->flags |= B44_FLAG_TX_PAUSE; + else + bp->flags &= ~B44_FLAG_TX_PAUSE; + if (bp->flags & B44_FLAG_PAUSE_AUTO) { + b44_halt(bp); + b44_init_rings(bp); + b44_init_hw(bp); + } else { + __b44_set_flow_ctrl(bp, bp->flags); } - }; + spin_unlock_irq(&bp->lock); - return -EOPNOTSUPP; + b44_enable_ints(bp); + + return 0; } +static struct ethtool_ops b44_ethtool_ops = { + .get_drvinfo = b44_get_drvinfo, + .get_settings = b44_get_settings, + .set_settings = b44_set_settings, + .nway_reset = b44_nway_reset, + .get_link = ethtool_op_get_link, + .get_ringparam = b44_get_ringparam, + .set_ringparam = b44_set_ringparam, + .get_pauseparam = b44_get_pauseparam, + .set_pauseparam = b44_set_pauseparam, + .get_msglevel = b44_get_msglevel, + .set_msglevel = b44_set_msglevel, +}; + static int b44_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { struct mii_ioctl_data __user *data = (struct mii_ioctl_data __user *)&ifr->ifr_data; - struct b44 *bp = dev->priv; + struct b44 *bp = netdev_priv(dev); int err; - switch (cmd) { - case SIOCETHTOOL: - return b44_ethtool_ioctl(dev, (void __user*) ifr->ifr_data); - - case SIOCGMIIPHY: - data->phy_id = bp->phy_addr; - - /* fallthru */ - case SIOCGMIIREG: { - u32 mii_regval; - - spin_lock_irq(&bp->lock); - err = b44_readphy(bp, data->reg_num & 0x1f, &mii_regval); - spin_unlock_irq(&bp->lock); - - data->val_out = mii_regval; - - return err; - } - - case SIOCSMIIREG: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - spin_lock_irq(&bp->lock); - err = b44_writephy(bp, data->reg_num & 0x1f, data->val_in); - spin_unlock_irq(&bp->lock); - - return err; + spin_lock_irq(&bp->lock); + err = generic_mii_ioctl(&bp->mii_if, data, cmd, NULL); + spin_unlock_irq(&bp->lock); - default: - /* do nothing */ - break; - }; - return -EOPNOTSUPP; + return err; } /* Read 128-bytes of EEPROM. */ @@ -1772,7 +1743,7 @@ /* No interesting netdevice features in this card... */ dev->features |= 0; - bp = dev->priv; + bp = netdev_priv(dev); bp->pdev = pdev; bp->dev = dev; if (b44_debug >= 0) @@ -1806,6 +1777,7 @@ dev->watchdog_timeo = B44_TX_TIMEOUT; dev->change_mtu = b44_change_mtu; dev->irq = pdev->irq; + SET_ETHTOOL_OPS(dev, &b44_ethtool_ops); err = b44_get_invariants(bp); if (err) { @@ -1814,6 +1786,13 @@ goto err_out_iounmap; } + bp->mii_if.dev = dev; + bp->mii_if.mdio_read = b44_mii_read; + bp->mii_if.mdio_write = b44_mii_write; + bp->mii_if.phy_id = bp->phy_addr; + bp->mii_if.phy_id_mask = 0x1f; + bp->mii_if.reg_num_mask = 0x1f; + /* By default, advertise all speed/duplex settings. */ bp->flags |= (B44_FLAG_ADV_10HALF | B44_FLAG_ADV_10FULL | B44_FLAG_ADV_100HALF | B44_FLAG_ADV_100FULL); @@ -1859,8 +1838,10 @@ struct net_device *dev = pci_get_drvdata(pdev); if (dev) { + struct b44 *bp = netdev_priv(dev); + unregister_netdev(dev); - iounmap((void *) ((struct b44 *)(dev->priv))->regs); + iounmap((void *) bp->regs); free_netdev(dev); pci_release_regions(pdev); pci_disable_device(pdev); diff -Nru a/drivers/net/b44.h b/drivers/net/b44.h --- a/drivers/net/b44.h Tue May 4 22:12:59 2004 +++ b/drivers/net/b44.h Tue May 4 22:12:59 2004 @@ -542,6 +542,8 @@ u8 phy_addr; u8 mdc_port; u8 core_unit; + + struct mii_if_info mii_if; }; #endif /* _B44_H */ diff -Nru a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c --- a/drivers/net/e1000/e1000_ethtool.c Tue May 4 22:12:59 2004 +++ b/drivers/net/e1000/e1000_ethtool.c Tue May 4 22:12:59 2004 @@ -53,7 +53,7 @@ #define E1000_STAT(m) sizeof(((struct e1000_adapter *)0)->m), \ offsetof(struct e1000_adapter, m) -static struct e1000_stats e1000_gstrings_stats[] = { +static const struct e1000_stats e1000_gstrings_stats[] = { { "rx_packets", E1000_STAT(net_stats.rx_packets) }, { "tx_packets", E1000_STAT(net_stats.tx_packets) }, { "rx_bytes", E1000_STAT(net_stats.rx_bytes) }, @@ -100,9 +100,10 @@ }; #define E1000_TEST_LEN sizeof(e1000_gstrings_test) / ETH_GSTRING_LEN -static void -e1000_ethtool_gset(struct e1000_adapter *adapter, struct ethtool_cmd *ecmd) +static int +e1000_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) { + struct e1000_adapter *adapter = netdev_priv(dev); struct e1000_hw *hw = &adapter->hw; if(hw->media_type == e1000_media_type_copper) { @@ -169,11 +170,13 @@ } ecmd->autoneg = (hw->autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE); + return 0; } static int -e1000_ethtool_sset(struct e1000_adapter *adapter, struct ethtool_cmd *ecmd) +e1000_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) { + struct e1000_adapter *adapter = netdev_priv(dev); struct e1000_hw *hw = &adapter->hw; if(ecmd->autoneg == AUTONEG_ENABLE) { @@ -195,10 +198,11 @@ return 0; } -static int -e1000_ethtool_gpause(struct e1000_adapter *adapter, +static void +e1000_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *epause) { + struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; epause->autoneg = @@ -212,14 +216,13 @@ epause->rx_pause = 1; epause->tx_pause = 1; } - - return 0; } static int -e1000_ethtool_spause(struct e1000_adapter *adapter, +e1000_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *epause) { + struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; adapter->fc_autoneg = epause->autoneg; @@ -248,28 +251,95 @@ return 0; } +static u32 +e1000_get_rx_csum(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + return adapter->rx_csum; +} + +static int +e1000_set_rx_csum(struct net_device *netdev, u32 data) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + + adapter->rx_csum = data; + if(netif_running(netdev)) { + e1000_down(adapter); + e1000_up(adapter); + } else + e1000_reset(adapter); + return 0; +} + +static u32 +e1000_get_tx_csum(struct net_device *netdev) +{ + return (netdev->features & NETIF_F_HW_CSUM) != 0; +} + +static int +e1000_set_tx_csum(struct net_device *netdev, u32 data) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + + if(adapter->hw.mac_type < e1000_82543) + return data ? -EINVAL : 0; + + if (data) + netdev->features |= NETIF_F_HW_CSUM; + else + netdev->features &= ~NETIF_F_HW_CSUM; + return 0; +} + +static int +e1000_set_tso(struct net_device *netdev, u32 data) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + + if (adapter->hw.mac_type < e1000_82544 || + adapter->hw.mac_type == e1000_82547) + return data ? -EINVAL : 0; + + if (data) + netdev->features |= NETIF_F_TSO; + else + netdev->features &= ~NETIF_F_TSO; + return 0; +} + + static void -e1000_ethtool_gdrvinfo(struct e1000_adapter *adapter, - struct ethtool_drvinfo *drvinfo) +e1000_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *drvinfo) { + struct e1000_adapter *adapter = netdev_priv(dev); + strncpy(drvinfo->driver, e1000_driver_name, 32); strncpy(drvinfo->version, e1000_driver_version, 32); strncpy(drvinfo->fw_version, "N/A", 32); strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32); - drvinfo->n_stats = E1000_STATS_LEN; - drvinfo->testinfo_len = E1000_TEST_LEN; +} + +static int +e1000_get_regs_len(struct net_device *dev) +{ #define E1000_REGS_LEN 32 - drvinfo->regdump_len = E1000_REGS_LEN * sizeof(uint32_t); - drvinfo->eedump_len = adapter->hw.eeprom.word_size * 2; + return E1000_REGS_LEN * sizeof(uint32_t); } static void -e1000_ethtool_gregs(struct e1000_adapter *adapter, - struct ethtool_regs *regs, uint32_t *regs_buff) +e1000_get_regs(struct net_device *dev, + struct ethtool_regs *regs, void *p) { + struct e1000_adapter *adapter = netdev_priv(dev); struct e1000_hw *hw = &adapter->hw; + u32 *regs_buff = p; uint16_t phy_data; + memset(p, 0, E1000_REGS_LEN * sizeof(uint32_t)); + regs->version = (1 << 24) | (hw->revision_id << 16) | hw->device_id; regs_buff[0] = E1000_READ_REG(hw, CTRL); @@ -342,30 +412,36 @@ e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data); regs_buff[24] = (uint32_t)phy_data; /* phy local receiver status */ regs_buff[25] = regs_buff[24]; /* phy remote receiver status */ +} - return; +static int +e1000_get_eeprom_len(struct net_device *dev) +{ + struct e1000_adapter *adapter = netdev_priv(dev); + + return adapter->hw.eeprom.word_size * 2; } static int -e1000_ethtool_geeprom(struct e1000_adapter *adapter, - struct ethtool_eeprom *eeprom, uint16_t *eeprom_buff) +e1000_get_eeprom(struct net_device *dev, + struct ethtool_eeprom *eeprom, u8 *bytes) { + struct e1000_adapter *adapter = netdev_priv(dev); struct e1000_hw *hw = &adapter->hw; + uint16_t *eeprom_buff = (uint16_t *) bytes; int first_word, last_word; int ret_val = 0; uint16_t i; - if(eeprom->len == 0) { - ret_val = -EINVAL; - goto geeprom_error; - } + if(eeprom->len == 0) + return -EINVAL; eeprom->magic = hw->vendor_id | (hw->device_id << 16); - if(eeprom->offset > eeprom->offset + eeprom->len) { - ret_val = -EINVAL; - goto geeprom_error; - } + if(eeprom->offset > eeprom->offset + eeprom->len) + return -EINVAL; + + memset(bytes, 0, adapter->hw.eeprom.word_size*2); if((eeprom->offset + eeprom->len) > (hw->eeprom.word_size * 2)) eeprom->len = ((hw->eeprom.word_size * 2) - eeprom->offset); @@ -388,14 +464,14 @@ for (i = 0; i < last_word - first_word + 1; i++) le16_to_cpus(&eeprom_buff[i]); -geeprom_error: return ret_val; } static int -e1000_ethtool_seeprom(struct e1000_adapter *adapter, - struct ethtool_eeprom *eeprom, void *user_data) +e1000_set_eeprom(struct net_device *netdev, + struct ethtool_eeprom *eeprom, u8 *bytes) { + struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; uint16_t *eeprom_buff; void *ptr; @@ -439,11 +515,7 @@ for (i = 0; i < last_word - first_word + 1; i++) le16_to_cpus(&eeprom_buff[i]); - if((ret_val != 0) || copy_from_user(ptr, user_data, eeprom->len)) { - ret_val = -EFAULT; - goto seeprom_error; - } - + memcpy(ptr, bytes, eeprom->len); for (i = 0; i < last_word - first_word + 1; i++) eeprom_buff[i] = cpu_to_le16(eeprom_buff[i]); @@ -454,15 +526,15 @@ if((ret_val == 0) && first_word <= EEPROM_CHECKSUM_REG) e1000_update_eeprom_checksum(hw); -seeprom_error: kfree(eeprom_buff); return ret_val; } -static int -e1000_ethtool_gring(struct e1000_adapter *adapter, +static void +e1000_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) { + struct e1000_adapter *adapter = netdev_priv(netdev); e1000_mac_type mac_type = adapter->hw.mac_type; struct e1000_desc_ring *txdr = &adapter->tx_ring; struct e1000_desc_ring *rxdr = &adapter->rx_ring; @@ -477,13 +549,12 @@ ring->tx_pending = txdr->count; ring->rx_mini_pending = 0; ring->rx_jumbo_pending = 0; - - return 0; } + static int -e1000_ethtool_sring(struct e1000_adapter *adapter, - struct ethtool_ringparam *ring) +e1000_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) { + struct e1000_adapter *adapter = netdev_priv(netdev); int err; e1000_mac_type mac_type = adapter->hw.mac_type; struct e1000_desc_ring *txdr = &adapter->tx_ring; @@ -806,8 +877,6 @@ kfree(txdr->buffer_info); if(rxdr->buffer_info) kfree(rxdr->buffer_info); - - return; } static int @@ -939,8 +1008,6 @@ e1000_write_phy_reg(&adapter->hw, 30, 0x8FFC); e1000_write_phy_reg(&adapter->hw, 29, 0x001A); e1000_write_phy_reg(&adapter->hw, 30, 0x8FF0); - - return; } static void @@ -1257,11 +1324,19 @@ return *data; } + static int -e1000_ethtool_test(struct e1000_adapter *adapter, - struct ethtool_test *eth_test, uint64_t *data) +e1000_diag_test_count(struct net_device *dev) { - boolean_t if_running = netif_running(adapter->netdev); + return E1000_TEST_LEN; +} + +static void +e1000_diag_test(struct net_device *netdev, + struct ethtool_test *eth_test, u64 *data) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + boolean_t if_running = netif_running(netdev); if(eth_test->flags == ETH_TEST_FL_OFFLINE) { /* Offline tests */ @@ -1305,12 +1380,12 @@ data[2] = 0; data[3] = 0; } - return 0; } static void -e1000_ethtool_gwol(struct e1000_adapter *adapter, struct ethtool_wolinfo *wol) +e1000_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { + struct e1000_adapter *adapter = netdev_priv(dev); struct e1000_hw *hw = &adapter->hw; switch(adapter->hw.device_id) { @@ -1348,10 +1423,10 @@ return; } } - static int -e1000_ethtool_swol(struct e1000_adapter *adapter, struct ethtool_wolinfo *wol) +e1000_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { + struct e1000_adapter *adapter = netdev_priv(dev); struct e1000_hw *hw = &adapter->hw; switch(adapter->hw.device_id) { @@ -1408,8 +1483,13 @@ } static int -e1000_ethtool_led_blink(struct e1000_adapter *adapter, struct ethtool_value *id) +e1000_phys_id(struct net_device *netdev, u32 data) { + struct e1000_adapter *adapter = netdev_priv(netdev); + + if(!data || data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ)) + data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ); + if(!adapter->blink_timer.function) { init_timer(&adapter->blink_timer); adapter->blink_timer.function = e1000_led_blink_callback; @@ -1420,11 +1500,7 @@ mod_timer(&adapter->blink_timer, jiffies); set_current_state(TASK_INTERRUPTIBLE); - if(id->data) - schedule_timeout(id->data * HZ); - else - schedule_timeout(MAX_SCHEDULE_TIMEOUT); - + schedule_timeout(data * HZ); del_timer_sync(&adapter->blink_timer); e1000_led_off(&adapter->hw); clear_bit(E1000_LED_ON, &adapter->led_status); @@ -1433,345 +1509,89 @@ return 0; } -int -e1000_ethtool_ioctl(struct net_device *netdev, struct ifreq *ifr) +static int +e1000_nway_reset(struct net_device *netdev) { - struct e1000_adapter *adapter = netdev->priv; - void *addr = ifr->ifr_data; - uint32_t cmd; - - if(get_user(cmd, (uint32_t *) addr)) - return -EFAULT; - - switch(cmd) { - case ETHTOOL_GSET: { - struct ethtool_cmd ecmd = {ETHTOOL_GSET}; - e1000_ethtool_gset(adapter, &ecmd); - if(copy_to_user(addr, &ecmd, sizeof(ecmd))) - return -EFAULT; - return 0; - } - case ETHTOOL_SSET: { - struct ethtool_cmd ecmd; - if(copy_from_user(&ecmd, addr, sizeof(ecmd))) - return -EFAULT; - return e1000_ethtool_sset(adapter, &ecmd); - } - case ETHTOOL_GDRVINFO: { - struct ethtool_drvinfo drvinfo = {ETHTOOL_GDRVINFO}; - e1000_ethtool_gdrvinfo(adapter, &drvinfo); - if(copy_to_user(addr, &drvinfo, sizeof(drvinfo))) - return -EFAULT; - return 0; - } - case ETHTOOL_GSTRINGS: { - struct ethtool_gstrings gstrings = { ETHTOOL_GSTRINGS }; - char *strings = NULL; - int err = 0; - - if(copy_from_user(&gstrings, addr, sizeof(gstrings))) - return -EFAULT; - switch(gstrings.string_set) { - case ETH_SS_TEST: - gstrings.len = E1000_TEST_LEN; - strings = kmalloc(E1000_TEST_LEN * ETH_GSTRING_LEN, - GFP_KERNEL); - if(!strings) - return -ENOMEM; - memcpy(strings, e1000_gstrings_test, E1000_TEST_LEN * - ETH_GSTRING_LEN); - break; - case ETH_SS_STATS: { - int i; - gstrings.len = E1000_STATS_LEN; - strings = kmalloc(E1000_STATS_LEN * ETH_GSTRING_LEN, - GFP_KERNEL); - if(!strings) - return -ENOMEM; - for(i=0; i < E1000_STATS_LEN; i++) { - memcpy(&strings[i * ETH_GSTRING_LEN], - e1000_gstrings_stats[i].stat_string, - ETH_GSTRING_LEN); - } - break; - } - default: - return -EOPNOTSUPP; - } - if(copy_to_user(addr, &gstrings, sizeof(gstrings))) - err = -EFAULT; - addr += offsetof(struct ethtool_gstrings, data); - if(!err && copy_to_user(addr, strings, - gstrings.len * ETH_GSTRING_LEN)) - err = -EFAULT; - - kfree(strings); - return err; - } - case ETHTOOL_GREGS: { - struct ethtool_regs regs = {ETHTOOL_GREGS}; - uint32_t regs_buff[E1000_REGS_LEN]; - - if(copy_from_user(®s, addr, sizeof(regs))) - return -EFAULT; - memset(regs_buff, 0, sizeof(regs_buff)); - if (regs.len > E1000_REGS_LEN) - regs.len = E1000_REGS_LEN; - e1000_ethtool_gregs(adapter, ®s, regs_buff); - if(copy_to_user(addr, ®s, sizeof(regs))) - return -EFAULT; - - addr += offsetof(struct ethtool_regs, data); - if(copy_to_user(addr, regs_buff, regs.len)) - return -EFAULT; - - return 0; - } - case ETHTOOL_NWAY_RST: { - if(netif_running(netdev)) { - e1000_down(adapter); - e1000_up(adapter); - } - return 0; - } - case ETHTOOL_PHYS_ID: { - struct ethtool_value id; - if(copy_from_user(&id, addr, sizeof(id))) - return -EFAULT; - return e1000_ethtool_led_blink(adapter, &id); - } - case ETHTOOL_GLINK: { - struct ethtool_value link = {ETHTOOL_GLINK}; - link.data = netif_carrier_ok(netdev); - if(copy_to_user(addr, &link, sizeof(link))) - return -EFAULT; - return 0; - } - case ETHTOOL_GWOL: { - struct ethtool_wolinfo wol = {ETHTOOL_GWOL}; - e1000_ethtool_gwol(adapter, &wol); - if(copy_to_user(addr, &wol, sizeof(wol)) != 0) - return -EFAULT; - return 0; - } - case ETHTOOL_SWOL: { - struct ethtool_wolinfo wol; - if(copy_from_user(&wol, addr, sizeof(wol)) != 0) - return -EFAULT; - return e1000_ethtool_swol(adapter, &wol); - } - case ETHTOOL_GEEPROM: { - struct ethtool_eeprom eeprom = {ETHTOOL_GEEPROM}; - struct e1000_hw *hw = &adapter->hw; - uint16_t *eeprom_buff; - void *ptr; - int err = 0; - - if(copy_from_user(&eeprom, addr, sizeof(eeprom))) - return -EFAULT; - - eeprom_buff = kmalloc(hw->eeprom.word_size * 2, GFP_KERNEL); - - if(!eeprom_buff) - return -ENOMEM; - - if((err = e1000_ethtool_geeprom(adapter, &eeprom, - eeprom_buff))) - goto err_geeprom_ioctl; - - if(copy_to_user(addr, &eeprom, sizeof(eeprom))) { - err = -EFAULT; - goto err_geeprom_ioctl; - } - - addr += offsetof(struct ethtool_eeprom, data); - ptr = ((void *)eeprom_buff) + (eeprom.offset & 1); - - if(copy_to_user(addr, ptr, eeprom.len)) - err = -EFAULT; - -err_geeprom_ioctl: - kfree(eeprom_buff); - return err; - } - case ETHTOOL_SEEPROM: { - struct ethtool_eeprom eeprom; - - if(copy_from_user(&eeprom, addr, sizeof(eeprom))) - return -EFAULT; - - addr += offsetof(struct ethtool_eeprom, data); - return e1000_ethtool_seeprom(adapter, &eeprom, addr); - } - case ETHTOOL_GRINGPARAM: { - struct ethtool_ringparam ering = {ETHTOOL_GRINGPARAM}; - e1000_ethtool_gring(adapter, &ering); - if(copy_to_user(addr, &ering, sizeof(ering))) - return -EFAULT; - return 0; - } - case ETHTOOL_SRINGPARAM: { - struct ethtool_ringparam ering; - if(copy_from_user(&ering, addr, sizeof(ering))) - return -EFAULT; - return e1000_ethtool_sring(adapter, &ering); - } - case ETHTOOL_GPAUSEPARAM: { - struct ethtool_pauseparam epause = {ETHTOOL_GPAUSEPARAM}; - e1000_ethtool_gpause(adapter, &epause); - if(copy_to_user(addr, &epause, sizeof(epause))) - return -EFAULT; - return 0; - } - case ETHTOOL_SPAUSEPARAM: { - struct ethtool_pauseparam epause; - if(copy_from_user(&epause, addr, sizeof(epause))) - return -EFAULT; - return e1000_ethtool_spause(adapter, &epause); - } - case ETHTOOL_GSTATS: { - struct { - struct ethtool_stats eth_stats; - uint64_t data[E1000_STATS_LEN]; - } stats = { {ETHTOOL_GSTATS, E1000_STATS_LEN} }; - int i; - - e1000_update_stats(adapter); - for(i = 0; i < E1000_STATS_LEN; i++) - stats.data[i] = (e1000_gstrings_stats[i].sizeof_stat == - sizeof(uint64_t)) ? - *(uint64_t *)((char *)adapter + - e1000_gstrings_stats[i].stat_offset) : - *(uint32_t *)((char *)adapter + - e1000_gstrings_stats[i].stat_offset); - if(copy_to_user(addr, &stats, sizeof(stats))) - return -EFAULT; - return 0; - } - case ETHTOOL_TEST: { - struct { - struct ethtool_test eth_test; - uint64_t data[E1000_TEST_LEN]; - } test = { {ETHTOOL_TEST} }; - int err; - - if(copy_from_user(&test.eth_test, addr, sizeof(test.eth_test))) - return -EFAULT; - - test.eth_test.len = E1000_TEST_LEN; - - if((err = e1000_ethtool_test(adapter, &test.eth_test, - test.data))) - return err; - - if(copy_to_user(addr, &test, sizeof(test)) != 0) - return -EFAULT; - return 0; - } - case ETHTOOL_GRXCSUM: { - struct ethtool_value edata = { ETHTOOL_GRXCSUM }; - - edata.data = adapter->rx_csum; - if (copy_to_user(addr, &edata, sizeof(edata))) - return -EFAULT; - return 0; - } - case ETHTOOL_SRXCSUM: { - struct ethtool_value edata; - - if (copy_from_user(&edata, addr, sizeof(edata))) - return -EFAULT; - adapter->rx_csum = edata.data; - if(netif_running(netdev)) { - e1000_down(adapter); - e1000_up(adapter); - } else - e1000_reset(adapter); - return 0; - } - case ETHTOOL_GTXCSUM: { - struct ethtool_value edata = { ETHTOOL_GTXCSUM }; + struct e1000_adapter *adapter = netdev_priv(netdev); - edata.data = - (netdev->features & NETIF_F_HW_CSUM) != 0; - if (copy_to_user(addr, &edata, sizeof(edata))) - return -EFAULT; - return 0; + if(netif_running(netdev)) { + e1000_down(adapter); + e1000_up(adapter); } - case ETHTOOL_STXCSUM: { - struct ethtool_value edata; - - if (copy_from_user(&edata, addr, sizeof(edata))) - return -EFAULT; - - if(adapter->hw.mac_type < e1000_82543) { - if (edata.data != 0) - return -EINVAL; - return 0; - } + return 0; +} - if (edata.data) - netdev->features |= NETIF_F_HW_CSUM; - else - netdev->features &= ~NETIF_F_HW_CSUM; +static int +e1000_get_stats_count(struct net_device *dev) +{ + return E1000_STATS_LEN; +} - return 0; - } - case ETHTOOL_GSG: { - struct ethtool_value edata = { ETHTOOL_GSG }; +static void +e1000_get_ethtool_stats(struct net_device *netdev, + struct ethtool_stats *stats, u64 *data) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + int i; - edata.data = - (netdev->features & NETIF_F_SG) != 0; - if (copy_to_user(addr, &edata, sizeof(edata))) - return -EFAULT; - return 0; + e1000_update_stats(adapter); + for(i = 0; i < E1000_STATS_LEN; i++) { + char *p = (char *) adapter + e1000_gstrings_stats[i].stat_offset; + data[i] = (e1000_gstrings_stats[i].sizeof_stat == sizeof(uint64_t)) + ? *(uint64_t *)p : *(uint32_t *)p; } - case ETHTOOL_SSG: { - struct ethtool_value edata; - - if (copy_from_user(&edata, addr, sizeof(edata))) - return -EFAULT; - - if (edata.data) - netdev->features |= NETIF_F_SG; - else - netdev->features &= ~NETIF_F_SG; +} - return 0; - } -#ifdef NETIF_F_TSO - case ETHTOOL_GTSO: { - struct ethtool_value edata = { ETHTOOL_GTSO }; - - edata.data = (netdev->features & NETIF_F_TSO) != 0; - if (copy_to_user(addr, &edata, sizeof(edata))) - return -EFAULT; - return 0; - } - case ETHTOOL_STSO: { - struct ethtool_value edata; +static void +e1000_get_strings(struct net_device *netdev, u32 string_set, u8 *data) +{ + int i; - if (copy_from_user(&edata, addr, sizeof(edata))) - return -EFAULT; + switch(string_set) { + case ETH_SS_TEST: + memcpy(data, e1000_gstrings_test, E1000_TEST_LEN * ETH_GSTRING_LEN); + break; - if ((adapter->hw.mac_type < e1000_82544) || - (adapter->hw.mac_type == e1000_82547)) { - if (edata.data != 0) - return -EINVAL; - return 0; + case ETH_SS_STATS: + for(i=0; i < E1000_STATS_LEN; i++) { + memcpy(data + i * ETH_GSTRING_LEN, + e1000_gstrings_stats[i].stat_string, + ETH_GSTRING_LEN); } - - if (edata.data) - netdev->features |= NETIF_F_TSO; - else - netdev->features &= ~NETIF_F_TSO; - - return 0; - } -#endif - default: - return -EOPNOTSUPP; + break; } } +struct ethtool_ops e1000_ethtool_ops = { + .get_settings = e1000_get_settings, + .set_settings = e1000_set_settings, + .get_drvinfo = e1000_get_drvinfo, + .get_regs_len = e1000_get_regs_len, + .get_regs = e1000_get_regs, + .get_wol = e1000_get_wol, + .set_wol = e1000_set_wol, + .nway_reset = e1000_nway_reset, + .get_link = ethtool_op_get_link, + .get_eeprom_len = e1000_get_eeprom_len, + .get_eeprom = e1000_get_eeprom, + .set_eeprom = e1000_set_eeprom, + .get_ringparam = e1000_get_ringparam, + .set_ringparam = e1000_set_ringparam, + .get_pauseparam = e1000_get_pauseparam, + .set_pauseparam = e1000_set_pauseparam, + .get_rx_csum = e1000_get_rx_csum, + .set_rx_csum = e1000_set_rx_csum, + .get_tx_csum = e1000_get_tx_csum, + .set_tx_csum = e1000_set_tx_csum, + .get_sg = ethtool_op_get_sg, + .set_sg = ethtool_op_set_sg, + .get_tso = ethtool_op_get_tso, + .set_tso = e1000_set_tso, + .self_test_count = e1000_diag_test_count, + .self_test = e1000_diag_test, + .get_strings = e1000_get_strings, + .phys_id = e1000_phys_id, + .get_stats_count = e1000_get_stats_count, + .get_ethtool_stats = e1000_get_ethtool_stats, +}; diff -Nru a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c --- a/drivers/net/e1000/e1000_main.c Tue May 4 22:12:59 2004 +++ b/drivers/net/e1000/e1000_main.c Tue May 4 22:12:59 2004 @@ -167,9 +167,9 @@ static boolean_t e1000_clean_rx_irq(struct e1000_adapter *adapter); #endif static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter); -static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd); -static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, - int cmd); + +static int e1000_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd); +extern struct ethtool_ops e1000_ethtool_ops; static void e1000_enter_82542_rst(struct e1000_adapter *adapter); static void e1000_leave_82542_rst(struct e1000_adapter *adapter); static inline void e1000_rx_checksum(struct e1000_adapter *adapter, @@ -206,7 +206,6 @@ /* Exported from other modules */ extern void e1000_check_options(struct e1000_adapter *adapter); -extern int e1000_ethtool_ioctl(struct net_device *netdev, struct ifreq *ifr); static struct pci_driver e1000_driver = { .name = e1000_driver_name, @@ -445,7 +444,8 @@ netdev->set_multicast_list = &e1000_set_multi; netdev->set_mac_address = &e1000_set_mac; netdev->change_mtu = &e1000_change_mtu; - netdev->do_ioctl = &e1000_ioctl; + netdev->do_ioctl = &e1000_do_ioctl; + SET_ETHTOOL_OPS(netdev, &e1000_ethtool_ops); netdev->tx_timeout = &e1000_tx_timeout; netdev->watchdog_timeo = 5 * HZ; #ifdef CONFIG_E1000_NAPI @@ -2498,37 +2498,16 @@ adapter->smartspeed = 0; } -/** - * e1000_ioctl - - * @netdev: - * @ifreq: - * @cmd: - **/ - -static int -e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) -{ - switch (cmd) { - case SIOCGMIIPHY: - case SIOCGMIIREG: - case SIOCSMIIREG: - return e1000_mii_ioctl(netdev, ifr, cmd); - case SIOCETHTOOL: - return e1000_ethtool_ioctl(netdev, ifr); - default: - return -EOPNOTSUPP; - } -} /** - * e1000_mii_ioctl - + * e1000_do_ioctl - * @netdev: * @ifreq: * @cmd: **/ static int -e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) +e1000_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) { struct e1000_adapter *adapter = netdev->priv; struct mii_ioctl_data *data = (struct mii_ioctl_data *)&ifr->ifr_data; diff -Nru a/drivers/net/epic100.c b/drivers/net/epic100.c --- a/drivers/net/epic100.c Tue May 4 22:12:59 2004 +++ b/drivers/net/epic100.c Tue May 4 22:12:59 2004 @@ -77,8 +77,6 @@ These may be modified when a driver module is loaded.*/ static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ -/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ -static int max_interrupt_work = 32; /* Used to pass the full-duplex flag, etc. */ #define MAX_UNITS 8 /* More are supported, limit only on options */ @@ -96,9 +94,9 @@ 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 TX_QUEUE_LEN 10 /* Limit ring entries actually used. */ -#define RX_RING_SIZE 32 +#define TX_RING_SIZE 256 +#define TX_QUEUE_LEN 240 /* Limit ring entries actually used. */ +#define RX_RING_SIZE 256 #define TX_TOTAL_SIZE TX_RING_SIZE*sizeof(struct epic_tx_desc) #define RX_TOTAL_SIZE RX_RING_SIZE*sizeof(struct epic_rx_desc) @@ -155,12 +153,10 @@ MODULE_LICENSE("GPL"); MODULE_PARM(debug, "i"); -MODULE_PARM(max_interrupt_work, "i"); MODULE_PARM(rx_copybreak, "i"); MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); MODULE_PARM_DESC(debug, "EPIC/100 debug level (0-5)"); -MODULE_PARM_DESC(max_interrupt_work, "EPIC/100 maximum events handled per interrupt"); MODULE_PARM_DESC(options, "EPIC/100: Bits 0-3: media type, bit 4: full duplex"); MODULE_PARM_DESC(rx_copybreak, "EPIC/100 copy breakpoint for copy-only-tiny-frames"); MODULE_PARM_DESC(full_duplex, "EPIC/100 full duplex setting(s) (1)"); @@ -292,6 +288,12 @@ StopTxDMA=0x20, StopRxDMA=0x40, RestartTx=0x80, }; +#define EpicRemoved 0xffffffff /* Chip failed or removed (CardBus) */ + +#define EpicNapiEvent (TxEmpty | TxDone | \ + RxDone | RxStarted | RxEarlyWarn | RxOverflow | RxFull) +#define EpicNormalEvent (0x0000ffff & ~EpicNapiEvent) + static u16 media2miictl[16] = { 0, 0x0C00, 0x0C00, 0x2000, 0x0100, 0x2100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; @@ -330,9 +332,12 @@ /* Ring pointers. */ spinlock_t lock; /* Group with Tx control cache line. */ + spinlock_t napi_lock; + unsigned int reschedule_in_poll; unsigned int cur_tx, dirty_tx; unsigned int cur_rx, dirty_rx; + u32 irq_mask; unsigned int rx_buf_sz; /* Based on MTU+slack. */ struct pci_dev *pci_dev; /* PCI bus location. */ @@ -359,7 +364,8 @@ static void epic_tx_timeout(struct net_device *dev); static void epic_init_ring(struct net_device *dev); static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev); -static int epic_rx(struct net_device *dev); +static int epic_rx(struct net_device *dev, int budget); +static int epic_poll(struct net_device *dev, int *budget); static irqreturn_t epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs); static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static struct ethtool_ops netdev_ethtool_ops; @@ -378,7 +384,7 @@ int irq; struct net_device *dev; struct epic_private *ep; - int i, option = 0, duplex = 0; + int i, ret, option = 0, duplex = 0; void *ring_space; dma_addr_t ring_dma; @@ -392,29 +398,33 @@ card_idx++; - i = pci_enable_device(pdev); - if (i) - return i; + ret = pci_enable_device(pdev); + if (ret) + goto out; irq = pdev->irq; if (pci_resource_len(pdev, 0) < pci_id_tbl[chip_idx].io_size) { printk (KERN_ERR "card %d: no PCI region space\n", card_idx); - return -ENODEV; + ret = -ENODEV; + goto err_out_disable; } pci_set_master(pdev); + ret = pci_request_regions(pdev, DRV_NAME); + if (ret < 0) + goto err_out_disable; + + ret = -ENOMEM; + dev = alloc_etherdev(sizeof (*ep)); if (!dev) { printk (KERN_ERR "card %d: no memory for eth device\n", card_idx); - return -ENOMEM; + goto err_out_free_res; } SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); - if (pci_request_regions(pdev, DRV_NAME)) - goto err_out_free_netdev; - #ifdef USE_IO_OPS ioaddr = pci_resource_start (pdev, 0); #else @@ -422,7 +432,7 @@ ioaddr = (long) ioremap (ioaddr, pci_resource_len (pdev, 1)); if (!ioaddr) { printk (KERN_ERR DRV_NAME " %d: ioremap failed\n", card_idx); - goto err_out_free_res; + goto err_out_free_netdev; } #endif @@ -459,7 +469,9 @@ dev->base_addr = ioaddr; dev->irq = irq; - spin_lock_init (&ep->lock); + spin_lock_init(&ep->lock); + spin_lock_init(&ep->napi_lock); + ep->reschedule_in_poll = 0; /* Bring the chip out of low-power mode. */ outl(0x4200, ioaddr + GENCTL); @@ -489,6 +501,9 @@ ep->pci_dev = pdev; ep->chip_id = chip_idx; ep->chip_flags = pci_id_tbl[chip_idx].drv_flags; + ep->irq_mask = + (ep->chip_flags & TYPE2_INTR ? PCIBusErr175 : PCIBusErr170) + | CntFull | TxUnderrun | EpicNapiEvent; /* Find the connected MII xcvrs. Doing this in open() would allow detecting external xcvrs later, but @@ -543,10 +558,12 @@ dev->ethtool_ops = &netdev_ethtool_ops; dev->watchdog_timeo = TX_TIMEOUT; dev->tx_timeout = &epic_tx_timeout; + dev->poll = epic_poll; + dev->weight = 64; - i = register_netdev(dev); - if (i) - goto err_out_unmap_tx; + ret = register_netdev(dev); + if (ret < 0) + goto err_out_unmap_rx; printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", dev->name, pci_id_tbl[chip_idx].name, ioaddr, dev->irq); @@ -554,19 +571,24 @@ printk("%2.2x:", dev->dev_addr[i]); printk("%2.2x.\n", dev->dev_addr[i]); - return 0; +out: + return ret; +err_out_unmap_rx: + pci_free_consistent(pdev, RX_TOTAL_SIZE, ep->rx_ring, ep->rx_ring_dma); err_out_unmap_tx: pci_free_consistent(pdev, TX_TOTAL_SIZE, ep->tx_ring, ep->tx_ring_dma); err_out_iounmap: #ifndef USE_IO_OPS iounmap(ioaddr); -err_out_free_res: -#endif - pci_release_regions(pdev); err_out_free_netdev: +#endif free_netdev(dev); - return -ENODEV; +err_out_free_res: + pci_release_regions(pdev); +err_out_disable: + pci_disable_device(pdev); + goto out; } /* Serial EEPROM section. */ @@ -592,6 +614,38 @@ #define EE_READ256_CMD (6 << 8) #define EE_ERASE_CMD (7 << 6) +static void epic_disable_int(struct net_device *dev, struct epic_private *ep) +{ + long ioaddr = dev->base_addr; + + outl(0x00000000, ioaddr + INTMASK); +} + +static inline void __epic_pci_commit(long ioaddr) +{ +#ifndef USE_IO_OPS + inl(ioaddr + INTMASK); +#endif +} + +static inline void epic_napi_irq_off(struct net_device *dev, + struct epic_private *ep) +{ + long ioaddr = dev->base_addr; + + outl(ep->irq_mask & ~EpicNapiEvent, ioaddr + INTMASK); + __epic_pci_commit(ioaddr); +} + +static inline void epic_napi_irq_on(struct net_device *dev, + struct epic_private *ep) +{ + long ioaddr = dev->base_addr; + + /* No need to commit possible posted write */ + outl(ep->irq_mask | EpicNapiEvent, ioaddr + INTMASK); +} + static int __devinit read_eeprom(long ioaddr, int location) { int i; @@ -752,9 +806,8 @@ /* Enable interrupts by setting the interrupt mask. */ outl((ep->chip_flags & TYPE2_INTR ? PCIBusErr175 : PCIBusErr170) - | CntFull | TxUnderrun | TxDone | TxEmpty - | RxError | RxOverflow | RxFull | RxHeader | RxDone, - ioaddr + INTMASK); + | CntFull | TxUnderrun + | RxError | RxHeader | EpicNapiEvent, ioaddr + INTMASK); if (debug > 1) printk(KERN_DEBUG "%s: epic_open() ioaddr %lx IRQ %d status %4.4x " @@ -795,7 +848,7 @@ } /* Remove the packets on the Rx queue. */ - epic_rx(dev); + epic_rx(dev, RX_RING_SIZE); } static void epic_restart(struct net_device *dev) @@ -841,9 +894,9 @@ /* Enable interrupts by setting the interrupt mask. */ outl((ep->chip_flags & TYPE2_INTR ? PCIBusErr175 : PCIBusErr170) - | CntFull | TxUnderrun | TxDone | TxEmpty - | RxError | RxOverflow | RxFull | RxHeader | RxDone, - ioaddr + INTMASK); + | CntFull | TxUnderrun + | RxError | RxHeader | EpicNapiEvent, ioaddr + INTMASK); + printk(KERN_DEBUG "%s: epic_restart() done, cmd status %4.4x, ctl %4.4x" " interrupt %4.4x.\n", dev->name, (int)inl(ioaddr + COMMAND), (int)inl(ioaddr + GENCTL), @@ -929,7 +982,6 @@ int i; ep->tx_full = 0; - ep->lock = (spinlock_t) SPIN_LOCK_UNLOCKED; ep->dirty_tx = ep->cur_tx = 0; ep->cur_rx = ep->dirty_rx = 0; ep->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); @@ -1029,6 +1081,76 @@ return 0; } +static void epic_tx_error(struct net_device *dev, struct epic_private *ep, + int status) +{ + struct net_device_stats *stats = &ep->stats; + +#ifndef final_version + /* There was an major error, log it. */ + if (debug > 1) + printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n", + dev->name, status); +#endif + stats->tx_errors++; + if (status & 0x1050) + stats->tx_aborted_errors++; + if (status & 0x0008) + stats->tx_carrier_errors++; + if (status & 0x0040) + stats->tx_window_errors++; + if (status & 0x0010) + stats->tx_fifo_errors++; +} + +static void epic_tx(struct net_device *dev, struct epic_private *ep) +{ + unsigned int dirty_tx, cur_tx; + + /* + * Note: if this lock becomes a problem we can narrow the locked + * region at the cost of occasionally grabbing the lock more times. + */ + cur_tx = ep->cur_tx; + for (dirty_tx = ep->dirty_tx; cur_tx - dirty_tx > 0; dirty_tx++) { + struct sk_buff *skb; + int entry = dirty_tx % TX_RING_SIZE; + int txstatus = le32_to_cpu(ep->tx_ring[entry].txstatus); + + if (txstatus & DescOwn) + break; /* It still hasn't been Txed */ + + if (likely(txstatus & 0x0001)) { + ep->stats.collisions += (txstatus >> 8) & 15; + ep->stats.tx_packets++; + ep->stats.tx_bytes += ep->tx_skbuff[entry]->len; + } else + epic_tx_error(dev, ep, txstatus); + + /* Free the original skb. */ + skb = ep->tx_skbuff[entry]; + pci_unmap_single(ep->pci_dev, ep->tx_ring[entry].bufaddr, + skb->len, PCI_DMA_TODEVICE); + dev_kfree_skb_irq(skb); + ep->tx_skbuff[entry] = 0; + } + +#ifndef final_version + if (cur_tx - dirty_tx > TX_RING_SIZE) { + printk(KERN_WARNING + "%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n", + dev->name, dirty_tx, cur_tx, ep->tx_full); + dirty_tx += TX_RING_SIZE; + } +#endif + ep->dirty_tx = dirty_tx; + if (ep->tx_full && cur_tx - dirty_tx < TX_QUEUE_LEN - 4) { + /* The ring is no longer full, allow new TX entries. */ + ep->tx_full = 0; + netif_wake_queue(dev); + } +} + /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */ static irqreturn_t epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs) @@ -1036,135 +1158,71 @@ struct net_device *dev = dev_instance; struct epic_private *ep = dev->priv; long ioaddr = dev->base_addr; - int status, boguscnt = max_interrupt_work; unsigned int handled = 0; + int status; - do { - status = inl(ioaddr + INTSTAT); - /* Acknowledge all of the current interrupt sources ASAP. */ - outl(status & 0x00007fff, ioaddr + INTSTAT); - - if (debug > 4) - printk(KERN_DEBUG "%s: Interrupt, status=%#8.8x new " - "intstat=%#8.8x.\n", - dev->name, status, (int)inl(ioaddr + INTSTAT)); - - if ((status & IntrSummary) == 0) - break; - handled = 1; + status = inl(ioaddr + INTSTAT); + /* Acknowledge all of the current interrupt sources ASAP. */ + outl(status & EpicNormalEvent, ioaddr + INTSTAT); - if (status & (RxDone | RxStarted | RxEarlyWarn | RxOverflow)) - epic_rx(dev); + if (debug > 4) { + printk(KERN_DEBUG "%s: Interrupt, status=%#8.8x new " + "intstat=%#8.8x.\n", dev->name, status, + (int)inl(ioaddr + INTSTAT)); + } - if (status & (TxEmpty | TxDone)) { - unsigned int dirty_tx, cur_tx; + if ((status & IntrSummary) == 0) + goto out; - /* Note: if this lock becomes a problem we can narrow the locked - region at the cost of occasionally grabbing the lock more - times. */ - spin_lock(&ep->lock); - cur_tx = ep->cur_tx; - dirty_tx = ep->dirty_tx; - for (; cur_tx - dirty_tx > 0; dirty_tx++) { - struct sk_buff *skb; - int entry = dirty_tx % TX_RING_SIZE; - int txstatus = le32_to_cpu(ep->tx_ring[entry].txstatus); + handled = 1; - if (txstatus & DescOwn) - break; /* It still hasn't been Txed */ + if ((status & EpicNapiEvent) && !ep->reschedule_in_poll) { + spin_lock(&ep->napi_lock); + if (netif_rx_schedule_prep(dev)) { + epic_napi_irq_off(dev, ep); + __netif_rx_schedule(dev); + } else + ep->reschedule_in_poll++; + spin_unlock(&ep->napi_lock); + } + status &= ~EpicNapiEvent; - if ( ! (txstatus & 0x0001)) { - /* There was an major error, log it. */ -#ifndef final_version - if (debug > 1) - printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n", - dev->name, txstatus); -#endif - ep->stats.tx_errors++; - if (txstatus & 0x1050) ep->stats.tx_aborted_errors++; - if (txstatus & 0x0008) ep->stats.tx_carrier_errors++; - if (txstatus & 0x0040) ep->stats.tx_window_errors++; - if (txstatus & 0x0010) ep->stats.tx_fifo_errors++; - } else { - ep->stats.collisions += (txstatus >> 8) & 15; - ep->stats.tx_packets++; - ep->stats.tx_bytes += ep->tx_skbuff[entry]->len; - } - - /* Free the original skb. */ - skb = ep->tx_skbuff[entry]; - pci_unmap_single(ep->pci_dev, ep->tx_ring[entry].bufaddr, - skb->len, PCI_DMA_TODEVICE); - dev_kfree_skb_irq(skb); - ep->tx_skbuff[entry] = 0; - } + /* Check uncommon events all at once. */ + if (status & (CntFull | TxUnderrun | PCIBusErr170 | PCIBusErr175)) { + if (status == EpicRemoved) + goto out; -#ifndef final_version - if (cur_tx - dirty_tx > TX_RING_SIZE) { - printk(KERN_WARNING "%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n", - dev->name, dirty_tx, cur_tx, ep->tx_full); - dirty_tx += TX_RING_SIZE; - } -#endif - ep->dirty_tx = dirty_tx; - if (ep->tx_full - && cur_tx - dirty_tx < TX_QUEUE_LEN - 4) { - /* The ring is no longer full, allow new TX entries. */ - ep->tx_full = 0; - spin_unlock(&ep->lock); - netif_wake_queue(dev); - } else - spin_unlock(&ep->lock); - } + /* Always update the error counts to avoid overhead later. */ + ep->stats.rx_missed_errors += inb(ioaddr + MPCNT); + ep->stats.rx_frame_errors += inb(ioaddr + ALICNT); + ep->stats.rx_crc_errors += inb(ioaddr + CRCCNT); - /* Check uncommon events all at once. */ - if (status & (CntFull | TxUnderrun | RxOverflow | RxFull | - PCIBusErr170 | PCIBusErr175)) { - if (status == 0xffffffff) /* Chip failed or removed (CardBus). */ - break; - /* Always update the error counts to avoid overhead later. */ - ep->stats.rx_missed_errors += inb(ioaddr + MPCNT); - ep->stats.rx_frame_errors += inb(ioaddr + ALICNT); - ep->stats.rx_crc_errors += inb(ioaddr + CRCCNT); - - if (status & TxUnderrun) { /* Tx FIFO underflow. */ - ep->stats.tx_fifo_errors++; - outl(ep->tx_threshold += 128, ioaddr + TxThresh); - /* Restart the transmit process. */ - outl(RestartTx, ioaddr + COMMAND); - } - if (status & RxOverflow) { /* Missed a Rx frame. */ - ep->stats.rx_errors++; - } - if (status & (RxOverflow | RxFull)) - outw(RxQueued, ioaddr + COMMAND); - if (status & PCIBusErr170) { - printk(KERN_ERR "%s: PCI Bus Error! EPIC status %4.4x.\n", - dev->name, status); - epic_pause(dev); - epic_restart(dev); - } - /* Clear all error sources. */ - outl(status & 0x7f18, ioaddr + INTSTAT); + if (status & TxUnderrun) { /* Tx FIFO underflow. */ + ep->stats.tx_fifo_errors++; + outl(ep->tx_threshold += 128, ioaddr + TxThresh); + /* Restart the transmit process. */ + outl(RestartTx, ioaddr + COMMAND); } - if (--boguscnt < 0) { - printk(KERN_ERR "%s: Too much work at interrupt, " - "IntrStatus=0x%8.8x.\n", - dev->name, status); - /* Clear all interrupt sources. */ - outl(0x0001ffff, ioaddr + INTSTAT); - break; + if (status & PCIBusErr170) { + printk(KERN_ERR "%s: PCI Bus Error! status %4.4x.\n", + dev->name, status); + epic_pause(dev); + epic_restart(dev); } - } while (1); + /* Clear all error sources. */ + outl(status & 0x7f18, ioaddr + INTSTAT); + } - if (debug > 3) - printk(KERN_DEBUG "%s: exiting interrupt, intr_status=%#4.4x.\n", - dev->name, status); +out: + if (debug > 3) { + printk(KERN_DEBUG "%s: exit interrupt, intr_status=%#4.4x.\n", + dev->name, status); + } return IRQ_RETVAL(handled); } -static int epic_rx(struct net_device *dev) +static int epic_rx(struct net_device *dev, int budget) { struct epic_private *ep = dev->priv; int entry = ep->cur_rx % RX_RING_SIZE; @@ -1174,6 +1232,10 @@ if (debug > 4) printk(KERN_DEBUG " In epic_rx(), entry %d %8.8x.\n", entry, ep->rx_ring[entry].rxstatus); + + if (rx_work_limit > budget) + rx_work_limit = budget; + /* If we own the next entry, it's a new packet. Send it up. */ while ((ep->rx_ring[entry].rxstatus & cpu_to_le32(DescOwn)) == 0) { int status = le32_to_cpu(ep->rx_ring[entry].rxstatus); @@ -1234,7 +1296,7 @@ ep->rx_skbuff[entry] = NULL; } skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); + netif_receive_skb(skb); dev->last_rx = jiffies; ep->stats.rx_packets++; ep->stats.rx_bytes += pkt_len; @@ -1262,6 +1324,65 @@ return work_done; } +static void epic_rx_err(struct net_device *dev, struct epic_private *ep) +{ + long ioaddr = dev->base_addr; + int status; + + status = inl(ioaddr + INTSTAT); + + if (status == EpicRemoved) + return; + if (status & RxOverflow) /* Missed a Rx frame. */ + ep->stats.rx_errors++; + if (status & (RxOverflow | RxFull)) + outw(RxQueued, ioaddr + COMMAND); +} + +static int epic_poll(struct net_device *dev, int *budget) +{ + struct epic_private *ep = dev->priv; + int work_done, orig_budget; + long ioaddr = dev->base_addr; + + orig_budget = (*budget > dev->quota) ? dev->quota : *budget; + +rx_action: + + epic_tx(dev, ep); + + work_done = epic_rx(dev, *budget); + + epic_rx_err(dev, ep); + + *budget -= work_done; + dev->quota -= work_done; + + if (netif_running(dev) && (work_done < orig_budget)) { + unsigned long flags; + int more; + + /* A bit baroque but it avoids a (space hungry) spin_unlock */ + + spin_lock_irqsave(&ep->napi_lock, flags); + + more = ep->reschedule_in_poll; + if (!more) { + __netif_rx_complete(dev); + outl(EpicNapiEvent, ioaddr + INTSTAT); + epic_napi_irq_on(dev, ep); + } else + ep->reschedule_in_poll--; + + spin_unlock_irqrestore(&ep->napi_lock, flags); + + if (more) + goto rx_action; + } + + return (work_done >= orig_budget); +} + static int epic_close(struct net_device *dev) { long ioaddr = dev->base_addr; @@ -1276,9 +1397,13 @@ dev->name, (int)inl(ioaddr + INTSTAT)); del_timer_sync(&ep->timer); - epic_pause(dev); + + epic_disable_int(dev, ep); + free_irq(dev->irq, dev); + epic_pause(dev); + /* Free all the skbuffs in the Rx queue. */ for (i = 0; i < RX_RING_SIZE; i++) { skb = ep->rx_skbuff[i]; @@ -1476,6 +1601,7 @@ #endif pci_release_regions(pdev); free_netdev(dev); + pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); /* pci_power_off(pdev, -1); */ } diff -Nru a/drivers/net/fealnx.c b/drivers/net/fealnx.c --- a/drivers/net/fealnx.c Tue May 4 22:12:59 2004 +++ b/drivers/net/fealnx.c Tue May 4 22:12:59 2004 @@ -84,6 +84,7 @@ #include #include #include +#include #include /* Processor type for cache alignment. */ #include @@ -233,15 +234,29 @@ RxErr = 0x00000002, /* receive error */ }; -/* Bits in the NetworkConfig register. */ +/* Bits in the NetworkConfig register, W for writing, R for reading */ +/* FIXME: some names are invented by me. Marked with (name?) */ +/* If you have docs and know bit names, please fix 'em */ enum rx_mode_bits { - RxModeMask = 0xe0, - PROM = 0x80, /* promiscuous mode */ - AB = 0x40, /* accept broadcast */ - AM = 0x20, /* accept mutlicast */ - ARP = 0x08, /* receive runt pkt */ - ALP = 0x04, /* receive long pkt */ - SEP = 0x02, /* receive error pkt */ + CR_W_ENH = 0x02000000, /* enhanced mode (name?) */ + CR_W_FD = 0x00100000, /* full duplex */ + CR_W_PS10 = 0x00080000, /* 10 mbit */ + CR_W_TXEN = 0x00040000, /* tx enable (name?) */ + CR_W_PS1000 = 0x00010000, /* 1000 mbit */ + /* CR_W_RXBURSTMASK= 0x00000e00, Im unsure about this */ + CR_W_RXMODEMASK = 0x000000e0, + CR_W_PROM = 0x00000080, /* promiscuous mode */ + CR_W_AB = 0x00000040, /* accept broadcast */ + CR_W_AM = 0x00000020, /* accept mutlicast */ + CR_W_ARP = 0x00000008, /* receive runt pkt */ + CR_W_ALP = 0x00000004, /* receive long pkt */ + CR_W_SEP = 0x00000002, /* receive error pkt */ + CR_W_RXEN = 0x00000001, /* rx enable (unicast?) (name?) */ + + CR_R_TXSTOP = 0x04000000, /* tx stopped (name?) */ + CR_R_FD = 0x00100000, /* full duplex detected */ + CR_R_PS10 = 0x00080000, /* 10 mbit detected */ + CR_R_RXSTOP = 0x00008000, /* rx stopped (name?) */ }; /* The Tulip Rx and Tx buffer descriptors. */ @@ -375,10 +390,7 @@ #define LXT1000_Full 0x200 // 89/12/29 add, for phy specific status register, levelone phy, (end) -/* for 3-in-1 case */ -#define PS10 0x00080000 -#define FD 0x00100000 -#define PS1000 0x00010000 +/* for 3-in-1 case, BMCRSR register */ #define LinkIsUp2 0x00040000 /* for PHY */ @@ -400,6 +412,12 @@ /* Media monitoring timer. */ struct timer_list timer; + /* Reset timer */ + struct timer_list reset_timer; + int reset_timer_armed; + unsigned long crvalue_sv; + unsigned long imrvalue_sv; + /* Frequently used values: keep some adjacent for cache effect. */ int flags; struct pci_dev *pci_dev; @@ -435,49 +453,44 @@ static void getlinktype(struct net_device *dev); static void getlinkstatus(struct net_device *dev); static void netdev_timer(unsigned long data); +static void reset_timer(unsigned long data); static void tx_timeout(struct net_device *dev); static void init_ring(struct net_device *dev); static int start_tx(struct sk_buff *skb, struct net_device *dev); static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *regs); static int netdev_rx(struct net_device *dev); static void set_rx_mode(struct net_device *dev); +static void __set_rx_mode(struct net_device *dev); 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 struct ethtool_ops netdev_ethtool_ops; static int netdev_close(struct net_device *dev); static void reset_rx_descriptors(struct net_device *dev); +static void reset_tx_descriptors(struct net_device *dev); -void stop_nic_tx(long ioaddr, long crvalue) +static void stop_nic_rx(long ioaddr, long crvalue) { - writel(crvalue & (~0x40000), ioaddr + TCRRCR); - - /* wait for tx stop */ - { - int i = 0, delay = 0x1000; - - while ((!(readl(ioaddr + TCRRCR) & 0x04000000)) && (i < delay)) { - ++i; - } + int delay = 0x1000; + writel(crvalue & ~(CR_W_RXEN), ioaddr + TCRRCR); + while (--delay) { + if ( (readl(ioaddr + TCRRCR) & CR_R_RXSTOP) == CR_R_RXSTOP) + break; } } -void stop_nic_rx(long ioaddr, long crvalue) +static void stop_nic_rxtx(long ioaddr, long crvalue) { - writel(crvalue & (~0x1), ioaddr + TCRRCR); - - /* wait for rx stop */ - { - int i = 0, delay = 0x1000; - - while ((!(readl(ioaddr + TCRRCR) & 0x00008000)) && (i < delay)) { - ++i; - } + int delay = 0x1000; + writel(crvalue & ~(CR_W_RXEN+CR_W_TXEN), ioaddr + TCRRCR); + while (--delay) { + if ( (readl(ioaddr + TCRRCR) & (CR_R_RXSTOP+CR_R_TXSTOP)) + == (CR_R_RXSTOP+CR_R_TXSTOP) ) + break; } } - static int __devinit fealnx_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -495,7 +508,7 @@ #ifndef MODULE static int printed_version; if (!printed_version++) - printk (version); + printk(version); #endif card_idx++; @@ -622,7 +635,7 @@ np->phys[0] = 32; /* 89/6/23 add, (begin) */ /* get phy type */ - if (readl(dev->base_addr + PHYIDENTIFIER) == MysonPHYID) + if (readl(ioaddr + PHYIDENTIFIER) == MysonPHYID) np->PHYType = MysonPHY; else np->PHYType = OtherPHY; @@ -657,7 +670,7 @@ if (np->flags == HAS_MII_XCVR) mdio_write(dev, np->phys[0], MII_ADVERTISE, ADVERTISE_FULL); else - writel(ADVERTISE_FULL, dev->base_addr + ANARANLPAR); + writel(ADVERTISE_FULL, ioaddr + ANARANLPAR); np->mii.force_media = 1; } @@ -669,7 +682,7 @@ dev->set_multicast_list = &set_rx_mode; dev->do_ioctl = &mii_ioctl; dev->ethtool_ops = &netdev_ethtool_ops; - dev->tx_timeout = tx_timeout; + dev->tx_timeout = &tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; err = register_netdev(dev); @@ -699,6 +712,7 @@ return err; } + static void __devexit fealnx_remove_one(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); @@ -721,42 +735,6 @@ printk(KERN_ERR "fealnx: remove for unknown device\n"); } -unsigned int m80x_read_tick(void) -/* function: Reads the Timer tick count register which decrements by 2 from */ -/* 65536 to 0 every 1/36.414 of a second. Each 2 decrements of the *//* count represents 838 nsec's. */ -/* input : none. */ -/* output : none. */ -{ - unsigned char tmp; - int value; - - writeb((char) 0x06, 0x43); // Command 8254 to latch T0's count - - // now read the count. - tmp = (unsigned char) readb(0x40); - value = ((int) tmp) << 8; - tmp = (unsigned char) readb(0x40); - value |= (((int) tmp) & 0xff); - return (value); -} - - -void m80x_delay(unsigned int interval) -/* function: to wait for a specified time. */ -/* input : interval ... the specified time. */ -/* output : none. */ -{ - unsigned int interval1, interval2, i = 0; - - interval1 = m80x_read_tick(); // get initial value - do { - interval2 = m80x_read_tick(); - if (interval1 < interval2) - interval1 = interval2; - ++i; - } while (((interval1 - interval2) < (ushort) interval) && (i < 65535)); -} - static ulong m80x_send_cmd_to_phy(long miiport, int opcode, int phyad, int regad) { @@ -796,7 +774,7 @@ /* high MDC */ miir |= MASK_MIIR_MII_MDC; writel(miir, miiport); - m80x_delay(30); + udelay(30); /* next */ mask >>= 1; @@ -831,7 +809,7 @@ /* high MDC, and wait */ miir |= MASK_MIIR_MII_MDC; writel(miir, miiport); - m80x_delay((int) 30); + udelay(30); /* next */ mask >>= 1; @@ -873,8 +851,6 @@ /* low MDC */ miir &= ~MASK_MIIR_MII_MDC; writel(miir, miiport); - - return; } @@ -949,7 +925,7 @@ np->imrvalue = TUNF | CNTOVF | RBU | TI | RI; if (np->pci_dev->device == 0x891) { np->bcrvalue |= 0x200; /* set PROG bit */ - np->crvalue |= 0x02000000; /* set enhanced bit */ + np->crvalue |= CR_W_ENH; /* set enhanced bit */ np->imrvalue |= ETI; } writel(np->bcrvalue, ioaddr + BCR); @@ -957,7 +933,7 @@ if (dev->if_port == 0) dev->if_port = np->default_port; - writel(0, dev->base_addr + RXPDR); + writel(0, ioaddr + RXPDR); // 89/9/1 modify, // np->crvalue = 0x00e40001; /* tx store and forward, tx/rx enable */ np->crvalue |= 0x00e40001; /* tx store and forward, tx/rx enable */ @@ -965,7 +941,7 @@ getlinkstatus(dev); if (np->linkok) getlinktype(dev); - set_rx_mode(dev); + __set_rx_mode(dev); netif_start_queue(dev); @@ -985,6 +961,11 @@ /* timer handler */ add_timer(&np->timer); + init_timer(&np->reset_timer); + np->reset_timer.data = (unsigned long) dev; + np->reset_timer.function = &reset_timer; + np->reset_timer_armed = 0; + return 0; } @@ -1005,8 +986,7 @@ np->linkok = 1; return; } - // delay - m80x_delay(100); + udelay(100); } } else { for (i = 0; i < DelayTime; ++i) { @@ -1014,8 +994,7 @@ np->linkok = 1; return; } - // delay - m80x_delay(100); + udelay(100); } } } @@ -1026,11 +1005,11 @@ struct netdev_private *np = dev->priv; if (np->PHYType == MysonPHY) { /* 3-in-1 case */ - if (readl(dev->base_addr + TCRRCR) & FD) + if (readl(dev->base_addr + TCRRCR) & CR_R_FD) np->duplexmode = 2; /* full duplex */ else np->duplexmode = 1; /* half duplex */ - if (readl(dev->base_addr + TCRRCR) & PS10) + if (readl(dev->base_addr + TCRRCR) & CR_R_PS10) np->line_speed = 1; /* 10M */ else np->line_speed = 2; /* 100M */ @@ -1112,19 +1091,18 @@ else np->line_speed = 1; /* 10M */ } - // chage crvalue - // np->crvalue&=(~PS10)&(~FD); - np->crvalue &= (~PS10) & (~FD) & (~PS1000); + np->crvalue &= (~CR_W_PS10) & (~CR_W_FD) & (~CR_W_PS1000); if (np->line_speed == 1) - np->crvalue |= PS10; + np->crvalue |= CR_W_PS10; else if (np->line_speed == 3) - np->crvalue |= PS1000; + np->crvalue |= CR_W_PS1000; if (np->duplexmode == 2) - np->crvalue |= FD; + np->crvalue |= CR_W_FD; } } +/* Take lock before calling this */ static void allocate_rx_buffers(struct net_device *dev) { struct netdev_private *np = dev->priv; @@ -1134,15 +1112,17 @@ struct sk_buff *skb; skb = dev_alloc_skb(np->rx_buf_sz); - np->lack_rxbuf->skbuff = skb; - if (skb == NULL) break; /* Better luck next round. */ + while (np->lack_rxbuf->skbuff) + np->lack_rxbuf = np->lack_rxbuf->next_desc_logical; + skb->dev = dev; /* Mark as being used by this device. */ + np->lack_rxbuf->skbuff = skb; np->lack_rxbuf->buffer = pci_map_single(np->pci_dev, skb->tail, np->rx_buf_sz, PCI_DMA_FROMDEVICE); - np->lack_rxbuf = np->lack_rxbuf->next_desc_logical; + np->lack_rxbuf->status = RXOWN; ++np->really_rx_count; } } @@ -1153,22 +1133,23 @@ struct net_device *dev = (struct net_device *) data; struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; - int next_tick = 10 * HZ; int old_crvalue = np->crvalue; unsigned int old_linkok = np->linkok; + unsigned long flags; if (debug) printk(KERN_DEBUG "%s: Media selection timer tick, status %8.8x " "config %8.8x.\n", dev->name, readl(ioaddr + ISR), readl(ioaddr + TCRRCR)); + spin_lock_irqsave(&np->lock, flags); + if (np->flags == HAS_MII_XCVR) { getlinkstatus(dev); if ((old_linkok == 0) && (np->linkok == 1)) { /* we need to detect the media type again */ getlinktype(dev); if (np->crvalue != old_crvalue) { - stop_nic_tx(ioaddr, np->crvalue); - stop_nic_rx(ioaddr, np->crvalue & (~0x40000)); + stop_nic_rxtx(ioaddr, np->crvalue); writel(np->crvalue, ioaddr + TCRRCR); } } @@ -1176,69 +1157,120 @@ allocate_rx_buffers(dev); - np->timer.expires = RUN_AT(next_tick); + spin_unlock_irqrestore(&np->lock, flags); + + np->timer.expires = RUN_AT(10 * HZ); add_timer(&np->timer); } -static void tx_timeout(struct net_device *dev) +/* Take lock before calling */ +/* Reset chip and disable rx, tx and interrupts */ +static void reset_and_disable_rxtx(struct net_device *dev) { - struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; - int i; - - printk(KERN_WARNING "%s: Transmit timed out, status %8.8x," - " resetting...\n", dev->name, readl(ioaddr + ISR)); - - { - - printk(KERN_DEBUG " Rx ring %p: ", np->rx_ring); - for (i = 0; i < RX_RING_SIZE; i++) - printk(" %8.8x", (unsigned int) np->rx_ring[i].status); - printk("\n" KERN_DEBUG " Tx ring %p: ", np->tx_ring); - for (i = 0; i < TX_RING_SIZE; i++) - printk(" %4.4x", np->tx_ring[i].status); - printk("\n"); - } - - /* Reinit. Gross */ + int delay=51; /* Reset the chip's Tx and Rx processes. */ - stop_nic_tx(ioaddr, 0); - reset_rx_descriptors(dev); + stop_nic_rxtx(ioaddr, 0); /* Disable interrupts by clearing the interrupt mask. */ - writel(0x0000, ioaddr + IMR); + writel(0, ioaddr + IMR); /* Reset the chip to erase previous misconfiguration. */ writel(0x00000001, ioaddr + BCR); /* Ueimor: wait for 50 PCI cycles (and flush posted writes btw). - We surely wait too long (address+data phase). Who cares ? */ - for (i = 0; i < 50; i++) { + We surely wait too long (address+data phase). Who cares? */ + while (--delay) { readl(ioaddr + BCR); rmb(); } +} + + +/* Take lock before calling */ +/* Restore chip after reset */ +static void enable_rxtx(struct net_device *dev) +{ + struct netdev_private *np = dev->priv; + long ioaddr = dev->base_addr; - writel((np->cur_tx - np->tx_ring)*sizeof(struct fealnx_desc) + - np->tx_ring_dma, ioaddr + TXLBA); - writel((np->cur_rx - np->rx_ring)*sizeof(struct fealnx_desc) + - np->rx_ring_dma, ioaddr + RXLBA); + reset_rx_descriptors(dev); + + writel(np->tx_ring_dma + ((char*)np->cur_tx - (char*)np->tx_ring), + ioaddr + TXLBA); + writel(np->rx_ring_dma + ((char*)np->cur_rx - (char*)np->rx_ring), + ioaddr + RXLBA); writel(np->bcrvalue, ioaddr + BCR); - writel(0, dev->base_addr + RXPDR); - set_rx_mode(dev); + writel(0, ioaddr + RXPDR); + __set_rx_mode(dev); /* changes np->crvalue, writes it into TCRRCR */ + /* Clear and Enable interrupts by setting the interrupt mask. */ writel(FBE | TUNF | CNTOVF | RBU | TI | RI, ioaddr + ISR); writel(np->imrvalue, ioaddr + IMR); - writel(0, dev->base_addr + TXPDR); + writel(0, ioaddr + TXPDR); +} + + +static void reset_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *) data; + struct netdev_private *np = dev->priv; + unsigned long flags; + + printk(KERN_WARNING "%s: resetting tx and rx machinery\n", dev->name); + + spin_lock_irqsave(&np->lock, flags); + np->crvalue = np->crvalue_sv; + np->imrvalue = np->imrvalue_sv; + + reset_and_disable_rxtx(dev); + /* works for me without this: + reset_tx_descriptors(dev); */ + enable_rxtx(dev); + netif_start_queue(dev); /* FIXME: or netif_wake_queue(dev); ? */ + + np->reset_timer_armed = 0; + + spin_unlock_irqrestore(&np->lock, flags); +} + + +static void tx_timeout(struct net_device *dev) +{ + struct netdev_private *np = dev->priv; + long ioaddr = dev->base_addr; + unsigned long flags; + int i; + + printk(KERN_WARNING "%s: Transmit timed out, status %8.8x," + " resetting...\n", dev->name, readl(ioaddr + ISR)); + + { + printk(KERN_DEBUG " Rx ring %p: ", np->rx_ring); + for (i = 0; i < RX_RING_SIZE; i++) + printk(" %8.8x", (unsigned int) np->rx_ring[i].status); + printk("\n" KERN_DEBUG " Tx ring %p: ", np->tx_ring); + for (i = 0; i < TX_RING_SIZE; i++) + printk(" %4.4x", np->tx_ring[i].status); + printk("\n"); + } + + spin_lock_irqsave(&np->lock, flags); + + reset_and_disable_rxtx(dev); + reset_tx_descriptors(dev); + enable_rxtx(dev); + + spin_unlock_irqrestore(&np->lock, flags); dev->trans_start = jiffies; np->stats.tx_errors++; - - return; + netif_wake_queue(dev); /* or .._start_.. ?? */ } @@ -1251,7 +1283,7 @@ /* initialize rx variables */ np->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); np->cur_rx = &np->rx_ring[0]; - np->lack_rxbuf = NULL; + np->lack_rxbuf = np->rx_ring; np->really_rx_count = 0; /* initial rx descriptors. */ @@ -1294,6 +1326,7 @@ for (i = 0; i < TX_RING_SIZE; i++) { np->tx_ring[i].status = 0; + /* do we need np->tx_ring[i].control = XXX; ?? */ np->tx_ring[i].next_desc = np->tx_ring_dma + (i + 1)*sizeof(struct fealnx_desc); np->tx_ring[i].next_desc_logical = &np->tx_ring[i + 1]; @@ -1341,7 +1374,7 @@ np->cur_tx_copy->control |= (BPT << TBSShift); /* buffer size */ /* for the last descriptor */ - next = (struct fealnx *) np->cur_tx_copy.next_desc_logical; + next = np->cur_tx_copy->next_desc_logical; next->skbuff = skb; next->control = TXIC | TXLD | CRCEnable | PADEnable; next->control |= (skb->len << PKTSShift); /* pkt size */ @@ -1383,35 +1416,59 @@ } -void free_one_rx_descriptor(struct netdev_private *np) +/* Take lock before calling */ +/* Chip probably hosed tx ring. Clean up. */ +static void reset_tx_descriptors(struct net_device *dev) { - if (np->really_rx_count == RX_RING_SIZE) - np->cur_rx->status = RXOWN; - else { - np->lack_rxbuf->skbuff = np->cur_rx->skbuff; - np->lack_rxbuf->buffer = np->cur_rx->buffer; - np->lack_rxbuf->status = RXOWN; - ++np->really_rx_count; - np->lack_rxbuf = np->lack_rxbuf->next_desc_logical; + struct netdev_private *np = dev->priv; + struct fealnx_desc *cur; + int i; + + /* initialize tx variables */ + np->cur_tx = &np->tx_ring[0]; + np->cur_tx_copy = &np->tx_ring[0]; + np->really_tx_count = 0; + np->free_tx_count = TX_RING_SIZE; + + for (i = 0; i < TX_RING_SIZE; i++) { + cur = &np->tx_ring[i]; + if (cur->skbuff) { + pci_unmap_single(np->pci_dev, cur->buffer, + cur->skbuff->len, PCI_DMA_TODEVICE); + dev_kfree_skb(cur->skbuff); + /* or dev_kfree_skb_irq(cur->skbuff); ? */ + cur->skbuff = NULL; + } + cur->status = 0; + cur->control = 0; /* needed? */ + /* probably not needed. We do it for purely paranoid reasons */ + cur->next_desc = np->tx_ring_dma + + (i + 1)*sizeof(struct fealnx_desc); + cur->next_desc_logical = &np->tx_ring[i + 1]; } - np->cur_rx = np->cur_rx->next_desc_logical; + /* for the last tx descriptor */ + np->tx_ring[TX_RING_SIZE - 1].next_desc = np->tx_ring_dma; + np->tx_ring[TX_RING_SIZE - 1].next_desc_logical = &np->tx_ring[0]; } -void reset_rx_descriptors(struct net_device *dev) +/* Take lock and stop rx before calling this */ +static void reset_rx_descriptors(struct net_device *dev) { struct netdev_private *np = dev->priv; - - stop_nic_rx(dev->base_addr, np->crvalue); - - while (!(np->cur_rx->status & RXOWN)) - free_one_rx_descriptor(np); + struct fealnx_desc *cur = np->cur_rx; + int i; allocate_rx_buffers(dev); - writel(np->rx_ring_dma + (np->cur_rx - np->rx_ring), + for (i = 0; i < RX_RING_SIZE; i++) { + if (cur->skbuff) + cur->status = RXOWN; + cur = cur->next_desc_logical; + } + + writel(np->rx_ring_dma + ((char*)np->cur_rx - (char*)np->rx_ring), dev->base_addr + RXLBA); - writel(np->crvalue, dev->base_addr + TCRRCR); } @@ -1421,16 +1478,14 @@ { struct net_device *dev = (struct net_device *) dev_instance; struct netdev_private *np = dev->priv; - long ioaddr, boguscnt = max_interrupt_work; + long ioaddr = dev->base_addr; + long boguscnt = max_interrupt_work; unsigned int num_tx = 0; int handled = 0; spin_lock(&np->lock); - writel(0, dev->base_addr + IMR); - - ioaddr = dev->base_addr; - np = dev->priv; + writel(0, ioaddr + IMR); do { u32 intr_status = readl(ioaddr + ISR); @@ -1471,8 +1526,11 @@ if (intr_status & (RI | RBU)) { if (intr_status & RI) netdev_rx(dev); - else + else { + stop_nic_rx(ioaddr, np->crvalue); reset_rx_descriptors(dev); + writel(np->crvalue, ioaddr + TCRRCR); + } } while (np->really_tx_count) { @@ -1490,7 +1548,7 @@ if (tx_status & TXOWN) break; - if (!(np->crvalue & 0x02000000)) { + if (!(np->crvalue & CR_W_ENH)) { if (tx_status & (CSL | LC | EC | UDF | HF)) { np->stats.tx_errors++; if (tx_status & EC) @@ -1539,7 +1597,7 @@ netif_wake_queue(dev); /* read transmit status for enhanced mode only */ - if (np->crvalue & 0x02000000) { + if (np->crvalue & CR_W_ENH) { long data; data = readl(ioaddr + TSR); @@ -1552,6 +1610,20 @@ if (--boguscnt < 0) { printk(KERN_WARNING "%s: Too much work at interrupt, " "status=0x%4.4x.\n", dev->name, intr_status); + if (!np->reset_timer_armed) { + np->reset_timer_armed = 1; + np->reset_timer.expires = RUN_AT(HZ/2); + add_timer(&np->reset_timer); + stop_nic_rxtx(ioaddr, 0); + netif_stop_queue(dev); + /* or netif_tx_disable(dev); ?? */ + /* Prevent other paths from enabling tx,rx,intrs */ + np->crvalue_sv = np->crvalue; + np->imrvalue_sv = np->imrvalue; + np->crvalue &= ~(CR_W_TXEN | CR_W_RXEN); /* or simply = 0? */ + np->imrvalue = 0; + } + break; } } while (1); @@ -1580,9 +1652,10 @@ static int netdev_rx(struct net_device *dev) { struct netdev_private *np = dev->priv; + long ioaddr = dev->base_addr; /* If EOP is set on the next entry, it's a new packet. Send it up. */ - while (!(np->cur_rx->status & RXOWN)) { + while (!(np->cur_rx->status & RXOWN) && np->cur_rx->skbuff) { s32 rx_status = np->cur_rx->status; if (np->really_rx_count == 0) @@ -1634,11 +1707,20 @@ np->stats.rx_length_errors++; /* free all rx descriptors related this long pkt */ - for (i = 0; i < desno; ++i) - free_one_rx_descriptor(np); + for (i = 0; i < desno; ++i) { + if (!np->cur_rx->skbuff) { + printk(KERN_DEBUG + "%s: I'm scared\n", dev->name); + break; + } + np->cur_rx->status = RXOWN; + np->cur_rx = np->cur_rx->next_desc_logical; + } continue; - } else { /* something error, need to reset this chip */ + } else { /* rx error, need to reset this chip */ + stop_nic_rx(ioaddr, np->crvalue); reset_rx_descriptors(dev); + writel(np->crvalue, ioaddr + TCRRCR); } break; /* exit the while loop */ } @@ -1685,8 +1767,6 @@ PCI_DMA_FROMDEVICE); skb_put(skb = np->cur_rx->skbuff, pkt_len); np->cur_rx->skbuff = NULL; - if (np->really_rx_count == RX_RING_SIZE) - np->lack_rxbuf = np->cur_rx; --np->really_rx_count; } skb->protocol = eth_type_trans(skb, dev); @@ -1696,24 +1776,7 @@ np->stats.rx_bytes += pkt_len; } - if (np->cur_rx->skbuff == NULL) { - struct sk_buff *skb; - - skb = dev_alloc_skb(np->rx_buf_sz); - - if (skb != NULL) { - skb->dev = dev; /* Mark as being used by this device. */ - np->cur_rx->buffer = pci_map_single(np->pci_dev, - skb->tail, - np->rx_buf_sz, - PCI_DMA_FROMDEVICE); - np->cur_rx->skbuff = skb; - ++np->really_rx_count; - } - } - - if (np->cur_rx->skbuff != NULL) - free_one_rx_descriptor(np); + np->cur_rx = np->cur_rx->next_desc_logical; } /* end of while loop */ /* allocate skb for rx buffers */ @@ -1737,8 +1800,21 @@ return &np->stats; } + +/* for dev->set_multicast_list */ static void set_rx_mode(struct net_device *dev) { + spinlock_t *lp = &((struct netdev_private *)dev->priv)->lock; + unsigned long flags; + spin_lock_irqsave(lp, flags); + __set_rx_mode(dev); + spin_unlock_irqrestore(&lp, flags); +} + + +/* Take lock before calling */ +static void __set_rx_mode(struct net_device *dev) +{ struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; u32 mc_filter[2]; /* Multicast hash filter */ @@ -1748,12 +1824,12 @@ /* Unconditionally log net taps. */ printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name); memset(mc_filter, 0xff, sizeof(mc_filter)); - rx_mode = PROM | AB | AM; + rx_mode = CR_W_PROM | CR_W_AB | CR_W_AM; } else if ((dev->mc_count > multicast_filter_limit) || (dev->flags & IFF_ALLMULTI)) { /* Too many to match, or accept all multicasts. */ memset(mc_filter, 0xff, sizeof(mc_filter)); - rx_mode = AB | AM; + rx_mode = CR_W_AB | CR_W_AM; } else { struct dev_mc_list *mclist; int i; @@ -1765,26 +1841,25 @@ bit = (ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26) ^ 0x3F; mc_filter[bit >> 5] |= (1 << bit); } - rx_mode = AB | AM; + rx_mode = CR_W_AB | CR_W_AM; } - stop_nic_tx(ioaddr, np->crvalue); - stop_nic_rx(ioaddr, np->crvalue & (~0x40000)); + stop_nic_rxtx(ioaddr, np->crvalue); writel(mc_filter[0], ioaddr + MAR0); writel(mc_filter[1], ioaddr + MAR1); - np->crvalue &= ~RxModeMask; + np->crvalue &= ~CR_W_RXMODEMASK; np->crvalue |= rx_mode; writel(np->crvalue, ioaddr + TCRRCR); } -static void netdev_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *info) +static void netdev_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { struct netdev_private *np = dev->priv; - strcpy (info->driver, DRV_NAME); - strcpy (info->version, DRV_VERSION); - strcpy (info->bus_info, pci_name(np->pci_dev)); + strcpy(info->driver, DRV_NAME); + strcpy(info->version, DRV_VERSION); + strcpy(info->bus_info, pci_name(np->pci_dev)); } static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) @@ -1874,10 +1949,10 @@ writel(0x0000, ioaddr + IMR); /* Stop the chip's Tx and Rx processes. */ - stop_nic_tx(ioaddr, 0); - stop_nic_rx(ioaddr, 0); + stop_nic_rxtx(ioaddr, 0); del_timer_sync(&np->timer); + del_timer_sync(&np->reset_timer); free_irq(dev->irq, dev); @@ -1928,7 +2003,7 @@ { /* when a module, this is printed whether or not devices are found in probe */ #ifdef MODULE - printk (version); + printk(version); #endif return pci_module_init(&fealnx_driver); diff -Nru a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c --- a/drivers/net/pcnet32.c Tue May 4 22:12:59 2004 +++ b/drivers/net/pcnet32.c Tue May 4 22:12:59 2004 @@ -132,6 +132,8 @@ }; #define PCNET32_TEST_LEN (sizeof(pcnet32_gstrings_test) / ETH_GSTRING_LEN) +#define PCNET32_NUM_REGS 146 + #define MAX_UNITS 8 /* More are supported, limit only on options */ static int options[MAX_UNITS]; static int full_duplex[MAX_UNITS]; @@ -234,7 +236,9 @@ * Jim Lewis added ethernet loopback test. * Thomas Munck Steenholdt non-mii ioctl corrections. * v1.29 6 Apr 2004 Jim Lewis added physical - * identification code (blink led's). + * identification code (blink led's) and register dump. + * Don Fry added timer for 971/972 so skbufs don't remain on tx ring + * forever. */ @@ -372,6 +376,9 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t *data1); static int pcnet32_phys_id(struct net_device *dev, u32 data); static void pcnet32_led_blink_callback(struct net_device *dev); +static int pcnet32_get_regs_len(struct net_device *dev); +static void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs, + void *ptr); enum pci_flags_bit { PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4, @@ -492,9 +499,9 @@ #ifdef CONFIG_NET_POLL_CONTROLLER static void pcnet32_poll_controller(struct net_device *dev) { - disable_irq(dev->irq); - pcnet32_interrupt(0, dev, NULL); - enable_irq(dev->irq); + disable_irq(dev->irq); + pcnet32_interrupt(0, dev, NULL); + enable_irq(dev->irq); } #endif @@ -681,7 +688,7 @@ for (i=0; i<6; i++) *packet++ = dev->dev_addr[i]; for (i=0; i<6; i++) - *packet++ = dev->dev_addr[i]; + *packet++ = dev->dev_addr[i]; /* type */ *packet++ = 0x08; *packet++ = 0x06; @@ -837,6 +844,72 @@ return 0; } +int pcnet32_get_regs_len(struct net_device *dev) +{ + return(PCNET32_NUM_REGS * sizeof(u16)); +} + +void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs, + void *ptr) +{ + int i, csr0; + u16 *buff = ptr; + struct pcnet32_private *lp = dev->priv; + struct pcnet32_access *a = &lp->a; + ulong ioaddr = dev->base_addr; + int ticks; + unsigned long flags; + + spin_lock_irqsave(&lp->lock, flags); + + csr0 = a->read_csr(ioaddr, 0); + if (!(csr0 & 0x0004)) { /* If not stopped */ + /* set SUSPEND (SPND) - CSR5 bit 0 */ + a->write_csr(ioaddr, 5, 0x0001); + + /* poll waiting for bit to be set */ + ticks = 0; + while (!(a->read_csr(ioaddr, 5) & 0x0001)) { + spin_unlock_irqrestore(&lp->lock, flags); + mdelay(1); + spin_lock_irqsave(&lp->lock, flags); + ticks++; + if (ticks > 200) { + if (netif_msg_hw(lp)) + printk(KERN_DEBUG "%s: Error getting into suspend!\n", + dev->name); + break; + } + } + } + + /* read address PROM */ + for (i=0; i<16; i += 2) + *buff++ = inw(ioaddr + i); + + for (i = 0; i <= 89; i++) { + *buff++ = a->read_csr(ioaddr, i); + } + + *buff++ = a->read_csr(ioaddr, 112); + *buff++ = a->read_csr(ioaddr, 114); + + for (i = 0; i <= 35; i++) { + *buff++ = a->read_bcr(ioaddr, i); + } + + if (!(csr0 & 0x0004)) { /* If not stopped */ + /* clear SUSPEND (SPND) - CSR5 bit 0 */ + a->write_csr(ioaddr, 5, 0x0000); + } + + i = buff - (u16 *)ptr; + for (; i < PCNET32_NUM_REGS; i++) + *buff++ = 0; + + spin_unlock_irqrestore(&lp->lock, flags); +} + static struct ethtool_ops pcnet32_ethtool_ops = { .get_settings = pcnet32_get_settings, .set_settings = pcnet32_set_settings, @@ -853,6 +926,8 @@ .self_test_count = pcnet32_self_test_count, .self_test = pcnet32_ethtool_test, .phys_id = pcnet32_phys_id, + .get_regs_len = pcnet32_get_regs_len, + .get_regs = pcnet32_get_regs, }; /* only probes for non-PCI devices, the rest are handled by @@ -1032,6 +1107,13 @@ ltint = 1; } + if (ltint) { + /* Enable timer to prevent skbuffs from remaining on the tx ring + * forever if no other tx being done. Set timer period to about + * 122 ms */ + a->write_bcr(ioaddr, 31, 0x253b); + } + dev = alloc_etherdev(0); if (!dev) { if (pcnet32_debug & NETIF_MSG_PROBE) @@ -1371,13 +1453,18 @@ /* Re-initialize the PCNET32, and start it when done. */ lp->a.write_csr (ioaddr, 1, (lp->dma_addr + - offsetof(struct pcnet32_private, init_block)) & 0xffff); + offsetof(struct pcnet32_private, init_block)) & 0xffff); lp->a.write_csr (ioaddr, 2, (lp->dma_addr + offsetof(struct pcnet32_private, init_block)) >> 16); lp->a.write_csr (ioaddr, 4, 0x0915); lp->a.write_csr (ioaddr, 0, 0x0001); + if (lp->ltint) { + /* start the software timer */ + lp->a.write_csr(ioaddr, 7, 0x0400); /* set STINTE */ + } + netif_start_queue(dev); /* If we have mii, print the link status and start the watchdog */ @@ -1579,13 +1666,13 @@ int entry; unsigned long flags; + spin_lock_irqsave(&lp->lock, flags); + if (netif_msg_tx_queued(lp)) { printk(KERN_DEBUG "%s: pcnet32_start_xmit() called, csr0 %4.4x.\n", dev->name, lp->a.read_csr(ioaddr, 0)); } - spin_lock_irqsave(&lp->lock, flags); - /* Default status -- will not enable Successful-TxDone * interrupt when that option is available to us. */ @@ -1646,7 +1733,7 @@ struct net_device *dev = dev_id; struct pcnet32_private *lp; unsigned long ioaddr; - u16 csr0,rap; + u16 csr0, csr7, rap; int boguscnt = max_interrupt_work; int must_restart; @@ -1663,13 +1750,19 @@ spin_lock(&lp->lock); rap = lp->a.read_rap(ioaddr); - while ((csr0 = lp->a.read_csr (ioaddr, 0)) & 0x8600 && --boguscnt >= 0) { + csr0 = lp->a.read_csr (ioaddr, 0); + csr7 = lp->ltint ? lp->a.read_csr(ioaddr, 7) : 0; + + while ((csr0 & 0x8600 || csr7 & 0x0800) && --boguscnt >= 0) { if (csr0 == 0xffff) { break; /* PCMCIA remove happened */ } /* Acknowledge all of the current interrupt sources ASAP. */ lp->a.write_csr (ioaddr, 0, csr0 & ~0x004f); + if (csr7 & 0x0800) + lp->a.write_csr(ioaddr, 7, csr7); + must_restart = 0; if (netif_msg_intr(lp)) @@ -1679,7 +1772,7 @@ if (csr0 & 0x0400) /* Rx interrupt */ pcnet32_rx(dev); - if (csr0 & 0x0200) { /* Tx-done interrupt */ + if (csr0 & 0x0200 || csr7 & 0x0800) { /* Tx-done or Timer interrupt */ unsigned int dirty_tx = lp->dirty_tx; int delta; @@ -1786,6 +1879,9 @@ lp->a.write_csr (ioaddr, 0, 0x0004); pcnet32_restart(dev, 0x0002); } + + csr0 = lp->a.read_csr (ioaddr, 0); + csr7 = lp->ltint ? lp->a.read_csr(ioaddr, 7) : 0; } /* Clear any other interrupt, and set interrupt enable. */ @@ -1872,6 +1968,7 @@ if (i > RX_RING_SIZE -2) { lp->stats.rx_dropped++; lp->rx_ring[entry].status |= le16_to_cpu(0x8000); + wmb(); /* Make sure adapter sees owner change */ lp->cur_rx++; } break; @@ -1935,6 +2032,10 @@ /* We stop the PCNET32 here -- it occasionally polls memory if we don't. */ lp->a.write_csr (ioaddr, 0, 0x0004); + if (lp->ltint) { /* Disable timer interrupts */ + lp->a.write_csr(ioaddr, 7, 0x0000); + } + /* * Switch back to 16bit mode to avoid problems with dumb * DOS packet driver after a warm reboot @@ -1945,9 +2046,12 @@ free_irq(dev->irq, dev); + spin_lock_irqsave(&lp->lock, flags); + /* free all allocated skbuffs */ for (i = 0; i < RX_RING_SIZE; i++) { lp->rx_ring[i].status = 0; + wmb(); /* Make sure adapter sees owner change */ if (lp->rx_skbuff[i]) { pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i], PKT_BUF_SZ-2, PCI_DMA_FROMDEVICE); @@ -1958,6 +2062,8 @@ } for (i = 0; i < TX_RING_SIZE; i++) { + lp->tx_ring[i].status = 0; /* CPU owns buffer */ + wmb(); /* Make sure adapter sees owner change */ if (lp->tx_skbuff[i]) { pci_unmap_single(lp->pci_dev, lp->tx_dma_addr[i], lp->tx_skbuff[i]->len, PCI_DMA_TODEVICE); @@ -1966,6 +2072,8 @@ lp->tx_skbuff[i] = NULL; lp->tx_dma_addr[i] = 0; } + + spin_unlock_irqrestore(&lp->lock, flags); return 0; }