aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorPatrice Vilchez <patrice.vilchez@rfo.atmel.com>2007-07-12 13:07:25 -0400
committerJeff Garzik <jeff@garzik.org>2007-07-16 18:28:04 -0400
commit446ebd0118d8e82791652bd17dd8db08ab993c0e (patch)
treea1a48ff7a609ee1195c95180f37144483bfbbdf4 /drivers/net
parent6c36a7074436e181fb3df41f66bbdaf53980951e (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.c120
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
833static 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 */
843static 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 */
861static 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 */
885static 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
799static int macb_open(struct net_device *dev) 918static 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;