blob: 3cca51735421a7435f4c7f32fa3f5af9003f2d37 [file] [log] [blame]
// 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. */
/* */
/**************************************************************************/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/completion.h>
#include <linux/ioport.h>
#include <linux/dma-mapping.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/ethtool.h>
#include <linux/proc_fs.h>
#include <linux/if_arp.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/irq.h>
#include <linux/kthread.h>
#include <linux/seq_file.h>
#include <linux/interrupt.h>
#include <net/net_namespace.h>
#include <asm/hvcall.h>
#include <linux/atomic.h>
#include <asm/vio.h>
#include <asm/iommu.h>
#include <linux/uaccess.h>
#include <asm/firmware.h>
#include <linux/workqueue.h>
#include <linux/if_vlan.h>
#include <linux/utsname.h>
#include "ibmvnic.h"
static const char ibmvnic_driver_name[] = "ibmvnic";
static const char 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);
static int ibmvnic_version = IBMVNIC_INITIAL_VERSION;
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 *);
static int ibmvnic_send_crq(struct ibmvnic_adapter *, union ibmvnic_crq *);
static int send_subcrq_indirect(struct ibmvnic_adapter *, u64, u64, u64);
static irqreturn_t ibmvnic_interrupt_rx(int irq, void *instance);
static int enable_scrq_irq(struct ibmvnic_adapter *,
struct ibmvnic_sub_crq_queue *);
static int disable_scrq_irq(struct ibmvnic_adapter *,
struct ibmvnic_sub_crq_queue *);
static int pending_scrq(struct ibmvnic_adapter *,
struct ibmvnic_sub_crq_queue *);
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_query_map(struct ibmvnic_adapter *adapter);
static int send_request_map(struct ibmvnic_adapter *, dma_addr_t, u32, u8);
static int send_request_unmap(struct ibmvnic_adapter *, u8);
static int send_login(struct ibmvnic_adapter *adapter);
static void send_query_cap(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_reset_init(struct ibmvnic_adapter *, bool reset);
static void release_crq_queue(struct ibmvnic_adapter *);
static int __ibmvnic_set_mac(struct net_device *, u8 *);
static int init_crq_queue(struct ibmvnic_adapter *adapter);
static int send_query_phys_parms(struct ibmvnic_adapter *adapter);
static void ibmvnic_tx_scrq_clean_buffer(struct ibmvnic_adapter *adapter,
struct ibmvnic_sub_crq_queue *tx_scrq);
static void free_long_term_buff(struct ibmvnic_adapter *adapter,
struct ibmvnic_long_term_buff *ltb);
struct ibmvnic_stat {
char name[ETH_GSTRING_LEN];
int offset;
};
#define IBMVNIC_STAT_OFF(stat) (offsetof(struct ibmvnic_adapter, stats) + \
offsetof(struct ibmvnic_statistics, stat))
#define IBMVNIC_GET_STAT(a, off) (*((u64 *)(((unsigned long)(a)) + (off))))
static const struct ibmvnic_stat ibmvnic_stats[] = {
{"rx_packets", IBMVNIC_STAT_OFF(rx_packets)},
{"rx_bytes", IBMVNIC_STAT_OFF(rx_bytes)},
{"tx_packets", IBMVNIC_STAT_OFF(tx_packets)},
{"tx_bytes", IBMVNIC_STAT_OFF(tx_bytes)},
{"ucast_tx_packets", IBMVNIC_STAT_OFF(ucast_tx_packets)},
{"ucast_rx_packets", IBMVNIC_STAT_OFF(ucast_rx_packets)},
{"mcast_tx_packets", IBMVNIC_STAT_OFF(mcast_tx_packets)},
{"mcast_rx_packets", IBMVNIC_STAT_OFF(mcast_rx_packets)},
{"bcast_tx_packets", IBMVNIC_STAT_OFF(bcast_tx_packets)},
{"bcast_rx_packets", IBMVNIC_STAT_OFF(bcast_rx_packets)},
{"align_errors", IBMVNIC_STAT_OFF(align_errors)},
{"fcs_errors", IBMVNIC_STAT_OFF(fcs_errors)},
{"single_collision_frames", IBMVNIC_STAT_OFF(single_collision_frames)},
{"multi_collision_frames", IBMVNIC_STAT_OFF(multi_collision_frames)},
{"sqe_test_errors", IBMVNIC_STAT_OFF(sqe_test_errors)},
{"deferred_tx", IBMVNIC_STAT_OFF(deferred_tx)},
{"late_collisions", IBMVNIC_STAT_OFF(late_collisions)},
{"excess_collisions", IBMVNIC_STAT_OFF(excess_collisions)},
{"internal_mac_tx_errors", IBMVNIC_STAT_OFF(internal_mac_tx_errors)},
{"carrier_sense", IBMVNIC_STAT_OFF(carrier_sense)},
{"too_long_frames", IBMVNIC_STAT_OFF(too_long_frames)},
{"internal_mac_rx_errors", IBMVNIC_STAT_OFF(internal_mac_rx_errors)},
};
static int send_crq_init_complete(struct ibmvnic_adapter *adapter)
{
union ibmvnic_crq crq;
memset(&crq, 0, sizeof(crq));
crq.generic.first = IBMVNIC_CRQ_INIT_CMD;
crq.generic.cmd = IBMVNIC_CRQ_INIT_COMPLETE;
return ibmvnic_send_crq(adapter, &crq);
}
static int send_version_xchg(struct ibmvnic_adapter *adapter)
{
union ibmvnic_crq crq;
memset(&crq, 0, sizeof(crq));
crq.version_exchange.first = IBMVNIC_CRQ_CMD;
crq.version_exchange.cmd = VERSION_EXCHANGE;
crq.version_exchange.version = cpu_to_be16(ibmvnic_version);
return ibmvnic_send_crq(adapter, &crq);
}
static long h_reg_sub_crq(unsigned long unit_address, unsigned long token,
unsigned long length, unsigned long *number,
unsigned long *irq)
{
unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
long rc;
rc = plpar_hcall(H_REG_SUB_CRQ, retbuf, unit_address, token, length);
*number = retbuf[0];
*irq = retbuf[1];
return rc;
}
/**
* 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.
*/
static int ibmvnic_wait_for_completion(struct ibmvnic_adapter *adapter,
struct completion *comp_done,
unsigned long timeout)
{
struct net_device *netdev;
unsigned long 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.
*/
static bool 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.
*/
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;
if (!reuse_ltb(ltb, size)) {
dev_dbg(dev,
"LTB size changed from 0x%llx to 0x%x, reallocating\n",
ltb->size, 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, &ltb->addr,
GFP_KERNEL);
if (!ltb->buff) {
dev_err(dev, "Couldn't alloc long term buffer\n");
return -ENOMEM;
}
ltb->size = size;
ltb->map_id = find_first_zero_bit(adapter->map_ids,
MAX_MAP_ID);
bitmap_set(adapter->map_ids, ltb->map_id, 1);
dev_dbg(dev,
"Allocated new LTB [map %d, size 0x%llx]\n",
ltb->map_id, ltb->size);
}
/* Ensure ltb is zeroed - specially when reusing it. */
memset(ltb->buff, 0, ltb->size);
mutex_lock(&adapter->fw_lock);
adapter->fw_done_rc = 0;
reinit_completion(&adapter->fw_done);
rc = send_request_map(adapter, ltb->addr, ltb->size, ltb->map_id);
if (rc) {
dev_err(dev, "send_request_map failed, rc = %d\n", rc);
goto out;
}
rc = ibmvnic_wait_for_completion(adapter, &adapter->fw_done, 10000);
if (rc) {
dev_err(dev, "LTB map request aborted or timed out, rc = %d\n",
rc);
goto out;
}
if (adapter->fw_done_rc) {
dev_err(dev, "Couldn't map LTB, rc = %d\n",
adapter->fw_done_rc);
rc = -1;
goto out;
}
rc = 0;
out:
/* don't free LTB on communication error - see function header */
mutex_unlock(&adapter->fw_lock);
return rc;
}
static void free_long_term_buff(struct ibmvnic_adapter *adapter,
struct ibmvnic_long_term_buff *ltb)
{
struct device *dev = &adapter->vdev->dev;
if (!ltb->buff)
return;
/* 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);
dma_free_coherent(dev, ltb->size, ltb->buff, ltb->addr);
ltb->buff = NULL;
/* mark this map_id free */
bitmap_clear(adapter->map_ids, ltb->map_id, 1);
ltb->map_id = 0;
}
static void deactivate_rx_pools(struct ibmvnic_adapter *adapter)
{
int i;
for (i = 0; i < adapter->num_active_rx_pools; i++)
adapter->rx_pool[i].active = 0;
}
static void replenish_rx_pool(struct ibmvnic_adapter *adapter,
struct ibmvnic_rx_pool *pool)
{
int count = pool->size - atomic_read(&pool->available);
u64 handle = adapter->rx_scrq[pool->index]->handle;
struct device *dev = &adapter->vdev->dev;
struct ibmvnic_ind_xmit_queue *ind_bufp;
struct ibmvnic_sub_crq_queue *rx_scrq;
union sub_crq *sub_crq;
int buffers_added = 0;
unsigned long lpar_rc;
struct sk_buff *skb;
unsigned int offset;
dma_addr_t dma_addr;
unsigned char *dst;
int shift = 0;
int index;
int i;
if (!pool->active)
return;
rx_scrq = adapter->rx_scrq[pool->index];
ind_bufp = &rx_scrq->ind_buf;
/* 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) {
index = 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[index].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;
}
}
pool->free_map[pool->next_free] = IBMVNIC_INVALID_MAP;
pool->next_free = (pool->next_free + 1) % pool->size;
/* Copy the skb to the long term mapped DMA buffer */
offset = index * pool->buff_size;
dst = pool->long_term_buff.buff + offset;
memset(dst, 0, pool->buff_size);
dma_addr = pool->long_term_buff.addr + offset;
/* add the skb to an rx_buff in the pool */
pool->rx_buff[index].data = dst;
pool->rx_buff[index].dma = dma_addr;
pool->rx_buff[index].skb = skb;
pool->rx_buff[index].pool_index = pool->index;
pool->rx_buff[index].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[index]);
sub_crq->rx_add.ioba = cpu_to_be32(dma_addr);
sub_crq->rx_add.map_id = pool->long_term_buff.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);
index = (int)(rx_buff - pool->rx_buff);
pool->free_map[pool->next_free] = index;
dev_kfree_skb_any(pool->rx_buff[index].skb);
pool->rx_buff[index].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);
}
}
static void 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]);
}
netdev_dbg(adapter->netdev, "Replenished %d pools\n", i);
}
static void release_stats_buffers(struct ibmvnic_adapter *adapter)
{
kfree(adapter->tx_stats_buffers);
kfree(adapter->rx_stats_buffers);
adapter->tx_stats_buffers = NULL;
adapter->rx_stats_buffers = NULL;
}
static int init_stats_buffers(struct ibmvnic_adapter *adapter)
{
adapter->tx_stats_buffers =
kcalloc(IBMVNIC_MAX_QUEUES,
sizeof(struct ibmvnic_tx_queue_stats),
GFP_KERNEL);
if (!adapter->tx_stats_buffers)
return -ENOMEM;
adapter->rx_stats_buffers =
kcalloc(IBMVNIC_MAX_QUEUES,
sizeof(struct ibmvnic_rx_queue_stats),
GFP_KERNEL);
if (!adapter->rx_stats_buffers)
return -ENOMEM;
return 0;
}
static void release_stats_token(struct ibmvnic_adapter *adapter)
{
struct device *dev = &adapter->vdev->dev;
if (!adapter->stats_token)
return;
dma_unmap_single(dev, adapter->stats_token,
sizeof(struct ibmvnic_statistics),
DMA_FROM_DEVICE);
adapter->stats_token = 0;
}
static int init_stats_token(struct ibmvnic_adapter *adapter)
{
struct device *dev = &adapter->vdev->dev;
dma_addr_t stok;
stok = dma_map_single(dev, &adapter->stats,
sizeof(struct ibmvnic_statistics),
DMA_FROM_DEVICE);
if (dma_mapping_error(dev, stok)) {
dev_err(dev, "Couldn't map stats buffer\n");
return -1;
}
adapter->stats_token = stok;
netdev_dbg(adapter->netdev, "Stats token initialized (%llx)\n", stok);
return 0;
}
/**
* 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.
*/
static void 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];
netdev_dbg(adapter->netdev, "Releasing rx_pool[%d]\n", i);
kfree(rx_pool->free_map);
free_long_term_buff(adapter, &rx_pool->long_term_buff);
if (!rx_pool->rx_buff)
continue;
for (j = 0; j < rx_pool->size; j++) {
if (rx_pool->rx_buff[j].skb) {
dev_kfree_skb_any(rx_pool->rx_buff[j].skb);
rx_pool->rx_buff[j].skb = NULL;
}
}
kfree(rx_pool->rx_buff);
}
kfree(adapter->rx_pool);
adapter->rx_pool = NULL;
adapter->num_active_rx_pools = 0;
adapter->prev_rx_pool_size = 0;
}
/**
* 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.
*/
static bool 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;
if (!adapter->rx_pool)
return false;
old_num_pools = adapter->num_active_rx_pools;
new_num_pools = adapter->req_rx_queues;
old_pool_size = adapter->prev_rx_pool_size;
new_pool_size = adapter->req_rx_add_entries_per_subcrq;
old_buff_size = adapter->prev_rx_buf_sz;
new_buff_size = adapter->cur_rx_buf_sz;
/* Require buff size to be exactly same for now */
if (old_buff_size != new_buff_size)
return false;
if (old_num_pools == new_num_pools && old_pool_size == new_pool_size)
return true;
if (old_num_pools < adapter->min_rx_queues ||
old_num_pools > adapter->max_rx_queues ||
old_pool_size < adapter->min_rx_add_entries_per_subcrq ||
old_pool_size > adapter->max_rx_add_entries_per_subcrq)
return false;
return true;
}
/**
* 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.
*/
static int 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;
pool_size = adapter->req_rx_add_entries_per_subcrq;
num_pools = adapter->req_rx_queues;
buff_size = adapter->cur_rx_buf_sz;
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 -1;
}
/* 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];
netdev_dbg(adapter->netdev,
"Initializing rx_pool[%d], %lld buffs, %lld bytes each\n",
i, pool_size, buff_size);
rx_pool->size = pool_size;
rx_pool->index = i;
rx_pool->buff_size = ALIGN(buff_size, L1_CACHE_BYTES);
rx_pool->free_map = kcalloc(rx_pool->size, sizeof(int),
GFP_KERNEL);
if (!rx_pool->free_map) {
dev_err(dev, "Couldn't alloc free_map %d\n", i);
goto out_release;
}
rx_pool->rx_buff = kcalloc(rx_pool->size,
sizeof(struct ibmvnic_rx_buff),
GFP_KERNEL);
if (!rx_pool->rx_buff) {
dev_err(dev, "Couldn't alloc rx buffers\n");
goto out_release;
}
}
adapter->prev_rx_pool_size = pool_size;
adapter->prev_rx_buf_sz = adapter->cur_rx_buf_sz;
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);
if (alloc_long_term_buff(adapter, &rx_pool->long_term_buff,
rx_pool->size * rx_pool->buff_size))
goto out;
for (j = 0; j < rx_pool->size; ++j) {
struct ibmvnic_rx_buff *rx_buff;
rx_pool->free_map[j] = j;
/* 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 -1;
}
static void release_vpd_data(struct ibmvnic_adapter *adapter)
{
if (!adapter->vpd)
return;
kfree(adapter->vpd->buff);
kfree(adapter->vpd);
adapter->vpd = NULL;
}
static void release_one_tx_pool(struct ibmvnic_adapter *adapter,
struct ibmvnic_tx_pool *tx_pool)
{
kfree(tx_pool->tx_buff);
kfree(tx_pool->free_map);
free_long_term_buff(adapter, &tx_pool->long_term_buff);
}
/**
* 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.
*/
static void 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]);
}
kfree(adapter->tx_pool);
adapter->tx_pool = NULL;
kfree(adapter->tso_pool);
adapter->tso_pool = NULL;
adapter->num_active_tx_pools = 0;
adapter->prev_tx_pool_size = 0;
}
static int init_one_tx_pool(struct net_device *netdev,
struct ibmvnic_tx_pool *tx_pool,
int pool_size, int buf_size)
{
int i;
tx_pool->tx_buff = kcalloc(pool_size,
sizeof(struct ibmvnic_tx_buff),
GFP_KERNEL);
if (!tx_pool->tx_buff)
return -1;
tx_pool->free_map = kcalloc(pool_size, sizeof(int), GFP_KERNEL);
if (!tx_pool->free_map) {
kfree(tx_pool->tx_buff);
tx_pool->tx_buff = NULL;
return -1;
}
for (i = 0; i < pool_size; i++)
tx_pool->free_map[i] = i;
tx_pool->consumer_index = 0;
tx_pool->producer_index = 0;
tx_pool->num_buffers = pool_size;
tx_pool->buf_size = buf_size;
return 0;
}
/**
* 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.
*/
static bool 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;
if (!adapter->tx_pool)
return false;
old_num_pools = adapter->num_active_tx_pools;
new_num_pools = adapter->num_active_tx_scrqs;
old_pool_size = adapter->prev_tx_pool_size;
new_pool_size = adapter->req_tx_entries_per_subcrq;
old_mtu = adapter->prev_mtu;
new_mtu = adapter->req_mtu;
/* Require MTU to be exactly same to reuse pools for now */
if (old_mtu != new_mtu)
return false;
if (old_num_pools == new_num_pools && old_pool_size == new_pool_size)
return true;
if (old_num_pools < adapter->min_tx_queues ||
old_num_pools > adapter->max_tx_queues ||
old_pool_size < adapter->min_tx_entries_per_subcrq ||
old_pool_size > adapter->max_tx_entries_per_subcrq)
return false;
return true;
}
/**
* 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.
*/
static int 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);
pool_size = adapter->req_tx_entries_per_subcrq;
num_pools = adapter->num_active_tx_scrqs;
adapter->tx_pool = kcalloc(num_pools,
sizeof(struct ibmvnic_tx_pool), GFP_KERNEL);
if (!adapter->tx_pool)
return -1;
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 -1;
}
/* 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;
buff_size = adapter->req_mtu + VLAN_HLEN;
buff_size = ALIGN(buff_size, L1_CACHE_BYTES);
for (i = 0; i < num_pools; i++) {
dev_dbg(dev, "Init tx pool %d [%llu, %llu]\n",
i, adapter->req_tx_entries_per_subcrq, buff_size);
rc = init_one_tx_pool(netdev, &adapter->tx_pool[i],
pool_size, buff_size);
if (rc)
goto out_release;
rc = init_one_tx_pool(netdev, &adapter->tso_pool[i],
IBMVNIC_TSO_BUFS,
IBMVNIC_TSO_BUF_SZ);
if (rc)
goto out_release;
}
adapter->prev_tx_pool_size = pool_size;
adapter->prev_mtu = adapter->req_mtu;
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;
u32 ltb_size;
tx_pool = &adapter->tx_pool[i];
ltb_size = tx_pool->num_buffers * tx_pool->buf_size;
if (alloc_long_term_buff(adapter, &tx_pool->long_term_buff,
ltb_size))
goto out;
dev_dbg(dev, "Updated LTB for tx pool %d [%p, %d, %d]\n",
i, tx_pool->long_term_buff.buff,
tx_pool->num_buffers, tx_pool->buf_size);
tx_pool->consumer_index = 0;
tx_pool->producer_index = 0;
for (j = 0; j < tx_pool->num_buffers; j++)
tx_pool->free_map[j] = j;
tso_pool = &adapter->tso_pool[i];
ltb_size = tso_pool->num_buffers * tso_pool->buf_size;
if (alloc_long_term_buff(adapter, &tso_pool->long_term_buff,
ltb_size))
goto out;
dev_dbg(dev, "Updated LTB for tso pool %d [%p, %d, %d]\n",
i, tso_pool->long_term_buff.buff,
tso_pool->num_buffers, tso_pool->buf_size);
tso_pool->consumer_index = 0;
tso_pool->producer_index = 0;
for (j = 0; j < tso_pool->num_buffers; j++)
tso_pool->free_map[j] = j;
}
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;
}
static void 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;
}
static void 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;
}
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);
}
adapter->num_active_rx_napi = adapter->req_rx_queues;
return 0;
}
static void release_napi(struct ibmvnic_adapter *adapter)
{
int i;
if (!adapter->napi)
return;
for (i = 0; i < adapter->num_active_rx_napi; i++) {
netdev_dbg(adapter->netdev, "Releasing napi[%d]\n", i);
netif_napi_del(&adapter->napi[i]);
}
kfree(adapter->napi);
adapter->napi = NULL;
adapter->num_active_rx_napi = 0;
adapter->napi_enabled = false;
}
static const char *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";
}
static int ibmvnic_login(struct net_device *netdev)
{
struct ibmvnic_adapter *adapter = netdev_priv(netdev);
unsigned long timeout = msecs_to_jiffies(20000);
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 -1;
}
adapter->init_done_rc = 0;
reinit_completion(&adapter->init_done);
rc = send_login(adapter);
if (rc)
return rc;
if (!wait_for_completion_timeout(&adapter->init_done,
timeout)) {
netdev_warn(netdev, "Login timed out, retrying...\n");
retry = true;
adapter->init_done_rc = 0;
retry_count++;
continue;
}
if (adapter->init_done_rc == ABORTED) {
netdev_warn(netdev, "Login aborted, retrying...\n");
retry = true;
adapter->init_done_rc = 0;
retry_count++;
/* FW or device may be busy, so
* wait a bit before retrying login
*/
msleep(500);
} else if (adapter->init_done_rc == PARTIALSUCCESS) {
retry_count++;
release_sub_crqs(adapter, 1);
retry = true;
netdev_dbg(netdev,
"Received partial success, retrying...\n");
adapter->init_done_rc = 0;
reinit_completion(&adapter->init_done);
send_query_cap(adapter);
if (!wait_for_completion_timeout(&adapter->init_done,
timeout)) {
netdev_warn(netdev,
"Capabilities query timed out\n");
return -1;
}
rc = init_sub_crqs(adapter);
if (rc) {
netdev_warn(netdev,
"SCRQ initialization failed\n");
return -1;
}
rc = init_sub_crq_irqs(adapter);
if (rc) {
netdev_warn(netdev,
"SCRQ irq initialization failed\n");
return -1;
}
} else if (adapter->init_done_rc) {
netdev_warn(netdev, "Adapter login failed\n");
return -1;
}
} while (retry);
__ibmvnic_set_mac(netdev, adapter->mac_addr);
netdev_dbg(netdev, "[S:%s] Login succeeded\n", adapter_state_to_string(adapter->state));
return 0;
}
static void release_login_buffer(struct ibmvnic_adapter *adapter)
{
kfree(adapter->login_buf);
adapter->login_buf = NULL;
}
static void release_login_rsp_buffer(struct ibmvnic_adapter *adapter)
{
kfree(adapter->login_rsp_buf);
adapter->login_rsp_buf = NULL;
}
static void release_resources(struct ibmvnic_adapter *adapter)
{
release_vpd_data(adapter);
release_napi(adapter);
release_login_buffer(adapter);
release_login_rsp_buffer(adapter);
}
static int set_link_state(struct ibmvnic_adapter *adapter, u8 link_state)
{
struct net_device *netdev = adapter->netdev;
unsigned long timeout = msecs_to_jiffies(20000);
union ibmvnic_crq crq;
bool resend;
int rc;
netdev_dbg(netdev, "setting link state %d\n", link_state);
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 = link_state;
do {
resend = false;
reinit_completion(&adapter->init_done);
rc = ibmvnic_send_crq(adapter, &crq);
if (rc) {
netdev_err(netdev, "Failed to set link state\n");
return rc;
}
if (!wait_for_completion_timeout(&adapter->init_done,
timeout)) {
netdev_err(netdev, "timeout setting link state\n");
return -1;
}
if (adapter->init_done_rc == PARTIALSUCCESS) {
/* 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);
return 0;
}
static int set_real_num_queues(struct net_device *netdev)
{
struct ibmvnic_adapter *adapter = netdev_priv(netdev);
int rc;
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;
}
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;
mutex_lock(&adapter->fw_lock);
adapter->fw_done_rc = 0;
reinit_completion(&adapter->fw_done);
crq.get_vpd_size.first = IBMVNIC_CRQ_CMD;
crq.get_vpd_size.cmd = GET_VPD_SIZE;
rc = ibmvnic_send_crq(adapter, &crq);
if (rc) {
mutex_unlock(&adapter->fw_lock);
return rc;
}
rc = ibmvnic_wait_for_completion(adapter, &adapter->fw_done, 10000);
if (rc) {
dev_err(dev, "Could not retrieve VPD size, rc = %d\n", rc);
mutex_unlock(&adapter->fw_lock);
return rc;
}
mutex_unlock(&adapter->fw_lock);
if (!adapter->vpd->len)
return -ENODATA;
if (!adapter->vpd->buff)
adapter->vpd->buff = kzalloc(adapter->vpd->len, GFP_KERNEL);
else if (adapter->vpd->len != len)
adapter->vpd->buff =
krealloc(adapter->vpd->buff,
adapter->vpd->len, GFP_KERNEL);
if (!adapter->vpd->buff) {
dev_err(dev, "Could allocate VPD buffer\n");
return -ENOMEM;
}
adapter->vpd->dma_addr =
dma_map_single(dev, adapter->vpd->buff, adapter->vpd->len,
DMA_FROM_DEVICE);
if (dma_mapping_error(dev, adapter->vpd->dma_addr)) {
dev_err(dev, "Could not map VPD buffer\n");
kfree(adapter->vpd->buff);
adapter->vpd->buff = NULL;
return -ENOMEM;
}
mutex_lock(&adapter->fw_lock);
adapter->fw_done_rc = 0;
reinit_completion(&adapter->fw_done);
crq.get_vpd.first = IBMVNIC_CRQ_CMD;
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);
rc = ibmvnic_send_crq(adapter, &crq);
if (rc) {
kfree(adapter->vpd->buff);
adapter->vpd->buff = NULL;
mutex_unlock(&adapter->fw_lock);
return rc;
}
rc = ibmvnic_wait_for_completion(adapter, &adapter->fw_done, 10000);
if (rc) {
dev_err(dev, "Unable to retrieve VPD, rc = %d\n", rc);
kfree(adapter->vpd->buff);
adapter->vpd->buff = NULL;
mutex_unlock(&adapter->fw_lock);
return rc;
}
mutex_unlock(&adapter->fw_lock);
return 0;
}
static int init_resources(struct ibmvnic_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
int rc;
rc = set_real_num_queues(netdev);
if (rc)
return rc;
adapter->vpd = kzalloc(sizeof(*adapter->vpd), GFP_KERNEL);
if (!adapter->vpd)
return -ENOMEM;
/* Vital Product Data (VPD) */
rc = ibmvnic_get_vpd(adapter);
if (rc) {
netdev_err(netdev, "failed to initialize Vital Product Data (VPD)\n");
return rc;
}
rc = init_napi(adapter);
if (rc)
return rc;
send_query_map(adapter);
rc = init_rx_pools(netdev);
if (rc)
return rc;
rc = init_tx_pools(netdev);
return rc;
}
static int __ibmvnic_open(struct net_device *netdev)
{
struct ibmvnic_adapter *adapter = netdev_priv(netdev);
enum vnic_state prev_state = adapter->state;
int i, rc;
adapter->state = VNIC_OPENING;
replenish_pools(adapter);
ibmvnic_napi_enable(adapter);
/* 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(netdev_get_tx_queue(netdev, i));
}
rc = set_link_state(adapter, IBMVNIC_LOGICAL_LNK_UP);
if (rc) {
ibmvnic_napi_disable(adapter);
release_resources(adapter);
return rc;
}
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]);
}
adapter->state = VNIC_OPEN;
return rc;
}
static int ibmvnic_open(struct net_device *netdev)
{
struct ibmvnic_adapter *adapter = netdev_priv(netdev);
int rc;
ASSERT_RTNL();
/* 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");
release_resources(adapter);
release_rx_pools(adapter);
release_tx_pools(adapter);
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;
}
return rc;
}
static void 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;
if (!adapter->rx_pool)
return;
rx_scrqs = adapter->num_active_rx_pools;
rx_entries = adapter->req_rx_add_entries_per_subcrq;
/* 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;
netdev_dbg(adapter->netdev, "Cleaning rx_pool[%d]\n", i);
for (j = 0; j < rx_entries; j++) {
rx_buff = &rx_pool->rx_buff[j];
if (rx_buff && rx_buff->skb) {
dev_kfree_skb_any(rx_buff->skb);
rx_buff->skb = NULL;
}
}
}
}
static void clean_one_tx_pool(struct ibmvnic_adapter *adapter,
struct ibmvnic_tx_pool *tx_pool)
{
struct ibmvnic_tx_buff *tx_buff;
u64 tx_entries;
int i;
if (!tx_pool || !tx_pool->tx_buff)
return;
tx_entries = tx_pool->num_buffers;
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;
}
}
}
static void 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]);
}
}
static void ibmvnic_disable_irqs(struct ibmvnic_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
int 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);
}
}
}
}
static void ibmvnic_cleanup(struct net_device *netdev)
{
struct ibmvnic_adapter *adapter = netdev_priv(netdev);
/* ensure that transmissions are stopped if called by do_reset */
if (test_bit(0, &adapter->resetting))
netif_tx_disable(netdev);
else
netif_tx_stop_all_queues(netdev);
ibmvnic_napi_disable(adapter);
ibmvnic_disable_irqs(adapter);
}
static int __ibmvnic_close(struct net_device *netdev)
{
struct ibmvnic_adapter *adapter = netdev_priv(netdev);
int rc = 0;
adapter->state = VNIC_CLOSING;
rc = set_link_state(adapter, IBMVNIC_LOGICAL_LNK_DN);
adapter->state = VNIC_CLOSED;
return rc;
}
static int ibmvnic_close(struct net_device *netdev)
{
struct ibmvnic_adapter *adapter = netdev_priv(netdev);
int rc;
netdev_dbg(netdev, "[S:%s FOP:%d FRR:%d] Closing\n",
adapter_state_to_string(adapter->state),
adapter->failover_pending,
adapter->force_reset_recovery);
/* 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;
}
rc = __ibmvnic_close(netdev);
ibmvnic_cleanup(netdev);
clean_rx_pools(adapter);
clean_tx_pools(adapter);
return rc;
}
/**
* build_hdr_data - creates L2/L3/L4 header data buffer
* @hdr_field: bitfield determining needed headers
* @skb: socket buffer
* @hdr_len: array of header lengths
* @hdr_data: buffer to write the header to
*
* 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.
*/
static int build_hdr_data(u8 hdr_field, struct sk_buff *skb,
int *hdr_len, u8 *hdr_data)
{
int len = 0;
u8 *hdr;
if (skb_vlan_tagged(skb) && !skb_vlan_tag_present(skb))
hdr_len[0] = sizeof(struct vlan_ethhdr);
else
hdr_len[0] = sizeof(struct ethhdr);
if (skb->protocol == htons(ETH_P_IP)) {
hdr_len[1] = ip_hdr(skb)->ihl * 4;
if (ip_hdr(skb)->protocol == IPPROTO_TCP)
hdr_len[2] = tcp_hdrlen(skb);
else if (ip_hdr(skb)->protocol == IPPROTO_UDP)
hdr_len[2] = sizeof(struct udphdr);
} else if (skb->protocol == htons(ETH_P_IPV6)) {
hdr_len[1] = sizeof(struct ipv6hdr);
if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP)
hdr_len[2] = tcp_hdrlen(skb);
else if (ipv6_hdr(skb)->nexthdr == IPPROTO_UDP)
hdr_len[2] = sizeof(struct udphdr);
} else if (skb->protocol == htons(ETH_P_ARP)) {
hdr_len[1] = arp_hdr_len(skb->dev);
hdr_len[2] = 0;
}
memset(hdr_data, 0, 120);
if ((hdr_field >> 6) & 1) {
hdr = skb_mac_header(skb);
memcpy(hdr_data, hdr, hdr_len[0]);
len += hdr_len[0];
}
if ((hdr_field >> 5) & 1) {
hdr = skb_network_header(skb);
memcpy(hdr_data + len, hdr, hdr_len[1]);
len += hdr_len[1];
}
if ((hdr_field >> 4) & 1) {
hdr = skb_transport_header(skb);
memcpy(hdr_data + len, hdr, hdr_len[2]);
len += hdr_len[2];
}
return len;
}
/**
* 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
*/
static int 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;
memset(&hdr_desc, 0, sizeof(hdr_desc));
if (cur != hdr_data) {
data = hdr_desc.hdr_ext.data;
tmp = tmp_len > 29 ? 29 : tmp_len;
hdr_desc.hdr_ext.first = IBMVNIC_CRQ_CMD;
hdr_desc.hdr_ext.type = IBMVNIC_HDR_EXT_DESC;
hdr_desc.hdr_ext.len = tmp;
} else {
data = hdr_desc.hdr.data;
tmp = tmp_len > 24 ? 24 : tmp_len;
hdr_desc.hdr.first = IBMVNIC_CRQ_CMD;
hdr_desc.hdr.type = IBMVNIC_HDR_DESC;
hdr_desc.hdr.len = tmp;
hdr_desc.hdr.l2_len = (u8)hdr_len[0];
hdr_desc.hdr.l3_len = cpu_to_be16((u16)hdr_len[1]);
hdr_desc.hdr.l4_len = (u8)hdr_len[2];
hdr_desc.hdr.flag = hdr_field << 1;
}
memcpy(data, cur, tmp);
tmp_len -= tmp;
*scrq_arr = hdr_desc;
scrq_arr++;
num_descs++;
}
return num_descs;
}
/**
* 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.
*/
static void 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};
u8 hdr_data[140] = {0};
int tot_len;
tot_len = build_hdr_data(hdr_field, skb, hdr_len,
hdr_data);
*num_entries += create_hdr_descs(hdr_field, hdr_data, tot_len, hdr_len,
indir_arr + 1);
}
static int 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;
}
static void 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;
ind_bufp = &tx_scrq->ind_buf;
entries = (u64)ind_bufp->index;
queue_num = tx_scrq->pool_index;
for (i = entries - 1; i >= 0; --i) {
tx_scrq_entry = ind_bufp->indir_arr[i];
if (tx_scrq_entry.v1.type != IBMVNIC_TX_DESC)
continue;
index = be32_to_cpu(tx_scrq_entry.v1.correlator);
if (index & IBMVNIC_TSO_POOL_MASK) {
tx_pool = &adapter->tso_pool[queue_num];
index &= ~IBMVNIC_TSO_POOL_MASK;
} else {
tx_pool = &adapter->tx_pool[queue_num];
}
tx_pool->free_map[tx_pool->consumer_index] = index;
tx_pool->consumer_index = tx_pool->consumer_index == 0 ?
tx_pool->num_buffers - 1 :
tx_pool->consumer_index - 1;
tx_buff = &tx_pool->tx_buff[index];
adapter->netdev->stats.tx_packets--;
adapter->netdev->stats.tx_bytes -= tx_buff->skb->len;
adapter->tx_stats_buffers[queue_num].packets--;
adapter->tx_stats_buffers[queue_num].bytes -=
tx_buff->skb->len;
dev_kfree_skb_any(tx_buff->skb);
tx_buff->skb = NULL;
adapter->netdev->stats.tx_dropped++;
}
ind_bufp->index = 0;
if (atomic_sub_return(entries, &tx_scrq->used) <=
(adapter->req_tx_entries_per_subcrq / 2) &&
__netif_subqueue_stopped(adapter->netdev, queue_num) &&
!test_bit(0, &adapter->resetting)) {
netif_wake_subqueue(adapter->netdev, queue_num);
netdev_dbg(adapter->netdev, "Started queue %d\n",
queue_num);
}
}
static int ibmvnic_tx_scrq_flush(struct ibmvnic_adapter *adapter,
struct ibmvnic_sub_crq_queue *tx_scrq)
{
struct ibmvnic_ind_xmit_queue *ind_bufp;
u64 dma_addr;
u64 entries;
u64 handle;
int rc;
ind_bufp = &tx_scrq->ind_buf;
dma_addr = (u64)ind_bufp->indir_dma;
entries = (u64)ind_bufp->index;
handle = tx_scrq->handle;
if (!entries)
return 0;
rc = send_subcrq_indirect(adapter, handle, dma_addr, entries);
if (rc)
ibmvnic_tx_scrq_clean_buffer(adapter, tx_scrq);
else
ind_bufp->index = 0;
return 0;
}
static netdev_tx_t ibmvnic_xmit(struct sk_buff *skb, struct net_device *netdev)
{
struct ibmvnic_adapter *adapter = netdev_priv(netdev);
int queue_num = skb_get_queue_mapping(skb);
u8 *hdrs = (u8 *)&adapter->tx_rx_desc_req;
struct device *dev = &adapter->vdev->dev;
struct ibmvnic_ind_xmit_queue *ind_bufp;
struct ibmvnic_tx_buff *tx_buff = NULL;
struct ibmvnic_sub_crq_queue *tx_scrq;
struct ibmvnic_tx_pool *tx_pool;
unsigned int tx_send_failed = 0;
netdev_tx_t ret = NETDEV_TX_OK;
unsigned int tx_map_failed = 0;
union sub_crq indir_arr[16];
unsigned int tx_dropped = 0;
unsigned int tx_packets = 0;
unsigned int tx_bytes = 0;
dma_addr_t data_dma_addr;
struct netdev_queue *txq;
unsigned long lpar_rc;
union sub_crq tx_crq;
unsigned int offset;
int num_entries = 1;
unsigned char *dst;
int index = 0;
u8 proto = 0;
tx_scrq = adapter->tx_scrq[queue_num];
txq = netdev_get_tx_queue(netdev, queue_num);
ind_bufp = &tx_scrq->ind_buf;
if (test_bit(0, &adapter->resetting)) {
dev_kfree_skb_any(skb);
tx_send_failed++;
tx_dropped++;
ret = NETDEV_TX_OK;
goto out;
}
if (ibmvnic_xmit_workarounds(skb, netdev)) {
tx_dropped++;
tx_send_failed++;
ret = NETDEV_TX_OK;
ibmvnic_tx_scrq_flush(adapter, tx_scrq);
goto out;
}
if (skb_is_gso(skb))
tx_pool = &adapter->tso_pool[queue_num];
else
tx_pool = &adapter->tx_pool[queue_num];
index = tx_pool->free_map[tx_pool->consumer_index];
if (index == IBMVNIC_INVALID_MAP) {
dev_kfree_skb_any(skb);
tx_send_failed++;
tx_dropped++;
ibmvnic_tx_scrq_flush(adapter, tx_scrq);
ret = NETDEV_TX_OK;
goto out;
}
tx_pool->free_map[tx_pool->consumer_index] = IBMVNIC_INVALID_MAP;
offset = index * tx_pool->buf_size;
dst = tx_pool->long_term_buff.buff + offset;
memset(dst, 0, tx_pool->buf_size);
data_dma_addr = tx_pool->long_term_buff.addr + offset;
if (skb_shinfo(skb)->nr_frags) {
int cur, i;
/* Copy the head */
skb_copy_from_linear_data(skb, dst, skb_headlen(skb));
cur = skb_headlen(skb);
/* Copy the frags */
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
memcpy(dst + cur, skb_frag_address(frag),
skb_frag_size(frag));
cur += skb_frag_size(frag);
}
} else {
skb_copy_from_linear_data(skb, dst, skb->len);
}
/* post changes to long_term_buff *dst before VIOS accessing it */
dma_wmb();
tx_pool->consumer_index =
(tx_pool->consumer_index + 1) % tx_pool->num_buffers;
tx_buff = &tx_pool->tx_buff[index];
tx_buff->skb = skb;
tx_buff->index = index;
tx_buff->pool_index = queue_num;
memset(&tx_crq, 0, sizeof(tx_crq));
tx_crq.v1.first = IBMVNIC_CRQ_CMD;
tx_crq.v1.type = IBMVNIC_TX_DESC;
tx_crq.v1.n_crq_elem = 1;
tx_crq.v1.n_sge = 1;
tx_crq.v1.flags1 = IBMVNIC_TX_COMP_NEEDED;
if (skb_is_gso(skb))
tx_crq.v1.correlator =
cpu_to_be32(index | IBMVNIC_TSO_POOL_MASK);
else
tx_crq.v1.correlator = cpu_to_be32(index);
tx_crq.v1.dma_reg = cpu_to_be16(tx_pool->long_term_buff.map_id);
tx_crq.v1.sge_len = cpu_to_be32(skb->len);
tx_crq.v1.ioba = cpu_to_be64(data_dma_addr);
if (adapter->vlan_header_insertion && skb_vlan_tag_present(skb)) {
tx_crq.v1.flags2 |= IBMVNIC_TX_VLAN_INSERT;
tx_crq.v1.vlan_id = cpu_to_be16(skb->vlan_tci);
}
if (skb->protocol == htons(ETH_P_IP)) {
tx_crq.v1.flags1 |= IBMVNIC_TX_PROT_IPV4;
proto = ip_hdr(skb)->protocol;
} else if (skb->protocol == htons(ETH_P_IPV6)) {
tx_crq.v1.flags1 |= IBMVNIC_TX_PROT_IPV6;
proto = ipv6_hdr(skb)->nexthdr;
}
if (proto == IPPROTO_TCP)
tx_crq.v1.flags1 |= IBMVNIC_TX_PROT_TCP;
else if (proto == IPPROTO_UDP)
tx_crq.v1.flags1 |= IBMVNIC_TX_PROT_UDP;
if (skb->ip_summed == CHECKSUM_PARTIAL) {
tx_crq.v1.flags1 |= IBMVNIC_TX_CHKSUM_OFFLOAD;
hdrs += 2;
}
if (skb_is_gso(skb)) {
tx_crq.v1.flags1 |= IBMVNIC_TX_LSO;
tx_crq.v1.mss = cpu_to_be16(skb_shinfo(skb)->gso_size);
hdrs += 2;
}
if ((*hdrs >> 7) & 1)
build_hdr_descs_arr(skb, indir_arr, &num_entries, *hdrs);
tx_crq.v1.n_crq_elem = num_entries;
tx_buff->num_entries = num_entries;
/* flush buffer if current entry can not fit */
if (num_entries + ind_bufp->index > IBMVNIC_MAX_IND_DESCS) {
lpar_rc = ibmvnic_tx_scrq_flush(adapter, tx_scrq);
if (lpar_rc != H_SUCCESS)
goto tx_flush_err;
}
indir_arr[0] = tx_crq;
memcpy(&ind_bufp->indir_arr[ind_bufp->index], &indir_arr[0],
num_entries * sizeof(struct ibmvnic_generic_scrq));
ind_bufp->index += num_entries;
if (__netdev_tx_sent_queue(txq, skb->len,
netdev_xmit_more() &&
ind_bufp->index < IBMVNIC_MAX_IND_DESCS)) {
lpar_rc = ibmvnic_tx_scrq_flush(adapter, tx_scrq);
if (lpar_rc != H_SUCCESS)
goto tx_err;
}
if (atomic_add_return(num_entries, &tx_scrq->used)
>= adapter->req_tx_entries_per_subcrq) {
netdev_dbg(netdev, "Stopping queue %d\n", queue_num);
netif_stop_subqueue(netdev, queue_num);
}
tx_packets++;
tx_bytes += skb->len;
txq->trans_start = jiffies;
ret = NETDEV_TX_OK;
goto out;
tx_flush_err:
dev_kfree_skb_any(skb);
tx_buff->skb = NULL;
tx_pool->consumer_index = tx_pool->consumer_index == 0 ?
tx_pool->num_buffers - 1 :
tx_pool->consumer_index - 1;
tx_dropped++;
tx_err:
if (lpar_rc != H_CLOSED && lpar_rc != H_PARAMETER)
dev_err_ratelimited(dev, "tx: send failed\n");
if (lpar_rc == H_CLOSED || adapter->failover_pending) {
/* Disable TX 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 or some other action.
*/
netif_tx_stop_all_queues(netdev);
netif_carrier_off(netdev);
}
out:
netdev->stats.tx_dropped += tx_dropped;
netdev->stats.tx_bytes += tx_bytes;
netdev->stats.tx_packets += tx_packets;
adapter->tx_send_failed += tx_send_failed;
adapter->tx_map_failed += tx_map_failed;
adapter->tx_stats_buffers[queue_num].packets += tx_packets;
adapter->tx_stats_buffers[queue_num].bytes += tx_bytes;
adapter->tx_stats_buffers[queue_num].dropped_packets += tx_dropped;
return ret;
}
static void ibmvnic_set_multi(struct net_device *netdev)
{
struct ibmvnic_adapter *adapter = netdev_priv(netdev);
struct netdev_hw_addr *ha;
union ibmvnic_crq crq;
memset(&crq, 0, sizeof(crq));
crq.request_capability.first = IBMVNIC_CRQ_CMD;
crq.request_capability.cmd = REQUEST_CAPABILITY;
if (netdev->flags & IFF_PROMISC) {
if (!adapter->promisc_supported)
return;
} else {
if (netdev->flags & IFF_ALLMULTI) {
/* Accept all multicast */
memset(&crq, 0, sizeof(crq));
crq.multicast_ctrl.first = IBMVNIC_CRQ_CMD;
crq.multicast_ctrl.cmd = MULTICAST_CTRL;
crq.multicast_ctrl.flags = IBMVNIC_ENABLE_ALL;
ibmvnic_send_crq(adapter, &crq);
} else if (netdev_mc_empty(netdev)) {
/* Reject all multicast */
memset(&crq, 0, sizeof(crq));
crq.multicast_ctrl.first = IBMVNIC_CRQ_CMD;
crq.multicast_ctrl.cmd = MULTICAST_CTRL;
crq.multicast_ctrl.flags = IBMVNIC_DISABLE_ALL;
ibmvnic_send_crq(adapter, &crq);
} else {
/* Accept one or more multicast(s) */
netdev_for_each_mc_addr(ha, netdev) {
memset(&crq, 0, sizeof(crq));
crq.multicast_ctrl.first = IBMVNIC_CRQ_CMD;
crq.multicast_ctrl.cmd = MULTICAST_CTRL;
crq.multicast_ctrl.flags = IBMVNIC_ENABLE_MC;
ether_addr_copy(&crq.multicast_ctrl.mac_addr[0],
ha->addr);
ibmvnic_send_crq(adapter, &crq);
}
}
}
}
static int __ibmvnic_set_mac(struct net_device *netdev, u8 *dev_addr)
{
struct ibmvnic_adapter *adapter = netdev_priv(netdev);
union ibmvnic_crq crq;
int rc;
if (!is_valid_ether_addr(dev_addr)) {
rc = -EADDRNOTAVAIL;
goto err;
}
memset(&crq, 0, sizeof(crq));
crq.change_mac_addr.first = IBMVNIC_CRQ_CMD;
crq.change_mac_addr.cmd = CHANGE_MAC_ADDR;
ether_addr_copy(&crq.change_mac_addr.mac_addr[0], dev_addr);
mutex_lock(&adapter->fw_lock);
adapter->fw_done_rc = 0;
reinit_completion(&adapter->fw_done);
rc = ibmvnic_send_crq(adapter, &crq);
if (rc) {
rc = -EIO;
mutex_unlock(&adapter->fw_lock);
goto err;
}
rc = ibmvnic_wait_for_completion(adapter, &adapter->fw_done, 10000);
/* netdev->dev_addr is changed in handle_change_mac_rsp function */
if (rc || adapter->fw_done_rc) {
rc = -EIO;
mutex_unlock(&adapter->fw_lock);
goto err;
}
mutex_unlock(&adapter->fw_lock);
return 0;
err:
ether_addr_copy(adapter->mac_addr, netdev->dev_addr);
return rc;
}
static int ibmvnic_set_mac(struct net_device *netdev, void *p)
{
struct ibmvnic_adapter *adapter = netdev_priv(netdev);
struct sockaddr *addr = p;
int rc;
rc = 0;
if (!is_valid_ether_addr(addr->sa_data))
return -EADDRNOTAVAIL;
ether_addr_copy(adapter->mac_addr, addr->sa_data);
if (adapter->state != VNIC_PROBED)
rc = __ibmvnic_set_mac(netdev, addr->sa_data);
return rc;
}
static const char *reset_reason_to_string(enum ibmvnic_reset_reason reason)
{
switch (reason) {
case VNIC_RESET_FAILOVER:
return "FAILOVER";
case VNIC_RESET_MOBILITY:
return "MOBILITY";
case VNIC_RESET_FATAL:
return "FATAL";
case VNIC_RESET_NON_FATAL:
return "NON_FATAL";
case VNIC_RESET_TIMEOUT:
return "TIMEOUT";
case VNIC_RESET_CHANGE_PARAM:
return "CHANGE_PARAM";
case VNIC_RESET_PASSIVE_INIT:
return "PASSIVE_INIT";
}
return "UNKNOWN";
}
/*
* do_reset returns zero if we are able to keep processing reset events, or
* non-zero if we hit a fatal error and must halt.
*/
static int do_reset(struct ibmvnic_adapter *adapter,
struct ibmvnic_rwi *rwi, u32 reset_state)
{
struct net_device *netdev = adapter->netdev;
u64 old_num_rx_queues, old_num_tx_queues;
u64 old_num_rx_slots, old_num_tx_slots;
int rc;
netdev_dbg(adapter->netdev,
"[S:%s FOP:%d] Reset reason: %s, reset_state: %s\n",
adapter_state_to_string(adapter->state),
adapter->failover_pending,
reset_reason_to_string(rwi->reset_reason),
adapter_state_to_string(reset_state));
adapter->reset_reason = rwi->reset_reason;
/* requestor of VNIC_RESET_CHANGE_PARAM already has the rtnl lock */
if (!(adapter->reset_reason == VNIC_RESET_CHANGE_PARAM))
rtnl_lock();
/* Now that we have the rtnl lock, clear any pending failover.
* This will ensure ibmvnic_open() has either completed or will
* block until failover is complete.
*/
if (rwi->reset_reason == VNIC_RESET_FAILOVER)
adapter->failover_pending = false;
/* read the state and check (again) after getting rtnl */
reset_state = adapter->state;
if (reset_state == VNIC_REMOVING || reset_state == VNIC_REMOVED) {
rc = -EBUSY;
goto out;
}
netif_carrier_off(netdev);
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);
if (reset_state == VNIC_OPEN &&
adapter->reset_reason != VNIC_RESET_MOBILITY &&
adapter->reset_reason != VNIC_RESET_FAILOVER) {
if (adapter->reset_reason == VNIC_RESET_CHANGE_PARAM) {
rc = __ibmvnic_close(netdev);
if (rc)
goto out;
} else {
adapter->state = VNIC_CLOSING;
/* Release the RTNL lock before link state change and
* re-acquire after the link state change to allow
* linkwatch_event to grab the RTNL lock and run during
* a reset.
*/
rtnl_unlock();
rc = set_link_state(adapter, IBMVNIC_LOGICAL_LNK_DN);
rtnl_lock();
if (rc)
goto out;
if (adapter->state == VNIC_OPEN) {
/* When we dropped rtnl, ibmvnic_open() got
* it and noticed that we are resetting and
* set the adapter state to OPEN. Update our
* new "target" state, and resume the reset
* from VNIC_CLOSING state.
*/
netdev_dbg(netdev,
"Open changed state from %s, updating.\n",
adapter_state_to_string(reset_state));
reset_state = VNIC_OPEN;
adapter->state = VNIC_CLOSING;
}
if (adapter->state != VNIC_CLOSING) {
/* If someone else changed the adapter state
* when we dropped the rtnl, fail the reset
*/
rc = -1;
goto out;
}
adapter->state = VNIC_CLOSED;
}
}
if (adapter->reset_reason == VNIC_RESET_CHANGE_PARAM) {
release_resources(adapter);
release_sub_crqs(adapter, 1);
release_crq_queue(adapter);
}
if (adapter->reset_reason != VNIC_RESET_NON_FATAL) {
/* remove the closed state so when we call open it appears
* we are coming from the probed state.
*/
adapter->state = VNIC_PROBED;
if (adapter->reset_reason == VNIC_RESET_CHANGE_PARAM) {
rc = init_crq_queue(adapter);
} else if (adapter->reset_reason == VNIC_RESET_MOBILITY) {
rc = ibmvnic_reenable_crq_queue(adapter);
release_sub_crqs(adapter, 1);
} else {
rc = ibmvnic_reset_crq(adapter);
if (rc == H_CLOSED || rc == H_SUCCESS) {
rc = vio_enable_interrupts(adapter->vdev);
if (rc)
netdev_err(adapter->netdev,
"Reset failed to enable interrupts. rc=%d\n",
rc);
}
}
if (rc) {
netdev_err(adapter->netdev,
"Reset couldn't initialize crq. rc=%d\n", rc);
goto out;
}
rc = ibmvnic_reset_init(adapter, true);
if (rc) {
rc = IBMVNIC_INIT_FAILED;
goto out;
}
/* If the adapter was in PROBE or DOWN state prior to the reset,
* exit here.
*/
if (reset_state == VNIC_PROBED || reset_state == VNIC_DOWN) {
rc = 0;
goto out;
}
rc = ibmvnic_login(netdev);
if (rc)
goto out;
if (adapter->reset_reason == VNIC_RESET_CHANGE_PARAM) {
rc = init_resources(adapter);
if (rc)
goto out;
} else if (adapter->req_rx_queues != old_num_rx_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 ||
!adapter->rx_pool ||
!adapter->tso_pool ||
!adapter->tx_pool) {
release_napi(adapter);
release_vpd_data(adapter);
rc = init_resources(adapter);
if (rc)
goto out;
} else {
rc = init_tx_pools(netdev);
if (rc) {
netdev_dbg(netdev,
"init tx pools failed (%d)\n",
rc);
goto out;
}
rc = init_rx_pools(netdev);
if (rc) {
netdev_dbg(netdev,
"init rx pools failed (%d)\n",
rc);
goto out;
}
}
ibmvnic_disable_irqs(adapter);
}
adapter->state = VNIC_CLOSED;
if (reset_state == VNIC_CLOSED) {
rc = 0;
goto out;
}
rc = __ibmvnic_open(netdev);
if (rc) {
rc = IBMVNIC_OPEN_FAILED;
goto out;
}
/* refresh device's multicast list */
ibmvnic_set_multi(netdev);
if (adapter->reset_reason == VNIC_RESET_FAILOVER ||
adapter->reset_reason == VNIC_RESET_MOBILITY)
__netdev_notify_peers(netdev);
rc = 0;
out:
/* restore the adapter state if reset failed */
if (rc)
adapter->state = reset_state;
/* requestor of VNIC_RESET_CHANGE_PARAM should still hold the rtnl lock */
if (!(adapter->reset_reason == VNIC_RESET_CHANGE_PARAM))
rtnl_unlock();
netdev_dbg(adapter->netdev, "[S:%s FOP:%d] Reset done, rc %d\n",
adapter_state_to_string(adapter->state),
adapter->failover_pending, rc);
return rc;
}
static int do_hard_reset(struct ibmvnic_adapter *adapter,
struct ibmvnic_rwi *rwi, u32 reset_state)
{
struct net_device *netdev = adapter->netdev;
int rc;
netdev_dbg(adapter->netdev, "Hard resetting driver (%s)\n",
reset_reason_to_string(rwi->reset_reason));
/* read the state and check (again) after getting rtnl */
reset_state = adapter->state;
if (reset_state == VNIC_REMOVING || reset_state == VNIC_REMOVED) {
rc = -EBUSY;
goto out;
}
netif_carrier_off(netdev);
adapter->reset_reason = rwi->reset_reason;
ibmvnic_cleanup(netdev);
release_resources(adapter);
release_sub_crqs(adapter, 0);
release_crq_queue(adapter);
/* remove the closed state so when we call open it appears
* we are coming from the probed state.
*/
adapter->state = VNIC_PROBED;
reinit_completion(&adapter->init_done);
rc = init_crq_queue(adapter);
if (rc) {
netdev_err(adapter->netdev,
"Couldn't initialize crq. rc=%d\n", rc);
goto out;
}
rc = ibmvnic_reset_init(adapter, false);
if (rc)
goto out;
/* If the adapter was in PROBE or DOWN state prior to the reset,
* exit here.
*/
if (reset_state == VNIC_PROBED || reset_state == VNIC_DOWN)
goto out;
rc = ibmvnic_login(netdev);
if (rc)
goto out;
rc = init_resources(adapter);
if (rc)
goto out;
ibmvnic_disable_irqs(adapter);
adapter->state = VNIC_CLOSED;
if (reset_state == VNIC_CLOSED)
goto out;
rc = __ibmvnic_open(netdev);
if (rc) {
rc = IBMVNIC_OPEN_FAILED;
goto out;
}
__netdev_notify_peers(netdev);
out:
/* restore adapter state if reset failed */
if (rc)
adapter->state = reset_state;
netdev_dbg(adapter->netdev, "[S:%s FOP:%d] Hard reset done, rc %d\n",
adapter_state_to_string(adapter->state),
adapter->failover_pending, rc);
return rc;
}
static struct ibmvnic_rwi *get_next_rwi(struct ibmvnic_adapter *adapter)
{
struct ibmvnic_rwi *rwi;
unsigned long flags;
spin_lock_irqsave(&adapter->rwi_lock, flags);
if (!list_empty(&adapter->rwi_list)) {
rwi = list_first_entry(&adapter->rwi_list, struct ibmvnic_rwi,
list);
list_del(&rwi->list);
} else {
rwi = NULL;
}
spin_unlock_irqrestore(&adapter->rwi_lock, flags);
return rwi;
}
/**
* do_passive_init - complete probing when partner device is detected.
* @adapter: ibmvnic_adapter struct
*
* If the ibmvnic device does not have a partner device to communicate with at boot
* and that partner device comes online at a later time, this function is called
* to complete the initialization process of ibmvnic device.
* Caller is expected to hold rtnl_lock().
*
* Returns non-zero if sub-CRQs are not initialized properly leaving the device
* in the down state.
* Returns 0 upon success and the device is in PROBED state.
*/
static int do_passive_init(struct ibmvnic_adapter *adapter)
{
unsigned long timeout = msecs_to_jiffies(30000);
struct net_device *netdev = adapter->netdev;
struct device *dev = &adapter->vdev->dev;
int rc;
netdev_dbg(netdev, "Partner device found, probing.\n");
adapter->state = VNIC_PROBING;
reinit_completion(&adapter->init_done);
adapter->init_done_rc = 0;
adapter->crq.active = true;
rc = send_crq_init_complete(adapter);
if (rc)
goto out;
rc = send_version_xchg(adapter);
if (rc)
netdev_dbg(adapter->netdev, "send_version_xchg failed, rc=%d\n", rc);
if (!wait_for_completion_timeout(&adapter->init_done, timeout)) {
dev_err(dev, "Initialization sequence timed out\n");
rc = -ETIMEDOUT;
goto out;
}
rc = init_sub_crqs(adapter);
if (rc) {
dev_err(dev, "Initialization of sub crqs failed, rc=%d\n", rc);
goto out;
}
rc = init_sub_crq_irqs(adapter);
if (rc) {
dev_err(dev, "Failed to initialize sub crq irqs\n, rc=%d", rc);
goto init_failed;
}
netdev->mtu = adapter->req_mtu - ETH_HLEN;
netdev->min_mtu = adapter->min_mtu - ETH_HLEN;
netdev->max_mtu = adapter->max_mtu - ETH_HLEN;
adapter->state = VNIC_PROBED;
netdev_dbg(netdev, "Probed successfully. Waiting for signal from partner device.\n");
return 0;
init_failed:
release_sub_crqs(adapter, 1);
out:
adapter->state = VNIC_DOWN;
return rc;
}
static void __ibmvnic_reset(struct work_struct *work)
{
struct ibmvnic_adapter *adapter;
bool saved_state = false;
struct ibmvnic_rwi *tmprwi;
struct ibmvnic_rwi *rwi;
unsigned long flags;
u32 reset_state;
int rc = 0;
adapter = container_of(work, struct ibmvnic_adapter, ibmvnic_reset);
if (test_and_set_bit_lock(0, &adapter->resetting)) {
queue_delayed_work(system_long_wq,
&adapter->ibmvnic_delayed_reset,
IBMVNIC_RESET_DELAY);
return;
}
rwi = get_next_rwi(adapter);
while (rwi) {
spin_lock_irqsave(&adapter->state_lock, flags);
if (adapter->state == VNIC_REMOVING ||
adapter->state == VNIC_REMOVED) {
spin_unlock_irqrestore(&adapter->state_lock, flags);
kfree(rwi);
rc = EBUSY;
break;
}
if (!saved_state) {
reset_state = adapter->state;
saved_state = true;
}
spin_unlock_irqrestore(&adapter->state_lock, flags);
if (rwi->reset_reason == VNIC_RESET_PASSIVE_INIT) {
rtnl_lock();
rc = do_passive_init(adapter);
rtnl_unlock();
if (!rc)
netif_carrier_on(adapter->netdev);
} else if (adapter->force_reset_recovery) {
/* Since we are doing a hard reset now, clear the
* failover_pending flag so we don't ignore any
* future MOBILITY or other resets.
*/
adapter->failover_pending = false;
/* Transport event occurred during previous reset */
if (adapter->wait_for_reset) {
/* Previous was CHANGE_PARAM; caller locked */
adapter->force_reset_recovery = false;
rc = do_hard_reset(adapter, rwi, reset_state);
} else {
rtnl_lock();
adapter->force_reset_recovery = false;
rc = do_hard_reset(adapter, rwi, reset_state);
rtnl_unlock();
}
if (rc) {
/* give backing device time to settle down */
netdev_dbg(adapter->netdev,
"[S:%s] Hard reset failed, waiting 60 secs\n",
adapter_state_to_string(adapter->state));
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(60 * HZ);
}
} else {
rc = do_reset(adapter, rwi, reset_state);
}
tmprwi = rwi;
adapter->last_reset_time = jiffies;
if (rc)
netdev_dbg(adapter->netdev, "Reset failed, rc=%d\n", rc);
rwi = get_next_rwi(adapter);
/*
* If there is another reset queued, free the previous rwi
* and process the new reset even if previous reset failed
* (the previous reset could have failed because of a fail
* over for instance, so process the fail over).
*
* If there are no resets queued and the previous reset failed,
* the adapter would be in an undefined state. So retry the
* previous reset as a hard reset.
*/
if (rwi)
kfree(tmprwi);
else if (rc)
rwi = tmprwi;
if (rwi && (rwi->reset_reason == VNIC_RESET_FAILOVER ||
rwi->reset_reason == VNIC_RESET_MOBILITY || rc))
adapter->force_reset_recovery = true;
}
if (adapter->wait_for_reset) {
adapter->reset_done_rc = rc;
complete(&adapter->reset_done);
}
clear_bit_unlock(0, &adapter->resetting);
netdev_dbg(adapter->netdev,
"[S:%s FRR:%d WFR:%d] Done processing resets\n",
adapter_state_to_string(adapter->state),
adapter->force_reset_recovery,
adapter->wait_for_reset);
}
static void __ibmvnic_delayed_reset(struct work_struct *work)
{
struct ibmvnic_adapter *adapter;
adapter = container_of(work, struct ibmvnic_adapter,
ibmvnic_delayed_reset.work);
__ibmvnic_reset(&adapter->ibmvnic_reset);
}
static int ibmvnic_reset(struct ibmvnic_adapter *adapter,
enum ibmvnic_reset_reason reason)
{
struct list_head *entry, *tmp_entry;
struct ibmvnic_rwi *rwi, *tmp;
struct net_device *netdev = adapter->netdev;
unsigned long flags;
int ret;
spin_lock_irqsave(&adapter->rwi_lock, flags);
/* If failover is pending don't schedule any other reset.
* Instead let the failover complete. If there is already a
* a failover reset scheduled, we will detect and drop the
* duplicate reset when walking the ->rwi_list below.
*/
if (adapter->state == VNIC_REMOVING ||
adapter->state == VNIC_REMOVED ||
(adapter->failover_pending && reason != VNIC_RESET_FAILOVER)) {
ret = EBUSY;
netdev_dbg(netdev, "Adapter removing or pending failover, skipping reset\n");
goto err;
}
if (adapter->state == VNIC_PROBING) {
netdev_warn(netdev, "Adapter reset during probe\n");
adapter->init_done_rc = -EAGAIN;
ret = EAGAIN;