patch-2.1.15 linux/drivers/net/8390.c
Next file: linux/drivers/net/8390.h
Previous file: linux/drivers/net/3c523.h
Back to the patch index
Back to the overall index
- Lines: 184
- Date:
Thu Dec 12 16:51:09 1996
- Orig file:
v2.1.14/linux/drivers/net/8390.c
- Orig date:
Tue Nov 19 15:53:54 1996
diff -u --recursive --new-file v2.1.14/linux/drivers/net/8390.c linux/drivers/net/8390.c
@@ -30,7 +30,8 @@
Paul Gortmaker : exchange static int ei_pingpong for a #define,
also add better Tx error handling.
Paul Gortmaker : rewrite Rx overrun handling as per NS specs.
- Alexey Kuznetsov : use the software multicast filter.
+ Alexey Kuznetsov : use the 8390's six bit hash multicast filter.
+ Paul Gortmaker : tweak ANK's above multicast changes a bit.
Sources:
@@ -679,73 +680,90 @@
}
/*
- * Set or clear the multicast filter for this adaptor.
- * (Don't assume 8bit char..)
+ * Update the given Autodin II CRC value with another data byte.
*/
-
-extern inline __u32 upd_8390_crc(__u8 b, __u32 x)
+static inline u32 update_crc(u8 byte, u32 current_crc)
{
- int i;
- __u8 ah=0;
- for(i=0;i<8;i++)
- {
- __u8 carry = (x>>31);
- x<<=1;
- ah = ((ah<<1)|carry)^b;
-
- if(ah&1)
- x^=0x04C11DB7;
- ah>>=1;
- b>>=1;
+ int bit;
+ u8 ah = 0;
+
+ for (bit=0; bit<8; bit++) {
+ u8 carry = (current_crc>>31);
+ current_crc <<= 1;
+ ah = ((ah<<1) | carry) ^ byte;
+ if (ah&1)
+ current_crc ^= 0x04C11DB7; /* CRC polynomial */
+ ah >>= 1;
+ byte >>= 1;
}
- return x;
+ return current_crc;
}
-extern __inline void make_8390_mc_bits(__u8 *bits, struct device *dev)
+/*
+ * Form the 64 bit 8390 multicast table from the linked list of addresses
+ * associated with this dev structure.
+ */
+static inline void make_mc_bits(u8 *bits, struct device *dev)
{
struct dev_mc_list *dmi;
- memset(bits,0,8);
-
- for(dmi=dev->mc_list;dmi!=NULL;dmi=dmi->next)
- {
+
+ for (dmi=dev->mc_list; dmi; dmi=dmi->next) {
int i;
- __u32 x;
- if(dmi->dmi_addrlen!=6)
- continue; /* !! */
- x=0xFFFFFFFFUL;
- for(i=0;i<6;i++)
- x = upd_8390_crc(dmi->dmi_addr[i],x);
- bits[x>>29] |= (1<<((x>>26)&7));
+ u32 crc;
+ if (dmi->dmi_addrlen != ETH_ALEN) {
+ printk(KERN_INFO "%s: invalid multicast address length given.\n", dev->name);
+ continue;
+ }
+ crc = 0xffffffff; /* initial CRC value */
+ for (i=0; i<ETH_ALEN; i++)
+ crc = update_crc(dmi->dmi_addr[i], crc);
+ /*
+ * The 8390 uses the 6 most significant bits of the
+ * CRC to index the multicast table.
+ */
+ bits[crc>>29] |= (1<<((crc>>26)&7));
}
}
+/*
+ * Set or clear the multicast filter for this adaptor.
+ */
+
static void set_multicast_list(struct device *dev)
{
short ioaddr = dev->base_addr;
-
+ int i;
+ unsigned long flags;
+ struct ei_device *ei = (struct ei_device*)dev->priv;
+
+ if (!(dev->flags&(IFF_PROMISC|IFF_ALLMULTI))) {
+ memset(ei->mcfilter, 0, 8);
+ if (dev->mc_list)
+ make_mc_bits(ei->mcfilter, dev);
+ } else
+ memset(ei->mcfilter, 0xFF, 8); /* mcast set to accept-all */
+
+ /*
+ * DP8390 manuals don't specify any magic sequence for altering
+ * the multicast regs on an already running card. To be safe, we
+ * ensure multicast mode is off prior to loading up the new hash
+ * table. If this proves to be not enough, we can always resort
+ * to stopping the NIC, loading the table and then restarting.
+ */
+ if (dev->start)
+ outb_p(E8390_RXCONFIG, ioaddr + EN0_RXCR);
+ save_flags(flags);
+ cli();
+ outb_p(E8390_NODMA + E8390_PAGE1, ioaddr + E8390_CMD);
+ for(i = 0; i < 8; i++)
+ outb_p(ei->mcfilter[i], ioaddr + EN1_MULT + i);
+ outb_p(E8390_NODMA + E8390_PAGE0, ioaddr + E8390_CMD);
+ restore_flags(flags);
+
if(dev->flags&IFF_PROMISC)
- {
outb_p(E8390_RXCONFIG | 0x18, ioaddr + EN0_RXCR);
- }
- else if((dev->flags&IFF_ALLMULTI)||dev->mc_list)
- {
- unsigned long flags;
- __u8 mc_bits[8];
- int i;
-
- if(dev->flags&IFF_ALLMULTI)
- memset(mc_bits,0xFF,8);
- else
- make_8390_mc_bits(mc_bits,dev);
- save_flags(flags);
- cli();
- outb_p(E8390_NODMA + E8390_PAGE1 + E8390_STOP, ioaddr);
- for(i = 0; i < 8; i++)
- outb_p(mc_bits[i], ioaddr + EN1_MULT + i);
- outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START, ioaddr);
+ else if(dev->flags&IFF_ALLMULTI || dev->mc_list)
outb_p(E8390_RXCONFIG | 0x08, ioaddr + EN0_RXCR);
- restore_flags(flags);
- }
else
outb_p(E8390_RXCONFIG, ioaddr + EN0_RXCR);
}
@@ -806,20 +824,15 @@
outb_p(0xFF, e8390_base + EN0_ISR);
outb_p(0x00, e8390_base + EN0_IMR);
- /* Copy the station address into the DS8390 registers,
- and set the multicast hash bitmap to receive all multicasts. */
+ /* Copy the station address into the DS8390 registers. */
save_flags(flags);
cli();
outb_p(E8390_NODMA + E8390_PAGE1 + E8390_STOP, e8390_base); /* 0x61 */
for(i = 0; i < 6; i++) {
outb_p(dev->dev_addr[i], e8390_base + EN1_PHYS + i);
}
- /* Initialize the multicast list to accept-all. If we enable multicast
- the higher levels can do the filtering. */
- for(i = 0; i < 8; i++)
- outb_p(0xff, e8390_base + EN1_MULT + i);
- outb_p(ei_local->rx_start_page, e8390_base + EN1_CURPAG);
+ outb_p(ei_local->rx_start_page, e8390_base + EN1_CURPAG);
outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base);
restore_flags(flags);
dev->tbusy = 0;
@@ -833,8 +846,7 @@
outb_p(E8390_TXCONFIG, e8390_base + EN0_TXCR); /* xmit on. */
/* 3c503 TechMan says rxconfig only after the NIC is started. */
outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR); /* rx on, */
- dev->set_multicast_list(dev); /* Get the multicast status right if this
- was a reset. */
+ set_multicast_list(dev); /* (re)load the mcast table */
}
return;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov