]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - drivers/net/ethernet/ibm/ibmvnic.c
ibmvnic: Create separate initialization routine for resets
[linux.git] / drivers / net / ethernet / ibm / ibmvnic.c
index 6e8d6a6f6aaf2c809a92349f64c83f406bd35e9a..f26e1f893441c27328b77c48c04580d77c1867dc 100644 (file)
@@ -109,13 +109,14 @@ static union sub_crq *ibmvnic_next_scrq(struct ibmvnic_adapter *,
                                        struct ibmvnic_sub_crq_queue *);
 static int ibmvnic_poll(struct napi_struct *napi, int data);
 static void send_map_query(struct ibmvnic_adapter *adapter);
-static void send_request_map(struct ibmvnic_adapter *, dma_addr_t, __be32, u8);
-static void send_request_unmap(struct ibmvnic_adapter *, u8);
+static int send_request_map(struct ibmvnic_adapter *, dma_addr_t, __be32, u8);
+static int send_request_unmap(struct ibmvnic_adapter *, u8);
 static int send_login(struct ibmvnic_adapter *adapter);
 static void send_cap_queries(struct ibmvnic_adapter *adapter);
 static int init_sub_crqs(struct ibmvnic_adapter *);
 static int init_sub_crq_irqs(struct ibmvnic_adapter *adapter);
 static int ibmvnic_init(struct ibmvnic_adapter *);
+static int ibmvnic_reset_init(struct ibmvnic_adapter *);
 static void release_crq_queue(struct ibmvnic_adapter *);
 static int __ibmvnic_set_mac(struct net_device *netdev, struct sockaddr *p);
 static int init_crq_queue(struct ibmvnic_adapter *adapter);
