// SPDX-License-Identifier: GPL-2.0-or-later /**************************************************************************/ /* */ /* IBM System i and System p Virtual NIC Device Driver */ /* Copyright (C) 2014 IBM Corp. */ /* Santiago Leon (santi_leon@yahoo.com) */ /* Thomas Falcon (tlfalcon@linux.vnet.ibm.com) */ /* John Allen (jallen@linux.vnet.ibm.com) */ /* */ /* */ /* This module contains the implementation of a virtual ethernet device */ /* for use with IBM i/p Series LPAR Linux. It utilizes the logical LAN */ /* option of the RS/6000 Platform Architecture to interface with virtual */ /* ethernet NICs that are presented to the partition by the hypervisor. */ /* */ /* Messages are passed between the VNIC driver and the VNIC server using */ /* Command/Response Queues (CRQs) and sub CRQs (sCRQs). CRQs are used to */ /* issue and receive commands that initiate communication with the server */ /* on driver initialization. Sub CRQs (sCRQs) are similar to CRQs, but */ /* are used by the driver to notify the server that a packet is */ /* ready for transmission or that a buffer has been added to receive a */ /* packet. Subsequently, sCRQs are used by the server to notify the */ /* driver that a packet transmission has been completed or that a packet */ /* has been received and placed in a waiting buffer. */ /* */ /* In lieu of a more conventional "on-the-fly" DMA mapping strategy in */ /* which skbs are DMA mapped and immediately unmapped when the transmit */ /* or receive has been completed, the VNIC driver is required to use */ /* "long term mapping". This entails that large, continuous DMA mapped */ /* buffers are allocated on driver initialization and these buffers are */ /* then continuously reused to pass skbs to and from the VNIC server. */ /* */ /**************************************************************************/
staticconstchar ibmvnic_driver_name[] = "ibmvnic"; staticconstchar ibmvnic_driver_string[] = "IBM System i/p Virtual NIC Driver";
MODULE_AUTHOR("Santiago Leon");
MODULE_DESCRIPTION("IBM System i/p Virtual NIC Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(IBMVNIC_DRIVER_VERSION);
netdev_dbg(adapter->netdev, "%s: Cleaning irq affinity hints", __func__); if (txqs) { for (i = 0; i < num_txqs; i++)
ibmvnic_clean_queue_affinity(adapter, txqs[i]);
} if (rxqs) { for (i = 0; i < num_rxqs; i++)
ibmvnic_clean_queue_affinity(adapter, rxqs[i]);
}
}
staticint ibmvnic_set_queue_affinity(struct ibmvnic_sub_crq_queue *queue, unsignedint *cpu, int *stragglers, int stride)
{
cpumask_var_t mask; int i; int rc = 0;
if (!(queue && queue->irq)) return rc;
/* cpumask_var_t is either a pointer or array, allocation works here */ if (!zalloc_cpumask_var(&mask, GFP_KERNEL)) return -ENOMEM;
/* while we have extra cpu give one extra to this irq */ if (*stragglers) {
stride++;
(*stragglers)--;
} /* atomic write is safer than writing bit by bit directly */
for_each_online_cpu_wrap(i, *cpu) { if (!stride--) { /* For the next queue we start from the first * unused CPU in this queue
*/
*cpu = i; break;
}
cpumask_set_cpu(i, mask);
}
/** * ibmvnic_wait_for_completion - Check device state and wait for completion * @adapter: private device data * @comp_done: completion structure to wait for * @timeout: time to wait in milliseconds * * Wait for a completion signal or until the timeout limit is reached * while checking that the device is still active.
*/ staticint ibmvnic_wait_for_completion(struct ibmvnic_adapter *adapter, struct completion *comp_done, unsignedlong timeout)
{ struct net_device *netdev; unsignedlong div_timeout;
u8 retry;
netdev = adapter->netdev;
retry = 5;
div_timeout = msecs_to_jiffies(timeout / retry); while (true) { if (!adapter->crq.active) {
netdev_err(netdev, "Device down!\n"); return -ENODEV;
} if (!retry--) break; if (wait_for_completion_timeout(comp_done, div_timeout)) return 0;
}
netdev_err(netdev, "Operation timed out.\n"); return -ETIMEDOUT;
}
/** * reuse_ltb() - Check if a long term buffer can be reused * @ltb: The long term buffer to be checked * @size: The size of the long term buffer. * * An LTB can be reused unless its size has changed. * * Return: Return true if the LTB can be reused, false otherwise.
*/ staticbool reuse_ltb(struct ibmvnic_long_term_buff *ltb, int size)
{ return (ltb->buff && ltb->size == size);
}
/** * alloc_long_term_buff() - Allocate a long term buffer (LTB) * * @adapter: ibmvnic adapter associated to the LTB * @ltb: container object for the LTB * @size: size of the LTB * * Allocate an LTB of the specified size and notify VIOS. * * If the given @ltb already has the correct size, reuse it. Otherwise if * its non-NULL, free it. Then allocate a new one of the correct size. * Notify the VIOS either way since we may now be working with a new VIOS. * * Allocating larger chunks of memory during resets, specially LPM or under * low memory situations can cause resets to fail/timeout and for LPAR to * lose connectivity. So hold onto the LTB even if we fail to communicate * with the VIOS and reuse it on next open. Free LTB when adapter is closed. * * Return: 0 if we were able to allocate the LTB and notify the VIOS and * a negative value otherwise.
*/ staticint alloc_long_term_buff(struct ibmvnic_adapter *adapter, struct ibmvnic_long_term_buff *ltb, int size)
{ struct device *dev = &adapter->vdev->dev;
u64 prev = 0; int rc;
if (!reuse_ltb(ltb, size)) {
dev_dbg(dev, "LTB size changed from 0x%llx to 0x%x, reallocating\n",
ltb->size, size);
prev = ltb->size;
free_long_term_buff(adapter, ltb);
}
if (ltb->buff) {
dev_dbg(dev, "Reusing LTB [map %d, size 0x%llx]\n",
ltb->map_id, ltb->size);
} else {
ltb->buff = dma_alloc_coherent(dev, size, <b->addr,
GFP_KERNEL); if (!ltb->buff) {
dev_err(dev, "Couldn't alloc long term buffer\n"); return -ENOMEM;
}
ltb->size = size;
/* VIOS automatically unmaps the long term buffer at remote * end for the following resets: * FAILOVER, MOBILITY, TIMEOUT.
*/ if (adapter->reset_reason != VNIC_RESET_FAILOVER &&
adapter->reset_reason != VNIC_RESET_MOBILITY &&
adapter->reset_reason != VNIC_RESET_TIMEOUT)
send_request_unmap(adapter, ltb->map_id);
ltb->buff = NULL; /* mark this map_id free */
bitmap_clear(adapter->map_ids, ltb->map_id, 1);
ltb->map_id = 0;
}
/** * free_ltb_set - free the given set of long term buffers (LTBS) * @adapter: The ibmvnic adapter containing this ltb set * @ltb_set: The ltb_set to be freed * * Free the set of LTBs in the given set.
*/
staticvoid free_ltb_set(struct ibmvnic_adapter *adapter, struct ibmvnic_ltb_set *ltb_set)
{ int i;
for (i = 0; i < ltb_set->num_ltbs; i++)
free_long_term_buff(adapter, <b_set->ltbs[i]);
/** * alloc_ltb_set() - Allocate a set of long term buffers (LTBs) * * @adapter: ibmvnic adapter associated to the LTB * @ltb_set: container object for the set of LTBs * @num_buffs: Number of buffers in the LTB * @buff_size: Size of each buffer in the LTB * * Allocate a set of LTBs to accommodate @num_buffs buffers of @buff_size * each. We currently cap size each LTB to IBMVNIC_ONE_LTB_SIZE. If the * new set of LTBs have fewer LTBs than the old set, free the excess LTBs. * If new set needs more than in old set, allocate the remaining ones. * Try and reuse as many LTBs as possible and avoid reallocation. * * Any changes to this allocation strategy must be reflected in * map_rxpool_buff_to_ltb() and map_txpool_buff_to_ltb().
*/ staticint alloc_ltb_set(struct ibmvnic_adapter *adapter, struct ibmvnic_ltb_set *ltb_set, int num_buffs, int buff_size)
{ struct device *dev = &adapter->vdev->dev; struct ibmvnic_ltb_set old_set; struct ibmvnic_ltb_set new_set; int rem_size; int tot_size; /* size of all ltbs */ int ltb_size; /* size of one ltb */ int nltbs; int rc; int n; int i;
nltbs = tot_size / ltb_size; if (tot_size % ltb_size)
nltbs++;
old_set = *ltb_set;
if (old_set.num_ltbs == nltbs) {
new_set = old_set;
} else { int tmp = nltbs * sizeof(struct ibmvnic_long_term_buff);
new_set.ltbs = kzalloc(tmp, GFP_KERNEL); if (!new_set.ltbs) return -ENOMEM;
new_set.num_ltbs = nltbs;
/* Free any excess ltbs in old set */ for (i = new_set.num_ltbs; i < old_set.num_ltbs; i++)
free_long_term_buff(adapter, &old_set.ltbs[i]);
/* Copy remaining ltbs to new set. All LTBs except the * last one are of the same size. alloc_long_term_buff() * will realloc if the size changes.
*/
n = min(old_set.num_ltbs, new_set.num_ltbs); for (i = 0; i < n; i++)
new_set.ltbs[i] = old_set.ltbs[i];
/* Any additional ltbs in new set will have NULL ltbs for * now and will be allocated in alloc_long_term_buff().
*/
/* We no longer need the old_set so free it. Note that we * may have reused some ltbs from old set and freed excess * ltbs above. So we only need to free the container now * not the LTBs themselves. (i.e. dont free_ltb_set()!)
*/
kfree(old_set.ltbs);
old_set.ltbs = NULL;
old_set.num_ltbs = 0;
/* Install the new set. If allocations fail below, we will * retry later and know what size LTBs we need.
*/
*ltb_set = new_set;
}
i = 0;
rem_size = tot_size; while (rem_size) { if (ltb_size > rem_size)
ltb_size = rem_size;
return 0;
out: /* We may have allocated one/more LTBs before failing and we * want to try and reuse on next reset. So don't free ltb set.
*/ return rc;
}
/** * map_rxpool_buf_to_ltb - Map given rxpool buffer to offset in an LTB. * @rxpool: The receive buffer pool containing buffer * @bufidx: Index of buffer in rxpool * @ltbp: (Output) pointer to the long term buffer containing the buffer * @offset: (Output) offset of buffer in the LTB from @ltbp * * Map the given buffer identified by [rxpool, bufidx] to an LTB in the * pool and its corresponding offset. Assume for now that each LTB is of * different size but could possibly be optimized based on the allocation * strategy in alloc_ltb_set().
*/ staticvoid map_rxpool_buf_to_ltb(struct ibmvnic_rx_pool *rxpool, unsignedint bufidx, struct ibmvnic_long_term_buff **ltbp, unsignedint *offset)
{ struct ibmvnic_long_term_buff *ltb; int nbufs; /* # of buffers in one ltb */ int i;
WARN_ON(bufidx >= rxpool->size);
for (i = 0; i < rxpool->ltb_set.num_ltbs; i++) {
ltb = &rxpool->ltb_set.ltbs[i];
nbufs = ltb->size / rxpool->buff_size; if (bufidx < nbufs) break;
bufidx -= nbufs;
}
/** * map_txpool_buf_to_ltb - Map given txpool buffer to offset in an LTB. * @txpool: The transmit buffer pool containing buffer * @bufidx: Index of buffer in txpool * @ltbp: (Output) pointer to the long term buffer (LTB) containing the buffer * @offset: (Output) offset of buffer in the LTB from @ltbp * * Map the given buffer identified by [txpool, bufidx] to an LTB in the * pool and its corresponding offset.
*/ staticvoid map_txpool_buf_to_ltb(struct ibmvnic_tx_pool *txpool, unsignedint bufidx, struct ibmvnic_long_term_buff **ltbp, unsignedint *offset)
{ struct ibmvnic_long_term_buff *ltb; int nbufs; /* # of buffers in one ltb */ int i;
WARN_ON_ONCE(bufidx >= txpool->num_buffers);
for (i = 0; i < txpool->ltb_set.num_ltbs; i++) {
ltb = &txpool->ltb_set.ltbs[i];
nbufs = ltb->size / txpool->buf_size; if (bufidx < nbufs) break;
bufidx -= nbufs;
}
/* netdev_skb_alloc() could have failed after we saved a few skbs * in the indir_buf and we would not have sent them to VIOS yet. * To account for them, start the loop at ind_bufp->index rather * than 0. If we pushed all the skbs to VIOS, ind_bufp->index will * be 0.
*/ for (i = ind_bufp->index; i < count; ++i) {
bufidx = pool->free_map[pool->next_free];
/* We maybe reusing the skb from earlier resets. Allocate * only if necessary. But since the LTB may have changed * during reset (see init_rx_pools()), update LTB below * even if reusing skb.
*/
skb = pool->rx_buff[bufidx].skb; if (!skb) {
skb = netdev_alloc_skb(adapter->netdev,
pool->buff_size); if (!skb) {
dev_err(dev, "Couldn't replenish rx buff\n");
adapter->replenish_no_mem++; break;
}
}
/* Copy the skb to the long term mapped DMA buffer */
map_rxpool_buf_to_ltb(pool, bufidx, <b, &offset);
dst = ltb->buff + offset;
memset(dst, 0, pool->buff_size);
dma_addr = ltb->addr + offset;
/* add the skb to an rx_buff in the pool */
pool->rx_buff[bufidx].data = dst;
pool->rx_buff[bufidx].dma = dma_addr;
pool->rx_buff[bufidx].skb = skb;
pool->rx_buff[bufidx].pool_index = pool->index;
pool->rx_buff[bufidx].size = pool->buff_size;
/* queue the rx_buff for the next send_subcrq_indirect */
sub_crq = &ind_bufp->indir_arr[ind_bufp->index++];
memset(sub_crq, 0, sizeof(*sub_crq));
sub_crq->rx_add.first = IBMVNIC_CRQ_CMD;
sub_crq->rx_add.correlator =
cpu_to_be64((u64)&pool->rx_buff[bufidx]);
sub_crq->rx_add.ioba = cpu_to_be32(dma_addr);
sub_crq->rx_add.map_id = ltb->map_id;
/* The length field of the sCRQ is defined to be 24 bits so the * buffer size needs to be left shifted by a byte before it is * converted to big endian to prevent the last byte from being * truncated.
*/ #ifdef __LITTLE_ENDIAN__
shift = 8; #endif
sub_crq->rx_add.len = cpu_to_be32(pool->buff_size << shift);
/* if send_subcrq_indirect queue is full, flush to VIOS */ if (ind_bufp->index == IBMVNIC_MAX_IND_DESCS ||
i == count - 1) {
lpar_rc =
send_subcrq_indirect(adapter, handle,
(u64)ind_bufp->indir_dma,
(u64)ind_bufp->index); if (lpar_rc != H_SUCCESS) goto failure;
buffers_added += ind_bufp->index;
adapter->replenish_add_buff_success += ind_bufp->index;
ind_bufp->index = 0;
}
}
atomic_add(buffers_added, &pool->available); return;
failure: if (lpar_rc != H_PARAMETER && lpar_rc != H_CLOSED)
dev_err_ratelimited(dev, "rx: replenish packet buffer failed\n"); for (i = ind_bufp->index - 1; i >= 0; --i) { struct ibmvnic_rx_buff *rx_buff;
pool->next_free = pool->next_free == 0 ?
pool->size - 1 : pool->next_free - 1;
sub_crq = &ind_bufp->indir_arr[i];
rx_buff = (struct ibmvnic_rx_buff *)
be64_to_cpu(sub_crq->rx_add.correlator);
bufidx = (int)(rx_buff - pool->rx_buff);
pool->free_map[pool->next_free] = bufidx;
dev_kfree_skb_any(pool->rx_buff[bufidx].skb);
pool->rx_buff[bufidx].skb = NULL;
}
adapter->replenish_add_buff_failure += ind_bufp->index;
atomic_add(buffers_added, &pool->available);
ind_bufp->index = 0; if (lpar_rc == H_CLOSED || adapter->failover_pending) { /* Disable buffer pool replenishment and report carrier off if * queue is closed or pending failover. * Firmware guarantees that a signal will be sent to the * driver, triggering a reset.
*/
deactivate_rx_pools(adapter);
netif_carrier_off(adapter->netdev);
}
}
staticvoid replenish_pools(struct ibmvnic_adapter *adapter)
{ int i;
adapter->replenish_task_cycles++; for (i = 0; i < adapter->num_active_rx_pools; i++) { if (adapter->rx_pool[i].active)
replenish_rx_pool(adapter, &adapter->rx_pool[i]);
}
/** * release_rx_pools() - Release any rx pools attached to @adapter. * @adapter: ibmvnic adapter * * Safe to call this multiple times - even if no pools are attached.
*/ staticvoid release_rx_pools(struct ibmvnic_adapter *adapter)
{ struct ibmvnic_rx_pool *rx_pool; int i, j;
if (!adapter->rx_pool) return;
for (i = 0; i < adapter->num_active_rx_pools; i++) {
rx_pool = &adapter->rx_pool[i];
/** * reuse_rx_pools() - Check if the existing rx pools can be reused. * @adapter: ibmvnic adapter * * Check if the existing rx pools in the adapter can be reused. The * pools can be reused if the pool parameters (number of pools, * number of buffers in the pool and size of each buffer) have not * changed. * * NOTE: This assumes that all pools have the same number of buffers * which is the case currently. If that changes, we must fix this. * * Return: true if the rx pools can be reused, false otherwise.
*/ staticbool reuse_rx_pools(struct ibmvnic_adapter *adapter)
{
u64 old_num_pools, new_num_pools;
u64 old_pool_size, new_pool_size;
u64 old_buff_size, new_buff_size;
/** * init_rx_pools(): Initialize the set of receiver pools in the adapter. * @netdev: net device associated with the vnic interface * * Initialize the set of receiver pools in the ibmvnic adapter associated * with the net_device @netdev. If possible, reuse the existing rx pools. * Otherwise free any existing pools and allocate a new set of pools * before initializing them. * * Return: 0 on success and negative value on error.
*/ staticint init_rx_pools(struct net_device *netdev)
{ struct ibmvnic_adapter *adapter = netdev_priv(netdev); struct device *dev = &adapter->vdev->dev; struct ibmvnic_rx_pool *rx_pool;
u64 num_pools;
u64 pool_size; /* # of buffers in one pool */
u64 buff_size; int i, j, rc;
if (reuse_rx_pools(adapter)) {
dev_dbg(dev, "Reusing rx pools\n"); goto update_ltb;
}
/* Allocate/populate the pools. */
release_rx_pools(adapter);
adapter->rx_pool = kcalloc(num_pools, sizeof(struct ibmvnic_rx_pool),
GFP_KERNEL); if (!adapter->rx_pool) {
dev_err(dev, "Failed to allocate rx pools\n"); return -ENOMEM;
}
/* Set num_active_rx_pools early. If we fail below after partial * allocation, release_rx_pools() will know how many to look for.
*/
adapter->num_active_rx_pools = num_pools;
for (i = 0; i < num_pools; i++) {
rx_pool = &adapter->rx_pool[i];
update_ltb: for (i = 0; i < num_pools; i++) {
rx_pool = &adapter->rx_pool[i];
dev_dbg(dev, "Updating LTB for rx pool %d [%d, %d]\n",
i, rx_pool->size, rx_pool->buff_size);
rc = alloc_ltb_set(adapter, &rx_pool->ltb_set,
rx_pool->size, rx_pool->buff_size); if (rc) goto out;
/* NOTE: Don't clear rx_buff->skb here - will leak * memory! replenish_rx_pool() will reuse skbs or * allocate as necessary.
*/
rx_buff = &rx_pool->rx_buff[j];
rx_buff->dma = 0;
rx_buff->data = 0;
rx_buff->size = 0;
rx_buff->pool_index = 0;
}
/* Mark pool "empty" so replenish_rx_pools() will * update the LTB info for each buffer
*/
atomic_set(&rx_pool->available, 0);
rx_pool->next_alloc = 0;
rx_pool->next_free = 0; /* replenish_rx_pool() may have called deactivate_rx_pools() * on failover. Ensure pool is active now.
*/
rx_pool->active = 1;
} return 0;
out_release:
release_rx_pools(adapter);
out: /* We failed to allocate one or more LTBs or map them on the VIOS. * Hold onto the pools and any LTBs that we did allocate/map.
*/ return rc;
}
staticvoid release_vpd_data(struct ibmvnic_adapter *adapter)
{ if (!adapter->vpd) return;
/** * release_tx_pools() - Release any tx pools attached to @adapter. * @adapter: ibmvnic adapter * * Safe to call this multiple times - even if no pools are attached.
*/ staticvoid release_tx_pools(struct ibmvnic_adapter *adapter)
{ int i;
/* init_tx_pools() ensures that ->tx_pool and ->tso_pool are * both NULL or both non-NULL. So we only need to check one.
*/ if (!adapter->tx_pool) return;
for (i = 0; i < adapter->num_active_tx_pools; i++) {
release_one_tx_pool(adapter, &adapter->tx_pool[i]);
release_one_tx_pool(adapter, &adapter->tso_pool[i]);
}
/** * reuse_tx_pools() - Check if the existing tx pools can be reused. * @adapter: ibmvnic adapter * * Check if the existing tx pools in the adapter can be reused. The * pools can be reused if the pool parameters (number of pools, * number of buffers in the pool and mtu) have not changed. * * NOTE: This assumes that all pools have the same number of buffers * which is the case currently. If that changes, we must fix this. * * Return: true if the tx pools can be reused, false otherwise.
*/ staticbool reuse_tx_pools(struct ibmvnic_adapter *adapter)
{
u64 old_num_pools, new_num_pools;
u64 old_pool_size, new_pool_size;
u64 old_mtu, new_mtu;
/** * init_tx_pools(): Initialize the set of transmit pools in the adapter. * @netdev: net device associated with the vnic interface * * Initialize the set of transmit pools in the ibmvnic adapter associated * with the net_device @netdev. If possible, reuse the existing tx pools. * Otherwise free any existing pools and allocate a new set of pools * before initializing them. * * Return: 0 on success and negative value on error.
*/ staticint init_tx_pools(struct net_device *netdev)
{ struct ibmvnic_adapter *adapter = netdev_priv(netdev); struct device *dev = &adapter->vdev->dev; int num_pools;
u64 pool_size; /* # of buffers in pool */
u64 buff_size; int i, j, rc;
num_pools = adapter->req_tx_queues;
/* We must notify the VIOS about the LTB on all resets - but we only * need to alloc/populate pools if either the number of buffers or * size of each buffer in the pool has changed.
*/ if (reuse_tx_pools(adapter)) {
netdev_dbg(netdev, "Reusing tx pools\n"); goto update_ltb;
}
/* Allocate/populate the pools. */
release_tx_pools(adapter);
adapter->tx_pool = kcalloc(num_pools, sizeof(struct ibmvnic_tx_pool), GFP_KERNEL); if (!adapter->tx_pool) return -ENOMEM;
adapter->tso_pool = kcalloc(num_pools, sizeof(struct ibmvnic_tx_pool), GFP_KERNEL); /* To simplify release_tx_pools() ensure that ->tx_pool and * ->tso_pool are either both NULL or both non-NULL.
*/ if (!adapter->tso_pool) {
kfree(adapter->tx_pool);
adapter->tx_pool = NULL; return -ENOMEM;
}
/* Set num_active_tx_pools early. If we fail below after partial * allocation, release_tx_pools() will know how many to look for.
*/
adapter->num_active_tx_pools = num_pools;
update_ltb: /* NOTE: All tx_pools have the same number of buffers (which is * same as pool_size). All tso_pools have IBMVNIC_TSO_BUFS * buffers (see calls init_one_tx_pool() for these). * For consistency, we use tx_pool->num_buffers and * tso_pool->num_buffers below.
*/
rc = -1; for (i = 0; i < num_pools; i++) { struct ibmvnic_tx_pool *tso_pool; struct ibmvnic_tx_pool *tx_pool;
tx_pool = &adapter->tx_pool[i];
dev_dbg(dev, "Updating LTB for tx pool %d [%d, %d]\n",
i, tx_pool->num_buffers, tx_pool->buf_size);
rc = alloc_ltb_set(adapter, &tx_pool->ltb_set,
tx_pool->num_buffers, tx_pool->buf_size); if (rc) goto out;
return 0;
out_release:
release_tx_pools(adapter);
out: /* We failed to allocate one or more LTBs or map them on the VIOS. * Hold onto the pools and any LTBs that we did allocate/map.
*/ return rc;
}
staticvoid ibmvnic_napi_enable(struct ibmvnic_adapter *adapter)
{ int i;
if (adapter->napi_enabled) return;
for (i = 0; i < adapter->req_rx_queues; i++)
napi_enable(&adapter->napi[i]);
adapter->napi_enabled = true;
}
staticvoid ibmvnic_napi_disable(struct ibmvnic_adapter *adapter)
{ int i;
if (!adapter->napi_enabled) return;
for (i = 0; i < adapter->req_rx_queues; i++) {
netdev_dbg(adapter->netdev, "Disabling napi[%d]\n", i);
napi_disable(&adapter->napi[i]);
}
adapter->napi_enabled = false;
}
staticint 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);
}
staticconstchar *adapter_state_to_string(enum vnic_state state)
{ switch (state) { case VNIC_PROBING: return"PROBING"; case VNIC_PROBED: return"PROBED"; case VNIC_OPENING: return"OPENING"; case VNIC_OPEN: return"OPEN"; case VNIC_CLOSING: return"CLOSING"; case VNIC_CLOSED: return"CLOSED"; case VNIC_REMOVING: return"REMOVING"; case VNIC_REMOVED: return"REMOVED"; case VNIC_DOWN: return"DOWN";
} return"UNKNOWN";
}
staticint ibmvnic_login(struct net_device *netdev)
{ unsignedlong flags, timeout = msecs_to_jiffies(20000); struct ibmvnic_adapter *adapter = netdev_priv(netdev); int retry_count = 0; int retries = 10; bool retry; int rc;
do {
retry = false; if (retry_count > retries) {
netdev_warn(netdev, "Login attempts exceeded\n"); return -EACCES;
}
partial_reset: /* adapter login failed, so free any CRQs or sub-CRQs * and register again before attempting to login again. * If we don't do this then the VIOS may think that * we are already logged in and reject any subsequent * attempts
*/
netdev_warn(netdev, "Freeing and re-registering CRQs before attempting to login again\n");
retry = true;
adapter->init_done_rc = 0;
release_sub_crqs(adapter, true); /* Much of this is similar logic as ibmvnic_probe(), * we are essentially re-initializing communication * with the server. We really should not run any * resets/failovers here because this is already a form * of reset and we do not want parallel resets occurring
*/ do {
reinit_init_done(adapter); /* Clear any failovers we got in the previous * pass since we are re-initializing the CRQ
*/
adapter->failover_pending = false;
release_crq_queue(adapter); /* If we don't sleep here then we risk an * unnecessary failover event from the VIOS. * This is a known VIOS issue caused by a vnic * device freeing and registering a CRQ too * quickly.
*/
msleep(1500); /* Avoid any resets, since we are currently * resetting.
*/
spin_lock_irqsave(&adapter->rwi_lock, flags);
flush_reset_queue(adapter);
spin_unlock_irqrestore(&adapter->rwi_lock,
flags);
rc = ibmvnic_reset_init(adapter, false); if (rc)
netdev_err(netdev, "login recovery: Reset init failed %d\n",
rc); /* IBMVNIC_CRQ_INIT will return EAGAIN if it * fails, since ibmvnic_reset_init will free * irq's in failure, we won't be able to receive * new CRQs so we need to keep trying. probe() * handles this similarly.
*/
} while (rc == -EAGAIN && retry_count++ < retries);
}
} while (retry);
netdev_dbg(netdev, "Setting real tx/rx queues (%llx/%llx)\n",
adapter->req_tx_queues, adapter->req_rx_queues);
rc = netif_set_real_num_tx_queues(netdev, adapter->req_tx_queues); if (rc) {
netdev_err(netdev, "failed to set the number of tx queues\n"); return rc;
}
rc = netif_set_real_num_rx_queues(netdev, adapter->req_rx_queues); if (rc)
netdev_err(netdev, "failed to set the number of rx queues\n");
return rc;
}
staticint ibmvnic_get_vpd(struct ibmvnic_adapter *adapter)
{ struct device *dev = &adapter->vdev->dev; union ibmvnic_crq crq; int len = 0; int rc;
/* We're ready to receive frames, enable the sub-crq interrupts and * set the logical link state to up
*/ for (i = 0; i < adapter->req_rx_queues; i++) {
netdev_dbg(netdev, "Enabling rx_scrq[%d] irq\n", i); if (prev_state == VNIC_CLOSED)
enable_irq(adapter->rx_scrq[i]->irq);
enable_scrq_irq(adapter, adapter->rx_scrq[i]);
}
for (i = 0; i < adapter->req_tx_queues; i++) {
netdev_dbg(netdev, "Enabling tx_scrq[%d] irq\n", i); if (prev_state == VNIC_CLOSED)
enable_irq(adapter->tx_scrq[i]->irq);
enable_scrq_irq(adapter, adapter->tx_scrq[i]); /* netdev_tx_reset_queue will reset dql stats. During NON_FATAL * resets, don't reset the stats because there could be batched * skb's waiting to be sent. If we reset dql stats, we risk * num_completed being greater than num_queued. This will cause * a BUG_ON in dql_completed().
*/ if (adapter->reset_reason != VNIC_RESET_NON_FATAL)
netdev_tx_reset_queue(netdev_get_tx_queue(netdev, i));
}
/* Since queues were stopped until now, there shouldn't be any * one in ibmvnic_complete_tx() or ibmvnic_xmit() so maybe we * don't need the synchronize_rcu()? Leaving it for consistency * with setting ->tx_queues_active = false.
*/
synchronize_rcu();
netif_tx_start_all_queues(netdev);
if (prev_state == VNIC_CLOSED) { for (i = 0; i < adapter->req_rx_queues; i++)
napi_schedule(&adapter->napi[i]);
}
/* If device failover is pending or we are about to reset, just set * device state and return. Device operation will be handled by reset * routine. * * It should be safe to overwrite the adapter->state here. Since * we hold the rtnl, either the reset has not actually started or * the rtnl got dropped during the set_link_state() in do_reset(). * In the former case, no one else is changing the state (again we * have the rtnl) and in the latter case, do_reset() will detect and * honor our setting below.
*/ if (adapter->failover_pending || (test_bit(0, &adapter->resetting))) {
netdev_dbg(netdev, "[S:%s FOP:%d] Resetting, deferring open\n",
adapter_state_to_string(adapter->state),
adapter->failover_pending);
adapter->state = VNIC_OPEN;
rc = 0; goto out;
}
if (adapter->state != VNIC_CLOSED) {
rc = ibmvnic_login(netdev); if (rc) goto out;
rc = init_resources(adapter); if (rc) {
netdev_err(netdev, "failed to initialize resources\n"); goto out;
}
}
rc = __ibmvnic_open(netdev);
out: /* If open failed and there is a pending failover or in-progress reset, * set device state and return. Device operation will be handled by * reset routine. See also comments above regarding rtnl.
*/ if (rc &&
(adapter->failover_pending || (test_bit(0, &adapter->resetting)))) {
adapter->state = VNIC_OPEN;
rc = 0;
}
if (rc) {
release_resources(adapter);
release_rx_pools(adapter);
release_tx_pools(adapter);
}
return rc;
}
staticvoid clean_rx_pools(struct ibmvnic_adapter *adapter)
{ struct ibmvnic_rx_pool *rx_pool; struct ibmvnic_rx_buff *rx_buff;
u64 rx_entries; int rx_scrqs; int i, j;
/* Free any remaining skbs in the rx buffer pools */ for (i = 0; i < rx_scrqs; i++) {
rx_pool = &adapter->rx_pool[i]; if (!rx_pool || !rx_pool->rx_buff) continue;
for (i = 0; i < tx_entries; i++) {
tx_buff = &tx_pool->tx_buff[i]; if (tx_buff && tx_buff->skb) {
dev_kfree_skb_any(tx_buff->skb);
tx_buff->skb = NULL;
}
}
}
staticvoid clean_tx_pools(struct ibmvnic_adapter *adapter)
{ int tx_scrqs; int i;
if (!adapter->tx_pool || !adapter->tso_pool) return;
tx_scrqs = adapter->num_active_tx_pools;
/* Free any remaining skbs in the tx buffer pools */ for (i = 0; i < tx_scrqs; i++) {
netdev_dbg(adapter->netdev, "Cleaning tx_pool[%d]\n", i);
clean_one_tx_pool(adapter, &adapter->tx_pool[i]);
clean_one_tx_pool(adapter, &adapter->tso_pool[i]);
}
}
if (adapter->tx_scrq) { for (i = 0; i < adapter->req_tx_queues; i++) if (adapter->tx_scrq[i]->irq) {
netdev_dbg(netdev, "Disabling tx_scrq[%d] irq\n", i);
disable_scrq_irq(adapter, adapter->tx_scrq[i]);
disable_irq(adapter->tx_scrq[i]->irq);
}
}
if (adapter->rx_scrq) { for (i = 0; i < adapter->req_rx_queues; i++) { if (adapter->rx_scrq[i]->irq) {
netdev_dbg(netdev, "Disabling rx_scrq[%d] irq\n", i);
disable_scrq_irq(adapter, adapter->rx_scrq[i]);
disable_irq(adapter->rx_scrq[i]->irq);
}
}
}
}
/* If device failover is pending, just set device state and return. * Device operation will be handled by reset routine.
*/ if (adapter->failover_pending) {
adapter->state = VNIC_CLOSED; return 0;
}
/** * get_hdr_lens - fills list of L2/L3/L4 hdr lens * @hdr_field: bitfield determining needed headers * @skb: socket buffer * @hdr_len: array of header lengths to be filled * * Reads hdr_field to determine which headers are needed by firmware. * Builds a buffer containing these headers. Saves individual header * lengths and total buffer length to be used to build descriptors. * * Return: total len of all headers
*/ staticint get_hdr_lens(u8 hdr_field, struct sk_buff *skb, int *hdr_len)
{ int len = 0;
if ((hdr_field >> 6) & 1) {
hdr_len[0] = skb_mac_header_len(skb);
len += hdr_len[0];
}
if ((hdr_field >> 5) & 1) {
hdr_len[1] = skb_network_header_len(skb);
len += hdr_len[1];
}
/** * create_hdr_descs - create header and header extension descriptors * @hdr_field: bitfield determining needed headers * @hdr_data: buffer containing header data * @len: length of data buffer * @hdr_len: array of individual header lengths * @scrq_arr: descriptor array * * Creates header and, if needed, header extension descriptors and * places them in a descriptor array, scrq_arr * * Return: Number of header descs
*/
staticint create_hdr_descs(u8 hdr_field, u8 *hdr_data, int len, int *hdr_len, union sub_crq *scrq_arr)
{ union sub_crq *hdr_desc; int tmp_len = len; int num_descs = 0;
u8 *data, *cur; int tmp;
while (tmp_len > 0) {
cur = hdr_data + len - tmp_len;
/** * build_hdr_descs_arr - build a header descriptor array * @skb: tx socket buffer * @indir_arr: indirect array * @num_entries: number of descriptors to be sent * @hdr_field: bit field determining which headers will be sent * * This function will build a TX descriptor array with applicable * L2/L3/L4 packet header descriptors to be sent by send_subcrq_indirect.
*/
staticvoid build_hdr_descs_arr(struct sk_buff *skb, union sub_crq *indir_arr, int *num_entries, u8 hdr_field)
{ int hdr_len[3] = {0, 0, 0}; int tot_len;
staticint ibmvnic_xmit_workarounds(struct sk_buff *skb, struct net_device *netdev)
{ /* For some backing devices, mishandling of small packets * can result in a loss of connection or TX stall. Device * architects recommend that no packet should be smaller * than the minimum MTU value provided to the driver, so * pad any packets to that length
*/ if (skb->len < netdev->min_mtu) return skb_put_padto(skb, netdev->min_mtu);
return 0;
}
staticvoid ibmvnic_tx_scrq_clean_buffer(struct ibmvnic_adapter *adapter, struct ibmvnic_sub_crq_queue *tx_scrq)
{ struct ibmvnic_ind_xmit_queue *ind_bufp; struct ibmvnic_tx_buff *tx_buff; struct ibmvnic_tx_pool *tx_pool; union sub_crq tx_scrq_entry; int queue_num; int entries; int index; int i;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.