summaryrefslogtreecommitdiffstats
path: root/drivers/net/tokenring/olympic.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/tokenring/olympic.c')
-rw-r--r--drivers/net/tokenring/olympic.c108
1 files changed, 43 insertions, 65 deletions
diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c
index 8f1f6cce0..fcb3ccd76 100644
--- a/drivers/net/tokenring/olympic.c
+++ b/drivers/net/tokenring/olympic.c
@@ -25,10 +25,11 @@
* 8/18/99 - Updated driver for 2.3.13 kernel to use new pci
* resource. Driver also reports the card name returned by
* the pci resource.
+ * 1/11/00 - Added spinlocks for smp
*
* To Do:
*
- * Sanitize for smp
+ * IPv6 Multicast
*
* If Problems do Occur
* Most problems can be rectified by either closing and opening the interface
@@ -69,6 +70,7 @@
#include <linux/stddef.h>
#include <linux/init.h>
#include <linux/pci.h>
+#include <linux/spinlock.h>
#include <net/checksum.h>
#include <asm/io.h>
@@ -86,7 +88,7 @@
*/
static char *version =
-"Olympic.c v0.3.0 8/18/99 - Peter De Schrijver & Mike Phillips" ;
+"Olympic.c v0.3.1 1/11/00 - Peter De Schrijver & Mike Phillips" ;
static char *open_maj_error[] = {"No error", "Lobe Media Test", "Physical Insertion",
"Address Verification", "Neighbor Notification (Ring Poll)",
@@ -202,7 +204,6 @@ static int __init olympic_scan(struct net_device *dev)
olympic_priv->olympic_ring_speed = ringspeed[card_no] ;
olympic_priv->olympic_message_level = message_level[card_no] ;
- olympic_priv->olympic_multicast_set = 0 ;
if(olympic_init(dev)==-1) {
unregister_netdevice(dev);
@@ -251,6 +252,8 @@ static int __init olympic_init(struct net_device *dev)
}
}
+ spin_lock_init(&olympic_priv->olympic_lock) ;
+
#if OLYMPIC_DEBUG
printk("BCTL: %x\n",readl(olympic_mmio+BCTL));
printk("GPR: %x\n",readw(olympic_mmio+GPR));
@@ -757,6 +760,8 @@ static void olympic_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if (!(sisr & SISR_MI)) /* Interrupt isn't for us */
return ;
+ spin_lock(&olympic_priv->olympic_lock);
+
if (dev->interrupt)
printk(KERN_WARNING "%s: Re-entering interrupt \n",dev->name) ;
@@ -835,15 +840,20 @@ static void olympic_interrupt(int irq, void *dev_id, struct pt_regs *regs)
dev->interrupt = 0 ;
writel(SISR_MI,olympic_mmio+SISR_MASK_SUM);
-
+
+ spin_unlock(&olympic_priv->olympic_lock) ;
}
static int olympic_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
- __u8 *olympic_mmio=olympic_priv->olympic_mmio;
+ __u8 *olympic_mmio=olympic_priv->olympic_mmio;
+ unsigned long flags ;
+
+ spin_lock_irqsave(&olympic_priv->olympic_lock, flags);
if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
+ spin_unlock_irqrestore(&olympic_priv->olympic_lock,flags);
return 1;
}
@@ -860,10 +870,12 @@ static int olympic_xmit(struct sk_buff *skb, struct net_device *dev)
writew((((readw(olympic_mmio+TXENQ_1)) & 0x8000) ^ 0x8000) | 1,olympic_mmio+TXENQ_1);
dev->tbusy=0;
-
+ spin_unlock_irqrestore(&olympic_priv->olympic_lock,flags);
return 0;
- } else
+ } else {
+ spin_unlock_irqrestore(&olympic_priv->olympic_lock,flags);
return 1;
+ }
}
@@ -936,9 +948,11 @@ static void olympic_set_rx_mode(struct net_device *dev)
{
struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv ;
__u8 *olympic_mmio = olympic_priv->olympic_mmio ;
- __u8 options = 0, set_mc_list = 0 ;
- __u8 *srb, *ata ;
+ __u8 options = 0;
+ __u8 *srb;
struct dev_mc_list *dmi ;
+ unsigned char dev_mc_address[4] ;
+ int i ;
writel(olympic_priv->srb,olympic_mmio+LAPA);
srb=olympic_priv->olympic_lap + (olympic_priv->srb & (~0xf800));
@@ -949,10 +963,6 @@ static void olympic_set_rx_mode(struct net_device *dev)
else
options &= ~(3<<5) ;
- if (dev->mc_count) {
- set_mc_list = 1 ;
- }
-
/* Only issue the srb if there is a change in options */
if ((options ^ olympic_priv->olympic_copy_all_options)) {
@@ -975,60 +985,30 @@ static void olympic_set_rx_mode(struct net_device *dev)
return ;
}
- if (set_mc_list ^ olympic_priv->olympic_multicast_set) { /* Multicast options have changed */
-
- dmi = dev->mc_list ;
+ /* Set the functional addresses we need for multicast */
- if (set_mc_list) { /* Turn multicast on */
-
- /* RFC 1469 Says we must support using the functional address C0 00 00 04 00 00
- * We do this with a set functional address mask.
- */
-
- ata=olympic_priv->olympic_lap + (olympic_priv->olympic_addr_table_addr) ;
- if (!(readb(ata+11) & 0x04)) { /* Hmmm, need to set the functional mask */
- writeb(SRB_SET_FUNC_ADDRESS,srb+0);
- writeb(0,srb+1);
- writeb(OLYMPIC_CLEAR_RET_CODE,srb+2);
- writeb(0,srb+3);
- writeb(0,srb+4);
- writeb(0,srb+5);
- writeb(readb(ata+10),srb+6);
- writeb(readb(ata+11)|4,srb+7);
- writeb(readb(ata+12),srb+8);
- writeb(readb(ata+13),srb+9);
-
- olympic_priv->srb_queued = 2 ;
- writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM);
-
- olympic_priv->olympic_multicast_set = 1 ;
- }
-
-
- } else { /* Turn multicast off */
-
- ata=olympic_priv->olympic_lap + (olympic_priv->olympic_addr_table_addr) ;
- if ((readb(ata+11) & 0x04)) { /* Hmmm, need to reset the functional mask */
- writeb(SRB_SET_FUNC_ADDRESS,srb+0);
- writeb(0,srb+1);
- writeb(OLYMPIC_CLEAR_RET_CODE,srb+2);
- writeb(0,srb+3);
- writeb(0,srb+4);
- writeb(0,srb+5);
- writeb(readb(ata+10),srb+6);
- writeb(readb(ata+11) & ~4,srb+7);
- writeb(readb(ata+12),srb+8);
- writeb(readb(ata+13),srb+9);
-
- olympic_priv->srb_queued = 2 ;
- writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM);
-
- olympic_priv->olympic_multicast_set = 0 ;
- }
- }
+ dev_mc_address[0] = dev_mc_address[1] = dev_mc_address[2] = dev_mc_address[3] = 0 ;
+ for (i=0,dmi=dev->mc_list;i < dev->mc_count; i++,dmi = dmi->next) {
+ dev_mc_address[0] |= dmi->dmi_addr[2] ;
+ dev_mc_address[1] |= dmi->dmi_addr[3] ;
+ dev_mc_address[2] |= dmi->dmi_addr[4] ;
+ dev_mc_address[3] |= dmi->dmi_addr[5] ;
}
+ writeb(SRB_SET_FUNC_ADDRESS,srb+0);
+ writeb(0,srb+1);
+ writeb(OLYMPIC_CLEAR_RET_CODE,srb+2);
+ writeb(0,srb+3);
+ writeb(0,srb+4);
+ writeb(0,srb+5);
+ writeb(dev_mc_address[0],srb+6);
+ writeb(dev_mc_address[1],srb+7);
+ writeb(dev_mc_address[2],srb+8);
+ writeb(dev_mc_address[3],srb+9);
+
+ olympic_priv->srb_queued = 2 ;
+ writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM);
}
@@ -1069,7 +1049,6 @@ static void olympic_srb_bh(struct net_device *dev)
case SRB_SET_GROUP_ADDRESS:
switch (readb(srb+2)) {
case 0x00:
- olympic_priv->olympic_multicast_set = 1 ;
break ;
case 0x01:
printk(KERN_WARNING "%s: Unrecognized srb command \n",dev->name) ;
@@ -1097,7 +1076,6 @@ static void olympic_srb_bh(struct net_device *dev)
case SRB_RESET_GROUP_ADDRESS:
switch (readb(srb+2)) {
case 0x00:
- olympic_priv->olympic_multicast_set = 0 ;
break ;
case 0x01:
printk(KERN_WARNING "%s: Unrecognized srb command \n",dev->name) ;