patch-1.3.73 linux/drivers/net/3c509.c
Next file: linux/drivers/net/Makefile
Previous file: linux/drivers/net/3c503.c
Back to the patch index
Back to the overall index
- Lines: 176
- Date:
Sun Mar 10 09:44:17 1996
- Orig file:
v1.3.72/linux/drivers/net/3c509.c
- Orig date:
Sat Mar 2 10:43:30 1996
diff -u --recursive --new-file v1.3.72/linux/drivers/net/3c509.c linux/drivers/net/3c509.c
@@ -94,8 +94,17 @@
#define WN4_MEDIA 0x0A /* Window 4: Various transcvr/media bits. */
#define MEDIA_TP 0x00C0 /* Enable link beat and jabber for 10baseT. */
+/*
+ * Must be a power of two (we use a binary and in the
+ * circular queue)
+ */
+#define SKB_QUEUE_SIZE 64
+
struct el3_private {
struct enet_statistics stats;
+ /* skb send-queue */
+ int head, size;
+ struct sk_buff *queue[SKB_QUEUE_SIZE];
};
static ushort id_read_eeprom(int index);
@@ -378,75 +387,40 @@
return 0; /* Always succeed */
}
-static int
-el3_start_xmit(struct sk_buff *skb, struct device *dev)
+static void
+el3_tx(struct device *dev)
{
struct el3_private *lp = (struct el3_private *)dev->priv;
int ioaddr = dev->base_addr;
+ struct sk_buff * skb;
- /* Transmitter timeout, serious problems. */
- if (dev->tbusy) {
- int tickssofar = jiffies - dev->trans_start;
- if (tickssofar < 10)
- return 1;
- printk("%s: transmit timed out, tx_status %2.2x status %4.4x.\n",
- dev->name, inb(ioaddr + TX_STATUS), inw(ioaddr + EL3_STATUS));
- dev->trans_start = jiffies;
- /* Issue TX_RESET and TX_START commands. */
- outw(TxReset, ioaddr + EL3_CMD);
- outw(TxEnable, ioaddr + EL3_CMD);
- dev->tbusy = 0;
- }
+ if (el3_debug > 5)
+ printk(" TX room bit was handled.\n");
- if (skb == NULL) {
- dev_tint(dev);
- return 0;
- }
-
- if (skb->len <= 0)
- return 0;
+ outw(AckIntr | 0x08, ioaddr + EL3_CMD);
+ if (!lp->size)
+ return;
- if (el3_debug > 4) {
- printk("%s: el3_start_xmit(length = %ld) called, status %4.4x.\n",
- dev->name, skb->len, inw(ioaddr + EL3_STATUS));
- }
-#ifndef final_version
- { /* Error-checking code, delete for 1.30. */
- ushort status = inw(ioaddr + EL3_STATUS);
- if (status & 0x0001 /* IRQ line active, missed one. */
- && inw(ioaddr + EL3_STATUS) & 1) { /* Make sure. */
- printk("%s: Missed interrupt, status then %04x now %04x"
- " Tx %2.2x Rx %4.4x.\n", dev->name, status,
- inw(ioaddr + EL3_STATUS), inb(ioaddr + TX_STATUS),
- inw(ioaddr + RX_STATUS));
- /* Fake interrupt trigger by masking, acknowledge interrupts. */
- outw(SetReadZero | 0x00, ioaddr + EL3_CMD);
- outw(AckIntr | 0x69, ioaddr + EL3_CMD); /* Ack IRQ */
- outw(SetReadZero | 0xff, ioaddr + EL3_CMD);
- }
- }
-#endif
+ /* There's room in the FIFO for a full-sized packet. */
+ while (inw(ioaddr + TX_FREE) > 1536) {
+ skb = lp->queue[lp->head];
+ lp->head = (lp->head + 1) & (SKB_QUEUE_SIZE-1);
+ lp->size--;
- /* Avoid timer-based retransmission conflicts. */
- if (set_bit(0, (void*)&dev->tbusy) != 0)
- printk("%s: Transmitter access conflict.\n", dev->name);
- else {
/* Put out the doubleword header... */
outw(skb->len, ioaddr + TX_FIFO);
outw(0x00, ioaddr + TX_FIFO);
/* ... and the packet rounded to a doubleword. */
outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
+ /* free the skb, we're done with it */
+ dev_kfree_skb(skb, FREE_WRITE);
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);
+ if (!lp->size)
+ return;
}
-
- dev_kfree_skb (skb, FREE_WRITE);
-
+ /* Interrupt us when the FIFO has room for max-sized packet. */
+ outw(SetTxThreshold + 1536, ioaddr + EL3_CMD);
/* Clear the Tx status stack. */
{
short tx_status;
@@ -459,6 +433,44 @@
outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */
}
}
+}
+
+static int
+el3_start_xmit(struct sk_buff *skb, struct device *dev)
+{
+ struct el3_private *lp = (struct el3_private *)dev->priv;
+ unsigned long flags;
+ int ioaddr = dev->base_addr;
+
+ save_flags(flags);
+ cli();
+ /*
+ * Do we have room in the send queue?
+ */
+ if (lp->size < SKB_QUEUE_SIZE) {
+ int tail = (lp->head + lp->size) & (SKB_QUEUE_SIZE-1);
+ lp->queue[tail] = skb;
+ lp->size++;
+ /* fake a transmit interrupt to get it started */
+ el3_tx(dev);
+ restore_flags(flags);
+ return 0;
+ }
+
+ /*
+ * No space, check if we might have timed out?
+ */
+ if (jiffies - dev->trans_start > HZ) {
+ printk("%s: transmit timed out, tx_status %2.2x status %4.4x.\n",
+ dev->name, inb(ioaddr + TX_STATUS), inw(ioaddr + EL3_STATUS));
+ dev->trans_start = jiffies;
+ /* Issue TX_RESET and TX_START commands. */
+ outw(TxReset, ioaddr + EL3_CMD);
+ outw(TxEnable, ioaddr + EL3_CMD);
+ }
+ /* free the skb, we might as well drop it on the floor */
+ dev_kfree_skb(skb, FREE_WRITE);
+ restore_flags(flags);
return 0;
}
@@ -490,14 +502,9 @@
if (status & 0x10)
el3_rx(dev);
- if (status & 0x08) {
- if (el3_debug > 5)
- printk(" TX room bit was handled.\n");
- /* There's room in the FIFO for a full-sized packet. */
- outw(AckIntr | 0x08, ioaddr + EL3_CMD);
- dev->tbusy = 0;
- mark_bh(NET_BH);
- }
+ if (status & 0x08)
+ el3_tx(dev);
+
if (status & 0x80) /* Statistics full. */
update_stats(ioaddr, dev);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this