patch-2.3.19 linux/drivers/net/3c527.c
Next file: linux/drivers/net/82596.c
Previous file: linux/drivers/net/3c509.c
Back to the patch index
Back to the overall index
- Lines: 197
- Date:
Wed Sep 29 14:02:59 1999
- Orig file:
v2.3.18/linux/drivers/net/3c527.c
- Orig date:
Wed Aug 18 11:36:41 1999
diff -u --recursive --new-file v2.3.18/linux/drivers/net/3c527.c linux/drivers/net/3c527.c
@@ -1,3 +1,4 @@
+
/* 3c527.c: 3Com Etherlink/MC32 driver for Linux
*
* (c) Copyright 1998 Red Hat Software Inc
@@ -15,7 +16,7 @@
*/
static const char *version =
- "3c527.c:v0.04 1999/03/16 Alan Cox (alan@redhat.com)\n";
+ "3c527.c:v0.05 1999/09/06 Alan Cox (alan@redhat.com)\n";
/*
* Things you need
@@ -108,6 +109,7 @@
u16 tx_skb_end;
struct sk_buff *rx_skb[RX_RING_MAX]; /* Receive ring */
void *rx_ptr[RX_RING_MAX]; /* Data pointers */
+ u32 mc_list_valid; /* True when the mclist is set */
};
/* The station (ethernet) address prefix, used for a sanity check. */
@@ -138,6 +140,8 @@
static int mc32_close(struct net_device *dev);
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);
+
/*
* Check for a network adaptor of this type, and return '0' iff one exists.
@@ -445,16 +449,56 @@
/*
* Send exec commands
*/
-
+
+
+/*
+ * Send command from interrupt state
+ */
+
+static int mc32_command_nowait(struct net_device *dev, u16 cmd, void *data, int len)
+{
+ struct mc32_local *lp = (struct mc32_local *)dev->priv;
+ int ioaddr = dev->base_addr;
+
+ if(lp->exec_pending)
+ return -1;
+
+ lp->exec_pending=1;
+ lp->exec_box->mbox=0;
+ lp->exec_box->mbox=cmd;
+ memcpy((void *)lp->exec_box->data, data, len);
+ barrier(); /* the memcpy forgot the volatile so be sure */
+
+ /* Send the command */
+ while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));
+ outb(1<<6, ioaddr+HOST_CMD);
+ return 0;
+}
+
+
+/*
+ * Send command and block for results. On completion spot and reissue
+ * multicasts
+ */
+
static int mc32_command(struct net_device *dev, u16 cmd, void *data, int len)
{
struct mc32_local *lp = (struct mc32_local *)dev->priv;
int ioaddr = dev->base_addr;
unsigned long flags;
+ int ret = 0;
+ /*
+ * Wait for a command
+ */
+
while(lp->exec_pending)
sleep_on(&lp->event);
+ /*
+ * Issue mine
+ */
+
lp->exec_pending=1;
lp->exec_box->mbox=0;
lp->exec_box->mbox=cmd;
@@ -472,18 +516,20 @@
lp->exec_pending=0;
restore_flags(flags);
+
+ if(lp->exec_box->data[0]&(1<<13))
+ ret = -1;
/*
* A multicast set got blocked - do it now
*/
-
+
if(lp->mc_reload_wait)
- mc32_set_multicast_list(dev);
+ mc32_reset_multicast_list(dev);
- if(lp->exec_box->data[0]&(1<<13))
- return -1;
- return 0;
+ return ret;
}
+
/*
* RX abort
*/
@@ -1063,20 +1109,18 @@
* num_addrs > 0 Multicast mode, receive normal and MC packets,
* and do best-effort filtering.
*/
-static void mc32_set_multicast_list(struct net_device *dev)
+static void do_mc32_set_multicast_list(struct net_device *dev, int retry)
{
+ struct mc32_local *lp = (struct mc32_local *)dev->priv;
u16 filt;
+
if (dev->flags&IFF_PROMISC)
- {
/* Enable promiscuous mode */
filt = 1;
- mc32_command(dev, 0, &filt, 2);
- }
else if((dev->flags&IFF_ALLMULTI) || dev->mc_count > 10)
{
dev->flags|=IFF_PROMISC;
filt = 1;
- mc32_command(dev, 0, &filt, 2);
}
else if(dev->mc_count)
{
@@ -1087,24 +1131,47 @@
int i;
filt = 0;
- block[1]=0;
- block[0]=dev->mc_count;
- bp=block+2;
- for(i=0;i<dev->mc_count;i++)
+ if(retry==0)
+ lp->mc_list_valid = 0;
+ if(!lp->mc_list_valid)
{
- memcpy(bp, dmc->dmi_addr, 6);
- bp+=6;
- dmc=dmc->next;
+ block[1]=0;
+ block[0]=dev->mc_count;
+ bp=block+2;
+
+ for(i=0;i<dev->mc_count;i++)
+ {
+ memcpy(bp, dmc->dmi_addr, 6);
+ bp+=6;
+ dmc=dmc->next;
+ }
+ if(mc32_command_nowait(dev, 2, block, 2+6*dev->mc_count)==-1)
+ {
+ lp->mc_reload_wait = 1;
+ return;
+ }
+ lp->mc_list_valid=1;
}
- mc32_command(dev, 2, block, 2+6*dev->mc_count);
- mc32_command(dev, 0, &filt, 2);
}
else
{
filt = 0;
- mc32_command(dev, 0, &filt, 2);
}
+ if(mc32_command_nowait(dev, 0, &filt, 2)==-1)
+ {
+ lp->mc_reload_wait = 1;
+ }
+}
+
+static void mc32_set_multicast_list(struct net_device *dev)
+{
+ do_mc32_set_multicast_list(dev,0);
+}
+
+static void mc32_reset_multicast_list(struct net_device *dev)
+{
+ do_mc32_set_multicast_list(dev,1);
}
#ifdef MODULE
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)