@@ -172,6 +173,7 @@ static int alloc_long_term_buff(struct ibmvnic_adapter *adapter,
                                struct ibmvnic_long_term_buff *ltb, int size)
 {
        struct device *dev = &adapter->vdev->dev;
+       int rc;
 
        ltb->size = size;
        ltb->buff = dma_alloc_coherent(dev, ltb->size, &ltb->addr,
@@ -185,13 +187,18 @@ static int alloc_long_term_buff(struct ibmvnic_adapter *adapter,
        adapter->map_id++;
 
        init_completion(&adapter->fw_done);
-       send_request_map(adapter, ltb->addr,
-                        ltb->size, ltb->map_id);
+       rc = send_request_map(adapter, ltb->addr,
+                             ltb->size, ltb->map_id);
+       if (rc) {
+               dma_free_coherent(dev, ltb->size, ltb->buff, ltb->addr);
+               return rc;
+       }
        wait_for_completion(&adapter->fw_done);
 
        if (adapter->fw_done_rc) {
                dev_err(dev, "Couldn't map long term buffer,rc = %d\n",
                        adapter->fw_done_rc);
+               dma_free_coherent(dev, ltb->size, ltb->buff, ltb->addr);
                return -1;
        }
        return 0;
@@ -214,10 +221,14 @@ static void free_long_term_buff(struct ibmvnic_adapter *adapter,
 static int reset_long_term_buff(struct ibmvnic_adapter *adapter,
                                struct ibmvnic_long_term_buff *ltb)
 {
+       int rc;
+
        memset(ltb->buff, 0, ltb->size);
 
        init_completion(&adapter->fw_done);
-       send_request_map(adapter, ltb->addr, ltb->size, ltb->map_id);
+       rc = send_request_map(adapter, ltb->addr, ltb->size, ltb->map_id);
+       if (rc)
+               return rc;
        wait_for_completion(&adapter->fw_done);
 
        if (adapter->fw_done_rc) {
@@ -788,6 +799,7 @@ static void release_napi(struct ibmvnic_adapter *adapter)
        kfree(adapter->napi);
        adapter->napi = NULL;
        adapter->num_active_rx_napi = 0;
+       adapter->napi_enabled = false;
 }
 
 static int ibmvnic_login(struct net_device *netdev)
@@ -918,6 +930,10 @@ static int set_link_state(struct ibmvnic_adapter *adapter, u8 link_state)
                        /* Partuial success, delay and re-send */
                        mdelay(1000);
                        resend = true;
+               } else if (adapter->init_done_rc) {
+                       netdev_warn(netdev, "Unable to set link state, rc=%d\n",
+                                   adapter->init_done_rc);
+                       return adapter->init_done_rc;
                }
        } while (resend);
 
@@ -950,6 +966,7 @@ static int ibmvnic_get_vpd(struct ibmvnic_adapter *adapter)
        struct device *dev = &adapter->vdev->dev;
        union ibmvnic_crq crq;
        int len = 0;
+       int rc;
 
        if (adapter->vpd->buff)
                len = adapter->vpd->len;
@@ -957,7 +974,9 @@ static int ibmvnic_get_vpd(struct ibmvnic_adapter *adapter)
        init_completion(&adapter->fw_done);
        crq.get_vpd_size.first = IBMVNIC_CRQ_CMD;
        crq.get_vpd_size.cmd = GET_VPD_SIZE;
-       ibmvnic_send_crq(adapter, &crq);
+       rc = ibmvnic_send_crq(adapter, &crq);
+       if (rc)
+               return rc;
        wait_for_completion(&adapter->fw_done);
 
        if (!adapter->vpd->len)
@@ -990,7 +1009,12 @@ static int ibmvnic_get_vpd(struct ibmvnic_adapter *adapter)
        crq.get_vpd.cmd = GET_VPD;
        crq.get_vpd.ioba = cpu_to_be32(adapter->vpd->dma_addr);
        crq.get_vpd.len = cpu_to_be32((u32)adapter->vpd->len);
-       ibmvnic_send_crq(adapter, &crq);
+       rc = ibmvnic_send_crq(adapter, &crq);
+       if (rc) {
+               kfree(adapter->vpd->buff);
+               adapter->vpd->buff = NULL;
+               return rc;
+       }
        wait_for_completion(&adapter->fw_done);
 
        return 0;
@@ -1689,6 +1713,7 @@ static int __ibmvnic_set_mac(struct net_device *netdev, struct sockaddr *p)
        struct ibmvnic_adapter *adapter = netdev_priv(netdev);
        struct sockaddr *addr = p;
        union ibmvnic_crq crq;
+       int rc;
 
        if (!is_valid_ether_addr(addr->sa_data))
                return -EADDRNOTAVAIL;
@@ -1699,7 +1724,9 @@ static int __ibmvnic_set_mac(struct net_device *netdev, struct sockaddr *p)
        ether_addr_copy(&crq.change_mac_addr.mac_addr[0], addr->sa_data);
 
        init_completion(&adapter->fw_done);
-       ibmvnic_send_crq(adapter, &crq);
+       rc = ibmvnic_send_crq(adapter, &crq);
+       if (rc)
+               return rc;
        wait_for_completion(&adapter->fw_done);
        /* netdev->dev_addr is changed in handle_change_mac_rsp function */
        return adapter->fw_done_rc ? -EIO : 0;
@@ -1781,7 +1808,7 @@ static int do_reset(struct ibmvnic_adapter *adapter,
                        return rc;
                }
 
-               rc = ibmvnic_init(adapter);
+               rc = ibmvnic_reset_init(adapter);
                if (rc)
                        return IBMVNIC_INIT_FAILED;
 
@@ -1821,9 +1848,8 @@ static int do_reset(struct ibmvnic_adapter *adapter,
                        if (rc)
                                return rc;
                }
+               ibmvnic_disable_irqs(adapter);
        }
-
-       ibmvnic_disable_irqs(adapter);
        adapter->state = VNIC_CLOSED;
 
        if (reset_state == VNIC_CLOSED)
@@ -2364,6 +2390,7 @@ static void ibmvnic_get_ethtool_stats(struct net_device *dev,
        struct ibmvnic_adapter *adapter = netdev_priv(dev);
        union ibmvnic_crq crq;
        int i, j;
+       int rc;
 
        memset(&crq, 0, sizeof(crq));
        crq.request_statistics.first = IBMVNIC_CRQ_CMD;
@@ -2374,7 +2401,9 @@ static void ibmvnic_get_ethtool_stats(struct net_device *dev,
 
        /* Wait for data to be written */
        init_completion(&adapter->stats_done);
-       ibmvnic_send_crq(adapter, &crq);
+       rc = ibmvnic_send_crq(adapter, &crq);
+       if (rc)
+               return;
        wait_for_completion(&adapter->stats_done);
 
        for (i = 0; i < ARRAY_SIZE(ibmvnic_stats); i++)
@@ -3146,6 +3175,12 @@ static int ibmvnic_send_crq(struct ibmvnic_adapter *adapter,
                   (unsigned long int)cpu_to_be64(u64_crq[0]),
                   (unsigned long int)cpu_to_be64(u64_crq[1]));
 
+       if (!adapter->crq.active &&
+           crq->generic.first != IBMVNIC_CRQ_INIT_CMD) {
+               dev_warn(dev, "Invalid request detected while CRQ is inactive, possible device state change during reset\n");
+               return -EINVAL;
+       }
+
        /* Make sure the hypervisor sees the complete request */
        mb();
 
@@ -3370,8 +3405,8 @@ static int send_login(struct ibmvnic_adapter *adapter)
        return -1;
 }
 
-static void send_request_map(struct ibmvnic_adapter *adapter, dma_addr_t addr,
-                            u32 len, u8 map_id)
+static int send_request_map(struct ibmvnic_adapter *adapter, dma_addr_t addr,
+                           u32 len, u8 map_id)
 {
        union ibmvnic_crq crq;
 
@@ -3381,10 +3416,10 @@ static void send_request_map(struct ibmvnic_adapter *adapter, dma_addr_t addr,
        crq.request_map.map_id = map_id;
        crq.request_map.ioba = cpu_to_be32(addr);
        crq.request_map.len = cpu_to_be32(len);
-       ibmvnic_send_crq(adapter, &crq);
+       return ibmvnic_send_crq(adapter, &crq);
 }
 
-static void send_request_unmap(struct ibmvnic_adapter *adapter, u8 map_id)
+static int send_request_unmap(struct ibmvnic_adapter *adapter, u8 map_id)
 {
        union ibmvnic_crq crq;
 
@@ -3392,7 +3427,7 @@ static void send_request_unmap(struct ibmvnic_adapter *adapter, u8 map_id)
        crq.request_unmap.first = IBMVNIC_CRQ_CMD;
        crq.request_unmap.cmd = REQUEST_UNMAP;
        crq.request_unmap.map_id = map_id;
-       ibmvnic_send_crq(adapter, &crq);
+       return ibmvnic_send_crq(adapter, &crq);
 }
 
 static void send_map_query(struct ibmvnic_adapter *adapter)
@@ -4219,11 +4254,15 @@ static void ibmvnic_handle_crq(union ibmvnic_crq *crq,
                        dev_info(dev, "Partner initialized\n");
                        adapter->from_passive_init = true;
                        adapter->failover_pending = false;
-                       complete(&adapter->init_done);
+                       if (!completion_done(&adapter->init_done)) {
+                               complete(&adapter->init_done);
+                               adapter->init_done_rc = -EIO;
+                       }
                        ibmvnic_reset(adapter, VNIC_RESET_FAILOVER);
                        break;
                case IBMVNIC_CRQ_INIT_COMPLETE:
                        dev_info(dev, "Partner initialization complete\n");
+                       adapter->crq.active = true;
                        send_version_xchg(adapter);
                        break;
                default:
@@ -4232,6 +4271,7 @@ static void ibmvnic_handle_crq(union ibmvnic_crq *crq,
                return;
        case IBMVNIC_CRQ_XPORT_EVENT:
                netif_carrier_off(netdev);
+               adapter->crq.active = false;
                if (gen_crq->cmd == IBMVNIC_PARTITION_MIGRATED) {
                        dev_info(dev, "Migrated, re-enabling adapter\n");
                        ibmvnic_reset(adapter, VNIC_RESET_MOBILITY);
@@ -4419,6 +4459,7 @@ static int ibmvnic_reset_crq(struct ibmvnic_adapter *adapter)
        /* Clean out the queue */
        memset(crq->msgs, 0, PAGE_SIZE);
        crq->cur = 0;
+       crq->active = false;
 
        /* And re-open it again */
        rc = plpar_hcall_norets(H_REG_CRQ, vdev->unit_address,
@@ -4453,6 +4494,7 @@ static void release_crq_queue(struct ibmvnic_adapter *adapter)
                         DMA_BIDIRECTIONAL);
        free_page((unsigned long)crq->msgs);
        crq->msgs = NULL;
+       crq->active = false;
 }
 
 static int init_crq_queue(struct ibmvnic_adapter *adapter)
@@ -4530,7 +4572,7 @@ static int init_crq_queue(struct ibmvnic_adapter *adapter)
        return retrc;
 }
 
-static int ibmvnic_init(struct ibmvnic_adapter *adapter)
+static int ibmvnic_reset_init(struct ibmvnic_adapter *adapter)
 {
        struct device *dev = &adapter->vdev->dev;
        unsigned long timeout = msecs_to_jiffies(30000);
@@ -4586,13 +4628,48 @@ static int ibmvnic_init(struct ibmvnic_adapter *adapter)
                release_crq_queue(adapter);
        }
 
-       rc = init_stats_buffers(adapter);
-       if (rc)
-               return rc;
+       return rc;
+}
 
-       rc = init_stats_token(adapter);
-       if (rc)
+static int ibmvnic_init(struct ibmvnic_adapter *adapter)
+{
+       struct device *dev = &adapter->vdev->dev;
+       unsigned long timeout = msecs_to_jiffies(30000);
+       int rc;
+
+       adapter->from_passive_init = false;
+
+       init_completion(&adapter->init_done);
+       adapter->init_done_rc = 0;
+       ibmvnic_send_crq_init(adapter);
+       if (!wait_for_completion_timeout(&adapter->init_done, timeout)) {
+               dev_err(dev, "Initialization sequence timed out\n");
+               return -1;
+       }
+
+       if (adapter->init_done_rc) {
+               release_crq_queue(adapter);
+               return adapter->init_done_rc;
+       }
+
+       if (adapter->from_passive_init) {
+               adapter->state = VNIC_OPEN;
+               adapter->from_passive_init = false;
+               return -1;
+       }
+
+       rc = init_sub_crqs(adapter);
+       if (rc) {
+               dev_err(dev, "Initialization of sub crqs failed\n");
+               release_crq_queue(adapter);
                return rc;
+       }
+
+       rc = init_sub_crq_irqs(adapter);
+       if (rc) {
+               dev_err(dev, "Failed to initialize sub crq irqs\n");
+               release_crq_queue(adapter);
+       }
 
        return rc;
 }
@@ -4662,13 +4739,21 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
                        goto ibmvnic_init_fail;
        } while (rc == EAGAIN);
 
+       rc = init_stats_buffers(adapter);
+       if (rc)
+               goto ibmvnic_init_fail;
+
+       rc = init_stats_token(adapter);
+       if (rc)
+               goto ibmvnic_stats_fail;
+
        netdev->mtu = adapter->req_mtu - ETH_HLEN;
        netdev->min_mtu = adapter->min_mtu - ETH_HLEN;
        netdev->max_mtu = adapter->max_mtu - ETH_HLEN;
 
        rc = device_create_file(&dev->dev, &dev_attr_failover);
        if (rc)
-               goto ibmvnic_init_fail;
+               goto ibmvnic_dev_file_err;
 
        netif_carrier_off(netdev);
        rc = register_netdev(netdev);
@@ -4687,6 +4772,12 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
 ibmvnic_register_fail:
        device_remove_file(&dev->dev, &dev_attr_failover);
 
+ibmvnic_dev_file_err:
+       release_stats_token(adapter);
+
+ibmvnic_stats_fail:
+       release_stats_buffers(adapter);
+
 ibmvnic_init_fail:
        release_sub_crqs(adapter, 1);
        release_crq_queue(adapter);