f2236655bfc1865e2b028edacce28c38a7d6d4de
[openwrt/openwrt.git] / target / linux / rdc / patches-2.6.32 / 015-r6040_fix_multicast.patch
1 --- a/drivers/net/r6040.c
2 +++ b/drivers/net/r6040.c
3 @@ -70,6 +70,8 @@
4
5 /* MAC registers */
6 #define MCR0 0x00 /* Control register 0 */
7 +#define PROMISC 0x0020 /* Promiscuous mode */
8 +#define HASH_EN 0x0100 /* Enable multicast hash table function */
9 #define MCR1 0x04 /* Control register 1 */
10 #define MAC_RST 0x0001 /* Reset the MAC */
11 #define MBCR 0x08 /* Bus control */
12 @@ -837,76 +839,96 @@
13 {
14 struct r6040_private *lp = netdev_priv(dev);
15 void __iomem *ioaddr = lp->base;
16 - u16 *adrp;
17 - u16 reg;
18 unsigned long flags;
19 struct dev_mc_list *dmi = dev->mc_list;
20 int i;
21 + u16 *adrp;
22 + u16 hash_table[4] = { 0 };
23 +
24 + spin_lock_irqsave(&lp->lock, flags);
25
26 - /* MAC Address */
27 + /* Keep our MAC Address */
28 adrp = (u16 *)dev->dev_addr;
29 iowrite16(adrp[0], ioaddr + MID_0L);
30 iowrite16(adrp[1], ioaddr + MID_0M);
31 iowrite16(adrp[2], ioaddr + MID_0H);
32
33 - /* Promiscous Mode */
34 - spin_lock_irqsave(&lp->lock, flags);
35 -
36 /* Clear AMCP & PROM bits */
37 - reg = ioread16(ioaddr) & ~0x0120;
38 + lp->mcr0 = ioread16(ioaddr + MCR0) & ~(PROMISC | HASH_EN);
39 +
40 + /* Promiscuous mode */
41 if (dev->flags & IFF_PROMISC) {
42 - reg |= 0x0020;
43 - lp->mcr0 |= 0x0020;
44 + lp->mcr0 |= PROMISC;
45 }
46 - /* Too many multicast addresses
47 - * accept all traffic */
48 - else if ((dev->mc_count > MCAST_MAX)
49 - || (dev->flags & IFF_ALLMULTI))
50 - reg |= 0x0020;
51
52 - iowrite16(reg, ioaddr);
53 - spin_unlock_irqrestore(&lp->lock, flags);
54 -
55 - /* Build the hash table */
56 - if (dev->mc_count > MCAST_MAX) {
57 - u16 hash_table[4];
58 - u32 crc;
59 + /* Enable multicast hash table function to
60 + * receive all multicast packets. */
61 + else if (dev->flags & IFF_ALLMULTI) {
62 + lp->mcr0 |= HASH_EN;
63 +
64 + for (i = 0; i < MCAST_MAX ; i++) {
65 + iowrite16(0, ioaddr + MID_1L + 8 * i);
66 + iowrite16(0, ioaddr + MID_1M + 8 * i);
67 + iowrite16(0, ioaddr + MID_1H + 8 * i);
68 + }
69
70 for (i = 0; i < 4; i++)
71 - hash_table[i] = 0;
72 + hash_table[i] = 0xffff;
73 + }
74
75 - for (i = 0; i < dev->mc_count; i++) {
76 - char *addrs = dmi->dmi_addr;
77 + /* Use internal multicast address registers if the number of
78 + * multicast addresses is not greater than MCAST_MAX. */
79 + else if (dev->mc_count <= MCAST_MAX) {
80 + i = 0;
81 + while (i < dev->mc_count) {
82 + u16 *adrp = (u16 *)dmi->dmi_addr;
83
84 dmi = dmi->next;
85 + iowrite16(adrp[0], ioaddr + MID_1L + 8 * i);
86 + iowrite16(adrp[1], ioaddr + MID_1M + 8 * i);
87 + iowrite16(adrp[2], ioaddr + MID_1H + 8 * i);
88 + i++;
89 + }
90 + while (i < MCAST_MAX) {
91 + iowrite16(0, ioaddr + MID_1L + 8 * i);
92 + iowrite16(0, ioaddr + MID_1M + 8 * i);
93 + iowrite16(0, ioaddr + MID_1H + 8 * i);
94 + i++;
95 + }
96 + }
97 + /* Otherwise, Enable multicast hash table function. */
98 + else {
99 + u32 crc;
100 +
101 + lp->mcr0 |= HASH_EN;
102
103 - if (!(*addrs & 1))
104 - continue;
105 + for (i = 0; i < MCAST_MAX ; i++) {
106 + iowrite16(0, ioaddr + MID_1L + 8 * i);
107 + iowrite16(0, ioaddr + MID_1M + 8 * i);
108 + iowrite16(0, ioaddr + MID_1H + 8 * i);
109 + }
110 +
111 + /* Build multicast hash table */
112 + for (i = 0; i < dev->mc_count; i++) {
113 + u8 *addrs = dmi->dmi_addr;
114 + dmi = dmi->next;
115
116 - crc = ether_crc_le(6, addrs);
117 + crc = ether_crc(ETH_ALEN, addrs);
118 crc >>= 26;
119 - hash_table[crc >> 4] |= 1 << (15 - (crc & 0xf));
120 + hash_table[crc >> 4] |= 1 << (crc & 0xf);
121 }
122 - /* Fill the MAC hash tables with their values */
123 + }
124 + iowrite16(lp->mcr0, ioaddr + MCR0);
125 +
126 + /* Fill the MAC hash tables with their values */
127 + if (lp->mcr0 && HASH_EN) {
128 iowrite16(hash_table[0], ioaddr + MAR0);
129 iowrite16(hash_table[1], ioaddr + MAR1);
130 iowrite16(hash_table[2], ioaddr + MAR2);
131 iowrite16(hash_table[3], ioaddr + MAR3);
132 }
133 - /* Multicast Address 1~4 case */
134 - dmi = dev->mc_list;
135 - for (i = 0, dmi; (i < dev->mc_count) && (i < MCAST_MAX); i++) {
136 - adrp = (u16 *)dmi->dmi_addr;
137 - iowrite16(adrp[0], ioaddr + MID_1L + 8*i);
138 - iowrite16(adrp[1], ioaddr + MID_1M + 8*i);
139 - iowrite16(adrp[2], ioaddr + MID_1H + 8*i);
140 - dmi = dmi->next;
141 - }
142 - for (i = dev->mc_count; i < MCAST_MAX; i++) {
143 - iowrite16(0xffff, ioaddr + MID_1L + 8*i);
144 - iowrite16(0xffff, ioaddr + MID_1M + 8*i);
145 - iowrite16(0xffff, ioaddr + MID_1H + 8*i);
146 - }
147 +
148 + spin_unlock_irqrestore(&lp->lock, flags);
149 }
150
151 static void netdev_get_drvinfo(struct net_device *dev,