Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
[safe/jmp/linux-2.6] / drivers / net / ehea / ehea_main.c
index 489fdb9..147c4b0 100644 (file)
@@ -155,6 +155,8 @@ static void ehea_update_firmware_handles(void)
        int num_fw_handles, k, l;
 
        /* Determine number of handles */
+       mutex_lock(&ehea_fw_handles.lock);
+
        list_for_each_entry(adapter, &adapter_list, list) {
                num_adapters++;
 
@@ -176,15 +178,19 @@ static void ehea_update_firmware_handles(void)
        if (num_fw_handles) {
                arr = kzalloc(num_fw_handles * sizeof(*arr), GFP_KERNEL);
                if (!arr)
-                       return;  /* Keep the existing array */
+                       goto out;  /* Keep the existing array */
        } else
                goto out_update;
 
        list_for_each_entry(adapter, &adapter_list, list) {
+               if (num_adapters == 0)
+                       break;
+
                for (k = 0; k < EHEA_MAX_PORTS; k++) {
                        struct ehea_port *port = adapter->port[k];
 
-                       if (!port || (port->state != EHEA_PORT_UP))
+                       if (!port || (port->state != EHEA_PORT_UP)
+                               || (num_ports == 0))
                                continue;
 
                        for (l = 0;
@@ -207,6 +213,7 @@ static void ehea_update_firmware_handles(void)
                        }
                        arr[i].adh = adapter->handle;
                        arr[i++].fwh = port->qp_eq->fw_handle;
+                       num_ports--;
                }
 
                arr[i].adh = adapter->handle;
@@ -216,16 +223,20 @@ static void ehea_update_firmware_handles(void)
                        arr[i].adh = adapter->handle;
                        arr[i++].fwh = adapter->mr.handle;
                }
+               num_adapters--;
        }
 
 out_update:
        kfree(ehea_fw_handles.arr);
        ehea_fw_handles.arr = arr;
        ehea_fw_handles.num_entries = i;
+out:
+       mutex_unlock(&ehea_fw_handles.lock);
 }
 
 static void ehea_update_bcmc_registrations(void)
 {
+       unsigned long flags;
        struct ehea_bcmc_reg_entry *arr = NULL;
        struct ehea_adapter *adapter;
        struct ehea_mc_list *mc_entry;
@@ -233,6 +244,8 @@ static void ehea_update_bcmc_registrations(void)
        int i = 0;
        int k;
 
+       spin_lock_irqsave(&ehea_bcmc_regs.lock, flags);
+
        /* Determine number of registrations */
        list_for_each_entry(adapter, &adapter_list, list)
                for (k = 0; k < EHEA_MAX_PORTS; k++) {
@@ -250,7 +263,7 @@ static void ehea_update_bcmc_registrations(void)
        if (num_registrations) {
                arr = kzalloc(num_registrations * sizeof(*arr), GFP_ATOMIC);
                if (!arr)
-                       return;  /* Keep the existing array */
+                       goto out;  /* Keep the existing array */
        } else
                goto out_update;
 
@@ -261,6 +274,9 @@ static void ehea_update_bcmc_registrations(void)
                        if (!port || (port->state != EHEA_PORT_UP))
                                continue;
 
+                       if (num_registrations == 0)
+                               goto out_update;
+
                        arr[i].adh = adapter->handle;
                        arr[i].port_id = port->logical_port_id;
                        arr[i].reg_type = EHEA_BCMC_BROADCAST |
@@ -272,9 +288,13 @@ static void ehea_update_bcmc_registrations(void)
                        arr[i].reg_type = EHEA_BCMC_BROADCAST |
                                          EHEA_BCMC_VLANID_ALL;
                        arr[i++].macaddr = port->mac_addr;
+                       num_registrations -= 2;
 
                        list_for_each_entry(mc_entry,
                                            &port->mc_list->list, list) {
+                               if (num_registrations == 0)
+                                       goto out_update;
+
                                arr[i].adh = adapter->handle;
                                arr[i].port_id = port->logical_port_id;
                                arr[i].reg_type = EHEA_BCMC_SCOPE_ALL |
@@ -288,6 +308,7 @@ static void ehea_update_bcmc_registrations(void)
                                                  EHEA_BCMC_MULTICAST |
                                                  EHEA_BCMC_VLANID_ALL;
                                arr[i++].macaddr = mc_entry->macaddr;
+                               num_registrations -= 2;
                        }
                }
        }
@@ -296,6 +317,8 @@ out_update:
        kfree(ehea_bcmc_regs.arr);
        ehea_bcmc_regs.arr = arr;
        ehea_bcmc_regs.num_entries = i;
+out:
+       spin_unlock_irqrestore(&ehea_bcmc_regs.lock, flags);
 }
 
 static struct net_device_stats *ehea_get_stats(struct net_device *dev)
