Commit 193cfca5cc754b2a9b178a37f70fbb78d1731333

Authored by Shawn Lin
Committed by David S. Miller
1 parent e0c563101a

r6040: fix multicast operations

The original code does not work well when the number of mulitcast
address to handle is greater than MCAST_MAX. It only enable promiscous
mode instead of multicast hash table mode, so the hash table function
will not be activated and all multicast frames will be recieved in this
condition.

This patch fixes the following issues with the r6040 NIC operating in
multicast:

1) When the IFF_ALLMULTI flag is set, we should write 0xffff to the NIC
hash table registers to make it process multicast traffic.

2) When the number of multicast address to handle is smaller than
MCAST_MAX, we should use the NIC multicast registers MID1_{L,M,H}.

3) The hashing of the address was not correct, due to an invalid
substraction (15 - (crc & 0x0f)) instead of (crc & 0x0f) and an
incorrect crc algorithm (ether_crc_le) instead of (ether_crc).

4) If necessary, we should set HASH_EN flag in MCR0 to enable multicast
hash table function.

Reported-by: Marc Leclerc <marc-leclerc@signaturealpha.com>
Tested-by: Marc Leclerc <marc-leclerc@signaturealpha.com>
Signed-off-by: Shawn Lin <shawn@dmp.com.tw>
Signed-off-by: Albert Chen <albert.chen@rdc.com.tw>
Signed-off-by: Florian Fainelli <florian@openwrt.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

Showing 1 changed file with 64 additions and 47 deletions Side-by-side Diff

... ... @@ -69,6 +69,8 @@
69 69  
70 70 /* MAC registers */
71 71 #define MCR0 0x00 /* Control register 0 */
  72 +#define MCR0_PROMISC 0x0020 /* Promiscuous mode */
  73 +#define MCR0_HASH_EN 0x0100 /* Enable multicast hash table function */
