diff options
Diffstat (limited to 'drivers/net/r6040.c')
-rw-r--r-- | drivers/net/r6040.c | 111 |
1 files changed, 64 insertions, 47 deletions
diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c index 27e6f6d43cac..7965ae42eae4 100644 --- a/drivers/net/r6040.c +++ b/drivers/net/r6040.c | |||
@@ -69,6 +69,8 @@ | |||
69 | 69 | ||
70 | /* MAC registers */ | 70 | /* MAC registers */ |
71 | #define MCR0 0x00 /* Control register 0 */ | 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 | #define MCR1 0x04 /* Control register 1 */ | 74 | #define MCR1 0x04 /* Control register 1 */ |
73 | #define MAC_RST 0x0001 /* Reset the MAC */ | 75 | #define MAC_RST 0x0001 /* Reset the MAC */ |
74 | #define MBCR 0x08 /* Bus control */ | 76 | #define MBCR 0x08 /* Bus control */ |
@@ -851,77 +853,92 @@ static void r6040_multicast_list(struct net_device *dev) | |||
851 | { | 853 | { |
852 | struct r6040_private *lp = netdev_priv(dev); | 854 | struct r6040_private *lp = netdev_priv(dev); |
853 | void __iomem *ioaddr = lp->base; | 855 | void __iomem *ioaddr = lp->base; |
854 | u16 *adrp; | ||
855 | u16 reg; | ||
856 | unsigned long flags; | 856 | unsigned long flags; |
857 | struct netdev_hw_addr *ha; | 857 | struct netdev_hw_addr *ha; |
858 | int i; | 858 | int i; |
859 | u16 *adrp; | ||
860 | u16 hash_table[4] = { 0 }; | ||
861 | |||
862 | spin_lock_irqsave(&lp->lock, flags); | ||
859 | 863 | ||
860 | /* MAC Address */ | 864 | /* Keep our MAC Address */ |
861 | adrp = (u16 *)dev->dev_addr; | 865 | adrp = (u16 *)dev->dev_addr; |
862 | iowrite16(adrp[0], ioaddr + MID_0L); | 866 | iowrite16(adrp[0], ioaddr + MID_0L); |
863 | iowrite16(adrp[1], ioaddr + MID_0M); | 867 | iowrite16(adrp[1], ioaddr + MID_0M); |
864 | iowrite16(adrp[2], ioaddr + MID_0H); | 868 | iowrite16(adrp[2], ioaddr + MID_0H); |
865 | 869 | ||
866 | /* Promiscous Mode */ | ||
867 | spin_lock_irqsave(&lp->lock, flags); | ||
868 | |||
869 | /* Clear AMCP & PROM bits */ | 870 | /* Clear AMCP & PROM bits */ |
870 | reg = ioread16(ioaddr) & ~0x0120; | 871 | lp->mcr0 = ioread16(ioaddr + MCR0) & ~(MCR0_PROMISC | MCR0_HASH_EN); |
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; | ||
880 | 872 | ||
881 | iowrite16(reg, ioaddr); | 873 | /* Promiscuous mode */ |
882 | spin_unlock_irqrestore(&lp->lock, flags); | 874 | if (dev->flags & IFF_PROMISC) |
875 | lp->mcr0 |= MCR0_PROMISC; | ||
883 | 876 | ||
884 | /* Build the hash table */ | 877 | /* Enable multicast hash table function to |
885 | if (netdev_mc_count(dev) > MCAST_MAX) { | 878 | * receive all multicast packets. */ |
886 | u16 hash_table[4]; | 879 | else if (dev->flags & IFF_ALLMULTI) { |
887 | u32 crc; | 880 | lp->mcr0 |= MCR0_HASH_EN; |
888 | 881 | ||
889 | for (i = 0; i < 4; i++) | 882 | for (i = 0; i < MCAST_MAX ; i++) { |
890 | hash_table[i] = 0; | 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 | netdev_for_each_mc_addr(ha, dev) { | 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)) | 913 | lp->mcr0 |= MCR0_HASH_EN; |
896 | continue; | 914 | |
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 | } | ||
897 | 920 | ||
898 | crc = ether_crc_le(6, addrs); | 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 | crc >>= 26; | 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 | iowrite16(hash_table[0], ioaddr + MAR0); | 935 | iowrite16(hash_table[0], ioaddr + MAR0); |
904 | iowrite16(hash_table[1], ioaddr + MAR1); | 936 | iowrite16(hash_table[1], ioaddr + MAR1); |
905 | iowrite16(hash_table[2], ioaddr + MAR2); | 937 | iowrite16(hash_table[2], ioaddr + MAR2); |
906 | iowrite16(hash_table[3], ioaddr + MAR3); | 938 | iowrite16(hash_table[3], ioaddr + MAR3); |
907 | } | 939 | } |
908 | /* Multicast Address 1~4 case */ | 940 | |
909 | i = 0; | 941 | spin_unlock_irqrestore(&lp->lock, flags); |
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 | } | ||
925 | } | 942 | } |
926 | 943 | ||
927 | static void netdev_get_drvinfo(struct net_device *dev, | 944 | static void netdev_get_drvinfo(struct net_device *dev, |