@@ -522,14 +545,17 @@ static inline struct sk_buff *get_skb_by_index(struct sk_buff **skb_array,
        x &= (arr_len - 1);
 
        pref = skb_array[x];
-       prefetchw(pref);
-       prefetchw(pref + EHEA_CACHE_LINE);
-
-       pref = (skb_array[x]->data);
-       prefetch(pref);
-       prefetch(pref + EHEA_CACHE_LINE);
-       prefetch(pref + EHEA_CACHE_LINE * 2);
-       prefetch(pref + EHEA_CACHE_LINE * 3);
+       if (pref) {
+               prefetchw(pref);
+               prefetchw(pref + EHEA_CACHE_LINE);
+
+               pref = (skb_array[x]->data);
+               prefetch(pref);
+               prefetch(pref + EHEA_CACHE_LINE);
+               prefetch(pref + EHEA_CACHE_LINE * 2);
+               prefetch(pref + EHEA_CACHE_LINE * 3);
+       }
+
        skb = skb_array[skb_index];
        skb_array[skb_index] = NULL;
        return skb;
@@ -546,12 +572,14 @@ static inline struct sk_buff *get_skb_by_index_ll(struct sk_buff **skb_array,
        x &= (arr_len - 1);
 
        pref = skb_array[x];
-       prefetchw(pref);
-       prefetchw(pref + EHEA_CACHE_LINE);
+       if (pref) {
+               prefetchw(pref);
+               prefetchw(pref + EHEA_CACHE_LINE);
 
-       pref = (skb_array[x]->data);
-       prefetchw(pref);
-       prefetchw(pref + EHEA_CACHE_LINE);
+               pref = (skb_array[x]->data);
+               prefetchw(pref);
+               prefetchw(pref + EHEA_CACHE_LINE);
+       }
 
        skb = skb_array[wqe_index];
        skb_array[wqe_index] = NULL;
@@ -1762,8 +1790,6 @@ static int ehea_set_mac_addr(struct net_device *dev, void *sa)
 
        memcpy(dev->dev_addr, mac_addr->sa_data, dev->addr_len);
 
-       spin_lock(&ehea_bcmc_regs.lock);
-
        /* Deregister old MAC in pHYP */
        if (port->state == EHEA_PORT_UP) {
                ret = ehea_broadcast_reg_helper(port, H_DEREG_BCMC);
@@ -1784,7 +1810,6 @@ static int ehea_set_mac_addr(struct net_device *dev, void *sa)
 
 out_upregs:
        ehea_update_bcmc_registrations();
-       spin_unlock(&ehea_bcmc_regs.lock);
 out_free:
        free_page((unsigned long)cb0);
 out:
@@ -1946,8 +1971,6 @@ static void ehea_set_multicast_list(struct net_device *dev)
        }
        ehea_promiscuous(dev, 0);
 
-       spin_lock(&ehea_bcmc_regs.lock);
-
        if (dev->flags & IFF_ALLMULTI) {
                ehea_allmulti(dev, 1);
                goto out;
@@ -1977,7 +2000,6 @@ static void ehea_set_multicast_list(struct net_device *dev)
        }
 out:
        ehea_update_bcmc_registrations();
-       spin_unlock(&ehea_bcmc_regs.lock);
        return;
 }
 
@@ -2458,8 +2480,6 @@ static int ehea_up(struct net_device *dev)
        if (port->state == EHEA_PORT_UP)
                return 0;
 
-       mutex_lock(&ehea_fw_handles.lock);
-
        ret = ehea_port_res_setup(port, port->num_def_qps,
                                  port->num_add_tx_qps);
        if (ret) {
@@ -2496,8 +2516,6 @@ static int ehea_up(struct net_device *dev)
                }
        }
 
-       spin_lock(&ehea_bcmc_regs.lock);
-
        ret = ehea_broadcast_reg_helper(port, H_REG_BCMC);
        if (ret) {
                ret = -EIO;
@@ -2519,10 +2537,7 @@ out:
                ehea_info("Failed starting %s. ret=%i", dev->name, ret);
 
        ehea_update_bcmc_registrations();
-       spin_unlock(&ehea_bcmc_regs.lock);
-
        ehea_update_firmware_handles();
-       mutex_unlock(&ehea_fw_handles.lock);
 
        return ret;
 }
@@ -2572,9 +2587,6 @@ static int ehea_down(struct net_device *dev)
        if (port->state == EHEA_PORT_DOWN)
                return 0;
 
-       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);
 
@@ -2583,7 +2595,6 @@ static int ehea_down(struct net_device *dev)
        port->state = EHEA_PORT_DOWN;
 
        ehea_update_bcmc_registrations();
-       spin_unlock(&ehea_bcmc_regs.lock);
 
        ret = ehea_clean_all_portres(port);
        if (ret)
@@ -2591,7 +2602,6 @@ static int ehea_down(struct net_device *dev)
                          dev->name, ret);
 
        ehea_update_firmware_handles();
