backport r27876
authorflorian <florian@3c298f89-4303-0410-b956-a3cf2f4a3e73>
Tue, 2 Aug 2011 14:13:15 +0000 (14:13 +0000)
committerflorian <florian@3c298f89-4303-0410-b956-a3cf2f4a3e73>
Tue, 2 Aug 2011 14:13:15 +0000 (14:13 +0000)
git-svn-id: svn://svn.openwrt.org/openwrt/branches/backfire@27877 3c298f89-4303-0410-b956-a3cf2f4a3e73

target/linux/rdc/patches-2.6.30/015-r6040_fix_multicast.patch

index f41b4b5..f223665 100644 (file)
----
 --- a/drivers/net/r6040.c
 +++ b/drivers/net/r6040.c
-@@ -136,7 +136,7 @@
- #define RX_DESC_SIZE  (RX_DCNT * sizeof(struct r6040_descriptor))
- #define TX_DESC_SIZE  (TX_DCNT * sizeof(struct r6040_descriptor))
- #define MBCR_DEFAULT  0x012A  /* MAC Bus Control Register */
--#define MCAST_MAX     4       /* Max number multicast addresses to filter */
-+#define MCAST_MAX     3       /* Max number multicast addresses to filter */
- /* Descriptor status */
- #define DSC_OWNER_MAC 0x8000  /* MAC is the owner of this descriptor */
-@@ -887,9 +887,6 @@ static void r6040_multicast_list(struct 
+@@ -70,6 +70,8 @@
+ /* MAC registers */
+ #define MCR0          0x00    /* Control register 0 */
++#define  PROMISC      0x0020  /* Promiscuous mode */
++#define  HASH_EN      0x0100  /* Enable multicast hash table function */
+ #define MCR1          0x04    /* Control register 1 */
+ #define  MAC_RST      0x0001  /* Reset the MAC */
+ #define MBCR          0x08    /* Bus control */
+@@ -837,76 +839,96 @@
+ {
+       struct r6040_private *lp = netdev_priv(dev);
+       void __iomem *ioaddr = lp->base;
+-      u16 *adrp;
+-      u16 reg;
+       unsigned long flags;
+       struct dev_mc_list *dmi = dev->mc_list;
+       int i;
++      u16 *adrp;
++      u16 hash_table[4] = { 0 };
++
++      spin_lock_irqsave(&lp->lock, flags);
+-      /* MAC Address */
++      /* Keep our MAC Address */
+       adrp = (u16 *)dev->dev_addr;
+       iowrite16(adrp[0], ioaddr + MID_0L);
+       iowrite16(adrp[1], ioaddr + MID_0M);
+       iowrite16(adrp[2], ioaddr + MID_0H);
+-      /* Promiscous Mode */
+-      spin_lock_irqsave(&lp->lock, flags);
+-
+       /* Clear AMCP & PROM bits */
+-      reg = ioread16(ioaddr) & ~0x0120;
++      lp->mcr0 = ioread16(ioaddr + MCR0) & ~(PROMISC | HASH_EN);
++
++      /* Promiscuous mode */
+       if (dev->flags & IFF_PROMISC) {
+-              reg |= 0x0020;
+-              lp->mcr0 |= 0x0020;
++              lp->mcr0 |= PROMISC;
+       }
+-      /* Too many multicast addresses
+-       * accept all traffic */
+-      else if ((dev->mc_count > MCAST_MAX)
+-              || (dev->flags & IFF_ALLMULTI))
+-              reg |= 0x0020;
+-      iowrite16(reg, ioaddr);
+-      spin_unlock_irqrestore(&lp->lock, flags);
+-
+-      /* Build the hash table */
+-      if (dev->mc_count > MCAST_MAX) {
+-              u16 hash_table[4];
+-              u32 crc;
++      /* Enable multicast hash table function to
++       * receive all multicast packets. */
++      else if (dev->flags & IFF_ALLMULTI) {
++              lp->mcr0 |= HASH_EN;
++
++              for (i = 0; i < MCAST_MAX ; i++) {
++                      iowrite16(0, ioaddr + MID_1L + 8 * i);
++                      iowrite16(0, ioaddr + MID_1M + 8 * i);
++                      iowrite16(0, ioaddr + MID_1H + 8 * i);
++              }
+               for (i = 0; i < 4; i++)
+-                      hash_table[i] = 0;
++                      hash_table[i] = 0xffff;
++      }
+-              for (i = 0; i < dev->mc_count; i++) {
+-                      char *addrs = dmi->dmi_addr;
++      /* Use internal multicast address registers if the number of
++       * multicast addresses is not greater than MCAST_MAX. */
++      else if (dev->mc_count <= MCAST_MAX) {
++              i = 0;
++              while (i < dev->mc_count) {
++                      u16 *adrp = (u16 *)dmi->dmi_addr;
+                       dmi = dmi->next;
++                      iowrite16(adrp[0], ioaddr + MID_1L + 8 * i);
++                      iowrite16(adrp[1], ioaddr + MID_1M + 8 * i);
++                      iowrite16(adrp[2], ioaddr + MID_1H + 8 * i);
++                      i++;
++              }
++              while (i < MCAST_MAX) {
++                      iowrite16(0, ioaddr + MID_1L + 8 * i);
++                      iowrite16(0, ioaddr + MID_1M + 8 * i);
++                      iowrite16(0, ioaddr + MID_1H + 8 * i);
++                      i++;
++              }
++      }
++      /* Otherwise, Enable multicast hash table function. */
++      else {
++              u32 crc;
++
++              lp->mcr0 |= HASH_EN;
+-                      if (!(*addrs & 1))
+-                              continue;
++              for (i = 0; i < MCAST_MAX ; i++) {
++                      iowrite16(0, ioaddr + MID_1L + 8 * i);
++                      iowrite16(0, ioaddr + MID_1M + 8 * i);
++                      iowrite16(0, ioaddr + MID_1H + 8 * i);
++              }
++
++              /* Build multicast hash table */
++              for (i = 0; i < dev->mc_count; i++) {
++                      u8 *addrs = dmi->dmi_addr;
++                      dmi = dmi->next;
+-                      crc = ether_crc_le(6, addrs);
++                      crc = ether_crc(ETH_ALEN, addrs);
                        crc >>= 26;
-                       hash_table[crc >> 4] |= 1 << (15 - (crc & 0xf));
+-                      hash_table[crc >> 4] |= 1 << (15 - (crc & 0xf));
++                      hash_table[crc >> 4] |= 1 << (crc & 0xf);
                }
--              /* Write the index of the hash table */
--              for (i = 0; i < 4; i++)
--                      iowrite16(hash_table[i] << 14, ioaddr + MCR1);
-               /* Fill the MAC hash tables with their values */
+-              /* Fill the MAC hash tables with their values */
++      }
++      iowrite16(lp->mcr0, ioaddr + MCR0);
++
++      /* Fill the MAC hash tables with their values */
++      if (lp->mcr0 && HASH_EN) {
                iowrite16(hash_table[0], ioaddr + MAR0);
                iowrite16(hash_table[1], ioaddr + MAR1);
-@@ -905,9 +902,9 @@ static void r6040_multicast_list(struct 
-               dmi = dmi->next;
-       }
-       for (i = dev->mc_count; i < MCAST_MAX; i++) {
--              iowrite16(0xffff, ioaddr + MID_0L + 8*i);
--              iowrite16(0xffff, ioaddr + MID_0M + 8*i);
--              iowrite16(0xffff, ioaddr + MID_0H + 8*i);
-+              iowrite16(0xffff, ioaddr + MID_1L + 8 * i);
-+              iowrite16(0xffff, ioaddr + MID_1M + 8 * i);
-+              iowrite16(0xffff, ioaddr + MID_1H + 8 * i);
+               iowrite16(hash_table[2], ioaddr + MAR2);
+               iowrite16(hash_table[3], ioaddr + MAR3);
        }
+-      /* Multicast Address 1~4 case */
+-      dmi = dev->mc_list;
+-      for (i = 0, dmi; (i < dev->mc_count) && (i < MCAST_MAX); i++) {
+-              adrp = (u16 *)dmi->dmi_addr;
+-              iowrite16(adrp[0], ioaddr + MID_1L + 8*i);
+-              iowrite16(adrp[1], ioaddr + MID_1M + 8*i);
+-              iowrite16(adrp[2], ioaddr + MID_1H + 8*i);
+-              dmi = dmi->next;
+-      }
+-      for (i = dev->mc_count; i < MCAST_MAX; i++) {
+-              iowrite16(0xffff, ioaddr + MID_1L + 8*i);
+-              iowrite16(0xffff, ioaddr + MID_1M + 8*i);
+-              iowrite16(0xffff, ioaddr + MID_1H + 8*i);
+-      }
++
++      spin_unlock_irqrestore(&lp->lock, flags);
  }
  
+ static void netdev_get_drvinfo(struct net_device *dev,