patch-2.3.43 linux/drivers/net/3c509.c
Next file: linux/drivers/net/3c523.c
Previous file: linux/drivers/net/3c507.c
Back to the patch index
Back to the overall index
- Lines: 329
- Date:
Thu Feb 10 12:31:07 2000
- Orig file:
v2.3.42/linux/drivers/net/3c509.c
- Orig date:
Fri Jan 21 18:19:16 2000
diff -u --recursive --new-file v2.3.42/linux/drivers/net/3c509.c linux/drivers/net/3c509.c
@@ -53,6 +53,7 @@
#include <linux/module.h>
#include <linux/mca.h>
+#include <linux/isapnp.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/interrupt.h>
@@ -149,6 +150,7 @@
static int el3_rx(struct net_device *dev);
static int el3_close(struct net_device *dev);
static void set_multicast_list(struct net_device *dev);
+static void el3_tx_timeout (struct net_device *dev);
#ifdef CONFIG_MCA
struct el3_mca_adapters_struct {
@@ -166,12 +168,34 @@
};
#endif
+#ifdef CONFIG_ISAPNP
+struct el3_isapnp_adapters_struct {
+ unsigned short vendor, function;
+ char *name;
+};
+struct el3_isapnp_adapters_struct el3_isapnp_adapters[] = {
+ {ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5090), "3Com Etherlink III (TP)"},
+ {ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5091), "3Com Etherlink III"},
+ {ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5094), "3Com Etherlink III (combo)"},
+ {ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5095), "3Com Etherlink III (TPO)"},
+ {ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5098), "3Com Etherlink III (TPC)"},
+ {ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_FUNCTION(0x80f8), "3Com Etherlink III compatible"},
+ {0, }
+};
+u16 el3_isapnp_phys_addr[8][3] = {
+ {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
+ {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}
+};
+#endif
+static int nopnp = 0;
+
int el3_probe(struct net_device *dev)
{
short lrs_state = 0xff, i;
int ioaddr, irq, if_port;
u16 phys_addr[3];
static int current_tag = 0;
+ static int pnp_cards = 0;
int mca_slot = -1;
/* First check all slots of the EISA bus. The next slot address to
@@ -265,9 +289,43 @@
return -ENODEV;
}
#endif
- /* Reset the ISA PnP mechanism on 3c509b. */
- outb(0x02, 0x279); /* Select PnP config control register. */
- outb(0x02, 0xA79); /* Return to WaitForKey state. */
+
+#ifdef CONFIG_ISAPNP
+ if (nopnp == 1)
+ goto no_pnp;
+
+ for (i=0; el3_isapnp_adapters[i].vendor != 0; i++) {
+ struct pci_dev *idev = NULL;
+ int j;
+ while ((idev = isapnp_find_dev(NULL,
+ el3_isapnp_adapters[i].vendor,
+ el3_isapnp_adapters[i].function,
+ idev))) {
+ idev->prepare(idev);
+ /* Deactivation is needed if the driver was called
+ with "nopnp=1" before, does not harm if not. */
+ idev->deactivate(idev);
+ idev->activate(idev);
+ if (!idev->resource[0].start || check_region(idev->resource[0].start,16))
+ continue;
+ ioaddr = idev->resource[0].start;
+ irq = idev->irq_resource[0].start;
+ if (el3_debug > 3)
+ printk ("ISAPnP reports %s at i/o 0x%x, irq %d\n",
+ el3_isapnp_adapters[i].name, ioaddr, irq);
+ EL3WINDOW(0);
+ for (j = 0; j < 3; j++)
+ el3_isapnp_phys_addr[pnp_cards][j] =
+ phys_addr[j] =
+ htons(read_eeprom(ioaddr, j));
+ if_port = read_eeprom(ioaddr, 8) >> 14;
+ pnp_cards++;
+ goto found;
+ }
+ }
+no_pnp:
+#endif
+
/* Select an open I/O location at 0x1*0 to do contention select. */
for ( ; id_port < 0x200; id_port += 0x10) {
if (check_region(id_port, 1))
@@ -312,6 +370,28 @@
phys_addr[i] = htons(id_read_eeprom(i));
}
+#ifdef CONFIG_ISAPNP
+ if (nopnp == 0) {
+ /* The ISA PnP 3c509 cards respond to the ID sequence.
+ This check is needed in order not to register them twice. */
+ for (i = 0; i < pnp_cards; i++) {
+ if (phys_addr[0] == el3_isapnp_phys_addr[i][0] &&
+ phys_addr[1] == el3_isapnp_phys_addr[i][1] &&
+ phys_addr[2] == el3_isapnp_phys_addr[i][2])
+ {
+ if (el3_debug > 3)
+ printk("3c509 with address %02x %02x %02x %02x %02x %02x was found by ISAPnP\n",
+ phys_addr[0] & 0xff, phys_addr[0] >> 8,
+ phys_addr[1] & 0xff, phys_addr[1] >> 8,
+ phys_addr[2] & 0xff, phys_addr[2] >> 8);
+ /* Set the adaptor tag so that the next card can be found. */
+ outb(0xd0 + ++current_tag, id_port);
+ goto no_pnp;
+ }
+ }
+ }
+#endif
+
{
unsigned int iobase = id_read_eeprom(8);
if_port = iobase >> 14;
@@ -357,8 +437,8 @@
{
const char *if_names[] = {"10baseT", "AUI", "undefined", "BNC"};
- printk("%s: 3c509 at %#3.3lx tag %d, %s port, address ",
- dev->name, dev->base_addr, current_tag, if_names[dev->if_port]);
+ printk("%s: 3c509 at %#3.3lx, %s port, address ",
+ dev->name, dev->base_addr, if_names[dev->if_port]);
}
/* Read in the station address. */
@@ -387,6 +467,8 @@
dev->stop = &el3_close;
dev->get_stats = &el3_get_stats;
dev->set_multicast_list = &set_multicast_list;
+ dev->tx_timeout = el3_tx_timeout;
+ dev->watchdog_timeo = TX_TIMEOUT;
/* Fill in the generic fields of the device structure. */
ether_setup(dev);
@@ -481,9 +563,7 @@
outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD);
outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */
- dev->interrupt = 0;
- dev->tbusy = 0;
- dev->start = 1;
+ netif_start_queue(dev);
outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */
outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */
@@ -503,28 +583,32 @@
return 0; /* Always succeed */
}
-static int
-el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static void
+el3_tx_timeout (struct net_device *dev)
{
struct el3_private *lp = (struct el3_private *)dev->priv;
int ioaddr = dev->base_addr;
/* Transmitter timeout, serious problems. */
- if (dev->tbusy) {
- int tickssofar = jiffies - dev->trans_start;
- if (tickssofar < TX_TIMEOUT)
- return 1;
- printk("%s: transmit timed out, Tx_status %2.2x status %4.4x "
- "Tx FIFO room %d.\n",
- dev->name, inb(ioaddr + TX_STATUS), inw(ioaddr + EL3_STATUS),
- inw(ioaddr + TX_FREE));
- lp->stats.tx_errors++;
- dev->trans_start = jiffies;
- /* Issue TX_RESET and TX_START commands. */
- outw(TxReset, ioaddr + EL3_CMD);
- outw(TxEnable, ioaddr + EL3_CMD);
- dev->tbusy = 0;
- }
+ printk("%s: transmit timed out, Tx_status %2.2x status %4.4x "
+ "Tx FIFO room %d.\n",
+ dev->name, inb(ioaddr + TX_STATUS), inw(ioaddr + EL3_STATUS),
+ inw(ioaddr + TX_FREE));
+ lp->stats.tx_errors++;
+ dev->trans_start = jiffies;
+ /* Issue TX_RESET and TX_START commands. */
+ outw(TxReset, ioaddr + EL3_CMD);
+ outw(TxEnable, ioaddr + EL3_CMD);
+ netif_start_queue(dev);
+}
+
+
+static int
+el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct el3_private *lp = (struct el3_private *)dev->priv;
+ int ioaddr = dev->base_addr;
+ unsigned long flags;
lp->stats.tx_bytes += skb->len;
@@ -551,47 +635,37 @@
}
#endif
#endif
- /* Avoid timer-based retransmission conflicts. */
- if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
- printk("%s: Transmitter access conflict.\n", dev->name);
- else {
- /*
- * We lock the driver against other processors. Note
- * we don't need to lock versus the IRQ as we suspended
- * that. This means that we lose the ability to take
- * an RX during a TX upload. That sucks a bit with SMP
- * on an original 3c509 (2K buffer)
- *
- * Using disable_irq stops us crapping on other
- * time sensitive devices.
- */
-
-#ifdef __SMP__
- disable_irq_nosync(dev->irq);
- spin_lock(&lp->lock);
-#endif
+ /*
+ * We lock the driver against other processors. Note
+ * we don't need to lock versus the IRQ as we suspended
+ * that. This means that we lose the ability to take
+ * an RX during a TX upload. That sucks a bit with SMP
+ * on an original 3c509 (2K buffer)
+ *
+ * Using disable_irq stops us crapping on other
+ * time sensitive devices.
+ */
+
+ spin_lock_irqsave(&lp->lock, flags);
- /* Put out the doubleword header... */
- outw(skb->len, ioaddr + TX_FIFO);
- outw(0x00, ioaddr + TX_FIFO);
- /* ... and the packet rounded to a doubleword. */
+ /* Put out the doubleword header... */
+ outw(skb->len, ioaddr + TX_FIFO);
+ outw(0x00, ioaddr + TX_FIFO);
+ /* ... and the packet rounded to a doubleword. */
#ifdef __powerpc__
- outsl_unswapped(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
+ outsl_unswapped(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
#else
- outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
+ outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
#endif
- dev->trans_start = jiffies;
- if (inw(ioaddr + TX_FREE) > 1536) {
- dev->tbusy = 0;
- } else
- /* Interrupt us when the FIFO has room for max-sized packet. */
- outw(SetTxThreshold + 1536, ioaddr + EL3_CMD);
-#ifdef __SMP__
- spin_unlock(&lp->lock);
- enable_irq(dev->irq);
-#endif
- }
+ dev->trans_start = jiffies;
+ if (inw(ioaddr + TX_FREE) > 1536)
+ netif_start_queue(dev);
+ else
+ /* Interrupt us when the FIFO has room for max-sized packet. */
+ outw(SetTxThreshold + 1536, ioaddr + EL3_CMD);
+
+ spin_unlock_irqrestore(&lp->lock, flags);
dev_kfree_skb (skb);
@@ -627,10 +701,6 @@
lp = (struct el3_private *)dev->priv;
spin_lock(&lp->lock);
- if (dev->interrupt)
- printk("%s: Re-entering the interrupt handler.\n", dev->name);
- dev->interrupt = 1;
-
ioaddr = dev->base_addr;
if (el3_debug > 4) {
@@ -649,8 +719,7 @@
printk(" TX room bit was handled.\n");
/* There's room in the FIFO for a full-sized packet. */
outw(AckIntr | TxAvailable, ioaddr + EL3_CMD);
- dev->tbusy = 0;
- mark_bh(NET_BH);
+ netif_wake_queue (dev);
}
if (status & (AdapterFailure | RxEarly | StatsFull | TxComplete)) {
/* Handle all uncommon interrupts. */
@@ -701,7 +770,6 @@
inw(ioaddr + EL3_STATUS));
}
spin_unlock(&lp->lock);
- dev->interrupt = 0;
return;
}
@@ -862,8 +930,7 @@
if (el3_debug > 2)
printk("%s: Shutting down ethercard.\n", dev->name);
- dev->tbusy = 1;
- dev->start = 0;
+ netif_stop_queue(dev);
/* Turn off statistics ASAP. We update lp->stats below. */
outw(StatsDisable, ioaddr + EL3_CMD);
@@ -902,6 +969,7 @@
MODULE_PARM(irq,"1-8i");
MODULE_PARM(xcvr,"1-8i");
MODULE_PARM(max_interrupt_work, "i");
+MODULE_PARM(nopnp, "i");
int
init_module(void)
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)