aboutsummaryrefslogtreecommitdiff
path: root/drivers/net/ethernet/ibm/ibmvnic.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet/ibm/ibmvnic.c')
-rw-r--r--drivers/net/ethernet/ibm/ibmvnic.c320
1 files changed, 179 insertions, 141 deletions
diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c
index b23d6545f835..3d7318278846 100644
--- a/drivers/net/ethernet/ibm/ibmvnic.c
+++ b/drivers/net/ethernet/ibm/ibmvnic.c
@@ -110,6 +110,11 @@ 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 void send_login(struct ibmvnic_adapter *adapter);
+static void send_cap_queries(struct ibmvnic_adapter *adapter);
+static int init_sub_crq_irqs(struct ibmvnic_adapter *adapter);
+static int ibmvnic_init(struct ibmvnic_adapter *);
+static void ibmvnic_release_crq_queue(struct ibmvnic_adapter *);
struct ibmvnic_stat {
char name[ETH_GSTRING_LEN];
@@ -368,6 +373,38 @@ static void free_rx_pool(struct ibmvnic_adapter *adapter,
pool->rx_buff = NULL;
}
+static int ibmvnic_login(struct net_device *netdev)
+{
+ struct ibmvnic_adapter *adapter = netdev_priv(netdev);
+ unsigned long timeout = msecs_to_jiffies(30000);
+ struct device *dev = &adapter->vdev->dev;
+
+ do {
+ if (adapter->renegotiate) {
+ adapter->renegotiate = false;
+ release_sub_crqs_no_irqs(adapter);
+
+ reinit_completion(&adapter->init_done);
+ send_cap_queries(adapter);
+ if (!wait_for_completion_timeout(&adapter->init_done,
+ timeout)) {
+ dev_err(dev, "Capabilities query timeout\n");
+ return -1;
+ }
+ }
+
+ reinit_completion(&adapter->init_done);
+ send_login(adapter);
+ if (!wait_for_completion_timeout(&adapter->init_done,
+ timeout)) {
+ dev_err(dev, "Login timeout\n");
+ return -1;
+ }
+ } while (adapter->renegotiate);
+
+ return 0;
+}
+
static int ibmvnic_open(struct net_device *netdev)
{
struct ibmvnic_adapter *adapter = netdev_priv(netdev);
@@ -377,8 +414,31 @@ static int ibmvnic_open(struct net_device *netdev)
int rxadd_subcrqs;
u64 *size_array;
int tx_subcrqs;
+ int rc = 0;
int i, j;
+ if (adapter->is_closed) {
+ rc = ibmvnic_init(adapter);
+ if (rc)
+ return rc;
+ }
+
+ rc = ibmvnic_login(netdev);
+ if (rc)
+ return rc;
+
+ rc = netif_set_real_num_tx_queues(netdev, adapter->req_tx_queues);
+ if (rc) {
+ dev_err(dev, "failed to set the number of tx queues\n");
+ return -1;
+ }
+
+ rc = init_sub_crq_irqs(adapter);
+ if (rc) {
+ dev_err(dev, "failed to initialize sub crq irqs\n");
+ return -1;
+ }
+
rxadd_subcrqs =
be32_to_cpu(adapter->login_rsp_buf->num_rxadd_subcrqs);
tx_subcrqs =
@@ -473,6 +533,7 @@ static int ibmvnic_open(struct net_device *netdev)
ibmvnic_send_crq(adapter, &crq);
netif_tx_start_all_queues(netdev);
+ adapter->is_closed = false;
return 0;
@@ -508,24 +569,16 @@ rx_pool_arr_alloc_failed:
for (i = 0; i < adapter->req_rx_queues; i++)
napi_disable(&adapter->napi[i]);
alloc_napi_failed:
+ release_sub_crqs(adapter);
return -ENOMEM;
}
-static int ibmvnic_close(struct net_device *netdev)
+static void ibmvnic_release_resources(struct ibmvnic_adapter *adapter)
{
- struct ibmvnic_adapter *adapter = netdev_priv(netdev);
struct device *dev = &adapter->vdev->dev;
- union ibmvnic_crq crq;
+ int tx_scrqs, rx_scrqs;
int i;
- adapter->closing = true;
-
- for (i = 0; i < adapter->req_rx_queues; i++)
- napi_disable(&adapter->napi[i]);
-
- if (!adapter->failover)
- netif_tx_stop_all_queues(netdev);
-
if (adapter->bounce_buffer) {
if (!dma_mapping_error(dev, adapter->bounce_buffer_dma)) {
dma_unmap_single(&adapter->vdev->dev,
@@ -538,33 +591,70 @@ static int ibmvnic_close(struct net_device *netdev)
adapter->bounce_buffer = NULL;
}
- memset(&crq, 0, sizeof(crq));
- crq.logical_link_state.first = IBMVNIC_CRQ_CMD;
- crq.logical_link_state.cmd = LOGICAL_LINK_STATE;
- crq.logical_link_state.link_state = IBMVNIC_LOGICAL_LNK_DN;
- ibmvnic_send_crq(adapter, &crq);
+ tx_scrqs = be32_to_cpu(adapter->login_rsp_buf->num_txsubm_subcrqs);
+ for (i = 0; i < tx_scrqs; i++) {
+ struct ibmvnic_tx_pool *tx_pool = &adapter->tx_pool[i];
- for (i = 0; i < be32_to_cpu(adapter->login_rsp_buf->num_txsubm_subcrqs);
- i++) {
- kfree(adapter->tx_pool[i].tx_buff);
- free_long_term_buff(adapter,
- &adapter->tx_pool[i].long_term_buff);
- kfree(adapter->tx_pool[i].free_map);
+ kfree(tx_pool->tx_buff);
+ free_long_term_buff(adapter, &tx_pool->long_term_buff);
+ kfree(tx_pool->free_map);
}
kfree(adapter->tx_pool);
adapter->tx_pool = NULL;
- for (i = 0; i < be32_to_cpu(adapter->login_rsp_buf->num_rxadd_subcrqs);
- i++) {
- free_rx_pool(adapter, &adapter->rx_pool[i]);
- free_long_term_buff(adapter,
- &adapter->rx_pool[i].long_term_buff);
+ rx_scrqs = be32_to_cpu(adapter->login_rsp_buf->num_rxadd_subcrqs);
+ for (i = 0; i < rx_scrqs; i++) {
+ struct ibmvnic_rx_pool *rx_pool = &adapter->rx_pool[i];
+
+ free_rx_pool(adapter, rx_pool);
+ free_long_term_buff(adapter, &rx_pool->long_term_buff);
}
kfree(adapter->rx_pool);
adapter->rx_pool = NULL;
- adapter->closing = false;
+ release_sub_crqs(adapter);
+ ibmvnic_release_crq_queue(adapter);
+ if (adapter->debugfs_dir && !IS_ERR(adapter->debugfs_dir))
+ debugfs_remove_recursive(adapter->debugfs_dir);
+
+ if (adapter->stats_token)
+ dma_unmap_single(dev, adapter->stats_token,
+ sizeof(struct ibmvnic_statistics),
+ DMA_FROM_DEVICE);
+
+ if (adapter->ras_comps)
+ dma_free_coherent(dev, adapter->ras_comp_num *
+ sizeof(struct ibmvnic_fw_component),
+ adapter->ras_comps, adapter->ras_comps_tok);
+
+ kfree(adapter->ras_comp_int);
+}
+
+static int ibmvnic_close(struct net_device *netdev)
+{
+ struct ibmvnic_adapter *adapter = netdev_priv(netdev);
+ union ibmvnic_crq crq;
+ int i;
+
+ adapter->closing = true;
+
+ for (i = 0; i < adapter->req_rx_queues; i++)
+ napi_disable(&adapter->napi[i]);
+
+ if (!adapter->failover)
+ netif_tx_stop_all_queues(netdev);
+
+ memset(&crq, 0, sizeof(crq));
+ crq.logical_link_state.first = IBMVNIC_CRQ_CMD;
+ crq.logical_link_state.cmd = LOGICAL_LINK_STATE;
+ crq.logical_link_state.link_state = IBMVNIC_LOGICAL_LNK_DN;
+ ibmvnic_send_crq(adapter, &crq);
+
+ ibmvnic_release_resources(adapter);
+
+ adapter->is_closed = true;
+ adapter->closing = false;
return 0;
}
@@ -3421,8 +3511,7 @@ static void ibmvnic_handle_crq(union ibmvnic_crq *crq,
dma_unmap_single(dev, adapter->ip_offload_ctrl_tok,
sizeof(adapter->ip_offload_ctrl),
DMA_TO_DEVICE);
- /* We're done with the queries, perform the login */
- send_login(adapter);
+ complete(&adapter->init_done);
break;
case REQUEST_RAS_COMP_NUM_RSP:
netdev_dbg(netdev, "Got Request RAS Comp Num Response\n");
@@ -3702,26 +3791,6 @@ static void handle_crq_init_rsp(struct work_struct *work)
goto task_failed;
}
- do {
- if (adapter->renegotiate) {
- adapter->renegotiate = false;
- release_sub_crqs_no_irqs(adapter);
-
- reinit_completion(&adapter->init_done);
- send_cap_queries(adapter);
- if (!wait_for_completion_timeout(&adapter->init_done,
- timeout)) {
- dev_err(dev, "Passive init timeout\n");
- goto task_failed;
- }
- }
- } while (adapter->renegotiate);
- rc = init_sub_crq_irqs(adapter);
-
- if (rc)
- goto task_failed;
-
- netdev->real_num_tx_queues = adapter->req_tx_queues;
netdev->mtu = adapter->req_mtu - ETH_HLEN;
if (adapter->failover) {
@@ -3753,14 +3822,65 @@ task_failed:
dev_err(dev, "Passive initialization was not successful\n");
}
-static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
+static int ibmvnic_init(struct ibmvnic_adapter *adapter)
{
+ struct device *dev = &adapter->vdev->dev;
unsigned long timeout = msecs_to_jiffies(30000);
+ struct dentry *ent;
+ char buf[17]; /* debugfs name buf */
+ int rc;
+
+ rc = ibmvnic_init_crq_queue(adapter);
+ if (rc) {
+ dev_err(dev, "Couldn't initialize crq. rc=%d\n", rc);
+ return rc;
+ }
+
+ adapter->stats_token = dma_map_single(dev, &adapter->stats,
+ sizeof(struct ibmvnic_statistics),
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(dev, adapter->stats_token)) {
+ ibmvnic_release_crq_queue(adapter);
+ dev_err(dev, "Couldn't map stats buffer\n");
+ return -ENOMEM;
+ }
+
+ snprintf(buf, sizeof(buf), "ibmvnic_%x", adapter->vdev->unit_address);
+ ent = debugfs_create_dir(buf, NULL);
+ if (!ent || IS_ERR(ent)) {
+ dev_info(dev, "debugfs create directory failed\n");
+ adapter->debugfs_dir = NULL;
+ } else {
+ adapter->debugfs_dir = ent;
+ ent = debugfs_create_file("dump", S_IRUGO,
+ adapter->debugfs_dir,
+ adapter->netdev, &ibmvnic_dump_ops);
+ if (!ent || IS_ERR(ent)) {
+ dev_info(dev, "debugfs create dump file failed\n");
+ adapter->debugfs_dump = NULL;
+ } else {
+ adapter->debugfs_dump = ent;
+ }
+ }
+
+ init_completion(&adapter->init_done);
+ ibmvnic_send_crq_init(adapter);
+ if (!wait_for_completion_timeout(&adapter->init_done, timeout)) {
+ dev_err(dev, "Initialization sequence timed out\n");
+ if (adapter->debugfs_dir && !IS_ERR(adapter->debugfs_dir))
+ debugfs_remove_recursive(adapter->debugfs_dir);
+ ibmvnic_release_crq_queue(adapter);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
+{
struct ibmvnic_adapter *adapter;
struct net_device *netdev;
unsigned char *mac_addr_p;
- struct dentry *ent;
- char buf[17]; /* debugfs name buf */
int rc;
dev_dbg(&dev->dev, "entering ibmvnic_probe for UA 0x%x\n",
@@ -3798,118 +3918,36 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
spin_lock_init(&adapter->stats_lock);
- rc = ibmvnic_init_crq_queue(adapter);
- if (rc) {
- dev_err(&dev->dev, "Couldn't initialize crq. rc=%d\n", rc);
- goto free_netdev;
- }
-
INIT_LIST_HEAD(&adapter->errors);
INIT_LIST_HEAD(&adapter->inflight);
spin_lock_init(&adapter->error_list_lock);
spin_lock_init(&adapter->inflight_lock);
- adapter->stats_token = dma_map_single(&dev->dev, &adapter->stats,
- sizeof(struct ibmvnic_statistics),
- DMA_FROM_DEVICE);
- if (dma_mapping_error(&dev->dev, adapter->stats_token)) {
- if (!firmware_has_feature(FW_FEATURE_CMO))
- dev_err(&dev->dev, "Couldn't map stats buffer\n");
- rc = -ENOMEM;
- goto free_crq;
- }
-
- snprintf(buf, sizeof(buf), "ibmvnic_%x", dev->unit_address);
- ent = debugfs_create_dir(buf, NULL);
- if (!ent || IS_ERR(ent)) {
- dev_info(&dev->dev, "debugfs create directory failed\n");
- adapter->debugfs_dir = NULL;
- } else {
- adapter->debugfs_dir = ent;
- ent = debugfs_create_file("dump", S_IRUGO, adapter->debugfs_dir,
- netdev, &ibmvnic_dump_ops);
- if (!ent || IS_ERR(ent)) {
- dev_info(&dev->dev,
- "debugfs create dump file failed\n");
- adapter->debugfs_dump = NULL;
- } else {
- adapter->debugfs_dump = ent;
- }
- }
-
- init_completion(&adapter->init_done);
- ibmvnic_send_crq_init(adapter);
- if (!wait_for_completion_timeout(&adapter->init_done, timeout))
- return 0;
-
- do {
- if (adapter->renegotiate) {
- adapter->renegotiate = false;
- release_sub_crqs_no_irqs(adapter);
-
- reinit_completion(&adapter->init_done);
- send_cap_queries(adapter);
- if (!wait_for_completion_timeout(&adapter->init_done,
- timeout))
- return 0;
- }
- } while (adapter->renegotiate);
-
- rc = init_sub_crq_irqs(adapter);
+ rc = ibmvnic_init(adapter);
if (rc) {
- dev_err(&dev->dev, "failed to initialize sub crq irqs\n");
- goto free_debugfs;
+ free_netdev(netdev);
+ return rc;
}
- netdev->real_num_tx_queues = adapter->req_tx_queues;
netdev->mtu = adapter->req_mtu - ETH_HLEN;
+ adapter->is_closed = false;
rc = register_netdev(netdev);
if (rc) {
dev_err(&dev->dev, "failed to register netdev rc=%d\n", rc);
- goto free_sub_crqs;
+ free_netdev(netdev);
+ return rc;
}
dev_info(&dev->dev, "ibmvnic registered\n");
return 0;
-
-free_sub_crqs:
- release_sub_crqs(adapter);
-free_debugfs:
- if (adapter->debugfs_dir && !IS_ERR(adapter->debugfs_dir))
- debugfs_remove_recursive(adapter->debugfs_dir);
-free_crq:
- ibmvnic_release_crq_queue(adapter);
-free_netdev:
- free_netdev(netdev);
- return rc;
}
static int ibmvnic_remove(struct vio_dev *dev)
{
struct net_device *netdev = dev_get_drvdata(&dev->dev);
- struct ibmvnic_adapter *adapter = netdev_priv(netdev);
unregister_netdev(netdev);
-
- release_sub_crqs(adapter);
-
- ibmvnic_release_crq_queue(adapter);
-
- if (adapter->debugfs_dir && !IS_ERR(adapter->debugfs_dir))
- debugfs_remove_recursive(adapter->debugfs_dir);
-
- dma_unmap_single(&dev->dev, adapter->stats_token,
- sizeof(struct ibmvnic_statistics), DMA_FROM_DEVICE);
-
- if (adapter->ras_comps)
- dma_free_coherent(&dev->dev,
- adapter->ras_comp_num *
- sizeof(struct ibmvnic_fw_component),
- adapter->ras_comps, adapter->ras_comps_tok);
-
- kfree(adapter->ras_comp_int);
-
free_netdev(netdev);
dev_set_drvdata(&dev->dev, NULL);