diff options
author | Patrice Vilchez <patrice.vilchez@rfo.atmel.com> | 2007-07-12 13:07:25 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2007-07-16 18:28:04 -0400 |
commit | 446ebd0118d8e82791652bd17dd8db08ab993c0e (patch) | |
tree | a1a48ff7a609ee1195c95180f37144483bfbbdf4 /drivers/net | |
parent | 6c36a7074436e181fb3df41f66bbdaf53980951e (diff) |
macb: Add multicast capability
Add multicast capability to Atmel ethernet macb driver.
Signed-off-by: Patrice Vilchez <patrice.vilchez@rfo.atmel.com>
Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/macb.c | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 83c35fd91e0f..a4bb0264180a 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c | |||
@@ -796,6 +796,125 @@ static void macb_init_hw(struct macb *bp) | |||
796 | 796 | ||
797 | } | 797 | } |
798 | 798 | ||
799 | /* | ||
800 | * The hash address register is 64 bits long and takes up two | ||
801 | * locations in the memory map. The least significant bits are stored | ||
802 | * in EMAC_HSL and the most significant bits in EMAC_HSH. | ||
803 | * | ||
804 | * The unicast hash enable and the multicast hash enable bits in the | ||
805 | * network configuration register enable the reception of hash matched | ||
806 | * frames. The destination address is reduced to a 6 bit index into | ||
807 | * the 64 bit hash register using the following hash function. The | ||
808 | * hash function is an exclusive or of every sixth bit of the | ||
809 | * destination address. | ||
810 | * | ||
811 | * hi[5] = da[5] ^ da[11] ^ da[17] ^ da[23] ^ da[29] ^ da[35] ^ da[41] ^ da[47] | ||
812 | * hi[4] = da[4] ^ da[10] ^ da[16] ^ da[22] ^ da[28] ^ da[34] ^ da[40] ^ da[46] | ||
813 | * hi[3] = da[3] ^ da[09] ^ da[15] ^ da[21] ^ da[27] ^ da[33] ^ da[39] ^ da[45] | ||
814 | * hi[2] = da[2] ^ da[08] ^ da[14] ^ da[20] ^ da[26] ^ da[32] ^ da[38] ^ da[44] | ||
815 | * hi[1] = da[1] ^ da[07] ^ da[13] ^ da[19] ^ da[25] ^ da[31] ^ da[37] ^ da[43] | ||
816 | * hi[0] = da[0] ^ da[06] ^ da[12] ^ da[18] ^ da[24] ^ da[30] ^ da[36] ^ da[42] | ||
817 | * | ||
818 | * da[0] represents the least significant bit of the first byte | ||
819 | * received, that is, the multicast/unicast indicator, and da[47] | ||
820 | * represents the most significant bit of the last byte received. If | ||
821 | * the hash index, hi[n], points to a bit that is set in the hash | ||
822 | * register then the frame will be matched according to whether the | ||
823 | * frame is multicast or unicast. A multicast match will be signalled | ||
824 | * if the multicast hash enable bit is set, da[0] is 1 and the hash | ||
825 | * index points to a bit set in the hash register. A unicast match | ||
826 | * will be signalled if the unicast hash enable bit is set, da[0] is 0 | ||
827 | * and the hash index points to a bit set in the hash register. To | ||
828 | * receive all multicast frames, the hash register should be set with | ||
829 | * all ones and the multicast hash enable bit should be set in the | ||
830 | * network configuration register. | ||
831 | */ | ||
832 | |||
833 | static inline int hash_bit_value(int bitnr, __u8 *addr) | ||
834 | { | ||
835 | if (addr[bitnr / 8] & (1 << (bitnr % 8))) | ||
836 | return 1; | ||
837 | return 0; | ||
838 | } | ||
839 | |||
840 | /* | ||
841 | * Return the hash index value for the specified address. | ||
842 | */ | ||
843 | static int hash_get_index(__u8 *addr) | ||
844 | { | ||
845 | int i, j, bitval; | ||
846 | int hash_index = 0; | ||
847 | |||
848 | for (j = 0; j < 6; j++) { | ||
849 | for (i = 0, bitval = 0; i < 8; i++) | ||
850 | bitval ^= hash_bit_value(i*6 + j, addr); | ||
851 | |||
852 | hash_index |= (bitval << j); | ||
853 | } | ||
854 | |||
855 | return hash_index; | ||
856 | } | ||
857 | |||
858 | /* | ||
859 | * Add multicast addresses to the internal multicast-hash table. | ||
860 | */ | ||
861 | static void macb_sethashtable(struct net_device *dev) | ||
862 | { | ||
863 | struct dev_mc_list *curr; | ||
864 | unsigned long mc_filter[2]; | ||
865 | unsigned int i, bitnr; | ||
866 | struct macb *bp = netdev_priv(dev); | ||
867 | |||
868 | mc_filter[0] = mc_filter[1] = 0; | ||
869 | |||
870 | curr = dev->mc_list; | ||
871 | for (i = 0; i < dev->mc_count; i++, curr = curr->next) { | ||
872 | if (!curr) break; /* unexpected end of list */ | ||
873 | |||
874 | bitnr = hash_get_index(curr->dmi_addr); | ||
875 | mc_filter[bitnr >> 5] |= 1 << (bitnr & 31); | ||
876 | } | ||
877 | |||
878 | macb_writel(bp, HRB, mc_filter[0]); | ||
879 | macb_writel(bp, HRT, mc_filter[1]); | ||
880 | } | ||
881 | |||
882 | /* | ||
883 | * Enable/Disable promiscuous and multicast modes. | ||
884 | */ | ||
885 | static void macb_set_rx_mode(struct net_device *dev) | ||
886 | { | ||
887 | unsigned long cfg; | ||
888 | struct macb *bp = netdev_priv(dev); | ||
889 | |||
890 | cfg = macb_readl(bp, NCFGR); | ||
891 | |||
892 | if (dev->flags & IFF_PROMISC) | ||
893 | /* Enable promiscuous mode */ | ||
894 | cfg |= MACB_BIT(CAF); | ||
895 | else if (dev->flags & (~IFF_PROMISC)) | ||
896 | /* Disable promiscuous mode */ | ||
897 | cfg &= ~MACB_BIT(CAF); | ||
898 | |||
899 | if (dev->flags & IFF_ALLMULTI) { | ||
900 | /* Enable all multicast mode */ | ||
901 | macb_writel(bp, HRB, -1); | ||
902 | macb_writel(bp, HRT, -1); | ||
903 | cfg |= MACB_BIT(NCFGR_MTI); | ||
904 | } else if (dev->mc_count > 0) { | ||
905 | /* Enable specific multicasts */ | ||
906 | macb_sethashtable(dev); | ||
907 | cfg |= MACB_BIT(NCFGR_MTI); | ||
908 | } else if (dev->flags & (~IFF_ALLMULTI)) { | ||
909 | /* Disable all multicast mode */ | ||
910 | macb_writel(bp, HRB, 0); | ||
911 | macb_writel(bp, HRT, 0); | ||
912 | cfg &= ~MACB_BIT(NCFGR_MTI); | ||
913 | } | ||
914 | |||
915 | macb_writel(bp, NCFGR, cfg); | ||
916 | } | ||
917 | |||
799 | static int macb_open(struct net_device *dev) | 918 | static int macb_open(struct net_device *dev) |
800 | { | 919 | { |
801 | struct macb *bp = netdev_priv(dev); | 920 | struct macb *bp = netdev_priv(dev); |
@@ -1025,6 +1144,7 @@ static int __devinit macb_probe(struct platform_device *pdev) | |||
1025 | dev->stop = macb_close; | 1144 | dev->stop = macb_close; |
1026 | dev->hard_start_xmit = macb_start_xmit; | 1145 | dev->hard_start_xmit = macb_start_xmit; |
1027 | dev->get_stats = macb_get_stats; | 1146 | dev->get_stats = macb_get_stats; |
1147 | dev->set_multicast_list = macb_set_rx_mode; | ||
1028 | dev->do_ioctl = macb_ioctl; | 1148 | dev->do_ioctl = macb_ioctl; |
1029 | dev->poll = macb_poll; | 1149 | dev->poll = macb_poll; |
1030 | dev->weight = 64; | 1150 | dev->weight = 64; |