#define DRV_NAME "3c527"
#define DRV_VERSION "0.7-SMP"
-#define DRV_RELDATE "2003/09/17"
+#define DRV_RELDATE "2003/09/21"
static const char *version =
DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " Richard Procter <rnp@paradise.net.nz>\n";
struct mc32_ring_desc rx_ring[RX_RING_LEN]; /* Host Receive ring */
atomic_t tx_count; /* buffers left */
- volatile u16 tx_ring_head; /* index to tx en-queue end */
- u16 tx_ring_tail; /* index to tx de-queue end */
+ atomic_t tx_ring_head; /* index to tx en-queue end */
+ u16 tx_ring_tail; /* index to tx de-queue end */
u16 rx_ring_tail; /* index to rx de-queue end */
/* see mc32_tx_ring */
atomic_set(&lp->tx_count, TX_RING_LEN-1);
- lp->tx_ring_head=lp->tx_ring_tail=0;
+ atomic_set(&lp->tx_ring_head, 0);
+ lp->tx_ring_tail=0;
}
}
atomic_set(&lp->tx_count, 0);
- lp->tx_ring_tail=lp->tx_ring_head=0;
+ atomic_set(&lp->tx_ring_head, 0);
+ lp->tx_ring_tail=0;
}
*
* We do not disable interrupts or acquire any locks; this can
* run concurrently with mc32_tx_ring(), and the function itself
- * is serialised at a higher layer. However, this makes it
- * crucial that we update lp->tx_ring_head only after we've
- * established a valid packet in the tx ring (and is why we mark
- * tx_ring_head volatile).
- *
- **/
+ * is serialised at a higher layer. However, similarly for the
+ * card itself, we must ensure that we update tx_ring_head only
+ * after we've established a valid packet on the tx ring (and
+ * before we let the card "see" it, to prevent it racing with the
+ * irq handler).
+ *
+ */
+
static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev)
{
struct mc32_local *lp = (struct mc32_local *)dev->priv;
- u16 head = lp->tx_ring_head;
-
+ u32 head = atomic_read(&lp->tx_ring_head);
+
volatile struct skb_header *p, *np;
netif_stop_queue(dev);
}
skb = skb_padto(skb, ETH_ZLEN);
-
if (skb == NULL) {
netif_wake_queue(dev);
return 0;
head = next_tx(head);
/* NP is the buffer we will be loading */
- np=lp->tx_ring[head].p;
-
+ np=lp->tx_ring[head].p;
+
/* We will need this to flush the buffer out */
- lp->tx_ring[lp->tx_ring_head].skb = skb;
-
- np->length = unlikely(skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len;
-
+ lp->tx_ring[head].skb=skb;
+
+ np->length = unlikely(skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len;
np->data = isa_virt_to_bus(skb->data);
np->status = 0;
np->control = CONTROL_EOP | CONTROL_EOL;
/*
* The new frame has been setup; we can now
- * let the card and interrupt handler "see" it
+ * let the interrupt handler and card "see" it
*/
+ atomic_set(&lp->tx_ring_head, head);
p->control &= ~CONTROL_EOL;
- lp->tx_ring_head= head;
netif_wake_queue(dev);
return 0;
* condition with 'queue full'
*/
- while (lp->tx_ring_tail != lp->tx_ring_head)
+ while (lp->tx_ring_tail != atomic_read(&lp->tx_ring_head))
{
u16 t;
if (lp->mc_reload_wait)
mc32_reset_multicast_list(dev);
}
- else {
- complete(&lp->execution_cmd);
- }
+ else complete(&lp->execution_cmd);
}
if(status&2)
{