diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-08-28 22:00:09 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-08-28 22:00:09 +0000 |
commit | 1a1d77dd589de5a567fa95e36aa6999c704ceca4 (patch) | |
tree | 141e31f89f18b9fe0831f31852e0435ceaccafc5 /drivers/net | |
parent | fb9c690a18b3d66925a65b17441c37fa14d4370b (diff) |
Merge with 2.4.0-test7.
Diffstat (limited to 'drivers/net')
32 files changed, 2551 insertions, 949 deletions
diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c index 61b51eeaf..ad9178ab9 100644 --- a/drivers/net/3c501.c +++ b/drivers/net/3c501.c @@ -280,6 +280,13 @@ static int __init el1_probe1(struct net_device *dev, int ioaddr) int i; /* + * Reserve I/O resource for exclusive use by this driver + */ + + if (!request_region(ioaddr, EL1_IO_EXTENT, dev->name)) + return -ENODEV; + + /* * Read the station address PROM data from the special port. */ @@ -302,15 +309,10 @@ static int __init el1_probe1(struct net_device *dev, int ioaddr) { mname = "NP943"; } - else - return -ENODEV; - - /* - * Grab the region so we can find the another board if autoIRQ fails. - */ - - if (!request_region(ioaddr, EL1_IO_EXTENT,"3c501")) + else { + release_region(ioaddr, EL1_IO_EXTENT); return -ENODEV; + } /* * We auto-IRQ by shutting off the interrupt line and letting it float @@ -332,6 +334,7 @@ static int __init el1_probe1(struct net_device *dev, int ioaddr) { printk("%s probe at %#x failed to detect IRQ line.\n", mname, ioaddr); + release_region(ioaddr, EL1_IO_EXTENT); return -EAGAIN; } } @@ -360,8 +363,10 @@ static int __init el1_probe1(struct net_device *dev, int ioaddr) */ dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); - if (dev->priv == NULL) + if (dev->priv == NULL) { + release_region(ioaddr, EL1_IO_EXTENT); return -ENOMEM; + } memset(dev->priv, 0, sizeof(struct net_local)); lp=dev->priv; diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 9bb2fa52f..fd01a6025 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -77,7 +77,29 @@ - Print a warning on out-of-memory (rate limited to 1 per 10 secs) - Added two more Cardbus 575 NICs: 5b57 and 6564 (Paul Wagland) + LK1.1.7 2 Jul 2000 andrewm + - Better handling of shared IRQs + - Reset the transmitter on a Tx reclaim error + - Fixed crash under OOM during vortex_open() (Mark Hemment) + - Fix Rx cessation problem during OOM (help from Mark Hemment) + - The spinlocks around the mdio access were blocking interrupts for 300uS. + Fix all this to use spin_lock_bh() within mdio_read/write + - Only write to TxFreeThreshold if it's a boomerang - other NICs don't + have one. + - Added 802.3x MAC-layer flow control support + + LK1.1.8 13 Aug 2000 andrewm + - Ignore request_region() return value - already reserved if Cardbus. + - Merged some additional Cardbus flags from Don's 0.99Qk + - Some fixes for 3c556 (Fred Maciel) + - Fix for EISA initialisation (Jan Rkorajski) + - Renamed MII_XCVR_PWR and EEPROM_230 to align with 3c575_cb and D. Becker's drivers + - Fixed MII_XCVR_PWR for 3CCFE575CT + - Added INVERT_LED_PWR, used it. + - Backed out the extra_reset stuff + - See http://www.uow.edu.au/~andrewm/linux/#3c59x-2.3 for more details. + - Also see Documentation/networking/vortex.txt */ /* @@ -103,8 +125,6 @@ static const int rx_copybreak = 200; static const int mtu = 1500; /* Maximum events (Rx packets, etc.) to handle at each interrupt. */ static int max_interrupt_work = 32; -/* Give the NIC an extra reset at the end of vortex_up() */ -static int extra_reset = 0; /* Tx timeout interval (millisecs) */ static int watchdog = 400; @@ -163,16 +183,16 @@ static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0, rx_csumhits; #include <linux/delay.h> static char version[] __devinitdata = -"3c59x.c:v0.99L+LK1.1.6 28 May 2000 Donald Becker and others. http://www.scyld.com/network/vortex.html " "$Revision: 1.97 $\n"; +"3c59x.c:LK1.1.8 13 Aug 2000 Donald Becker and others. http://www.scyld.com/network/vortex.html " "$Revision: 1.102.2.25 $\n"; MODULE_AUTHOR("Donald Becker <becker@scyld.com>"); MODULE_DESCRIPTION("3Com 3c59x/3c90x/3c575 series Vortex/Boomerang/Cyclone driver"); MODULE_PARM(debug, "i"); MODULE_PARM(options, "1-" __MODULE_STRING(8) "i"); MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i"); +MODULE_PARM(flow_ctrl, "1-" __MODULE_STRING(8) "i"); MODULE_PARM(rx_copybreak, "i"); MODULE_PARM(max_interrupt_work, "i"); -MODULE_PARM(extra_reset, "i"); MODULE_PARM(compaq_ioaddr, "i"); MODULE_PARM(compaq_irq, "i"); MODULE_PARM(compaq_device_id, "i"); @@ -281,8 +301,9 @@ enum pci_flags_bit { }; enum { IS_VORTEX=1, IS_BOOMERANG=2, IS_CYCLONE=4, IS_TORNADO=8, - EEPROM_230=0x10, /* AKPM: Uses 0x230 as the base bitmaps for EEPROM reads */ - HAS_PWR_CTRL=0x20, HAS_MII=0x40, HAS_NWAY=0x80, HAS_CB_FNS=0x100, }; + EEPROM_8BIT=0x10, /* AKPM: Uses 0x230 as the base bitmaps for EEPROM reads */ + HAS_PWR_CTRL=0x20, HAS_MII=0x40, HAS_NWAY=0x80, HAS_CB_FNS=0x100, + INVERT_MII_PWR=0x200, INVERT_LED_PWR=0x400 }; enum vortex_chips { @@ -312,14 +333,16 @@ enum vortex_chips { CH_3CSOHO100_TX, CH_3C555, + CH_3C556, CH_3C575, CH_3C575_1, - CH_3CCFE575, + CH_3CCFE575, CH_3CCFE575CT, CH_3CCFE656, CH_3CCFEM656, CH_3CCFEM656_1, + CH_3C450, }; @@ -383,24 +406,26 @@ static struct vortex_chip_info { PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, {"3c555 Laptop Hurricane", PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, + {"3c556 10/100 Mini PCI Adapter", + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|EEPROM_8BIT|HAS_CB_FNS|INVERT_MII_PWR, 128, }, {"3c575 [Megahertz] 10/100 LAN CardBus", - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_230, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_8BIT, 128, }, {"3c575 Boomerang CardBus", - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_230, 128, }, - {"3CCFE575 Cyclone CardBus", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_230, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_8BIT, 128, }, + {"3CCFE575BT Cyclone CardBus", + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_LED_PWR, 128, }, {"3CCFE575CT Cyclone CardBus", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_230, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR, 128, }, {"3CCFE656 Cyclone CardBus", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_230, 128, }, - {"3CCFEM656 Cyclone CardBus", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_230, 128, }, - {"3CCFEM656 Cyclone CardBus(0x6564)", /* From pcmcia-cs-3.1.5 */ - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_230, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|INVERT_LED_PWR, 128, }, + {"3CCFEM656B Cyclone+Winmodem CardBus", + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|INVERT_LED_PWR, 128, }, + {"3CCFE656C Tornado+Winmodem CardBus", /* From pcmcia-cs-3.1.5 */ + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR, 128, }, + {"3c450 HomePNA Tornado", /* AKPM: from Don's 0.99Q */ PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY, 128, }, - {0,}, /* 0 terminated list. */ }; @@ -432,16 +457,17 @@ static struct pci_device_id vortex_pci_tbl[] __devinitdata = { { 0x10B7, 0x7646, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CSOHO100_TX }, { 0x10B7, 0x5055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C555 }, + { 0x10B7, 0x6055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C556 }, { 0x10B7, 0x5b57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C575 }, { 0x10B7, 0x5057, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C575_1 }, - { 0x10B7, 0x5157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE575 }, + { 0x10B7, 0x5157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE575 }, { 0x10B7, 0x5257, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE575CT }, { 0x10B7, 0x6560, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE656 }, { 0x10B7, 0x6562, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFEM656 }, { 0x10B7, 0x6564, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFEM656_1 }, - { 0x10B7, 0x4500, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C450 }, + { 0x10B7, 0x4500, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C450 }, {0,} /* 0 terminated list. */ }; MODULE_DEVICE_TABLE(pci, vortex_pci_tbl); @@ -612,16 +638,20 @@ struct vortex_private { /* The remainder are related to chip state, mostly media selection. */ struct timer_list timer; /* Media selection timer. */ + struct timer_list rx_oom_timer; /* Rx skb allocation retry timer */ int options; /* User-settable misc. driver options. */ unsigned int media_override:4, /* Passed-in media type. */ default_media:4, /* Read from the EEPROM/Wn3_Config. */ full_duplex:1, force_fd:1, autoselect:1, bus_master:1, /* Vortex can only do a fragment bus-m. */ full_bus_master_tx:1, full_bus_master_rx:2, /* Boomerang */ - hw_csums:1, /* Has hardware checksums. */ + flow_ctrl:1, /* Use 802.3x flow control (PAUSE only) */ + partner_flow_ctrl:1, /* Partner supports flow control */ tx_full:1, has_nway:1, - open:1; + open:1, + must_free_region:1; /* Flag: if zero, Cardbus owns the I/O region */ + int drv_flags; int tx_reset_resume; /* Flag to retart timer after vortex_error handling */ u16 status_enable; u16 intr_enable; @@ -632,7 +662,8 @@ struct vortex_private { u16 deferred; /* Resend these interrupts when we * bale from the ISR */ u16 io_size; /* Size of PCI region (for release_region) */ - spinlock_t lock; + spinlock_t lock; /* Serialise access to device & its vortex_private */ + spinlock_t mdio_lock; /* Serialise access to mdio hardware */ }; /* The action to take with a media selection timer tick. @@ -669,9 +700,10 @@ static void vortex_up(struct net_device *dev); static void vortex_down(struct net_device *dev); static int vortex_open(struct net_device *dev); static void mdio_sync(long ioaddr, int bits); -static int mdio_read(long ioaddr, int phy_id, int location); -static void mdio_write(long ioaddr, int phy_id, int location, int value); +static int mdio_read(struct net_device *dev, int phy_id, int location); +static void mdio_write(struct net_device *vp, int phy_id, int location, int value); static void vortex_timer(unsigned long arg); +static void rx_oom_timer(unsigned long arg); static int vortex_start_xmit(struct sk_buff *skb, struct net_device *dev); static int boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev); static int vortex_rx(struct net_device *dev); @@ -692,7 +724,9 @@ static void acpi_set_WOL(struct net_device *dev); #define MAX_UNITS 8 static int options[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1,}; static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; +static int flow_ctrl[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; +/* #define dev_alloc_skb dev_alloc_skb_debug */ /* A list of all installed Vortex EISA devices, for removing the driver module. */ static struct net_device *root_vortex_eisa_dev = NULL; @@ -746,7 +780,7 @@ static int __init vortex_eisa_init (void) for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) { int device_id; - if (request_region(ioaddr, VORTEX_TOTAL_SIZE, "vortex") == NULL) + if (request_region(ioaddr, VORTEX_TOTAL_SIZE, "3c59x") == NULL) continue; /* Check the standard EISA ID register for an encoded '3Com'. */ @@ -780,7 +814,6 @@ static int __init vortex_eisa_init (void) return vortex_cards_found - orig_cards_found; } - /* returns count (>= 0), or negative on error */ static int __devinit vortex_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) @@ -815,6 +848,7 @@ static int __devinit vortex_probe1(struct pci_dev *pdev, if (!printed_version) { printk (KERN_INFO "%s", version); + printk (KERN_INFO "See Documentation/networking/vortex.txt\n"); printed_version = 1; } @@ -836,6 +870,7 @@ static int __devinit vortex_probe1(struct pci_dev *pdev, dev->base_addr = ioaddr; dev->irq = irq; dev->mtu = mtu; + vp->drv_flags = vci->drv_flags; vp->has_nway = (vci->drv_flags & HAS_NWAY) ? 1 : 0; vp->io_size = vci->io_size; @@ -848,11 +883,9 @@ static int __devinit vortex_probe1(struct pci_dev *pdev, /* PCI-only startup logic */ if (pdev) { /* EISA resources already marked, so only PCI needs to do this here */ - if (!request_region (ioaddr, vci->io_size, dev->name)) { - printk (KERN_ERR "%s: Cannot reserve I/O resource 0x%x @ 0x%lx, aborting\n", - dev->name, vci->io_size, ioaddr); - retval = -EBUSY; - goto free_dev; + /* Ignore return value, because Cardbus drivers already allocate for us */ + if (request_region(ioaddr, vci->io_size, dev->name) != NULL) { + vp->must_free_region = 1; } /* wake up and enable device */ @@ -866,15 +899,15 @@ static int __devinit vortex_probe1(struct pci_dev *pdev, pci_set_master (pdev); } - vp->lock = SPIN_LOCK_UNLOCKED; + spin_lock_init(&vp->lock); + spin_lock_init(&vp->mdio_lock); vp->pdev = pdev; /* Makes sure rings are at least 16 byte aligned. */ vp->rx_ring = pci_alloc_consistent(pdev, sizeof(struct boom_rx_desc) * RX_RING_SIZE + sizeof(struct boom_tx_desc) * TX_RING_SIZE, &vp->rx_ring_dma); - if (vp->rx_ring == 0) - { + if (vp->rx_ring == 0) { retval = -ENOMEM; goto free_region; } @@ -888,8 +921,8 @@ static int __devinit vortex_probe1(struct pci_dev *pdev, pdev->driver_data = dev; /* The lower four bits are the media type. */ - if (dev->mem_start) - { /* + if (dev->mem_start) { + /* * AKPM: ewww.. The 'options' param is passed in as the third arg to the * LILO 'ether=' argument for non-modular use */ @@ -900,24 +933,26 @@ static int __devinit vortex_probe1(struct pci_dev *pdev, else option = -1; + vp->media_override = 7; if (option >= 0) { vp->media_override = ((option & 7) == 2) ? 0 : option & 15; vp->full_duplex = (option & 0x200) ? 1 : 0; vp->bus_master = (option & 16) ? 1 : 0; - } else { - vp->media_override = 7; - vp->full_duplex = 0; - vp->bus_master = 0; } - if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0) - vp->full_duplex = 1; + + if (card_idx < MAX_UNITS) { + if (full_duplex[card_idx] > 0) + vp->full_duplex = 1; + if (flow_ctrl[card_idx] > 0) + vp->flow_ctrl = 1; + } vp->force_fd = vp->full_duplex; vp->options = option; /* Read the station address from the EEPROM. */ EL3WINDOW(0); { - int base = (vci->drv_flags & EEPROM_230) ? 0x230 : EEPROM_Read; + int base = (vci->drv_flags & EEPROM_8BIT) ? 0x230 : EEPROM_Read; for (i = 0; i < 0x40; i++) { int timer; outw(base + i, ioaddr + Wn0EepromCmd); @@ -960,17 +995,21 @@ static int __devinit vortex_probe1(struct pci_dev *pdev, if (pdev && vci->drv_flags & HAS_CB_FNS) { unsigned long fn_st_addr; /* Cardbus function status space */ + unsigned short n; + fn_st_addr = pci_resource_start (pdev, 2); if (fn_st_addr) vp->cb_fn_base = ioremap(fn_st_addr, 128); printk(KERN_INFO "%s: CardBus functions mapped %8.8lx->%p\n", dev->name, fn_st_addr, vp->cb_fn_base); -#if 1 /* AKPM: the 575_cb and 905B LEDs seem OK without this */ - if (vortex_pci_tbl[chip_idx].device != 0x5257) { - EL3WINDOW(2); - outw(0x10 | inw(ioaddr + Wn2_ResetOptions), ioaddr + Wn2_ResetOptions); - } -#endif + EL3WINDOW(2); + + n = inw(ioaddr + Wn2_ResetOptions) & ~0x4010; + if (vp->drv_flags & INVERT_LED_PWR) + n |= 0x10; + if (vp->drv_flags & INVERT_MII_PWR) + n |= 0x4000; + outw(n, ioaddr + Wn2_ResetOptions); } /* Extract our information from the EEPROM data. */ @@ -978,8 +1017,7 @@ static int __devinit vortex_probe1(struct pci_dev *pdev, vp->info2 = eeprom[15]; vp->capabilities = eeprom[16]; - if (vp->info1 & 0x8000) - { + if (vp->info1 & 0x8000) { vp->full_duplex = 1; printk(KERN_INFO "Full duplex capable\n"); } @@ -1018,10 +1056,10 @@ static int __devinit vortex_probe1(struct pci_dev *pdev, EL3WINDOW(4); mii_preamble_required++; mii_preamble_required++; - mdio_read(ioaddr, 24, 1); + mdio_read(dev, 24, 1); for (phy = 1; phy <= 32 && phy_idx < sizeof(vp->phys); phy++) { int mii_status, phyx = phy & 0x1f; - mii_status = mdio_read(ioaddr, phyx, 1); + mii_status = mdio_read(dev, phyx, 1); if (mii_status && mii_status != 0xffff) { vp->phys[phy_idx++] = phyx; printk(KERN_INFO " MII transceiver found at address %d," @@ -1035,11 +1073,11 @@ static int __devinit vortex_probe1(struct pci_dev *pdev, printk(KERN_WARNING" ***WARNING*** No MII transceivers found!\n"); vp->phys[0] = 24; } else { - vp->advertising = mdio_read(ioaddr, vp->phys[0], 4); + vp->advertising = mdio_read(dev, vp->phys[0], 4); if (vp->full_duplex) { /* Only advertise the FD media types. */ vp->advertising &= ~0x02A0; - mdio_write(ioaddr, vp->phys[0], 4, vp->advertising); + mdio_write(dev, vp->phys[0], 4, vp->advertising); } } } @@ -1056,20 +1094,21 @@ static int __devinit vortex_probe1(struct pci_dev *pdev, } /* The 3c59x-specific entries in the device structure. */ - dev->open = &vortex_open; - dev->hard_start_xmit = &vortex_start_xmit; - dev->stop = &vortex_close; - dev->get_stats = &vortex_get_stats; - dev->do_ioctl = &vortex_ioctl; - dev->set_multicast_list = &set_rx_mode; - dev->tx_timeout = &vortex_tx_timeout; + dev->open = vortex_open; + dev->hard_start_xmit = vp->full_bus_master_tx ? + boomerang_start_xmit : vortex_start_xmit; + dev->stop = vortex_close; + dev->get_stats = vortex_get_stats; + dev->do_ioctl = vortex_ioctl; + dev->set_multicast_list = set_rx_mode; + dev->tx_timeout = vortex_tx_timeout; dev->watchdog_timeo = (watchdog * HZ) / 1000; return 0; free_region: - release_region (ioaddr, vci->io_size); -free_dev: + if (vp->must_free_region) + release_region(ioaddr, vci->io_size); unregister_netdev(dev); kfree (dev); printk(KERN_ERR PFX "vortex_probe1 fails. Returns %d\n", retval); @@ -1082,8 +1121,7 @@ static void wait_for_completion(struct net_device *dev, int cmd) int i = 4000; outw(cmd, dev->base_addr + EL3_CMD); - while (--i > 0) - { + while (--i > 0) { if (!(inw(dev->base_addr + EL3_STATUS) & CmdInProgress)) return; } @@ -1136,9 +1174,13 @@ vortex_up(struct net_device *dev) init_timer(&vp->timer); vp->timer.expires = RUN_AT(media_tbl[dev->if_port].wait); vp->timer.data = (unsigned long)dev; - vp->timer.function = &vortex_timer; /* timer handler */ + vp->timer.function = vortex_timer; /* timer handler */ add_timer(&vp->timer); + init_timer(&vp->rx_oom_timer); + vp->rx_oom_timer.data = (unsigned long)dev; + vp->rx_oom_timer.function = rx_oom_timer; + if (vortex_debug > 1) printk(KERN_DEBUG "%s: Initial media type %s.\n", dev->name, media_tbl[dev->if_port].name); @@ -1157,13 +1199,14 @@ vortex_up(struct net_device *dev) int mii_reg1, mii_reg5; EL3WINDOW(4); /* Read BMSR (reg1) only to clear old status. */ - mii_reg1 = mdio_read(ioaddr, vp->phys[0], 1); - mii_reg5 = mdio_read(ioaddr, vp->phys[0], 5); + mii_reg1 = mdio_read(dev, vp->phys[0], 1); + mii_reg5 = mdio_read(dev, vp->phys[0], 5); if (mii_reg5 == 0xffff || mii_reg5 == 0x0000) ; /* No MII device or no link partner report */ else if ((mii_reg5 & 0x0100) != 0 /* 100baseTx-FD */ || (mii_reg5 & 0x00C0) == 0x0040) /* 10T-FD, but not 100-HD */ vp->full_duplex = 1; + vp->partner_flow_ctrl = ((mii_reg5 & 0x0400) != 0); if (vortex_debug > 1) printk(KERN_INFO "%s: MII #%d status %4.4x, link partner capability %4.4x," " setting %s-duplex.\n", dev->name, vp->phys[0], @@ -1172,8 +1215,10 @@ vortex_up(struct net_device *dev) } /* Set the full-duplex bit. */ - outb(((vp->info1 & 0x8000) || vp->full_duplex ? 0x20 : 0) | - (dev->mtu > 1500 ? 0x40 : 0), ioaddr + Wn3_MAC_Ctrl); + outw( ((vp->info1 & 0x8000) || vp->full_duplex ? 0x20 : 0) | + (dev->mtu > 1500 ? 0x40 : 0) | + ((vp->full_duplex && vp->flow_ctrl && vp->partner_flow_ctrl) ? 0x100 : 0), + ioaddr + Wn3_MAC_Ctrl); if (vortex_debug > 1) { printk(KERN_DEBUG "%s: vortex_up() InternalConfig %8.8x.\n", @@ -1199,15 +1244,10 @@ vortex_up(struct net_device *dev) outw(0, ioaddr + i); if (vp->cb_fn_base) { - u_short n = inw(ioaddr + Wn2_ResetOptions); -#if 0 /* AKPM: This is done in vortex_probe1, and seems to be wrong anyway... */ - /* Inverted LED polarity */ - if (device_id != 0x5257) - n |= 0x0010; -#endif - /* Inverted polarity of MII power bit */ - if ((device_id == 0x6560) || (device_id == 0x6562) || - (device_id == 0x5257)) + unsigned short n = inw(ioaddr + Wn2_ResetOptions) & ~0x4010; + if (vp->drv_flags & INVERT_LED_PWR) + n |= 0x10; + if (vp->drv_flags & INVERT_MII_PWR) n |= 0x4000; outw(n, ioaddr + Wn2_ResetOptions); } @@ -1245,9 +1285,9 @@ vortex_up(struct net_device *dev) outl(vp->rx_ring_dma, ioaddr + UpListPtr); } if (vp->full_bus_master_tx) { /* Boomerang bus master Tx. */ - dev->hard_start_xmit = &boomerang_start_xmit; vp->cur_tx = vp->dirty_tx = 0; - outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); /* Room for a packet. */ + if (vp->drv_flags & IS_BOOMERANG) + outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); /* Room for a packet. */ /* Clear the Rx, Tx rings. */ for (i = 0; i < RX_RING_SIZE; i++) /* AKPM: this is done in vortex_open, too */ vp->rx_ring[i].status = 0; @@ -1277,17 +1317,6 @@ vortex_up(struct net_device *dev) outw(vp->intr_enable, ioaddr + EL3_CMD); if (vp->cb_fn_base) /* The PCMCIA people are idiots. */ writel(0x8000, vp->cb_fn_base + 4); - - if (extra_reset) - { - /* AKPM: unjam the 3CCFE575CT */ - wait_for_completion(dev, TxReset); - if (vp->full_bus_master_tx) { - outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); - outw(DownUnstall, ioaddr + EL3_CMD); - } - outw(TxEnable, ioaddr + EL3_CMD); - } netif_start_queue (dev); } @@ -1301,9 +1330,9 @@ vortex_open(struct net_device *dev) MOD_INC_USE_COUNT; /* Use the now-standard shared IRQ implementation. */ - if (request_irq(dev->irq, vp->full_bus_master_rx ? &boomerang_interrupt : &vortex_interrupt, - SA_SHIRQ, dev->name, dev)) { - retval = -EAGAIN; + if ((retval = request_irq(dev->irq, vp->full_bus_master_rx ? + &boomerang_interrupt : &vortex_interrupt, SA_SHIRQ, dev->name, dev))) { + printk(KERN_ERR "%s: Could not reserve IRQ %d\n", dev->name, dev->irq); goto out; } @@ -1323,6 +1352,17 @@ vortex_open(struct net_device *dev) skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ vp->rx_ring[i].addr = cpu_to_le32(pci_map_single(vp->pdev, skb->tail, PKT_BUF_SZ, PCI_DMA_FROMDEVICE)); } + if (i != RX_RING_SIZE) { + int j; + for (j = 0; j < RX_RING_SIZE; j++) { + if (vp->rx_skbuff[j]) { + dev_kfree_skb(vp->rx_skbuff[j]); + vp->rx_skbuff[j] = 0; + } + } + retval = -ENOMEM; + goto out_free_irq; + } /* Wrap the ring. */ vp->rx_ring[i-1].next = cpu_to_le32(vp->rx_ring_dma); } @@ -1330,10 +1370,13 @@ vortex_open(struct net_device *dev) vortex_up(dev); vp->open = 1; return 0; + +out_free_irq: + free_irq(dev->irq, dev); out: - MOD_DEC_USE_COUNT; if (vortex_debug > 1) - printk(KERN_ERR PFX "vortex_open() fails: returning %d\n", retval); + printk(KERN_ERR "%s: vortex_open() fails: returning %d\n", dev->name, retval); + MOD_DEC_USE_COUNT; return retval; } @@ -1346,7 +1389,7 @@ static void vortex_timer(unsigned long data) int ok = 0; int media_status, mii_status, old_window; - if (vortex_debug > 1) { + if (vortex_debug > 2) { printk(KERN_DEBUG "%s: Media selection timer tick happened, %s.\n", dev->name, media_tbl[dev->if_port].name); printk(KERN_DEBUG "dev->watchdog_timeo=%d\n", dev->watchdog_timeo); @@ -1369,16 +1412,13 @@ static void vortex_timer(unsigned long data) break; case XCVR_MII: case XCVR_NWAY: { - unsigned long flags; - spin_lock_irqsave(&vp->lock, flags); /* AKPM: protect mdio state */ - - mii_status = mdio_read(ioaddr, vp->phys[0], 1); + mii_status = mdio_read(dev, vp->phys[0], 1); ok = 1; - if (vortex_debug > 1) + if (vortex_debug > 2) printk(KERN_DEBUG "%s: MII transceiver has status %4.4x.\n", dev->name, mii_status); if (mii_status & 0x0004) { - int mii_reg5 = mdio_read(ioaddr, vp->phys[0], 5); + int mii_reg5 = mdio_read(dev, vp->phys[0], 5); if (! vp->force_fd && mii_reg5 != 0xffff) { int duplex = (mii_reg5&0x0100) || (mii_reg5 & 0x01C0) == 0x0040; @@ -1390,17 +1430,16 @@ static void vortex_timer(unsigned long data) vp->phys[0], mii_reg5); /* Set the full-duplex bit. */ EL3WINDOW(3); /* AKPM: this was missing from 2.3.99 3c59x.c! */ - outb((vp->full_duplex ? 0x20 : 0) | - (dev->mtu > 1500 ? 0x40 : 0), - ioaddr + Wn3_MAC_Ctrl); + outw( (vp->full_duplex ? 0x20 : 0) | + (dev->mtu > 1500 ? 0x40 : 0) | + ((vp->full_duplex && vp->flow_ctrl && vp->partner_flow_ctrl) ? 0x100 : 0), + ioaddr + Wn3_MAC_Ctrl); if (vortex_debug > 1) printk(KERN_DEBUG "Setting duplex in Wn3_MAC_Ctrl\n"); /* AKPM: bug: should reset Tx and Rx after setting Duplex. Page 180 */ } - next_tick = 60*HZ; } } - spin_unlock_irqrestore(&vp->lock, flags); } break; default: /* Other media types handled by Tx timeouts. */ @@ -1445,7 +1484,7 @@ static void vortex_timer(unsigned long data) EL3WINDOW(old_window); enable_irq(dev->irq); - if (vortex_debug > 1) + if (vortex_debug > 2) printk(KERN_DEBUG "%s: Media selection timer finished, %s.\n", dev->name, media_tbl[dev->if_port].name); @@ -1506,7 +1545,8 @@ static void vortex_tx_timeout(struct net_device *dev) } if (vp->tx_full) netif_stop_queue (dev); - outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); + if (vp->drv_flags & IS_BOOMERANG) + outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); outw(DownUnstall, ioaddr + EL3_CMD); } else { vp->stats.tx_dropped++; @@ -1549,8 +1589,8 @@ vortex_error(struct net_device *dev, int status) if (tx_status & 0x14) vp->stats.tx_fifo_errors++; if (tx_status & 0x38) vp->stats.tx_aborted_errors++; outb(0, ioaddr + TxStatus); - if (tx_status & 0x38) /* AKPM: tx reset after 16 collisions, despite what the manual says */ - do_tx_reset = 1; + if (tx_status & 0x3a) /* TxReset after 16 collisions, despite what the manual says */ + do_tx_reset = 1; /* Also reset on reclaim errors */ else /* Merely re-enable the transmitter. */ outw(TxEnable, ioaddr + EL3_CMD); } @@ -1592,7 +1632,7 @@ vortex_error(struct net_device *dev, int status) /* In this case, blow the card away */ vortex_down(dev); wait_for_completion(dev, TotalReset | 0xff); - vortex_up(dev); + vortex_up(dev); /* AKPM: bug. vortex_up() assumes that the rx ring is full. It may not be. */ } else if (fifo_diag & 0x0400) do_tx_reset = 1; if (fifo_diag & 0x3000) { @@ -1706,12 +1746,13 @@ boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev) struct boom_tx_desc *prev_entry = &vp->tx_ring[(vp->cur_tx-1) % TX_RING_SIZE]; unsigned long flags; - if (vortex_debug > 6) + if (vortex_debug > 6) { printk(KERN_DEBUG "boomerang_start_xmit()\n"); + if (vortex_debug > 3) + printk(KERN_DEBUG "%s: Trying to send a packet, Tx index %d.\n", + dev->name, vp->cur_tx); + } - if (vortex_debug > 3) - printk(KERN_DEBUG "%s: Trying to send a packet, Tx index %d.\n", - dev->name, vp->cur_tx); if (vp->tx_full) { if (vortex_debug > 0) printk(KERN_WARNING "%s: Tx Ring full, refusing to send buffer.\n", @@ -1765,15 +1806,18 @@ static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs) long ioaddr; int status; int work_done = max_interrupt_work; - - spin_lock(&vp->lock); ioaddr = dev->base_addr; + spin_lock(&vp->lock); + status = inw(ioaddr + EL3_STATUS); if (vortex_debug > 6) printk("vortex_interrupt(). status=0x%4x\n", status); + if ((status & IntLatch) == 0) + goto handler_exit; /* No interrupt: shared IRQs cause this */ + if (status & IntReq) { status |= vp->deferred; vp->deferred = 0; @@ -1785,6 +1829,7 @@ static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs) if (vortex_debug > 4) printk(KERN_DEBUG "%s: interrupt, status %4.4x, latency %d ticks.\n", dev->name, status, inb(ioaddr + Timer)); + do { if (vortex_debug > 5) printk(KERN_DEBUG "%s: In interrupt loop, status %4.4x.\n", @@ -1841,9 +1886,6 @@ static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs) } /* Acknowledge the IRQ. */ outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD); - if (vp->cb_fn_base) /* The PCMCIA people are idiots. */ - writel(0x8000, vp->cb_fn_base + 4); - } while ((status = inw(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete)); if (vortex_debug > 4) @@ -1866,14 +1908,22 @@ static void boomerang_interrupt(int irq, void *dev_id, struct pt_regs *regs) int status; int work_done = max_interrupt_work; - spin_lock(&vp->lock); - ioaddr = dev->base_addr; + + /* + * It seems dopey to put the spinlock this early, but we could race against vortex_tx_timeout + * and boomerang_start_xmit + */ + spin_lock(&vp->lock); + status = inw(ioaddr + EL3_STATUS); if (vortex_debug > 6) printk(KERN_DEBUG "boomerang_interrupt. status=0x%4x\n", status); + if ((status & IntLatch) == 0) + goto handler_exit; /* No interrupt: shared IRQs can cause this */ + if (status == 0xffff) { /* AKPM: h/w no longer present (hotplug)? */ if (vortex_debug > 1) printk(KERN_DEBUG "boomerang_interrupt(1): status = 0xffff\n"); @@ -2120,6 +2170,8 @@ boomerang_rx(struct net_device *dev) printk(KERN_WARNING "%s: memory shortage\n", dev->name); last_jif = jiffies; } + if ((vp->cur_rx - vp->dirty_rx) == RX_RING_SIZE) + mod_timer(&vp->rx_oom_timer, RUN_AT(HZ * 1)); break; /* Bad news! */ } skb->dev = dev; /* Mark as being used by this device. */ @@ -2133,6 +2185,26 @@ boomerang_rx(struct net_device *dev) return 0; } +/* + * If we've hit a total OOM refilling the Rx ring we poll once a second + * for some memory. Otherwise there is no way to restart the rx process. + */ +static void +rx_oom_timer(unsigned long arg) +{ + struct net_device *dev = (struct net_device *)arg; + struct vortex_private *vp = (struct vortex_private *)dev->priv; + + spin_lock_irq(&vp->lock); + if ((vp->cur_rx - vp->dirty_rx) == RX_RING_SIZE) /* This test is redundant, but makes me feel good */ + boomerang_rx(dev); + if (vortex_debug > 1) { + printk(KERN_DEBUG "%s: rx_oom_timer %s\n", dev->name, + ((vp->cur_rx - vp->dirty_rx) != RX_RING_SIZE) ? "succeeded" : "retrying"); + } + spin_unlock_irq(&vp->lock); +} + static void vortex_down(struct net_device *dev) { @@ -2141,6 +2213,7 @@ vortex_down(struct net_device *dev) netif_stop_queue (dev); + del_timer_sync(&vp->rx_oom_timer); del_timer_sync(&vp->timer); /* Turn off statistics ASAP. We update vp->stats below. */ @@ -2311,16 +2384,13 @@ static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) u16 *data = (u16 *)&rq->ifr_data; int phy = vp->phys[0] & 0x1f; int retval; - unsigned long flags; - - spin_lock_irqsave(&vp->lock, flags); switch(cmd) { case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ data[0] = phy; case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ EL3WINDOW(4); - data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f); + data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f); retval = 0; break; case SIOCDEVPRIVATE+2: /* Write the specified MII register */ @@ -2328,7 +2398,7 @@ static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) retval = -EPERM; } else { EL3WINDOW(4); - mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]); + mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]); retval = 0; } break; @@ -2337,7 +2407,6 @@ static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) break; } - spin_unlock_irqrestore(&vp->lock, flags); return retval; } @@ -2393,13 +2462,17 @@ static void mdio_sync(long ioaddr, int bits) } } -static int mdio_read(long ioaddr, int phy_id, int location) +static int mdio_read(struct net_device *dev, int phy_id, int location) { + struct vortex_private *vp = (struct vortex_private *)dev->priv; int i; + long ioaddr = dev->base_addr; int read_cmd = (0xf6 << 10) | (phy_id << 5) | location; unsigned int retval = 0; long mdio_addr = ioaddr + Wn4_PhysicalMgmt; + spin_lock_bh(&vp->mdio_lock); + if (mii_preamble_required) mdio_sync(ioaddr, 32); @@ -2419,15 +2492,20 @@ static int mdio_read(long ioaddr, int phy_id, int location) outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(); } + spin_unlock_bh(&vp->mdio_lock); return retval & 0x20000 ? 0xffff : retval>>1 & 0xffff; } -static void mdio_write(long ioaddr, int phy_id, int location, int value) +static void mdio_write(struct net_device *dev, int phy_id, int location, int value) { + struct vortex_private *vp = (struct vortex_private *)dev->priv; + long ioaddr = dev->base_addr; int write_cmd = 0x50020000 | (phy_id << 23) | (location << 18) | value; long mdio_addr = ioaddr + Wn4_PhysicalMgmt; int i; + spin_lock_bh(&vp->mdio_lock); + if (mii_preamble_required) mdio_sync(ioaddr, 32); @@ -2446,7 +2524,7 @@ static void mdio_write(long ioaddr, int phy_id, int location, int value) outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(); } - + spin_unlock_bh(&vp->mdio_lock); return; } @@ -2458,7 +2536,7 @@ static void acpi_set_WOL(struct net_device *dev) long ioaddr = dev->base_addr; /* AKPM: This kills the 905 */ - if (vortex_debug > 0) { + if (vortex_debug > 1) { printk(KERN_INFO PFX "Wake-on-LAN functions disabled\n"); } return; @@ -2493,7 +2571,8 @@ static void __devexit vortex_remove_one (struct pci_dev *pdev) */ unregister_netdev(dev); outw(TotalReset, dev->base_addr + EL3_CMD); - release_region(dev->base_addr, vp->io_size); + if (vp->must_free_region) + release_region(dev->base_addr, vp->io_size); kfree(dev); } @@ -2516,21 +2595,15 @@ static int __init vortex_init (void) { int rc; - rc = pci_module_init (&vortex_driver); - if (rc < 0) - goto out; - - if (rc >= 0) /* AKPM: had "> 0" */ + rc = pci_module_init(&vortex_driver); + if (rc < 0) { + rc = vortex_eisa_init(); + if (rc > 0) + vortex_have_eisa = 1; + } else { vortex_have_pci = 1; + } - rc = vortex_eisa_init (); - if (rc < 0) - goto out; - - if (rc > 0) - vortex_have_eisa = 1; - -out: return rc; } @@ -2575,8 +2648,6 @@ module_exit(vortex_cleanup); /* * Local variables: - * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" - * cardbus-compile-command: "gcc -DCONFIG_HOTPLUG -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c -o 3c575_cb.o -I/usr/src/linux/pcmcia-cs-3.0.9/include/" * c-indent-level: 4 * c-basic-offset: 4 * tab-width: 4 diff --git a/drivers/net/Config.in b/drivers/net/Config.in index 2f9442b22..8a2aff56d 100644 --- a/drivers/net/Config.in +++ b/drivers/net/Config.in @@ -8,9 +8,10 @@ source drivers/net/appletalk/Config.in tristate 'Dummy net driver support' CONFIG_DUMMY tristate 'Bonding driver support' CONFIG_BONDING tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER +tristate 'Universal TUN/TAP device driver support' CONFIG_TUN if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then if [ "$CONFIG_NETLINK" = "y" ]; then - tristate 'Ethertap network tap (EXPERIMENTAL)' CONFIG_ETHERTAP + tristate 'Ethertap network tap (OBSOLETE)' CONFIG_ETHERTAP fi fi @@ -143,15 +144,18 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then bool ' Enable Power Management (EXPERIMENTAL)' CONFIG_EEPRO100_PM fi tristate ' Mylex EISA LNE390A/B support (EXPERIMENTAL)' CONFIG_LNE390 - tristate ' Novell/Eagle/Microdyne NE3210 EISA support (EXPERIMENTAL)' CONFIG_NE3210 fi + dep_tristate ' National Semiconductor DP83810 series PCI Ethernet support' CONFIG_NATSEMI $CONFIG_PCI dep_tristate ' PCI NE2000 support' CONFIG_NE2K_PCI $CONFIG_PCI - # tristate ' Sundance Alta support' CONFIG_ALTA + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate ' Novell/Eagle/Microdyne NE3210 EISA support (EXPERIMENTAL)' CONFIG_NE3210 + fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate ' RealTek 8129 (not 8019/8029!) support (EXPERIMENTAL)' CONFIG_RTL8129 fi tristate ' RealTek RTL-8139 PCI Fast Ethernet Adapter support' CONFIG_8139TOO tristate ' SiS 900/7016 PCI Fast Ethernet Adapter support' CONFIG_SIS900 + # tristate ' Sundance Alta support' CONFIG_ALTA tristate ' TI ThunderLAN support' CONFIG_TLAN tristate ' VIA Rhine support' CONFIG_VIA_RHINE if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then diff --git a/drivers/net/Makefile b/drivers/net/Makefile index e5ac867a6..5aa7f5858 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -136,7 +136,7 @@ obj-$(CONFIG_SIS900) += sis900.o obj-$(CONFIG_DM9102) += dmfe.o obj-$(CONFIG_YELLOWFIN) += yellowfin.o obj-$(CONFIG_ACENIC) += acenic.o - +obj-$(CONFIG_NATSEMI) += natsemi.o obj-$(CONFIG_STNIC) += stnic.o 8390.o ifeq ($(CONFIG_SK98LIN),y) @@ -273,7 +273,7 @@ obj-$(CONFIG_CS89x0) += cs89x0.o obj-$(CONFIG_MACSONIC) += macsonic.o obj-$(CONFIG_MACMACE) += macmace.o obj-$(CONFIG_MAC89x0) += mac89x0.o - +obj-$(CONFIG_TUN) += tun.o # # HIPPI adapters # diff --git a/drivers/net/Space.c b/drivers/net/Space.c index 25257b052..5a64da542 100644 --- a/drivers/net/Space.c +++ b/drivers/net/Space.c @@ -102,11 +102,10 @@ extern int macsonic_probe(struct net_device *dev); extern int mac8390_probe(struct net_device *dev); extern int mac89x0_probe(struct net_device *dev); - /* Gigabit Ethernet adapters */ - extern int yellowfin_probe(struct net_device *dev); +/* Gigabit Ethernet adapters */ +extern int yellowfin_probe(struct net_device *dev); /* Detachable devices ("pocket adaptors") */ -extern int atp_init(struct net_device *); extern int de600_probe(struct net_device *); extern int de620_probe(struct net_device *); @@ -310,9 +309,6 @@ struct devprobe parport_probes[] __initdata = { #ifdef CONFIG_DE620 /* D-Link DE-620 adapter */ {de620_probe, 0}, #endif -#ifdef CONFIG_ATP /* AT-LAN-TEC (RealTek) pocket adaptor. */ - {atp_init, 0}, -#endif {NULL, 0}, }; @@ -681,8 +677,15 @@ static struct net_device tr0_dev = { #undef NEXT_DEV #define NEXT_DEV (&escon0_dev) #endif - - + +#ifdef CONFIG_TUN + extern int tun_init(struct net_device *dev); + static struct net_device tun_dev = { + "tun", 0, 0, 0, 0, 0, 0, 0, 0, 0, NEXT_DEV, tun_init }; +# undef NEXT_DEV +# define NEXT_DEV (&tun_dev) +#endif + /* * The loopback device is global so it can be directly referenced * by the network code. Also, it must be first on device list. diff --git a/drivers/net/atp.c b/drivers/net/atp.c index 096dd03c5..a898fbb02 100644 --- a/drivers/net/atp.c +++ b/drivers/net/atp.c @@ -154,7 +154,7 @@ static void set_multicast_list(struct net_device *dev); (detachable devices only). */ -int __init atp_init(struct net_device *dev) +static int __init atp_init(struct net_device *dev) { int *port, ports[] = {0x378, 0x278, 0x3bc, 0}; int base_addr = dev->base_addr; @@ -336,6 +336,9 @@ static int net_open(struct net_device *dev) return -EAGAIN; } hardware_init(dev); + + MOD_INC_USE_COUNT; + netif_start_queue(dev); return 0; } @@ -702,6 +705,8 @@ static int net_close(struct net_device *dev) /* Leave the hardware in a reset state. */ write_reg_high(ioaddr, CMR1, CMR1h_RESET); + MOD_DEC_USE_COUNT; + return 0; } @@ -735,35 +740,27 @@ static void set_multicast_list(struct net_device *dev) lp->addr_mode = num_addrs ? CMR2h_PROMISC : CMR2h_Normal; write_reg_high(ioaddr, CMR2, lp->addr_mode); } - -/* - * Local variables: - * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c atp.c" - * version-control: t - * kept-new-versions: 5 - * tab-width: 4 - * End: - */ - -#ifdef MODULE -static int io = 0; -static struct net_device atp_dev = { - "", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, atp_init }; - +/* module stuff */ +static int io; +static struct net_device atp_dev = { init: atp_init }; +MODULE_AUTHOR("Donald Becker <becker@scyld.com>"); +MODULE_DESCRIPTION("Realtek 8002/8012 Pocket Lan Adapter"); MODULE_PARM(io, "I/O port of the pocket adapter"); -int init_module(void) -{ +static int __init atp_init_module(void) { atp_dev.base_addr = io; + if (register_netdev(&atp_dev) != 0) return -EIO; + return 0; } -void cleanup_module(void) -{ +static void __exit atp_cleanup_module(void) { unregister_netdev(&atp_dev); } -#endif +module_init(atp_init_module); +module_exit(atp_cleanup_module); + diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c index c343bc53c..485852c0e 100644 --- a/drivers/net/eepro100.c +++ b/drivers/net/eepro100.c @@ -23,6 +23,8 @@ Convert to new PCI driver interface 2000 Mar 24 Dragan Stancevic <visitor@valinux.com> Disabled FC and ER, to avoid lockups when when we get FCP interrupts. + 2000 Jul 17 Goutham Rao <goutham.rao@intel.com> + PCI DMA API fixes, adding pci_dma_sync_single calls where neccesary */ static const char *version = @@ -515,6 +517,7 @@ struct speedo_private { spinlock_t lock; /* Group with Tx control cache line. */ u32 tx_threshold; /* The value for txdesc.count. */ struct RxFD *last_rxf; /* Last filled RX buffer. */ + dma_addr_t last_rxf_dma; unsigned int cur_rx, dirty_rx; /* The next free ring entry */ long last_rx_time; /* Last Rx, in jiffies, to handle Rx hang. */ const char *product_name; @@ -1213,19 +1216,24 @@ speedo_init_rx_ring(struct net_device *dev) sp->rx_ring_dma[i] = pci_map_single(sp->pdev, rxf, PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE); skb_reserve(skb, sizeof(struct RxFD)); - if (last_rxf) + if (last_rxf) { last_rxf->link = cpu_to_le32(sp->rx_ring_dma[i]); + pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[i-1], sizeof(struct RxFD), PCI_DMA_TODEVICE); + } last_rxf = rxf; rxf->status = cpu_to_le32(0x00000001); /* '1' is flag value only. */ rxf->link = 0; /* None yet. */ /* This field unused by i82557. */ rxf->rx_buf_addr = 0xffffffff; rxf->count = cpu_to_le32(PKT_BUF_SZ << 16); + pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[i], sizeof(struct RxFD), PCI_DMA_TODEVICE); } sp->dirty_rx = (unsigned int)(i - RX_RING_SIZE); /* Mark the last entry as end-of-list. */ last_rxf->status = cpu_to_le32(0xC0000002); /* '2' is flag value only. */ + pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[RX_RING_SIZE-1], sizeof(struct RxFD), PCI_DMA_TODEVICE); sp->last_rxf = last_rxf; + sp->last_rxf_dma = sp->rx_ring_dma[RX_RING_SIZE-1]; } static void speedo_purge_tx(struct net_device *dev) @@ -1660,6 +1668,7 @@ static inline struct RxFD *speedo_rx_alloc(struct net_device *dev, int entry) skb->dev = dev; skb_reserve(skb, sizeof(struct RxFD)); rxf->rx_buf_addr = 0xffffffff; + pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[entry], sizeof(struct RxFD), PCI_DMA_TODEVICE); return rxf; } @@ -1672,7 +1681,9 @@ static inline void speedo_rx_link(struct net_device *dev, int entry, rxf->count = cpu_to_le32(PKT_BUF_SZ << 16); sp->last_rxf->link = cpu_to_le32(rxf_dma); sp->last_rxf->status &= cpu_to_le32(~0xC0000000); + pci_dma_sync_single(sp->pdev, sp->last_rxf_dma, sizeof(struct RxFD), PCI_DMA_TODEVICE); sp->last_rxf = rxf; + sp->last_rxf_dma = rxf_dma; } static int speedo_refill_rx_buf(struct net_device *dev, int force) @@ -1738,9 +1749,17 @@ speedo_rx(struct net_device *dev) if (speedo_debug > 4) printk(KERN_DEBUG " In speedo_rx().\n"); /* If we own the next entry, it's a new packet. Send it up. */ - while (sp->rx_ringp[entry] != NULL && - (status = le32_to_cpu(sp->rx_ringp[entry]->status)) & RxComplete) { - int pkt_len = le32_to_cpu(sp->rx_ringp[entry]->count) & 0x3fff; + while (sp->rx_ringp[entry] != NULL) { + int pkt_len; + + pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[entry], + sizeof(struct RxFD), PCI_DMA_FROMDEVICE); + + if(!((status = le32_to_cpu(sp->rx_ringp[entry]->status)) & RxComplete)) { + break; + } + + pkt_len = le32_to_cpu(sp->rx_ringp[entry]->count) & 0x3fff; if (--rx_work_limit < 0) break; @@ -1782,7 +1801,8 @@ speedo_rx(struct net_device *dev) skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ /* 'skb_put()' points to the start of sk_buff data area. */ pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[entry], - PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE); + sizeof(struct RxFD) + pkt_len, PCI_DMA_FROMDEVICE); + #if 1 || USE_IP_CSUM /* Packet is in one chunk -- we can copy + cksum. */ eth_copy_and_sum(skb, sp->rx_skbuff[entry]->tail, pkt_len, 0); @@ -2166,6 +2186,8 @@ static void set_rx_mode(struct net_device *dev) mc_setup_frm->link = cpu_to_le32(TX_RING_ELEM_DMA(sp, (entry + 1) % TX_RING_SIZE)); + pci_dma_sync_single(sp->pdev, mc_blk->frame_dma, mc_blk->len, PCI_DMA_TODEVICE); + wait_for_cmd_done(ioaddr + SCBCmd); clear_suspend(last_cmd); /* Immediately trigger the command unit resume. */ diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c index f1723670c..afa7538af 100644 --- a/drivers/net/epic100.c +++ b/drivers/net/epic100.c @@ -19,17 +19,30 @@ Information and updates available at http://www.scyld.com/network/epic100.html + + --------------------------------------------------------------------- Linux kernel-specific changes: LK1.1.2 (jgarzik): - * Merge becker version 1.09 + * Merge becker version 1.09 (4/08/2000) LK1.1.3: * Major bugfix to 1.09 driver (Francis Romieu) + + LK1.1.4 (jgarzik): + * Merge becker test version 1.09 (5/29/2000) */ +/* These identify the driver base version and may not be removed. */ +static const char version[] = +"epic100.c:v1.09 5/29/2000 Written by Donald Becker <becker@scyld.com>\n"; +static const char version2[] = +" http://www.scyld.com/network/epic100.html\n"; +static const char version3[] = +" (unofficial 2.4.x kernel port, version 1.1.4, August 10, 2000)\n"; + /* The user-configurable values. These may be modified when a driver module is loaded.*/ @@ -44,11 +57,12 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; /* Set the copy breakpoint for the copy-only-tiny-frames scheme. Setting to > 1518 effectively disables this feature. */ -static int rx_copybreak = 200; +static int rx_copybreak = 0; /* Operational parameters that are set at compile time. */ -/* Keep the ring sizes a power of two for efficiency. +/* Keep the ring sizes a power of two for operational efficiency. + The compiler will convert <unsigned>'%'<2^N> into a bit mask. 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. */ @@ -73,7 +87,12 @@ static int rx_copybreak = 200; #error You must compile this driver with "-O". #endif +#include <linux/version.h> #include <linux/module.h> +#if LINUX_VERSION_CODE < 0x20300 && defined(MODVERSIONS) +#include <linux/modversions.h> +#endif + #include <linux/kernel.h> #include <linux/string.h> #include <linux/timer.h> @@ -91,15 +110,6 @@ static int rx_copybreak = 200; #include <asm/bitops.h> #include <asm/io.h> -/* These identify the driver base version and may not be removed. */ -static char version[] __devinitdata = -"epic100.c:v1.09+LK1.1.3 6/17/2000 Written by Donald Becker <becker@scyld.com>\n"; -static char version2[] __devinitdata = -" http://www.scyld.com/network/epic100.html\n"; - -#define EPIC100_MODULE_NAME "epic100" -#define PFX EPIC100_MODULE_NAME ": " - MODULE_AUTHOR("Donald Becker <becker@scyld.com>"); MODULE_DESCRIPTION("SMC 83c170 EPIC series Ethernet driver"); MODULE_PARM(debug, "i"); @@ -133,7 +143,7 @@ IVb. References http://www.smsc.com/main/datasheets/83c171.pdf http://www.smsc.com/main/datasheets/83c175.pdf -http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html +http://scyld.com/expert/NWay.html http://www.national.com/pf/DP/DP83840A.html IVc. Errata @@ -149,10 +159,8 @@ enum pci_id_flags_bits { PCI_ADDR_64BITS=0x100, PCI_NO_ACPI_WAKE=0x200, PCI_NO_MIN_LATENCY=0x400, }; - enum chip_capability_flags { MII_PWRDWN=1, TYPE2_INTR=2, NO_MII=4 }; - #define EPIC_TOTAL_SIZE 0x100 #ifdef USE_IO_OPS #define EPIC_IOTYPE PCI_USES_MASTER|PCI_USES_IO|PCI_ADDR0 @@ -289,6 +297,7 @@ struct epic_private { int tx_threshold; unsigned char mc_filter[8]; signed char phys[4]; /* MII device addresses. */ + u16 advertising; /* NWay media advertisement */ int mii_phy_cnt; unsigned int tx_full:1; /* The Tx queue is full. */ unsigned int full_duplex:1; /* Current duplex setting. */ @@ -332,7 +341,8 @@ static int __devinit epic_init_one (struct pci_dev *pdev, card_idx++; if (!printed_version++) - printk (KERN_INFO "%s" KERN_INFO "%s", version, version2); + printk (KERN_INFO "%s" KERN_INFO "%s" KERN_INFO "%s", + version, version2, version3); if ((pci_resource_len(pdev, 0) < ci->io_size) || (pci_resource_len(pdev, 1) < ci->io_size)) { @@ -357,12 +367,12 @@ static int __devinit epic_init_one (struct pci_dev *pdev, * to them */ if (!request_region (pci_resource_start (pdev, 0), pci_resource_len (pdev, 0), dev->name)) { - printk (KERN_ERR PFX "card %d: I/O region busy\n", card_idx); + printk (KERN_ERR "epic100 %d: I/O region busy\n", card_idx); goto err_out_free_netdev; } if (!request_mem_region (pci_resource_start (pdev, 1), pci_resource_len (pdev, 1), dev->name)) { - printk (KERN_ERR PFX "card %d: I/O region busy\n", card_idx); + printk (KERN_ERR "epic100 %d: I/O region busy\n", card_idx); goto err_out_free_pio; } @@ -372,7 +382,7 @@ static int __devinit epic_init_one (struct pci_dev *pdev, ioaddr = pci_resource_start (pdev, 1); ioaddr = (long) ioremap (ioaddr, pci_resource_len (pdev, 1)); if (!ioaddr) { - printk (KERN_ERR PFX "card %d: ioremap failed\n", card_idx); + printk (KERN_ERR "epic100 %d: ioremap failed\n", card_idx); goto err_out_free_mmio; } #endif @@ -387,7 +397,7 @@ static int __devinit epic_init_one (struct pci_dev *pdev, duplex = full_duplex[card_idx]; } - pdev->driver_data = dev; + pdev->driver_data = dev; dev->base_addr = ioaddr; dev->irq = pdev->irq; @@ -426,25 +436,26 @@ static int __devinit epic_init_one (struct pci_dev *pdev, /* Find the connected MII xcvrs. Doing this in open() would allow detecting external xcvrs later, but - takes too much time. */ + takes much time and no cards have external MII. */ { - int phy, phy_idx; - for (phy = 1, phy_idx = 0; phy < 32 && phy_idx < sizeof(ep->phys); - phy++) { + int phy, phy_idx = 0; + for (phy = 1; phy < 32 && phy_idx < sizeof(ep->phys); phy++) { int mii_status = mdio_read(ioaddr, phy, 1); - if (mii_status != 0xffff && mii_status != 0x0000) { + if (mii_status != 0xffff && mii_status != 0x0000) { ep->phys[phy_idx++] = phy; printk(KERN_INFO "%s: MII transceiver #%d control " - "%4.4x status %4.4x.\n" - KERN_INFO "%s: Autonegotiation advertising %4.4x " - "link partner %4.4x.\n", - dev->name, phy, mdio_read(ioaddr, phy, 0), mii_status, - dev->name, mdio_read(ioaddr, phy, 4), - mdio_read(ioaddr, phy, 5)); + "%4.4x status %4.4x.\n", + dev->name, phy, mdio_read(ioaddr, phy, 0), mii_status); } } ep->mii_phy_cnt = phy_idx; - if (phy_idx == 0 && (ep->chip_flags & NO_MII) == 0) { + if (phy_idx != 0) { + phy = ep->phys[0]; + ep->advertising = mdio_read(ioaddr, phy, 4); + printk( KERN_INFO "%s: Autonegotiation advertising %4.4x link " + "partner %4.4x.\n", + dev->name, ep->advertising, mdio_read(ioaddr, phy, 5)); + } else if ( ! (ep->chip_flags & NO_MII)) { printk(KERN_WARNING "%s: ***WARNING***: No MII transceiver found!\n", dev->name); /* Use the known PHY address of the EPII. */ @@ -668,7 +679,7 @@ static int epic_open(struct net_device *dev) if (debug > 1) printk(KERN_DEBUG "%s: epic_open() ioaddr %lx IRQ %d status %4.4x " "%s-duplex.\n", - dev->name, ioaddr, dev->irq, inl(ioaddr + GENCTL), + dev->name, ioaddr, dev->irq, (int)inl(ioaddr + GENCTL), ep->full_duplex ? "full" : "half"); /* Set the timer to switch to check for link beat and perhaps switch @@ -752,8 +763,8 @@ static void epic_restart(struct net_device *dev) ioaddr + INTMASK); printk(KERN_DEBUG "%s: epic_restart() done, cmd status %4.4x, ctl %4.4x" " interrupt %4.4x.\n", - dev->name, inl(ioaddr + COMMAND), inl(ioaddr + GENCTL), - inl(ioaddr + INTSTAT)); + dev->name, (int)inl(ioaddr + COMMAND), (int)inl(ioaddr + GENCTL), + (int)inl(ioaddr + INTSTAT)); return; } @@ -764,18 +775,19 @@ static void epic_timer(unsigned long data) long ioaddr = dev->base_addr; int next_tick = 60*HZ; int mii_reg5 = ep->mii_phy_cnt ? mdio_read(ioaddr, ep->phys[0], 5) : 0; + int negotiated = mii_reg5 & ep->advertising; + int duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040; if (debug > 3) { printk(KERN_DEBUG "%s: Media monitor tick, Tx status %8.8x.\n", - dev->name, inl(ioaddr + TxSTAT)); + dev->name, (int)inl(ioaddr + TxSTAT)); printk(KERN_DEBUG "%s: Other registers are IntMask %4.4x " "IntStatus %4.4x RxStatus %4.4x.\n", - dev->name, inl(ioaddr + INTMASK), inl(ioaddr + INTSTAT), - inl(ioaddr + RxSTAT)); + dev->name, (int)inl(ioaddr + INTMASK), + (int)inl(ioaddr + INTSTAT), (int)inl(ioaddr + RxSTAT)); } - if (! ep->force_fd && mii_reg5 != 0xffff) { - int duplex = (mii_reg5&0x0100) || (mii_reg5 & 0x01C0) == 0x0040; + if (! ep->force_fd) { if (ep->full_duplex != duplex) { ep->full_duplex = duplex; printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d link" @@ -797,7 +809,7 @@ static void epic_tx_timeout(struct net_device *dev) if (debug > 0) { printk(KERN_WARNING "%s: Transmit timeout using MII device, " "Tx status %4.4x.\n", - dev->name, inw(ioaddr + TxSTAT)); + dev->name, (int)inw(ioaddr + TxSTAT)); if (debug > 1) { printk(KERN_DEBUG "%s: Tx indices: dirty_tx %d, cur_tx %d.\n", dev->name, ep->dirty_tx, ep->cur_tx); @@ -880,11 +892,11 @@ static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev) ep->tx_skbuff[entry] = skb; ep->tx_ring[entry].bufaddr = virt_to_le32desc(skb->data); - if (free_count < TX_RING_SIZE/2) {/* Typical path */ + if (free_count < TX_QUEUE_LEN/2) {/* Typical path */ ctrl_word = cpu_to_le32(0x100000); /* No interrupt */ - } else if (free_count == TX_RING_SIZE/2) { + } else if (free_count == TX_QUEUE_LEN/2) { ctrl_word = cpu_to_le32(0x140000); /* Tx-done intr. */ - } else if (free_count < TX_RING_SIZE - 1) { + } else if (free_count < TX_QUEUE_LEN - 1) { ctrl_word = cpu_to_le32(0x100000); /* No Tx-done intr. */ } else { /* Leave room for an additional entry. */ @@ -910,7 +922,7 @@ static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev) printk(KERN_DEBUG "%s: Queued Tx packet size %d to slot %d, " "flag %2.2x Tx status %8.8x.\n", dev->name, (int)skb->len, entry, ctrl_word, - inl(dev->base_addr + TxSTAT)); + (int)inl(dev->base_addr + TxSTAT)); return 0; } @@ -924,7 +936,8 @@ static void epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs) long ioaddr = dev->base_addr; int status, boguscnt = max_interrupt_work; - spin_lock(&ep->lock); + if (!spin_trylock(&ep->lock)) + return; do { status = inl(ioaddr + INTSTAT); @@ -932,9 +945,9 @@ static void epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs) outl(status & 0x00007fff, ioaddr + INTSTAT); if (debug > 4) - printk(KERN_DEBUG "%s: interrupt interrupt=%#8.8x new " + printk(KERN_DEBUG "%s: Interrupt, status=%#8.8x new " "intstat=%#8.8x.\n", - dev->name, status, inl(ioaddr + INTSTAT)); + dev->name, status, (int)inl(ioaddr + INTSTAT)); if ((status & IntrSummary) == 0) break; @@ -995,7 +1008,7 @@ static void epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs) #endif ep->dirty_tx = dirty_tx; if (ep->tx_full - && cur_tx - dirty_tx < TX_RING_SIZE + 2) { + && cur_tx - dirty_tx < TX_QUEUE_LEN - 4) { /* The ring is no longer full, clear tbusy. */ ep->tx_full = 0; netif_wake_queue(dev); @@ -1044,7 +1057,7 @@ static void epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs) if (debug > 3) printk(KERN_DEBUG "%s: exiting interrupt, intr_status=%#4.4x.\n", - dev->name, inl(ioaddr + INTSTAT)); + dev->name, status); spin_unlock(&ep->lock); } @@ -1144,7 +1157,7 @@ static int epic_close(struct net_device *dev) if (debug > 1) printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n", - dev->name, inl(ioaddr + INTSTAT)); + dev->name, (int)inl(ioaddr + INTSTAT)); del_timer_sync(&ep->timer); epic_pause(dev); @@ -1333,7 +1346,7 @@ static void epic_resume (struct pci_dev *pdev) static struct pci_driver epic_driver = { - name: EPIC100_MODULE_NAME, + name: "epic100", id_table: epic_pci_tbl, probe: epic_init_one, remove: epic_remove_one, @@ -1356,14 +1369,3 @@ static void __exit epic_cleanup (void) module_init(epic_init); module_exit(epic_cleanup); - - -/* - * Local variables: - * compile-command: "gcc -DMODULE -Wall -Wstrict-prototypes -O6 -c epic100.c" - * cardbus-compile-command: "gcc -DCARDBUS -DMODULE -Wall -Wstrict-prototypes -O6 -c epic100.c -o epic_cb.o -I/usr/src/pcmcia/include/" - * c-indent-level: 4 - * c-basic-offset: 4 - * tab-width: 4 - * End: - */ diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c index 6c5964d83..60cef746f 100644 --- a/drivers/net/ewrk3.c +++ b/drivers/net/ewrk3.c @@ -843,6 +843,7 @@ static int ewrk3_queue_pkt(struct sk_buff *skb, struct net_device *dev) } } + lp->stats.tx_bytes += skb->len; dev->trans_start = jiffies; dev_kfree_skb(skb); } else { /* return unused page to the free memory queue */ @@ -1010,6 +1011,7 @@ static int ewrk3_rx(struct net_device *dev) ** Update stats */ lp->stats.rx_packets++; + lp->stats.rx_bytes += pkt_len; for (i = 1; i < EWRK3_PKT_STAT_SZ - 1; i++) { if (pkt_len < i * EWRK3_PKT_BIN_SZ) { lp->pktStats.bins[i]++; diff --git a/drivers/net/fc/Makefile b/drivers/net/fc/Makefile index 87e599863..a36b9f855 100644 --- a/drivers/net/fc/Makefile +++ b/drivers/net/fc/Makefile @@ -1,27 +1,15 @@ - +# # Makefile for linux/drivers/net/fc # -# Note! Dependencies are done automagically by 'make dep', which also -# removes any old dependencies. DON'T put your own dependencies here -# unless it's something special (ie not a .c file). +# 9 Aug 2000, Christoph Hellwig <hch@caldera.de> +# Rewritten to use lists instead of if-statements. # -L_TARGET := fc.a -L_OBJS := -M_OBJS := -MX_OBJS := -FC_SRCS = $(wildcard $(L_OBJS:%.o=%.c)) +O_TARGET := fc.o -ifeq ($(CONFIG_IPHASE5526),y) -L_OBJS += iph5526.o -else - ifeq ($(CONFIG_IPHASE5526),m) - M_OBJS += iph5526.o - endif -endif +obj-$(CONFIG_IPHASE5526) += iph5526.o -include $(TOPDIR)/Rules.make - -clean: - rm *.o +O_OBJS := $(obj-y) +M_OBJS := $(obj-m) +include $(TOPDIR)/Rules.make diff --git a/drivers/net/hamradio/Makefile b/drivers/net/hamradio/Makefile index c2fb726c3..7ca3c1efd 100644 --- a/drivers/net/hamradio/Makefile +++ b/drivers/net/hamradio/Makefile @@ -1,153 +1,55 @@ -# File: drivers/hamradio/Makefile # # Makefile for the Linux AX.25 and HFMODEM device drivers. # +# # 19971130 Moved the amateur radio related network drivers from # drivers/net/ to drivers/hamradio for easier maintainance. # Joerg Reuter DL1BKE <jreuter@poboxes.com> +# +# 20000806 Rewritten to use lists instead of if-statements. +# Christoph Hellwig <hch@caldera.de> +# SUB_DIRS := MOD_SUB_DIRS := $(SUB_DIRS) -ALL_SUB_DIRS := $(SUB_DIRS) +ALL_SUB_DIRS := $(SUB_DIRS) soundmodem O_TARGET := hamradio.o -O_OBJS := -M_OBJS := - -# Need these to keep track of whether the hdlc module should -# really go in the kernel or a module. -CONFIG_HDLCDRV_BUILTIN := -CONFIG_HDLCDRV_MODULE := - -ifeq ($(CONFIG_DMASCC),y) -O_OBJS += dmascc.o -else - ifeq ($(CONFIG_DMASCC),m) - M_OBJS += dmascc.o - endif -endif - -ifeq ($(CONFIG_SCC),y) -O_OBJS += scc.o -else - ifeq ($(CONFIG_SCC),m) - M_OBJS += scc.o - endif -endif - -ifeq ($(CONFIG_MKISS),y) -O_OBJS += mkiss.o -else - ifeq ($(CONFIG_MKISS),m) - M_OBJS += mkiss.o - endif -endif - -ifeq ($(CONFIG_6PACK),y) -O_OBJS += 6pack.o -else - ifeq ($(CONFIG_6PACK),m) - M_OBJS += 6pack.o - endif -endif - -ifeq ($(CONFIG_YAM),y) -O_OBJS += yam.o -else - ifeq ($(CONFIG_YAM),m) - M_OBJS += yam.o - endif -endif - -ifeq ($(CONFIG_PI),y) -O_OBJS += pi2.o -else - ifeq ($(CONFIG_PI),m) - M_OBJS += pi2.o - endif -endif -ifeq ($(CONFIG_PT),y) -O_OBJS += pt.o -else - ifeq ($(CONFIG_PT),m) - M_OBJS += pt.o - endif -endif - -ifeq ($(CONFIG_BPQETHER),y) -O_OBJS += bpqether.o -else - ifeq ($(CONFIG_BPQETHER),m) - M_OBJS += bpqether.o - endif -endif +export-objs = hdlcdrv.o -ifeq ($(CONFIG_BAYCOM_SER_FDX),y) -O_OBJS += baycom_ser_fdx.o -CONFIG_HDLCDRV_BUILTIN = y -else - ifeq ($(CONFIG_BAYCOM_SER_FDX),m) - CONFIG_HDLCDRV_MODULE = y - M_OBJS += baycom_ser_fdx.o - endif -endif -ifeq ($(CONFIG_BAYCOM_SER_HDX),y) -O_OBJS += baycom_ser_hdx.o -CONFIG_HDLCDRV_BUILTIN = y -else - ifeq ($(CONFIG_BAYCOM_SER_HDX),m) - CONFIG_HDLCDRV_MODULE = y - M_OBJS += baycom_ser_hdx.o - endif -endif - -ifeq ($(CONFIG_BAYCOM_PAR),y) -O_OBJS += baycom_par.o -CONFIG_HDLCDRV_BUILTIN = y -else - ifeq ($(CONFIG_BAYCOM_PAR),m) - CONFIG_HDLCDRV_MODULE = y - M_OBJS += baycom_par.o - endif -endif - -ifeq ($(CONFIG_BAYCOM_EPP),y) -O_OBJS += baycom_epp.o -CONFIG_HDLCDRV_BUILTIN = y -else - ifeq ($(CONFIG_BAYCOM_EPP),m) - CONFIG_HDLCDRV_MODULE = y - M_OBJS += baycom_epp.o - endif -endif +obj-$(CONFIG_DMASCC) += dmascc.o +obj-$(CONFIG_SCC) += scc.o +obj-$(CONFIG_MKISS) += mkiss.o +obj-$(CONFIG_6PACK) += 6pack.o +obj-$(CONFIG_YAM) += yam.o +obj-$(CONFIG_PI) += pi2.o +obj-$(CONFIG_PT) += pt.o +obj-$(CONFIG_BPQETHER) += bpqether.o +obj-$(CONFIG_BAYCOM_SER_FDX) += baycom_ser_fdx.o hdlcdrv.o +obj-$(CONFIG_BAYCOM_SER_HDX) += baycom_ser_hdx.o hdlcdrv.o +obj-$(CONFIG_BAYCOM_PAR) += baycom_par.o hdlcdrv.o +obj-$(CONFIG_BAYCOM_EPP) += baycom_epp.o hdlcdrv.o +obj-$(CONFIG_SOUNDMODEM) += hdlcdrv.o ifeq ($(CONFIG_SOUNDMODEM),y) -ALL_SUB_DIRS += soundmodem SUB_DIRS += soundmodem O_OBJS += soundmodem/soundmodem.o -CONFIG_HDLCDRV_BUILTIN = y else ifeq ($(CONFIG_SOUNDMODEM),m) - CONFIG_HDLCDRV_MODULE = y - ALL_SUB_DIRS += soundmodem MOD_SUB_DIRS += soundmodem endif endif -# If anything built-in uses the hdlcdrv, then build it into the kernel also. -# If not, but a module uses it, build as a module. -ifdef CONFIG_HDLCDRV_BUILTIN -OX_OBJS += hdlcdrv.o -else - ifdef CONFIG_HDLCDRV_MODULE - MX_OBJS += hdlcdrv.o - endif -endif +# Files that are both resident and modular: remove from modular. +obj-m := $(filter-out $(obj-y), $(obj-m)) -include $(TOPDIR)/Rules.make +# Translate to Rules.make lists. +O_OBJS := $(filter-out $(export-objs), $(obj-y)) +OX_OBJS := $(filter $(export-objs), $(obj-y)) +M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) +MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) -clean: - rm -f core *.o *.a *.s +include $(TOPDIR)/Rules.make diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c index cc60b41a3..99d8c65aa 100644 --- a/drivers/net/hamradio/scc.c +++ b/drivers/net/hamradio/scc.c @@ -120,8 +120,8 @@ please (!) contact me first. New versions of the driver will be announced on the linux-hams - mailing list on vger.rutgers.edu. To subscribe send an e-mail - to majordomo@vger.rutgers.edu with the following line in + mailing list on vger.kernel.org. To subscribe send an e-mail + to majordomo@vger.kernel.org with the following line in the body of the mail: subscribe linux-hams diff --git a/drivers/net/irda/Makefile b/drivers/net/irda/Makefile index 53ee8867c..f923bf012 100644 --- a/drivers/net/irda/Makefile +++ b/drivers/net/irda/Makefile @@ -1,121 +1,40 @@ -# File: drivers/irda/Makefile # # Makefile for the Linux IrDA infrared port device drivers. # +# 9 Aug 2000, Christoph Hellwig <hch@caldera.de> +# Rewritten to use lists instead of if-statements. +# SUB_DIRS := MOD_SUB_DIRS := $(SUB_DIRS) ALL_SUB_DIRS := $(SUB_DIRS) -L_TARGET := irda_drivers.a -L_OBJS := -M_OBJS := - -ifeq ($(CONFIG_IRTTY_SIR),y) -L_OBJS += irtty.o -else - ifeq ($(CONFIG_IRTTY_SIR),m) - M_OBJS += irtty.o - endif -endif - -ifeq ($(CONFIG_IRPORT_SIR),y) -LX_OBJS += irport.o -else - ifeq ($(CONFIG_IRPORT_SIR),m) - MX_OBJS += irport.o - endif -endif - -ifeq ($(CONFIG_NSC_FIR),y) -L_OBJS += nsc-ircc.o -else - ifeq ($(CONFIG_NSC_FIR),m) - M_OBJS += nsc-ircc.o - endif -endif - -ifeq ($(CONFIG_WINBOND_FIR),y) -L_OBJS += w83977af_ir.o -else - ifeq ($(CONFIG_WINBOND_FIR),m) - M_OBJS += w83977af_ir.o - endif -endif - -ifeq ($(CONFIG_TOSHIBA_FIR),y) -L_OBJS += toshoboe.o -else - ifeq ($(CONFIG_TOSHIBA_FIR),m) - M_OBJS += toshoboe.o - endif -endif - -ifeq ($(CONFIG_SMC_IRCC_FIR),y) -L_OBJS += smc-ircc.o -LX_OBJS += irport.o -else - ifeq ($(CONFIG_SMC_IRCC_FIR),m) - M_OBJS += smc-ircc.o - MX_OBJS += irport.o - endif -endif +O_TARGET := irda.o -ifeq ($(CONFIG_ESI_DONGLE),y) -L_OBJS += esi.o -else - ifeq ($(CONFIG_ESI_DONGLE),m) - M_OBJS += esi.o - endif -endif +export-objs = irport.o -ifeq ($(CONFIG_TEKRAM_DONGLE),y) -L_OBJS += tekram.o -else - ifeq ($(CONFIG_TEKRAM_DONGLE),m) - M_OBJS += tekram.o - endif -endif -ifeq ($(CONFIG_ACTISYS_DONGLE),y) -L_OBJS += actisys.o -else - ifeq ($(CONFIG_ACTISYS_DONGLE),m) - M_OBJS += actisys.o - endif -endif +obj-$(CONFIG_IRTTY_SIR) += irtty.o +obj-$(CONFIG_IRPORT_SIR) += irport.o +obj-$(CONFIG_NSC_FIR) += nsc-ircc.o +obj-$(CONFIG_WINBOND_FIR) += w83977af_ir.o +obj-$(CONFIG_TOSHIBA_FIR) += toshoboe.o +obj-$(CONFIG_SMC_IRCC_FIR) += smc-ircc.o irport.o +obj-$(CONFIG_ESI_DONGLE) += esi.o +obj-$(CONFIG_TEKRAM_DONGLE) += tekram.o +obj-$(CONFIG_ACTISYS_DONGLE) += actisys.o +obj-$(CONFIG_GIRBIL_DONGLE) += girbil.o +obj-$(CONFIG_LITELINK_DONGLE) += litelink.o +obj-$(CONFIG_OLD_BELKIN_DONGLE) += old_belkin.o -ifeq ($(CONFIG_GIRBIL_DONGLE),y) -L_OBJS += girbil.o -else - ifeq ($(CONFIG_GIRBIL_DONGLE),m) - M_OBJS += girbil.o - endif -endif -ifeq ($(CONFIG_LITELINK_DONGLE),y) -L_OBJS += litelink.o -else - ifeq ($(CONFIG_LITELINK_DONGLE),m) - M_OBJS += litelink.o - endif -endif +# Files that are both resident and modular: remove from modular. +obj-m := $(filter-out $(obj-y), $(obj-m)) -ifeq ($(CONFIG_OLD_BELKIN_DONGLE),y) -L_OBJS += old_belkin.o -else - ifeq ($(CONFIG_OLD_BELKIN_DONGLE),m) - M_OBJS += old_belkin.o - endif -endif +# Translate to Rules.make lists. +O_OBJS := $(filter-out $(export-objs), $(obj-y)) +OX_OBJS := $(filter $(export-objs), $(obj-y)) +M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) +MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) include $(TOPDIR)/Rules.make - -clean: - rm -f core *.o *.a *.s - - - - - - diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c new file mode 100644 index 000000000..565ddc52b --- /dev/null +++ b/drivers/net/natsemi.c @@ -0,0 +1,1186 @@ +/* natsemi.c: A Linux PCI Ethernet driver for the NatSemi DP83810 series. */ +/* + Written/copyright 1999-2000 by Donald Becker. + + This software may be used and distributed according to the terms of + the GNU General Public License (GPL), incorporated herein by reference. + Drivers based on or derived from this code fall under the GPL and must + retain the authorship, copyright and license notice. This file is not + a complete program and may only be used when the entire operating + system is licensed under the GPL. License for under other terms may be + available. Contact the original author for details. + + The original author may be reached as becker@scyld.com, or at + Scyld Computing Corporation + 410 Severn Ave., Suite 210 + Annapolis MD 21403 + + Support information and updates available at + http://www.scyld.com/network/netsemi.html +*/ + +/* These identify the driver base version and may not be removed. */ +static const char version1[] = +"natsemi.c:v1.05 8/7/2000 Written by Donald Becker <becker@scyld.com>\n"; +static const char version2[] = +" http://www.scyld.com/network/natsemi.html\n"; +static const char version3[] = +" (unofficial 2.4.x kernel port, version 1.0.0, August 10, 2000)\n"; +/* Updated to recommendations in pci-skeleton v2.03. */ + +/* Automatically extracted configuration info: +probe-func: natsemi_probe +config-in: tristate 'National Semiconductor DP83810 series PCI Ethernet support' CONFIG_NATSEMI + +c-help-name: National Semiconductor DP83810 series PCI Ethernet support +c-help-symbol: CONFIG_NATSEMI +c-help: This driver is for the National Semiconductor DP83810 series, +c-help: including the 83815 chip. +c-help: More specific information and updates are available from +c-help: http://www.scyld.com/network/natsemi.html +*/ + +/* The user-configurable values. + 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 = 20; +static int mtu = 0; +/* Maximum number of multicast addresses to filter (vs. rx-all-multicast). + This chip uses a 512 element hash table based on the Ethernet CRC. */ +static int multicast_filter_limit = 100; + +/* Set the copy breakpoint for the copy-only-tiny-frames scheme. + Setting to > 1518 effectively disables this feature. */ +static int rx_copybreak = 0; + +/* Used to pass the media type, etc. + Both 'options[]' and 'full_duplex[]' should exist for driver + interoperability. + The media type is usually passed in 'options[]'. +*/ +#define MAX_UNITS 8 /* More are supported, limit only on options */ +static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; +static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; + +/* Operational parameters that are set at compile time. */ + +/* Keep the ring sizes a power of two for compile efficiency. + The compiler will convert <unsigned>'%'<2^N> into a bit mask. + 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 + +/* Operational parameters that usually are not changed. */ +/* Time in jiffies before concluding the transmitter is hung. */ +#define TX_TIMEOUT (2*HZ) + +#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ + +#if !defined(__OPTIMIZE__) +#warning You must compile this file with the correct options! +#warning See the last lines of the source file. +#error You must compile this driver with "-O". +#endif + +/* Include files, designed to support most kernel versions 2.0.0 and later. */ +#include <linux/version.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/timer.h> +#include <linux/errno.h> +#include <linux/ioport.h> +#include <linux/malloc.h> +#include <linux/interrupt.h> +#include <linux/pci.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/init.h> +#include <linux/spinlock.h> +#include <asm/processor.h> /* Processor type for cache alignment. */ +#include <asm/bitops.h> +#include <asm/io.h> + +/* Condensed operations for readability. */ +#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr)) +#define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr)) + +MODULE_AUTHOR("Donald Becker <becker@scyld.com>"); +MODULE_DESCRIPTION("National Semiconductor DP83810 series PCI Ethernet driver"); +MODULE_PARM(max_interrupt_work, "i"); +MODULE_PARM(mtu, "i"); +MODULE_PARM(debug, "i"); +MODULE_PARM(rx_copybreak, "i"); +MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); + +/* + Theory of Operation + +I. Board Compatibility + +This driver is designed for National Semiconductor DP83815 PCI Ethernet NIC. +It also works with other chips in in the DP83810 series. + +II. Board-specific settings + +This driver requires the PCI interrupt line to be valid. +It honors the EEPROM-set values. + +III. Driver operation + +IIIa. Ring buffers + +This driver uses two statically allocated fixed-size descriptor lists +formed into rings by a branch from the final descriptor to the beginning of +the list. The ring sizes are set at compile time by RX/TX_RING_SIZE. +The NatSemi design uses a 'next descriptor' pointer that the driver forms +into a list. + +IIIb/c. Transmit/Receive Structure + +This driver uses a zero-copy receive and transmit scheme. +The driver allocates full frame size skbuffs for the Rx ring buffers at +open() time and passes the skb->data field to the chip as receive data +buffers. When an incoming frame is less than RX_COPYBREAK bytes long, +a fresh skbuff is allocated and the frame is copied to the new skbuff. +When the incoming frame is larger, the skbuff is passed directly up the +protocol stack. Buffers consumed this way are replaced by newly allocated +skbuffs in a later phase of receives. + +The RX_COPYBREAK value is chosen to trade-off the memory wasted by +using a full-sized skbuff for small frames vs. the copying costs of larger +frames. New boards are typically used in generously configured machines +and the underfilled buffers have negligible impact compared to the benefit of +a single allocation size, so the default value of zero results in never +copying packets. When copying is done, the cost is usually mitigated by using +a combined copy/checksum routine. Copying also preloads the cache, which is +most useful with small frames. + +A subtle aspect of the operation is that unaligned buffers are not permitted +by the hardware. Thus the IP header at offset 14 in an ethernet frame isn't +longword aligned for further processing. On copies frames are put into the +skbuff at an offset of "+2", 16-byte aligning the IP header. + +IIId. Synchronization + +The driver runs as two independent, single-threaded flows of control. One +is the send-packet routine, which enforces single-threaded use by the +dev->tbusy flag. The other thread is the interrupt handler, which is single +threaded by the hardware and interrupt handling software. + +The send packet thread has partial control over the Tx ring and 'dev->tbusy' +flag. It sets the tbusy flag whenever it's queuing a Tx packet. If the next +queue slot is empty, it clears the tbusy flag when finished otherwise it sets +the 'lp->tx_full' flag. + +The interrupt handler has exclusive control over the Rx ring and records stats +from the Tx ring. After reaping the stats, it marks the Tx queue entry as +empty by incrementing the dirty_tx mark. Iff the 'lp->tx_full' flag is set, it +clears both the tx_full and tbusy flags. + +IV. Notes + +NatSemi PCI network controllers are very uncommon. + +IVb. References + +http://www.scyld.com/expert/100mbps.html +http://www.scyld.com/expert/NWay.html +No NatSemi datasheet was publically available at the initial release date. + +IVc. Errata + +None characterised. +*/ + + + +enum pcistuff { + PCI_USES_IO = 0x01, + PCI_USES_MEM = 0x02, + PCI_USES_MASTER = 0x04, + PCI_ADDR0 = 0x08, + PCI_ADDR1 = 0x10, +}; + +/* MMIO operations required */ +#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR1) + + +/* array of board data directly indexed by pci_tbl[x].driver_data */ +static struct { + const char *name; + unsigned long flags; +} natsemi_pci_info[] __devinitdata = { + { "NatSemi DP83815", PCI_IOTYPE }, +}; + +static struct pci_device_id natsemi_pci_tbl[] __devinitdata = { + { 0x100B, 0x0020, PCI_ANY_ID, PCI_ANY_ID, }, + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, natsemi_pci_tbl); + +/* Offsets to the device registers. + Unlike software-only systems, device drivers interact with complex hardware. + It's not useful to define symbolic names for every register bit in the + device. +*/ +enum register_offsets { + ChipCmd=0x00, ChipConfig=0x04, EECtrl=0x08, PCIBusCfg=0x0C, + IntrStatus=0x10, IntrMask=0x14, IntrEnable=0x18, + TxRingPtr=0x20, TxConfig=0x24, + RxRingPtr=0x30, RxConfig=0x34, + WOLCmd=0x40, PauseCmd=0x44, RxFilterAddr=0x48, RxFilterData=0x4C, + BootRomAddr=0x50, BootRomData=0x54, StatsCtrl=0x5C, StatsData=0x60, + RxPktErrs=0x60, RxMissed=0x68, RxCRCErrs=0x64, +}; + +/* Bit in ChipCmd. */ +enum ChipCmdBits { + ChipReset=0x100, RxReset=0x20, TxReset=0x10, RxOff=0x08, RxOn=0x04, + TxOff=0x02, TxOn=0x01, +}; + +/* Bits in the interrupt status/mask registers. */ +enum intr_status_bits { + IntrRxDone=0x0001, IntrRxIntr=0x0002, IntrRxErr=0x0004, IntrRxEarly=0x0008, + IntrRxIdle=0x0010, IntrRxOverrun=0x0020, + IntrTxDone=0x0040, IntrTxIntr=0x0080, IntrTxErr=0x0100, + IntrTxIdle=0x0200, IntrTxOverrun=0x0400, + StatsMax=0x0800, LinkChange=0x4000, + WOLPkt=0x2000, + RxResetDone=0x1000000, TxResetDone=0x2000000, + IntrPCIErr=0x00f00000, + IntrNormalSummary=0x0251, IntrAbnormalSummary=0xCD20, +}; + +/* Bits in the RxMode register. */ +enum rx_mode_bits { + AcceptErr=0x20, AcceptRunt=0x10, + AcceptBroadcast=0xC0000000, + AcceptMulticast=0x00200000, AcceptAllMulticast=0x20000000, + AcceptAllPhys=0x10000000, AcceptMyPhys=0x08000000, +}; + +/* The Rx and Tx buffer descriptors. */ +/* Note that using only 32 bit fields simplifies conversion to big-endian + architectures. */ +struct netdev_desc { + u32 next_desc; + s32 cmd_status; + u32 addr; + u32 software_use; +}; + +/* Bits in network_desc.status */ +enum desc_status_bits { + DescOwn=0x80000000, DescMore=0x40000000, DescIntr=0x20000000, + DescNoCRC=0x10000000, + DescPktOK=0x08000000, RxTooLong=0x00400000, +}; + +#define PRIV_ALIGN 15 /* Required alignment mask */ +struct netdev_private { + /* Descriptor rings first for alignment. */ + struct netdev_desc rx_ring[RX_RING_SIZE]; + struct netdev_desc tx_ring[TX_RING_SIZE]; + /* The addresses of receive-in-place skbuffs. */ + struct sk_buff* rx_skbuff[RX_RING_SIZE]; + /* The saved address of a sent-in-place packet/buffer, for later free(). */ + struct sk_buff* tx_skbuff[TX_RING_SIZE]; + struct net_device_stats stats; + struct timer_list timer; /* Media monitoring timer. */ + /* Frequently used values: keep some adjacent for cache effect. */ + struct pci_dev *pci_dev; + struct netdev_desc *rx_head_desc; + unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ + unsigned int cur_tx, dirty_tx; + unsigned int rx_buf_sz; /* Based on MTU+slack. */ + unsigned int tx_full:1; /* The Tx queue is full. */ + /* These values are keep track of the transceiver/media in use. */ + unsigned int full_duplex:1; /* Full-duplex operation requested. */ + unsigned int duplex_lock:1; + unsigned int medialock:1; /* Do not sense media. */ + unsigned int default_port:4; /* Last dev->if_port value. */ + /* Rx filter. */ + u32 cur_rx_mode; + u32 rx_filter[16]; + /* FIFO and PCI burst thresholds. */ + int tx_config, rx_config; + /* MII transceiver section. */ + u16 advertising; /* NWay media advertisement */ + + unsigned int iosize; + spinlock_t lock; +}; + +static int eeprom_read(long ioaddr, int location); +static int mdio_read(struct net_device *dev, int phy_id, int location); +static void mdio_write(struct net_device *dev, int phy_id, int location, int value); +static int netdev_open(struct net_device *dev); +static void check_duplex(struct net_device *dev); +static void netdev_timer(unsigned long data); +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 void intr_handler(int irq, void *dev_instance, struct pt_regs *regs); +static void netdev_error(struct net_device *dev, int intr_status); +static int netdev_rx(struct net_device *dev); +static void netdev_error(struct net_device *dev, int intr_status); +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 int netdev_close(struct net_device *dev); + + +static int __devinit natsemi_probe1 (struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct net_device *dev; + struct netdev_private *np; + int i, option, irq = pdev->irq, chip_idx = ent->driver_data; + static int find_cnt = -1; + static int printed_version; + unsigned long ioaddr; + const int pcibar = 1; /* PCI base address register */ + + if ((debug <= 1) && !printed_version++) + printk(KERN_INFO "%s" KERN_INFO "%s" KERN_INFO "%s", + version1, version2, version3); + + find_cnt++; + option = find_cnt < MAX_UNITS ? options[find_cnt] : 0; + ioaddr = pci_resource_start(pdev, pcibar); + + if (pci_enable_device(pdev)) + return -EIO; + if (natsemi_pci_info[chip_idx].flags & PCI_USES_MASTER) + pci_set_master(pdev); + + dev = init_etherdev(NULL, sizeof (struct netdev_private)); + if (!dev) + return -ENOMEM; + + { + void *mmio; + if (request_mem_region(ioaddr, pci_resource_len (pdev, pcibar), + dev->name) == NULL) { + unregister_netdev(dev); + kfree(dev); + return -EBUSY; + } + mmio = ioremap (ioaddr, pci_resource_len (pdev, pcibar)); + if (!mmio) { + release_mem_region(ioaddr, pci_resource_len (pdev, pcibar)); + unregister_netdev(dev); + kfree(dev); + return -ENOMEM; + } + ioaddr = (unsigned long) mmio; + } + + printk(KERN_INFO "%s: %s at 0x%lx, ", + dev->name, natsemi_pci_info[chip_idx].name, ioaddr); + + for (i = 0; i < 3; i++) + ((u16 *)dev->dev_addr)[i] = be16_to_cpu(eeprom_read(ioaddr, i + 7)); + for (i = 0; i < 5; i++) + printk("%2.2x:", dev->dev_addr[i]); + printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); + +#if ! defined(final_version) /* Dump the EEPROM contents during development. */ + if (debug > 4) + for (i = 0; i < 64; i++) + printk("%4.4x%s", + eeprom_read(ioaddr, i), i % 16 != 15 ? " " : "\n"); +#endif + + /* Reset the chip to erase previous misconfiguration. */ + writel(ChipReset, ioaddr + ChipCmd); + + dev->base_addr = ioaddr; + dev->irq = irq; + + np = dev->priv; + + np->pci_dev = pdev; + pdev->driver_data = dev; + np->iosize = pci_resource_len(pdev, pcibar); + + if (dev->mem_start) + option = dev->mem_start; + + /* The lower four bits are the media type. */ + if (option > 0) { + if (option & 0x200) + np->full_duplex = 1; + np->default_port = option & 15; + if (np->default_port) + np->medialock = 1; + } + if (find_cnt < MAX_UNITS && full_duplex[find_cnt] > 0) + np->full_duplex = 1; + + if (np->full_duplex) + np->duplex_lock = 1; + + /* The chip-specific entries in the device structure. */ + dev->open = &netdev_open; + dev->hard_start_xmit = &start_tx; + dev->stop = &netdev_close; + dev->get_stats = &get_stats; + dev->set_multicast_list = &set_rx_mode; + dev->do_ioctl = &mii_ioctl; + dev->tx_timeout = &tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + + if (mtu) + dev->mtu = mtu; + + np->advertising = readl(ioaddr + 0x90); + printk(KERN_INFO "%s: Transceiver status 0x%4.4x advertising %4.4x.\n", + dev->name, (int)readl(ioaddr + 0x84), np->advertising); + + return 0; +} + + +/* Read the EEPROM and MII Management Data I/O (MDIO) interfaces. + The EEPROM code is for the common 93c06/46 EEPROMs with 6 bit addresses. */ + +/* Delay between EEPROM clock transitions. + No extra delay is needed with 33Mhz PCI, but future 66Mhz access may need + a delay. Note that pre-2.0.34 kernels had a cache-alignment bug that + made udelay() unreliable. + The old method of using an ISA access as a delay, __SLOW_DOWN_IO__, is + depricated. +*/ +#define eeprom_delay(ee_addr) readl(ee_addr) + +enum EEPROM_Ctrl_Bits { + EE_ShiftClk=0x04, EE_DataIn=0x01, EE_ChipSelect=0x08, EE_DataOut=0x02, +}; +#define EE_Write0 (EE_ChipSelect) +#define EE_Write1 (EE_ChipSelect | EE_DataIn) + +/* The EEPROM commands include the alway-set leading bit. */ +enum EEPROM_Cmds { + EE_WriteCmd=(5 << 6), EE_ReadCmd=(6 << 6), EE_EraseCmd=(7 << 6), +}; + +static int eeprom_read(long addr, int location) +{ + int i; + int retval = 0; + int ee_addr = addr + EECtrl; + int read_cmd = location | EE_ReadCmd; + writel(EE_Write0, ee_addr); + + /* Shift the read command bits out. */ + for (i = 10; i >= 0; i--) { + short dataval = (read_cmd & (1 << i)) ? EE_Write1 : EE_Write0; + writel(dataval, ee_addr); + eeprom_delay(ee_addr); + writel(dataval | EE_ShiftClk, ee_addr); + eeprom_delay(ee_addr); + } + writel(EE_ChipSelect, ee_addr); + + for (i = 16; i > 0; i--) { + writel(EE_ChipSelect | EE_ShiftClk, ee_addr); + eeprom_delay(ee_addr); + retval = (retval << 1) | ((readl(ee_addr) & EE_DataOut) ? 1 : 0); + writel(EE_ChipSelect, ee_addr); + eeprom_delay(ee_addr); + } + + /* Terminate the EEPROM access. */ + writel(EE_Write0, ee_addr); + writel(0, ee_addr); + return retval; +} + +/* MII transceiver control section. + The 83815 series has an internal transceiver, and we present the + management registers as if they were MII connected. */ + +static int mdio_read(struct net_device *dev, int phy_id, int location) +{ + if (phy_id == 1 && location < 32) + return readl(dev->base_addr + 0x80 + (location<<2)) & 0xffff; + else + return 0xffff; +} + +static void mdio_write(struct net_device *dev, int phy_id, int location, int value) +{ + if (phy_id == 1 && location < 32) + writew(value, dev->base_addr + 0x80 + (location<<2)); +} + + +static int netdev_open(struct net_device *dev) +{ + struct netdev_private *np = (struct netdev_private *)dev->priv; + long ioaddr = dev->base_addr; + int i; + + /* Do we need to reset the chip??? */ + + MOD_INC_USE_COUNT; + + if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev)) { + MOD_DEC_USE_COUNT; + return -EAGAIN; + } + + if (debug > 1) + printk(KERN_DEBUG "%s: netdev_open() irq %d.\n", + dev->name, dev->irq); + + init_ring(dev); + + writel(virt_to_bus(np->rx_ring), ioaddr + RxRingPtr); + writel(virt_to_bus(np->tx_ring), ioaddr + TxRingPtr); + + for (i = 0; i < 6; i += 2) { + writel(i, ioaddr + RxFilterAddr); + writew(dev->dev_addr[i] + (dev->dev_addr[i+1] << 8), + ioaddr + RxFilterData); + } + + /* Initialize other registers. */ + /* Configure the PCI bus bursts and FIFO thresholds. */ + /* Configure for standard, in-spec Ethernet. */ + np->tx_config = 0x10800802; + writel(np->tx_config, ioaddr + TxConfig); + np->rx_config = 0x0020; + writel(np->rx_config, ioaddr + RxConfig); + + if (dev->if_port == 0) + dev->if_port = np->default_port; + + netif_start_queue(dev); + + check_duplex(dev); + set_rx_mode(dev); + + /* Enable interrupts by setting the interrupt mask. */ + writel(IntrNormalSummary | IntrAbnormalSummary | 0x1f, ioaddr + IntrMask); + writel(1, ioaddr + IntrEnable); + + writel(RxOn | TxOn, ioaddr + ChipCmd); + writel(4, ioaddr + StatsCtrl); /* Clear Stats */ + + if (debug > 2) + printk(KERN_DEBUG "%s: Done netdev_open(), status: %x.\n", + dev->name, (int)readl(ioaddr + ChipCmd)); + + /* Set the timer to check for link beat. */ + init_timer(&np->timer); + np->timer.expires = jiffies + 3*HZ; + np->timer.data = (unsigned long)dev; + np->timer.function = &netdev_timer; /* timer handler */ + add_timer(&np->timer); + + return 0; +} + +static void check_duplex(struct net_device *dev) +{ + struct netdev_private *np = (struct netdev_private *)dev->priv; + long ioaddr = dev->base_addr; + int duplex; + + if (np->duplex_lock) + return; + duplex = readl(ioaddr + ChipConfig) & 0x20000000 ? 1 : 0; + if (np->full_duplex != duplex) { + np->full_duplex = duplex; + if (debug) + printk(KERN_INFO "%s: Setting %s-duplex based on negotiated link" + " capability.\n", dev->name, + duplex ? "full" : "half"); + if (duplex) { + np->rx_config |= 0x10000000; + np->tx_config |= 0xC0000000; + } else { + np->rx_config &= ~0x10000000; + np->tx_config &= ~0xC0000000; + } + writew(np->tx_config, ioaddr + TxConfig); + writew(np->rx_config, ioaddr + RxConfig); + } +} + +static void netdev_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct netdev_private *np = (struct netdev_private *)dev->priv; + long ioaddr = dev->base_addr; + int next_tick = 60*HZ; + + if (debug > 3) + printk(KERN_DEBUG "%s: Media selection timer tick, status %8.8x.\n", + dev->name, (int)readl(ioaddr + IntrStatus)); + check_duplex(dev); + np->timer.expires = jiffies + next_tick; + add_timer(&np->timer); +} + +static void tx_timeout(struct net_device *dev) +{ + struct netdev_private *np = (struct netdev_private *)dev->priv; + long ioaddr = dev->base_addr; + + printk(KERN_WARNING "%s: Transmit timed out, status %8.8x," + " resetting...\n", dev->name, (int)readl(ioaddr + TxRingPtr)); + +#ifndef __alpha__ + { + int i; + printk(KERN_DEBUG " Rx ring %8.8x: ", (int)np->rx_ring); + for (i = 0; i < RX_RING_SIZE; i++) + printk(" %8.8x", (unsigned int)np->rx_ring[i].cmd_status); + printk("\n"KERN_DEBUG" Tx ring %8.8x: ", (int)np->tx_ring); + for (i = 0; i < TX_RING_SIZE; i++) + printk(" %4.4x", np->tx_ring[i].cmd_status); + printk("\n"); + } +#endif + + /* Perhaps we should reinitialize the hardware here. */ + dev->if_port = 0; + /* Stop and restart the chip's Tx processes . */ + + /* Trigger an immediate transmit demand. */ + + dev->trans_start = jiffies; + np->stats.tx_errors++; + return; +} + + +/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ +static void init_ring(struct net_device *dev) +{ + struct netdev_private *np = (struct netdev_private *)dev->priv; + int i; + + np->tx_full = 0; + np->cur_rx = np->cur_tx = 0; + np->dirty_rx = np->dirty_tx = 0; + + np->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); + np->rx_head_desc = &np->rx_ring[0]; + + /* Initialize all Rx descriptors. */ + for (i = 0; i < RX_RING_SIZE; i++) { + np->rx_ring[i].next_desc = virt_to_le32desc(&np->rx_ring[i+1]); + np->rx_ring[i].cmd_status = DescOwn; + np->rx_skbuff[i] = 0; + } + /* Mark the last entry as wrapping the ring. */ + np->rx_ring[i-1].next_desc = virt_to_le32desc(&np->rx_ring[0]); + + /* Fill in the Rx buffers. Handle allocation failure gracefully. */ + for (i = 0; i < RX_RING_SIZE; i++) { + struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz); + np->rx_skbuff[i] = skb; + if (skb == NULL) + break; + skb->dev = dev; /* Mark as being used by this device. */ + np->rx_ring[i].addr = virt_to_le32desc(skb->tail); + np->rx_ring[i].cmd_status = + cpu_to_le32(DescIntr | np->rx_buf_sz); + } + np->dirty_rx = (unsigned int)(i - RX_RING_SIZE); + + for (i = 0; i < TX_RING_SIZE; i++) { + np->tx_skbuff[i] = 0; + np->tx_ring[i].next_desc = virt_to_le32desc(&np->tx_ring[i+1]); + np->tx_ring[i].cmd_status = 0; + } + np->tx_ring[i-1].next_desc = virt_to_le32desc(&np->tx_ring[0]); + return; +} + +static int start_tx(struct sk_buff *skb, struct net_device *dev) +{ + struct netdev_private *np = (struct netdev_private *)dev->priv; + unsigned entry; + + /* Note: Ordering is important here, set the field with the + "ownership" bit last, and only then increment cur_tx. */ + + /* Calculate the next Tx descriptor entry. */ + entry = np->cur_tx % TX_RING_SIZE; + + np->tx_skbuff[entry] = skb; + + np->tx_ring[entry].addr = virt_to_le32desc(skb->data); + np->tx_ring[entry].cmd_status = cpu_to_le32(DescOwn|DescIntr | skb->len); + np->cur_tx++; + + /* StrongARM: Explicitly cache flush np->tx_ring and skb->data,skb->len. */ + + if (np->cur_tx - np->dirty_tx >= TX_QUEUE_LEN - 1) { + np->tx_full = 1; + netif_stop_queue(dev); + } + /* Wake the potentially-idle transmit channel. */ + writel(TxOn, dev->base_addr + ChipCmd); + + dev->trans_start = jiffies; + + if (debug > 4) { + printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n", + dev->name, np->cur_tx, entry); + } + return 0; +} + +/* The interrupt handler does all of the Rx thread work and cleans up + after the Tx thread. */ +static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) +{ + struct net_device *dev = (struct net_device *)dev_instance; + struct netdev_private *np; + long ioaddr; + int boguscnt = max_interrupt_work; + +#ifndef final_version /* Can never occur. */ + if (dev == NULL) { + printk (KERN_ERR "Netdev interrupt handler(): IRQ %d for unknown " + "device.\n", irq); + return; + } +#endif + + ioaddr = dev->base_addr; + np = (struct netdev_private *)dev->priv; + + if (!spin_trylock(&np->lock)) + return; + + do { + u32 intr_status = readl(ioaddr + IntrStatus); + + /* Acknowledge all of the current interrupt sources ASAP. */ + writel(intr_status & 0x000ffff, ioaddr + IntrStatus); + + if (debug > 4) + printk(KERN_DEBUG "%s: Interrupt, status %4.4x.\n", + dev->name, intr_status); + + if (intr_status == 0) + break; + + if (intr_status & (IntrRxDone | IntrRxIntr)) + netdev_rx(dev); + + for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) { + int entry = np->dirty_tx % TX_RING_SIZE; + if (np->tx_ring[entry].cmd_status & cpu_to_le32(DescOwn)) + break; + if (np->tx_ring[entry].cmd_status & cpu_to_le32(0x08000000)) { + np->stats.tx_packets++; +#if LINUX_VERSION_CODE > 0x20127 + np->stats.tx_bytes += np->tx_skbuff[entry]->len; +#endif + } else { /* Various Tx errors */ + int tx_status = le32_to_cpu(np->tx_ring[entry].cmd_status); + if (tx_status & 0x04010000) np->stats.tx_aborted_errors++; + if (tx_status & 0x02000000) np->stats.tx_fifo_errors++; + if (tx_status & 0x01000000) np->stats.tx_carrier_errors++; + if (tx_status & 0x00200000) np->stats.tx_window_errors++; + np->stats.tx_errors++; + } + /* Free the original skb. */ + dev_kfree_skb(np->tx_skbuff[entry]); + np->tx_skbuff[entry] = 0; + } + if (np->tx_full + && np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 4) { + /* The ring is no longer full, wake queue. */ + np->tx_full = 0; + netif_wake_queue(dev); + } + + /* Abnormal error summary/uncommon events handlers. */ + if (intr_status & IntrAbnormalSummary) + netdev_error(dev, intr_status); + + if (--boguscnt < 0) { + printk(KERN_WARNING "%s: Too much work at interrupt, " + "status=0x%4.4x.\n", + dev->name, intr_status); + break; + } + } while (1); + + if (debug > 3) + printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n", + dev->name, (int)readl(ioaddr + IntrStatus)); + +#ifndef final_version + /* Code that should never be run! Perhaps remove after testing.. */ + { + static int stopit = 10; + if (!netif_running(dev) && --stopit < 0) { + printk(KERN_ERR "%s: Emergency stop, looping startup interrupt.\n", + dev->name); + free_irq(irq, dev); + } + } +#endif + + spin_unlock(&np->lock); +} + +/* This routine is logically part of the interrupt handler, but separated + for clarity and better register allocation. */ +static int netdev_rx(struct net_device *dev) +{ + struct netdev_private *np = (struct netdev_private *)dev->priv; + int entry = np->cur_rx % RX_RING_SIZE; + int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx; + s32 desc_status = le32_to_cpu(np->rx_head_desc->cmd_status); + + /* If the driver owns the next entry it's a new packet. Send it up. */ + while (desc_status < 0) { /* e.g. & DescOwn */ + if (debug > 4) + printk(KERN_DEBUG " In netdev_rx() entry %d status was %8.8x.\n", + entry, desc_status); + if (--boguscnt < 0) + break; + if ((desc_status & (DescMore|DescPktOK|RxTooLong)) != DescPktOK) { + if (desc_status & DescMore) { + printk(KERN_WARNING "%s: Oversized(?) Ethernet frame spanned " + "multiple buffers, entry %#x status %x.\n", + dev->name, np->cur_rx, desc_status); + np->stats.rx_length_errors++; + } else { + /* There was a error. */ + if (debug > 2) + printk(KERN_DEBUG " netdev_rx() Rx error was %8.8x.\n", + desc_status); + np->stats.rx_errors++; + if (desc_status & 0x06000000) np->stats.rx_over_errors++; + if (desc_status & 0x00600000) np->stats.rx_length_errors++; + if (desc_status & 0x00140000) np->stats.rx_frame_errors++; + if (desc_status & 0x00080000) np->stats.rx_crc_errors++; + } + } else { + struct sk_buff *skb; + int pkt_len = (desc_status & 0x0fff) - 4; /* Omit CRC size. */ + /* Check if the packet is long enough to accept without copying + to a minimally-sized skbuff. */ + if (pkt_len < rx_copybreak + && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { + skb->dev = dev; + skb_reserve(skb, 2); /* 16 byte align the IP header */ +#if HAS_IP_COPYSUM + eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0); + skb_put(skb, pkt_len); +#else + memcpy(skb_put(skb, pkt_len), np->rx_skbuff[entry]->tail, + pkt_len); +#endif + } else { + char *temp = skb_put(skb = np->rx_skbuff[entry], pkt_len); + np->rx_skbuff[entry] = NULL; +#ifndef final_version /* Remove after testing. */ + if (le32desc_to_virt(np->rx_ring[entry].addr) != temp) + printk(KERN_ERR "%s: Internal fault: The skbuff addresses " + "do not match in netdev_rx: %p vs. %p / %p.\n", + dev->name, + le32desc_to_virt(np->rx_ring[entry].addr), + skb->head, temp); +#endif + } +#ifndef final_version /* Remove after testing. */ + /* You will want this info for the initial debug. */ + if (debug > 5) + printk(KERN_DEBUG " Rx data %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:" + "%2.2x %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x %2.2x%2.2x " + "%d.%d.%d.%d.\n", + skb->data[0], skb->data[1], skb->data[2], skb->data[3], + skb->data[4], skb->data[5], skb->data[6], skb->data[7], + skb->data[8], skb->data[9], skb->data[10], + skb->data[11], skb->data[12], skb->data[13], + skb->data[14], skb->data[15], skb->data[16], + skb->data[17]); +#endif + skb->protocol = eth_type_trans(skb, dev); + /* W/ hardware checksum: skb->ip_summed = CHECKSUM_UNNECESSARY; */ + netif_rx(skb); + dev->last_rx = jiffies; + np->stats.rx_packets++; +#if LINUX_VERSION_CODE > 0x20127 + np->stats.rx_bytes += pkt_len; +#endif + } + entry = (++np->cur_rx) % RX_RING_SIZE; + np->rx_head_desc = &np->rx_ring[entry]; + desc_status = le32_to_cpu(np->rx_head_desc->cmd_status); + } + + /* Refill the Rx ring buffers. */ + for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) { + struct sk_buff *skb; + entry = np->dirty_rx % RX_RING_SIZE; + if (np->rx_skbuff[entry] == NULL) { + skb = dev_alloc_skb(np->rx_buf_sz); + np->rx_skbuff[entry] = skb; + if (skb == NULL) + break; /* Better luck next round. */ + skb->dev = dev; /* Mark as being used by this device. */ + np->rx_ring[entry].addr = virt_to_le32desc(skb->tail); + } + np->rx_ring[entry].cmd_status = + cpu_to_le32(DescIntr | np->rx_buf_sz); + } + + /* Restart Rx engine if stopped. */ + writel(RxOn, dev->base_addr + ChipCmd); + return 0; +} + +static void netdev_error(struct net_device *dev, int intr_status) +{ + struct netdev_private *np = (struct netdev_private *)dev->priv; + long ioaddr = dev->base_addr; + + if (intr_status & LinkChange) { + printk(KERN_NOTICE "%s: Link changed: Autonegotiation advertising" + " %4.4x partner %4.4x.\n", dev->name, + (int)readl(ioaddr + 0x90), (int)readl(ioaddr + 0x94)); + check_duplex(dev); + } + if (intr_status & StatsMax) { + get_stats(dev); + } + if ((intr_status & ~(LinkChange|StatsMax|RxResetDone|TxResetDone|0x83ff)) + && debug) + printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n", + dev->name, intr_status); + /* Hmmmmm, it's not clear how to recover from PCI faults. */ + if (intr_status & IntrPCIErr) { + np->stats.tx_fifo_errors++; + np->stats.rx_fifo_errors++; + } +} + +static struct net_device_stats *get_stats(struct net_device *dev) +{ + long ioaddr = dev->base_addr; + struct netdev_private *np = (struct netdev_private *)dev->priv; + + /* We should lock this segment of code for SMP eventually, although + the vulnerability window is very small and statistics are + non-critical. */ + /* The chip only need report frame silently dropped. */ + np->stats.rx_crc_errors += readl(ioaddr + RxCRCErrs); + np->stats.rx_missed_errors += readl(ioaddr + RxMissed); + + return &np->stats; +} + +/* The little-endian AUTODIN II ethernet CRC calculations. + A big-endian version is also available. + This is slow but compact code. Do not use this routine for bulk data, + use a table-based routine instead. + This is common code and should be moved to net/core/crc.c. + Chips may use the upper or lower CRC bits, and may reverse and/or invert + them. Select the endian-ness that results in minimal calculations. +*/ +static unsigned const ethernet_polynomial_le = 0xedb88320U; +static inline unsigned ether_crc_le(int length, unsigned char *data) +{ + unsigned int crc = 0xffffffff; /* Initial value. */ + while(--length >= 0) { + unsigned char current_octet = *data++; + int bit; + for (bit = 8; --bit >= 0; current_octet >>= 1) { + if ((crc ^ current_octet) & 1) { + crc >>= 1; + crc ^= ethernet_polynomial_le; + } else + crc >>= 1; + } + } + return crc; +} + +static void set_rx_mode(struct net_device *dev) +{ + long ioaddr = dev->base_addr; + struct netdev_private *np = (struct netdev_private *)dev->priv; + u16 mc_filter[32]; /* Multicast hash filter */ + u32 rx_mode; + + if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ + /* Unconditionally log net taps. */ + printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name); + rx_mode = AcceptBroadcast | AcceptAllMulticast | AcceptAllPhys + | AcceptMyPhys; + } else if ((dev->mc_count > multicast_filter_limit) + || (dev->flags & IFF_ALLMULTI)) { + rx_mode = AcceptBroadcast | AcceptAllMulticast | AcceptMyPhys; + } else { + struct dev_mc_list *mclist; + int i; + memset(mc_filter, 0, sizeof(mc_filter)); + for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + i++, mclist = mclist->next) { + set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x1ff, + mc_filter); + } + rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; + for (i = 0; i < 32; i++) { + writew(0x200 + (i<<1), ioaddr + RxFilterAddr); + writew(cpu_to_be16(mc_filter[i]), ioaddr + RxFilterData); + } + } + writel(rx_mode, ioaddr + RxFilterAddr); + np->cur_rx_mode = rx_mode; +} + +static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + u16 *data = (u16 *)&rq->ifr_data; + + switch(cmd) { + case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ + data[0] = 1; + /* Fall Through */ + case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ + data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f); + return 0; + case SIOCDEVPRIVATE+2: /* Write the specified MII register */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]); + return 0; + default: + return -EOPNOTSUPP; + } +} + +static int netdev_close(struct net_device *dev) +{ + long ioaddr = dev->base_addr; + struct netdev_private *np = (struct netdev_private *)dev->priv; + int i; + + netif_stop_queue(dev); + + if (debug > 1) { + printk(KERN_DEBUG "%s: Shutting down ethercard, status was %4.4x " + "Int %2.2x.\n", + dev->name, (int)readl(ioaddr + ChipCmd), + (int)readl(ioaddr + IntrStatus)); + printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d, Rx %d / %d.\n", + dev->name, np->cur_tx, np->dirty_tx, np->cur_rx, np->dirty_rx); + } + + /* Disable interrupts using the mask. */ + writel(0, ioaddr + IntrMask); + writel(0, ioaddr + IntrEnable); + writel(2, ioaddr + StatsCtrl); /* Freeze Stats */ + + /* Stop the chip's Tx and Rx processes. */ + writel(RxOff | TxOff, ioaddr + ChipCmd); + + del_timer_sync(&np->timer); + +#ifdef __i386__ + if (debug > 2) { + printk("\n"KERN_DEBUG" Tx ring at %8.8x:\n", + (int)virt_to_bus(np->tx_ring)); + for (i = 0; i < TX_RING_SIZE; i++) + printk(" #%d desc. %8.8x %8.8x.\n", + i, np->tx_ring[i].cmd_status, np->tx_ring[i].addr); + printk("\n"KERN_DEBUG " Rx ring %8.8x:\n", + (int)virt_to_bus(np->rx_ring)); + for (i = 0; i < RX_RING_SIZE; i++) { + printk(KERN_DEBUG " #%d desc. %8.8x %8.8x\n", + i, np->rx_ring[i].cmd_status, np->rx_ring[i].addr); + } + } +#endif /* __i386__ debugging only */ + + free_irq(dev->irq, dev); + + /* Free all the skbuffs in the Rx queue. */ + for (i = 0; i < RX_RING_SIZE; i++) { + np->rx_ring[i].cmd_status = 0; + np->rx_ring[i].addr = 0xBADF00D0; /* An invalid address. */ + if (np->rx_skbuff[i]) { +#if LINUX_VERSION_CODE < 0x20100 + np->rx_skbuff[i]->free = 1; +#endif + dev_kfree_skb(np->rx_skbuff[i]); + } + np->rx_skbuff[i] = 0; + } + for (i = 0; i < TX_RING_SIZE; i++) { + if (np->tx_skbuff[i]) + dev_kfree_skb(np->tx_skbuff[i]); + np->tx_skbuff[i] = 0; + } + +#if 0 + writel(0x0200, ioaddr + ChipConfig); /* Power down Xcvr. */ +#endif + + MOD_DEC_USE_COUNT; + + return 0; +} + + +static void __devexit natsemi_remove1 (struct pci_dev *pdev) +{ + struct net_device *dev = pdev->driver_data; + struct netdev_private *np = (struct netdev_private *)dev->priv; + + unregister_netdev (dev); + release_mem_region(dev->base_addr, np->iosize); + iounmap ((char *) dev->base_addr); + kfree (dev); +} + +static struct pci_driver natsemi_driver = { + name: "natsemi", + id_table: natsemi_pci_tbl, + probe: natsemi_probe1, + remove: natsemi_remove1, +}; + +static int __init natsemi_init_mod (void) +{ + if (debug > 1) + printk(KERN_INFO "%s" KERN_INFO "%s" KERN_INFO "%s", + version1, version2, version3); + + return pci_module_init (&natsemi_driver); +} + +static void __exit natsemi_exit_mod (void) +{ + pci_unregister_driver (&natsemi_driver); +} + +module_init(natsemi_init_mod); +module_exit(natsemi_exit_mod); + diff --git a/drivers/net/pcmcia/Config.in b/drivers/net/pcmcia/Config.in index e1070f8f0..4ad968390 100644 --- a/drivers/net/pcmcia/Config.in +++ b/drivers/net/pcmcia/Config.in @@ -15,7 +15,9 @@ if [ "$CONFIG_NET_PCMCIA" = "y" ]; then dep_tristate ' SMC 91Cxx PCMCIA support' CONFIG_PCMCIA_SMC91C92 $CONFIG_PCMCIA dep_tristate ' Xircom 16-bit PCMCIA support' CONFIG_PCMCIA_XIRC2PS $CONFIG_PCMCIA dep_tristate ' COM20020 ARCnet PCMCIA support' CONFIG_ARCNET_COM20020_CS $CONFIG_ARCNET_COM20020 $CONFIG_ARCNET $CONFIG_PCMCIA - dep_tristate ' IBM PCMCIA tokenring adapter support' CONFIG_PCMCIA_IBMTR $CONFIG_TR $CONFIG_PCMCIA + if [ "$CONFIG_IBMTR" != "y" ]; then + dep_tristate ' IBM PCMCIA tokenring adapter support' CONFIG_PCMCIA_IBMTR $CONFIG_TR $CONFIG_PCMCIA + fi if [ "$CONFIG_CARDBUS" = "y" ]; then tristate ' Xircom Tulip-like CardBus support' CONFIG_PCMCIA_XIRTULIP diff --git a/drivers/net/pcmcia/xircom_tulip_cb.c b/drivers/net/pcmcia/xircom_tulip_cb.c index 46f37e946..0355f9e5d 100644 --- a/drivers/net/pcmcia/xircom_tulip_cb.c +++ b/drivers/net/pcmcia/xircom_tulip_cb.c @@ -2714,6 +2714,8 @@ tulip_down(struct net_device *dev) long ioaddr = dev->base_addr; struct tulip_private *tp = (struct tulip_private *)dev->priv; + del_timer_sync(&tp->timer); + /* Disable interrupts by clearing the interrupt mask. */ outl(0x00000000, ioaddr + CSR7); /* Stop the chip's Tx and Rx processes. */ @@ -2739,13 +2741,13 @@ tulip_close(struct net_device *dev) printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n", dev->name, inl(ioaddr + CSR5)); + del_timer_sync(&tp->timer); + netif_stop_queue(dev); if (netif_device_present(dev)) tulip_down(dev); - del_timer(&tp->timer); - free_irq(dev->irq, dev); /* Free all the skbuffs in the Rx queue. */ diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c index 0f624fccd..c71539c9a 100644 --- a/drivers/net/pppoe.c +++ b/drivers/net/pppoe.c @@ -5,19 +5,22 @@ * PPPoE --- PPP over Ethernet (RFC 2516) * * - * Version: 0.6.1 + * Version: 0.6.2 * * 030700 : Fixed connect logic to allow for disconnect. * 270700 : Fixed potential SMP problems; we must protect against * simultaneous invocation of ppp_input * and ppp_unregister_channel. * 040800 : Respect reference count mechanisms on net-devices. + * 200800 : fix kfree(skb) in pppoe_rcv (acme) * * Module reference count is decremented in the right spot now, * guards against sock_put not actually freeing the sk * in pppoe_release. * * Author: Michal Ostrowski <mostrows@styx.uwaterloo.ca> + * Contributors: + * Arnaldo Carvalho de Melo <acme@conectiva.com.br> * * License: * This program is free software; you can redistribute it and/or @@ -353,7 +356,7 @@ static int pppoe_rcv(struct sk_buff *skb, po = get_item((unsigned long) ph->sid, skb->mac.ethernet->h_source); if(!po){ - kfree(skb); + kfree_skb(skb); return 0; } diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c index 31521cfde..fba1949a8 100644 --- a/drivers/net/smc9194.c +++ b/drivers/net/smc9194.c @@ -18,6 +18,8 @@ . . author: . Erik Stahlman ( erik@vt.edu ) + . contributors: + . Arnaldo Carvalho de Melo <acme@conectiva.com.br> . . Hardware multicast code from Peter Cammaert ( pc@denkart.be ) . @@ -47,6 +49,7 @@ . 03/06/96 Erik Stahlman Added hardware multicast from Peter Cammaert . 04/14/00 Heiko Pruessing (SMA Regelsysteme) Fixed bug in chip memory . allocation + . 08/20/00 Arnaldo Melo fix kfree(skb) in smc_hardware_send_packet ----------------------------------------------------------------------------*/ static const char *version = @@ -623,7 +626,7 @@ static void smc_hardware_send_packet( struct net_device * dev ) if ( packet_no & 0x80 ) { /* or isn't there? BAD CHIP! */ printk(KERN_DEBUG CARDNAME": Memory allocation failed. \n"); - kfree(skb); + kfree_skb(skb); lp->saved_skb = NULL; netif_wake_queue(dev); return; diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index 85089a8ea..fd453a2de 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -17,6 +17,8 @@ Support and updates available at http://www.scyld.com/network/starfire.html + ----------------------------------------------------------- + Linux kernel-specific changes: LK1.1.1 (jgarzik): @@ -29,8 +31,20 @@ LK1.1.3 (Andrew Morton) - Timer cleanups + + LK1.1.4 (jgarzik): + - Merge Becker version 1.03 */ +/* These identify the driver base version and may not be removed. */ +static const char version1[] = +"starfire.c:v1.03 7/26/2000 Written by Donald Becker <becker@scyld.com>\n"; +static const char version2[] = +" Updates and info at http://www.scyld.com/network/starfire.html\n"; + +static const char version3[] = +" (unofficial 2.4.x kernel port, version 1.1.4, August 10, 2000)\n"; + /* The user-configurable values. These may be modified when a driver module is loaded.*/ @@ -74,8 +88,6 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; #define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ -#define PFX "starfire: " - #if !defined(__OPTIMIZE__) #warning You must compile this file with the correct options! #warning See the last lines of the source file. @@ -85,6 +97,10 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; /* Include files, designed to support most kernel versions 2.0.0 and later. */ #include <linux/version.h> #include <linux/module.h> +#if LINUX_VERSION_CODE < 0x20300 && defined(MODVERSIONS) +#include <linux/modversions.h> +#endif + #include <linux/kernel.h> #include <linux/string.h> #include <linux/timer.h> @@ -101,12 +117,6 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; #include <asm/bitops.h> #include <asm/io.h> -/* These identify the driver base version and may not be removed. */ -static char version1[] __devinitdata = -"starfire.c:v0.15+LK1.1.3 6/17/2000 Written by Donald Becker <becker@scyld.com>\n"; -static char version2[] __devinitdata = -" Updates and info at http://www.scyld.com/network/starfire.html\n"; - MODULE_AUTHOR("Donald Becker <becker@scyld.com>"); MODULE_DESCRIPTION("Adaptec Starfire Ethernet driver"); MODULE_PARM(max_interrupt_work, "i"); @@ -187,18 +197,18 @@ IV. Notes IVb. References -The Adaptec Starfire manuals. -http://cesdis.gsfc.nasa.gov/linux/misc/100mbps.html -http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html - +The Adaptec Starfire manuals, available only from Adaptec. +http://www.scyld.com/expert/100mbps.html +http://www.scyld.com/expert/NWay.html IVc. Errata */ + enum chip_capability_flags {CanHaveMII=1, }; - +#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR0) #define MEM_ADDR_SZ 0x80000 /* And maps in 0.5MB(!). */ #if 0 @@ -211,14 +221,12 @@ enum chipset { CH_6915 = 0, }; - static struct pci_device_id starfire_pci_tbl[] __devinitdata = { { 0x9004, 0x6915, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_6915 }, { 0, } }; MODULE_DEVICE_TABLE(pci, starfire_pci_tbl); - /* A chip capabilities table, matching the CH_xxx entries in xxx_pci_tbl[] above. */ static struct chip_info { const char *name; @@ -309,6 +317,7 @@ struct tx_done_report { #endif }; +#define PRIV_ALIGN 15 /* Required alignment mask */ struct ring_info { struct sk_buff *skb; dma_addr_t mapping; @@ -333,7 +342,6 @@ struct netdev_private { dma_addr_t tx_done_q_dma; struct net_device_stats stats; struct timer_list timer; /* Media monitoring timer. */ - int chip_id, drv_flags; struct pci_dev *pci_dev; /* Frequently used values: keep some adjacent for cache effect. */ unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ @@ -341,11 +349,10 @@ struct netdev_private { unsigned int rx_buf_sz; /* Based on MTU+slack. */ unsigned int tx_full:1; /* The Tx queue is full. */ /* These values are keep track of the transceiver/media in use. */ - unsigned int duplex_lock:1; unsigned int full_duplex:1, /* Full-duplex operation requested. */ + medialock:1, /* Xcvr set to fixed speed/duplex. */ rx_flowctrl:1, tx_flowctrl:1; /* Use 802.3x flow control. */ - unsigned int medialock:1; /* Do not sense media. */ unsigned int default_port:4; /* Last dev->if_port value. */ u32 tx_mode; u8 tx_threshold; @@ -383,30 +390,31 @@ static int __devinit starfire_init_one (struct pci_dev *pdev, static int card_idx = -1; static int printed_version = 0; long ioaddr; - int io_size = netdrv_tbl[chip_idx].io_size; + int drv_flags, io_size = netdrv_tbl[chip_idx].io_size; card_idx++; option = card_idx < MAX_UNITS ? options[card_idx] : 0; if (!printed_version++) - printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2); + printk(KERN_INFO "%s" KERN_INFO "%s" KERN_INFO "%s", + version1, version2, version3); ioaddr = pci_resource_start (pdev, 0); if (!ioaddr || ((pci_resource_flags (pdev, 0) & IORESOURCE_MEM) == 0)) { - printk (KERN_ERR PFX "card %d: no PCI MEM resources, aborting\n", card_idx); + printk (KERN_ERR "starfire %d: no PCI MEM resources, aborting\n", card_idx); return -ENODEV; } dev = init_etherdev(NULL, sizeof(*np)); if (!dev) { - printk (KERN_ERR PFX "card %d: cannot alloc etherdev, aborting\n", card_idx); + printk (KERN_ERR "starfire %d: cannot alloc etherdev, aborting\n", card_idx); return -ENOMEM; } irq = pdev->irq; if (request_mem_region (ioaddr, io_size, dev->name) == NULL) { - printk (KERN_ERR PFX "card %d: resource 0x%x @ 0x%lx busy, aborting\n", + printk (KERN_ERR "starfire %d: resource 0x%x @ 0x%lx busy, aborting\n", card_idx, io_size, ioaddr); goto err_out_free_netdev; } @@ -416,7 +424,7 @@ static int __devinit starfire_init_one (struct pci_dev *pdev, ioaddr = (long) ioremap (ioaddr, io_size); if (!ioaddr) { - printk (KERN_ERR PFX "card %d: cannot remap 0x%x @ 0x%lx, aborting\n", + printk (KERN_ERR "starfire %d: cannot remap 0x%x @ 0x%lx, aborting\n", card_idx, io_size, ioaddr); goto err_out_free_res; } @@ -436,7 +444,7 @@ static int __devinit starfire_init_one (struct pci_dev *pdev, #if ! defined(final_version) /* Dump the EEPROM contents during development. */ if (debug > 4) for (i = 0; i < 0x20; i++) - printk("%2.2x%s", readb(ioaddr + EEPROMCtrl + i), + printk("%2.2x%s", (unsigned int)readb(ioaddr + EEPROMCtrl + i), i % 16 != 15 ? " " : "\n"); #endif @@ -446,16 +454,11 @@ static int __devinit starfire_init_one (struct pci_dev *pdev, dev->base_addr = ioaddr; dev->irq = irq; - pdev->driver_data = dev; - - /* private struct aligned and zeroed by init_etherdev */ np = dev->priv; + pdev->driver_data = dev; np->pci_dev = pdev; - np->chip_id = chip_idx; - - /* save useful data, netdrv_tbl is __devinitdata and might be dropped */ - np->drv_flags = netdrv_tbl[chip_idx].drv_flags; + drv_flags = netdrv_tbl[chip_idx].drv_flags; if (dev->mem_start) option = dev->mem_start; @@ -472,7 +475,7 @@ static int __devinit starfire_init_one (struct pci_dev *pdev, np->full_duplex = 1; if (np->full_duplex) - np->duplex_lock = 1; + np->medialock = 1; /* The chip-specific entries in the device structure. */ dev->open = &netdev_open; @@ -487,7 +490,7 @@ static int __devinit starfire_init_one (struct pci_dev *pdev, if (mtu) dev->mtu = mtu; - if (np->drv_flags & CanHaveMII) { + if (drv_flags & CanHaveMII) { int phy, phy_idx = 0; for (phy = 0; phy < 32 && phy_idx < 4; phy++) { int mii_status = mdio_read(dev, phy, 1); @@ -611,17 +614,18 @@ static int netdev_open(struct net_device *dev) /* Fill both the unused Tx SA register and the Rx perfect filter. */ for (i = 0; i < 6; i++) - writeb(dev->dev_addr[i], ioaddr + StationAddr + 6-i); + writeb(dev->dev_addr[i], ioaddr + StationAddr + 5-i); for (i = 0; i < 16; i++) { u16 *eaddrs = (u16 *)dev->dev_addr; long setup_frm = ioaddr + 0x56000 + i*16; - writew(eaddrs[0], setup_frm); setup_frm += 4; - writew(eaddrs[1], setup_frm); setup_frm += 4; - writew(eaddrs[2], setup_frm); setup_frm += 4; + writew(cpu_to_be16(eaddrs[2]), setup_frm); setup_frm += 4; + writew(cpu_to_be16(eaddrs[1]), setup_frm); setup_frm += 4; + writew(cpu_to_be16(eaddrs[0]), setup_frm); setup_frm += 8; } /* Initialize other registers. */ /* Configure the PCI bus bursts and FIFO thresholds. */ + np->tx_mode = 0; /* Initialized when TxMode set. */ np->tx_threshold = 4; writel(np->tx_threshold, ioaddr + TxThreshold); writel(interrupt_mitigation, ioaddr + IntrTimerCtrl); @@ -635,6 +639,7 @@ static int netdev_open(struct net_device *dev) printk(KERN_DEBUG "%s: Setting the Rx and Tx modes.\n", dev->name); set_rx_mode(dev); + np->advertising = mdio_read(dev, np->phys[0], 4); check_duplex(dev, 1); /* Set the interrupt mask and enable PCI interrupts. */ @@ -666,23 +671,26 @@ static void check_duplex(struct net_device *dev, int startup) { struct netdev_private *np = (struct netdev_private *)dev->priv; long ioaddr = dev->base_addr; - int mii_reg5 = mdio_read(dev, np->phys[0], 5); - int negotiated = mii_reg5 & np->advertising; - int duplex, new_tx_mode ; - - new_tx_mode = 0x0C04 | (np->tx_flowctrl ? 0x0800:0) | (np->rx_flowctrl ? 0x0400:0); - if (np->duplex_lock) - duplex = 1; - else - duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040; - if (duplex) - new_tx_mode |= 2; - if (np->full_duplex != duplex) { - np->full_duplex = duplex; - if (debug) - printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d" - " negotiated capability %4.4x.\n", dev->name, - duplex ? "full" : "half", np->phys[0], negotiated); + int new_tx_mode ; + + new_tx_mode = 0x0C04 | (np->tx_flowctrl ? 0x0800:0) + | (np->rx_flowctrl ? 0x0400:0); + if (np->medialock) { + if (np->full_duplex) + new_tx_mode |= 2; + } else { + int mii_reg5 = mdio_read(dev, np->phys[0], 5); + int negotiated = mii_reg5 & np->advertising; + int duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040; + if (duplex) + new_tx_mode |= 2; + if (np->full_duplex != duplex) { + np->full_duplex = duplex; + if (debug > 1) + printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d" + " negotiated capability %4.4x.\n", dev->name, + duplex ? "full" : "half", np->phys[0], negotiated); + } } if (new_tx_mode != np->tx_mode) { np->tx_mode = new_tx_mode; @@ -700,7 +708,7 @@ static void netdev_timer(unsigned long data) if (debug > 3) { printk(KERN_DEBUG "%s: Media selection timer tick, status %8.8x.\n", - dev->name, readl(ioaddr + IntrStatus)); + dev->name, (int)readl(ioaddr + IntrStatus)); } check_duplex(dev, 0); #if ! defined(final_version) @@ -710,7 +718,7 @@ static void netdev_timer(unsigned long data) /* Bogus hardware IRQ: Fake an interrupt handler call. */ if (new_status & 1) { printk(KERN_ERR "%s: Interrupt blocked, status %8.8x/%8.8x.\n", - dev->name, new_status, readl(ioaddr + IntrStatus)); + dev->name, new_status, (int)readl(ioaddr + IntrStatus)); intr_handler(dev->irq, dev, 0); } } @@ -726,7 +734,7 @@ static void tx_timeout(struct net_device *dev) long ioaddr = dev->base_addr; printk(KERN_WARNING "%s: Transmit timed out, status %8.8x," - " resetting...\n", dev->name, readl(ioaddr + IntrStatus)); + " resetting...\n", dev->name, (int)readl(ioaddr + IntrStatus)); #ifndef __alpha__ { @@ -743,15 +751,13 @@ static void tx_timeout(struct net_device *dev) /* Perhaps we should reinitialize the hardware here. */ dev->if_port = 0; - /* Stop and restart the chip's Tx processes . */ - /* XXX todo */ /* Trigger an immediate transmit demand. */ - /* XXX todo */ dev->trans_start = jiffies; np->stats.tx_errors++; + return; } @@ -952,7 +958,7 @@ static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) if (debug > 4) printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n", - dev->name, readl(ioaddr + IntrStatus)); + dev->name, (int)readl(ioaddr + IntrStatus)); #ifndef final_version /* Code that should never be run! Remove after testing.. */ @@ -1104,7 +1110,7 @@ static void netdev_error(struct net_device *dev, int intr_status) struct netdev_private *np = (struct netdev_private *)dev->priv; if (intr_status & LinkChange) { - printk(KERN_ERR "%s: Link changed: Autonegotiation advertising" + printk(KERN_NOTICE "%s: Link changed: Autonegotiation advertising" " %4.4x partner %4.4x.\n", dev->name, mdio_read(dev, np->phys[0], 4), mdio_read(dev, np->phys[0], 5)); @@ -1132,9 +1138,7 @@ static struct net_device_stats *get_stats(struct net_device *dev) long ioaddr = dev->base_addr; struct netdev_private *np = (struct netdev_private *)dev->priv; - /* We should lock this segment of code for SMP eventually, although - the vulnerability window is very small and statistics are - non-critical. */ + /* This adapter architecture needs no SMP locks. */ np->stats.tx_bytes = readl(ioaddr + 0x57010); np->stats.rx_bytes = readl(ioaddr + 0x57044); np->stats.tx_packets = readl(ioaddr + 0x57000); @@ -1201,9 +1205,9 @@ static void set_rx_mode(struct net_device *dev) for (i = 1, mclist = dev->mc_list; mclist && i <= dev->mc_count; i++, mclist = mclist->next) { u16 *eaddrs = (u16 *)mclist->dmi_addr; - writew(*eaddrs++, filter_addr); filter_addr += 4; - writew(*eaddrs++, filter_addr); filter_addr += 4; - writew(*eaddrs++, filter_addr); filter_addr += 8; + writew(cpu_to_be16(eaddrs[2]), filter_addr); filter_addr += 4; + writew(cpu_to_be16(eaddrs[1]), filter_addr); filter_addr += 4; + writew(cpu_to_be16(eaddrs[0]), filter_addr); filter_addr += 8; } while (i++ < 16) { writew(0xffff, filter_addr); filter_addr += 4; @@ -1232,16 +1236,17 @@ static void set_rx_mode(struct net_device *dev) writew(mc_filter[i], filter_addr); rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; } - writel(rx_mode|AcceptAll, ioaddr + RxFilterMode); + writel(rx_mode, ioaddr + RxFilterMode); } static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { + struct netdev_private *np = (struct netdev_private *)dev->priv; u16 *data = (u16 *)&rq->ifr_data; switch(cmd) { case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ - data[0] = ((struct netdev_private *)dev->priv)->phys[0] & 0x1f; + data[0] = np->phys[0] & 0x1f; /* Fall Through */ case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f); @@ -1249,6 +1254,21 @@ static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) case SIOCDEVPRIVATE+2: /* Write the specified MII register */ if (!capable(CAP_NET_ADMIN)) return -EPERM; + if (data[0] == np->phys[0]) { + u16 value = data[2]; + switch (data[1]) { + case 0: + if (value & 0x9000) /* Autonegotiation. */ + np->medialock = 0; + else { + np->full_duplex = (value & 0x0100) ? 1 : 0; + np->medialock = 1; + } + break; + case 4: np->advertising = value; break; + } + check_duplex(dev, 0); + } mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]); return 0; default: @@ -1267,8 +1287,8 @@ static int netdev_close(struct net_device *dev) del_timer_sync(&np->timer); if (debug > 1) { - printk(KERN_DEBUG "%s: Shutting down ethercard, status was Int %4.4x.\n", - dev->name, readl(ioaddr + IntrStatus)); + printk(KERN_DEBUG "%s: Shutting down ethercard, Intr status %4.4x.\n", + dev->name, (int)readl(ioaddr + IntrStatus)); printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d, Rx %d / %d.\n", dev->name, np->cur_tx, np->dirty_tx, np->cur_rx, np->dirty_rx); } diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c index 39d278bb1..ad98ac405 100644 --- a/drivers/net/sunlance.c +++ b/drivers/net/sunlance.c @@ -1,4 +1,4 @@ -/* $Id: sunlance.c,v 1.102 2000/06/30 10:18:35 davem Exp $ +/* $Id: sunlance.c,v 1.103 2000/08/12 19:23:38 anton Exp $ * lance.c: Linux/Sparc/Lance driver * * Written 1995, 1996 by Miguel de Icaza @@ -109,8 +109,6 @@ static char *lancestr = "LANCE"; #include <linux/etherdevice.h> #include <linux/skbuff.h> -#include <asm/machines.h> - /* Define: 2^4 Tx buffers and 2^4 Rx buffers */ #ifndef LANCE_LOG_TX_BUFFERS #define LANCE_LOG_TX_BUFFERS 4 diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c index 165d611b8..63dce60eb 100644 --- a/drivers/net/tlan.c +++ b/drivers/net/tlan.c @@ -97,6 +97,12 @@ * * v1.8a May 28, 2000 - Minor updates. * + * v1.9 July 25, 2000 - Fixed a few remaining Full-Duplex issues. + * - Updated with timer fixes from Andrew Morton. + * - Fixed module race in TLan_Open. + * - Added routine to monitor PHY status. + * - Added activity led support for Proliant devices. + * *******************************************************************************/ @@ -138,7 +144,7 @@ static int debug = 0; static int bbuf = 0; static u8 *TLanPadBuffer; static char TLanSignature[] = "TLAN"; -static const char *tlan_banner = "ThunderLAN driver v1.8a\n"; +static const char *tlan_banner = "ThunderLAN driver v1.9\n"; const char *media[] = { "10BaseT-HD ", "10BaseT-FD ","100baseTx-HD ", @@ -181,7 +187,7 @@ static TLanAdapterEntry TLanAdapterList[] __initdata = { { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETELLIGENT_10_100_PROLIANT, "Compaq Netelligent Integrated 10/100 TX UTP", - TLAN_ADAPTER_NONE, + TLAN_ADAPTER_ACTIVITY_LED, 0x83 }, { PCI_VENDOR_ID_COMPAQ, @@ -272,6 +278,7 @@ static void TLan_PhyPowerUp( struct net_device * ); static void TLan_PhyReset( struct net_device * ); static void TLan_PhyStartLink( struct net_device * ); static void TLan_PhyFinishAutoNeg( struct net_device * ); +static void TLan_PhyMonitor( struct net_device * ); /* static int TLan_PhyNop( struct net_device * ); static int TLan_PhyInternalCheck( struct net_device * ); @@ -701,7 +708,8 @@ static int TLan_Open( struct net_device *dev ) if ( err ) { printk(KERN_ERR "TLAN: Cannot open %s because IRQ %d is already in use.\n", dev->name, dev->irq ); - return -EAGAIN; + MOD_DEC_USE_COUNT; + return err; } netif_start_queue(dev); @@ -942,7 +950,7 @@ static int TLan_Close(struct net_device *dev) TLan_ReadAndClearStats( dev, TLAN_RECORD ); outl( TLAN_HC_AD_RST, dev->base_addr + TLAN_HOST_CMD ); if ( priv->timer.function != NULL ) { - del_timer( &priv->timer ); + del_timer_sync( &priv->timer ); priv->timer.function = NULL; } free_irq( dev->irq, dev ); @@ -1590,6 +1598,9 @@ void TLan_Timer( unsigned long data ) priv->timer.function = NULL; switch ( priv->timerType ) { + case TLAN_TIMER_LINK_BEAT: + TLan_PhyMonitor( dev ); + break; case TLAN_TIMER_PHY_PDOWN: TLan_PhyPowerDown( dev ); break; @@ -2041,6 +2052,12 @@ TLan_FinishReset( struct net_device *dev ) } TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK ); + + /* We have link beat..for now anyway */ + priv->link = 1; + /*Enabling link beat monitoring */ + TLan_SetTimer( dev, (10*HZ), TLAN_TIMER_LINK_BEAT ); + } } @@ -2062,7 +2079,8 @@ TLan_FinishReset( struct net_device *dev ) } outl( virt_to_bus( priv->rxList ), dev->base_addr + TLAN_CH_PARM ); outl( TLAN_HC_GO | TLAN_HC_RT, dev->base_addr + TLAN_HOST_CMD ); - } else { + + } else { printk( "TLAN: %s: Link inactive, will retry in 10 secs...\n", dev->name ); TLan_SetTimer( dev, (10*HZ), TLAN_TIMER_FINISH_RESET ); return; @@ -2329,12 +2347,14 @@ void TLan_PhyStartLink( struct net_device *dev ) TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x0000); } else if ( priv->speed == TLAN_SPEED_10 && priv->duplex == TLAN_DUPLEX_FULL) { + priv->tlanFullDuplex = TRUE; TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x0100); } else if ( priv->speed == TLAN_SPEED_100 && priv->duplex == TLAN_DUPLEX_HALF) { TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x2000); } else if ( priv->speed == TLAN_SPEED_100 && priv->duplex == TLAN_DUPLEX_FULL) { + priv->tlanFullDuplex = TRUE; TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x2100); } else { @@ -2418,9 +2438,9 @@ void TLan_PhyFinishAutoNeg( struct net_device *dev ) TLan_MiiReadReg( dev, phy, MII_AN_LPA, &an_lpa ); mode = an_adv & an_lpa & 0x03E0; if ( mode & 0x0100 ) { - priv->tlanFullDuplex = TRUE; + priv->tlanFullDuplex = TRUE; } else if ( ! ( mode & 0x0080 ) && ( mode & 0x0040 ) ) { - priv->tlanFullDuplex = TRUE; + priv->tlanFullDuplex = TRUE; } if ( ( ! ( mode & 0x0180 ) ) && ( priv->adapter->flags & TLAN_ADAPTER_USE_INTERN_10 ) && ( priv->phyNum != 0 ) ) { @@ -2450,6 +2470,61 @@ void TLan_PhyFinishAutoNeg( struct net_device *dev ) + /********************************************************************* + * + * TLan_PhyMonitor + * + * Returns: + * None + * + * Params: + * dev The device structure of this device. + * + * + * This function monitors PHY condition by reading the status + * register via the MII bus. This can be used to give info + * about link changes (up/down), and possible switch to alternate + * media. + * + * ******************************************************************/ + +void TLan_PhyMonitor( struct net_device *dev ) +{ + TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + u16 phy; + u16 phy_status; + + phy = priv->phy[priv->phyNum]; + + /* Get PHY status register */ + TLan_MiiReadReg( dev, phy, MII_GEN_STS, &phy_status ); + + /* Check if link has been lost */ + if (!(phy_status & MII_GS_LINK)) { + if (priv->link) { + priv->link = 0; + printk(KERN_DEBUG "TLAN: %s has lost link\n", dev->name); + dev->flags &= ~IFF_RUNNING; + TLan_SetTimer( dev, (2*HZ), TLAN_TIMER_LINK_BEAT ); + return; + } + } + + /* Link restablished? */ + if ((phy_status & MII_GS_LINK) && !priv->link) { + priv->link = 1; + printk(KERN_DEBUG "TLAN: %s has reestablished link\n", dev->name); + dev->flags |= IFF_RUNNING; + TLan_SetTimer( dev, (2*HZ), TLAN_TIMER_LINK_BEAT ); + } + + /* Setup a new monitor */ + TLan_SetTimer( dev, (2*HZ), TLAN_TIMER_LINK_BEAT ); + +} + + + /***************************************************************************** ****************************************************************************** diff --git a/drivers/net/tlan.h b/drivers/net/tlan.h index f04ca6996..1d032f4b0 100644 --- a/drivers/net/tlan.h +++ b/drivers/net/tlan.h @@ -187,6 +187,7 @@ typedef struct tlan_private_tag { u8 tlanFullDuplex; char devName[8]; spinlock_t lock; + u8 link; } TLanPrivateInfo; @@ -197,7 +198,7 @@ typedef struct tlan_private_tag { * ****************************************************************/ -#define TLAN_TIMER_LINK 1 +#define TLAN_TIMER_LINK_BEAT 1 #define TLAN_TIMER_ACTIVITY 2 #define TLAN_TIMER_PHY_PDOWN 3 #define TLAN_TIMER_PHY_PUP 4 @@ -381,9 +382,9 @@ typedef struct tlan_private_tag { #define MII_GIL_OUI 0xFC00 #define MII_GIL_MODEL 0x03F0 #define MII_GIL_REVISION 0x000F -#define MII_AN_ADV 0x04 -#define MII_AN_LPA 0x05 -#define MII_AN_EXP 0x06 +#define MII_AN_ADV 0x0004 +#define MII_AN_LPA 0x0005 +#define MII_AN_EXP 0x0006 /* ThunderLAN Specific MII/PHY Registers */ diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index 4f6252383..4e2338bb3 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -28,7 +28,7 @@ #include <asm/unaligned.h> static char version[] __devinitdata = - "Linux Tulip driver version 0.9.8 (July 13, 2000)\n"; + "Linux Tulip driver version 0.9.9 (August 11, 2000)\n"; /* A few user-configurable values. */ @@ -165,6 +165,8 @@ static struct pci_device_id tulip_pci_tbl[] __devinitdata = { { 0x1317, 0x0981, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, { 0x1317, 0x0985, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, { 0x1317, 0x1985, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, + { 0x13D1, 0xAB02, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, + { 0x13D1, 0xAB03, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, { 0x11F6, 0x9881, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMPEX9881 }, { 0x8086, 0x0039, PCI_ANY_ID, PCI_ANY_ID, 0, 0, I21145 }, { 0x1282, 0x9100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21140 }, diff --git a/drivers/net/tun.c b/drivers/net/tun.c new file mode 100644 index 000000000..26282e38f --- /dev/null +++ b/drivers/net/tun.c @@ -0,0 +1,535 @@ +/* + * TUN - Universal TUN/TAP device driver. + * Copyright (C) 1999-2000 Maxim Krasnyansky <max_mk@yahoo.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * $Id: tun.c,v 1.1 2000/08/23 05:59:28 davem Exp $ + */ + +/* + * Daniel Podlejski <underley@underley.eu.org> + * Modifications for 2.3.99-pre5 kernel. + */ + +#define TUN_VER "1.1" + +#include <linux/module.h> + +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/major.h> +#include <linux/sched.h> +#include <linux/malloc.h> +#include <linux/poll.h> +#include <linux/fcntl.h> +#include <linux/init.h> +#include <linux/devfs_fs_kernel.h> +#include <linux/random.h> + +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/rtnetlink.h> +#include <linux/if.h> +#include <linux/if_arp.h> +#include <linux/if_ether.h> +#include <linux/if_tun.h> + +#include <asm/system.h> +#include <asm/uaccess.h> + + +#ifdef TUN_DEBUG +static int debug=0; +#endif + +/* Network device part of the driver */ + +/* Net device open. */ +static int tun_net_open(struct net_device *dev) +{ +#ifdef TUN_DEBUG + struct tun_struct *tun = (struct tun_struct *)dev->priv; + + DBG(KERN_INFO "%s: tun_net_open\n", tun->name); +#endif + + netif_start_queue(dev); + + return 0; +} + +/* Net device close. */ +static int tun_net_close(struct net_device *dev) +{ +#ifdef TUN_DEBUG + struct tun_struct *tun = (struct tun_struct *)dev->priv; + + DBG(KERN_INFO "%s: tun_net_close\n", tun->name); +#endif + + netif_stop_queue(dev); + + return 0; +} + +/* Net device start xmit */ +static int tun_net_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct tun_struct *tun = (struct tun_struct *)dev->priv; + + DBG(KERN_INFO "%s: tun_net_xmit %d\n", tun->name, skb->len); + + + if (netif_queue_stopped(dev)) + return 1; + + tun->stats.tx_packets++; + + /* Queue frame */ + skb_queue_tail(&tun->txq, skb); + if (skb_queue_len(&tun->txq) >= TUN_TXQ_SIZE) + netif_stop_queue(dev); + + if (tun->flags & TUN_FASYNC) + kill_fasync(&tun->fasync, SIGIO, POLL_IN); + + /* Wake up process */ + wake_up_interruptible(&tun->read_wait); + + return 0; +} + +static void tun_net_mclist(struct net_device *dev) +{ +#ifdef TUN_DEBUG + struct tun_struct *tun = (struct tun_struct *)dev->priv; + + DBG(KERN_INFO "%s: tun_net_mclist\n", tun->name); +#endif + + /* Nothing to do for multicast filters. + * We always accept all frames. + */ + return; +} + +static struct net_device_stats *tun_net_stats(struct net_device *dev) +{ + struct tun_struct *tun = (struct tun_struct *)dev->priv; + + return &tun->stats; +} + +/* Initialize net device. */ +int tun_net_init(struct net_device *dev) +{ + struct tun_struct *tun = (struct tun_struct *)dev->priv; + + DBG(KERN_INFO "%s: tun_net_init\n", tun->name); + + dev->open = tun_net_open; + dev->hard_start_xmit = tun_net_xmit; + dev->stop = tun_net_close; + dev->get_stats = tun_net_stats; + + switch (tun->flags & TUN_TYPE_MASK) { + case TUN_TUN_DEV: + /* Point-to-Point TUN Device */ + dev->hard_header_len = 0; + dev->addr_len = 0; + dev->mtu = 1500; + + /* Type PPP seems most suitable */ + dev->type = ARPHRD_PPP; + dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST; + dev->tx_queue_len = 10; + + dev_init_buffers(dev); + break; + + case TUN_TAP_DEV: + /* Ethernet TAP Device */ + dev->set_multicast_list = tun_net_mclist; + + /* Generate random Ethernet address. */ + *(u16 *)dev->dev_addr = htons(0x00FF); + get_random_bytes(dev->dev_addr + sizeof(u16), 4); + + ether_setup(dev); + break; + }; + + return 0; +} + +/* Character device part */ + +/* Poll */ +static unsigned int tun_chr_poll(struct file *file, poll_table * wait) +{ + struct tun_struct *tun = (struct tun_struct *)file->private_data; + + DBG(KERN_INFO "%s: tun_chr_poll\n", tun->name); + + poll_wait(file, &tun->read_wait, wait); + + if (skb_queue_len(&tun->txq)) + return POLLIN | POLLRDNORM; + + return POLLOUT | POLLWRNORM; +} + +/* Get packet from user space buffer(already verified) */ +static __inline__ ssize_t tun_get_user(struct tun_struct *tun, const char *buf, size_t count) +{ + struct tun_pi pi = { 0, __constant_htons(ETH_P_IP) }; + register const char *ptr = buf; + register int len = count; + struct sk_buff *skb; + + if (len > TUN_MAX_FRAME) + return -EINVAL; + + if (!(tun->flags & TUN_NO_PI)) { + if ((len -= sizeof(pi)) < 0) + return -EINVAL; + + copy_from_user(&pi, ptr, sizeof(pi)); + ptr += sizeof(pi); + } + + if (!(skb = alloc_skb(len + 2, GFP_KERNEL))) { + tun->stats.rx_dropped++; + return -ENOMEM; + } + + skb_reserve(skb, 2); + copy_from_user(skb_put(skb, count), ptr, len); + + skb->dev = &tun->dev; + switch (tun->flags & TUN_TYPE_MASK) { + case TUN_TUN_DEV: + skb->mac.raw = skb->data; + skb->protocol = pi.proto; + break; + case TUN_TAP_DEV: + skb->protocol = eth_type_trans(skb, &tun->dev); + break; + }; + + if (tun->flags & TUN_NOCHECKSUM) + skb->ip_summed = CHECKSUM_UNNECESSARY; + + netif_rx(skb); + + tun->stats.rx_packets++; + return count; +} + +/* Write */ +static ssize_t tun_chr_write(struct file * file, const char * buf, + size_t count, loff_t *pos) +{ + struct tun_struct *tun = (struct tun_struct *)file->private_data; + + DBG(KERN_INFO "%s: tun_chr_write %d\n", tun->name, count); + + if (!(tun->flags & TUN_IFF_SET)) + return -EBUSY; + + if (verify_area(VERIFY_READ, buf, count)) + return -EFAULT; + + return tun_get_user(tun, buf, count); +} + +/* Put packet to user space buffer(already verified) */ +static __inline__ ssize_t tun_put_user(struct tun_struct *tun, + struct sk_buff *skb, + char *buf, int count) +{ + struct tun_pi pi = { 0, skb->protocol }; + int len = count, total = 0; + char *ptr = buf; + + if (!(tun->flags & TUN_NO_PI)) { + if ((len -= sizeof(pi)) < 0) + return -EINVAL; + + if (len < skb->len) { + /* Packet will be striped */ + pi.flags |= TUN_PKT_STRIP; + } + + copy_to_user(ptr, &pi, sizeof(pi)); + + total += sizeof(pi); + ptr += sizeof(pi); + } + + len = MIN(skb->len, len); + copy_to_user(ptr, skb->data, len); + total += len; + + return total; +} + +/* Read */ +static ssize_t tun_chr_read(struct file * file, char * buf, + size_t count, loff_t *pos) +{ + struct tun_struct *tun = (struct tun_struct *)file->private_data; + DECLARE_WAITQUEUE(wait, current); + struct sk_buff *skb; + ssize_t ret = 0; + + DBG(KERN_INFO "%s: tun_chr_read\n", tun->name); + + add_wait_queue(&tun->read_wait, &wait); + while (count) { + current->state = TASK_INTERRUPTIBLE; + + /* Read frames from device queue */ + if (!(skb=skb_dequeue(&tun->txq))) { + if (file->f_flags & O_NONBLOCK) { + ret = -EAGAIN; + break; + } + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + + /* Nothing to read, let's sleep */ + schedule(); + continue; + } + netif_start_queue(&tun->dev); + + if (!verify_area(VERIFY_WRITE, buf, count)) + ret = tun_put_user(tun, skb, buf, count); + else + ret = -EFAULT; + + kfree_skb(skb); + break; + } + + current->state = TASK_RUNNING; + remove_wait_queue(&tun->read_wait, &wait); + + return ret; +} + +static loff_t tun_chr_lseek(struct file * file, loff_t offset, int origin) +{ + return -ESPIPE; +} + +static int tun_set_iff(struct tun_struct *tun, unsigned long arg) +{ + struct ifreq ifr; + char *mask; + + if (copy_from_user(&ifr, (void *)arg, sizeof(ifr))) + return -EFAULT; + ifr.ifr_name[IFNAMSIZ-1] = '\0'; + + if (tun->flags & TUN_IFF_SET) + return -EEXIST; + + /* Set dev type */ + if (ifr.ifr_flags & IFF_TUN) { + /* TUN device */ + tun->flags |= TUN_TUN_DEV; + mask = "tun%d"; + } else if (ifr.ifr_flags & IFF_TAP) { + /* TAP device */ + tun->flags |= TUN_TAP_DEV; + mask = "tap%d"; + } else + return -EINVAL; + + if (ifr.ifr_flags & IFF_NO_PI) + tun->flags |= TUN_NO_PI; + + if (*ifr.ifr_name) + strcpy(tun->dev.name, ifr.ifr_name); + else + strcpy(tun->dev.name, mask); + + /* Register net device */ + if (register_netdev(&tun->dev)) + return -EBUSY; + + tun->flags |= TUN_IFF_SET; + strcpy(tun->name, tun->dev.name); + + /* Return iface info to the user space */ + strcpy(ifr.ifr_name, tun->dev.name); + copy_to_user((void *)arg, &ifr, sizeof(ifr)); + + return 0; +} + +static int tun_chr_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct tun_struct *tun = (struct tun_struct *)file->private_data; + + DBG(KERN_INFO "%s: tun_chr_ioctl\n", tun->name); + + switch (cmd) { + case TUNSETIFF: + return tun_set_iff(tun, arg); + + case TUNSETNOCSUM: + /* Disable/Enable checksum on net iface */ + if (arg) + tun->flags |= TUN_NOCHECKSUM; + else + tun->flags &= ~TUN_NOCHECKSUM; + + DBG(KERN_INFO "%s: checksum %s\n", + tun->name, arg ? "disabled" : "enabled"); + break; + +#ifdef TUN_DEBUG + case TUNSETDEBUG: + tun->debug = arg; + break; +#endif + + default: + return -EINVAL; + }; + + return 0; +} + +static int tun_chr_fasync(int fd, struct file *file, int on) +{ + struct tun_struct *tun = (struct tun_struct *)file->private_data; + int ret; + + DBG(KERN_INFO "%s: tun_chr_fasync %d\n", tun->name, on); + + if ((ret = fasync_helper(fd, file, on, &tun->fasync)) < 0) + return ret; + + if (on) + tun->flags |= TUN_FASYNC; + else + tun->flags &= ~TUN_FASYNC; + + return 0; +} + +static int tun_chr_open(struct inode *inode, struct file * file) +{ + struct tun_struct *tun = NULL; + + DBG1(KERN_INFO "tunX: tun_chr_open\n"); + + tun = kmalloc(sizeof(struct tun_struct), GFP_KERNEL); + if (tun == NULL) + return -ENOMEM; + + memset(tun, 0, sizeof(struct tun_struct)); + file->private_data = tun; + + skb_queue_head_init(&tun->txq); + init_waitqueue_head(&tun->read_wait); + + sprintf(tun->name, "tunX"); + + tun->dev.init = tun_net_init; + tun->dev.priv = tun; + + MOD_INC_USE_COUNT; + + return 0; +} + +static int tun_chr_close(struct inode *inode, struct file *file) +{ + struct tun_struct *tun = (struct tun_struct *)file->private_data; + + DBG(KERN_INFO "%s: tun_chr_close\n", tun->name); + + if (tun->flags & TUN_IFF_SET) { + rtnl_lock(); + dev_close(&tun->dev); + rtnl_unlock(); + + /* Drop TX queue */ + skb_queue_purge(&tun->txq); + + unregister_netdev(&tun->dev); + } + + kfree(tun); + file->private_data = NULL; + + MOD_DEC_USE_COUNT; + return 0; +} + +static struct file_operations tun_fops = { + owner: THIS_MODULE, + llseek: tun_chr_lseek, + read: tun_chr_read, + write: tun_chr_write, + poll: tun_chr_poll, + ioctl: tun_chr_ioctl, + open: tun_chr_open, + release:tun_chr_close, + fasync: tun_chr_fasync +}; + +static devfs_handle_t devfs_handle = NULL; + +int __init tun_init(void) +{ + printk(KERN_INFO "Universal TUN/TAP device driver %s " + "(C)1999-2000 Maxim Krasnyansky\n", TUN_VER); + + if (devfs_register_chrdev(TUN_MAJOR, "tun", &tun_fops)) { + printk(KERN_ERR "tun: Can't register char device %d\n", + TUN_MAJOR); + return -EIO; + } + + devfs_handle = devfs_register(NULL, "net/tun", DEVFS_FL_DEFAULT, + TUN_MAJOR, 0, + S_IFCHR | S_IRUSR | S_IWUSR, + &tun_fops, NULL); + +#ifdef MODULE + return 0; +#else + /* If driver is not module, tun_init will be called from Space.c. + * Return non-zero not to register fake device. + */ + return 1; +#endif +} + +void tun_cleanup(void) +{ + devfs_unregister_chrdev(TUN_MAJOR,"tun"); + devfs_unregister(devfs_handle); +} + +module_init(tun_init); +module_exit(tun_cleanup); diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index 67db42e97..9d0947b05 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -51,8 +51,13 @@ - Urban Widmark: mdio locking, bounce buffer changes merges from Beckers 1.05 version added netif_running_on/off support + + LK1.1.6: + - Urban Widmark: merges from Beckers 1.08b version (VT6102 + mdio) + set netif_running_on/off on startup, del_timer_sync */ + /* A few user-configurable values. These may be modified when a driver module is loaded. */ @@ -85,7 +90,7 @@ static const int multicast_filter_limit = 32; bonding and packet priority. There are no ill effects from too-large receive rings. */ #define TX_RING_SIZE 16 -#define TX_QUEUE_LEN 10 /* Limit ring entries actually used. */ +#define TX_QUEUE_LEN 10 /* Limit ring entries actually used. */ #define RX_RING_SIZE 16 @@ -122,7 +127,7 @@ static const int multicast_filter_limit = 32; /* These identify the driver base version and may not be removed. */ static char version1[] __devinitdata = -"via-rhine.c:v1.05-LK1.1.5 5/2/2000 Written by Donald Becker\n"; +"via-rhine.c:v1.08b-LK1.1.6 8/9/2000 Written by Donald Becker\n"; static char version2[] __devinitdata = " http://www.scyld.com/network/via-rhine.html\n"; @@ -233,13 +238,13 @@ IV. Notes IVb. References Preliminary VT86C100A manual from http://www.via.com.tw/ -http://cesdis.gsfc.nasa.gov/linux/misc/100mbps.html -http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html +http://www.scyld.com/expert/100mbps.html +http://www.scyld.com/expert/NWay.html IVc. Errata The VT86C100A manual is not reliable information. -The chip does not handle unaligned transmit or receive buffers, resulting +The 3043 chip does not handle unaligned transmit or receive buffers, resulting in significant performance degradation for bounce buffer copies on transmit and unaligned IP headers on receive. The chip does not pad to minimum transmit length. @@ -261,6 +266,7 @@ enum pci_flags_bit { enum via_rhine_chips { VT86C100A = 0, + VT6102, VT3043, }; @@ -272,24 +278,33 @@ struct via_rhine_chip_info { }; -enum chip_capability_flags {CanHaveMII=1, HasESIPhy=2 }; +enum chip_capability_flags { + CanHaveMII=1, HasESIPhy=2, HasDavicomPhy=4, + ReqTxAlign=0x10, HasWOL=0x20, }; #if defined(VIA_USE_MEMORY) #define RHINE_IOTYPE (PCI_USES_MEM | PCI_USES_MASTER | PCI_ADDR1) +#define RHINEII_IOSIZE 4096 #else #define RHINE_IOTYPE (PCI_USES_IO | PCI_USES_MASTER | PCI_ADDR0) +#define RHINEII_IOSIZE 256 #endif /* directly indexed by enum via_rhine_chips, above */ static struct via_rhine_chip_info via_rhine_chip_info[] __devinitdata = { - { "VIA VT86C100A Rhine-II", RHINE_IOTYPE, 128, CanHaveMII }, - { "VIA VT3043 Rhine", RHINE_IOTYPE, 128, CanHaveMII } + { "VIA VT86C100A Rhine", RHINE_IOTYPE, 128, + CanHaveMII | ReqTxAlign }, + { "VIA VT6102 Rhine-II", RHINE_IOTYPE, RHINEII_IOSIZE, + CanHaveMII | HasWOL }, + { "VIA VT3043 Rhine", RHINE_IOTYPE, 128, + CanHaveMII | ReqTxAlign } }; static struct pci_device_id via_rhine_pci_tbl[] __devinitdata = { {0x1106, 0x6100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT86C100A}, + {0x1106, 0x3065, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT6102}, {0x1106, 0x3043, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT3043}, {0,} /* terminate list */ }; @@ -304,7 +319,8 @@ enum register_offsets { RxRingPtr=0x18, TxRingPtr=0x1C, MIIPhyAddr=0x6C, MIIStatus=0x6D, PCIBusConfig=0x6E, MIICmd=0x70, MIIRegAddr=0x71, MIIData=0x72, - Config=0x78, RxMissed=0x7C, RxCRCErrs=0x7E, + Config=0x78, ConfigA=0x7A, RxMissed=0x7C, RxCRCErrs=0x7E, + StickyHW=0x83, WOLcrClr=0xA4, WOLcgClr=0xA7, PwrcsrClr=0xAC, }; /* Bits in the interrupt status/mask registers. */ @@ -585,6 +601,12 @@ static int __devinit via_rhine_init_one (struct pci_dev *pdev, "0x%4.4x advertising %4.4x Link %4.4x.\n", dev->name, phy, mii_status, np->advertising, mdio_read(dev, phy, 5)); + + /* set IFF_RUNNING */ + if (mii_status & MIILink) + netif_carrier_on(dev); + else + netif_carrier_off(dev); } } } @@ -641,8 +663,20 @@ static void mdio_write(struct net_device *dev, int phy_id, int regnum, int value long ioaddr = dev->base_addr; int boguscnt = 1024; - if (phy_id == np->phys[0] && regnum == 4) - np->advertising = value; + if (phy_id == np->phys[0]) { + switch (regnum) { + case 0: /* Is user forcing speed/duplex? */ + if (value & 0x9000) /* Autonegotiation. */ + np->duplex_lock = 0; + else + np->full_duplex = (value & 0x0100) ? 1 : 0; + break; + case 4: + np->advertising = value; + break; + } + } + /* Wait for a previous command to complete. */ while ((readb(ioaddr + MIICmd) & 0x60) && --boguscnt > 0) ; @@ -900,7 +934,8 @@ static int via_rhine_start_tx(struct sk_buff *skb, struct net_device *dev) np->tx_skbuff[entry] = skb; - if ((long)skb->data & 3) { /* Must use alignment buffer. */ + if ((np->drv_flags & ReqTxAlign) && ((long)skb->data & 3)) { + /* Must use alignment buffer. */ memcpy(np->tx_buf[entry], skb->data, skb->len); np->tx_skbuff_dma[entry] = 0; np->tx_ring[entry].addr = cpu_to_le32(np->tx_bufs_dma + @@ -1154,10 +1189,11 @@ static void via_rhine_error(struct net_device *dev, int intr_status) spin_lock (&np->lock); if (intr_status & (IntrMIIChange | IntrLinkChange)) { - if (readb(ioaddr + MIIStatus) & 0x02) + if (readb(ioaddr + MIIStatus) & 0x02) { /* Link failed, restart autonegotiation. */ - mdio_write(dev, np->phys[0], 0, 0x3300); - else + if (np->drv_flags & HasDavicomPhy) + mdio_write(dev, np->phys[0], 0, 0x3300); + } else via_rhine_check_duplex(dev); if (debug) printk(KERN_ERR "%s: MII status changed: Autonegotiation " @@ -1309,6 +1345,8 @@ static int via_rhine_close(struct net_device *dev) int i; unsigned long flags; + del_timer_sync(&np->timer); + spin_lock_irqsave(&np->lock, flags); netif_stop_queue(dev); @@ -1317,14 +1355,15 @@ static int via_rhine_close(struct net_device *dev) printk(KERN_DEBUG "%s: Shutting down ethercard, status was %4.4x.\n", dev->name, readw(ioaddr + ChipCmd)); + /* Switch to loopback mode to avoid hardware races. */ + writeb(np->tx_thresh | 0x01, ioaddr + TxConfig); + /* Disable interrupts by clearing the interrupt mask. */ writew(0x0000, ioaddr + IntrEnable); /* Stop the chip's Tx and Rx processes. */ writew(CmdStop, ioaddr + ChipCmd); - del_timer(&np->timer); - spin_unlock_irqrestore(&np->lock, flags); /* Make sure there is no irq-handler running on a different CPU. */ diff --git a/drivers/net/wan/Config.in b/drivers/net/wan/Config.in index 4621d3981..4c8517081 100644 --- a/drivers/net/wan/Config.in +++ b/drivers/net/wan/Config.in @@ -7,86 +7,87 @@ comment 'Wan interfaces' bool 'Wan interfaces support' CONFIG_WAN if [ "$CONFIG_WAN" = "y" ]; then +# There is no way to detect a comtrol sv11 - force it modular for now. - # There is no way to detect a comtrol sv11 - force it modular for now. - - dep_tristate 'Comtrol Hostess SV-11 support' CONFIG_HOSTESS_SV11 m - - # The COSA/SRP driver has not been tested as non-modular yet. - - dep_tristate 'COSA/SRP sync serial boards support' CONFIG_COSA m - - # - # COMX drivers - # - - tristate 'MultiGate (COMX) synchronous serial boards support' CONFIG_COMX - - # - # Lan Media's board. Currently 1000, 1200, 5200, 5245 - # - tristate 'LanMedia Corp. SSI/V.35, T1/E1, HSSI, T3 boards' CONFIG_LANMEDIA - - if [ "$CONFIG_COMX" != "n" ]; then - dep_tristate ' Support for COMX/CMX/HiCOMX boards' CONFIG_COMX_HW_COMX $CONFIG_COMX - dep_tristate ' Support for LoCOMX board' CONFIG_COMX_HW_LOCOMX $CONFIG_COMX - dep_tristate ' Support for MixCOM board' CONFIG_COMX_HW_MIXCOM $CONFIG_COMX - dep_tristate ' Support for HDLC and syncPPP protocols on MultiGate boards' CONFIG_COMX_PROTO_PPP $CONFIG_COMX - if [ "$CONFIG_LAPB" = "y" ]; then - dep_tristate ' Support for LAPB protocol on MultiGate boards' CONFIG_COMX_PROTO_LAPB $CONFIG_COMX - fi - if [ "$CONFIG_LAPB" = "m" ]; then - dep_tristate ' Support for LAPB protocol on MultiGate boards' CONFIG_COMX_PROTO_LAPB $CONFIG_LAPB - fi - dep_tristate ' Support for Frame Relay on MultiGate boards' CONFIG_COMX_PROTO_FR $CONFIG_COMX - fi - - # There is no way to detect a Sealevel board. Force it modular - - dep_tristate 'Sealevel Systems 4021 support' CONFIG_SEALEVEL_4021 m - - dep_tristate 'SyncLink HDLC/SYNCPPP support' CONFIG_SYNCLINK_SYNCPPP m - - tristate 'Frame relay DLCI support' CONFIG_DLCI - if [ "$CONFIG_DLCI" != "n" ]; then - int 'Max open DLCI' CONFIG_DLCI_COUNT 24 - int 'Max DLCI per device' CONFIG_DLCI_MAX 8 - dep_tristate ' SDLA (Sangoma S502/S508) support' CONFIG_SDLA $CONFIG_DLCI - fi - - # Wan router core. - - if [ "$CONFIG_WAN_ROUTER" != "n" ]; then - bool 'WAN router drivers' CONFIG_WAN_ROUTER_DRIVERS - if [ "$CONFIG_WAN_ROUTER_DRIVERS" = "y" ]; then - dep_tristate ' Sangoma WANPIPE(tm) multiprotocol cards' CONFIG_VENDOR_SANGOMA $CONFIG_WAN_ROUTER_DRIVERS - if [ "$CONFIG_VENDOR_SANGOMA" != "n" ]; then - int ' Maximum number of cards' CONFIG_WANPIPE_CARDS 1 - bool ' WANPIPE Cisco HDLC support' CONFIG_WANPIPE_CHDLC - if [ "$CONFIG_OBSOLETE" = "y" ]; then - bool ' WANPIPE Frame Relay support' CONFIG_WANPIPE_FR - bool ' WANPIPE X.25 support' CONFIG_WANPIPE_X25 - fi - bool ' WANPIPE PPP support' CONFIG_WANPIPE_PPP - fi - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - dep_tristate ' Cyclom 2X(tm) cards (EXPERIMENTAL)' CONFIG_CYCLADES_SYNC $CONFIG_WAN_ROUTER_DRIVERS - if [ "$CONFIG_CYCLADES_SYNC" != "n" ]; then - bool ' Cyclom 2X X.25 support' CONFIG_CYCLOMX_X25 - fi - fi - fi - fi - - # X.25 network drivers - - dep_tristate 'LAPB over Ethernet driver' CONFIG_LAPBETHER $CONFIG_LAPB $CONFIG_X25 - dep_tristate 'X.25 async driver' CONFIG_X25_ASY $CONFIG_LAPB $CONFIG_X25 - - if [ "$CONFIG_X86" = "y" ]; then - tristate 'SBNI12-xx support' CONFIG_SBNI - fi + dep_tristate ' Comtrol Hostess SV-11 support' CONFIG_HOSTESS_SV11 m + +# The COSA/SRP driver has not been tested as non-modular yet. + + dep_tristate ' COSA/SRP sync serial boards support' CONFIG_COSA m + +# +# COMX drivers +# + + tristate ' MultiGate (COMX) synchronous serial boards support' CONFIG_COMX + if [ "$CONFIG_COMX" != "n" ]; then + dep_tristate ' Support for COMX/CMX/HiCOMX boards' CONFIG_COMX_HW_COMX $CONFIG_COMX + dep_tristate ' Support for LoCOMX board' CONFIG_COMX_HW_LOCOMX $CONFIG_COMX + dep_tristate ' Support for MixCOM board' CONFIG_COMX_HW_MIXCOM $CONFIG_COMX + dep_tristate ' Support for HDLC and syncPPP protocols on MultiGate boards' CONFIG_COMX_PROTO_PPP $CONFIG_COMX + if [ "$CONFIG_LAPB" = "y" ]; then + dep_tristate ' Support for LAPB protocol on MultiGate boards' CONFIG_COMX_PROTO_LAPB $CONFIG_COMX + fi + if [ "$CONFIG_LAPB" = "m" ]; then + dep_tristate ' Support for LAPB protocol on MultiGate boards' CONFIG_COMX_PROTO_LAPB $CONFIG_LAPB + fi + dep_tristate ' Support for Frame Relay on MultiGate boards' CONFIG_COMX_PROTO_FR $CONFIG_COMX + fi + +# +# Lan Media's board. Currently 1000, 1200, 5200, 5245 +# + + tristate ' LanMedia Corp. SSI/V.35, T1/E1, HSSI, T3 boards' CONFIG_LANMEDIA + +# There is no way to detect a Sealevel board. Force it modular + + dep_tristate ' Sealevel Systems 4021 support' CONFIG_SEALEVEL_4021 m + + dep_tristate ' SyncLink HDLC/SYNCPPP support' CONFIG_SYNCLINK_SYNCPPP m + + tristate ' Frame relay DLCI support' CONFIG_DLCI + if [ "$CONFIG_DLCI" != "n" ]; then + int ' Max open DLCI' CONFIG_DLCI_COUNT 24 + int ' Max DLCI per device' CONFIG_DLCI_MAX 8 + dep_tristate ' SDLA (Sangoma S502/S508) support' CONFIG_SDLA $CONFIG_DLCI + fi + +# Wan router core. + + if [ "$CONFIG_WAN_ROUTER" != "n" ]; then + bool ' WAN router drivers' CONFIG_WAN_ROUTER_DRIVERS + if [ "$CONFIG_WAN_ROUTER_DRIVERS" = "y" ]; then + dep_tristate ' Sangoma WANPIPE(tm) multiprotocol cards' CONFIG_VENDOR_SANGOMA $CONFIG_WAN_ROUTER_DRIVERS + if [ "$CONFIG_VENDOR_SANGOMA" != "n" ]; then + int ' Maximum number of cards' CONFIG_WANPIPE_CARDS 1 + bool ' WANPIPE Cisco HDLC support' CONFIG_WANPIPE_CHDLC + if [ "$CONFIG_OBSOLETE" = "y" ]; then + bool ' WANPIPE Frame Relay support (OBSOLETE)' CONFIG_WANPIPE_FR + bool ' WANPIPE X.25 support (OBSOLETE)' CONFIG_WANPIPE_X25 + fi + bool ' WANPIPE PPP support' CONFIG_WANPIPE_PPP + fi + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + dep_tristate ' Cyclom 2X(tm) cards (EXPERIMENTAL)' CONFIG_CYCLADES_SYNC $CONFIG_WAN_ROUTER_DRIVERS + if [ "$CONFIG_CYCLADES_SYNC" != "n" ]; then + bool ' Cyclom 2X X.25 support' CONFIG_CYCLOMX_X25 + fi + fi + fi + fi + + +# X.25 network drivers + + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + dep_tristate ' LAPB over Ethernet driver (EXPERIMENTAL)' CONFIG_LAPBETHER $CONFIG_LAPB $CONFIG_X25 + dep_tristate ' X.25 async driver (EXPERIMENTAL)' CONFIG_X25_ASY $CONFIG_LAPB $CONFIG_X25 + fi + + if [ "$CONFIG_X86" = "y" ]; then + tristate ' SBNI12-xx support' CONFIG_SBNI + fi fi endmenu - diff --git a/drivers/net/wan/Makefile b/drivers/net/wan/Makefile index f7f3fe58a..5b13578e7 100644 --- a/drivers/net/wan/Makefile +++ b/drivers/net/wan/Makefile @@ -1,269 +1,86 @@ -# File: drivers/net/wan/Makefile # # Makefile for the Linux network (wan) device drivers. # -# Note! Dependencies are done automagically by 'make dep', which also -# removes any old dependencies. DON'T put your own dependencies here -# unless it's something special (ie not a .c file). -# -# Note 2! The CFLAGS definition is now inherited from the -# parent makefile. +# 3 Aug 2000, Christoph Hellwig <hch@caldera.de> +# Rewritten to use lists instead of if-statements. # SUB_DIRS := MOD_SUB_DIRS := $(SUB_DIRS) ALL_SUB_DIRS := $(SUB_DIRS) lmc -L_TARGET := wan.a -L_OBJS := -M_OBJS := - -# Need these to keep track of whether the 82530 or SYNCPPP -# modules should really go in the kernel or a module. -CONFIG_85230_BUILTIN := -CONFIG_85230_MODULE := -CONFIG_SYNCPPP_BUILTIN := -CONFIG_SYNCPPP_MODULE := - -ifeq ($(CONFIG_HOSTESS_SV11),y) -L_OBJS += hostess_sv11.o -CONFIG_85230_BUILTIN = y -CONFIG_SYNCPPP_BUILTIN = y -else - ifeq ($(CONFIG_HOSTESS_SV11),m) - CONFIG_85230_MODULE = y - CONFIG_SYNCPPP_MODULE = y - M_OBJS += hostess_sv11.o - endif -endif - -ifeq ($(CONFIG_SEALEVEL_4021),y) -L_OBJS += sealevel.o -CONFIG_85230_BUILTIN = y -CONFIG_SYNCPPP_BUILTIN = y -else - ifeq ($(CONFIG_SEALEVEL_4021),m) - CONFIG_85230_MODULE = y - CONFIG_SYNCPPP_MODULE = y - M_OBJS += sealevel.o - endif -endif - -ifeq ($(CONFIG_SYNCLINK_SYNCPPP),y) -CONFIG_SYNCPPP_BUILTIN = y -else - ifeq ($(CONFIG_SYNCLINK_SYNCPPP),m) - CONFIG_SYNCPPP_MODULE = y - endif -endif - -ifeq ($(CONFIG_COMX),y) -LX_OBJS += comx.o -else - ifeq ($(CONFIG_COMX),m) - MX_OBJS += comx.o - endif -endif - -ifeq ($(CONFIG_COMX_HW_COMX),y) -L_OBJS += comx-hw-comx.o -else - ifeq ($(CONFIG_COMX_HW_COMX),m) - M_OBJS += comx-hw-comx.o - endif -endif - -ifeq ($(CONFIG_COMX_HW_LOCOMX),y) -L_OBJS += comx-hw-locomx.o -CONFIG_85230_BUILTIN=y -CONFIG_SYNCPPP_BUILTIN = y -else - ifeq ($(CONFIG_COMX_HW_LOCOMX),m) - M_OBJS += comx-hw-locomx.o - CONFIG_85230_MODULE=y - CONFIG_SYNCPPP_MODULE = y - endif -endif +O_TARGET := wan.o -ifeq ($(CONFIG_COMX_HW_MIXCOM),y) -L_OBJS += comx-hw-mixcom.o -else - ifeq ($(CONFIG_COMX_HW_MIXCOM),m) - M_OBJS += comx-hw-mixcom.o - endif -endif +export-objs = z85230.o syncppp.o comx.o sdladrv.o cycx_drv.o +list-multi = wanpipe.o cyclomx.o -ifeq ($(CONFIG_COMX_PROTO_PPP),y) -L_OBJS += comx-proto-ppp.o -CONFIG_SYNCPPP_BUILTIN = y -else - ifeq ($(CONFIG_COMX_PROTO_PPP),m) - M_OBJS += comx-proto-ppp.o - CONFIG_SYNCPPP_MODULE = y - endif -endif +wanpipe-objs = sdlamain.o $(wanpipe-y) +wanpipe-$(CONFIG_WANPIPE_X25) += sdla_x25.o +wanpipe-$(CONFIG_WANPIPE_FR) += sdla_fr.o +wanpipe-$(CONFIG_WANPIPE_CHDLC) += sdla_chdlc.o +wanpipe-$(CONFIG_WANPIPE_PPP) += sdla_ppp.o -ifeq ($(CONFIG_COMX_PROTO_LAPB),y) -L_OBJS += comx-proto-lapb.o -else - ifeq ($(CONFIG_COMX_PROTO_LAPB),m) - M_OBJS += comx-proto-lapb.o - endif -endif +cyclomx-objs = cycx_main.o $(cyclomx-y) +cyclomx-$(CONFIG_CYCLOMX_X25) += cycx_x25.o -ifeq ($(CONFIG_COMX_PROTO_FR),y) -L_OBJS += comx-proto-fr.o -else - ifeq ($(CONFIG_COMX_PROTO_FR),m) - M_OBJS += comx-proto-fr.o - endif -endif -ifeq ($(CONFIG_COSA),y) -L_OBJS += cosa.o -CONFIG_SYNCPPP_BUILTIN = y -else - ifeq ($(CONFIG_COSA),m) - CONFIG_SYNCPPP_MODULE = y - M_OBJS += cosa.o - endif -endif +obj-$(CONFIG_HOSTESS_SV11) += z85230.o syncppp.o hostess_sv11.o +obj-$(CONFIG_SEALEVEL_4021) += z85230.o syncppp.o sealevel.o +obj-$(CONFIG_COMX) += comx.o +obj-$(CONFIG_COMX_HW_COMX) += comx-hw-comx.o +obj-$(CONFIG_COMX_HW_LOCOMX) += z85230.o syncppp.o comx-hw-locomx.o +obj-$(CONFIG_COMX_HW_MIXCOM) += comx-hw-mixcom.o +obj-$(CONFIG_COMX_PROTO_PPP) += syncppp.o comx-proto-ppp.o +obj-$(CONFIG_COMX_PROTO_LAPB) += comx-proto-lapb.o +obj-$(CONFIG_COMX_PROTO_FR) += comx-proto-fr.o +obj-$(CONFIG_COSA) += syncppp.o cosa.o +obj-$(CONFIG_LANMEDIA) += syncppp.o ifeq ($(CONFIG_LANMEDIA),y) SUB_DIRS += lmc MOD_IN_SUB_DIRS += lmc - L_OBJS += lmc/lmc.o - CONFIG_SYNCPPP_BUILTIN = y + obj-y += lmc/lmc.o else ifeq ($(CONFIG_LANMEDIA),m) - CONFIG_SYNCPPP_MODULE = y MOD_IN_SUB_DIRS += lmc endif endif - -# If anything built-in uses syncppp, then build it into the kernel also. -# If not, but a module uses it, build as a module. - -ifdef CONFIG_SYNCPPP_BUILTIN -LX_OBJS += syncppp.o -else - ifdef CONFIG_SYNCPPP_MODULE - MX_OBJS += syncppp.o - endif -endif - -# If anything built-in uses Z85230, then build it into the kernel also. -# If not, but a module uses it, build as a module. - -ifdef CONFIG_85230_BUILTIN -LX_OBJS += z85230.o -else - ifdef CONFIG_85230_MODULE - MX_OBJS += z85230.o - endif -endif - -ifeq ($(CONFIG_DLCI),y) -L_OBJS += dlci.o -else - ifeq ($(CONFIG_DLCI),m) - M_OBJS += dlci.o - endif -endif - -ifeq ($(CONFIG_SDLA),y) - L_OBJS += sdla.o -else - ifeq ($(CONFIG_SDLA),m) - M_OBJS += sdla.o - endif -endif - -ifeq ($(CONFIG_VENDOR_SANGOMA),y) - LX_OBJS += sdladrv.o - L_OBJS += sdlamain.o - ifeq ($(CONFIG_WANPIPE_X25),y) - L_OBJS += sdla_x25.o - endif - ifeq ($(CONFIG_WANPIPE_CHDLC),y) - L_OBJS += sdla_chdlc.o - endif - ifeq ($(CONFIG_WANPIPE_FR),y) - L_OBJS += sdla_fr.o - endif - ifeq ($(CONFIG_WANPIPE_PPP),y) - L_OBJS += sdla_ppp.o - endif -endif - -ifeq ($(CONFIG_VENDOR_SANGOMA),m) - MX_OBJS += sdladrv.o - M_OBJS += wanpipe.o - WANPIPE_OBJS = sdlamain.o - ifeq ($(CONFIG_WANPIPE_X25),y) - WANPIPE_OBJS += sdla_x25.o - endif - ifeq ($(CONFIG_WANPIPE_FR),y) - WANPIPE_OBJS += sdla_fr.o - endif - ifeq ($(CONFIG_WANPIPE_CHDLC),y) - WANPIPE_OBJS += sdla_chdlc.o - endif - ifeq ($(CONFIG_WANPIPE_PPP),y) - WANPIPE_OBJS += sdla_ppp.o - endif -endif - -ifeq ($(CONFIG_CYCLADES_SYNC),y) - LX_OBJS += cycx_drv.o - L_OBJS += cycx_main.o - ifeq ($(CONFIG_CYCLOMX_X25),y) - L_OBJS += cycx_x25.o - endif -endif - -ifeq ($(CONFIG_CYCLADES_SYNC),m) - MX_OBJS += cycx_drv.o - M_OBJS += cyclomx.o - CYCLOMX_OBJS = cycx_main.o - ifeq ($(CONFIG_CYCLOMX_X25),y) - CYCLOMX_OBJS += cycx_x25.o - endif -endif - -ifeq ($(CONFIG_X25_ASY),y) -L_OBJS += x25_asy.o -else - ifeq ($(CONFIG_X25_ASY),m) - M_OBJS += x25_asy.o - endif -endif - -ifeq ($(CONFIG_LAPBETHER),y) -L_OBJS += lapbether.o -else - ifeq ($(CONFIG_LAPBETHER),m) - M_OBJS += lapbether.o - endif -endif - -ifeq ($(CONFIG_SBNI),y) -L_OBJS += sbni.o -else - ifeq ($(CONFIG_SBNI),m) - M_OBJS += sbni.o - endif -endif +obj-$(CONFIG_DLCI) += dlci.o +obj-$(CONFIG_SDLA) += sdla.o +obj-$(CONFIG_VENDOR_SANGOMA) += sdladrv.o wanpipe.o +obj-$(CONFIG_CYCLADES_SYNC) += cycx_drv.o cyclomx.o +obj-$(CONFIG_LAPBETHER) += lapbether.o +obj-$(CONFIG_SBNI) += sbni.o + + +# Extract lists of the multi-part drivers. +# The 'int-*' lists are the intermediate files used to build the multi's. +multi-y := $(filter $(list-multi), $(obj-y)) +multi-m := $(filter $(list-multi), $(obj-m)) +int-y := $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs))) +int-m := $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs))) + +# Files that are both resident and modular: remove from modular. +obj-m := $(filter-out $(obj-y), $(obj-m)) +int-m := $(filter-out $(int-y), $(int-m)) + +# Take multi-part drivers out of obj-y and put components in. +obj-y := $(filter-out $(list-multi), $(obj-y)) $(int-y) + +# Translate to Rules.make lists. +O_OBJS := $(filter-out $(export-objs), $(obj-y)) +OX_OBJS := $(filter $(export-objs), $(obj-y)) +M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) +MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) +MI_OBJS := $(sort $(filter-out $(export-objs), $(int-m))) +MIX_OBJS := $(sort $(filter $(export-objs), $(int-m))) include $(TOPDIR)/Rules.make -clean: - rm -f core *.o *.a *.s - -wanpipe.o: $(WANPIPE_OBJS) - $(LD) -r -o $@ $(WANPIPE_OBJS) +wanpipe.o: $(wanpipe-objs) + $(LD) -r -o $@ $(wanpipe-objs) -cyclomx.o: $(CYCLOMX_OBJS) - $(LD) -r -o $@ $(CYCLOMX_OBJS) +cyclomx.o: $(cyclomx-objs) + $(LD) -r -o $@ $(cyclomx-objs) diff --git a/drivers/net/wan/cycx_main.c b/drivers/net/wan/cycx_main.c index 207c9e21c..0426143af 100644 --- a/drivers/net/wan/cycx_main.c +++ b/drivers/net/wan/cycx_main.c @@ -101,7 +101,7 @@ static cycx_t *card_array = NULL; /* adapter data space */ * < 0 error. * Context: process */ -static int __init cyclomx_init (void) +int __init cyclomx_init (void) { int cnt, err = 0; diff --git a/drivers/net/wan/hostess_sv11.c b/drivers/net/wan/hostess_sv11.c index 09d6c9556..4c7bf4bf4 100644 --- a/drivers/net/wan/hostess_sv11.c +++ b/drivers/net/wan/hostess_sv11.c @@ -305,6 +305,7 @@ static struct sv11_device *sv11_init(int iobase, int irq) if(z8530_init(dev)!=0) { printk(KERN_ERR "Z8530 series device not found.\n"); + restore_flags(flags); goto dmafail2; } z8530_channel_load(&dev->chanB, z8530_dead_port); diff --git a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c index 37ef27487..b4073b00f 100644 --- a/drivers/net/wan/sbni.c +++ b/drivers/net/wan/sbni.c @@ -448,6 +448,7 @@ static int __init sbni_probe1(struct net_device *dev, int ioaddr) if(dev->priv == NULL) { DP( printk("%s: cannot allocate memory\n", dev->name); ) + free_irq(dev->irq, dev); return -ENOMEM; } diff --git a/drivers/net/wan/sealevel.c b/drivers/net/wan/sealevel.c index f1a895e36..2128a386e 100644 --- a/drivers/net/wan/sealevel.c +++ b/drivers/net/wan/sealevel.c @@ -323,6 +323,7 @@ static struct slvl_board *slvl_init(int iobase, int irq, int txdma, int rxdma, i if(z8530_init(dev)!=0) { printk(KERN_ERR "Z8530 series device not found.\n"); + restore_flags(flags); goto dmafail2; } if(dev->type==Z85C30) diff --git a/drivers/net/wan/syncppp.c b/drivers/net/wan/syncppp.c index 096d8164a..8a62cc8ed 100644 --- a/drivers/net/wan/syncppp.c +++ b/drivers/net/wan/syncppp.c @@ -866,7 +866,7 @@ EXPORT_SYMBOL(sppp_close); * * Close down any existing synchronous session and commence * from scratch. In the PPP case this means negotiating LCP/IPCP - * and friends, while for Cisco HDLC we simply need to staet sending + * and friends, while for Cisco HDLC we simply need to start sending * keepalives */ |