]> err.no Git - linux-2.6/blobdiff - drivers/net/ehea/ehea_main.c
Merge commit 'v2.6.26' into core/locking
[linux-2.6] / drivers / net / ehea / ehea_main.c
index f460b623c0771356acca11780e06b62efac2e0c4..0920b796bd78375b17c679861a30e50338c9c3c7 100644 (file)
@@ -35,7 +35,9 @@
 #include <linux/if_ether.h>
 #include <linux/notifier.h>
 #include <linux/reboot.h>
+#include <linux/memory.h>
 #include <asm/kexec.h>
+#include <linux/mutex.h>
 
 #include <net/ip.h>
 
@@ -99,7 +101,7 @@ static int port_name_cnt;
 static LIST_HEAD(adapter_list);
 u64 ehea_driver_flags;
 struct work_struct ehea_rereg_mr_task;
-struct semaphore dlpar_mem_lock;
+static DEFINE_MUTEX(dlpar_mem_lock);
 struct ehea_fw_handle_array ehea_fw_handles;
 struct ehea_bcmc_reg_array ehea_bcmc_regs;
 
@@ -116,6 +118,7 @@ static struct of_device_id ehea_device_table[] = {
        },
        {},
 };
+MODULE_DEVICE_TABLE(of, ehea_device_table);
 
 static struct of_platform_driver ehea_driver = {
        .name = "ehea",
@@ -135,6 +138,12 @@ void ehea_dump(void *adr, int len, char *msg)
        }
 }
 
+void ehea_schedule_port_reset(struct ehea_port *port)
+{
+       if (!test_bit(__EHEA_DISABLE_PORT_RESET, &port->flags))
+               schedule_work(&port->reset_task);
+}
+
 static void ehea_update_firmware_handles(void)
 {
        struct ehea_fw_handle_entry *arr = NULL;
@@ -239,7 +248,7 @@ static void ehea_update_bcmc_registrations(void)
                }
 
        if (num_registrations) {
-               arr = kzalloc(num_registrations * sizeof(*arr), GFP_KERNEL);
+               arr = kzalloc(num_registrations * sizeof(*arr), GFP_ATOMIC);
                if (!arr)
                        return;  /* Keep the existing array */
        } else
@@ -299,7 +308,7 @@ static struct net_device_stats *ehea_get_stats(struct net_device *dev)
 
        memset(stats, 0, sizeof(*stats));
 
-       cb2 = kzalloc(PAGE_SIZE, GFP_KERNEL);
+       cb2 = kzalloc(PAGE_SIZE, GFP_ATOMIC);
        if (!cb2) {
                ehea_error("no mem for cb2");
                goto out;
@@ -585,7 +594,7 @@ static int ehea_treat_poll_error(struct ehea_port_res *pr, int rq,
                                   "Resetting port.", pr->qp->init_attr.qp_nr);
                        ehea_dump(cqe, sizeof(*cqe), "CQE");
                }
-               schedule_work(&pr->port->reset_task);
+               ehea_schedule_port_reset(pr->port);
                return 1;
        }
 
@@ -614,7 +623,7 @@ static int get_skb_hdr(struct sk_buff *skb, void **iphdr,
        *tcph = tcp_hdr(skb);
 
        /* check if ip header and tcp header are complete */
-       if (iph->tot_len < ip_len + tcp_hdrlen(skb))
+       if (ntohs(iph->tot_len) < ip_len + tcp_hdrlen(skb))
                return -1;
 
        *hdr_flags = LRO_IPV4 | LRO_TCP;
@@ -763,7 +772,7 @@ static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota)
                        ehea_error("Send Completion Error: Resetting port");
                        if (netif_msg_tx_err(pr->port))
                                ehea_dump(cqe, sizeof(*cqe), "Send CQE");
-                       schedule_work(&pr->port->reset_task);
+                       ehea_schedule_port_reset(pr->port);
                        break;
                }
 
@@ -883,7 +892,7 @@ static irqreturn_t ehea_qp_aff_irq_handler(int irq, void *param)
                eqe = ehea_poll_eq(port->qp_eq);
        }
 
-       schedule_work(&port->reset_task);
+       ehea_schedule_port_reset(port);
 
        return IRQ_HANDLED;
 }
@@ -1761,25 +1770,29 @@ static int ehea_set_mac_addr(struct net_device *dev, void *sa)
 
        memcpy(dev->dev_addr, mac_addr->sa_data, dev->addr_len);
 
-       down(&ehea_bcmc_regs.lock);
+       spin_lock(&ehea_bcmc_regs.lock);
 
        /* Deregister old MAC in pHYP */
