Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: meth: Add set_rx_mode hook to fix ICMPv6 neighbor discovery

SGI IP32 (O2)'s ethernet driver (meth) lacks a set_rx_mode function, which
prevents IPv6 from working completely because any ICMPv6 neighbor
solicitation requests aren't picked up by the driver. So the machine can
ping out and connect to other systems, but other systems will have a very
hard time connecting to the O2.

Signed-off-by: Joshua Kinard <kumba@gentoo.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Joshua Kinard and committed by
David S. Miller
c0d2b837 65cb5df5

+48 -2
+1 -1
arch/mips/include/asm/ip32/mace.h
··· 95 95 * Ethernet interface 96 96 */ 97 97 struct mace_ethernet { 98 - volatile unsigned long mac_ctrl; 98 + volatile u64 mac_ctrl; 99 99 volatile unsigned long int_stat; 100 100 volatile unsigned long dma_ctrl; 101 101 volatile unsigned long timer;
+47 -1
drivers/net/ethernet/sgi/meth.c
··· 28 28 #include <linux/tcp.h> /* struct tcphdr */ 29 29 #include <linux/skbuff.h> 30 30 #include <linux/mii.h> /* MII definitions */ 31 + #include <linux/crc32.h> 31 32 32 33 #include <asm/ip32/mace.h> 33 34 #include <asm/ip32/ip32_ints.h> ··· 59 58 module_param(timeout, int, 0); 60 59 61 60 /* 61 + * Maximum number of multicast addresses to filter (vs. Rx-all-multicast). 62 + * MACE Ethernet uses a 64 element hash table based on the Ethernet CRC. 63 + */ 64 + #define METH_MCF_LIMIT 32 65 + 66 + /* 62 67 * This structure is private to each device. It is used to pass 63 68 * packets in and out, so there is place for a packet 64 69 */ 65 70 struct meth_private { 66 71 /* in-memory copy of MAC Control register */ 67 - unsigned long mac_ctrl; 72 + u64 mac_ctrl; 73 + 68 74 /* in-memory copy of DMA Control register */ 69 75 unsigned long dma_ctrl; 70 76 /* address of PHY, used by mdio_* functions, initialized in mdio_probe */ ··· 86 78 dma_addr_t rx_ring_dmas[RX_RING_ENTRIES]; 87 79 struct sk_buff *rx_skbs[RX_RING_ENTRIES]; 88 80 unsigned long rx_write; 81 + 82 + /* Multicast filter. */ 83 + u64 mcast_filter; 89 84 90 85 spinlock_t meth_lock; 91 86 }; ··· 776 765 } 777 766 } 778 767 768 + static void meth_set_rx_mode(struct net_device *dev) 769 + { 770 + struct meth_private *priv = netdev_priv(dev); 771 + unsigned long flags; 772 + 773 + netif_stop_queue(dev); 774 + spin_lock_irqsave(&priv->meth_lock, flags); 775 + priv->mac_ctrl &= ~METH_PROMISC; 776 + 777 + if (dev->flags & IFF_PROMISC) { 778 + priv->mac_ctrl |= METH_PROMISC; 779 + priv->mcast_filter = 0xffffffffffffffffUL; 780 + } else if ((netdev_mc_count(dev) > METH_MCF_LIMIT) || 781 + (dev->flags & IFF_ALLMULTI)) { 782 + priv->mac_ctrl |= METH_ACCEPT_AMCAST; 783 + priv->mcast_filter = 0xffffffffffffffffUL; 784 + } else { 785 + struct netdev_hw_addr *ha; 786 + priv->mac_ctrl |= METH_ACCEPT_MCAST; 787 + 788 + netdev_for_each_mc_addr(ha, dev) 789 + set_bit((ether_crc(ETH_ALEN, ha->addr) >> 26), 790 + (volatile unsigned long *)&priv->mcast_filter); 791 + } 792 + 793 + /* Write the changes to the chip registers. */ 794 + mace->eth.mac_ctrl = priv->mac_ctrl; 795 + mace->eth.mcast_filter = priv->mcast_filter; 796 + 797 + /* Done! */ 798 + spin_unlock_irqrestore(&priv->meth_lock, flags); 799 + netif_wake_queue(dev); 800 + } 801 + 779 802 static const struct net_device_ops meth_netdev_ops = { 780 803 .ndo_open = meth_open, 781 804 .ndo_stop = meth_release, ··· 819 774 .ndo_change_mtu = eth_change_mtu, 820 775 .ndo_validate_addr = eth_validate_addr, 821 776 .ndo_set_mac_address = eth_mac_addr, 777 + .ndo_set_rx_mode = meth_set_rx_mode, 822 778 }; 823 779 824 780 /*