aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoshua Kinard <kumba@gentoo.org>2011-12-26 14:06:15 -0500
committerDavid S. Miller <davem@davemloft.net>2011-12-27 13:17:34 -0500
commitc0d2b8376ae2d74aa862e946a372502603e9066d (patch)
tree5ae45fb9c4e1823a43ba5b3082fa68f39e93e864
parent65cb5df51acaa6b1070a81d6c2e0a1535d3a7b8d (diff)
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>
-rw-r--r--arch/mips/include/asm/ip32/mace.h2
-rw-r--r--drivers/net/ethernet/sgi/meth.c48
2 files changed, 48 insertions, 2 deletions
diff --git a/arch/mips/include/asm/ip32/mace.h b/arch/mips/include/asm/ip32/mace.h
index d08d7c672139..c523123df380 100644
--- a/arch/mips/include/asm/ip32/mace.h
+++ b/arch/mips/include/asm/ip32/mace.h
@@ -95,7 +95,7 @@ struct mace_video {
95 * Ethernet interface 95 * Ethernet interface
96 */ 96 */
97struct mace_ethernet { 97struct mace_ethernet {
98 volatile unsigned long mac_ctrl; 98 volatile u64 mac_ctrl;
99 volatile unsigned long int_stat; 99 volatile unsigned long int_stat;
100 volatile unsigned long dma_ctrl; 100 volatile unsigned long dma_ctrl;
101 volatile unsigned long timer; 101 volatile unsigned long timer;
diff --git a/drivers/net/ethernet/sgi/meth.c b/drivers/net/ethernet/sgi/meth.c
index f98c6c6eedcd..53efe7c7b1c0 100644
--- a/drivers/net/ethernet/sgi/meth.c
+++ b/drivers/net/ethernet/sgi/meth.c
@@ -28,6 +28,7 @@
28#include <linux/tcp.h> /* struct tcphdr */ 28#include <linux/tcp.h> /* struct tcphdr */
29#include <linux/skbuff.h> 29#include <linux/skbuff.h>
30#include <linux/mii.h> /* MII definitions */ 30#include <linux/mii.h> /* MII definitions */
31#include <linux/crc32.h>
31 32
32#include <asm/ip32/mace.h> 33#include <asm/ip32/mace.h>
33#include <asm/ip32/ip32_ints.h> 34#include <asm/ip32/ip32_ints.h>
@@ -58,12 +59,19 @@ static int timeout = TX_TIMEOUT;
58module_param(timeout, int, 0); 59module_param(timeout, int, 0);
59 60
60/* 61/*
62 * Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
63 * MACE Ethernet uses a 64 element hash table based on the Ethernet CRC.
64 */
65#define METH_MCF_LIMIT 32
66
67/*
61 * This structure is private to each device. It is used to pass 68 * This structure is private to each device. It is used to pass
62 * packets in and out, so there is place for a packet 69 * packets in and out, so there is place for a packet
63 */ 70 */
64struct meth_private { 71struct meth_private {
65 /* in-memory copy of MAC Control register */ 72 /* in-memory copy of MAC Control register */
66 unsigned long mac_ctrl; 73 u64 mac_ctrl;
74
67 /* in-memory copy of DMA Control register */ 75 /* in-memory copy of DMA Control register */
68 unsigned long dma_ctrl; 76 unsigned long dma_ctrl;
69 /* address of PHY, used by mdio_* functions, initialized in mdio_probe */ 77 /* address of PHY, used by mdio_* functions, initialized in mdio_probe */
@@ -79,6 +87,9 @@ struct meth_private {
79 struct sk_buff *rx_skbs[RX_RING_ENTRIES]; 87 struct sk_buff *rx_skbs[RX_RING_ENTRIES];
80 unsigned long rx_write; 88 unsigned long rx_write;
81 89
90 /* Multicast filter. */
91 u64 mcast_filter;
92
82 spinlock_t meth_lock; 93 spinlock_t meth_lock;
83}; 94};
84 95
@@ -765,6 +776,40 @@ static int meth_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
765 } 776 }
766} 777}
767 778
779static void meth_set_rx_mode(struct net_device *dev)
780{
781 struct meth_private *priv = netdev_priv(dev);
782 unsigned long flags;
783
784 netif_stop_queue(dev);
785 spin_lock_irqsave(&priv->meth_lock, flags);
786 priv->mac_ctrl &= ~METH_PROMISC;
787
788 if (dev->flags & IFF_PROMISC) {
789 priv->mac_ctrl |= METH_PROMISC;
790 priv->mcast_filter = 0xffffffffffffffffUL;
791 } else if ((netdev_mc_count(dev) > METH_MCF_LIMIT) ||
792 (dev->flags & IFF_ALLMULTI)) {
793 priv->mac_ctrl |= METH_ACCEPT_AMCAST;
794 priv->mcast_filter = 0xffffffffffffffffUL;
795 } else {
796 struct netdev_hw_addr *ha;
797 priv->mac_ctrl |= METH_ACCEPT_MCAST;
798
799 netdev_for_each_mc_addr(ha, dev)
800 set_bit((ether_crc(ETH_ALEN, ha->addr) >> 26),
801 (volatile unsigned long *)&priv->mcast_filter);
802 }
803
804 /* Write the changes to the chip registers. */
805 mace->eth.mac_ctrl = priv->mac_ctrl;
806 mace->eth.mcast_filter = priv->mcast_filter;
807
808 /* Done! */
809 spin_unlock_irqrestore(&priv->meth_lock, flags);
810 netif_wake_queue(dev);
811}
812
768static const struct net_device_ops meth_netdev_ops = { 813static const struct net_device_ops meth_netdev_ops = {
769 .ndo_open = meth_open, 814 .ndo_open = meth_open,
770 .ndo_stop = meth_release, 815 .ndo_stop = meth_release,
@@ -774,6 +819,7 @@ static const struct net_device_ops meth_netdev_ops = {
774 .ndo_change_mtu = eth_change_mtu, 819 .ndo_change_mtu = eth_change_mtu,
775 .ndo_validate_addr = eth_validate_addr, 820 .ndo_validate_addr = eth_validate_addr,
776 .ndo_set_mac_address = eth_mac_addr, 821 .ndo_set_mac_address = eth_mac_addr,
822 .ndo_set_rx_mode = meth_set_rx_mode,
777}; 823};
778 824
779/* 825/*