Re: epic100 freezes 2.4.0-test1

From: Jeff Garzik (jgarzik@mandrakesoft.com)
Date: Thu Jun 01 2000 - 16:04:19 EST


Robert Cawley wrote:
>
> Cannot boot any 2.4.0-test1 kernels with epic network driver enabled.

My epic100 card should arrive today or tomorrow, hopefully I can debug
it then.

Since noone is maintaining it, it was updated to [almost] match Donald's
latest version on his Web site. Attached is the work so far I have on
the fix, mainly merging a new 'test' version posted by Donald, but at
least one person has said this doesn't work. (so beware, the patch is
really for any potentially interested kernel hackers)

I am very very interested in feedback from anyone and everyone on the
following:

1) Does a virgin copy of Donald's epic100.c from
ftp://ftp.scyld.com/network/ work for you, under a 2.2.x kernel? (note
you must also download k*.h and pci-scan*.[ch])

2) Does a virgin copy of Donald's test version of epic100.c from
ftp://ftp.scyld.com/network/test/ work for you, under the same
conditions/requirements as #1?

Regards,

        Jeff

-- 
Jeff Garzik              | Liberty is always dangerous, but
Building 1024            | it is the safest thing we have.
MandrakeSoft, Inc.       |      -- Harry Emerson Fosdick

Index: drivers/net/epic100.c =================================================================== RCS file: /g/cvslan/linux_2_3/drivers/net/epic100.c,v retrieving revision 1.1.1.20 retrieving revision 1.1.1.20.32.1 diff -u -r1.1.1.20 -r1.1.1.20.32.1 --- drivers/net/epic100.c 2000/05/13 16:15:13 1.1.1.20 +++ drivers/net/epic100.c 2000/05/31 14:10:10 1.1.1.20.32.1 @@ -24,6 +24,10 @@ LK1.1.2 (jgarzik): * Merge becker version 1.09 + + LK1.1.3 (jgarzik): + * Merge becker test version 05/29/2000 (also called 1.09) + * Fix oops on module unload */ @@ -41,11 +45,12 @@ /* 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. */ @@ -64,13 +69,25 @@ #define TX_FIFO_THRESH 256 #define RX_FIFO_THRESH 1 /* 0-3, 0==32, 64,96, or 3==128 bytes */ +#ifndef __KERNEL__ +#define __KERNEL__ +#endif #if !defined(__OPTIMIZE__) #warning You must compile this file with the correct options! #warning See the last lines of the source file. #error You must compile this driver with "-O". #endif +#include <linux/config.h> #include <linux/module.h> +#if defined(CONFIG_SMP) && ! defined(__SMP__) +#define __SMP__ +#endif +#if defined(CONFIG_MODVERSIONS) && ! defined(MODVERSIONS) +#define MODVERSIONS +#endif + +#include <linux/version.h> #include <linux/kernel.h> #include <linux/string.h> #include <linux/timer.h> @@ -90,7 +107,7 @@ /* These identify the driver base version and may not be removed. */ static char version[] __devinitdata = -"epic100.c:v1.09+LK1.1.2 4/28/2000 Written by Donald Becker <becker@scyld.com>\n"; +"epic100.c:v1.09+LK1.1.3 5/29/2000 Written by Donald Becker <becker@scyld.com>\n"; static char version2[] __devinitdata = " http://www.scyld.com/network/epic100.html\n"; @@ -130,7 +147,7 @@ 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 @@ -160,8 +177,9 @@ #define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr)) typedef enum { - SMSC_83C170_0, - SMSC_83C170, + SMSC_83C172, + SMSC_83C170_1, + SMSC_83C170_2, SMSC_83C175, } chip_t; @@ -176,6 +194,8 @@ /* indexed by chip_t */ static struct epic_chip_info epic_chip_info[] __devinitdata = { + { "SMSC EPIC 83c172", + EPIC_IOTYPE, EPIC_TOTAL_SIZE, TYPE2_INTR | MII_PWRDWN }, { "SMSC EPIC/100 83c170", EPIC_IOTYPE, EPIC_TOTAL_SIZE, TYPE2_INTR | NO_MII | MII_PWRDWN }, { "SMSC EPIC/100 83c170", @@ -186,8 +206,8 @@ static struct pci_device_id epic_pci_tbl[] __devinitdata = { - { 0x10B8, 0x0005, 0x1092, 0x0AB4, 0, 0, SMSC_83C170_0 }, - { 0x10B8, 0x0005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SMSC_83C170 }, + { 0x10B8, 0x0005, 0x1092, 0x0AB4, 0, 0, SMSC_83C170_1 }, + { 0x10B8, 0x0005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SMSC_83C170_2 }, { 0x10B8, 0x0006, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SMSC_83C175 }, { 0,} }; @@ -279,13 +299,14 @@ long last_rx_time; /* Last Rx, in jiffies. */ struct pci_dev *pci_dev; /* PCI bus location. */ - int chip_flags; + int chip_id, chip_flags; struct net_device_stats stats; struct timer_list timer; /* Media selection timer. */ 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. */ @@ -389,6 +410,8 @@ printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", dev->name, ci->name, ioaddr, dev->irq); + pdev->driver_data = dev; + /* Bring the chip out of low-power mode. */ outl(0x4200, ioaddr + GENCTL); /* Magic?! If we don't set this bit the MII interface won't work. */ @@ -421,25 +444,26 @@ /* 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. */ @@ -662,7 +686,7 @@ 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 @@ -746,8 +770,8 @@ 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; } @@ -758,18 +782,19 @@ 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" @@ -791,7 +816,7 @@ 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); @@ -865,20 +890,20 @@ /* Caution: the write order is important here, set the field with the "ownership" bit last. */ - spin_lock_irq(&ep->lock); /* Calculate the next Tx descriptor entry. */ + spin_lock_irq(&ep->lock); free_count = ep->cur_tx - ep->dirty_tx; entry = ep->cur_tx % TX_RING_SIZE; ep->tx_skbuff[entry] = skb; ep->tx_ring[entry].bufaddr = virt_to_le32desc(skb->data); - 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. */ @@ -904,7 +929,7 @@ 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; } @@ -918,17 +943,15 @@ long ioaddr = dev->base_addr; int status, boguscnt = max_interrupt_work; - spin_lock(&ep->lock); - do { status = inl(ioaddr + INTSTAT); /* Acknowledge all of the current interrupt sources ASAP. */ 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; @@ -942,6 +965,7 @@ /* Note: if this lock becomes a problem we can narrow the locked region at the cost of occasionally grabbing the lock more times. */ + spin_lock(&ep->lock); cur_tx = ep->cur_tx; dirty_tx = ep->dirty_tx; for (; cur_tx - dirty_tx > 0; dirty_tx++) { @@ -989,11 +1013,13 @@ #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; + spin_unlock(&ep->lock); netif_wake_queue(dev); - } + } else + spin_unlock(&ep->lock); } /* Check uncommon events all at once. */ @@ -1038,9 +1064,7 @@ if (debug > 3) printk(KERN_DEBUG "%s: exiting interrupt, intr_status=%#4.4x.\n", - dev->name, inl(ioaddr + INTSTAT)); - - spin_unlock(&ep->lock); + dev->name, status); } static int epic_rx(struct net_device *dev) @@ -1138,7 +1162,7 @@ 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)); epic_pause(dev); del_timer(&ep->timer);

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Wed Jun 07 2000 - 21:00:13 EST