]> Pileus Git - ~andy/linux/blobdiff - drivers/net/netxen/netxen_nic_main.c
netxen: enable ip addr hashing
[~andy/linux] / drivers / net / netxen / netxen_nic_main.c
index 4c7e4c28bf6bb7923fee2a528aaa82dea44d1e7e..b3683260a0b6a8168a59abedecf124d95b07003a 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/if_vlan.h>
 #include <net/ip.h>
 #include <linux/ipv6.h>
+#include <linux/inetdevice.h>
 
 MODULE_DESCRIPTION("NetXen Multi port (1/10) Gigabit Network Driver");
 MODULE_LICENSE("GPL");
@@ -1780,6 +1781,125 @@ static void netxen_nic_poll_controller(struct net_device *netdev)
 }
 #endif
 
+#define is_netxen_netdev(dev) (dev->netdev_ops == &netxen_netdev_ops)
+
+static int
+netxen_destip_supported(struct netxen_adapter *adapter)
+{
+       if (NX_IS_REVISION_P2(adapter->ahw.revision_id))
+               return 0;
+
+       if (adapter->ahw.cut_through)
+               return 0;
+
+       return 1;
+}
+
+static int netxen_netdev_event(struct notifier_block *this,
+                                unsigned long event, void *ptr)
+{
+       struct netxen_adapter *adapter;
+       struct net_device *dev = (struct net_device *)ptr;
+       struct in_device *indev;
+
+recheck:
+       if (dev == NULL)
+               goto done;
+
+       if (dev->priv_flags & IFF_802_1Q_VLAN) {
+               dev = vlan_dev_real_dev(dev);
+               goto recheck;
+       }
+
+       if (!is_netxen_netdev(dev))
+               goto done;
+
+       adapter = netdev_priv(dev);
+
+       if (!adapter || !netxen_destip_supported(adapter))
+               goto done;
+
+       if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC)
+               goto done;
+
+       indev = in_dev_get(dev);
+       if (!indev)
+               goto done;
+
+       for_ifa(indev) {
+               switch (event) {
+               case NETDEV_UP:
+                       netxen_config_ipaddr(adapter,
+                                       ifa->ifa_address, NX_IP_UP);
+                       break;
+               case NETDEV_DOWN:
+                       netxen_config_ipaddr(adapter,
+                                       ifa->ifa_address, NX_IP_DOWN);
+                       break;
+               default:
+                       break;
+               }
+       } endfor_ifa(indev);
+
+       in_dev_put(indev);
+done:
+       return NOTIFY_DONE;
+}
+
+static int
+netxen_inetaddr_event(struct notifier_block *this,
+               unsigned long event, void *ptr)
+{
+       struct netxen_adapter *adapter;
+       struct net_device *dev;
+
+       struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
+
+       dev = ifa->ifa_dev ? ifa->ifa_dev->dev : NULL;
+
+recheck:
+       if (dev == NULL || !netif_running(dev))
+               goto done;
+
+       if (dev->priv_flags & IFF_802_1Q_VLAN) {
+               dev = vlan_dev_real_dev(dev);
+               goto recheck;
+       }
+
+       if (!is_netxen_netdev(dev))
+               goto done;
+
+       adapter = netdev_priv(dev);
+
+       if (!adapter || !netxen_destip_supported(adapter))
+               goto done;
+
+       if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC)
+               goto done;
+
+       switch (event) {
+       case NETDEV_UP:
+               netxen_config_ipaddr(adapter, ifa->ifa_address, NX_IP_UP);
+               break;
+       case NETDEV_DOWN:
+               netxen_config_ipaddr(adapter, ifa->ifa_address, NX_IP_DOWN);
+               break;
+       default:
+               break;
+       }
+
+done:
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block   netxen_netdev_cb = {
+       .notifier_call = netxen_netdev_event,
+};
+
+static struct notifier_block netxen_inetaddr_cb = {
+       .notifier_call = netxen_inetaddr_event,
+};
+
 static struct pci_driver netxen_driver = {
        .name = netxen_nic_driver_name,
        .id_table = netxen_pci_tbl,
@@ -1800,6 +1920,9 @@ static int __init netxen_init_module(void)
        if ((netxen_workq = create_singlethread_workqueue("netxen")) == NULL)
                return -ENOMEM;
 
+       register_netdevice_notifier(&netxen_netdev_cb);
+       register_inetaddr_notifier(&netxen_inetaddr_cb);
+
        return pci_register_driver(&netxen_driver);
 }
 
@@ -1808,6 +1931,9 @@ module_init(netxen_init_module);
 static void __exit netxen_exit_module(void)
 {
        pci_unregister_driver(&netxen_driver);
+
+       unregister_inetaddr_notifier(&netxen_inetaddr_cb);
+       unregister_netdevice_notifier(&netxen_netdev_cb);
        destroy_workqueue(netxen_workq);
 }