-       mutex_unlock(&ehea_fw_handles.lock);
 
        return ret;
 }
@@ -3075,7 +3085,8 @@ static const struct net_device_ops ehea_netdev_ops = {
        .ndo_change_mtu         = ehea_change_mtu,
        .ndo_vlan_rx_register   = ehea_vlan_rx_register,
        .ndo_vlan_rx_add_vid    = ehea_vlan_rx_add_vid,
-       .ndo_vlan_rx_kill_vid   = ehea_vlan_rx_kill_vid
+       .ndo_vlan_rx_kill_vid   = ehea_vlan_rx_kill_vid,
+       .ndo_tx_timeout         = ehea_tx_watchdog,
 };
 
 struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter,
@@ -3137,7 +3148,6 @@ struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter,
                      | NETIF_F_HIGHDMA | NETIF_F_IP_CSUM | NETIF_F_HW_VLAN_TX
                      | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER
                      | NETIF_F_LLTX;
-       dev->tx_timeout = &ehea_tx_watchdog;
        dev->watchdog_timeo = EHEA_WATCH_DOG_TIMEOUT;
 
        INIT_WORK(&port->reset_task, ehea_reset_port);
@@ -3251,7 +3261,7 @@ static ssize_t ehea_probe_port(struct device *dev,
                               struct device_attribute *attr,
                               const char *buf, size_t count)
 {
-       struct ehea_adapter *adapter = dev->driver_data;
+       struct ehea_adapter *adapter = dev_get_drvdata(dev);
        struct ehea_port *port;
        struct device_node *eth_dn = NULL;
        int i;
@@ -3306,7 +3316,7 @@ static ssize_t ehea_remove_port(struct device *dev,
                                struct device_attribute *attr,
                                const char *buf, size_t count)
 {
-       struct ehea_adapter *adapter = dev->driver_data;
+       struct ehea_adapter *adapter = dev_get_drvdata(dev);
        struct ehea_port *port;
        int i;
        u32 logical_port_id;
@@ -3368,7 +3378,6 @@ static int __devinit ehea_probe_adapter(struct of_device *dev,
                ehea_error("Invalid ibmebus device probed");
                return -EINVAL;
        }
-       mutex_lock(&ehea_fw_handles.lock);
 
        adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
        if (!adapter) {
@@ -3395,7 +3404,7 @@ static int __devinit ehea_probe_adapter(struct of_device *dev,
 
        adapter->pd = EHEA_PD_ID;
 
-       dev->dev.driver_data = adapter;
+       dev_set_drvdata(&dev->dev, adapter);
 
 
        /* initialize adapter and ports */
@@ -3448,17 +3457,18 @@ out_kill_eq:
        ehea_destroy_eq(adapter->neq);
 
 out_free_ad:
+       list_del(&adapter->list);
        kfree(adapter);
 
 out:
        ehea_update_firmware_handles();
-       mutex_unlock(&ehea_fw_handles.lock);
+
        return ret;
 }
 
 static int __devexit ehea_remove(struct of_device *dev)
 {
-       struct ehea_adapter *adapter = dev->dev.driver_data;
+       struct ehea_adapter *adapter = dev_get_drvdata(&dev->dev);
        int i;
 
        for (i = 0; i < EHEA_MAX_PORTS; i++)
@@ -3471,8 +3481,6 @@ static int __devexit ehea_remove(struct of_device *dev)
 
        flush_scheduled_work();
 
-       mutex_lock(&ehea_fw_handles.lock);
-
        ibmebus_free_irq(adapter->neq->attr.ist1, adapter);
        tasklet_kill(&adapter->neq_tasklet);
 
@@ -3482,7 +3490,6 @@ static int __devexit ehea_remove(struct of_device *dev)
        kfree(adapter);
 
        ehea_update_firmware_handles();
-       mutex_unlock(&ehea_fw_handles.lock);
 
        return 0;
 }
@@ -3516,12 +3523,14 @@ static int ehea_mem_notifier(struct notifier_block *nb,
                /* Readd canceled memory block */
        case MEM_ONLINE:
                ehea_info("memory is going online");
+               set_bit(__EHEA_STOP_XFER, &ehea_driver_flags);
                if (ehea_add_sect_bmap(arg->start_pfn, arg->nr_pages))
                        return NOTIFY_BAD;
                ehea_rereg_mrs(NULL);
                break;
        case MEM_GOING_OFFLINE:
                ehea_info("memory is going offline");
+               set_bit(__EHEA_STOP_XFER, &ehea_driver_flags);
                if (ehea_rem_sect_bmap(arg->start_pfn, arg->nr_pages))
                        return NOTIFY_BAD;
                ehea_rereg_mrs(NULL);
@@ -3529,6 +3538,9 @@ static int ehea_mem_notifier(struct notifier_block *nb,
        default:
                break;
        }
+
+       ehea_update_firmware_handles();
+
        return NOTIFY_OK;
 }