Merge branch 'ibmvnic-Make-driver-resources-dynamic'

Nathan Fontenot says:

====================
ibmvnic: Make driver resources dynamic

The ibmvnic driver needs to be able to handle the number of tx/rx
sub-crqs changing during a reset of the driver. To do this several
changes need to be made. First the num_active_[tx|rx]_pools
counters need to be re-named to num_active_[tc|rx]_scrqs, and
updated after resource initialization.

With this change we can now release and init the sub crqs and napi
(for rx sub crqs) when the number of sub crqs change.

Lastly, the stats buffer allocation is updated to always allocate
the maximum number of sub-crqs count of stats buffers.

-Nathan
---

Updates for V3:
Patch 3/5 - Make do_h_free parameter a bool

Updates for V2:
Patch 3/5 - Use correct queue count when driver is in probed state
for releasing sub crqs.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2018-02-21 14:21:56 -05:00
commit 960103ff8d
2 changed files with 110 additions and 67 deletions

View File

@ -90,7 +90,7 @@ MODULE_VERSION(IBMVNIC_DRIVER_VERSION);
static int ibmvnic_version = IBMVNIC_INITIAL_VERSION;
static int ibmvnic_remove(struct vio_dev *);
static void release_sub_crqs(struct ibmvnic_adapter *);
static void release_sub_crqs(struct ibmvnic_adapter *, bool);
static int ibmvnic_reset_crq(struct ibmvnic_adapter *);
static int ibmvnic_send_crq_init(struct ibmvnic_adapter *);
static int ibmvnic_reenable_crq_queue(struct ibmvnic_adapter *);
@ -361,14 +361,14 @@ static void release_stats_buffers(struct ibmvnic_adapter *adapter)
static int init_stats_buffers(struct ibmvnic_adapter *adapter)
{
adapter->tx_stats_buffers =
kcalloc(adapter->req_tx_queues,
kcalloc(IBMVNIC_MAX_QUEUES,
sizeof(struct ibmvnic_tx_queue_stats),
GFP_KERNEL);
if (!adapter->tx_stats_buffers)
return -ENOMEM;
adapter->rx_stats_buffers =
kcalloc(adapter->req_rx_queues,
kcalloc(IBMVNIC_MAX_QUEUES,
sizeof(struct ibmvnic_rx_queue_stats),
GFP_KERNEL);
if (!adapter->rx_stats_buffers)
@ -461,7 +461,7 @@ static void release_rx_pools(struct ibmvnic_adapter *adapter)
if (!adapter->rx_pool)
return;
for (i = 0; i < adapter->num_active_rx_pools; i++) {
for (i = 0; i < adapter->num_active_rx_scrqs; i++) {
rx_pool = &adapter->rx_pool[i];
netdev_dbg(adapter->netdev, "Releasing rx_pool[%d]\n", i);
@ -484,7 +484,6 @@ static void release_rx_pools(struct ibmvnic_adapter *adapter)
kfree(adapter->rx_pool);
adapter->rx_pool = NULL;
adapter->num_active_rx_pools = 0;
}
static int init_rx_pools(struct net_device *netdev)
@ -509,8 +508,6 @@ static int init_rx_pools(struct net_device *netdev)
return -1;
}
adapter->num_active_rx_pools = 0;
for (i = 0; i < rxadd_subcrqs; i++) {
rx_pool = &adapter->rx_pool[i];
@ -554,8 +551,6 @@ static int init_rx_pools(struct net_device *netdev)
rx_pool->next_free = 0;
}
adapter->num_active_rx_pools = rxadd_subcrqs;
return 0;
}
@ -613,7 +608,7 @@ static void release_tx_pools(struct ibmvnic_adapter *adapter)
if (!adapter->tx_pool)
return;
for (i = 0; i < adapter->num_active_tx_pools; i++) {
for (i = 0; i < adapter->num_active_tx_scrqs; i++) {
netdev_dbg(adapter->netdev, "Releasing tx_pool[%d]\n", i);
tx_pool = &adapter->tx_pool[i];
kfree(tx_pool->tx_buff);
@ -624,7 +619,6 @@ static void release_tx_pools(struct ibmvnic_adapter *adapter)
kfree(adapter->tx_pool);
adapter->tx_pool = NULL;
adapter->num_active_tx_pools = 0;
}
static int init_tx_pools(struct net_device *netdev)
@ -641,8 +635,6 @@ static int init_tx_pools(struct net_device *netdev)
if (!adapter->tx_pool)
return -1;
adapter->num_active_tx_pools = 0;
for (i = 0; i < tx_subcrqs; i++) {
tx_pool = &adapter->tx_pool[i];
@ -690,8 +682,6 @@ static int init_tx_pools(struct net_device *netdev)
tx_pool->producer_index = 0;
}
adapter->num_active_tx_pools = tx_subcrqs;
return 0;
}
@ -740,6 +730,43 @@ static void ibmvnic_napi_disable(struct ibmvnic_adapter *adapter)
adapter->napi_enabled = false;
}
static int init_napi(struct ibmvnic_adapter *adapter)
{
int i;
adapter->napi = kcalloc(adapter->req_rx_queues,
sizeof(struct napi_struct), GFP_KERNEL);
if (!adapter->napi)
return -ENOMEM;
for (i = 0; i < adapter->req_rx_queues; i++) {
netdev_dbg(adapter->netdev, "Adding napi[%d]\n", i);
netif_napi_add(adapter->netdev, &adapter->napi[i],
ibmvnic_poll, NAPI_POLL_WEIGHT);
}
return 0;
}
static void release_napi(struct ibmvnic_adapter *adapter)
{
int i;
if (!adapter->napi)
return;
for (i = 0; i < adapter->num_active_rx_scrqs; i++) {
if (&adapter->napi[i]) {
netdev_dbg(adapter->netdev,
"Releasing napi[%d]\n", i);
netif_napi_del(&adapter->napi[i]);
}
}
kfree(adapter->napi);
adapter->napi = NULL;
}
static int ibmvnic_login(struct net_device *netdev)
{
struct ibmvnic_adapter *adapter = netdev_priv(netdev);
@ -750,7 +777,7 @@ static int ibmvnic_login(struct net_device *netdev)
do {
if (adapter->renegotiate) {
adapter->renegotiate = false;
release_sub_crqs(adapter);
release_sub_crqs(adapter, 1);
reinit_completion(&adapter->init_done);
send_cap_queries(adapter);
@ -805,8 +832,6 @@ static void release_login_rsp_buffer(struct ibmvnic_adapter *adapter)
static void release_resources(struct ibmvnic_adapter *adapter)
{
int i;
release_vpd_data(adapter);
release_tx_pools(adapter);
@ -815,19 +840,7 @@ static void release_resources(struct ibmvnic_adapter *adapter)
release_stats_token(adapter);
release_stats_buffers(adapter);
release_error_buffers(adapter);
if (adapter->napi) {
for (i = 0; i < adapter->req_rx_queues; i++) {
if (&adapter->napi[i]) {
netdev_dbg(adapter->netdev,
"Releasing napi[%d]\n", i);
netif_napi_del(&adapter->napi[i]);
}
}
}
kfree(adapter->napi);
adapter->napi = NULL;
release_napi(adapter);
release_login_rsp_buffer(adapter);
}
@ -947,7 +960,7 @@ static int ibmvnic_get_vpd(struct ibmvnic_adapter *adapter)
static int init_resources(struct ibmvnic_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
int i, rc;
int rc;
rc = set_real_num_queues(netdev);
if (rc)
@ -973,16 +986,10 @@ static int init_resources(struct ibmvnic_adapter *adapter)
}
adapter->map_id = 1;
adapter->napi = kcalloc(adapter->req_rx_queues,
sizeof(struct napi_struct), GFP_KERNEL);
if (!adapter->napi)
return -ENOMEM;
for (i = 0; i < adapter->req_rx_queues; i++) {
netdev_dbg(netdev, "Adding napi[%d]\n", i);
netif_napi_add(netdev, &adapter->napi[i], ibmvnic_poll,
NAPI_POLL_WEIGHT);
}
rc = init_napi(adapter);
if (rc)
return rc;
send_map_query(adapter);
@ -991,6 +998,10 @@ static int init_resources(struct ibmvnic_adapter *adapter)
return rc;
rc = init_tx_pools(netdev);
adapter->num_active_tx_scrqs = adapter->req_tx_queues;
adapter->num_active_rx_scrqs = adapter->req_rx_queues;
return rc;
}
@ -1654,7 +1665,7 @@ static int do_reset(struct ibmvnic_adapter *adapter,
if (adapter->reset_reason == VNIC_RESET_CHANGE_PARAM ||
adapter->wait_for_reset) {
release_resources(adapter);
release_sub_crqs(adapter);
release_sub_crqs(adapter, 1);
release_crq_queue(adapter);
}
@ -1692,6 +1703,12 @@ static int do_reset(struct ibmvnic_adapter *adapter,
release_tx_pools(adapter);
init_rx_pools(netdev);
init_tx_pools(netdev);
release_napi(adapter);
init_napi(adapter);
adapter->num_active_tx_scrqs = adapter->req_tx_queues;
adapter->num_active_rx_scrqs = adapter->req_rx_queues;
} else {
rc = reset_tx_pools(adapter);
if (rc)
@ -2291,24 +2308,27 @@ static int reset_sub_crq_queues(struct ibmvnic_adapter *adapter)
}
static void release_sub_crq_queue(struct ibmvnic_adapter *adapter,
struct ibmvnic_sub_crq_queue *scrq)
struct ibmvnic_sub_crq_queue *scrq,
bool do_h_free)
{
struct device *dev = &adapter->vdev->dev;
long rc;
netdev_dbg(adapter->netdev, "Releasing sub-CRQ\n");
/* Close the sub-crqs */
do {
rc = plpar_hcall_norets(H_FREE_SUB_CRQ,
adapter->vdev->unit_address,
scrq->crq_num);
} while (rc == H_BUSY || H_IS_LONG_BUSY(rc));
if (do_h_free) {
/* Close the sub-crqs */
do {
rc = plpar_hcall_norets(H_FREE_SUB_CRQ,
adapter->vdev->unit_address,
scrq->crq_num);
} while (rc == H_BUSY || H_IS_LONG_BUSY(rc));
if (rc) {
netdev_err(adapter->netdev,
"Failed to release sub-CRQ %16lx, rc = %ld\n",
scrq->crq_num, rc);
if (rc) {
netdev_err(adapter->netdev,
"Failed to release sub-CRQ %16lx, rc = %ld\n",
scrq->crq_num, rc);
}
}
dma_unmap_single(dev, scrq->msg_token, 4 * PAGE_SIZE,
@ -2376,12 +2396,21 @@ zero_page_failed:
return NULL;
}
static void release_sub_crqs(struct ibmvnic_adapter *adapter)
static void release_sub_crqs(struct ibmvnic_adapter *adapter, bool do_h_free)
{
u64 num_tx_scrqs, num_rx_scrqs;
int i;
if (adapter->state == VNIC_PROBED) {
num_tx_scrqs = adapter->req_tx_queues;
num_rx_scrqs = adapter->req_rx_queues;
} else {
num_tx_scrqs = adapter->num_active_tx_scrqs;
num_rx_scrqs = adapter->num_active_rx_scrqs;
}
if (adapter->tx_scrq) {
for (i = 0; i < adapter->req_tx_queues; i++) {
for (i = 0; i < num_tx_scrqs; i++) {
if (!adapter->tx_scrq[i])
continue;
@ -2394,7 +2423,8 @@ static void release_sub_crqs(struct ibmvnic_adapter *adapter)
adapter->tx_scrq[i]->irq = 0;
}
release_sub_crq_queue(adapter, adapter->tx_scrq[i]);
release_sub_crq_queue(adapter, adapter->tx_scrq[i],
do_h_free);
}
kfree(adapter->tx_scrq);
@ -2402,7 +2432,7 @@ static void release_sub_crqs(struct ibmvnic_adapter *adapter)
}
if (adapter->rx_scrq) {
for (i = 0; i < adapter->req_rx_queues; i++) {
for (i = 0; i < num_rx_scrqs; i++) {
if (!adapter->rx_scrq[i])
continue;
@ -2415,7 +2445,8 @@ static void release_sub_crqs(struct ibmvnic_adapter *adapter)
adapter->rx_scrq[i]->irq = 0;
}
release_sub_crq_queue(adapter, adapter->rx_scrq[i]);
release_sub_crq_queue(adapter, adapter->rx_scrq[i],
do_h_free);
}
kfree(adapter->rx_scrq);
@ -2625,7 +2656,7 @@ req_tx_irq_failed:
free_irq(adapter->tx_scrq[j]->irq, adapter->tx_scrq[j]);
irq_dispose_mapping(adapter->rx_scrq[j]->irq);
}
release_sub_crqs(adapter);
release_sub_crqs(adapter, 1);
return rc;
}
@ -2707,7 +2738,7 @@ rx_failed:
adapter->tx_scrq = NULL;
tx_failed:
for (i = 0; i < registered_queues; i++)
release_sub_crq_queue(adapter, allqueues[i]);
release_sub_crq_queue(adapter, allqueues[i], 1);
kfree(allqueues);
return -1;
}
@ -4334,6 +4365,7 @@ static int ibmvnic_init(struct ibmvnic_adapter *adapter)
{
struct device *dev = &adapter->vdev->dev;
unsigned long timeout = msecs_to_jiffies(30000);
u64 old_num_rx_queues, old_num_tx_queues;
int rc;
if (adapter->resetting && !adapter->wait_for_reset) {
@ -4351,6 +4383,9 @@ static int ibmvnic_init(struct ibmvnic_adapter *adapter)
adapter->from_passive_init = false;
old_num_rx_queues = adapter->req_rx_queues;
old_num_tx_queues = adapter->req_tx_queues;
init_completion(&adapter->init_done);
adapter->init_done_rc = 0;
ibmvnic_send_crq_init(adapter);
@ -4370,10 +4405,18 @@ static int ibmvnic_init(struct ibmvnic_adapter *adapter)
return -1;
}
if (adapter->resetting && !adapter->wait_for_reset)
rc = reset_sub_crq_queues(adapter);
else
if (adapter->resetting && !adapter->wait_for_reset) {
if (adapter->req_rx_queues != old_num_rx_queues ||
adapter->req_tx_queues != old_num_tx_queues) {
release_sub_crqs(adapter, 0);
rc = init_sub_crqs(adapter);
} else {
rc = reset_sub_crq_queues(adapter);
}
} else {
rc = init_sub_crqs(adapter);
}
if (rc) {
dev_err(dev, "Initialization of sub crqs failed\n");
release_crq_queue(adapter);
@ -4473,7 +4516,7 @@ ibmvnic_register_fail:
device_remove_file(&dev->dev, &dev_attr_failover);
ibmvnic_init_fail:
release_sub_crqs(adapter);
release_sub_crqs(adapter, 1);
release_crq_queue(adapter);
free_netdev(netdev);
@ -4490,7 +4533,7 @@ static int ibmvnic_remove(struct vio_dev *dev)
mutex_lock(&adapter->reset_lock);
release_resources(adapter);
release_sub_crqs(adapter);
release_sub_crqs(adapter, 1);
release_crq_queue(adapter);
adapter->state = VNIC_REMOVED;

View File

@ -1092,8 +1092,8 @@ struct ibmvnic_adapter {
u64 opt_rxba_entries_per_subcrq;
__be64 tx_rx_desc_req;
u8 map_id;
u64 num_active_rx_pools;
u64 num_active_tx_pools;
u64 num_active_rx_scrqs;
u64 num_active_tx_scrqs;
struct tasklet_struct tasklet;
enum vnic_state state;