summaryrefslogtreecommitdiffstats
path: root/drivers/net/depca.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-02-24 00:12:35 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-02-24 00:12:35 +0000
commit482368b1a8e45430672c58c9a42e7d2004367126 (patch)
treece2a1a567d4d62dee7c2e71a46a99cf72cf1d606 /drivers/net/depca.c
parente4d0251c6f56ab2e191afb70f80f382793e23f74 (diff)
Merge with 2.3.47. Guys, this is buggy as shit. You've been warned.
Diffstat (limited to 'drivers/net/depca.c')
-rw-r--r--drivers/net/depca.c200
1 files changed, 94 insertions, 106 deletions
diff --git a/drivers/net/depca.c b/drivers/net/depca.c
index bfcc78744..06d9e6171 100644
--- a/drivers/net/depca.c
+++ b/drivers/net/depca.c
@@ -270,6 +270,8 @@ static int depca_debug = 1;
#define DEPCA_NDA 0xffe0 /* No Device Address */
+#define TX_TIMEOUT (1*HZ)
+
/*
** Ethernet PROM defines
*/
@@ -387,6 +389,7 @@ struct depca_private {
int rx_new, tx_new; /* The next free ring entry */
int rx_old, tx_old; /* The ring entries to be free()ed. */
struct net_device_stats stats;
+ spinlock_t lock;
struct { /* Private stats counters */
u32 bins[DEPCA_PKT_STAT_SZ];
u32 unicast;
@@ -421,6 +424,7 @@ static int depca_start_xmit(struct sk_buff *skb, struct net_device *dev);
static void depca_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static int depca_close(struct net_device *dev);
static int depca_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static void depca_tx_timeout (struct net_device *dev);
static struct net_device_stats *depca_get_stats(struct net_device *dev);
static void set_multicast_list(struct net_device *dev);
@@ -584,6 +588,7 @@ depca_hw_init(struct net_device *dev, u_long ioaddr, int mca_slot)
memset((char *)dev->priv, 0, sizeof(struct depca_private));
lp->adapter = adapter;
lp->mca_slot = mca_slot;
+ lp->lock = SPIN_LOCK_UNLOCKED;
sprintf(lp->adapter_name,"%s (%s)", name, dev->name);
request_region(ioaddr, DEPCA_TOTAL_SIZE, lp->adapter_name);
@@ -703,6 +708,8 @@ depca_hw_init(struct net_device *dev, u_long ioaddr, int mca_slot)
dev->get_stats = &depca_get_stats;
dev->set_multicast_list = &set_multicast_list;
dev->do_ioctl = &depca_ioctl;
+ dev->tx_timeout = depca_tx_timeout;
+ dev->watchdog_timeo = TX_TIMEOUT;
dev->mem_start = 0;
@@ -755,9 +762,7 @@ depca_open(struct net_device *dev)
outb(nicsr, DEPCA_NICSR);
outw(CSR0,DEPCA_ADDR);
- dev->tbusy = 0;
- dev->interrupt = 0;
- dev->start = 1;
+ netif_start_queue(dev);
status = InitRestartDepca(dev);
@@ -781,7 +786,7 @@ depca_init_ring(struct net_device *dev)
u_long p;
/* Lock out other processes whilst setting up the hardware */
- test_and_set_bit(0, (void *)&dev->tbusy);
+ netif_stop_queue(dev);
lp->rx_new = lp->tx_new = 0;
lp->rx_old = lp->tx_old = 0;
@@ -809,122 +814,110 @@ depca_init_ring(struct net_device *dev)
}
lp->init_block.mode = 0x0000; /* Enable the Tx and Rx */
+}
- return;
+
+static void depca_tx_timeout (struct net_device *dev)
+{
+ u_long ioaddr = dev->base_addr;
+
+ printk ("%s: transmit timed out, status %04x, resetting.\n",
+ dev->name, inw (DEPCA_DATA));
+
+ STOP_DEPCA;
+ depca_init_ring (dev);
+ LoadCSRs (dev);
+ dev->trans_start = jiffies;
+ netif_wake_queue (dev);
+ InitRestartDepca (dev);
}
+
/*
** Writes a socket buffer to TX descriptor ring and starts transmission
*/
-static int
-depca_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static int depca_start_xmit (struct sk_buff *skb, struct net_device *dev)
{
- struct depca_private *lp = (struct depca_private *)dev->priv;
- u_long ioaddr = dev->base_addr;
- int status = 0;
+ struct depca_private *lp = (struct depca_private *) dev->priv;
+ u_long ioaddr = dev->base_addr;
+ int status = 0;
- /* Transmitter timeout, serious problems. */
- if (dev->tbusy) {
- int tickssofar = jiffies - dev->trans_start;
- if (tickssofar < 1*HZ) {
- status = -1;
- } else {
- printk("%s: transmit timed out, status %04x, resetting.\n",
- dev->name, inw(DEPCA_DATA));
-
- STOP_DEPCA;
- depca_init_ring(dev);
- LoadCSRs(dev);
- dev->interrupt = UNMASK_INTERRUPTS;
- dev->start = 1;
- dev->tbusy=0;
- dev->trans_start = jiffies;
- InitRestartDepca(dev);
- }
- return status;
- } else if (skb->len > 0) {
- /* Enforce 1 process per h/w access */
- if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
- printk("%s: Transmitter access conflict.\n", dev->name);
- status = -1;
- } else {
- if (TX_BUFFS_AVAIL) { /* Fill in a Tx ring entry */
- status = load_packet(dev, skb);
+ /* Transmitter timeout, serious problems. */
+ if (skb->len < 1)
+ goto out;
- if (!status) {
- /* Trigger an immediate send demand. */
- outw(CSR0, DEPCA_ADDR);
- outw(INEA | TDMD, DEPCA_DATA);
-
- dev->trans_start = jiffies;
- dev_kfree_skb(skb);
- }
- if (TX_BUFFS_AVAIL) {
- dev->tbusy=0;
- }
- } else {
- status = -1;
- }
- }
- }
-
- return status;
+ netif_stop_queue (dev);
+
+ if (TX_BUFFS_AVAIL) { /* Fill in a Tx ring entry */
+ status = load_packet (dev, skb);
+
+ if (!status) {
+ /* Trigger an immediate send demand. */
+ outw (CSR0, DEPCA_ADDR);
+ outw (INEA | TDMD, DEPCA_DATA);
+
+ dev->trans_start = jiffies;
+ dev_kfree_skb (skb);
+ }
+ if (TX_BUFFS_AVAIL)
+ netif_start_queue (dev);
+ } else
+ status = -1;
+
+out:
+ return status;
}
/*
** The DEPCA interrupt handler.
*/
-static void
-depca_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static void depca_interrupt (int irq, void *dev_id, struct pt_regs *regs)
{
- struct net_device *dev = dev_id;
- struct depca_private *lp;
- s16 csr0, nicsr;
- u_long ioaddr;
+ struct net_device *dev = dev_id;
+ struct depca_private *lp;
+ s16 csr0, nicsr;
+ u_long ioaddr;
- if (dev == NULL) {
- printk ("depca_interrupt(): irq %d for unknown device.\n", irq);
- } else {
- lp = (struct depca_private *)dev->priv;
- ioaddr = dev->base_addr;
-
- if (dev->interrupt)
- printk("%s: Re-entering the interrupt handler.\n", dev->name);
+ if (dev == NULL) {
+ printk ("depca_interrupt(): irq %d for unknown device.\n", irq);
+ return;
+ }
- dev->interrupt = MASK_INTERRUPTS;
+ lp = (struct depca_private *) dev->priv;
+ ioaddr = dev->base_addr;
- /* mask the DEPCA board interrupts and turn on the LED */
- nicsr = inb(DEPCA_NICSR);
- nicsr |= (IM|LED);
- outb(nicsr, DEPCA_NICSR);
+ spin_lock (&lp->lock);
- outw(CSR0, DEPCA_ADDR);
- csr0 = inw(DEPCA_DATA);
+ /* mask the DEPCA board interrupts and turn on the LED */
+ nicsr = inb (DEPCA_NICSR);
+ nicsr |= (IM | LED);
+ outb (nicsr, DEPCA_NICSR);
- /* Acknowledge all of the current interrupt sources ASAP. */
- outw(csr0 & INTE, DEPCA_DATA);
+ outw (CSR0, DEPCA_ADDR);
+ csr0 = inw (DEPCA_DATA);
- if (csr0 & RINT) /* Rx interrupt (packet arrived) */
- depca_rx(dev);
+ /* Acknowledge all of the current interrupt sources ASAP. */
+ outw (csr0 & INTE, DEPCA_DATA);
- if (csr0 & TINT) /* Tx interrupt (packet sent) */
- depca_tx(dev);
+ if (csr0 & RINT) /* Rx interrupt (packet arrived) */
+ depca_rx (dev);
- if ((TX_BUFFS_AVAIL >= 0) && dev->tbusy) { /* any resources available? */
- dev->tbusy = 0; /* clear TX busy flag */
- mark_bh(NET_BH);
- }
+ if (csr0 & TINT) /* Tx interrupt (packet sent) */
+ depca_tx (dev);
- /* Unmask the DEPCA board interrupts and turn off the LED */
- nicsr = (nicsr & ~IM & ~LED);
- outb(nicsr, DEPCA_NICSR);
+ /* Any resources available? */
+ if ((TX_BUFFS_AVAIL >= 0) && netif_queue_stopped(dev)) {
+ netif_wake_queue (dev);
- dev->interrupt = UNMASK_INTERRUPTS;
- }
+ /* Unmask the DEPCA board interrupts and turn off the LED */
+ nicsr = (nicsr & ~IM & ~LED);
+ outb (nicsr, DEPCA_NICSR);
+ }
- return;
+ spin_unlock (&lp->lock);
}
+
static int
depca_rx(struct net_device *dev)
{
@@ -1070,8 +1063,7 @@ depca_close(struct net_device *dev)
s16 nicsr;
u_long ioaddr = dev->base_addr;
- dev->start = 0;
- dev->tbusy = 1;
+ netif_stop_queue(dev);
outw(CSR0, DEPCA_ADDR);
@@ -1173,8 +1165,7 @@ set_multicast_list(struct net_device *dev)
u_long ioaddr = dev->base_addr;
if (dev) {
- while(dev->tbusy) barrier(); /* Stop ring access */
- set_bit(0, (void*)&dev->tbusy);
+ netif_stop_queue(dev);
while(lp->tx_old != lp->tx_new); /* Wait for the ring to empty */
STOP_DEPCA; /* Temporarily stop the depca. */
@@ -1189,7 +1180,7 @@ set_multicast_list(struct net_device *dev)
LoadCSRs(dev); /* Reload CSR3 */
InitRestartDepca(dev); /* Resume normal operation. */
- dev->tbusy = 0; /* Unlock the TX ring */
+ netif_start_queue(dev); /* Unlock the TX ring */
}
}
@@ -1909,21 +1900,19 @@ static int depca_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
for (i=0; i<ETH_ALEN; i++) {
dev->dev_addr[i] = tmp.addr[i];
}
- while(dev->tbusy) barrier(); /* Stop ring access */
- test_and_set_bit(0, (void*)&dev->tbusy);
+ netif_stop_queue(dev);
while(lp->tx_old != lp->tx_new); /* Wait for the ring to empty */
STOP_DEPCA; /* Temporarily stop the depca. */
depca_init_ring(dev); /* Initialize the descriptor rings */
LoadCSRs(dev); /* Reload CSR3 */
InitRestartDepca(dev); /* Resume normal operation. */
- dev->tbusy = 0; /* Unlock the TX ring */
+ netif_start_queue(dev); /* Unlock the TX ring */
break;
case DEPCA_SET_PROM: /* Set Promiscuous Mode */
if (!capable(CAP_NET_ADMIN)) return -EPERM;
- while(dev->tbusy) barrier(); /* Stop ring access */
- test_and_set_bit(0, (void*)&dev->tbusy);
+ netif_stop_queue(dev);
while(lp->tx_old != lp->tx_new); /* Wait for the ring to empty */
STOP_DEPCA; /* Temporarily stop the depca. */
@@ -1932,13 +1921,12 @@ static int depca_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
LoadCSRs(dev); /* Reload CSR3 */
InitRestartDepca(dev); /* Resume normal operation. */
- dev->tbusy = 0; /* Unlock the TX ring */
+ netif_start_queue(dev); /* Unlock the TX ring */
break;
case DEPCA_CLR_PROM: /* Clear Promiscuous Mode */
if (!capable(CAP_NET_ADMIN)) return -EPERM;
- while(dev->tbusy) barrier(); /* Stop ring access */
- test_and_set_bit(0, (void*)&dev->tbusy);
+ netif_stop_queue(dev);
while(lp->tx_old != lp->tx_new); /* Wait for the ring to empty */
STOP_DEPCA; /* Temporarily stop the depca. */
@@ -1947,7 +1935,7 @@ static int depca_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
LoadCSRs(dev); /* Reload CSR3 */
InitRestartDepca(dev); /* Resume normal operation. */
- dev->tbusy = 0; /* Unlock the TX ring */
+ netif_start_queue(dev); /* Unlock the TX ring */
break;
case DEPCA_SAY_BOO: /* Say "Boo!" to the kernel log file */