fix r6040 multicast patch, thanks nicolas le falher
[librecmc/librecmc.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,