72 74 #define MCR1 0x04 /* Control register 1 */
73 75 #define MAC_RST 0x0001 /* Reset the MAC */
74 76 #define MBCR 0x08 /* Bus control */
75 77  
76 78  
77 79  
78 80  
79 81  
80 82  
81 83  
82 84  
83 85  
84 86  
85 87  
86 88  
87 89  
88 90  
... ... @@ -851,77 +853,92 @@
851 853 {
852 854 struct r6040_private *lp = netdev_priv(dev);
853 855 void __iomem *ioaddr = lp->base;
854   - u16 *adrp;
855   - u16 reg;
856 856 unsigned long flags;
857 857 struct netdev_hw_addr *ha;
858 858 int i;
  859 + u16 *adrp;
  860 + u16 hash_table[4] = { 0 };
859 861  
860   - /* MAC Address */
  862 + spin_lock_irqsave(&lp->lock, flags);
  863 +
  864 + /* Keep our MAC Address */
861 865 adrp = (u16 *)dev->dev_addr;
862 866 iowrite16(adrp[0], ioaddr + MID_0L);
863 867 iowrite16(adrp[1], ioaddr + MID_0M);
864 868 iowrite16(adrp[2], ioaddr + MID_0H);
865 869  
866   - /* Promiscous Mode */
867   - spin_lock_irqsave(&lp->lock, flags);
868   -
869 870 /* Clear AMCP & PROM bits */
870   - reg = ioread16(ioaddr) & ~0x0120;
871   - if (dev->flags & IFF_PROMISC) {
872   - reg |= 0x0020;
873   - lp->mcr0 |= 0x0020;
874   - }
875   - /* Too many multicast addresses
876   - * accept all traffic */
877   - else if ((netdev_mc_count(dev) > MCAST_MAX) ||
878   - (dev->flags & IFF_ALLMULTI))
879   - reg |= 0x0020;
  871 + lp->mcr0 = ioread16(ioaddr + MCR0) & ~(MCR0_PROMISC | MCR0_HASH_EN);
880 872  
881   - iowrite16(reg, ioaddr);
882   - spin_unlock_irqrestore(&lp->lock, flags);
  873 + /* Promiscuous mode */
  874 + if (dev->flags & IFF_PROMISC)
  875 + lp->mcr0 |= MCR0_PROMISC;
883 876  
884   - /* Build the hash table */
885   - if (netdev_mc_count(dev) > MCAST_MAX) {
886   - u16 hash_table[4];
887   - u32 crc;
  877 + /* Enable multicast hash table function to
  878 + * receive all multicast packets. */
  879 + else if (dev->flags & IFF_ALLMULTI) {
  880 + lp->mcr0 |= MCR0_HASH_EN;
888 881  
889   - for (i = 0; i < 4; i++)
890   - hash_table[i] = 0;
  882 + for (i = 0; i < MCAST_MAX ; i++) {
  883 + iowrite16(0, ioaddr + MID_1L + 8 * i);
  884 + iowrite16(0, ioaddr + MID_1M + 8 * i);
  885 + iowrite16(0, ioaddr + MID_1H + 8 * i);
  886 + }
891 887  
  888 + for (i = 0; i < 4; i++)
  889 + hash_table[i] = 0xffff;
  890 + }
  891 + /* Use internal multicast address registers if the number of
  892 + * multicast addresses is not greater than MCAST_MAX. */
  893 + else if (netdev_mc_count(dev) <= MCAST_MAX) {
  894 + i = 0;
892 895 netdev_for_each_mc_addr(ha, dev) {
893   - char *addrs = ha->addr;
  896 + u16 *adrp = (u16 *) ha->addr;
  897 + iowrite16(adrp[0], ioaddr + MID_1L + 8 * i);
  898 + iowrite16(adrp[1], ioaddr + MID_1M + 8 * i);
  899 + iowrite16(adrp[2], ioaddr + MID_1H + 8 * i);
  900 + i++;
  901 + }
  902 + while (i < MCAST_MAX) {
  903 + iowrite16(0, ioaddr + MID_1L + 8 * i);
  904 + iowrite16(0, ioaddr + MID_1M + 8 * i);
  905 + iowrite16(0, ioaddr + MID_1H + 8 * i);
  906 + i++;
  907 + }
  908 + }
  909 + /* Otherwise, Enable multicast hash table function. */
  910 + else {
  911 + u32 crc;
894 912  
895   - if (!(*addrs & 1))
896   - continue;
  913 + lp->mcr0 |= MCR0_HASH_EN;
897 914  
898   - crc = ether_crc_le(6, addrs);
  915 + for (i = 0; i < MCAST_MAX ; i++) {
  916 + iowrite16(0, ioaddr + MID_1L + 8 * i);
  917 + iowrite16(0, ioaddr + MID_1M + 8 * i);
  918 + iowrite16(0, ioaddr + MID_1H + 8 * i);
  919 + }
  920 +
  921 + /* Build multicast hash table */
  922 + netdev_for_each_mc_addr(ha, dev) {
  923 + u8 *addrs = ha->addr;
  924 +
  925 + crc = ether_crc(ETH_ALEN, addrs);
899 926 crc >>= 26;
900   - hash_table[crc >> 4] |= 1 << (15 - (crc & 0xf));
  927 + hash_table[crc >> 4] |= 1 << (crc & 0xf);
901 928 }
902   - /* Fill the MAC hash tables with their values */
  929 + }
  930 +
  931 + iowrite16(lp->mcr0, ioaddr + MCR0);
  932 +
  933 + /* Fill the MAC hash tables with their values */
  934 + if (lp->mcr0 && MCR0_HASH_EN) {
903 935 iowrite16(hash_table[0], ioaddr + MAR0);
904 936 iowrite16(hash_table[1], ioaddr + MAR1);
905 937 iowrite16(hash_table[2], ioaddr + MAR2);
906 938 iowrite16(hash_table[3], ioaddr + MAR3);
907 939 }
908   - /* Multicast Address 1~4 case */
909   - i = 0;
910   - netdev_for_each_mc_addr(ha, dev) {
911   - if (i >= MCAST_MAX)
912   - break;
913   - adrp = (u16 *) ha->addr;
914   - iowrite16(adrp[0], ioaddr + MID_1L + 8 * i);
915   - iowrite16(adrp[1], ioaddr + MID_1M + 8 * i);
916   - iowrite16(adrp[2], ioaddr + MID_1H + 8 * i);
917   - i++;
918   - }
919   - while (i < MCAST_MAX) {
920   - iowrite16(0xffff, ioaddr + MID_1L + 8 * i);
921   - iowrite16(0xffff, ioaddr + MID_1M + 8 * i);
922   - iowrite16(0xffff, ioaddr + MID_1H + 8 * i);
923   - i++;
924   - }
  940 +
  941 + spin_unlock_irqrestore(&lp->lock, flags);
925 942 }
926 943  
927 944 static void netdev_get_drvinfo(struct net_device *dev,