-       ret = ehea_broadcast_reg_helper(port, H_DEREG_BCMC);
-       if (ret)
-               goto out_upregs;
+       if (port->state == EHEA_PORT_UP) {
+               ret = ehea_broadcast_reg_helper(port, H_DEREG_BCMC);
+               if (ret)
+                       goto out_upregs;
+       }
 
        port->mac_addr = cb0->port_mac_addr << 16;
 
        /* Register new MAC in pHYP */
-       ret = ehea_broadcast_reg_helper(port, H_REG_BCMC);
-       if (ret)
-               goto out_upregs;
+       if (port->state == EHEA_PORT_UP) {
+               ret = ehea_broadcast_reg_helper(port, H_REG_BCMC);
+               if (ret)
+                       goto out_upregs;
+       }
 
        ret = 0;
 
 out_upregs:
        ehea_update_bcmc_registrations();
-       up(&ehea_bcmc_regs.lock);
+       spin_unlock(&ehea_bcmc_regs.lock);
 out_free:
        kfree(cb0);
 out:
@@ -1941,7 +1954,7 @@ static void ehea_set_multicast_list(struct net_device *dev)
        }
        ehea_promiscuous(dev, 0);
 
-       down(&ehea_bcmc_regs.lock);
+       spin_lock(&ehea_bcmc_regs.lock);
 
        if (dev->flags & IFF_ALLMULTI) {
                ehea_allmulti(dev, 1);
@@ -1972,7 +1985,7 @@ static void ehea_set_multicast_list(struct net_device *dev)
        }
 out:
        ehea_update_bcmc_registrations();
-       up(&ehea_bcmc_regs.lock);
+       spin_unlock(&ehea_bcmc_regs.lock);
        return;
 }
 
@@ -2211,8 +2224,6 @@ static void ehea_vlan_rx_register(struct net_device *dev,
                goto out;
        }
 
-       memset(cb1->vlan_filter, 0, sizeof(cb1->vlan_filter));
-
        hret = ehea_h_modify_ehea_port(adapter->handle, port->logical_port_id,
                                       H_PORT_CB1, H_PORT_CB1_ALL, cb1);
        if (hret != H_SUCCESS)
@@ -2455,7 +2466,7 @@ static int ehea_up(struct net_device *dev)
        if (port->state == EHEA_PORT_UP)
                return 0;
 
-       down(&ehea_fw_handles.lock);
+       mutex_lock(&ehea_fw_handles.lock);
 
        ret = ehea_port_res_setup(port, port->num_def_qps,
                                  port->num_add_tx_qps);
@@ -2493,7 +2504,7 @@ static int ehea_up(struct net_device *dev)
                }
        }
 
-       down(&ehea_bcmc_regs.lock);
+       spin_lock(&ehea_bcmc_regs.lock);
 
        ret = ehea_broadcast_reg_helper(port, H_REG_BCMC);
        if (ret) {
@@ -2516,10 +2527,10 @@ out:
                ehea_info("Failed starting %s. ret=%i", dev->name, ret);
 
        ehea_update_bcmc_registrations();
-       up(&ehea_bcmc_regs.lock);
+       spin_unlock(&ehea_bcmc_regs.lock);
 
        ehea_update_firmware_handles();
-       up(&ehea_fw_handles.lock);
+       mutex_unlock(&ehea_fw_handles.lock);
 
        return ret;
 }
@@ -2545,7 +2556,7 @@ static int ehea_open(struct net_device *dev)
        int ret;
        struct ehea_port *port = netdev_priv(dev);
 
-       down(&port->port_lock);
+       mutex_lock(&port->port_lock);
 
        if (netif_msg_ifup(port))
                ehea_info("enabling port %s", dev->name);
@@ -2556,7 +2567,7 @@ static int ehea_open(struct net_device *dev)
                netif_start_queue(dev);
        }
 
-       up(&port->port_lock);
+       mutex_unlock(&port->port_lock);
 
        return ret;
 }
@@ -2569,18 +2580,18 @@ static int ehea_down(struct net_device *dev)
        if (port->state == EHEA_PORT_DOWN)
                return 0;
 
-       down(&ehea_bcmc_regs.lock);
+       mutex_lock(&ehea_fw_handles.lock);
+
+       spin_lock(&ehea_bcmc_regs.lock);
        ehea_drop_multicast_list(dev);
        ehea_broadcast_reg_helper(port, H_DEREG_BCMC);
 
        ehea_free_interrupts(dev);
 
-       down(&ehea_fw_handles.lock);
-
        port->state = EHEA_PORT_DOWN;
 
        ehea_update_bcmc_registrations();
-       up(&ehea_bcmc_regs.lock);
+       spin_unlock(&ehea_bcmc_regs.lock);
 
        ret = ehea_clean_all_portres(port);
        if (ret)
@@ -2588,7 +2599,7 @@ static int ehea_down(struct net_device *dev)
                          dev->name, ret);
 
        ehea_update_firmware_handles();
