--- linux-2.6.0-test8/drivers/net/3c527.felipe.c 2003-10-20 20:27:22.000000000 +1300 +++ linux-2.6.0-test8/drivers/net/3c527.c 2003-10-21 16:47:32.000000000 +1300 @@ -19,7 +19,7 @@ #define DRV_NAME "3c527" #define DRV_VERSION "0.7-SMP" -#define DRV_RELDATE "2003/10/06" +#define DRV_RELDATE "2003/10/20" static const char *version = DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " Richard Procter \n"; @@ -176,9 +176,10 @@ struct mc32_local struct mc32_ring_desc tx_ring[TX_RING_LEN]; /* Host Transmit ring */ 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_count; /* buffers left */ + 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 */ struct semaphore cmd_mutex; /* Serialises issuing of execute commands */ @@ -223,7 +224,7 @@ static int mc32_close(struct net_device static struct net_device_stats *mc32_get_stats(struct net_device *dev); static void mc32_set_multicast_list(struct net_device *dev); static void mc32_reset_multicast_list(struct net_device *dev); -static struct ethtool_ops netdev_ethtool_ops; +static struct ethtool_ops netdev_ethtool_ops; /** * mc32_probe - Search for supported boards @@ -832,11 +833,12 @@ static void mc32_load_tx_ring(struct net tx_base=p->next; } - /* -1 so that tx_ring_head cannot "lap" tx_ring_tail, */ - /* see mc32_tx_ring */ - + /* -1 so that tx_ring_head cannot "lap" tx_ring_tail. */ + /* 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; } @@ -866,7 +868,8 @@ static void mc32_flush_tx_ring(struct ne } 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; } @@ -999,20 +1002,20 @@ static void mc32_timeout(struct net_devi * full then we set tx_busy and return. Once the interrupt handler * gets messages telling it to reclaim transmit queue entries, we will * clear tx_busy and the kernel will start calling this again. - * - * 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). - */ - + * + * 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, 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; @@ -1027,7 +1030,7 @@ static int mc32_send_packet(struct sk_bu netif_wake_queue(dev); return 0; } - + atomic_dec(&lp->tx_count); /* P is the last sending/sent buffer as a pointer */ @@ -1041,8 +1044,7 @@ static int mc32_send_packet(struct sk_bu /* We will need this to flush the buffer out */ lp->tx_ring[head].skb=skb; - np->length = unlikely(skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len; - + 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; @@ -1050,11 +1052,11 @@ static int mc32_send_packet(struct sk_bu /* * 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; @@ -1234,8 +1236,8 @@ static void mc32_tx_ring(struct net_devi * tx_ring_head wrapping to tail and confusing a 'queue empty' * 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; @@ -1487,7 +1489,7 @@ static int mc32_close(struct net_device static struct net_device_stats *mc32_get_stats(struct net_device *dev) { - struct mc32_local *lp = (struct mc32_local *)dev->priv;; + struct mc32_local *lp = (struct mc32_local *)dev->priv; mc32_update_stats(dev);