]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - drivers/net/ethernet/ibm/ibmvnic.c
ibmvnic: Fix non-atomic memory allocation in IRQ context
[linux.git] / drivers / net / ethernet / ibm / ibmvnic.c
index 27a6df30eafd28e6f2af2b647769e9f0857546ea..67cc6d9c8fd7257af3e3c592fd96a636cc8be326 100644 (file)
@@ -485,8 +485,8 @@ static void release_rx_pools(struct ibmvnic_adapter *adapter)
 
                for (j = 0; j < rx_pool->size; j++) {
                        if (rx_pool->rx_buff[j].skb) {
-                               dev_kfree_skb_any(rx_pool->rx_buff[i].skb);
-                               rx_pool->rx_buff[i].skb = NULL;
+                               dev_kfree_skb_any(rx_pool->rx_buff[j].skb);
+                               rx_pool->rx_buff[j].skb = NULL;
                        }
                }
 
@@ -1737,6 +1737,7 @@ static int do_reset(struct ibmvnic_adapter *adapter,
                    struct ibmvnic_rwi *rwi, u32 reset_state)
 {
        u64 old_num_rx_queues, old_num_tx_queues;
+       u64 old_num_rx_slots, old_num_tx_slots;
        struct net_device *netdev = adapter->netdev;
        int i, rc;
 
@@ -1748,6 +1749,8 @@ static int do_reset(struct ibmvnic_adapter *adapter,
 
        old_num_rx_queues = adapter->req_rx_queues;
        old_num_tx_queues = adapter->req_tx_queues;
+       old_num_rx_slots = adapter->req_rx_add_entries_per_subcrq;
+       old_num_tx_slots = adapter->req_tx_entries_per_subcrq;
 
        ibmvnic_cleanup(netdev);
 
@@ -1810,7 +1813,11 @@ static int do_reset(struct ibmvnic_adapter *adapter,
                        if (rc)
                                return rc;
                } else if (adapter->req_rx_queues != old_num_rx_queues ||
-                          adapter->req_tx_queues != old_num_tx_queues) {
+                          adapter->req_tx_queues != old_num_tx_queues ||
+                          adapter->req_rx_add_entries_per_subcrq !=
+                                                       old_num_rx_slots ||
+                          adapter->req_tx_entries_per_subcrq !=
+                                                       old_num_tx_slots) {
                        release_rx_pools(adapter);
                        release_tx_pools(adapter);
                        release_napi(adapter);
@@ -1852,7 +1859,7 @@ static int do_reset(struct ibmvnic_adapter *adapter,
 
        if (adapter->reset_reason != VNIC_RESET_FAILOVER &&
            adapter->reset_reason != VNIC_RESET_CHANGE_PARAM)
-               netdev_notify_peers(netdev);
+               call_netdevice_notifiers(NETDEV_NOTIFY_PEERS, netdev);
 
        netif_carrier_on(netdev);
 
@@ -1932,8 +1939,9 @@ static int do_hard_reset(struct ibmvnic_adapter *adapter,
 static struct ibmvnic_rwi *get_next_rwi(struct ibmvnic_adapter *adapter)
 {
        struct ibmvnic_rwi *rwi;
+       unsigned long flags;
 
-       mutex_lock(&adapter->rwi_lock);
+       spin_lock_irqsave(&adapter->rwi_lock, flags);
 
        if (!list_empty(&adapter->rwi_list)) {
                rwi = list_first_entry(&adapter->rwi_list, struct ibmvnic_rwi,
@@ -1943,7 +1951,7 @@ static struct ibmvnic_rwi *get_next_rwi(struct ibmvnic_adapter *adapter)
                rwi = NULL;
        }
 
-       mutex_unlock(&adapter->rwi_lock);
+       spin_unlock_irqrestore(&adapter->rwi_lock, flags);
        return rwi;
 }
 
@@ -2018,6 +2026,7 @@ static int ibmvnic_reset(struct ibmvnic_adapter *adapter,
        struct list_head *entry, *tmp_entry;
        struct ibmvnic_rwi *rwi, *tmp;
        struct net_device *netdev = adapter->netdev;
+       unsigned long flags;
        int ret;
 
        if (adapter->state == VNIC_REMOVING ||
@@ -2034,21 +2043,21 @@ static int ibmvnic_reset(struct ibmvnic_adapter *adapter,
                goto err;
        }
 
-       mutex_lock(&adapter->rwi_lock);
+       spin_lock_irqsave(&adapter->rwi_lock, flags);
 
        list_for_each(entry, &adapter->rwi_list) {
                tmp = list_entry(entry, struct ibmvnic_rwi, list);
                if (tmp->reset_reason == reason) {
                        netdev_dbg(netdev, "Skipping matching reset\n");
-                       mutex_unlock(&adapter->rwi_lock);
+                       spin_unlock_irqrestore(&adapter->rwi_lock, flags);
                        ret = EBUSY;
                        goto err;
                }
        }
 
-       rwi = kzalloc(sizeof(*rwi), GFP_KERNEL);
+       rwi = kzalloc(sizeof(*rwi), GFP_ATOMIC);
        if (!rwi) {
-               mutex_unlock(&adapter->rwi_lock);
+               spin_unlock_irqrestore(&adapter->rwi_lock, flags);
                ibmvnic_close(netdev);
                ret = ENOMEM;
                goto err;
@@ -2062,7 +2071,7 @@ static int ibmvnic_reset(struct ibmvnic_adapter *adapter,
        }
        rwi->reset_reason = reason;
        list_add_tail(&rwi->list, &adapter->rwi_list);
-       mutex_unlock(&adapter->rwi_lock);
+       spin_unlock_irqrestore(&adapter->rwi_lock, flags);
        adapter->resetting = true;
        netdev_dbg(adapter->netdev, "Scheduling reset (reason %d)\n", reason);
        schedule_work(&adapter->ibmvnic_reset);
@@ -4752,7 +4761,7 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
 
        INIT_WORK(&adapter->ibmvnic_reset, __ibmvnic_reset);
        INIT_LIST_HEAD(&adapter->rwi_list);
-       mutex_init(&adapter->rwi_lock);
+       spin_lock_init(&adapter->rwi_lock);
        adapter->resetting = false;
 
        adapter->mac_change_pending = false;