-       up(&ehea_fw_handles.lock);
+       mutex_unlock(&ehea_fw_handles.lock);
 
        return ret;
 }
@@ -2601,16 +2612,18 @@ static int ehea_stop(struct net_device *dev)
        if (netif_msg_ifdown(port))
                ehea_info("disabling port %s", dev->name);
 
-       flush_scheduled_work();
-       down(&port->port_lock);
+       set_bit(__EHEA_DISABLE_PORT_RESET, &port->flags);
+       cancel_work_sync(&port->reset_task);
+       mutex_lock(&port->port_lock);
        netif_stop_queue(dev);
        port_napi_disable(port);
        ret = ehea_down(dev);
-       up(&port->port_lock);
+       mutex_unlock(&port->port_lock);
+       clear_bit(__EHEA_DISABLE_PORT_RESET, &port->flags);
        return ret;
 }
 
-void ehea_purge_sq(struct ehea_qp *orig_qp)
+static void ehea_purge_sq(struct ehea_qp *orig_qp)
 {
        struct ehea_qp qp = *orig_qp;
        struct ehea_qp_init_attr *init_attr = &qp.init_attr;
@@ -2624,7 +2637,7 @@ void ehea_purge_sq(struct ehea_qp *orig_qp)
        }
 }
 
-void ehea_flush_sq(struct ehea_port *port)
+static void ehea_flush_sq(struct ehea_port *port)
 {
        int i;
 
@@ -2820,7 +2833,7 @@ static void ehea_reset_port(struct work_struct *work)
        struct net_device *dev = port->netdev;
 
        port->resets++;
-       down(&port->port_lock);
+       mutex_lock(&port->port_lock);
        netif_stop_queue(dev);
 
        port_napi_disable(port);
@@ -2840,7 +2853,7 @@ static void ehea_reset_port(struct work_struct *work)
 
        netif_wake_queue(dev);
 out:
-       up(&port->port_lock);
+       mutex_unlock(&port->port_lock);
        return;
 }
 
@@ -2849,7 +2862,7 @@ static void ehea_rereg_mrs(struct work_struct *work)
        int ret, i;
        struct ehea_adapter *adapter;
 
-       down(&dlpar_mem_lock);
+       mutex_lock(&dlpar_mem_lock);
        ehea_info("LPAR memory enlarged - re-initializing driver");
 
        list_for_each_entry(adapter, &adapter_list, list)
@@ -2857,22 +2870,24 @@ static void ehea_rereg_mrs(struct work_struct *work)
                        /* Shutdown all ports */
                        for (i = 0; i < EHEA_MAX_PORTS; i++) {
                                struct ehea_port *port = adapter->port[i];
+                               struct net_device *dev;
 
-                               if (port) {
-                                       struct net_device *dev = port->netdev;
+                               if (!port)
+                                       continue;
 
-                                       if (dev->flags & IFF_UP) {
-                                               down(&port->port_lock);
-                                               netif_stop_queue(dev);
-                                               ehea_flush_sq(port);
-                                               ret = ehea_stop_qps(dev);
-                                               if (ret) {
-                                                       up(&port->port_lock);
-                                                       goto out;
-                                               }
-                                               port_napi_disable(port);
-                                               up(&port->port_lock);
+                               dev = port->netdev;
+
+                               if (dev->flags & IFF_UP) {
+                                       mutex_lock(&port->port_lock);
+                                       netif_stop_queue(dev);
+                                       ehea_flush_sq(port);
+                                       ret = ehea_stop_qps(dev);
+                                       if (ret) {
+                                               mutex_unlock(&port->port_lock);
+                                               goto out;
                                        }
+                                       port_napi_disable(port);
+                                       mutex_unlock(&port->port_lock);
                                }
                        }
 
@@ -2912,17 +2927,17 @@ static void ehea_rereg_mrs(struct work_struct *work)
                                        struct net_device *dev = port->netdev;
 
                                        if (dev->flags & IFF_UP) {
-                                               down(&port->port_lock);
+                                               mutex_lock(&port->port_lock);
                                                port_napi_enable(port);
                                                ret = ehea_restart_qps(dev);
                                                if (!ret)
                                                        netif_wake_queue(dev);
-                                               up(&port->port_lock);
+                                               mutex_unlock(&port->port_lock);
                                        }
                                }
                        }
                }
-       up(&dlpar_mem_lock);
+       mutex_unlock(&dlpar_mem_lock);
        ehea_info("re-initializing driver complete");
 out:
        return;
@@ -2934,7 +2949,7 @@ static void ehea_tx_watchdog(struct net_device *dev)
 
        if (netif_carrier_ok(dev) &&
            !test_bit(__EHEA_STOP_XFER, &ehea_driver_flags))
-               schedule_work(&port->reset_task);
+               ehea_schedule_port_reset(port);
 }
 
 int ehea_sense_adapter_attr(struct ehea_adapter *adapter)
@@ -3083,7 +3098,7 @@ struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter,
 
        port = netdev_priv(dev);
 
-       sema_init(&port->port_lock, 1);
+       mutex_init(&port->port_lock);
        port->state = EHEA_PORT_DOWN;
        port->sig_comp_iv = sq_entries / 10;
 
@@ -3174,11 +3189,12 @@ out_err:
 
 static void ehea_shutdown_single_port(struct ehea_port *port)
 {
+       struct ehea_adapter *adapter = port->adapter;
        unregister_netdev(port->netdev);
        ehea_unregister_port(port);
        kfree(port->mc_list);
        free_netdev(port->netdev);
-       port->adapter->active_ports--;
+       adapter->active_ports--;
 }
 
 static int ehea_setup_ports(struct ehea_adapter *adapter)
@@ -3362,7 +3378,7 @@ static int __devinit ehea_probe_adapter(struct of_device *dev,
                ehea_error("Invalid ibmebus device probed");
                return -EINVAL;
        }
-       down(&ehea_fw_handles.lock);
+       mutex_lock(&ehea_fw_handles.lock);
 
        adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
        if (!adapter) {
@@ -3446,7 +3462,7 @@ out_free_ad:
 
 out:
        ehea_update_firmware_handles();
-       up(&ehea_fw_handles.lock);
+       mutex_unlock(&ehea_fw_handles.lock);
        return ret;
 }
 
@@ -3465,7 +3481,7 @@ static int __devexit ehea_remove(struct of_device *dev)
 
        flush_scheduled_work();
 
-       down(&ehea_fw_handles.lock);
+       mutex_lock(&ehea_fw_handles.lock);
 
        ibmebus_free_irq(adapter->neq->attr.ist1, adapter);
        tasklet_kill(&adapter->neq_tasklet);
@@ -3476,7 +3492,7 @@ static int __devexit ehea_remove(struct of_device *dev)
        kfree(adapter);
 
        ehea_update_firmware_handles();
-       up(&ehea_fw_handles.lock);
+       mutex_unlock(&ehea_fw_handles.lock);
 
        return 0;
 }
@@ -3500,6 +3516,24 @@ void ehea_crash_handler(void)
                                              0, H_DEREG_BCMC);
 }
 
+static int ehea_mem_notifier(struct notifier_block *nb,
+                             unsigned long action, void *data)
+{
+       switch (action) {
+       case MEM_OFFLINE:
+               ehea_info("memory has been removed");
+               ehea_rereg_mrs(NULL);
+               break;
+       default:
+               break;
+       }
+       return NOTIFY_OK;
+}
+
+static struct notifier_block ehea_mem_nb = {
+       .notifier_call = ehea_mem_notifier,
+};
+
 static int ehea_reboot_notifier(struct notifier_block *nb,
                                unsigned long action, void *unused)
 {
@@ -3563,9 +3597,8 @@ int __init ehea_module_init(void)
        memset(&ehea_fw_handles, 0, sizeof(ehea_fw_handles));
        memset(&ehea_bcmc_regs, 0, sizeof(ehea_bcmc_regs));
 
-       sema_init(&dlpar_mem_lock, 1);
-       sema_init(&ehea_fw_handles.lock, 1);
-       sema_init(&ehea_bcmc_regs.lock, 1);
+       mutex_init(&ehea_fw_handles.lock);
+       spin_lock_init(&ehea_bcmc_regs.lock);
 
        ret = check_module_parm();
        if (ret)
@@ -3579,6 +3612,10 @@ int __init ehea_module_init(void)
        if (ret)
                ehea_info("failed registering reboot notifier");
 
+       ret = register_memory_notifier(&ehea_mem_nb);
+       if (ret)
+               ehea_info("failed registering memory remove notifier");
+
        ret = crash_shutdown_register(&ehea_crash_handler);
        if (ret)
                ehea_info("failed registering crash handler");
@@ -3602,6 +3639,7 @@ int __init ehea_module_init(void)
 out3:
        ibmebus_unregister_driver(&ehea_driver);
 out2:
+       unregister_memory_notifier(&ehea_mem_nb);
        unregister_reboot_notifier(&ehea_reboot_nb);
        crash_shutdown_unregister(&ehea_crash_handler);
 out:
@@ -3619,6 +3657,7 @@ static void __exit ehea_module_exit(void)
        ret = crash_shutdown_unregister(&ehea_crash_handler);
        if (ret)
                ehea_info("failed unregistering crash handler");
+       unregister_memory_notifier(&ehea_mem_nb);
        kfree(ehea_fw_handles.arr);
        kfree(ehea_bcmc_regs.arr);
        ehea_destroy_busmap();