162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/**************************************************************************/
362306a36Sopenharmony_ci/*                                                                        */
462306a36Sopenharmony_ci/*  IBM System i and System p Virtual NIC Device Driver                   */
562306a36Sopenharmony_ci/*  Copyright (C) 2014 IBM Corp.                                          */
662306a36Sopenharmony_ci/*  Santiago Leon (santi_leon@yahoo.com)                                  */
762306a36Sopenharmony_ci/*  Thomas Falcon (tlfalcon@linux.vnet.ibm.com)                           */
862306a36Sopenharmony_ci/*  John Allen (jallen@linux.vnet.ibm.com)                                */
962306a36Sopenharmony_ci/*                                                                        */
1062306a36Sopenharmony_ci/*                                                                        */
1162306a36Sopenharmony_ci/* This module contains the implementation of a virtual ethernet device   */
1262306a36Sopenharmony_ci/* for use with IBM i/p Series LPAR Linux. It utilizes the logical LAN    */
1362306a36Sopenharmony_ci/* option of the RS/6000 Platform Architecture to interface with virtual  */
1462306a36Sopenharmony_ci/* ethernet NICs that are presented to the partition by the hypervisor.   */
1562306a36Sopenharmony_ci/*									   */
1662306a36Sopenharmony_ci/* Messages are passed between the VNIC driver and the VNIC server using  */
1762306a36Sopenharmony_ci/* Command/Response Queues (CRQs) and sub CRQs (sCRQs). CRQs are used to  */
1862306a36Sopenharmony_ci/* issue and receive commands that initiate communication with the server */
1962306a36Sopenharmony_ci/* on driver initialization. Sub CRQs (sCRQs) are similar to CRQs, but    */
2062306a36Sopenharmony_ci/* are used by the driver to notify the server that a packet is           */
2162306a36Sopenharmony_ci/* ready for transmission or that a buffer has been added to receive a    */
2262306a36Sopenharmony_ci/* packet. Subsequently, sCRQs are used by the server to notify the       */
2362306a36Sopenharmony_ci/* driver that a packet transmission has been completed or that a packet  */
2462306a36Sopenharmony_ci/* has been received and placed in a waiting buffer.                      */
2562306a36Sopenharmony_ci/*                                                                        */
2662306a36Sopenharmony_ci/* In lieu of a more conventional "on-the-fly" DMA mapping strategy in    */
2762306a36Sopenharmony_ci/* which skbs are DMA mapped and immediately unmapped when the transmit   */
2862306a36Sopenharmony_ci/* or receive has been completed, the VNIC driver is required to use      */
2962306a36Sopenharmony_ci/* "long term mapping". This entails that large, continuous DMA mapped    */
3062306a36Sopenharmony_ci/* buffers are allocated on driver initialization and these buffers are   */
3162306a36Sopenharmony_ci/* then continuously reused to pass skbs to and from the VNIC server.     */
3262306a36Sopenharmony_ci/*                                                                        */
3362306a36Sopenharmony_ci/**************************************************************************/
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#include <linux/module.h>
3662306a36Sopenharmony_ci#include <linux/moduleparam.h>
3762306a36Sopenharmony_ci#include <linux/types.h>
3862306a36Sopenharmony_ci#include <linux/errno.h>
3962306a36Sopenharmony_ci#include <linux/completion.h>
4062306a36Sopenharmony_ci#include <linux/ioport.h>
4162306a36Sopenharmony_ci#include <linux/dma-mapping.h>
4262306a36Sopenharmony_ci#include <linux/kernel.h>
4362306a36Sopenharmony_ci#include <linux/netdevice.h>
4462306a36Sopenharmony_ci#include <linux/etherdevice.h>
4562306a36Sopenharmony_ci#include <linux/skbuff.h>
4662306a36Sopenharmony_ci#include <linux/init.h>
4762306a36Sopenharmony_ci#include <linux/delay.h>
4862306a36Sopenharmony_ci#include <linux/mm.h>
4962306a36Sopenharmony_ci#include <linux/ethtool.h>
5062306a36Sopenharmony_ci#include <linux/proc_fs.h>
5162306a36Sopenharmony_ci#include <linux/if_arp.h>
5262306a36Sopenharmony_ci#include <linux/in.h>
5362306a36Sopenharmony_ci#include <linux/ip.h>
5462306a36Sopenharmony_ci#include <linux/ipv6.h>
5562306a36Sopenharmony_ci#include <linux/irq.h>
5662306a36Sopenharmony_ci#include <linux/irqdomain.h>
5762306a36Sopenharmony_ci#include <linux/kthread.h>
5862306a36Sopenharmony_ci#include <linux/seq_file.h>
5962306a36Sopenharmony_ci#include <linux/interrupt.h>
6062306a36Sopenharmony_ci#include <net/net_namespace.h>
6162306a36Sopenharmony_ci#include <asm/hvcall.h>
6262306a36Sopenharmony_ci#include <linux/atomic.h>
6362306a36Sopenharmony_ci#include <asm/vio.h>
6462306a36Sopenharmony_ci#include <asm/xive.h>
6562306a36Sopenharmony_ci#include <asm/iommu.h>
6662306a36Sopenharmony_ci#include <linux/uaccess.h>
6762306a36Sopenharmony_ci#include <asm/firmware.h>
6862306a36Sopenharmony_ci#include <linux/workqueue.h>
6962306a36Sopenharmony_ci#include <linux/if_vlan.h>
7062306a36Sopenharmony_ci#include <linux/utsname.h>
7162306a36Sopenharmony_ci#include <linux/cpu.h>
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci#include "ibmvnic.h"
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_cistatic const char ibmvnic_driver_name[] = "ibmvnic";
7662306a36Sopenharmony_cistatic const char ibmvnic_driver_string[] = "IBM System i/p Virtual NIC Driver";
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ciMODULE_AUTHOR("Santiago Leon");
7962306a36Sopenharmony_ciMODULE_DESCRIPTION("IBM System i/p Virtual NIC Driver");
8062306a36Sopenharmony_ciMODULE_LICENSE("GPL");
8162306a36Sopenharmony_ciMODULE_VERSION(IBMVNIC_DRIVER_VERSION);
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cistatic int ibmvnic_version = IBMVNIC_INITIAL_VERSION;
8462306a36Sopenharmony_cistatic void release_sub_crqs(struct ibmvnic_adapter *, bool);
8562306a36Sopenharmony_cistatic int ibmvnic_reset_crq(struct ibmvnic_adapter *);
8662306a36Sopenharmony_cistatic int ibmvnic_send_crq_init(struct ibmvnic_adapter *);
8762306a36Sopenharmony_cistatic int ibmvnic_reenable_crq_queue(struct ibmvnic_adapter *);
8862306a36Sopenharmony_cistatic int ibmvnic_send_crq(struct ibmvnic_adapter *, union ibmvnic_crq *);
8962306a36Sopenharmony_cistatic int send_subcrq_indirect(struct ibmvnic_adapter *, u64, u64, u64);
9062306a36Sopenharmony_cistatic irqreturn_t ibmvnic_interrupt_rx(int irq, void *instance);
9162306a36Sopenharmony_cistatic int enable_scrq_irq(struct ibmvnic_adapter *,
9262306a36Sopenharmony_ci			   struct ibmvnic_sub_crq_queue *);
9362306a36Sopenharmony_cistatic int disable_scrq_irq(struct ibmvnic_adapter *,
9462306a36Sopenharmony_ci			    struct ibmvnic_sub_crq_queue *);
9562306a36Sopenharmony_cistatic int pending_scrq(struct ibmvnic_adapter *,
9662306a36Sopenharmony_ci			struct ibmvnic_sub_crq_queue *);
9762306a36Sopenharmony_cistatic union sub_crq *ibmvnic_next_scrq(struct ibmvnic_adapter *,
9862306a36Sopenharmony_ci					struct ibmvnic_sub_crq_queue *);
9962306a36Sopenharmony_cistatic int ibmvnic_poll(struct napi_struct *napi, int data);
10062306a36Sopenharmony_cistatic int reset_sub_crq_queues(struct ibmvnic_adapter *adapter);
10162306a36Sopenharmony_cistatic inline void reinit_init_done(struct ibmvnic_adapter *adapter);
10262306a36Sopenharmony_cistatic void send_query_map(struct ibmvnic_adapter *adapter);
10362306a36Sopenharmony_cistatic int send_request_map(struct ibmvnic_adapter *, dma_addr_t, u32, u8);
10462306a36Sopenharmony_cistatic int send_request_unmap(struct ibmvnic_adapter *, u8);
10562306a36Sopenharmony_cistatic int send_login(struct ibmvnic_adapter *adapter);
10662306a36Sopenharmony_cistatic void send_query_cap(struct ibmvnic_adapter *adapter);
10762306a36Sopenharmony_cistatic int init_sub_crqs(struct ibmvnic_adapter *);
10862306a36Sopenharmony_cistatic int init_sub_crq_irqs(struct ibmvnic_adapter *adapter);
10962306a36Sopenharmony_cistatic int ibmvnic_reset_init(struct ibmvnic_adapter *, bool reset);
11062306a36Sopenharmony_cistatic void release_crq_queue(struct ibmvnic_adapter *);
11162306a36Sopenharmony_cistatic int __ibmvnic_set_mac(struct net_device *, u8 *);
11262306a36Sopenharmony_cistatic int init_crq_queue(struct ibmvnic_adapter *adapter);
11362306a36Sopenharmony_cistatic int send_query_phys_parms(struct ibmvnic_adapter *adapter);
11462306a36Sopenharmony_cistatic void ibmvnic_tx_scrq_clean_buffer(struct ibmvnic_adapter *adapter,
11562306a36Sopenharmony_ci					 struct ibmvnic_sub_crq_queue *tx_scrq);
11662306a36Sopenharmony_cistatic void free_long_term_buff(struct ibmvnic_adapter *adapter,
11762306a36Sopenharmony_ci				struct ibmvnic_long_term_buff *ltb);
11862306a36Sopenharmony_cistatic void ibmvnic_disable_irqs(struct ibmvnic_adapter *adapter);
11962306a36Sopenharmony_cistatic void flush_reset_queue(struct ibmvnic_adapter *adapter);
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_cistruct ibmvnic_stat {
12262306a36Sopenharmony_ci	char name[ETH_GSTRING_LEN];
12362306a36Sopenharmony_ci	int offset;
12462306a36Sopenharmony_ci};
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci#define IBMVNIC_STAT_OFF(stat) (offsetof(struct ibmvnic_adapter, stats) + \
12762306a36Sopenharmony_ci			     offsetof(struct ibmvnic_statistics, stat))
12862306a36Sopenharmony_ci#define IBMVNIC_GET_STAT(a, off) (*((u64 *)(((unsigned long)(a)) + (off))))
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_cistatic const struct ibmvnic_stat ibmvnic_stats[] = {
13162306a36Sopenharmony_ci	{"rx_packets", IBMVNIC_STAT_OFF(rx_packets)},
13262306a36Sopenharmony_ci	{"rx_bytes", IBMVNIC_STAT_OFF(rx_bytes)},
13362306a36Sopenharmony_ci	{"tx_packets", IBMVNIC_STAT_OFF(tx_packets)},
13462306a36Sopenharmony_ci	{"tx_bytes", IBMVNIC_STAT_OFF(tx_bytes)},
13562306a36Sopenharmony_ci	{"ucast_tx_packets", IBMVNIC_STAT_OFF(ucast_tx_packets)},
13662306a36Sopenharmony_ci	{"ucast_rx_packets", IBMVNIC_STAT_OFF(ucast_rx_packets)},
13762306a36Sopenharmony_ci	{"mcast_tx_packets", IBMVNIC_STAT_OFF(mcast_tx_packets)},
13862306a36Sopenharmony_ci	{"mcast_rx_packets", IBMVNIC_STAT_OFF(mcast_rx_packets)},
13962306a36Sopenharmony_ci	{"bcast_tx_packets", IBMVNIC_STAT_OFF(bcast_tx_packets)},
14062306a36Sopenharmony_ci	{"bcast_rx_packets", IBMVNIC_STAT_OFF(bcast_rx_packets)},
14162306a36Sopenharmony_ci	{"align_errors", IBMVNIC_STAT_OFF(align_errors)},
14262306a36Sopenharmony_ci	{"fcs_errors", IBMVNIC_STAT_OFF(fcs_errors)},
14362306a36Sopenharmony_ci	{"single_collision_frames", IBMVNIC_STAT_OFF(single_collision_frames)},
14462306a36Sopenharmony_ci	{"multi_collision_frames", IBMVNIC_STAT_OFF(multi_collision_frames)},
14562306a36Sopenharmony_ci	{"sqe_test_errors", IBMVNIC_STAT_OFF(sqe_test_errors)},
14662306a36Sopenharmony_ci	{"deferred_tx", IBMVNIC_STAT_OFF(deferred_tx)},
14762306a36Sopenharmony_ci	{"late_collisions", IBMVNIC_STAT_OFF(late_collisions)},
14862306a36Sopenharmony_ci	{"excess_collisions", IBMVNIC_STAT_OFF(excess_collisions)},
14962306a36Sopenharmony_ci	{"internal_mac_tx_errors", IBMVNIC_STAT_OFF(internal_mac_tx_errors)},
15062306a36Sopenharmony_ci	{"carrier_sense", IBMVNIC_STAT_OFF(carrier_sense)},
15162306a36Sopenharmony_ci	{"too_long_frames", IBMVNIC_STAT_OFF(too_long_frames)},
15262306a36Sopenharmony_ci	{"internal_mac_rx_errors", IBMVNIC_STAT_OFF(internal_mac_rx_errors)},
15362306a36Sopenharmony_ci};
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_cistatic int send_crq_init_complete(struct ibmvnic_adapter *adapter)
15662306a36Sopenharmony_ci{
15762306a36Sopenharmony_ci	union ibmvnic_crq crq;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	memset(&crq, 0, sizeof(crq));
16062306a36Sopenharmony_ci	crq.generic.first = IBMVNIC_CRQ_INIT_CMD;
16162306a36Sopenharmony_ci	crq.generic.cmd = IBMVNIC_CRQ_INIT_COMPLETE;
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	return ibmvnic_send_crq(adapter, &crq);
16462306a36Sopenharmony_ci}
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_cistatic int send_version_xchg(struct ibmvnic_adapter *adapter)
16762306a36Sopenharmony_ci{
16862306a36Sopenharmony_ci	union ibmvnic_crq crq;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	memset(&crq, 0, sizeof(crq));
17162306a36Sopenharmony_ci	crq.version_exchange.first = IBMVNIC_CRQ_CMD;
17262306a36Sopenharmony_ci	crq.version_exchange.cmd = VERSION_EXCHANGE;
17362306a36Sopenharmony_ci	crq.version_exchange.version = cpu_to_be16(ibmvnic_version);
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	return ibmvnic_send_crq(adapter, &crq);
17662306a36Sopenharmony_ci}
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_cistatic void ibmvnic_clean_queue_affinity(struct ibmvnic_adapter *adapter,
17962306a36Sopenharmony_ci					 struct ibmvnic_sub_crq_queue *queue)
18062306a36Sopenharmony_ci{
18162306a36Sopenharmony_ci	if (!(queue && queue->irq))
18262306a36Sopenharmony_ci		return;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	cpumask_clear(queue->affinity_mask);
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	if (irq_set_affinity_and_hint(queue->irq, NULL))
18762306a36Sopenharmony_ci		netdev_warn(adapter->netdev,
18862306a36Sopenharmony_ci			    "%s: Clear affinity failed, queue addr = %p, IRQ = %d\n",
18962306a36Sopenharmony_ci			    __func__, queue, queue->irq);
19062306a36Sopenharmony_ci}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_cistatic void ibmvnic_clean_affinity(struct ibmvnic_adapter *adapter)
19362306a36Sopenharmony_ci{
19462306a36Sopenharmony_ci	struct ibmvnic_sub_crq_queue **rxqs;
19562306a36Sopenharmony_ci	struct ibmvnic_sub_crq_queue **txqs;
19662306a36Sopenharmony_ci	int num_rxqs, num_txqs;
19762306a36Sopenharmony_ci	int i;
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	rxqs = adapter->rx_scrq;
20062306a36Sopenharmony_ci	txqs = adapter->tx_scrq;
20162306a36Sopenharmony_ci	num_txqs = adapter->num_active_tx_scrqs;
20262306a36Sopenharmony_ci	num_rxqs = adapter->num_active_rx_scrqs;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	netdev_dbg(adapter->netdev, "%s: Cleaning irq affinity hints", __func__);
20562306a36Sopenharmony_ci	if (txqs) {
20662306a36Sopenharmony_ci		for (i = 0; i < num_txqs; i++)
20762306a36Sopenharmony_ci			ibmvnic_clean_queue_affinity(adapter, txqs[i]);
20862306a36Sopenharmony_ci	}
20962306a36Sopenharmony_ci	if (rxqs) {
21062306a36Sopenharmony_ci		for (i = 0; i < num_rxqs; i++)
21162306a36Sopenharmony_ci			ibmvnic_clean_queue_affinity(adapter, rxqs[i]);
21262306a36Sopenharmony_ci	}
21362306a36Sopenharmony_ci}
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_cistatic int ibmvnic_set_queue_affinity(struct ibmvnic_sub_crq_queue *queue,
21662306a36Sopenharmony_ci				      unsigned int *cpu, int *stragglers,
21762306a36Sopenharmony_ci				      int stride)
21862306a36Sopenharmony_ci{
21962306a36Sopenharmony_ci	cpumask_var_t mask;
22062306a36Sopenharmony_ci	int i;
22162306a36Sopenharmony_ci	int rc = 0;
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	if (!(queue && queue->irq))
22462306a36Sopenharmony_ci		return rc;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	/* cpumask_var_t is either a pointer or array, allocation works here */
22762306a36Sopenharmony_ci	if (!zalloc_cpumask_var(&mask, GFP_KERNEL))
22862306a36Sopenharmony_ci		return -ENOMEM;
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	/* while we have extra cpu give one extra to this irq */
23162306a36Sopenharmony_ci	if (*stragglers) {
23262306a36Sopenharmony_ci		stride++;
23362306a36Sopenharmony_ci		(*stragglers)--;
23462306a36Sopenharmony_ci	}
23562306a36Sopenharmony_ci	/* atomic write is safer than writing bit by bit directly */
23662306a36Sopenharmony_ci	for (i = 0; i < stride; i++) {
23762306a36Sopenharmony_ci		cpumask_set_cpu(*cpu, mask);
23862306a36Sopenharmony_ci		*cpu = cpumask_next_wrap(*cpu, cpu_online_mask,
23962306a36Sopenharmony_ci					 nr_cpu_ids, false);
24062306a36Sopenharmony_ci	}
24162306a36Sopenharmony_ci	/* set queue affinity mask */
24262306a36Sopenharmony_ci	cpumask_copy(queue->affinity_mask, mask);
24362306a36Sopenharmony_ci	rc = irq_set_affinity_and_hint(queue->irq, queue->affinity_mask);
24462306a36Sopenharmony_ci	free_cpumask_var(mask);
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	return rc;
24762306a36Sopenharmony_ci}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci/* assumes cpu read lock is held */
25062306a36Sopenharmony_cistatic void ibmvnic_set_affinity(struct ibmvnic_adapter *adapter)
25162306a36Sopenharmony_ci{
25262306a36Sopenharmony_ci	struct ibmvnic_sub_crq_queue **rxqs = adapter->rx_scrq;
25362306a36Sopenharmony_ci	struct ibmvnic_sub_crq_queue **txqs = adapter->tx_scrq;
25462306a36Sopenharmony_ci	struct ibmvnic_sub_crq_queue *queue;
25562306a36Sopenharmony_ci	int num_rxqs = adapter->num_active_rx_scrqs, i_rxqs = 0;
25662306a36Sopenharmony_ci	int num_txqs = adapter->num_active_tx_scrqs, i_txqs = 0;
25762306a36Sopenharmony_ci	int total_queues, stride, stragglers, i;
25862306a36Sopenharmony_ci	unsigned int num_cpu, cpu;
25962306a36Sopenharmony_ci	bool is_rx_queue;
26062306a36Sopenharmony_ci	int rc = 0;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	netdev_dbg(adapter->netdev, "%s: Setting irq affinity hints", __func__);
26362306a36Sopenharmony_ci	if (!(adapter->rx_scrq && adapter->tx_scrq)) {
26462306a36Sopenharmony_ci		netdev_warn(adapter->netdev,
26562306a36Sopenharmony_ci			    "%s: Set affinity failed, queues not allocated\n",
26662306a36Sopenharmony_ci			    __func__);
26762306a36Sopenharmony_ci		return;
26862306a36Sopenharmony_ci	}
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	total_queues = num_rxqs + num_txqs;
27162306a36Sopenharmony_ci	num_cpu = num_online_cpus();
27262306a36Sopenharmony_ci	/* number of cpu's assigned per irq */
27362306a36Sopenharmony_ci	stride = max_t(int, num_cpu / total_queues, 1);
27462306a36Sopenharmony_ci	/* number of leftover cpu's */
27562306a36Sopenharmony_ci	stragglers = num_cpu >= total_queues ? num_cpu % total_queues : 0;
27662306a36Sopenharmony_ci	/* next available cpu to assign irq to */
27762306a36Sopenharmony_ci	cpu = cpumask_next(-1, cpu_online_mask);
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	for (i = 0; i < total_queues; i++) {
28062306a36Sopenharmony_ci		is_rx_queue = false;
28162306a36Sopenharmony_ci		/* balance core load by alternating rx and tx assignments
28262306a36Sopenharmony_ci		 * ex: TX0 -> RX0 -> TX1 -> RX1 etc.
28362306a36Sopenharmony_ci		 */
28462306a36Sopenharmony_ci		if ((i % 2 == 1 && i_rxqs < num_rxqs) || i_txqs == num_txqs) {
28562306a36Sopenharmony_ci			queue = rxqs[i_rxqs++];
28662306a36Sopenharmony_ci			is_rx_queue = true;
28762306a36Sopenharmony_ci		} else {
28862306a36Sopenharmony_ci			queue = txqs[i_txqs++];
28962306a36Sopenharmony_ci		}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci		rc = ibmvnic_set_queue_affinity(queue, &cpu, &stragglers,
29262306a36Sopenharmony_ci						stride);
29362306a36Sopenharmony_ci		if (rc)
29462306a36Sopenharmony_ci			goto out;
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci		if (!queue || is_rx_queue)
29762306a36Sopenharmony_ci			continue;
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci		rc = __netif_set_xps_queue(adapter->netdev,
30062306a36Sopenharmony_ci					   cpumask_bits(queue->affinity_mask),
30162306a36Sopenharmony_ci					   i_txqs - 1, XPS_CPUS);
30262306a36Sopenharmony_ci		if (rc)
30362306a36Sopenharmony_ci			netdev_warn(adapter->netdev, "%s: Set XPS on queue %d failed, rc = %d.\n",
30462306a36Sopenharmony_ci				    __func__, i_txqs - 1, rc);
30562306a36Sopenharmony_ci	}
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ciout:
30862306a36Sopenharmony_ci	if (rc) {
30962306a36Sopenharmony_ci		netdev_warn(adapter->netdev,
31062306a36Sopenharmony_ci			    "%s: Set affinity failed, queue addr = %p, IRQ = %d, rc = %d.\n",
31162306a36Sopenharmony_ci			    __func__, queue, queue->irq, rc);
31262306a36Sopenharmony_ci		ibmvnic_clean_affinity(adapter);
31362306a36Sopenharmony_ci	}
31462306a36Sopenharmony_ci}
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_cistatic int ibmvnic_cpu_online(unsigned int cpu, struct hlist_node *node)
31762306a36Sopenharmony_ci{
31862306a36Sopenharmony_ci	struct ibmvnic_adapter *adapter;
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	adapter = hlist_entry_safe(node, struct ibmvnic_adapter, node);
32162306a36Sopenharmony_ci	ibmvnic_set_affinity(adapter);
32262306a36Sopenharmony_ci	return 0;
32362306a36Sopenharmony_ci}
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_cistatic int ibmvnic_cpu_dead(unsigned int cpu, struct hlist_node *node)
32662306a36Sopenharmony_ci{
32762306a36Sopenharmony_ci	struct ibmvnic_adapter *adapter;
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	adapter = hlist_entry_safe(node, struct ibmvnic_adapter, node_dead);
33062306a36Sopenharmony_ci	ibmvnic_set_affinity(adapter);
33162306a36Sopenharmony_ci	return 0;
33262306a36Sopenharmony_ci}
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_cistatic int ibmvnic_cpu_down_prep(unsigned int cpu, struct hlist_node *node)
33562306a36Sopenharmony_ci{
33662306a36Sopenharmony_ci	struct ibmvnic_adapter *adapter;
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	adapter = hlist_entry_safe(node, struct ibmvnic_adapter, node);
33962306a36Sopenharmony_ci	ibmvnic_clean_affinity(adapter);
34062306a36Sopenharmony_ci	return 0;
34162306a36Sopenharmony_ci}
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_cistatic enum cpuhp_state ibmvnic_online;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_cistatic int ibmvnic_cpu_notif_add(struct ibmvnic_adapter *adapter)
34662306a36Sopenharmony_ci{
34762306a36Sopenharmony_ci	int ret;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	ret = cpuhp_state_add_instance_nocalls(ibmvnic_online, &adapter->node);
35062306a36Sopenharmony_ci	if (ret)
35162306a36Sopenharmony_ci		return ret;
35262306a36Sopenharmony_ci	ret = cpuhp_state_add_instance_nocalls(CPUHP_IBMVNIC_DEAD,
35362306a36Sopenharmony_ci					       &adapter->node_dead);
35462306a36Sopenharmony_ci	if (!ret)
35562306a36Sopenharmony_ci		return ret;
35662306a36Sopenharmony_ci	cpuhp_state_remove_instance_nocalls(ibmvnic_online, &adapter->node);
35762306a36Sopenharmony_ci	return ret;
35862306a36Sopenharmony_ci}
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_cistatic void ibmvnic_cpu_notif_remove(struct ibmvnic_adapter *adapter)
36162306a36Sopenharmony_ci{
36262306a36Sopenharmony_ci	cpuhp_state_remove_instance_nocalls(ibmvnic_online, &adapter->node);
36362306a36Sopenharmony_ci	cpuhp_state_remove_instance_nocalls(CPUHP_IBMVNIC_DEAD,
36462306a36Sopenharmony_ci					    &adapter->node_dead);
36562306a36Sopenharmony_ci}
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_cistatic long h_reg_sub_crq(unsigned long unit_address, unsigned long token,
36862306a36Sopenharmony_ci			  unsigned long length, unsigned long *number,
36962306a36Sopenharmony_ci			  unsigned long *irq)
37062306a36Sopenharmony_ci{
37162306a36Sopenharmony_ci	unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
37262306a36Sopenharmony_ci	long rc;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	rc = plpar_hcall(H_REG_SUB_CRQ, retbuf, unit_address, token, length);
37562306a36Sopenharmony_ci	*number = retbuf[0];
37662306a36Sopenharmony_ci	*irq = retbuf[1];
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	return rc;
37962306a36Sopenharmony_ci}
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci/**
38262306a36Sopenharmony_ci * ibmvnic_wait_for_completion - Check device state and wait for completion
38362306a36Sopenharmony_ci * @adapter: private device data
38462306a36Sopenharmony_ci * @comp_done: completion structure to wait for
38562306a36Sopenharmony_ci * @timeout: time to wait in milliseconds
38662306a36Sopenharmony_ci *
38762306a36Sopenharmony_ci * Wait for a completion signal or until the timeout limit is reached
38862306a36Sopenharmony_ci * while checking that the device is still active.
38962306a36Sopenharmony_ci */
39062306a36Sopenharmony_cistatic int ibmvnic_wait_for_completion(struct ibmvnic_adapter *adapter,
39162306a36Sopenharmony_ci				       struct completion *comp_done,
39262306a36Sopenharmony_ci				       unsigned long timeout)
39362306a36Sopenharmony_ci{
39462306a36Sopenharmony_ci	struct net_device *netdev;
39562306a36Sopenharmony_ci	unsigned long div_timeout;
39662306a36Sopenharmony_ci	u8 retry;
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	netdev = adapter->netdev;
39962306a36Sopenharmony_ci	retry = 5;
40062306a36Sopenharmony_ci	div_timeout = msecs_to_jiffies(timeout / retry);
40162306a36Sopenharmony_ci	while (true) {
40262306a36Sopenharmony_ci		if (!adapter->crq.active) {
40362306a36Sopenharmony_ci			netdev_err(netdev, "Device down!\n");
40462306a36Sopenharmony_ci			return -ENODEV;
40562306a36Sopenharmony_ci		}
40662306a36Sopenharmony_ci		if (!retry--)
40762306a36Sopenharmony_ci			break;
40862306a36Sopenharmony_ci		if (wait_for_completion_timeout(comp_done, div_timeout))
40962306a36Sopenharmony_ci			return 0;
41062306a36Sopenharmony_ci	}
41162306a36Sopenharmony_ci	netdev_err(netdev, "Operation timed out.\n");
41262306a36Sopenharmony_ci	return -ETIMEDOUT;
41362306a36Sopenharmony_ci}
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci/**
41662306a36Sopenharmony_ci * reuse_ltb() - Check if a long term buffer can be reused
41762306a36Sopenharmony_ci * @ltb:  The long term buffer to be checked
41862306a36Sopenharmony_ci * @size: The size of the long term buffer.
41962306a36Sopenharmony_ci *
42062306a36Sopenharmony_ci * An LTB can be reused unless its size has changed.
42162306a36Sopenharmony_ci *
42262306a36Sopenharmony_ci * Return: Return true if the LTB can be reused, false otherwise.
42362306a36Sopenharmony_ci */
42462306a36Sopenharmony_cistatic bool reuse_ltb(struct ibmvnic_long_term_buff *ltb, int size)
42562306a36Sopenharmony_ci{
42662306a36Sopenharmony_ci	return (ltb->buff && ltb->size == size);
42762306a36Sopenharmony_ci}
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci/**
43062306a36Sopenharmony_ci * alloc_long_term_buff() - Allocate a long term buffer (LTB)
43162306a36Sopenharmony_ci *
43262306a36Sopenharmony_ci * @adapter: ibmvnic adapter associated to the LTB
43362306a36Sopenharmony_ci * @ltb:     container object for the LTB
43462306a36Sopenharmony_ci * @size:    size of the LTB
43562306a36Sopenharmony_ci *
43662306a36Sopenharmony_ci * Allocate an LTB of the specified size and notify VIOS.
43762306a36Sopenharmony_ci *
43862306a36Sopenharmony_ci * If the given @ltb already has the correct size, reuse it. Otherwise if
43962306a36Sopenharmony_ci * its non-NULL, free it. Then allocate a new one of the correct size.
44062306a36Sopenharmony_ci * Notify the VIOS either way since we may now be working with a new VIOS.
44162306a36Sopenharmony_ci *
44262306a36Sopenharmony_ci * Allocating larger chunks of memory during resets, specially LPM or under
44362306a36Sopenharmony_ci * low memory situations can cause resets to fail/timeout and for LPAR to
44462306a36Sopenharmony_ci * lose connectivity. So hold onto the LTB even if we fail to communicate
44562306a36Sopenharmony_ci * with the VIOS and reuse it on next open. Free LTB when adapter is closed.
44662306a36Sopenharmony_ci *
44762306a36Sopenharmony_ci * Return: 0 if we were able to allocate the LTB and notify the VIOS and
44862306a36Sopenharmony_ci *	   a negative value otherwise.
44962306a36Sopenharmony_ci */
45062306a36Sopenharmony_cistatic int alloc_long_term_buff(struct ibmvnic_adapter *adapter,
45162306a36Sopenharmony_ci				struct ibmvnic_long_term_buff *ltb, int size)
45262306a36Sopenharmony_ci{
45362306a36Sopenharmony_ci	struct device *dev = &adapter->vdev->dev;
45462306a36Sopenharmony_ci	u64 prev = 0;
45562306a36Sopenharmony_ci	int rc;
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	if (!reuse_ltb(ltb, size)) {
45862306a36Sopenharmony_ci		dev_dbg(dev,
45962306a36Sopenharmony_ci			"LTB size changed from 0x%llx to 0x%x, reallocating\n",
46062306a36Sopenharmony_ci			 ltb->size, size);
46162306a36Sopenharmony_ci		prev = ltb->size;
46262306a36Sopenharmony_ci		free_long_term_buff(adapter, ltb);
46362306a36Sopenharmony_ci	}
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	if (ltb->buff) {
46662306a36Sopenharmony_ci		dev_dbg(dev, "Reusing LTB [map %d, size 0x%llx]\n",
46762306a36Sopenharmony_ci			ltb->map_id, ltb->size);
46862306a36Sopenharmony_ci	} else {
46962306a36Sopenharmony_ci		ltb->buff = dma_alloc_coherent(dev, size, &ltb->addr,
47062306a36Sopenharmony_ci					       GFP_KERNEL);
47162306a36Sopenharmony_ci		if (!ltb->buff) {
47262306a36Sopenharmony_ci			dev_err(dev, "Couldn't alloc long term buffer\n");
47362306a36Sopenharmony_ci			return -ENOMEM;
47462306a36Sopenharmony_ci		}
47562306a36Sopenharmony_ci		ltb->size = size;
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci		ltb->map_id = find_first_zero_bit(adapter->map_ids,
47862306a36Sopenharmony_ci						  MAX_MAP_ID);
47962306a36Sopenharmony_ci		bitmap_set(adapter->map_ids, ltb->map_id, 1);
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci		dev_dbg(dev,
48262306a36Sopenharmony_ci			"Allocated new LTB [map %d, size 0x%llx was 0x%llx]\n",
48362306a36Sopenharmony_ci			 ltb->map_id, ltb->size, prev);
48462306a36Sopenharmony_ci	}
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	/* Ensure ltb is zeroed - specially when reusing it. */
48762306a36Sopenharmony_ci	memset(ltb->buff, 0, ltb->size);
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	mutex_lock(&adapter->fw_lock);
49062306a36Sopenharmony_ci	adapter->fw_done_rc = 0;
49162306a36Sopenharmony_ci	reinit_completion(&adapter->fw_done);
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci	rc = send_request_map(adapter, ltb->addr, ltb->size, ltb->map_id);
49462306a36Sopenharmony_ci	if (rc) {
49562306a36Sopenharmony_ci		dev_err(dev, "send_request_map failed, rc = %d\n", rc);
49662306a36Sopenharmony_ci		goto out;
49762306a36Sopenharmony_ci	}
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	rc = ibmvnic_wait_for_completion(adapter, &adapter->fw_done, 10000);
50062306a36Sopenharmony_ci	if (rc) {
50162306a36Sopenharmony_ci		dev_err(dev, "LTB map request aborted or timed out, rc = %d\n",
50262306a36Sopenharmony_ci			rc);
50362306a36Sopenharmony_ci		goto out;
50462306a36Sopenharmony_ci	}
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	if (adapter->fw_done_rc) {
50762306a36Sopenharmony_ci		dev_err(dev, "Couldn't map LTB, rc = %d\n",
50862306a36Sopenharmony_ci			adapter->fw_done_rc);
50962306a36Sopenharmony_ci		rc = -EIO;
51062306a36Sopenharmony_ci		goto out;
51162306a36Sopenharmony_ci	}
51262306a36Sopenharmony_ci	rc = 0;
51362306a36Sopenharmony_ciout:
51462306a36Sopenharmony_ci	/* don't free LTB on communication error - see function header */
51562306a36Sopenharmony_ci	mutex_unlock(&adapter->fw_lock);
51662306a36Sopenharmony_ci	return rc;
51762306a36Sopenharmony_ci}
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_cistatic void free_long_term_buff(struct ibmvnic_adapter *adapter,
52062306a36Sopenharmony_ci				struct ibmvnic_long_term_buff *ltb)
52162306a36Sopenharmony_ci{
52262306a36Sopenharmony_ci	struct device *dev = &adapter->vdev->dev;
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	if (!ltb->buff)
52562306a36Sopenharmony_ci		return;
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	/* VIOS automatically unmaps the long term buffer at remote
52862306a36Sopenharmony_ci	 * end for the following resets:
52962306a36Sopenharmony_ci	 * FAILOVER, MOBILITY, TIMEOUT.
53062306a36Sopenharmony_ci	 */
53162306a36Sopenharmony_ci	if (adapter->reset_reason != VNIC_RESET_FAILOVER &&
53262306a36Sopenharmony_ci	    adapter->reset_reason != VNIC_RESET_MOBILITY &&
53362306a36Sopenharmony_ci	    adapter->reset_reason != VNIC_RESET_TIMEOUT)
53462306a36Sopenharmony_ci		send_request_unmap(adapter, ltb->map_id);
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	dma_free_coherent(dev, ltb->size, ltb->buff, ltb->addr);
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	ltb->buff = NULL;
53962306a36Sopenharmony_ci	/* mark this map_id free */
54062306a36Sopenharmony_ci	bitmap_clear(adapter->map_ids, ltb->map_id, 1);
54162306a36Sopenharmony_ci	ltb->map_id = 0;
54262306a36Sopenharmony_ci}
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci/**
54562306a36Sopenharmony_ci * free_ltb_set - free the given set of long term buffers (LTBS)
54662306a36Sopenharmony_ci * @adapter: The ibmvnic adapter containing this ltb set
54762306a36Sopenharmony_ci * @ltb_set: The ltb_set to be freed
54862306a36Sopenharmony_ci *
54962306a36Sopenharmony_ci * Free the set of LTBs in the given set.
55062306a36Sopenharmony_ci */
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_cistatic void free_ltb_set(struct ibmvnic_adapter *adapter,
55362306a36Sopenharmony_ci			 struct ibmvnic_ltb_set *ltb_set)
55462306a36Sopenharmony_ci{
55562306a36Sopenharmony_ci	int i;
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	for (i = 0; i < ltb_set->num_ltbs; i++)
55862306a36Sopenharmony_ci		free_long_term_buff(adapter, &ltb_set->ltbs[i]);
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	kfree(ltb_set->ltbs);
56162306a36Sopenharmony_ci	ltb_set->ltbs = NULL;
56262306a36Sopenharmony_ci	ltb_set->num_ltbs = 0;
56362306a36Sopenharmony_ci}
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci/**
56662306a36Sopenharmony_ci * alloc_ltb_set() - Allocate a set of long term buffers (LTBs)
56762306a36Sopenharmony_ci *
56862306a36Sopenharmony_ci * @adapter: ibmvnic adapter associated to the LTB
56962306a36Sopenharmony_ci * @ltb_set: container object for the set of LTBs
57062306a36Sopenharmony_ci * @num_buffs: Number of buffers in the LTB
57162306a36Sopenharmony_ci * @buff_size: Size of each buffer in the LTB
57262306a36Sopenharmony_ci *
57362306a36Sopenharmony_ci * Allocate a set of LTBs to accommodate @num_buffs buffers of @buff_size
57462306a36Sopenharmony_ci * each. We currently cap size each LTB to IBMVNIC_ONE_LTB_SIZE. If the
57562306a36Sopenharmony_ci * new set of LTBs have fewer LTBs than the old set, free the excess LTBs.
57662306a36Sopenharmony_ci * If new set needs more than in old set, allocate the remaining ones.
57762306a36Sopenharmony_ci * Try and reuse as many LTBs as possible and avoid reallocation.
57862306a36Sopenharmony_ci *
57962306a36Sopenharmony_ci * Any changes to this allocation strategy must be reflected in
58062306a36Sopenharmony_ci * map_rxpool_buff_to_ltb() and map_txpool_buff_to_ltb().
58162306a36Sopenharmony_ci */
58262306a36Sopenharmony_cistatic int alloc_ltb_set(struct ibmvnic_adapter *adapter,
58362306a36Sopenharmony_ci			 struct ibmvnic_ltb_set *ltb_set, int num_buffs,
58462306a36Sopenharmony_ci			 int buff_size)
58562306a36Sopenharmony_ci{
58662306a36Sopenharmony_ci	struct device *dev = &adapter->vdev->dev;
58762306a36Sopenharmony_ci	struct ibmvnic_ltb_set old_set;
58862306a36Sopenharmony_ci	struct ibmvnic_ltb_set new_set;
58962306a36Sopenharmony_ci	int rem_size;
59062306a36Sopenharmony_ci	int tot_size;		/* size of all ltbs */
59162306a36Sopenharmony_ci	int ltb_size;		/* size of one ltb */
59262306a36Sopenharmony_ci	int nltbs;
59362306a36Sopenharmony_ci	int rc;
59462306a36Sopenharmony_ci	int n;
59562306a36Sopenharmony_ci	int i;
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	dev_dbg(dev, "%s() num_buffs %d, buff_size %d\n", __func__, num_buffs,
59862306a36Sopenharmony_ci		buff_size);
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	ltb_size = rounddown(IBMVNIC_ONE_LTB_SIZE, buff_size);
60162306a36Sopenharmony_ci	tot_size = num_buffs * buff_size;
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	if (ltb_size > tot_size)
60462306a36Sopenharmony_ci		ltb_size = tot_size;
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	nltbs = tot_size / ltb_size;
60762306a36Sopenharmony_ci	if (tot_size % ltb_size)
60862306a36Sopenharmony_ci		nltbs++;
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	old_set = *ltb_set;
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	if (old_set.num_ltbs == nltbs) {
61362306a36Sopenharmony_ci		new_set = old_set;
61462306a36Sopenharmony_ci	} else {
61562306a36Sopenharmony_ci		int tmp = nltbs * sizeof(struct ibmvnic_long_term_buff);
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci		new_set.ltbs = kzalloc(tmp, GFP_KERNEL);
61862306a36Sopenharmony_ci		if (!new_set.ltbs)
61962306a36Sopenharmony_ci			return -ENOMEM;
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci		new_set.num_ltbs = nltbs;
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci		/* Free any excess ltbs in old set */
62462306a36Sopenharmony_ci		for (i = new_set.num_ltbs; i < old_set.num_ltbs; i++)
62562306a36Sopenharmony_ci			free_long_term_buff(adapter, &old_set.ltbs[i]);
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci		/* Copy remaining ltbs to new set. All LTBs except the
62862306a36Sopenharmony_ci		 * last one are of the same size. alloc_long_term_buff()
62962306a36Sopenharmony_ci		 * will realloc if the size changes.
63062306a36Sopenharmony_ci		 */
63162306a36Sopenharmony_ci		n = min(old_set.num_ltbs, new_set.num_ltbs);
63262306a36Sopenharmony_ci		for (i = 0; i < n; i++)
63362306a36Sopenharmony_ci			new_set.ltbs[i] = old_set.ltbs[i];
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci		/* Any additional ltbs in new set will have NULL ltbs for
63662306a36Sopenharmony_ci		 * now and will be allocated in alloc_long_term_buff().
63762306a36Sopenharmony_ci		 */
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci		/* We no longer need the old_set so free it. Note that we
64062306a36Sopenharmony_ci		 * may have reused some ltbs from old set and freed excess
64162306a36Sopenharmony_ci		 * ltbs above. So we only need to free the container now
64262306a36Sopenharmony_ci		 * not the LTBs themselves. (i.e. dont free_ltb_set()!)
64362306a36Sopenharmony_ci		 */
64462306a36Sopenharmony_ci		kfree(old_set.ltbs);
64562306a36Sopenharmony_ci		old_set.ltbs = NULL;
64662306a36Sopenharmony_ci		old_set.num_ltbs = 0;
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci		/* Install the new set. If allocations fail below, we will
64962306a36Sopenharmony_ci		 * retry later and know what size LTBs we need.
65062306a36Sopenharmony_ci		 */
65162306a36Sopenharmony_ci		*ltb_set = new_set;
65262306a36Sopenharmony_ci	}
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	i = 0;
65562306a36Sopenharmony_ci	rem_size = tot_size;
65662306a36Sopenharmony_ci	while (rem_size) {
65762306a36Sopenharmony_ci		if (ltb_size > rem_size)
65862306a36Sopenharmony_ci			ltb_size = rem_size;
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci		rem_size -= ltb_size;
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci		rc = alloc_long_term_buff(adapter, &new_set.ltbs[i], ltb_size);
66362306a36Sopenharmony_ci		if (rc)
66462306a36Sopenharmony_ci			goto out;
66562306a36Sopenharmony_ci		i++;
66662306a36Sopenharmony_ci	}
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci	WARN_ON(i != new_set.num_ltbs);
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci	return 0;
67162306a36Sopenharmony_ciout:
67262306a36Sopenharmony_ci	/* We may have allocated one/more LTBs before failing and we
67362306a36Sopenharmony_ci	 * want to try and reuse on next reset. So don't free ltb set.
67462306a36Sopenharmony_ci	 */
67562306a36Sopenharmony_ci	return rc;
67662306a36Sopenharmony_ci}
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci/**
67962306a36Sopenharmony_ci * map_rxpool_buf_to_ltb - Map given rxpool buffer to offset in an LTB.
68062306a36Sopenharmony_ci * @rxpool: The receive buffer pool containing buffer
68162306a36Sopenharmony_ci * @bufidx: Index of buffer in rxpool
68262306a36Sopenharmony_ci * @ltbp: (Output) pointer to the long term buffer containing the buffer
68362306a36Sopenharmony_ci * @offset: (Output) offset of buffer in the LTB from @ltbp
68462306a36Sopenharmony_ci *
68562306a36Sopenharmony_ci * Map the given buffer identified by [rxpool, bufidx] to an LTB in the
68662306a36Sopenharmony_ci * pool and its corresponding offset. Assume for now that each LTB is of
68762306a36Sopenharmony_ci * different size but could possibly be optimized based on the allocation
68862306a36Sopenharmony_ci * strategy in alloc_ltb_set().
68962306a36Sopenharmony_ci */
69062306a36Sopenharmony_cistatic void map_rxpool_buf_to_ltb(struct ibmvnic_rx_pool *rxpool,
69162306a36Sopenharmony_ci				  unsigned int bufidx,
69262306a36Sopenharmony_ci				  struct ibmvnic_long_term_buff **ltbp,
69362306a36Sopenharmony_ci				  unsigned int *offset)
69462306a36Sopenharmony_ci{
69562306a36Sopenharmony_ci	struct ibmvnic_long_term_buff *ltb;
69662306a36Sopenharmony_ci	int nbufs;	/* # of buffers in one ltb */
69762306a36Sopenharmony_ci	int i;
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci	WARN_ON(bufidx >= rxpool->size);
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci	for (i = 0; i < rxpool->ltb_set.num_ltbs; i++) {
70262306a36Sopenharmony_ci		ltb = &rxpool->ltb_set.ltbs[i];
70362306a36Sopenharmony_ci		nbufs = ltb->size / rxpool->buff_size;
70462306a36Sopenharmony_ci		if (bufidx < nbufs)
70562306a36Sopenharmony_ci			break;
70662306a36Sopenharmony_ci		bufidx -= nbufs;
70762306a36Sopenharmony_ci	}
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci	*ltbp = ltb;
71062306a36Sopenharmony_ci	*offset = bufidx * rxpool->buff_size;
71162306a36Sopenharmony_ci}
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci/**
71462306a36Sopenharmony_ci * map_txpool_buf_to_ltb - Map given txpool buffer to offset in an LTB.
71562306a36Sopenharmony_ci * @txpool: The transmit buffer pool containing buffer
71662306a36Sopenharmony_ci * @bufidx: Index of buffer in txpool
71762306a36Sopenharmony_ci * @ltbp: (Output) pointer to the long term buffer (LTB) containing the buffer
71862306a36Sopenharmony_ci * @offset: (Output) offset of buffer in the LTB from @ltbp
71962306a36Sopenharmony_ci *
72062306a36Sopenharmony_ci * Map the given buffer identified by [txpool, bufidx] to an LTB in the
72162306a36Sopenharmony_ci * pool and its corresponding offset.
72262306a36Sopenharmony_ci */
72362306a36Sopenharmony_cistatic void map_txpool_buf_to_ltb(struct ibmvnic_tx_pool *txpool,
72462306a36Sopenharmony_ci				  unsigned int bufidx,
72562306a36Sopenharmony_ci				  struct ibmvnic_long_term_buff **ltbp,
72662306a36Sopenharmony_ci				  unsigned int *offset)
72762306a36Sopenharmony_ci{
72862306a36Sopenharmony_ci	struct ibmvnic_long_term_buff *ltb;
72962306a36Sopenharmony_ci	int nbufs;	/* # of buffers in one ltb */
73062306a36Sopenharmony_ci	int i;
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	WARN_ON_ONCE(bufidx >= txpool->num_buffers);
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci	for (i = 0; i < txpool->ltb_set.num_ltbs; i++) {
73562306a36Sopenharmony_ci		ltb = &txpool->ltb_set.ltbs[i];
73662306a36Sopenharmony_ci		nbufs = ltb->size / txpool->buf_size;
73762306a36Sopenharmony_ci		if (bufidx < nbufs)
73862306a36Sopenharmony_ci			break;
73962306a36Sopenharmony_ci		bufidx -= nbufs;
74062306a36Sopenharmony_ci	}
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	*ltbp = ltb;
74362306a36Sopenharmony_ci	*offset = bufidx * txpool->buf_size;
74462306a36Sopenharmony_ci}
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_cistatic void deactivate_rx_pools(struct ibmvnic_adapter *adapter)
74762306a36Sopenharmony_ci{
74862306a36Sopenharmony_ci	int i;
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	for (i = 0; i < adapter->num_active_rx_pools; i++)
75162306a36Sopenharmony_ci		adapter->rx_pool[i].active = 0;
75262306a36Sopenharmony_ci}
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_cistatic void replenish_rx_pool(struct ibmvnic_adapter *adapter,
75562306a36Sopenharmony_ci			      struct ibmvnic_rx_pool *pool)
75662306a36Sopenharmony_ci{
75762306a36Sopenharmony_ci	int count = pool->size - atomic_read(&pool->available);
75862306a36Sopenharmony_ci	u64 handle = adapter->rx_scrq[pool->index]->handle;
75962306a36Sopenharmony_ci	struct device *dev = &adapter->vdev->dev;
76062306a36Sopenharmony_ci	struct ibmvnic_ind_xmit_queue *ind_bufp;
76162306a36Sopenharmony_ci	struct ibmvnic_sub_crq_queue *rx_scrq;
76262306a36Sopenharmony_ci	struct ibmvnic_long_term_buff *ltb;
76362306a36Sopenharmony_ci	union sub_crq *sub_crq;
76462306a36Sopenharmony_ci	int buffers_added = 0;
76562306a36Sopenharmony_ci	unsigned long lpar_rc;
76662306a36Sopenharmony_ci	struct sk_buff *skb;
76762306a36Sopenharmony_ci	unsigned int offset;
76862306a36Sopenharmony_ci	dma_addr_t dma_addr;
76962306a36Sopenharmony_ci	unsigned char *dst;
77062306a36Sopenharmony_ci	int shift = 0;
77162306a36Sopenharmony_ci	int bufidx;
77262306a36Sopenharmony_ci	int i;
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci	if (!pool->active)
77562306a36Sopenharmony_ci		return;
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	rx_scrq = adapter->rx_scrq[pool->index];
77862306a36Sopenharmony_ci	ind_bufp = &rx_scrq->ind_buf;
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci	/* netdev_skb_alloc() could have failed after we saved a few skbs
78162306a36Sopenharmony_ci	 * in the indir_buf and we would not have sent them to VIOS yet.
78262306a36Sopenharmony_ci	 * To account for them, start the loop at ind_bufp->index rather
78362306a36Sopenharmony_ci	 * than 0. If we pushed all the skbs to VIOS, ind_bufp->index will
78462306a36Sopenharmony_ci	 * be 0.
78562306a36Sopenharmony_ci	 */
78662306a36Sopenharmony_ci	for (i = ind_bufp->index; i < count; ++i) {
78762306a36Sopenharmony_ci		bufidx = pool->free_map[pool->next_free];
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci		/* We maybe reusing the skb from earlier resets. Allocate
79062306a36Sopenharmony_ci		 * only if necessary. But since the LTB may have changed
79162306a36Sopenharmony_ci		 * during reset (see init_rx_pools()), update LTB below
79262306a36Sopenharmony_ci		 * even if reusing skb.
79362306a36Sopenharmony_ci		 */
79462306a36Sopenharmony_ci		skb = pool->rx_buff[bufidx].skb;
79562306a36Sopenharmony_ci		if (!skb) {
79662306a36Sopenharmony_ci			skb = netdev_alloc_skb(adapter->netdev,
79762306a36Sopenharmony_ci					       pool->buff_size);
79862306a36Sopenharmony_ci			if (!skb) {
79962306a36Sopenharmony_ci				dev_err(dev, "Couldn't replenish rx buff\n");
80062306a36Sopenharmony_ci				adapter->replenish_no_mem++;
80162306a36Sopenharmony_ci				break;
80262306a36Sopenharmony_ci			}
80362306a36Sopenharmony_ci		}
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci		pool->free_map[pool->next_free] = IBMVNIC_INVALID_MAP;
80662306a36Sopenharmony_ci		pool->next_free = (pool->next_free + 1) % pool->size;
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci		/* Copy the skb to the long term mapped DMA buffer */
80962306a36Sopenharmony_ci		map_rxpool_buf_to_ltb(pool, bufidx, &ltb, &offset);
81062306a36Sopenharmony_ci		dst = ltb->buff + offset;
81162306a36Sopenharmony_ci		memset(dst, 0, pool->buff_size);
81262306a36Sopenharmony_ci		dma_addr = ltb->addr + offset;
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci		/* add the skb to an rx_buff in the pool */
81562306a36Sopenharmony_ci		pool->rx_buff[bufidx].data = dst;
81662306a36Sopenharmony_ci		pool->rx_buff[bufidx].dma = dma_addr;
81762306a36Sopenharmony_ci		pool->rx_buff[bufidx].skb = skb;
81862306a36Sopenharmony_ci		pool->rx_buff[bufidx].pool_index = pool->index;
81962306a36Sopenharmony_ci		pool->rx_buff[bufidx].size = pool->buff_size;
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci		/* queue the rx_buff for the next send_subcrq_indirect */
82262306a36Sopenharmony_ci		sub_crq = &ind_bufp->indir_arr[ind_bufp->index++];
82362306a36Sopenharmony_ci		memset(sub_crq, 0, sizeof(*sub_crq));
82462306a36Sopenharmony_ci		sub_crq->rx_add.first = IBMVNIC_CRQ_CMD;
82562306a36Sopenharmony_ci		sub_crq->rx_add.correlator =
82662306a36Sopenharmony_ci		    cpu_to_be64((u64)&pool->rx_buff[bufidx]);
82762306a36Sopenharmony_ci		sub_crq->rx_add.ioba = cpu_to_be32(dma_addr);
82862306a36Sopenharmony_ci		sub_crq->rx_add.map_id = ltb->map_id;
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci		/* The length field of the sCRQ is defined to be 24 bits so the
83162306a36Sopenharmony_ci		 * buffer size needs to be left shifted by a byte before it is
83262306a36Sopenharmony_ci		 * converted to big endian to prevent the last byte from being
83362306a36Sopenharmony_ci		 * truncated.
83462306a36Sopenharmony_ci		 */
83562306a36Sopenharmony_ci#ifdef __LITTLE_ENDIAN__
83662306a36Sopenharmony_ci		shift = 8;
83762306a36Sopenharmony_ci#endif
83862306a36Sopenharmony_ci		sub_crq->rx_add.len = cpu_to_be32(pool->buff_size << shift);
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci		/* if send_subcrq_indirect queue is full, flush to VIOS */
84162306a36Sopenharmony_ci		if (ind_bufp->index == IBMVNIC_MAX_IND_DESCS ||
84262306a36Sopenharmony_ci		    i == count - 1) {
84362306a36Sopenharmony_ci			lpar_rc =
84462306a36Sopenharmony_ci				send_subcrq_indirect(adapter, handle,
84562306a36Sopenharmony_ci						     (u64)ind_bufp->indir_dma,
84662306a36Sopenharmony_ci						     (u64)ind_bufp->index);
84762306a36Sopenharmony_ci			if (lpar_rc != H_SUCCESS)
84862306a36Sopenharmony_ci				goto failure;
84962306a36Sopenharmony_ci			buffers_added += ind_bufp->index;
85062306a36Sopenharmony_ci			adapter->replenish_add_buff_success += ind_bufp->index;
85162306a36Sopenharmony_ci			ind_bufp->index = 0;
85262306a36Sopenharmony_ci		}
85362306a36Sopenharmony_ci	}
85462306a36Sopenharmony_ci	atomic_add(buffers_added, &pool->available);
85562306a36Sopenharmony_ci	return;
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_cifailure:
85862306a36Sopenharmony_ci	if (lpar_rc != H_PARAMETER && lpar_rc != H_CLOSED)
85962306a36Sopenharmony_ci		dev_err_ratelimited(dev, "rx: replenish packet buffer failed\n");
86062306a36Sopenharmony_ci	for (i = ind_bufp->index - 1; i >= 0; --i) {
86162306a36Sopenharmony_ci		struct ibmvnic_rx_buff *rx_buff;
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci		pool->next_free = pool->next_free == 0 ?
86462306a36Sopenharmony_ci				  pool->size - 1 : pool->next_free - 1;
86562306a36Sopenharmony_ci		sub_crq = &ind_bufp->indir_arr[i];
86662306a36Sopenharmony_ci		rx_buff = (struct ibmvnic_rx_buff *)
86762306a36Sopenharmony_ci				be64_to_cpu(sub_crq->rx_add.correlator);
86862306a36Sopenharmony_ci		bufidx = (int)(rx_buff - pool->rx_buff);
86962306a36Sopenharmony_ci		pool->free_map[pool->next_free] = bufidx;
87062306a36Sopenharmony_ci		dev_kfree_skb_any(pool->rx_buff[bufidx].skb);
87162306a36Sopenharmony_ci		pool->rx_buff[bufidx].skb = NULL;
87262306a36Sopenharmony_ci	}
87362306a36Sopenharmony_ci	adapter->replenish_add_buff_failure += ind_bufp->index;
87462306a36Sopenharmony_ci	atomic_add(buffers_added, &pool->available);
87562306a36Sopenharmony_ci	ind_bufp->index = 0;
87662306a36Sopenharmony_ci	if (lpar_rc == H_CLOSED || adapter->failover_pending) {
87762306a36Sopenharmony_ci		/* Disable buffer pool replenishment and report carrier off if
87862306a36Sopenharmony_ci		 * queue is closed or pending failover.
87962306a36Sopenharmony_ci		 * Firmware guarantees that a signal will be sent to the
88062306a36Sopenharmony_ci		 * driver, triggering a reset.
88162306a36Sopenharmony_ci		 */
88262306a36Sopenharmony_ci		deactivate_rx_pools(adapter);
88362306a36Sopenharmony_ci		netif_carrier_off(adapter->netdev);
88462306a36Sopenharmony_ci	}
88562306a36Sopenharmony_ci}
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_cistatic void replenish_pools(struct ibmvnic_adapter *adapter)
88862306a36Sopenharmony_ci{
88962306a36Sopenharmony_ci	int i;
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_ci	adapter->replenish_task_cycles++;
89262306a36Sopenharmony_ci	for (i = 0; i < adapter->num_active_rx_pools; i++) {
89362306a36Sopenharmony_ci		if (adapter->rx_pool[i].active)
89462306a36Sopenharmony_ci			replenish_rx_pool(adapter, &adapter->rx_pool[i]);
89562306a36Sopenharmony_ci	}
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci	netdev_dbg(adapter->netdev, "Replenished %d pools\n", i);
89862306a36Sopenharmony_ci}
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_cistatic void release_stats_buffers(struct ibmvnic_adapter *adapter)
90162306a36Sopenharmony_ci{
90262306a36Sopenharmony_ci	kfree(adapter->tx_stats_buffers);
90362306a36Sopenharmony_ci	kfree(adapter->rx_stats_buffers);
90462306a36Sopenharmony_ci	adapter->tx_stats_buffers = NULL;
90562306a36Sopenharmony_ci	adapter->rx_stats_buffers = NULL;
90662306a36Sopenharmony_ci}
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_cistatic int init_stats_buffers(struct ibmvnic_adapter *adapter)
90962306a36Sopenharmony_ci{
91062306a36Sopenharmony_ci	adapter->tx_stats_buffers =
91162306a36Sopenharmony_ci				kcalloc(IBMVNIC_MAX_QUEUES,
91262306a36Sopenharmony_ci					sizeof(struct ibmvnic_tx_queue_stats),
91362306a36Sopenharmony_ci					GFP_KERNEL);
91462306a36Sopenharmony_ci	if (!adapter->tx_stats_buffers)
91562306a36Sopenharmony_ci		return -ENOMEM;
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci	adapter->rx_stats_buffers =
91862306a36Sopenharmony_ci				kcalloc(IBMVNIC_MAX_QUEUES,
91962306a36Sopenharmony_ci					sizeof(struct ibmvnic_rx_queue_stats),
92062306a36Sopenharmony_ci					GFP_KERNEL);
92162306a36Sopenharmony_ci	if (!adapter->rx_stats_buffers)
92262306a36Sopenharmony_ci		return -ENOMEM;
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_ci	return 0;
92562306a36Sopenharmony_ci}
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_cistatic void release_stats_token(struct ibmvnic_adapter *adapter)
92862306a36Sopenharmony_ci{
92962306a36Sopenharmony_ci	struct device *dev = &adapter->vdev->dev;
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci	if (!adapter->stats_token)
93262306a36Sopenharmony_ci		return;
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci	dma_unmap_single(dev, adapter->stats_token,
93562306a36Sopenharmony_ci			 sizeof(struct ibmvnic_statistics),
93662306a36Sopenharmony_ci			 DMA_FROM_DEVICE);
93762306a36Sopenharmony_ci	adapter->stats_token = 0;
93862306a36Sopenharmony_ci}
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_cistatic int init_stats_token(struct ibmvnic_adapter *adapter)
94162306a36Sopenharmony_ci{
94262306a36Sopenharmony_ci	struct device *dev = &adapter->vdev->dev;
94362306a36Sopenharmony_ci	dma_addr_t stok;
94462306a36Sopenharmony_ci	int rc;
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci	stok = dma_map_single(dev, &adapter->stats,
94762306a36Sopenharmony_ci			      sizeof(struct ibmvnic_statistics),
94862306a36Sopenharmony_ci			      DMA_FROM_DEVICE);
94962306a36Sopenharmony_ci	rc = dma_mapping_error(dev, stok);
95062306a36Sopenharmony_ci	if (rc) {
95162306a36Sopenharmony_ci		dev_err(dev, "Couldn't map stats buffer, rc = %d\n", rc);
95262306a36Sopenharmony_ci		return rc;
95362306a36Sopenharmony_ci	}
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci	adapter->stats_token = stok;
95662306a36Sopenharmony_ci	netdev_dbg(adapter->netdev, "Stats token initialized (%llx)\n", stok);
95762306a36Sopenharmony_ci	return 0;
95862306a36Sopenharmony_ci}
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci/**
96162306a36Sopenharmony_ci * release_rx_pools() - Release any rx pools attached to @adapter.
96262306a36Sopenharmony_ci * @adapter: ibmvnic adapter
96362306a36Sopenharmony_ci *
96462306a36Sopenharmony_ci * Safe to call this multiple times - even if no pools are attached.
96562306a36Sopenharmony_ci */
96662306a36Sopenharmony_cistatic void release_rx_pools(struct ibmvnic_adapter *adapter)
96762306a36Sopenharmony_ci{
96862306a36Sopenharmony_ci	struct ibmvnic_rx_pool *rx_pool;
96962306a36Sopenharmony_ci	int i, j;
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci	if (!adapter->rx_pool)
97262306a36Sopenharmony_ci		return;
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci	for (i = 0; i < adapter->num_active_rx_pools; i++) {
97562306a36Sopenharmony_ci		rx_pool = &adapter->rx_pool[i];
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci		netdev_dbg(adapter->netdev, "Releasing rx_pool[%d]\n", i);
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci		kfree(rx_pool->free_map);
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci		free_ltb_set(adapter, &rx_pool->ltb_set);
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci		if (!rx_pool->rx_buff)
98462306a36Sopenharmony_ci			continue;
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ci		for (j = 0; j < rx_pool->size; j++) {
98762306a36Sopenharmony_ci			if (rx_pool->rx_buff[j].skb) {
98862306a36Sopenharmony_ci				dev_kfree_skb_any(rx_pool->rx_buff[j].skb);
98962306a36Sopenharmony_ci				rx_pool->rx_buff[j].skb = NULL;
99062306a36Sopenharmony_ci			}
99162306a36Sopenharmony_ci		}
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ci		kfree(rx_pool->rx_buff);
99462306a36Sopenharmony_ci	}
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_ci	kfree(adapter->rx_pool);
99762306a36Sopenharmony_ci	adapter->rx_pool = NULL;
99862306a36Sopenharmony_ci	adapter->num_active_rx_pools = 0;
99962306a36Sopenharmony_ci	adapter->prev_rx_pool_size = 0;
100062306a36Sopenharmony_ci}
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_ci/**
100362306a36Sopenharmony_ci * reuse_rx_pools() - Check if the existing rx pools can be reused.
100462306a36Sopenharmony_ci * @adapter: ibmvnic adapter
100562306a36Sopenharmony_ci *
100662306a36Sopenharmony_ci * Check if the existing rx pools in the adapter can be reused. The
100762306a36Sopenharmony_ci * pools can be reused if the pool parameters (number of pools,
100862306a36Sopenharmony_ci * number of buffers in the pool and size of each buffer) have not
100962306a36Sopenharmony_ci * changed.
101062306a36Sopenharmony_ci *
101162306a36Sopenharmony_ci * NOTE: This assumes that all pools have the same number of buffers
101262306a36Sopenharmony_ci *       which is the case currently. If that changes, we must fix this.
101362306a36Sopenharmony_ci *
101462306a36Sopenharmony_ci * Return: true if the rx pools can be reused, false otherwise.
101562306a36Sopenharmony_ci */
101662306a36Sopenharmony_cistatic bool reuse_rx_pools(struct ibmvnic_adapter *adapter)
101762306a36Sopenharmony_ci{
101862306a36Sopenharmony_ci	u64 old_num_pools, new_num_pools;
101962306a36Sopenharmony_ci	u64 old_pool_size, new_pool_size;
102062306a36Sopenharmony_ci	u64 old_buff_size, new_buff_size;
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci	if (!adapter->rx_pool)
102362306a36Sopenharmony_ci		return false;
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_ci	old_num_pools = adapter->num_active_rx_pools;
102662306a36Sopenharmony_ci	new_num_pools = adapter->req_rx_queues;
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ci	old_pool_size = adapter->prev_rx_pool_size;
102962306a36Sopenharmony_ci	new_pool_size = adapter->req_rx_add_entries_per_subcrq;
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci	old_buff_size = adapter->prev_rx_buf_sz;
103262306a36Sopenharmony_ci	new_buff_size = adapter->cur_rx_buf_sz;
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_ci	if (old_buff_size != new_buff_size ||
103562306a36Sopenharmony_ci	    old_num_pools != new_num_pools ||
103662306a36Sopenharmony_ci	    old_pool_size != new_pool_size)
103762306a36Sopenharmony_ci		return false;
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_ci	return true;
104062306a36Sopenharmony_ci}
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci/**
104362306a36Sopenharmony_ci * init_rx_pools(): Initialize the set of receiver pools in the adapter.
104462306a36Sopenharmony_ci * @netdev: net device associated with the vnic interface
104562306a36Sopenharmony_ci *
104662306a36Sopenharmony_ci * Initialize the set of receiver pools in the ibmvnic adapter associated
104762306a36Sopenharmony_ci * with the net_device @netdev. If possible, reuse the existing rx pools.
104862306a36Sopenharmony_ci * Otherwise free any existing pools and  allocate a new set of pools
104962306a36Sopenharmony_ci * before initializing them.
105062306a36Sopenharmony_ci *
105162306a36Sopenharmony_ci * Return: 0 on success and negative value on error.
105262306a36Sopenharmony_ci */
105362306a36Sopenharmony_cistatic int init_rx_pools(struct net_device *netdev)
105462306a36Sopenharmony_ci{
105562306a36Sopenharmony_ci	struct ibmvnic_adapter *adapter = netdev_priv(netdev);
105662306a36Sopenharmony_ci	struct device *dev = &adapter->vdev->dev;
105762306a36Sopenharmony_ci	struct ibmvnic_rx_pool *rx_pool;
105862306a36Sopenharmony_ci	u64 num_pools;
105962306a36Sopenharmony_ci	u64 pool_size;		/* # of buffers in one pool */
106062306a36Sopenharmony_ci	u64 buff_size;
106162306a36Sopenharmony_ci	int i, j, rc;
106262306a36Sopenharmony_ci
106362306a36Sopenharmony_ci	pool_size = adapter->req_rx_add_entries_per_subcrq;
106462306a36Sopenharmony_ci	num_pools = adapter->req_rx_queues;
106562306a36Sopenharmony_ci	buff_size = adapter->cur_rx_buf_sz;
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci	if (reuse_rx_pools(adapter)) {
106862306a36Sopenharmony_ci		dev_dbg(dev, "Reusing rx pools\n");
106962306a36Sopenharmony_ci		goto update_ltb;
107062306a36Sopenharmony_ci	}
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci	/* Allocate/populate the pools. */
107362306a36Sopenharmony_ci	release_rx_pools(adapter);
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci	adapter->rx_pool = kcalloc(num_pools,
107662306a36Sopenharmony_ci				   sizeof(struct ibmvnic_rx_pool),
107762306a36Sopenharmony_ci				   GFP_KERNEL);
107862306a36Sopenharmony_ci	if (!adapter->rx_pool) {
107962306a36Sopenharmony_ci		dev_err(dev, "Failed to allocate rx pools\n");
108062306a36Sopenharmony_ci		return -ENOMEM;
108162306a36Sopenharmony_ci	}
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci	/* Set num_active_rx_pools early. If we fail below after partial
108462306a36Sopenharmony_ci	 * allocation, release_rx_pools() will know how many to look for.
108562306a36Sopenharmony_ci	 */
108662306a36Sopenharmony_ci	adapter->num_active_rx_pools = num_pools;
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci	for (i = 0; i < num_pools; i++) {
108962306a36Sopenharmony_ci		rx_pool = &adapter->rx_pool[i];
109062306a36Sopenharmony_ci
109162306a36Sopenharmony_ci		netdev_dbg(adapter->netdev,
109262306a36Sopenharmony_ci			   "Initializing rx_pool[%d], %lld buffs, %lld bytes each\n",
109362306a36Sopenharmony_ci			   i, pool_size, buff_size);
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_ci		rx_pool->size = pool_size;
109662306a36Sopenharmony_ci		rx_pool->index = i;
109762306a36Sopenharmony_ci		rx_pool->buff_size = ALIGN(buff_size, L1_CACHE_BYTES);
109862306a36Sopenharmony_ci
109962306a36Sopenharmony_ci		rx_pool->free_map = kcalloc(rx_pool->size, sizeof(int),
110062306a36Sopenharmony_ci					    GFP_KERNEL);
110162306a36Sopenharmony_ci		if (!rx_pool->free_map) {
110262306a36Sopenharmony_ci			dev_err(dev, "Couldn't alloc free_map %d\n", i);
110362306a36Sopenharmony_ci			rc = -ENOMEM;
110462306a36Sopenharmony_ci			goto out_release;
110562306a36Sopenharmony_ci		}
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_ci		rx_pool->rx_buff = kcalloc(rx_pool->size,
110862306a36Sopenharmony_ci					   sizeof(struct ibmvnic_rx_buff),
110962306a36Sopenharmony_ci					   GFP_KERNEL);
111062306a36Sopenharmony_ci		if (!rx_pool->rx_buff) {
111162306a36Sopenharmony_ci			dev_err(dev, "Couldn't alloc rx buffers\n");
111262306a36Sopenharmony_ci			rc = -ENOMEM;
111362306a36Sopenharmony_ci			goto out_release;
111462306a36Sopenharmony_ci		}
111562306a36Sopenharmony_ci	}
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_ci	adapter->prev_rx_pool_size = pool_size;
111862306a36Sopenharmony_ci	adapter->prev_rx_buf_sz = adapter->cur_rx_buf_sz;
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_ciupdate_ltb:
112162306a36Sopenharmony_ci	for (i = 0; i < num_pools; i++) {
112262306a36Sopenharmony_ci		rx_pool = &adapter->rx_pool[i];
112362306a36Sopenharmony_ci		dev_dbg(dev, "Updating LTB for rx pool %d [%d, %d]\n",
112462306a36Sopenharmony_ci			i, rx_pool->size, rx_pool->buff_size);
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_ci		rc = alloc_ltb_set(adapter, &rx_pool->ltb_set,
112762306a36Sopenharmony_ci				   rx_pool->size, rx_pool->buff_size);
112862306a36Sopenharmony_ci		if (rc)
112962306a36Sopenharmony_ci			goto out;
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_ci		for (j = 0; j < rx_pool->size; ++j) {
113262306a36Sopenharmony_ci			struct ibmvnic_rx_buff *rx_buff;
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci			rx_pool->free_map[j] = j;
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_ci			/* NOTE: Don't clear rx_buff->skb here - will leak
113762306a36Sopenharmony_ci			 * memory! replenish_rx_pool() will reuse skbs or
113862306a36Sopenharmony_ci			 * allocate as necessary.
113962306a36Sopenharmony_ci			 */
114062306a36Sopenharmony_ci			rx_buff = &rx_pool->rx_buff[j];
114162306a36Sopenharmony_ci			rx_buff->dma = 0;
114262306a36Sopenharmony_ci			rx_buff->data = 0;
114362306a36Sopenharmony_ci			rx_buff->size = 0;
114462306a36Sopenharmony_ci			rx_buff->pool_index = 0;
114562306a36Sopenharmony_ci		}
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_ci		/* Mark pool "empty" so replenish_rx_pools() will
114862306a36Sopenharmony_ci		 * update the LTB info for each buffer
114962306a36Sopenharmony_ci		 */
115062306a36Sopenharmony_ci		atomic_set(&rx_pool->available, 0);
115162306a36Sopenharmony_ci		rx_pool->next_alloc = 0;
115262306a36Sopenharmony_ci		rx_pool->next_free = 0;
115362306a36Sopenharmony_ci		/* replenish_rx_pool() may have called deactivate_rx_pools()
115462306a36Sopenharmony_ci		 * on failover. Ensure pool is active now.
115562306a36Sopenharmony_ci		 */
115662306a36Sopenharmony_ci		rx_pool->active = 1;
115762306a36Sopenharmony_ci	}
115862306a36Sopenharmony_ci	return 0;
115962306a36Sopenharmony_ciout_release:
116062306a36Sopenharmony_ci	release_rx_pools(adapter);
116162306a36Sopenharmony_ciout:
116262306a36Sopenharmony_ci	/* We failed to allocate one or more LTBs or map them on the VIOS.
116362306a36Sopenharmony_ci	 * Hold onto the pools and any LTBs that we did allocate/map.
116462306a36Sopenharmony_ci	 */
116562306a36Sopenharmony_ci	return rc;
116662306a36Sopenharmony_ci}
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_cistatic void release_vpd_data(struct ibmvnic_adapter *adapter)
116962306a36Sopenharmony_ci{
117062306a36Sopenharmony_ci	if (!adapter->vpd)
117162306a36Sopenharmony_ci		return;
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ci	kfree(adapter->vpd->buff);
117462306a36Sopenharmony_ci	kfree(adapter->vpd);
117562306a36Sopenharmony_ci
117662306a36Sopenharmony_ci	adapter->vpd = NULL;
117762306a36Sopenharmony_ci}
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_cistatic void release_one_tx_pool(struct ibmvnic_adapter *adapter,
118062306a36Sopenharmony_ci				struct ibmvnic_tx_pool *tx_pool)
118162306a36Sopenharmony_ci{
118262306a36Sopenharmony_ci	kfree(tx_pool->tx_buff);
118362306a36Sopenharmony_ci	kfree(tx_pool->free_map);
118462306a36Sopenharmony_ci	free_ltb_set(adapter, &tx_pool->ltb_set);
118562306a36Sopenharmony_ci}
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_ci/**
118862306a36Sopenharmony_ci * release_tx_pools() - Release any tx pools attached to @adapter.
118962306a36Sopenharmony_ci * @adapter: ibmvnic adapter
119062306a36Sopenharmony_ci *
119162306a36Sopenharmony_ci * Safe to call this multiple times - even if no pools are attached.
119262306a36Sopenharmony_ci */
119362306a36Sopenharmony_cistatic void release_tx_pools(struct ibmvnic_adapter *adapter)
119462306a36Sopenharmony_ci{
119562306a36Sopenharmony_ci	int i;
119662306a36Sopenharmony_ci
119762306a36Sopenharmony_ci	/* init_tx_pools() ensures that ->tx_pool and ->tso_pool are
119862306a36Sopenharmony_ci	 * both NULL or both non-NULL. So we only need to check one.
119962306a36Sopenharmony_ci	 */
120062306a36Sopenharmony_ci	if (!adapter->tx_pool)
120162306a36Sopenharmony_ci		return;
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_ci	for (i = 0; i < adapter->num_active_tx_pools; i++) {
120462306a36Sopenharmony_ci		release_one_tx_pool(adapter, &adapter->tx_pool[i]);
120562306a36Sopenharmony_ci		release_one_tx_pool(adapter, &adapter->tso_pool[i]);
120662306a36Sopenharmony_ci	}
120762306a36Sopenharmony_ci
120862306a36Sopenharmony_ci	kfree(adapter->tx_pool);
120962306a36Sopenharmony_ci	adapter->tx_pool = NULL;
121062306a36Sopenharmony_ci	kfree(adapter->tso_pool);
121162306a36Sopenharmony_ci	adapter->tso_pool = NULL;
121262306a36Sopenharmony_ci	adapter->num_active_tx_pools = 0;
121362306a36Sopenharmony_ci	adapter->prev_tx_pool_size = 0;
121462306a36Sopenharmony_ci}
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_cistatic int init_one_tx_pool(struct net_device *netdev,
121762306a36Sopenharmony_ci			    struct ibmvnic_tx_pool *tx_pool,
121862306a36Sopenharmony_ci			    int pool_size, int buf_size)
121962306a36Sopenharmony_ci{
122062306a36Sopenharmony_ci	int i;
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_ci	tx_pool->tx_buff = kcalloc(pool_size,
122362306a36Sopenharmony_ci				   sizeof(struct ibmvnic_tx_buff),
122462306a36Sopenharmony_ci				   GFP_KERNEL);
122562306a36Sopenharmony_ci	if (!tx_pool->tx_buff)
122662306a36Sopenharmony_ci		return -ENOMEM;
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci	tx_pool->free_map = kcalloc(pool_size, sizeof(int), GFP_KERNEL);
122962306a36Sopenharmony_ci	if (!tx_pool->free_map) {
123062306a36Sopenharmony_ci		kfree(tx_pool->tx_buff);
123162306a36Sopenharmony_ci		tx_pool->tx_buff = NULL;
123262306a36Sopenharmony_ci		return -ENOMEM;
123362306a36Sopenharmony_ci	}
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_ci	for (i = 0; i < pool_size; i++)
123662306a36Sopenharmony_ci		tx_pool->free_map[i] = i;
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_ci	tx_pool->consumer_index = 0;
123962306a36Sopenharmony_ci	tx_pool->producer_index = 0;
124062306a36Sopenharmony_ci	tx_pool->num_buffers = pool_size;
124162306a36Sopenharmony_ci	tx_pool->buf_size = buf_size;
124262306a36Sopenharmony_ci
124362306a36Sopenharmony_ci	return 0;
124462306a36Sopenharmony_ci}
124562306a36Sopenharmony_ci
124662306a36Sopenharmony_ci/**
124762306a36Sopenharmony_ci * reuse_tx_pools() - Check if the existing tx pools can be reused.
124862306a36Sopenharmony_ci * @adapter: ibmvnic adapter
124962306a36Sopenharmony_ci *
125062306a36Sopenharmony_ci * Check if the existing tx pools in the adapter can be reused. The
125162306a36Sopenharmony_ci * pools can be reused if the pool parameters (number of pools,
125262306a36Sopenharmony_ci * number of buffers in the pool and mtu) have not changed.
125362306a36Sopenharmony_ci *
125462306a36Sopenharmony_ci * NOTE: This assumes that all pools have the same number of buffers
125562306a36Sopenharmony_ci *       which is the case currently. If that changes, we must fix this.
125662306a36Sopenharmony_ci *
125762306a36Sopenharmony_ci * Return: true if the tx pools can be reused, false otherwise.
125862306a36Sopenharmony_ci */
125962306a36Sopenharmony_cistatic bool reuse_tx_pools(struct ibmvnic_adapter *adapter)
126062306a36Sopenharmony_ci{
126162306a36Sopenharmony_ci	u64 old_num_pools, new_num_pools;
126262306a36Sopenharmony_ci	u64 old_pool_size, new_pool_size;
126362306a36Sopenharmony_ci	u64 old_mtu, new_mtu;
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_ci	if (!adapter->tx_pool)
126662306a36Sopenharmony_ci		return false;
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_ci	old_num_pools = adapter->num_active_tx_pools;
126962306a36Sopenharmony_ci	new_num_pools = adapter->num_active_tx_scrqs;
127062306a36Sopenharmony_ci	old_pool_size = adapter->prev_tx_pool_size;
127162306a36Sopenharmony_ci	new_pool_size = adapter->req_tx_entries_per_subcrq;
127262306a36Sopenharmony_ci	old_mtu = adapter->prev_mtu;
127362306a36Sopenharmony_ci	new_mtu = adapter->req_mtu;
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_ci	if (old_mtu != new_mtu ||
127662306a36Sopenharmony_ci	    old_num_pools != new_num_pools ||
127762306a36Sopenharmony_ci	    old_pool_size != new_pool_size)
127862306a36Sopenharmony_ci		return false;
127962306a36Sopenharmony_ci
128062306a36Sopenharmony_ci	return true;
128162306a36Sopenharmony_ci}
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_ci/**
128462306a36Sopenharmony_ci * init_tx_pools(): Initialize the set of transmit pools in the adapter.
128562306a36Sopenharmony_ci * @netdev: net device associated with the vnic interface
128662306a36Sopenharmony_ci *
128762306a36Sopenharmony_ci * Initialize the set of transmit pools in the ibmvnic adapter associated
128862306a36Sopenharmony_ci * with the net_device @netdev. If possible, reuse the existing tx pools.
128962306a36Sopenharmony_ci * Otherwise free any existing pools and  allocate a new set of pools
129062306a36Sopenharmony_ci * before initializing them.
129162306a36Sopenharmony_ci *
129262306a36Sopenharmony_ci * Return: 0 on success and negative value on error.
129362306a36Sopenharmony_ci */
129462306a36Sopenharmony_cistatic int init_tx_pools(struct net_device *netdev)
129562306a36Sopenharmony_ci{
129662306a36Sopenharmony_ci	struct ibmvnic_adapter *adapter = netdev_priv(netdev);
129762306a36Sopenharmony_ci	struct device *dev = &adapter->vdev->dev;
129862306a36Sopenharmony_ci	int num_pools;
129962306a36Sopenharmony_ci	u64 pool_size;		/* # of buffers in pool */
130062306a36Sopenharmony_ci	u64 buff_size;
130162306a36Sopenharmony_ci	int i, j, rc;
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ci	num_pools = adapter->req_tx_queues;
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci	/* We must notify the VIOS about the LTB on all resets - but we only
130662306a36Sopenharmony_ci	 * need to alloc/populate pools if either the number of buffers or
130762306a36Sopenharmony_ci	 * size of each buffer in the pool has changed.
130862306a36Sopenharmony_ci	 */
130962306a36Sopenharmony_ci	if (reuse_tx_pools(adapter)) {
131062306a36Sopenharmony_ci		netdev_dbg(netdev, "Reusing tx pools\n");
131162306a36Sopenharmony_ci		goto update_ltb;
131262306a36Sopenharmony_ci	}
131362306a36Sopenharmony_ci
131462306a36Sopenharmony_ci	/* Allocate/populate the pools. */
131562306a36Sopenharmony_ci	release_tx_pools(adapter);
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_ci	pool_size = adapter->req_tx_entries_per_subcrq;
131862306a36Sopenharmony_ci	num_pools = adapter->num_active_tx_scrqs;
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_ci	adapter->tx_pool = kcalloc(num_pools,
132162306a36Sopenharmony_ci				   sizeof(struct ibmvnic_tx_pool), GFP_KERNEL);
132262306a36Sopenharmony_ci	if (!adapter->tx_pool)
132362306a36Sopenharmony_ci		return -ENOMEM;
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_ci	adapter->tso_pool = kcalloc(num_pools,
132662306a36Sopenharmony_ci				    sizeof(struct ibmvnic_tx_pool), GFP_KERNEL);
132762306a36Sopenharmony_ci	/* To simplify release_tx_pools() ensure that ->tx_pool and
132862306a36Sopenharmony_ci	 * ->tso_pool are either both NULL or both non-NULL.
132962306a36Sopenharmony_ci	 */
133062306a36Sopenharmony_ci	if (!adapter->tso_pool) {
133162306a36Sopenharmony_ci		kfree(adapter->tx_pool);
133262306a36Sopenharmony_ci		adapter->tx_pool = NULL;
133362306a36Sopenharmony_ci		return -ENOMEM;
133462306a36Sopenharmony_ci	}
133562306a36Sopenharmony_ci
133662306a36Sopenharmony_ci	/* Set num_active_tx_pools early. If we fail below after partial
133762306a36Sopenharmony_ci	 * allocation, release_tx_pools() will know how many to look for.
133862306a36Sopenharmony_ci	 */
133962306a36Sopenharmony_ci	adapter->num_active_tx_pools = num_pools;
134062306a36Sopenharmony_ci
134162306a36Sopenharmony_ci	buff_size = adapter->req_mtu + VLAN_HLEN;
134262306a36Sopenharmony_ci	buff_size = ALIGN(buff_size, L1_CACHE_BYTES);
134362306a36Sopenharmony_ci
134462306a36Sopenharmony_ci	for (i = 0; i < num_pools; i++) {
134562306a36Sopenharmony_ci		dev_dbg(dev, "Init tx pool %d [%llu, %llu]\n",
134662306a36Sopenharmony_ci			i, adapter->req_tx_entries_per_subcrq, buff_size);
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_ci		rc = init_one_tx_pool(netdev, &adapter->tx_pool[i],
134962306a36Sopenharmony_ci				      pool_size, buff_size);
135062306a36Sopenharmony_ci		if (rc)
135162306a36Sopenharmony_ci			goto out_release;
135262306a36Sopenharmony_ci
135362306a36Sopenharmony_ci		rc = init_one_tx_pool(netdev, &adapter->tso_pool[i],
135462306a36Sopenharmony_ci				      IBMVNIC_TSO_BUFS,
135562306a36Sopenharmony_ci				      IBMVNIC_TSO_BUF_SZ);
135662306a36Sopenharmony_ci		if (rc)
135762306a36Sopenharmony_ci			goto out_release;
135862306a36Sopenharmony_ci	}
135962306a36Sopenharmony_ci
136062306a36Sopenharmony_ci	adapter->prev_tx_pool_size = pool_size;
136162306a36Sopenharmony_ci	adapter->prev_mtu = adapter->req_mtu;
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_ciupdate_ltb:
136462306a36Sopenharmony_ci	/* NOTE: All tx_pools have the same number of buffers (which is
136562306a36Sopenharmony_ci	 *       same as pool_size). All tso_pools have IBMVNIC_TSO_BUFS
136662306a36Sopenharmony_ci	 *       buffers (see calls init_one_tx_pool() for these).
136762306a36Sopenharmony_ci	 *       For consistency, we use tx_pool->num_buffers and
136862306a36Sopenharmony_ci	 *       tso_pool->num_buffers below.
136962306a36Sopenharmony_ci	 */
137062306a36Sopenharmony_ci	rc = -1;
137162306a36Sopenharmony_ci	for (i = 0; i < num_pools; i++) {
137262306a36Sopenharmony_ci		struct ibmvnic_tx_pool *tso_pool;
137362306a36Sopenharmony_ci		struct ibmvnic_tx_pool *tx_pool;
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_ci		tx_pool = &adapter->tx_pool[i];
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_ci		dev_dbg(dev, "Updating LTB for tx pool %d [%d, %d]\n",
137862306a36Sopenharmony_ci			i, tx_pool->num_buffers, tx_pool->buf_size);
137962306a36Sopenharmony_ci
138062306a36Sopenharmony_ci		rc = alloc_ltb_set(adapter, &tx_pool->ltb_set,
138162306a36Sopenharmony_ci				   tx_pool->num_buffers, tx_pool->buf_size);
138262306a36Sopenharmony_ci		if (rc)
138362306a36Sopenharmony_ci			goto out;
138462306a36Sopenharmony_ci
138562306a36Sopenharmony_ci		tx_pool->consumer_index = 0;
138662306a36Sopenharmony_ci		tx_pool->producer_index = 0;
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_ci		for (j = 0; j < tx_pool->num_buffers; j++)
138962306a36Sopenharmony_ci			tx_pool->free_map[j] = j;
139062306a36Sopenharmony_ci
139162306a36Sopenharmony_ci		tso_pool = &adapter->tso_pool[i];
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci		dev_dbg(dev, "Updating LTB for tso pool %d [%d, %d]\n",
139462306a36Sopenharmony_ci			i, tso_pool->num_buffers, tso_pool->buf_size);
139562306a36Sopenharmony_ci
139662306a36Sopenharmony_ci		rc = alloc_ltb_set(adapter, &tso_pool->ltb_set,
139762306a36Sopenharmony_ci				   tso_pool->num_buffers, tso_pool->buf_size);
139862306a36Sopenharmony_ci		if (rc)
139962306a36Sopenharmony_ci			goto out;
140062306a36Sopenharmony_ci
140162306a36Sopenharmony_ci		tso_pool->consumer_index = 0;
140262306a36Sopenharmony_ci		tso_pool->producer_index = 0;
140362306a36Sopenharmony_ci
140462306a36Sopenharmony_ci		for (j = 0; j < tso_pool->num_buffers; j++)
140562306a36Sopenharmony_ci			tso_pool->free_map[j] = j;
140662306a36Sopenharmony_ci	}
140762306a36Sopenharmony_ci
140862306a36Sopenharmony_ci	return 0;
140962306a36Sopenharmony_ciout_release:
141062306a36Sopenharmony_ci	release_tx_pools(adapter);
141162306a36Sopenharmony_ciout:
141262306a36Sopenharmony_ci	/* We failed to allocate one or more LTBs or map them on the VIOS.
141362306a36Sopenharmony_ci	 * Hold onto the pools and any LTBs that we did allocate/map.
141462306a36Sopenharmony_ci	 */
141562306a36Sopenharmony_ci	return rc;
141662306a36Sopenharmony_ci}
141762306a36Sopenharmony_ci
141862306a36Sopenharmony_cistatic void ibmvnic_napi_enable(struct ibmvnic_adapter *adapter)
141962306a36Sopenharmony_ci{
142062306a36Sopenharmony_ci	int i;
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_ci	if (adapter->napi_enabled)
142362306a36Sopenharmony_ci		return;
142462306a36Sopenharmony_ci
142562306a36Sopenharmony_ci	for (i = 0; i < adapter->req_rx_queues; i++)
142662306a36Sopenharmony_ci		napi_enable(&adapter->napi[i]);
142762306a36Sopenharmony_ci
142862306a36Sopenharmony_ci	adapter->napi_enabled = true;
142962306a36Sopenharmony_ci}
143062306a36Sopenharmony_ci
143162306a36Sopenharmony_cistatic void ibmvnic_napi_disable(struct ibmvnic_adapter *adapter)
143262306a36Sopenharmony_ci{
143362306a36Sopenharmony_ci	int i;
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_ci	if (!adapter->napi_enabled)
143662306a36Sopenharmony_ci		return;
143762306a36Sopenharmony_ci
143862306a36Sopenharmony_ci	for (i = 0; i < adapter->req_rx_queues; i++) {
143962306a36Sopenharmony_ci		netdev_dbg(adapter->netdev, "Disabling napi[%d]\n", i);
144062306a36Sopenharmony_ci		napi_disable(&adapter->napi[i]);
144162306a36Sopenharmony_ci	}
144262306a36Sopenharmony_ci
144362306a36Sopenharmony_ci	adapter->napi_enabled = false;
144462306a36Sopenharmony_ci}
144562306a36Sopenharmony_ci
144662306a36Sopenharmony_cistatic int init_napi(struct ibmvnic_adapter *adapter)
144762306a36Sopenharmony_ci{
144862306a36Sopenharmony_ci	int i;
144962306a36Sopenharmony_ci
145062306a36Sopenharmony_ci	adapter->napi = kcalloc(adapter->req_rx_queues,
145162306a36Sopenharmony_ci				sizeof(struct napi_struct), GFP_KERNEL);
145262306a36Sopenharmony_ci	if (!adapter->napi)
145362306a36Sopenharmony_ci		return -ENOMEM;
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci	for (i = 0; i < adapter->req_rx_queues; i++) {
145662306a36Sopenharmony_ci		netdev_dbg(adapter->netdev, "Adding napi[%d]\n", i);
145762306a36Sopenharmony_ci		netif_napi_add(adapter->netdev, &adapter->napi[i],
145862306a36Sopenharmony_ci			       ibmvnic_poll);
145962306a36Sopenharmony_ci	}
146062306a36Sopenharmony_ci
146162306a36Sopenharmony_ci	adapter->num_active_rx_napi = adapter->req_rx_queues;
146262306a36Sopenharmony_ci	return 0;
146362306a36Sopenharmony_ci}
146462306a36Sopenharmony_ci
146562306a36Sopenharmony_cistatic void release_napi(struct ibmvnic_adapter *adapter)
146662306a36Sopenharmony_ci{
146762306a36Sopenharmony_ci	int i;
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_ci	if (!adapter->napi)
147062306a36Sopenharmony_ci		return;
147162306a36Sopenharmony_ci
147262306a36Sopenharmony_ci	for (i = 0; i < adapter->num_active_rx_napi; i++) {
147362306a36Sopenharmony_ci		netdev_dbg(adapter->netdev, "Releasing napi[%d]\n", i);
147462306a36Sopenharmony_ci		netif_napi_del(&adapter->napi[i]);
147562306a36Sopenharmony_ci	}
147662306a36Sopenharmony_ci
147762306a36Sopenharmony_ci	kfree(adapter->napi);
147862306a36Sopenharmony_ci	adapter->napi = NULL;
147962306a36Sopenharmony_ci	adapter->num_active_rx_napi = 0;
148062306a36Sopenharmony_ci	adapter->napi_enabled = false;
148162306a36Sopenharmony_ci}
148262306a36Sopenharmony_ci
148362306a36Sopenharmony_cistatic const char *adapter_state_to_string(enum vnic_state state)
148462306a36Sopenharmony_ci{
148562306a36Sopenharmony_ci	switch (state) {
148662306a36Sopenharmony_ci	case VNIC_PROBING:
148762306a36Sopenharmony_ci		return "PROBING";
148862306a36Sopenharmony_ci	case VNIC_PROBED:
148962306a36Sopenharmony_ci		return "PROBED";
149062306a36Sopenharmony_ci	case VNIC_OPENING:
149162306a36Sopenharmony_ci		return "OPENING";
149262306a36Sopenharmony_ci	case VNIC_OPEN:
149362306a36Sopenharmony_ci		return "OPEN";
149462306a36Sopenharmony_ci	case VNIC_CLOSING:
149562306a36Sopenharmony_ci		return "CLOSING";
149662306a36Sopenharmony_ci	case VNIC_CLOSED:
149762306a36Sopenharmony_ci		return "CLOSED";
149862306a36Sopenharmony_ci	case VNIC_REMOVING:
149962306a36Sopenharmony_ci		return "REMOVING";
150062306a36Sopenharmony_ci	case VNIC_REMOVED:
150162306a36Sopenharmony_ci		return "REMOVED";
150262306a36Sopenharmony_ci	case VNIC_DOWN:
150362306a36Sopenharmony_ci		return "DOWN";
150462306a36Sopenharmony_ci	}
150562306a36Sopenharmony_ci	return "UNKNOWN";
150662306a36Sopenharmony_ci}
150762306a36Sopenharmony_ci
150862306a36Sopenharmony_cistatic int ibmvnic_login(struct net_device *netdev)
150962306a36Sopenharmony_ci{
151062306a36Sopenharmony_ci	unsigned long flags, timeout = msecs_to_jiffies(20000);
151162306a36Sopenharmony_ci	struct ibmvnic_adapter *adapter = netdev_priv(netdev);
151262306a36Sopenharmony_ci	int retry_count = 0;
151362306a36Sopenharmony_ci	int retries = 10;
151462306a36Sopenharmony_ci	bool retry;
151562306a36Sopenharmony_ci	int rc;
151662306a36Sopenharmony_ci
151762306a36Sopenharmony_ci	do {
151862306a36Sopenharmony_ci		retry = false;
151962306a36Sopenharmony_ci		if (retry_count > retries) {
152062306a36Sopenharmony_ci			netdev_warn(netdev, "Login attempts exceeded\n");
152162306a36Sopenharmony_ci			return -EACCES;
152262306a36Sopenharmony_ci		}
152362306a36Sopenharmony_ci
152462306a36Sopenharmony_ci		adapter->init_done_rc = 0;
152562306a36Sopenharmony_ci		reinit_completion(&adapter->init_done);
152662306a36Sopenharmony_ci		rc = send_login(adapter);
152762306a36Sopenharmony_ci		if (rc)
152862306a36Sopenharmony_ci			return rc;
152962306a36Sopenharmony_ci
153062306a36Sopenharmony_ci		if (!wait_for_completion_timeout(&adapter->init_done,
153162306a36Sopenharmony_ci						 timeout)) {
153262306a36Sopenharmony_ci			netdev_warn(netdev, "Login timed out\n");
153362306a36Sopenharmony_ci			adapter->login_pending = false;
153462306a36Sopenharmony_ci			goto partial_reset;
153562306a36Sopenharmony_ci		}
153662306a36Sopenharmony_ci
153762306a36Sopenharmony_ci		if (adapter->init_done_rc == ABORTED) {
153862306a36Sopenharmony_ci			netdev_warn(netdev, "Login aborted, retrying...\n");
153962306a36Sopenharmony_ci			retry = true;
154062306a36Sopenharmony_ci			adapter->init_done_rc = 0;
154162306a36Sopenharmony_ci			retry_count++;
154262306a36Sopenharmony_ci			/* FW or device may be busy, so
154362306a36Sopenharmony_ci			 * wait a bit before retrying login
154462306a36Sopenharmony_ci			 */
154562306a36Sopenharmony_ci			msleep(500);
154662306a36Sopenharmony_ci		} else if (adapter->init_done_rc == PARTIALSUCCESS) {
154762306a36Sopenharmony_ci			retry_count++;
154862306a36Sopenharmony_ci			release_sub_crqs(adapter, 1);
154962306a36Sopenharmony_ci
155062306a36Sopenharmony_ci			retry = true;
155162306a36Sopenharmony_ci			netdev_dbg(netdev,
155262306a36Sopenharmony_ci				   "Received partial success, retrying...\n");
155362306a36Sopenharmony_ci			adapter->init_done_rc = 0;
155462306a36Sopenharmony_ci			reinit_completion(&adapter->init_done);
155562306a36Sopenharmony_ci			send_query_cap(adapter);
155662306a36Sopenharmony_ci			if (!wait_for_completion_timeout(&adapter->init_done,
155762306a36Sopenharmony_ci							 timeout)) {
155862306a36Sopenharmony_ci				netdev_warn(netdev,
155962306a36Sopenharmony_ci					    "Capabilities query timed out\n");
156062306a36Sopenharmony_ci				return -ETIMEDOUT;
156162306a36Sopenharmony_ci			}
156262306a36Sopenharmony_ci
156362306a36Sopenharmony_ci			rc = init_sub_crqs(adapter);
156462306a36Sopenharmony_ci			if (rc) {
156562306a36Sopenharmony_ci				netdev_warn(netdev,
156662306a36Sopenharmony_ci					    "SCRQ initialization failed\n");
156762306a36Sopenharmony_ci				return rc;
156862306a36Sopenharmony_ci			}
156962306a36Sopenharmony_ci
157062306a36Sopenharmony_ci			rc = init_sub_crq_irqs(adapter);
157162306a36Sopenharmony_ci			if (rc) {
157262306a36Sopenharmony_ci				netdev_warn(netdev,
157362306a36Sopenharmony_ci					    "SCRQ irq initialization failed\n");
157462306a36Sopenharmony_ci				return rc;
157562306a36Sopenharmony_ci			}
157662306a36Sopenharmony_ci		/* Default/timeout error handling, reset and start fresh */
157762306a36Sopenharmony_ci		} else if (adapter->init_done_rc) {
157862306a36Sopenharmony_ci			netdev_warn(netdev, "Adapter login failed, init_done_rc = %d\n",
157962306a36Sopenharmony_ci				    adapter->init_done_rc);
158062306a36Sopenharmony_ci
158162306a36Sopenharmony_cipartial_reset:
158262306a36Sopenharmony_ci			/* adapter login failed, so free any CRQs or sub-CRQs
158362306a36Sopenharmony_ci			 * and register again before attempting to login again.
158462306a36Sopenharmony_ci			 * If we don't do this then the VIOS may think that
158562306a36Sopenharmony_ci			 * we are already logged in and reject any subsequent
158662306a36Sopenharmony_ci			 * attempts
158762306a36Sopenharmony_ci			 */
158862306a36Sopenharmony_ci			netdev_warn(netdev,
158962306a36Sopenharmony_ci				    "Freeing and re-registering CRQs before attempting to login again\n");
159062306a36Sopenharmony_ci			retry = true;
159162306a36Sopenharmony_ci			adapter->init_done_rc = 0;
159262306a36Sopenharmony_ci			release_sub_crqs(adapter, true);
159362306a36Sopenharmony_ci			/* Much of this is similar logic as ibmvnic_probe(),
159462306a36Sopenharmony_ci			 * we are essentially re-initializing communication
159562306a36Sopenharmony_ci			 * with the server. We really should not run any
159662306a36Sopenharmony_ci			 * resets/failovers here because this is already a form
159762306a36Sopenharmony_ci			 * of reset and we do not want parallel resets occurring
159862306a36Sopenharmony_ci			 */
159962306a36Sopenharmony_ci			do {
160062306a36Sopenharmony_ci				reinit_init_done(adapter);
160162306a36Sopenharmony_ci				/* Clear any failovers we got in the previous
160262306a36Sopenharmony_ci				 * pass since we are re-initializing the CRQ
160362306a36Sopenharmony_ci				 */
160462306a36Sopenharmony_ci				adapter->failover_pending = false;
160562306a36Sopenharmony_ci				release_crq_queue(adapter);
160662306a36Sopenharmony_ci				/* If we don't sleep here then we risk an
160762306a36Sopenharmony_ci				 * unnecessary failover event from the VIOS.
160862306a36Sopenharmony_ci				 * This is a known VIOS issue caused by a vnic
160962306a36Sopenharmony_ci				 * device freeing and registering a CRQ too
161062306a36Sopenharmony_ci				 * quickly.
161162306a36Sopenharmony_ci				 */
161262306a36Sopenharmony_ci				msleep(1500);
161362306a36Sopenharmony_ci				/* Avoid any resets, since we are currently
161462306a36Sopenharmony_ci				 * resetting.
161562306a36Sopenharmony_ci				 */
161662306a36Sopenharmony_ci				spin_lock_irqsave(&adapter->rwi_lock, flags);
161762306a36Sopenharmony_ci				flush_reset_queue(adapter);
161862306a36Sopenharmony_ci				spin_unlock_irqrestore(&adapter->rwi_lock,
161962306a36Sopenharmony_ci						       flags);
162062306a36Sopenharmony_ci
162162306a36Sopenharmony_ci				rc = init_crq_queue(adapter);
162262306a36Sopenharmony_ci				if (rc) {
162362306a36Sopenharmony_ci					netdev_err(netdev, "login recovery: init CRQ failed %d\n",
162462306a36Sopenharmony_ci						   rc);
162562306a36Sopenharmony_ci					return -EIO;
162662306a36Sopenharmony_ci				}
162762306a36Sopenharmony_ci
162862306a36Sopenharmony_ci				rc = ibmvnic_reset_init(adapter, false);
162962306a36Sopenharmony_ci				if (rc)
163062306a36Sopenharmony_ci					netdev_err(netdev, "login recovery: Reset init failed %d\n",
163162306a36Sopenharmony_ci						   rc);
163262306a36Sopenharmony_ci				/* IBMVNIC_CRQ_INIT will return EAGAIN if it
163362306a36Sopenharmony_ci				 * fails, since ibmvnic_reset_init will free
163462306a36Sopenharmony_ci				 * irq's in failure, we won't be able to receive
163562306a36Sopenharmony_ci				 * new CRQs so we need to keep trying. probe()
163662306a36Sopenharmony_ci				 * handles this similarly.
163762306a36Sopenharmony_ci				 */
163862306a36Sopenharmony_ci			} while (rc == -EAGAIN && retry_count++ < retries);
163962306a36Sopenharmony_ci		}
164062306a36Sopenharmony_ci	} while (retry);
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_ci	__ibmvnic_set_mac(netdev, adapter->mac_addr);
164362306a36Sopenharmony_ci
164462306a36Sopenharmony_ci	netdev_dbg(netdev, "[S:%s] Login succeeded\n", adapter_state_to_string(adapter->state));
164562306a36Sopenharmony_ci	return 0;
164662306a36Sopenharmony_ci}
164762306a36Sopenharmony_ci
164862306a36Sopenharmony_cistatic void release_login_buffer(struct ibmvnic_adapter *adapter)
164962306a36Sopenharmony_ci{
165062306a36Sopenharmony_ci	if (!adapter->login_buf)
165162306a36Sopenharmony_ci		return;
165262306a36Sopenharmony_ci
165362306a36Sopenharmony_ci	dma_unmap_single(&adapter->vdev->dev, adapter->login_buf_token,
165462306a36Sopenharmony_ci			 adapter->login_buf_sz, DMA_TO_DEVICE);
165562306a36Sopenharmony_ci	kfree(adapter->login_buf);
165662306a36Sopenharmony_ci	adapter->login_buf = NULL;
165762306a36Sopenharmony_ci}
165862306a36Sopenharmony_ci
165962306a36Sopenharmony_cistatic void release_login_rsp_buffer(struct ibmvnic_adapter *adapter)
166062306a36Sopenharmony_ci{
166162306a36Sopenharmony_ci	if (!adapter->login_rsp_buf)
166262306a36Sopenharmony_ci		return;
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_ci	dma_unmap_single(&adapter->vdev->dev, adapter->login_rsp_buf_token,
166562306a36Sopenharmony_ci			 adapter->login_rsp_buf_sz, DMA_FROM_DEVICE);
166662306a36Sopenharmony_ci	kfree(adapter->login_rsp_buf);
166762306a36Sopenharmony_ci	adapter->login_rsp_buf = NULL;
166862306a36Sopenharmony_ci}
166962306a36Sopenharmony_ci
167062306a36Sopenharmony_cistatic void release_resources(struct ibmvnic_adapter *adapter)
167162306a36Sopenharmony_ci{
167262306a36Sopenharmony_ci	release_vpd_data(adapter);
167362306a36Sopenharmony_ci
167462306a36Sopenharmony_ci	release_napi(adapter);
167562306a36Sopenharmony_ci	release_login_buffer(adapter);
167662306a36Sopenharmony_ci	release_login_rsp_buffer(adapter);
167762306a36Sopenharmony_ci}
167862306a36Sopenharmony_ci
167962306a36Sopenharmony_cistatic int set_link_state(struct ibmvnic_adapter *adapter, u8 link_state)
168062306a36Sopenharmony_ci{
168162306a36Sopenharmony_ci	struct net_device *netdev = adapter->netdev;
168262306a36Sopenharmony_ci	unsigned long timeout = msecs_to_jiffies(20000);
168362306a36Sopenharmony_ci	union ibmvnic_crq crq;
168462306a36Sopenharmony_ci	bool resend;
168562306a36Sopenharmony_ci	int rc;
168662306a36Sopenharmony_ci
168762306a36Sopenharmony_ci	netdev_dbg(netdev, "setting link state %d\n", link_state);
168862306a36Sopenharmony_ci
168962306a36Sopenharmony_ci	memset(&crq, 0, sizeof(crq));
169062306a36Sopenharmony_ci	crq.logical_link_state.first = IBMVNIC_CRQ_CMD;
169162306a36Sopenharmony_ci	crq.logical_link_state.cmd = LOGICAL_LINK_STATE;
169262306a36Sopenharmony_ci	crq.logical_link_state.link_state = link_state;
169362306a36Sopenharmony_ci
169462306a36Sopenharmony_ci	do {
169562306a36Sopenharmony_ci		resend = false;
169662306a36Sopenharmony_ci
169762306a36Sopenharmony_ci		reinit_completion(&adapter->init_done);
169862306a36Sopenharmony_ci		rc = ibmvnic_send_crq(adapter, &crq);
169962306a36Sopenharmony_ci		if (rc) {
170062306a36Sopenharmony_ci			netdev_err(netdev, "Failed to set link state\n");
170162306a36Sopenharmony_ci			return rc;
170262306a36Sopenharmony_ci		}
170362306a36Sopenharmony_ci
170462306a36Sopenharmony_ci		if (!wait_for_completion_timeout(&adapter->init_done,
170562306a36Sopenharmony_ci						 timeout)) {
170662306a36Sopenharmony_ci			netdev_err(netdev, "timeout setting link state\n");
170762306a36Sopenharmony_ci			return -ETIMEDOUT;
170862306a36Sopenharmony_ci		}
170962306a36Sopenharmony_ci
171062306a36Sopenharmony_ci		if (adapter->init_done_rc == PARTIALSUCCESS) {
171162306a36Sopenharmony_ci			/* Partuial success, delay and re-send */
171262306a36Sopenharmony_ci			mdelay(1000);
171362306a36Sopenharmony_ci			resend = true;
171462306a36Sopenharmony_ci		} else if (adapter->init_done_rc) {
171562306a36Sopenharmony_ci			netdev_warn(netdev, "Unable to set link state, rc=%d\n",
171662306a36Sopenharmony_ci				    adapter->init_done_rc);
171762306a36Sopenharmony_ci			return adapter->init_done_rc;
171862306a36Sopenharmony_ci		}
171962306a36Sopenharmony_ci	} while (resend);
172062306a36Sopenharmony_ci
172162306a36Sopenharmony_ci	return 0;
172262306a36Sopenharmony_ci}
172362306a36Sopenharmony_ci
172462306a36Sopenharmony_cistatic int set_real_num_queues(struct net_device *netdev)
172562306a36Sopenharmony_ci{
172662306a36Sopenharmony_ci	struct ibmvnic_adapter *adapter = netdev_priv(netdev);
172762306a36Sopenharmony_ci	int rc;
172862306a36Sopenharmony_ci
172962306a36Sopenharmony_ci	netdev_dbg(netdev, "Setting real tx/rx queues (%llx/%llx)\n",
173062306a36Sopenharmony_ci		   adapter->req_tx_queues, adapter->req_rx_queues);
173162306a36Sopenharmony_ci
173262306a36Sopenharmony_ci	rc = netif_set_real_num_tx_queues(netdev, adapter->req_tx_queues);
173362306a36Sopenharmony_ci	if (rc) {
173462306a36Sopenharmony_ci		netdev_err(netdev, "failed to set the number of tx queues\n");
173562306a36Sopenharmony_ci		return rc;
173662306a36Sopenharmony_ci	}
173762306a36Sopenharmony_ci
173862306a36Sopenharmony_ci	rc = netif_set_real_num_rx_queues(netdev, adapter->req_rx_queues);
173962306a36Sopenharmony_ci	if (rc)
174062306a36Sopenharmony_ci		netdev_err(netdev, "failed to set the number of rx queues\n");
174162306a36Sopenharmony_ci
174262306a36Sopenharmony_ci	return rc;
174362306a36Sopenharmony_ci}
174462306a36Sopenharmony_ci
174562306a36Sopenharmony_cistatic int ibmvnic_get_vpd(struct ibmvnic_adapter *adapter)
174662306a36Sopenharmony_ci{
174762306a36Sopenharmony_ci	struct device *dev = &adapter->vdev->dev;
174862306a36Sopenharmony_ci	union ibmvnic_crq crq;
174962306a36Sopenharmony_ci	int len = 0;
175062306a36Sopenharmony_ci	int rc;
175162306a36Sopenharmony_ci
175262306a36Sopenharmony_ci	if (adapter->vpd->buff)
175362306a36Sopenharmony_ci		len = adapter->vpd->len;
175462306a36Sopenharmony_ci
175562306a36Sopenharmony_ci	mutex_lock(&adapter->fw_lock);
175662306a36Sopenharmony_ci	adapter->fw_done_rc = 0;
175762306a36Sopenharmony_ci	reinit_completion(&adapter->fw_done);
175862306a36Sopenharmony_ci
175962306a36Sopenharmony_ci	crq.get_vpd_size.first = IBMVNIC_CRQ_CMD;
176062306a36Sopenharmony_ci	crq.get_vpd_size.cmd = GET_VPD_SIZE;
176162306a36Sopenharmony_ci	rc = ibmvnic_send_crq(adapter, &crq);
176262306a36Sopenharmony_ci	if (rc) {
176362306a36Sopenharmony_ci		mutex_unlock(&adapter->fw_lock);
176462306a36Sopenharmony_ci		return rc;
176562306a36Sopenharmony_ci	}
176662306a36Sopenharmony_ci
176762306a36Sopenharmony_ci	rc = ibmvnic_wait_for_completion(adapter, &adapter->fw_done, 10000);
176862306a36Sopenharmony_ci	if (rc) {
176962306a36Sopenharmony_ci		dev_err(dev, "Could not retrieve VPD size, rc = %d\n", rc);
177062306a36Sopenharmony_ci		mutex_unlock(&adapter->fw_lock);
177162306a36Sopenharmony_ci		return rc;
177262306a36Sopenharmony_ci	}
177362306a36Sopenharmony_ci	mutex_unlock(&adapter->fw_lock);
177462306a36Sopenharmony_ci
177562306a36Sopenharmony_ci	if (!adapter->vpd->len)
177662306a36Sopenharmony_ci		return -ENODATA;
177762306a36Sopenharmony_ci
177862306a36Sopenharmony_ci	if (!adapter->vpd->buff)
177962306a36Sopenharmony_ci		adapter->vpd->buff = kzalloc(adapter->vpd->len, GFP_KERNEL);
178062306a36Sopenharmony_ci	else if (adapter->vpd->len != len)
178162306a36Sopenharmony_ci		adapter->vpd->buff =
178262306a36Sopenharmony_ci			krealloc(adapter->vpd->buff,
178362306a36Sopenharmony_ci				 adapter->vpd->len, GFP_KERNEL);
178462306a36Sopenharmony_ci
178562306a36Sopenharmony_ci	if (!adapter->vpd->buff) {
178662306a36Sopenharmony_ci		dev_err(dev, "Could allocate VPD buffer\n");
178762306a36Sopenharmony_ci		return -ENOMEM;
178862306a36Sopenharmony_ci	}
178962306a36Sopenharmony_ci
179062306a36Sopenharmony_ci	adapter->vpd->dma_addr =
179162306a36Sopenharmony_ci		dma_map_single(dev, adapter->vpd->buff, adapter->vpd->len,
179262306a36Sopenharmony_ci			       DMA_FROM_DEVICE);
179362306a36Sopenharmony_ci	if (dma_mapping_error(dev, adapter->vpd->dma_addr)) {
179462306a36Sopenharmony_ci		dev_err(dev, "Could not map VPD buffer\n");
179562306a36Sopenharmony_ci		kfree(adapter->vpd->buff);
179662306a36Sopenharmony_ci		adapter->vpd->buff = NULL;
179762306a36Sopenharmony_ci		return -ENOMEM;
179862306a36Sopenharmony_ci	}
179962306a36Sopenharmony_ci
180062306a36Sopenharmony_ci	mutex_lock(&adapter->fw_lock);
180162306a36Sopenharmony_ci	adapter->fw_done_rc = 0;
180262306a36Sopenharmony_ci	reinit_completion(&adapter->fw_done);
180362306a36Sopenharmony_ci
180462306a36Sopenharmony_ci	crq.get_vpd.first = IBMVNIC_CRQ_CMD;
180562306a36Sopenharmony_ci	crq.get_vpd.cmd = GET_VPD;
180662306a36Sopenharmony_ci	crq.get_vpd.ioba = cpu_to_be32(adapter->vpd->dma_addr);
180762306a36Sopenharmony_ci	crq.get_vpd.len = cpu_to_be32((u32)adapter->vpd->len);
180862306a36Sopenharmony_ci	rc = ibmvnic_send_crq(adapter, &crq);
180962306a36Sopenharmony_ci	if (rc) {
181062306a36Sopenharmony_ci		kfree(adapter->vpd->buff);
181162306a36Sopenharmony_ci		adapter->vpd->buff = NULL;
181262306a36Sopenharmony_ci		mutex_unlock(&adapter->fw_lock);
181362306a36Sopenharmony_ci		return rc;
181462306a36Sopenharmony_ci	}
181562306a36Sopenharmony_ci
181662306a36Sopenharmony_ci	rc = ibmvnic_wait_for_completion(adapter, &adapter->fw_done, 10000);
181762306a36Sopenharmony_ci	if (rc) {
181862306a36Sopenharmony_ci		dev_err(dev, "Unable to retrieve VPD, rc = %d\n", rc);
181962306a36Sopenharmony_ci		kfree(adapter->vpd->buff);
182062306a36Sopenharmony_ci		adapter->vpd->buff = NULL;
182162306a36Sopenharmony_ci		mutex_unlock(&adapter->fw_lock);
182262306a36Sopenharmony_ci		return rc;
182362306a36Sopenharmony_ci	}
182462306a36Sopenharmony_ci
182562306a36Sopenharmony_ci	mutex_unlock(&adapter->fw_lock);
182662306a36Sopenharmony_ci	return 0;
182762306a36Sopenharmony_ci}
182862306a36Sopenharmony_ci
182962306a36Sopenharmony_cistatic int init_resources(struct ibmvnic_adapter *adapter)
183062306a36Sopenharmony_ci{
183162306a36Sopenharmony_ci	struct net_device *netdev = adapter->netdev;
183262306a36Sopenharmony_ci	int rc;
183362306a36Sopenharmony_ci
183462306a36Sopenharmony_ci	rc = set_real_num_queues(netdev);
183562306a36Sopenharmony_ci	if (rc)
183662306a36Sopenharmony_ci		return rc;
183762306a36Sopenharmony_ci
183862306a36Sopenharmony_ci	adapter->vpd = kzalloc(sizeof(*adapter->vpd), GFP_KERNEL);
183962306a36Sopenharmony_ci	if (!adapter->vpd)
184062306a36Sopenharmony_ci		return -ENOMEM;
184162306a36Sopenharmony_ci
184262306a36Sopenharmony_ci	/* Vital Product Data (VPD) */
184362306a36Sopenharmony_ci	rc = ibmvnic_get_vpd(adapter);
184462306a36Sopenharmony_ci	if (rc) {
184562306a36Sopenharmony_ci		netdev_err(netdev, "failed to initialize Vital Product Data (VPD)\n");
184662306a36Sopenharmony_ci		return rc;
184762306a36Sopenharmony_ci	}
184862306a36Sopenharmony_ci
184962306a36Sopenharmony_ci	rc = init_napi(adapter);
185062306a36Sopenharmony_ci	if (rc)
185162306a36Sopenharmony_ci		return rc;
185262306a36Sopenharmony_ci
185362306a36Sopenharmony_ci	send_query_map(adapter);
185462306a36Sopenharmony_ci
185562306a36Sopenharmony_ci	rc = init_rx_pools(netdev);
185662306a36Sopenharmony_ci	if (rc)
185762306a36Sopenharmony_ci		return rc;
185862306a36Sopenharmony_ci
185962306a36Sopenharmony_ci	rc = init_tx_pools(netdev);
186062306a36Sopenharmony_ci	return rc;
186162306a36Sopenharmony_ci}
186262306a36Sopenharmony_ci
186362306a36Sopenharmony_cistatic int __ibmvnic_open(struct net_device *netdev)
186462306a36Sopenharmony_ci{
186562306a36Sopenharmony_ci	struct ibmvnic_adapter *adapter = netdev_priv(netdev);
186662306a36Sopenharmony_ci	enum vnic_state prev_state = adapter->state;
186762306a36Sopenharmony_ci	int i, rc;
186862306a36Sopenharmony_ci
186962306a36Sopenharmony_ci	adapter->state = VNIC_OPENING;
187062306a36Sopenharmony_ci	replenish_pools(adapter);
187162306a36Sopenharmony_ci	ibmvnic_napi_enable(adapter);
187262306a36Sopenharmony_ci
187362306a36Sopenharmony_ci	/* We're ready to receive frames, enable the sub-crq interrupts and
187462306a36Sopenharmony_ci	 * set the logical link state to up
187562306a36Sopenharmony_ci	 */
187662306a36Sopenharmony_ci	for (i = 0; i < adapter->req_rx_queues; i++) {
187762306a36Sopenharmony_ci		netdev_dbg(netdev, "Enabling rx_scrq[%d] irq\n", i);
187862306a36Sopenharmony_ci		if (prev_state == VNIC_CLOSED)
187962306a36Sopenharmony_ci			enable_irq(adapter->rx_scrq[i]->irq);
188062306a36Sopenharmony_ci		enable_scrq_irq(adapter, adapter->rx_scrq[i]);
188162306a36Sopenharmony_ci	}
188262306a36Sopenharmony_ci
188362306a36Sopenharmony_ci	for (i = 0; i < adapter->req_tx_queues; i++) {
188462306a36Sopenharmony_ci		netdev_dbg(netdev, "Enabling tx_scrq[%d] irq\n", i);
188562306a36Sopenharmony_ci		if (prev_state == VNIC_CLOSED)
188662306a36Sopenharmony_ci			enable_irq(adapter->tx_scrq[i]->irq);
188762306a36Sopenharmony_ci		enable_scrq_irq(adapter, adapter->tx_scrq[i]);
188862306a36Sopenharmony_ci		/* netdev_tx_reset_queue will reset dql stats. During NON_FATAL
188962306a36Sopenharmony_ci		 * resets, don't reset the stats because there could be batched
189062306a36Sopenharmony_ci		 * skb's waiting to be sent. If we reset dql stats, we risk
189162306a36Sopenharmony_ci		 * num_completed being greater than num_queued. This will cause
189262306a36Sopenharmony_ci		 * a BUG_ON in dql_completed().
189362306a36Sopenharmony_ci		 */
189462306a36Sopenharmony_ci		if (adapter->reset_reason != VNIC_RESET_NON_FATAL)
189562306a36Sopenharmony_ci			netdev_tx_reset_queue(netdev_get_tx_queue(netdev, i));
189662306a36Sopenharmony_ci	}
189762306a36Sopenharmony_ci
189862306a36Sopenharmony_ci	rc = set_link_state(adapter, IBMVNIC_LOGICAL_LNK_UP);
189962306a36Sopenharmony_ci	if (rc) {
190062306a36Sopenharmony_ci		ibmvnic_napi_disable(adapter);
190162306a36Sopenharmony_ci		ibmvnic_disable_irqs(adapter);
190262306a36Sopenharmony_ci		return rc;
190362306a36Sopenharmony_ci	}
190462306a36Sopenharmony_ci
190562306a36Sopenharmony_ci	adapter->tx_queues_active = true;
190662306a36Sopenharmony_ci
190762306a36Sopenharmony_ci	/* Since queues were stopped until now, there shouldn't be any
190862306a36Sopenharmony_ci	 * one in ibmvnic_complete_tx() or ibmvnic_xmit() so maybe we
190962306a36Sopenharmony_ci	 * don't need the synchronize_rcu()? Leaving it for consistency
191062306a36Sopenharmony_ci	 * with setting ->tx_queues_active = false.
191162306a36Sopenharmony_ci	 */
191262306a36Sopenharmony_ci	synchronize_rcu();
191362306a36Sopenharmony_ci
191462306a36Sopenharmony_ci	netif_tx_start_all_queues(netdev);
191562306a36Sopenharmony_ci
191662306a36Sopenharmony_ci	if (prev_state == VNIC_CLOSED) {
191762306a36Sopenharmony_ci		for (i = 0; i < adapter->req_rx_queues; i++)
191862306a36Sopenharmony_ci			napi_schedule(&adapter->napi[i]);
191962306a36Sopenharmony_ci	}
192062306a36Sopenharmony_ci
192162306a36Sopenharmony_ci	adapter->state = VNIC_OPEN;
192262306a36Sopenharmony_ci	return rc;
192362306a36Sopenharmony_ci}
192462306a36Sopenharmony_ci
192562306a36Sopenharmony_cistatic int ibmvnic_open(struct net_device *netdev)
192662306a36Sopenharmony_ci{
192762306a36Sopenharmony_ci	struct ibmvnic_adapter *adapter = netdev_priv(netdev);
192862306a36Sopenharmony_ci	int rc;
192962306a36Sopenharmony_ci
193062306a36Sopenharmony_ci	ASSERT_RTNL();
193162306a36Sopenharmony_ci
193262306a36Sopenharmony_ci	/* If device failover is pending or we are about to reset, just set
193362306a36Sopenharmony_ci	 * device state and return. Device operation will be handled by reset
193462306a36Sopenharmony_ci	 * routine.
193562306a36Sopenharmony_ci	 *
193662306a36Sopenharmony_ci	 * It should be safe to overwrite the adapter->state here. Since
193762306a36Sopenharmony_ci	 * we hold the rtnl, either the reset has not actually started or
193862306a36Sopenharmony_ci	 * the rtnl got dropped during the set_link_state() in do_reset().
193962306a36Sopenharmony_ci	 * In the former case, no one else is changing the state (again we
194062306a36Sopenharmony_ci	 * have the rtnl) and in the latter case, do_reset() will detect and
194162306a36Sopenharmony_ci	 * honor our setting below.
194262306a36Sopenharmony_ci	 */
194362306a36Sopenharmony_ci	if (adapter->failover_pending || (test_bit(0, &adapter->resetting))) {
194462306a36Sopenharmony_ci		netdev_dbg(netdev, "[S:%s FOP:%d] Resetting, deferring open\n",
194562306a36Sopenharmony_ci			   adapter_state_to_string(adapter->state),
194662306a36Sopenharmony_ci			   adapter->failover_pending);
194762306a36Sopenharmony_ci		adapter->state = VNIC_OPEN;
194862306a36Sopenharmony_ci		rc = 0;
194962306a36Sopenharmony_ci		goto out;
195062306a36Sopenharmony_ci	}
195162306a36Sopenharmony_ci
195262306a36Sopenharmony_ci	if (adapter->state != VNIC_CLOSED) {
195362306a36Sopenharmony_ci		rc = ibmvnic_login(netdev);
195462306a36Sopenharmony_ci		if (rc)
195562306a36Sopenharmony_ci			goto out;
195662306a36Sopenharmony_ci
195762306a36Sopenharmony_ci		rc = init_resources(adapter);
195862306a36Sopenharmony_ci		if (rc) {
195962306a36Sopenharmony_ci			netdev_err(netdev, "failed to initialize resources\n");
196062306a36Sopenharmony_ci			goto out;
196162306a36Sopenharmony_ci		}
196262306a36Sopenharmony_ci	}
196362306a36Sopenharmony_ci
196462306a36Sopenharmony_ci	rc = __ibmvnic_open(netdev);
196562306a36Sopenharmony_ci
196662306a36Sopenharmony_ciout:
196762306a36Sopenharmony_ci	/* If open failed and there is a pending failover or in-progress reset,
196862306a36Sopenharmony_ci	 * set device state and return. Device operation will be handled by
196962306a36Sopenharmony_ci	 * reset routine. See also comments above regarding rtnl.
197062306a36Sopenharmony_ci	 */
197162306a36Sopenharmony_ci	if (rc &&
197262306a36Sopenharmony_ci	    (adapter->failover_pending || (test_bit(0, &adapter->resetting)))) {
197362306a36Sopenharmony_ci		adapter->state = VNIC_OPEN;
197462306a36Sopenharmony_ci		rc = 0;
197562306a36Sopenharmony_ci	}
197662306a36Sopenharmony_ci
197762306a36Sopenharmony_ci	if (rc) {
197862306a36Sopenharmony_ci		release_resources(adapter);
197962306a36Sopenharmony_ci		release_rx_pools(adapter);
198062306a36Sopenharmony_ci		release_tx_pools(adapter);
198162306a36Sopenharmony_ci	}
198262306a36Sopenharmony_ci
198362306a36Sopenharmony_ci	return rc;
198462306a36Sopenharmony_ci}
198562306a36Sopenharmony_ci
198662306a36Sopenharmony_cistatic void clean_rx_pools(struct ibmvnic_adapter *adapter)
198762306a36Sopenharmony_ci{
198862306a36Sopenharmony_ci	struct ibmvnic_rx_pool *rx_pool;
198962306a36Sopenharmony_ci	struct ibmvnic_rx_buff *rx_buff;
199062306a36Sopenharmony_ci	u64 rx_entries;
199162306a36Sopenharmony_ci	int rx_scrqs;
199262306a36Sopenharmony_ci	int i, j;
199362306a36Sopenharmony_ci
199462306a36Sopenharmony_ci	if (!adapter->rx_pool)
199562306a36Sopenharmony_ci		return;
199662306a36Sopenharmony_ci
199762306a36Sopenharmony_ci	rx_scrqs = adapter->num_active_rx_pools;
199862306a36Sopenharmony_ci	rx_entries = adapter->req_rx_add_entries_per_subcrq;
199962306a36Sopenharmony_ci
200062306a36Sopenharmony_ci	/* Free any remaining skbs in the rx buffer pools */
200162306a36Sopenharmony_ci	for (i = 0; i < rx_scrqs; i++) {
200262306a36Sopenharmony_ci		rx_pool = &adapter->rx_pool[i];
200362306a36Sopenharmony_ci		if (!rx_pool || !rx_pool->rx_buff)
200462306a36Sopenharmony_ci			continue;
200562306a36Sopenharmony_ci
200662306a36Sopenharmony_ci		netdev_dbg(adapter->netdev, "Cleaning rx_pool[%d]\n", i);
200762306a36Sopenharmony_ci		for (j = 0; j < rx_entries; j++) {
200862306a36Sopenharmony_ci			rx_buff = &rx_pool->rx_buff[j];
200962306a36Sopenharmony_ci			if (rx_buff && rx_buff->skb) {
201062306a36Sopenharmony_ci				dev_kfree_skb_any(rx_buff->skb);
201162306a36Sopenharmony_ci				rx_buff->skb = NULL;
201262306a36Sopenharmony_ci			}
201362306a36Sopenharmony_ci		}
201462306a36Sopenharmony_ci	}
201562306a36Sopenharmony_ci}
201662306a36Sopenharmony_ci
201762306a36Sopenharmony_cistatic void clean_one_tx_pool(struct ibmvnic_adapter *adapter,
201862306a36Sopenharmony_ci			      struct ibmvnic_tx_pool *tx_pool)
201962306a36Sopenharmony_ci{
202062306a36Sopenharmony_ci	struct ibmvnic_tx_buff *tx_buff;
202162306a36Sopenharmony_ci	u64 tx_entries;
202262306a36Sopenharmony_ci	int i;
202362306a36Sopenharmony_ci
202462306a36Sopenharmony_ci	if (!tx_pool || !tx_pool->tx_buff)
202562306a36Sopenharmony_ci		return;
202662306a36Sopenharmony_ci
202762306a36Sopenharmony_ci	tx_entries = tx_pool->num_buffers;
202862306a36Sopenharmony_ci
202962306a36Sopenharmony_ci	for (i = 0; i < tx_entries; i++) {
203062306a36Sopenharmony_ci		tx_buff = &tx_pool->tx_buff[i];
203162306a36Sopenharmony_ci		if (tx_buff && tx_buff->skb) {
203262306a36Sopenharmony_ci			dev_kfree_skb_any(tx_buff->skb);
203362306a36Sopenharmony_ci			tx_buff->skb = NULL;
203462306a36Sopenharmony_ci		}
203562306a36Sopenharmony_ci	}
203662306a36Sopenharmony_ci}
203762306a36Sopenharmony_ci
203862306a36Sopenharmony_cistatic void clean_tx_pools(struct ibmvnic_adapter *adapter)
203962306a36Sopenharmony_ci{
204062306a36Sopenharmony_ci	int tx_scrqs;
204162306a36Sopenharmony_ci	int i;
204262306a36Sopenharmony_ci
204362306a36Sopenharmony_ci	if (!adapter->tx_pool || !adapter->tso_pool)
204462306a36Sopenharmony_ci		return;
204562306a36Sopenharmony_ci
204662306a36Sopenharmony_ci	tx_scrqs = adapter->num_active_tx_pools;
204762306a36Sopenharmony_ci
204862306a36Sopenharmony_ci	/* Free any remaining skbs in the tx buffer pools */
204962306a36Sopenharmony_ci	for (i = 0; i < tx_scrqs; i++) {
205062306a36Sopenharmony_ci		netdev_dbg(adapter->netdev, "Cleaning tx_pool[%d]\n", i);
205162306a36Sopenharmony_ci		clean_one_tx_pool(adapter, &adapter->tx_pool[i]);
205262306a36Sopenharmony_ci		clean_one_tx_pool(adapter, &adapter->tso_pool[i]);
205362306a36Sopenharmony_ci	}
205462306a36Sopenharmony_ci}
205562306a36Sopenharmony_ci
205662306a36Sopenharmony_cistatic void ibmvnic_disable_irqs(struct ibmvnic_adapter *adapter)
205762306a36Sopenharmony_ci{
205862306a36Sopenharmony_ci	struct net_device *netdev = adapter->netdev;
205962306a36Sopenharmony_ci	int i;
206062306a36Sopenharmony_ci
206162306a36Sopenharmony_ci	if (adapter->tx_scrq) {
206262306a36Sopenharmony_ci		for (i = 0; i < adapter->req_tx_queues; i++)
206362306a36Sopenharmony_ci			if (adapter->tx_scrq[i]->irq) {
206462306a36Sopenharmony_ci				netdev_dbg(netdev,
206562306a36Sopenharmony_ci					   "Disabling tx_scrq[%d] irq\n", i);
206662306a36Sopenharmony_ci				disable_scrq_irq(adapter, adapter->tx_scrq[i]);
206762306a36Sopenharmony_ci				disable_irq(adapter->tx_scrq[i]->irq);
206862306a36Sopenharmony_ci			}
206962306a36Sopenharmony_ci	}
207062306a36Sopenharmony_ci
207162306a36Sopenharmony_ci	if (adapter->rx_scrq) {
207262306a36Sopenharmony_ci		for (i = 0; i < adapter->req_rx_queues; i++) {
207362306a36Sopenharmony_ci			if (adapter->rx_scrq[i]->irq) {
207462306a36Sopenharmony_ci				netdev_dbg(netdev,
207562306a36Sopenharmony_ci					   "Disabling rx_scrq[%d] irq\n", i);
207662306a36Sopenharmony_ci				disable_scrq_irq(adapter, adapter->rx_scrq[i]);
207762306a36Sopenharmony_ci				disable_irq(adapter->rx_scrq[i]->irq);
207862306a36Sopenharmony_ci			}
207962306a36Sopenharmony_ci		}
208062306a36Sopenharmony_ci	}
208162306a36Sopenharmony_ci}
208262306a36Sopenharmony_ci
208362306a36Sopenharmony_cistatic void ibmvnic_cleanup(struct net_device *netdev)
208462306a36Sopenharmony_ci{
208562306a36Sopenharmony_ci	struct ibmvnic_adapter *adapter = netdev_priv(netdev);
208662306a36Sopenharmony_ci
208762306a36Sopenharmony_ci	/* ensure that transmissions are stopped if called by do_reset */
208862306a36Sopenharmony_ci
208962306a36Sopenharmony_ci	adapter->tx_queues_active = false;
209062306a36Sopenharmony_ci
209162306a36Sopenharmony_ci	/* Ensure complete_tx() and ibmvnic_xmit() see ->tx_queues_active
209262306a36Sopenharmony_ci	 * update so they don't restart a queue after we stop it below.
209362306a36Sopenharmony_ci	 */
209462306a36Sopenharmony_ci	synchronize_rcu();
209562306a36Sopenharmony_ci
209662306a36Sopenharmony_ci	if (test_bit(0, &adapter->resetting))
209762306a36Sopenharmony_ci		netif_tx_disable(netdev);
209862306a36Sopenharmony_ci	else
209962306a36Sopenharmony_ci		netif_tx_stop_all_queues(netdev);
210062306a36Sopenharmony_ci
210162306a36Sopenharmony_ci	ibmvnic_napi_disable(adapter);
210262306a36Sopenharmony_ci	ibmvnic_disable_irqs(adapter);
210362306a36Sopenharmony_ci}
210462306a36Sopenharmony_ci
210562306a36Sopenharmony_cistatic int __ibmvnic_close(struct net_device *netdev)
210662306a36Sopenharmony_ci{
210762306a36Sopenharmony_ci	struct ibmvnic_adapter *adapter = netdev_priv(netdev);
210862306a36Sopenharmony_ci	int rc = 0;
210962306a36Sopenharmony_ci
211062306a36Sopenharmony_ci	adapter->state = VNIC_CLOSING;
211162306a36Sopenharmony_ci	rc = set_link_state(adapter, IBMVNIC_LOGICAL_LNK_DN);
211262306a36Sopenharmony_ci	adapter->state = VNIC_CLOSED;
211362306a36Sopenharmony_ci	return rc;
211462306a36Sopenharmony_ci}
211562306a36Sopenharmony_ci
211662306a36Sopenharmony_cistatic int ibmvnic_close(struct net_device *netdev)
211762306a36Sopenharmony_ci{
211862306a36Sopenharmony_ci	struct ibmvnic_adapter *adapter = netdev_priv(netdev);
211962306a36Sopenharmony_ci	int rc;
212062306a36Sopenharmony_ci
212162306a36Sopenharmony_ci	netdev_dbg(netdev, "[S:%s FOP:%d FRR:%d] Closing\n",
212262306a36Sopenharmony_ci		   adapter_state_to_string(adapter->state),
212362306a36Sopenharmony_ci		   adapter->failover_pending,
212462306a36Sopenharmony_ci		   adapter->force_reset_recovery);
212562306a36Sopenharmony_ci
212662306a36Sopenharmony_ci	/* If device failover is pending, just set device state and return.
212762306a36Sopenharmony_ci	 * Device operation will be handled by reset routine.
212862306a36Sopenharmony_ci	 */
212962306a36Sopenharmony_ci	if (adapter->failover_pending) {
213062306a36Sopenharmony_ci		adapter->state = VNIC_CLOSED;
213162306a36Sopenharmony_ci		return 0;
213262306a36Sopenharmony_ci	}
213362306a36Sopenharmony_ci
213462306a36Sopenharmony_ci	rc = __ibmvnic_close(netdev);
213562306a36Sopenharmony_ci	ibmvnic_cleanup(netdev);
213662306a36Sopenharmony_ci	clean_rx_pools(adapter);
213762306a36Sopenharmony_ci	clean_tx_pools(adapter);
213862306a36Sopenharmony_ci
213962306a36Sopenharmony_ci	return rc;
214062306a36Sopenharmony_ci}
214162306a36Sopenharmony_ci
214262306a36Sopenharmony_ci/**
214362306a36Sopenharmony_ci * build_hdr_data - creates L2/L3/L4 header data buffer
214462306a36Sopenharmony_ci * @hdr_field: bitfield determining needed headers
214562306a36Sopenharmony_ci * @skb: socket buffer
214662306a36Sopenharmony_ci * @hdr_len: array of header lengths
214762306a36Sopenharmony_ci * @hdr_data: buffer to write the header to
214862306a36Sopenharmony_ci *
214962306a36Sopenharmony_ci * Reads hdr_field to determine which headers are needed by firmware.
215062306a36Sopenharmony_ci * Builds a buffer containing these headers.  Saves individual header
215162306a36Sopenharmony_ci * lengths and total buffer length to be used to build descriptors.
215262306a36Sopenharmony_ci */
215362306a36Sopenharmony_cistatic int build_hdr_data(u8 hdr_field, struct sk_buff *skb,
215462306a36Sopenharmony_ci			  int *hdr_len, u8 *hdr_data)
215562306a36Sopenharmony_ci{
215662306a36Sopenharmony_ci	int len = 0;
215762306a36Sopenharmony_ci	u8 *hdr;
215862306a36Sopenharmony_ci
215962306a36Sopenharmony_ci	if (skb_vlan_tagged(skb) && !skb_vlan_tag_present(skb))
216062306a36Sopenharmony_ci		hdr_len[0] = sizeof(struct vlan_ethhdr);
216162306a36Sopenharmony_ci	else
216262306a36Sopenharmony_ci		hdr_len[0] = sizeof(struct ethhdr);
216362306a36Sopenharmony_ci
216462306a36Sopenharmony_ci	if (skb->protocol == htons(ETH_P_IP)) {
216562306a36Sopenharmony_ci		hdr_len[1] = ip_hdr(skb)->ihl * 4;
216662306a36Sopenharmony_ci		if (ip_hdr(skb)->protocol == IPPROTO_TCP)
216762306a36Sopenharmony_ci			hdr_len[2] = tcp_hdrlen(skb);
216862306a36Sopenharmony_ci		else if (ip_hdr(skb)->protocol == IPPROTO_UDP)
216962306a36Sopenharmony_ci			hdr_len[2] = sizeof(struct udphdr);
217062306a36Sopenharmony_ci	} else if (skb->protocol == htons(ETH_P_IPV6)) {
217162306a36Sopenharmony_ci		hdr_len[1] = sizeof(struct ipv6hdr);
217262306a36Sopenharmony_ci		if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP)
217362306a36Sopenharmony_ci			hdr_len[2] = tcp_hdrlen(skb);
217462306a36Sopenharmony_ci		else if (ipv6_hdr(skb)->nexthdr == IPPROTO_UDP)
217562306a36Sopenharmony_ci			hdr_len[2] = sizeof(struct udphdr);
217662306a36Sopenharmony_ci	} else if (skb->protocol == htons(ETH_P_ARP)) {
217762306a36Sopenharmony_ci		hdr_len[1] = arp_hdr_len(skb->dev);
217862306a36Sopenharmony_ci		hdr_len[2] = 0;
217962306a36Sopenharmony_ci	}
218062306a36Sopenharmony_ci
218162306a36Sopenharmony_ci	memset(hdr_data, 0, 120);
218262306a36Sopenharmony_ci	if ((hdr_field >> 6) & 1) {
218362306a36Sopenharmony_ci		hdr = skb_mac_header(skb);
218462306a36Sopenharmony_ci		memcpy(hdr_data, hdr, hdr_len[0]);
218562306a36Sopenharmony_ci		len += hdr_len[0];
218662306a36Sopenharmony_ci	}
218762306a36Sopenharmony_ci
218862306a36Sopenharmony_ci	if ((hdr_field >> 5) & 1) {
218962306a36Sopenharmony_ci		hdr = skb_network_header(skb);
219062306a36Sopenharmony_ci		memcpy(hdr_data + len, hdr, hdr_len[1]);
219162306a36Sopenharmony_ci		len += hdr_len[1];
219262306a36Sopenharmony_ci	}
219362306a36Sopenharmony_ci
219462306a36Sopenharmony_ci	if ((hdr_field >> 4) & 1) {
219562306a36Sopenharmony_ci		hdr = skb_transport_header(skb);
219662306a36Sopenharmony_ci		memcpy(hdr_data + len, hdr, hdr_len[2]);
219762306a36Sopenharmony_ci		len += hdr_len[2];
219862306a36Sopenharmony_ci	}
219962306a36Sopenharmony_ci	return len;
220062306a36Sopenharmony_ci}
220162306a36Sopenharmony_ci
220262306a36Sopenharmony_ci/**
220362306a36Sopenharmony_ci * create_hdr_descs - create header and header extension descriptors
220462306a36Sopenharmony_ci * @hdr_field: bitfield determining needed headers
220562306a36Sopenharmony_ci * @hdr_data: buffer containing header data
220662306a36Sopenharmony_ci * @len: length of data buffer
220762306a36Sopenharmony_ci * @hdr_len: array of individual header lengths
220862306a36Sopenharmony_ci * @scrq_arr: descriptor array
220962306a36Sopenharmony_ci *
221062306a36Sopenharmony_ci * Creates header and, if needed, header extension descriptors and
221162306a36Sopenharmony_ci * places them in a descriptor array, scrq_arr
221262306a36Sopenharmony_ci */
221362306a36Sopenharmony_ci
221462306a36Sopenharmony_cistatic int create_hdr_descs(u8 hdr_field, u8 *hdr_data, int len, int *hdr_len,
221562306a36Sopenharmony_ci			    union sub_crq *scrq_arr)
221662306a36Sopenharmony_ci{
221762306a36Sopenharmony_ci	union sub_crq hdr_desc;
221862306a36Sopenharmony_ci	int tmp_len = len;
221962306a36Sopenharmony_ci	int num_descs = 0;
222062306a36Sopenharmony_ci	u8 *data, *cur;
222162306a36Sopenharmony_ci	int tmp;
222262306a36Sopenharmony_ci
222362306a36Sopenharmony_ci	while (tmp_len > 0) {
222462306a36Sopenharmony_ci		cur = hdr_data + len - tmp_len;
222562306a36Sopenharmony_ci
222662306a36Sopenharmony_ci		memset(&hdr_desc, 0, sizeof(hdr_desc));
222762306a36Sopenharmony_ci		if (cur != hdr_data) {
222862306a36Sopenharmony_ci			data = hdr_desc.hdr_ext.data;
222962306a36Sopenharmony_ci			tmp = tmp_len > 29 ? 29 : tmp_len;
223062306a36Sopenharmony_ci			hdr_desc.hdr_ext.first = IBMVNIC_CRQ_CMD;
223162306a36Sopenharmony_ci			hdr_desc.hdr_ext.type = IBMVNIC_HDR_EXT_DESC;
223262306a36Sopenharmony_ci			hdr_desc.hdr_ext.len = tmp;
223362306a36Sopenharmony_ci		} else {
223462306a36Sopenharmony_ci			data = hdr_desc.hdr.data;
223562306a36Sopenharmony_ci			tmp = tmp_len > 24 ? 24 : tmp_len;
223662306a36Sopenharmony_ci			hdr_desc.hdr.first = IBMVNIC_CRQ_CMD;
223762306a36Sopenharmony_ci			hdr_desc.hdr.type = IBMVNIC_HDR_DESC;
223862306a36Sopenharmony_ci			hdr_desc.hdr.len = tmp;
223962306a36Sopenharmony_ci			hdr_desc.hdr.l2_len = (u8)hdr_len[0];
224062306a36Sopenharmony_ci			hdr_desc.hdr.l3_len = cpu_to_be16((u16)hdr_len[1]);
224162306a36Sopenharmony_ci			hdr_desc.hdr.l4_len = (u8)hdr_len[2];
224262306a36Sopenharmony_ci			hdr_desc.hdr.flag = hdr_field << 1;
224362306a36Sopenharmony_ci		}
224462306a36Sopenharmony_ci		memcpy(data, cur, tmp);
224562306a36Sopenharmony_ci		tmp_len -= tmp;
224662306a36Sopenharmony_ci		*scrq_arr = hdr_desc;
224762306a36Sopenharmony_ci		scrq_arr++;
224862306a36Sopenharmony_ci		num_descs++;
224962306a36Sopenharmony_ci	}
225062306a36Sopenharmony_ci
225162306a36Sopenharmony_ci	return num_descs;
225262306a36Sopenharmony_ci}
225362306a36Sopenharmony_ci
225462306a36Sopenharmony_ci/**
225562306a36Sopenharmony_ci * build_hdr_descs_arr - build a header descriptor array
225662306a36Sopenharmony_ci * @skb: tx socket buffer
225762306a36Sopenharmony_ci * @indir_arr: indirect array
225862306a36Sopenharmony_ci * @num_entries: number of descriptors to be sent
225962306a36Sopenharmony_ci * @hdr_field: bit field determining which headers will be sent
226062306a36Sopenharmony_ci *
226162306a36Sopenharmony_ci * This function will build a TX descriptor array with applicable
226262306a36Sopenharmony_ci * L2/L3/L4 packet header descriptors to be sent by send_subcrq_indirect.
226362306a36Sopenharmony_ci */
226462306a36Sopenharmony_ci
226562306a36Sopenharmony_cistatic void build_hdr_descs_arr(struct sk_buff *skb,
226662306a36Sopenharmony_ci				union sub_crq *indir_arr,
226762306a36Sopenharmony_ci				int *num_entries, u8 hdr_field)
226862306a36Sopenharmony_ci{
226962306a36Sopenharmony_ci	int hdr_len[3] = {0, 0, 0};
227062306a36Sopenharmony_ci	u8 hdr_data[140] = {0};
227162306a36Sopenharmony_ci	int tot_len;
227262306a36Sopenharmony_ci
227362306a36Sopenharmony_ci	tot_len = build_hdr_data(hdr_field, skb, hdr_len,
227462306a36Sopenharmony_ci				 hdr_data);
227562306a36Sopenharmony_ci	*num_entries += create_hdr_descs(hdr_field, hdr_data, tot_len, hdr_len,
227662306a36Sopenharmony_ci					 indir_arr + 1);
227762306a36Sopenharmony_ci}
227862306a36Sopenharmony_ci
227962306a36Sopenharmony_cistatic int ibmvnic_xmit_workarounds(struct sk_buff *skb,
228062306a36Sopenharmony_ci				    struct net_device *netdev)
228162306a36Sopenharmony_ci{
228262306a36Sopenharmony_ci	/* For some backing devices, mishandling of small packets
228362306a36Sopenharmony_ci	 * can result in a loss of connection or TX stall. Device
228462306a36Sopenharmony_ci	 * architects recommend that no packet should be smaller
228562306a36Sopenharmony_ci	 * than the minimum MTU value provided to the driver, so
228662306a36Sopenharmony_ci	 * pad any packets to that length
228762306a36Sopenharmony_ci	 */
228862306a36Sopenharmony_ci	if (skb->len < netdev->min_mtu)
228962306a36Sopenharmony_ci		return skb_put_padto(skb, netdev->min_mtu);
229062306a36Sopenharmony_ci
229162306a36Sopenharmony_ci	return 0;
229262306a36Sopenharmony_ci}
229362306a36Sopenharmony_ci
229462306a36Sopenharmony_cistatic void ibmvnic_tx_scrq_clean_buffer(struct ibmvnic_adapter *adapter,
229562306a36Sopenharmony_ci					 struct ibmvnic_sub_crq_queue *tx_scrq)
229662306a36Sopenharmony_ci{
229762306a36Sopenharmony_ci	struct ibmvnic_ind_xmit_queue *ind_bufp;
229862306a36Sopenharmony_ci	struct ibmvnic_tx_buff *tx_buff;
229962306a36Sopenharmony_ci	struct ibmvnic_tx_pool *tx_pool;
230062306a36Sopenharmony_ci	union sub_crq tx_scrq_entry;
230162306a36Sopenharmony_ci	int queue_num;
230262306a36Sopenharmony_ci	int entries;
230362306a36Sopenharmony_ci	int index;
230462306a36Sopenharmony_ci	int i;
230562306a36Sopenharmony_ci
230662306a36Sopenharmony_ci	ind_bufp = &tx_scrq->ind_buf;
230762306a36Sopenharmony_ci	entries = (u64)ind_bufp->index;
230862306a36Sopenharmony_ci	queue_num = tx_scrq->pool_index;
230962306a36Sopenharmony_ci
231062306a36Sopenharmony_ci	for (i = entries - 1; i >= 0; --i) {
231162306a36Sopenharmony_ci		tx_scrq_entry = ind_bufp->indir_arr[i];
231262306a36Sopenharmony_ci		if (tx_scrq_entry.v1.type != IBMVNIC_TX_DESC)
231362306a36Sopenharmony_ci			continue;
231462306a36Sopenharmony_ci		index = be32_to_cpu(tx_scrq_entry.v1.correlator);
231562306a36Sopenharmony_ci		if (index & IBMVNIC_TSO_POOL_MASK) {
231662306a36Sopenharmony_ci			tx_pool = &adapter->tso_pool[queue_num];
231762306a36Sopenharmony_ci			index &= ~IBMVNIC_TSO_POOL_MASK;
231862306a36Sopenharmony_ci		} else {
231962306a36Sopenharmony_ci			tx_pool = &adapter->tx_pool[queue_num];
232062306a36Sopenharmony_ci		}
232162306a36Sopenharmony_ci		tx_pool->free_map[tx_pool->consumer_index] = index;
232262306a36Sopenharmony_ci		tx_pool->consumer_index = tx_pool->consumer_index == 0 ?
232362306a36Sopenharmony_ci					  tx_pool->num_buffers - 1 :
232462306a36Sopenharmony_ci					  tx_pool->consumer_index - 1;
232562306a36Sopenharmony_ci		tx_buff = &tx_pool->tx_buff[index];
232662306a36Sopenharmony_ci		adapter->netdev->stats.tx_packets--;
232762306a36Sopenharmony_ci		adapter->netdev->stats.tx_bytes -= tx_buff->skb->len;
232862306a36Sopenharmony_ci		adapter->tx_stats_buffers[queue_num].packets--;
232962306a36Sopenharmony_ci		adapter->tx_stats_buffers[queue_num].bytes -=
233062306a36Sopenharmony_ci						tx_buff->skb->len;
233162306a36Sopenharmony_ci		dev_kfree_skb_any(tx_buff->skb);
233262306a36Sopenharmony_ci		tx_buff->skb = NULL;
233362306a36Sopenharmony_ci		adapter->netdev->stats.tx_dropped++;
233462306a36Sopenharmony_ci	}
233562306a36Sopenharmony_ci
233662306a36Sopenharmony_ci	ind_bufp->index = 0;
233762306a36Sopenharmony_ci
233862306a36Sopenharmony_ci	if (atomic_sub_return(entries, &tx_scrq->used) <=
233962306a36Sopenharmony_ci	    (adapter->req_tx_entries_per_subcrq / 2) &&
234062306a36Sopenharmony_ci	    __netif_subqueue_stopped(adapter->netdev, queue_num)) {
234162306a36Sopenharmony_ci		rcu_read_lock();
234262306a36Sopenharmony_ci
234362306a36Sopenharmony_ci		if (adapter->tx_queues_active) {
234462306a36Sopenharmony_ci			netif_wake_subqueue(adapter->netdev, queue_num);
234562306a36Sopenharmony_ci			netdev_dbg(adapter->netdev, "Started queue %d\n",
234662306a36Sopenharmony_ci				   queue_num);
234762306a36Sopenharmony_ci		}
234862306a36Sopenharmony_ci
234962306a36Sopenharmony_ci		rcu_read_unlock();
235062306a36Sopenharmony_ci	}
235162306a36Sopenharmony_ci}
235262306a36Sopenharmony_ci
235362306a36Sopenharmony_cistatic int ibmvnic_tx_scrq_flush(struct ibmvnic_adapter *adapter,
235462306a36Sopenharmony_ci				 struct ibmvnic_sub_crq_queue *tx_scrq)
235562306a36Sopenharmony_ci{
235662306a36Sopenharmony_ci	struct ibmvnic_ind_xmit_queue *ind_bufp;
235762306a36Sopenharmony_ci	u64 dma_addr;
235862306a36Sopenharmony_ci	u64 entries;
235962306a36Sopenharmony_ci	u64 handle;
236062306a36Sopenharmony_ci	int rc;
236162306a36Sopenharmony_ci
236262306a36Sopenharmony_ci	ind_bufp = &tx_scrq->ind_buf;
236362306a36Sopenharmony_ci	dma_addr = (u64)ind_bufp->indir_dma;
236462306a36Sopenharmony_ci	entries = (u64)ind_bufp->index;
236562306a36Sopenharmony_ci	handle = tx_scrq->handle;
236662306a36Sopenharmony_ci
236762306a36Sopenharmony_ci	if (!entries)
236862306a36Sopenharmony_ci		return 0;
236962306a36Sopenharmony_ci	rc = send_subcrq_indirect(adapter, handle, dma_addr, entries);
237062306a36Sopenharmony_ci	if (rc)
237162306a36Sopenharmony_ci		ibmvnic_tx_scrq_clean_buffer(adapter, tx_scrq);
237262306a36Sopenharmony_ci	else
237362306a36Sopenharmony_ci		ind_bufp->index = 0;
237462306a36Sopenharmony_ci	return 0;
237562306a36Sopenharmony_ci}
237662306a36Sopenharmony_ci
237762306a36Sopenharmony_cistatic netdev_tx_t ibmvnic_xmit(struct sk_buff *skb, struct net_device *netdev)
237862306a36Sopenharmony_ci{
237962306a36Sopenharmony_ci	struct ibmvnic_adapter *adapter = netdev_priv(netdev);
238062306a36Sopenharmony_ci	int queue_num = skb_get_queue_mapping(skb);
238162306a36Sopenharmony_ci	u8 *hdrs = (u8 *)&adapter->tx_rx_desc_req;
238262306a36Sopenharmony_ci	struct device *dev = &adapter->vdev->dev;
238362306a36Sopenharmony_ci	struct ibmvnic_ind_xmit_queue *ind_bufp;
238462306a36Sopenharmony_ci	struct ibmvnic_tx_buff *tx_buff = NULL;
238562306a36Sopenharmony_ci	struct ibmvnic_sub_crq_queue *tx_scrq;
238662306a36Sopenharmony_ci	struct ibmvnic_long_term_buff *ltb;
238762306a36Sopenharmony_ci	struct ibmvnic_tx_pool *tx_pool;
238862306a36Sopenharmony_ci	unsigned int tx_send_failed = 0;
238962306a36Sopenharmony_ci	netdev_tx_t ret = NETDEV_TX_OK;
239062306a36Sopenharmony_ci	unsigned int tx_map_failed = 0;
239162306a36Sopenharmony_ci	union sub_crq indir_arr[16];
239262306a36Sopenharmony_ci	unsigned int tx_dropped = 0;
239362306a36Sopenharmony_ci	unsigned int tx_packets = 0;
239462306a36Sopenharmony_ci	unsigned int tx_bytes = 0;
239562306a36Sopenharmony_ci	dma_addr_t data_dma_addr;
239662306a36Sopenharmony_ci	struct netdev_queue *txq;
239762306a36Sopenharmony_ci	unsigned long lpar_rc;
239862306a36Sopenharmony_ci	union sub_crq tx_crq;
239962306a36Sopenharmony_ci	unsigned int offset;
240062306a36Sopenharmony_ci	int num_entries = 1;
240162306a36Sopenharmony_ci	unsigned char *dst;
240262306a36Sopenharmony_ci	int bufidx = 0;
240362306a36Sopenharmony_ci	u8 proto = 0;
240462306a36Sopenharmony_ci
240562306a36Sopenharmony_ci	/* If a reset is in progress, drop the packet since
240662306a36Sopenharmony_ci	 * the scrqs may get torn down. Otherwise use the
240762306a36Sopenharmony_ci	 * rcu to ensure reset waits for us to complete.
240862306a36Sopenharmony_ci	 */
240962306a36Sopenharmony_ci	rcu_read_lock();
241062306a36Sopenharmony_ci	if (!adapter->tx_queues_active) {
241162306a36Sopenharmony_ci		dev_kfree_skb_any(skb);
241262306a36Sopenharmony_ci
241362306a36Sopenharmony_ci		tx_send_failed++;
241462306a36Sopenharmony_ci		tx_dropped++;
241562306a36Sopenharmony_ci		ret = NETDEV_TX_OK;
241662306a36Sopenharmony_ci		goto out;
241762306a36Sopenharmony_ci	}
241862306a36Sopenharmony_ci
241962306a36Sopenharmony_ci	tx_scrq = adapter->tx_scrq[queue_num];
242062306a36Sopenharmony_ci	txq = netdev_get_tx_queue(netdev, queue_num);
242162306a36Sopenharmony_ci	ind_bufp = &tx_scrq->ind_buf;
242262306a36Sopenharmony_ci
242362306a36Sopenharmony_ci	if (ibmvnic_xmit_workarounds(skb, netdev)) {
242462306a36Sopenharmony_ci		tx_dropped++;
242562306a36Sopenharmony_ci		tx_send_failed++;
242662306a36Sopenharmony_ci		ret = NETDEV_TX_OK;
242762306a36Sopenharmony_ci		ibmvnic_tx_scrq_flush(adapter, tx_scrq);
242862306a36Sopenharmony_ci		goto out;
242962306a36Sopenharmony_ci	}
243062306a36Sopenharmony_ci
243162306a36Sopenharmony_ci	if (skb_is_gso(skb))
243262306a36Sopenharmony_ci		tx_pool = &adapter->tso_pool[queue_num];
243362306a36Sopenharmony_ci	else
243462306a36Sopenharmony_ci		tx_pool = &adapter->tx_pool[queue_num];
243562306a36Sopenharmony_ci
243662306a36Sopenharmony_ci	bufidx = tx_pool->free_map[tx_pool->consumer_index];
243762306a36Sopenharmony_ci
243862306a36Sopenharmony_ci	if (bufidx == IBMVNIC_INVALID_MAP) {
243962306a36Sopenharmony_ci		dev_kfree_skb_any(skb);
244062306a36Sopenharmony_ci		tx_send_failed++;
244162306a36Sopenharmony_ci		tx_dropped++;
244262306a36Sopenharmony_ci		ibmvnic_tx_scrq_flush(adapter, tx_scrq);
244362306a36Sopenharmony_ci		ret = NETDEV_TX_OK;
244462306a36Sopenharmony_ci		goto out;
244562306a36Sopenharmony_ci	}
244662306a36Sopenharmony_ci
244762306a36Sopenharmony_ci	tx_pool->free_map[tx_pool->consumer_index] = IBMVNIC_INVALID_MAP;
244862306a36Sopenharmony_ci
244962306a36Sopenharmony_ci	map_txpool_buf_to_ltb(tx_pool, bufidx, &ltb, &offset);
245062306a36Sopenharmony_ci
245162306a36Sopenharmony_ci	dst = ltb->buff + offset;
245262306a36Sopenharmony_ci	memset(dst, 0, tx_pool->buf_size);
245362306a36Sopenharmony_ci	data_dma_addr = ltb->addr + offset;
245462306a36Sopenharmony_ci
245562306a36Sopenharmony_ci	if (skb_shinfo(skb)->nr_frags) {
245662306a36Sopenharmony_ci		int cur, i;
245762306a36Sopenharmony_ci
245862306a36Sopenharmony_ci		/* Copy the head */
245962306a36Sopenharmony_ci		skb_copy_from_linear_data(skb, dst, skb_headlen(skb));
246062306a36Sopenharmony_ci		cur = skb_headlen(skb);
246162306a36Sopenharmony_ci
246262306a36Sopenharmony_ci		/* Copy the frags */
246362306a36Sopenharmony_ci		for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
246462306a36Sopenharmony_ci			const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
246562306a36Sopenharmony_ci
246662306a36Sopenharmony_ci			memcpy(dst + cur, skb_frag_address(frag),
246762306a36Sopenharmony_ci			       skb_frag_size(frag));
246862306a36Sopenharmony_ci			cur += skb_frag_size(frag);
246962306a36Sopenharmony_ci		}
247062306a36Sopenharmony_ci	} else {
247162306a36Sopenharmony_ci		skb_copy_from_linear_data(skb, dst, skb->len);
247262306a36Sopenharmony_ci	}
247362306a36Sopenharmony_ci
247462306a36Sopenharmony_ci	/* post changes to long_term_buff *dst before VIOS accessing it */
247562306a36Sopenharmony_ci	dma_wmb();
247662306a36Sopenharmony_ci
247762306a36Sopenharmony_ci	tx_pool->consumer_index =
247862306a36Sopenharmony_ci	    (tx_pool->consumer_index + 1) % tx_pool->num_buffers;
247962306a36Sopenharmony_ci
248062306a36Sopenharmony_ci	tx_buff = &tx_pool->tx_buff[bufidx];
248162306a36Sopenharmony_ci	tx_buff->skb = skb;
248262306a36Sopenharmony_ci	tx_buff->index = bufidx;
248362306a36Sopenharmony_ci	tx_buff->pool_index = queue_num;
248462306a36Sopenharmony_ci
248562306a36Sopenharmony_ci	memset(&tx_crq, 0, sizeof(tx_crq));
248662306a36Sopenharmony_ci	tx_crq.v1.first = IBMVNIC_CRQ_CMD;
248762306a36Sopenharmony_ci	tx_crq.v1.type = IBMVNIC_TX_DESC;
248862306a36Sopenharmony_ci	tx_crq.v1.n_crq_elem = 1;
248962306a36Sopenharmony_ci	tx_crq.v1.n_sge = 1;
249062306a36Sopenharmony_ci	tx_crq.v1.flags1 = IBMVNIC_TX_COMP_NEEDED;
249162306a36Sopenharmony_ci
249262306a36Sopenharmony_ci	if (skb_is_gso(skb))
249362306a36Sopenharmony_ci		tx_crq.v1.correlator =
249462306a36Sopenharmony_ci			cpu_to_be32(bufidx | IBMVNIC_TSO_POOL_MASK);
249562306a36Sopenharmony_ci	else
249662306a36Sopenharmony_ci		tx_crq.v1.correlator = cpu_to_be32(bufidx);
249762306a36Sopenharmony_ci	tx_crq.v1.dma_reg = cpu_to_be16(ltb->map_id);
249862306a36Sopenharmony_ci	tx_crq.v1.sge_len = cpu_to_be32(skb->len);
249962306a36Sopenharmony_ci	tx_crq.v1.ioba = cpu_to_be64(data_dma_addr);
250062306a36Sopenharmony_ci
250162306a36Sopenharmony_ci	if (adapter->vlan_header_insertion && skb_vlan_tag_present(skb)) {
250262306a36Sopenharmony_ci		tx_crq.v1.flags2 |= IBMVNIC_TX_VLAN_INSERT;
250362306a36Sopenharmony_ci		tx_crq.v1.vlan_id = cpu_to_be16(skb->vlan_tci);
250462306a36Sopenharmony_ci	}
250562306a36Sopenharmony_ci
250662306a36Sopenharmony_ci	if (skb->protocol == htons(ETH_P_IP)) {
250762306a36Sopenharmony_ci		tx_crq.v1.flags1 |= IBMVNIC_TX_PROT_IPV4;
250862306a36Sopenharmony_ci		proto = ip_hdr(skb)->protocol;
250962306a36Sopenharmony_ci	} else if (skb->protocol == htons(ETH_P_IPV6)) {
251062306a36Sopenharmony_ci		tx_crq.v1.flags1 |= IBMVNIC_TX_PROT_IPV6;
251162306a36Sopenharmony_ci		proto = ipv6_hdr(skb)->nexthdr;
251262306a36Sopenharmony_ci	}
251362306a36Sopenharmony_ci
251462306a36Sopenharmony_ci	if (proto == IPPROTO_TCP)
251562306a36Sopenharmony_ci		tx_crq.v1.flags1 |= IBMVNIC_TX_PROT_TCP;
251662306a36Sopenharmony_ci	else if (proto == IPPROTO_UDP)
251762306a36Sopenharmony_ci		tx_crq.v1.flags1 |= IBMVNIC_TX_PROT_UDP;
251862306a36Sopenharmony_ci
251962306a36Sopenharmony_ci	if (skb->ip_summed == CHECKSUM_PARTIAL) {
252062306a36Sopenharmony_ci		tx_crq.v1.flags1 |= IBMVNIC_TX_CHKSUM_OFFLOAD;
252162306a36Sopenharmony_ci		hdrs += 2;
252262306a36Sopenharmony_ci	}
252362306a36Sopenharmony_ci	if (skb_is_gso(skb)) {
252462306a36Sopenharmony_ci		tx_crq.v1.flags1 |= IBMVNIC_TX_LSO;
252562306a36Sopenharmony_ci		tx_crq.v1.mss = cpu_to_be16(skb_shinfo(skb)->gso_size);
252662306a36Sopenharmony_ci		hdrs += 2;
252762306a36Sopenharmony_ci	}
252862306a36Sopenharmony_ci
252962306a36Sopenharmony_ci	if ((*hdrs >> 7) & 1)
253062306a36Sopenharmony_ci		build_hdr_descs_arr(skb, indir_arr, &num_entries, *hdrs);
253162306a36Sopenharmony_ci
253262306a36Sopenharmony_ci	tx_crq.v1.n_crq_elem = num_entries;
253362306a36Sopenharmony_ci	tx_buff->num_entries = num_entries;
253462306a36Sopenharmony_ci	/* flush buffer if current entry can not fit */
253562306a36Sopenharmony_ci	if (num_entries + ind_bufp->index > IBMVNIC_MAX_IND_DESCS) {
253662306a36Sopenharmony_ci		lpar_rc = ibmvnic_tx_scrq_flush(adapter, tx_scrq);
253762306a36Sopenharmony_ci		if (lpar_rc != H_SUCCESS)
253862306a36Sopenharmony_ci			goto tx_flush_err;
253962306a36Sopenharmony_ci	}
254062306a36Sopenharmony_ci
254162306a36Sopenharmony_ci	indir_arr[0] = tx_crq;
254262306a36Sopenharmony_ci	memcpy(&ind_bufp->indir_arr[ind_bufp->index], &indir_arr[0],
254362306a36Sopenharmony_ci	       num_entries * sizeof(struct ibmvnic_generic_scrq));
254462306a36Sopenharmony_ci	ind_bufp->index += num_entries;
254562306a36Sopenharmony_ci	if (__netdev_tx_sent_queue(txq, skb->len,
254662306a36Sopenharmony_ci				   netdev_xmit_more() &&
254762306a36Sopenharmony_ci				   ind_bufp->index < IBMVNIC_MAX_IND_DESCS)) {
254862306a36Sopenharmony_ci		lpar_rc = ibmvnic_tx_scrq_flush(adapter, tx_scrq);
254962306a36Sopenharmony_ci		if (lpar_rc != H_SUCCESS)
255062306a36Sopenharmony_ci			goto tx_err;
255162306a36Sopenharmony_ci	}
255262306a36Sopenharmony_ci
255362306a36Sopenharmony_ci	if (atomic_add_return(num_entries, &tx_scrq->used)
255462306a36Sopenharmony_ci					>= adapter->req_tx_entries_per_subcrq) {
255562306a36Sopenharmony_ci		netdev_dbg(netdev, "Stopping queue %d\n", queue_num);
255662306a36Sopenharmony_ci		netif_stop_subqueue(netdev, queue_num);
255762306a36Sopenharmony_ci	}
255862306a36Sopenharmony_ci
255962306a36Sopenharmony_ci	tx_packets++;
256062306a36Sopenharmony_ci	tx_bytes += skb->len;
256162306a36Sopenharmony_ci	txq_trans_cond_update(txq);
256262306a36Sopenharmony_ci	ret = NETDEV_TX_OK;
256362306a36Sopenharmony_ci	goto out;
256462306a36Sopenharmony_ci
256562306a36Sopenharmony_citx_flush_err:
256662306a36Sopenharmony_ci	dev_kfree_skb_any(skb);
256762306a36Sopenharmony_ci	tx_buff->skb = NULL;
256862306a36Sopenharmony_ci	tx_pool->consumer_index = tx_pool->consumer_index == 0 ?
256962306a36Sopenharmony_ci				  tx_pool->num_buffers - 1 :
257062306a36Sopenharmony_ci				  tx_pool->consumer_index - 1;
257162306a36Sopenharmony_ci	tx_dropped++;
257262306a36Sopenharmony_citx_err:
257362306a36Sopenharmony_ci	if (lpar_rc != H_CLOSED && lpar_rc != H_PARAMETER)
257462306a36Sopenharmony_ci		dev_err_ratelimited(dev, "tx: send failed\n");
257562306a36Sopenharmony_ci
257662306a36Sopenharmony_ci	if (lpar_rc == H_CLOSED || adapter->failover_pending) {
257762306a36Sopenharmony_ci		/* Disable TX and report carrier off if queue is closed
257862306a36Sopenharmony_ci		 * or pending failover.
257962306a36Sopenharmony_ci		 * Firmware guarantees that a signal will be sent to the
258062306a36Sopenharmony_ci		 * driver, triggering a reset or some other action.
258162306a36Sopenharmony_ci		 */
258262306a36Sopenharmony_ci		netif_tx_stop_all_queues(netdev);
258362306a36Sopenharmony_ci		netif_carrier_off(netdev);
258462306a36Sopenharmony_ci	}
258562306a36Sopenharmony_ciout:
258662306a36Sopenharmony_ci	rcu_read_unlock();
258762306a36Sopenharmony_ci	netdev->stats.tx_dropped += tx_dropped;
258862306a36Sopenharmony_ci	netdev->stats.tx_bytes += tx_bytes;
258962306a36Sopenharmony_ci	netdev->stats.tx_packets += tx_packets;
259062306a36Sopenharmony_ci	adapter->tx_send_failed += tx_send_failed;
259162306a36Sopenharmony_ci	adapter->tx_map_failed += tx_map_failed;
259262306a36Sopenharmony_ci	adapter->tx_stats_buffers[queue_num].packets += tx_packets;
259362306a36Sopenharmony_ci	adapter->tx_stats_buffers[queue_num].bytes += tx_bytes;
259462306a36Sopenharmony_ci	adapter->tx_stats_buffers[queue_num].dropped_packets += tx_dropped;
259562306a36Sopenharmony_ci
259662306a36Sopenharmony_ci	return ret;
259762306a36Sopenharmony_ci}
259862306a36Sopenharmony_ci
259962306a36Sopenharmony_cistatic void ibmvnic_set_multi(struct net_device *netdev)
260062306a36Sopenharmony_ci{
260162306a36Sopenharmony_ci	struct ibmvnic_adapter *adapter = netdev_priv(netdev);
260262306a36Sopenharmony_ci	struct netdev_hw_addr *ha;
260362306a36Sopenharmony_ci	union ibmvnic_crq crq;
260462306a36Sopenharmony_ci
260562306a36Sopenharmony_ci	memset(&crq, 0, sizeof(crq));
260662306a36Sopenharmony_ci	crq.request_capability.first = IBMVNIC_CRQ_CMD;
260762306a36Sopenharmony_ci	crq.request_capability.cmd = REQUEST_CAPABILITY;
260862306a36Sopenharmony_ci
260962306a36Sopenharmony_ci	if (netdev->flags & IFF_PROMISC) {
261062306a36Sopenharmony_ci		if (!adapter->promisc_supported)
261162306a36Sopenharmony_ci			return;
261262306a36Sopenharmony_ci	} else {
261362306a36Sopenharmony_ci		if (netdev->flags & IFF_ALLMULTI) {
261462306a36Sopenharmony_ci			/* Accept all multicast */
261562306a36Sopenharmony_ci			memset(&crq, 0, sizeof(crq));
261662306a36Sopenharmony_ci			crq.multicast_ctrl.first = IBMVNIC_CRQ_CMD;
261762306a36Sopenharmony_ci			crq.multicast_ctrl.cmd = MULTICAST_CTRL;
261862306a36Sopenharmony_ci			crq.multicast_ctrl.flags = IBMVNIC_ENABLE_ALL;
261962306a36Sopenharmony_ci			ibmvnic_send_crq(adapter, &crq);
262062306a36Sopenharmony_ci		} else if (netdev_mc_empty(netdev)) {
262162306a36Sopenharmony_ci			/* Reject all multicast */
262262306a36Sopenharmony_ci			memset(&crq, 0, sizeof(crq));
262362306a36Sopenharmony_ci			crq.multicast_ctrl.first = IBMVNIC_CRQ_CMD;
262462306a36Sopenharmony_ci			crq.multicast_ctrl.cmd = MULTICAST_CTRL;
262562306a36Sopenharmony_ci			crq.multicast_ctrl.flags = IBMVNIC_DISABLE_ALL;
262662306a36Sopenharmony_ci			ibmvnic_send_crq(adapter, &crq);
262762306a36Sopenharmony_ci		} else {
262862306a36Sopenharmony_ci			/* Accept one or more multicast(s) */
262962306a36Sopenharmony_ci			netdev_for_each_mc_addr(ha, netdev) {
263062306a36Sopenharmony_ci				memset(&crq, 0, sizeof(crq));
263162306a36Sopenharmony_ci				crq.multicast_ctrl.first = IBMVNIC_CRQ_CMD;
263262306a36Sopenharmony_ci				crq.multicast_ctrl.cmd = MULTICAST_CTRL;
263362306a36Sopenharmony_ci				crq.multicast_ctrl.flags = IBMVNIC_ENABLE_MC;
263462306a36Sopenharmony_ci				ether_addr_copy(&crq.multicast_ctrl.mac_addr[0],
263562306a36Sopenharmony_ci						ha->addr);
263662306a36Sopenharmony_ci				ibmvnic_send_crq(adapter, &crq);
263762306a36Sopenharmony_ci			}
263862306a36Sopenharmony_ci		}
263962306a36Sopenharmony_ci	}
264062306a36Sopenharmony_ci}
264162306a36Sopenharmony_ci
264262306a36Sopenharmony_cistatic int __ibmvnic_set_mac(struct net_device *netdev, u8 *dev_addr)
264362306a36Sopenharmony_ci{
264462306a36Sopenharmony_ci	struct ibmvnic_adapter *adapter = netdev_priv(netdev);
264562306a36Sopenharmony_ci	union ibmvnic_crq crq;
264662306a36Sopenharmony_ci	int rc;
264762306a36Sopenharmony_ci
264862306a36Sopenharmony_ci	if (!is_valid_ether_addr(dev_addr)) {
264962306a36Sopenharmony_ci		rc = -EADDRNOTAVAIL;
265062306a36Sopenharmony_ci		goto err;
265162306a36Sopenharmony_ci	}
265262306a36Sopenharmony_ci
265362306a36Sopenharmony_ci	memset(&crq, 0, sizeof(crq));
265462306a36Sopenharmony_ci	crq.change_mac_addr.first = IBMVNIC_CRQ_CMD;
265562306a36Sopenharmony_ci	crq.change_mac_addr.cmd = CHANGE_MAC_ADDR;
265662306a36Sopenharmony_ci	ether_addr_copy(&crq.change_mac_addr.mac_addr[0], dev_addr);
265762306a36Sopenharmony_ci
265862306a36Sopenharmony_ci	mutex_lock(&adapter->fw_lock);
265962306a36Sopenharmony_ci	adapter->fw_done_rc = 0;
266062306a36Sopenharmony_ci	reinit_completion(&adapter->fw_done);
266162306a36Sopenharmony_ci
266262306a36Sopenharmony_ci	rc = ibmvnic_send_crq(adapter, &crq);
266362306a36Sopenharmony_ci	if (rc) {
266462306a36Sopenharmony_ci		rc = -EIO;
266562306a36Sopenharmony_ci		mutex_unlock(&adapter->fw_lock);
266662306a36Sopenharmony_ci		goto err;
266762306a36Sopenharmony_ci	}
266862306a36Sopenharmony_ci
266962306a36Sopenharmony_ci	rc = ibmvnic_wait_for_completion(adapter, &adapter->fw_done, 10000);
267062306a36Sopenharmony_ci	/* netdev->dev_addr is changed in handle_change_mac_rsp function */
267162306a36Sopenharmony_ci	if (rc || adapter->fw_done_rc) {
267262306a36Sopenharmony_ci		rc = -EIO;
267362306a36Sopenharmony_ci		mutex_unlock(&adapter->fw_lock);
267462306a36Sopenharmony_ci		goto err;
267562306a36Sopenharmony_ci	}
267662306a36Sopenharmony_ci	mutex_unlock(&adapter->fw_lock);
267762306a36Sopenharmony_ci	return 0;
267862306a36Sopenharmony_cierr:
267962306a36Sopenharmony_ci	ether_addr_copy(adapter->mac_addr, netdev->dev_addr);
268062306a36Sopenharmony_ci	return rc;
268162306a36Sopenharmony_ci}
268262306a36Sopenharmony_ci
268362306a36Sopenharmony_cistatic int ibmvnic_set_mac(struct net_device *netdev, void *p)
268462306a36Sopenharmony_ci{
268562306a36Sopenharmony_ci	struct ibmvnic_adapter *adapter = netdev_priv(netdev);
268662306a36Sopenharmony_ci	struct sockaddr *addr = p;
268762306a36Sopenharmony_ci	int rc;
268862306a36Sopenharmony_ci
268962306a36Sopenharmony_ci	rc = 0;
269062306a36Sopenharmony_ci	if (!is_valid_ether_addr(addr->sa_data))
269162306a36Sopenharmony_ci		return -EADDRNOTAVAIL;
269262306a36Sopenharmony_ci
269362306a36Sopenharmony_ci	ether_addr_copy(adapter->mac_addr, addr->sa_data);
269462306a36Sopenharmony_ci	if (adapter->state != VNIC_PROBED)
269562306a36Sopenharmony_ci		rc = __ibmvnic_set_mac(netdev, addr->sa_data);
269662306a36Sopenharmony_ci
269762306a36Sopenharmony_ci	return rc;
269862306a36Sopenharmony_ci}
269962306a36Sopenharmony_ci
270062306a36Sopenharmony_cistatic const char *reset_reason_to_string(enum ibmvnic_reset_reason reason)
270162306a36Sopenharmony_ci{
270262306a36Sopenharmony_ci	switch (reason) {
270362306a36Sopenharmony_ci	case VNIC_RESET_FAILOVER:
270462306a36Sopenharmony_ci		return "FAILOVER";
270562306a36Sopenharmony_ci	case VNIC_RESET_MOBILITY:
270662306a36Sopenharmony_ci		return "MOBILITY";
270762306a36Sopenharmony_ci	case VNIC_RESET_FATAL:
270862306a36Sopenharmony_ci		return "FATAL";
270962306a36Sopenharmony_ci	case VNIC_RESET_NON_FATAL:
271062306a36Sopenharmony_ci		return "NON_FATAL";
271162306a36Sopenharmony_ci	case VNIC_RESET_TIMEOUT:
271262306a36Sopenharmony_ci		return "TIMEOUT";
271362306a36Sopenharmony_ci	case VNIC_RESET_CHANGE_PARAM:
271462306a36Sopenharmony_ci		return "CHANGE_PARAM";
271562306a36Sopenharmony_ci	case VNIC_RESET_PASSIVE_INIT:
271662306a36Sopenharmony_ci		return "PASSIVE_INIT";
271762306a36Sopenharmony_ci	}
271862306a36Sopenharmony_ci	return "UNKNOWN";
271962306a36Sopenharmony_ci}
272062306a36Sopenharmony_ci
272162306a36Sopenharmony_ci/*
272262306a36Sopenharmony_ci * Initialize the init_done completion and return code values. We
272362306a36Sopenharmony_ci * can get a transport event just after registering the CRQ and the
272462306a36Sopenharmony_ci * tasklet will use this to communicate the transport event. To ensure
272562306a36Sopenharmony_ci * we don't miss the notification/error, initialize these _before_
272662306a36Sopenharmony_ci * regisering the CRQ.
272762306a36Sopenharmony_ci */
272862306a36Sopenharmony_cistatic inline void reinit_init_done(struct ibmvnic_adapter *adapter)
272962306a36Sopenharmony_ci{
273062306a36Sopenharmony_ci	reinit_completion(&adapter->init_done);
273162306a36Sopenharmony_ci	adapter->init_done_rc = 0;
273262306a36Sopenharmony_ci}
273362306a36Sopenharmony_ci
273462306a36Sopenharmony_ci/*
273562306a36Sopenharmony_ci * do_reset returns zero if we are able to keep processing reset events, or
273662306a36Sopenharmony_ci * non-zero if we hit a fatal error and must halt.
273762306a36Sopenharmony_ci */
273862306a36Sopenharmony_cistatic int do_reset(struct ibmvnic_adapter *adapter,
273962306a36Sopenharmony_ci		    struct ibmvnic_rwi *rwi, u32 reset_state)
274062306a36Sopenharmony_ci{
274162306a36Sopenharmony_ci	struct net_device *netdev = adapter->netdev;
274262306a36Sopenharmony_ci	u64 old_num_rx_queues, old_num_tx_queues;
274362306a36Sopenharmony_ci	u64 old_num_rx_slots, old_num_tx_slots;
274462306a36Sopenharmony_ci	int rc;
274562306a36Sopenharmony_ci
274662306a36Sopenharmony_ci	netdev_dbg(adapter->netdev,
274762306a36Sopenharmony_ci		   "[S:%s FOP:%d] Reset reason: %s, reset_state: %s\n",
274862306a36Sopenharmony_ci		   adapter_state_to_string(adapter->state),
274962306a36Sopenharmony_ci		   adapter->failover_pending,
275062306a36Sopenharmony_ci		   reset_reason_to_string(rwi->reset_reason),
275162306a36Sopenharmony_ci		   adapter_state_to_string(reset_state));
275262306a36Sopenharmony_ci
275362306a36Sopenharmony_ci	adapter->reset_reason = rwi->reset_reason;
275462306a36Sopenharmony_ci	/* requestor of VNIC_RESET_CHANGE_PARAM already has the rtnl lock */
275562306a36Sopenharmony_ci	if (!(adapter->reset_reason == VNIC_RESET_CHANGE_PARAM))
275662306a36Sopenharmony_ci		rtnl_lock();
275762306a36Sopenharmony_ci
275862306a36Sopenharmony_ci	/* Now that we have the rtnl lock, clear any pending failover.
275962306a36Sopenharmony_ci	 * This will ensure ibmvnic_open() has either completed or will
276062306a36Sopenharmony_ci	 * block until failover is complete.
276162306a36Sopenharmony_ci	 */
276262306a36Sopenharmony_ci	if (rwi->reset_reason == VNIC_RESET_FAILOVER)
276362306a36Sopenharmony_ci		adapter->failover_pending = false;
276462306a36Sopenharmony_ci
276562306a36Sopenharmony_ci	/* read the state and check (again) after getting rtnl */
276662306a36Sopenharmony_ci	reset_state = adapter->state;
276762306a36Sopenharmony_ci
276862306a36Sopenharmony_ci	if (reset_state == VNIC_REMOVING || reset_state == VNIC_REMOVED) {
276962306a36Sopenharmony_ci		rc = -EBUSY;
277062306a36Sopenharmony_ci		goto out;
277162306a36Sopenharmony_ci	}
277262306a36Sopenharmony_ci
277362306a36Sopenharmony_ci	netif_carrier_off(netdev);
277462306a36Sopenharmony_ci
277562306a36Sopenharmony_ci	old_num_rx_queues = adapter->req_rx_queues;
277662306a36Sopenharmony_ci	old_num_tx_queues = adapter->req_tx_queues;
277762306a36Sopenharmony_ci	old_num_rx_slots = adapter->req_rx_add_entries_per_subcrq;
277862306a36Sopenharmony_ci	old_num_tx_slots = adapter->req_tx_entries_per_subcrq;
277962306a36Sopenharmony_ci
278062306a36Sopenharmony_ci	ibmvnic_cleanup(netdev);
278162306a36Sopenharmony_ci
278262306a36Sopenharmony_ci	if (reset_state == VNIC_OPEN &&
278362306a36Sopenharmony_ci	    adapter->reset_reason != VNIC_RESET_MOBILITY &&
278462306a36Sopenharmony_ci	    adapter->reset_reason != VNIC_RESET_FAILOVER) {
278562306a36Sopenharmony_ci		if (adapter->reset_reason == VNIC_RESET_CHANGE_PARAM) {
278662306a36Sopenharmony_ci			rc = __ibmvnic_close(netdev);
278762306a36Sopenharmony_ci			if (rc)
278862306a36Sopenharmony_ci				goto out;
278962306a36Sopenharmony_ci		} else {
279062306a36Sopenharmony_ci			adapter->state = VNIC_CLOSING;
279162306a36Sopenharmony_ci
279262306a36Sopenharmony_ci			/* Release the RTNL lock before link state change and
279362306a36Sopenharmony_ci			 * re-acquire after the link state change to allow
279462306a36Sopenharmony_ci			 * linkwatch_event to grab the RTNL lock and run during
279562306a36Sopenharmony_ci			 * a reset.
279662306a36Sopenharmony_ci			 */
279762306a36Sopenharmony_ci			rtnl_unlock();
279862306a36Sopenharmony_ci			rc = set_link_state(adapter, IBMVNIC_LOGICAL_LNK_DN);
279962306a36Sopenharmony_ci			rtnl_lock();
280062306a36Sopenharmony_ci			if (rc)
280162306a36Sopenharmony_ci				goto out;
280262306a36Sopenharmony_ci
280362306a36Sopenharmony_ci			if (adapter->state == VNIC_OPEN) {
280462306a36Sopenharmony_ci				/* When we dropped rtnl, ibmvnic_open() got
280562306a36Sopenharmony_ci				 * it and noticed that we are resetting and
280662306a36Sopenharmony_ci				 * set the adapter state to OPEN. Update our
280762306a36Sopenharmony_ci				 * new "target" state, and resume the reset
280862306a36Sopenharmony_ci				 * from VNIC_CLOSING state.
280962306a36Sopenharmony_ci				 */
281062306a36Sopenharmony_ci				netdev_dbg(netdev,
281162306a36Sopenharmony_ci					   "Open changed state from %s, updating.\n",
281262306a36Sopenharmony_ci					   adapter_state_to_string(reset_state));
281362306a36Sopenharmony_ci				reset_state = VNIC_OPEN;
281462306a36Sopenharmony_ci				adapter->state = VNIC_CLOSING;
281562306a36Sopenharmony_ci			}
281662306a36Sopenharmony_ci
281762306a36Sopenharmony_ci			if (adapter->state != VNIC_CLOSING) {
281862306a36Sopenharmony_ci				/* If someone else changed the adapter state
281962306a36Sopenharmony_ci				 * when we dropped the rtnl, fail the reset
282062306a36Sopenharmony_ci				 */
282162306a36Sopenharmony_ci				rc = -EAGAIN;
282262306a36Sopenharmony_ci				goto out;
282362306a36Sopenharmony_ci			}
282462306a36Sopenharmony_ci			adapter->state = VNIC_CLOSED;
282562306a36Sopenharmony_ci		}
282662306a36Sopenharmony_ci	}
282762306a36Sopenharmony_ci
282862306a36Sopenharmony_ci	if (adapter->reset_reason == VNIC_RESET_CHANGE_PARAM) {
282962306a36Sopenharmony_ci		release_resources(adapter);
283062306a36Sopenharmony_ci		release_sub_crqs(adapter, 1);
283162306a36Sopenharmony_ci		release_crq_queue(adapter);
283262306a36Sopenharmony_ci	}
283362306a36Sopenharmony_ci
283462306a36Sopenharmony_ci	if (adapter->reset_reason != VNIC_RESET_NON_FATAL) {
283562306a36Sopenharmony_ci		/* remove the closed state so when we call open it appears
283662306a36Sopenharmony_ci		 * we are coming from the probed state.
283762306a36Sopenharmony_ci		 */
283862306a36Sopenharmony_ci		adapter->state = VNIC_PROBED;
283962306a36Sopenharmony_ci
284062306a36Sopenharmony_ci		reinit_init_done(adapter);
284162306a36Sopenharmony_ci
284262306a36Sopenharmony_ci		if (adapter->reset_reason == VNIC_RESET_CHANGE_PARAM) {
284362306a36Sopenharmony_ci			rc = init_crq_queue(adapter);
284462306a36Sopenharmony_ci		} else if (adapter->reset_reason == VNIC_RESET_MOBILITY) {
284562306a36Sopenharmony_ci			rc = ibmvnic_reenable_crq_queue(adapter);
284662306a36Sopenharmony_ci			release_sub_crqs(adapter, 1);
284762306a36Sopenharmony_ci		} else {
284862306a36Sopenharmony_ci			rc = ibmvnic_reset_crq(adapter);
284962306a36Sopenharmony_ci			if (rc == H_CLOSED || rc == H_SUCCESS) {
285062306a36Sopenharmony_ci				rc = vio_enable_interrupts(adapter->vdev);
285162306a36Sopenharmony_ci				if (rc)
285262306a36Sopenharmony_ci					netdev_err(adapter->netdev,
285362306a36Sopenharmony_ci						   "Reset failed to enable interrupts. rc=%d\n",
285462306a36Sopenharmony_ci						   rc);
285562306a36Sopenharmony_ci			}
285662306a36Sopenharmony_ci		}
285762306a36Sopenharmony_ci
285862306a36Sopenharmony_ci		if (rc) {
285962306a36Sopenharmony_ci			netdev_err(adapter->netdev,
286062306a36Sopenharmony_ci				   "Reset couldn't initialize crq. rc=%d\n", rc);
286162306a36Sopenharmony_ci			goto out;
286262306a36Sopenharmony_ci		}
286362306a36Sopenharmony_ci
286462306a36Sopenharmony_ci		rc = ibmvnic_reset_init(adapter, true);
286562306a36Sopenharmony_ci		if (rc)
286662306a36Sopenharmony_ci			goto out;
286762306a36Sopenharmony_ci
286862306a36Sopenharmony_ci		/* If the adapter was in PROBE or DOWN state prior to the reset,
286962306a36Sopenharmony_ci		 * exit here.
287062306a36Sopenharmony_ci		 */
287162306a36Sopenharmony_ci		if (reset_state == VNIC_PROBED || reset_state == VNIC_DOWN) {
287262306a36Sopenharmony_ci			rc = 0;
287362306a36Sopenharmony_ci			goto out;
287462306a36Sopenharmony_ci		}
287562306a36Sopenharmony_ci
287662306a36Sopenharmony_ci		rc = ibmvnic_login(netdev);
287762306a36Sopenharmony_ci		if (rc)
287862306a36Sopenharmony_ci			goto out;
287962306a36Sopenharmony_ci
288062306a36Sopenharmony_ci		if (adapter->reset_reason == VNIC_RESET_CHANGE_PARAM) {
288162306a36Sopenharmony_ci			rc = init_resources(adapter);
288262306a36Sopenharmony_ci			if (rc)
288362306a36Sopenharmony_ci				goto out;
288462306a36Sopenharmony_ci		} else if (adapter->req_rx_queues != old_num_rx_queues ||
288562306a36Sopenharmony_ci		    adapter->req_tx_queues != old_num_tx_queues ||
288662306a36Sopenharmony_ci		    adapter->req_rx_add_entries_per_subcrq !=
288762306a36Sopenharmony_ci		    old_num_rx_slots ||
288862306a36Sopenharmony_ci		    adapter->req_tx_entries_per_subcrq !=
288962306a36Sopenharmony_ci		    old_num_tx_slots ||
289062306a36Sopenharmony_ci		    !adapter->rx_pool ||
289162306a36Sopenharmony_ci		    !adapter->tso_pool ||
289262306a36Sopenharmony_ci		    !adapter->tx_pool) {
289362306a36Sopenharmony_ci			release_napi(adapter);
289462306a36Sopenharmony_ci			release_vpd_data(adapter);
289562306a36Sopenharmony_ci
289662306a36Sopenharmony_ci			rc = init_resources(adapter);
289762306a36Sopenharmony_ci			if (rc)
289862306a36Sopenharmony_ci				goto out;
289962306a36Sopenharmony_ci
290062306a36Sopenharmony_ci		} else {
290162306a36Sopenharmony_ci			rc = init_tx_pools(netdev);
290262306a36Sopenharmony_ci			if (rc) {
290362306a36Sopenharmony_ci				netdev_dbg(netdev,
290462306a36Sopenharmony_ci					   "init tx pools failed (%d)\n",
290562306a36Sopenharmony_ci					   rc);
290662306a36Sopenharmony_ci				goto out;
290762306a36Sopenharmony_ci			}
290862306a36Sopenharmony_ci
290962306a36Sopenharmony_ci			rc = init_rx_pools(netdev);
291062306a36Sopenharmony_ci			if (rc) {
291162306a36Sopenharmony_ci				netdev_dbg(netdev,
291262306a36Sopenharmony_ci					   "init rx pools failed (%d)\n",
291362306a36Sopenharmony_ci					   rc);
291462306a36Sopenharmony_ci				goto out;
291562306a36Sopenharmony_ci			}
291662306a36Sopenharmony_ci		}
291762306a36Sopenharmony_ci		ibmvnic_disable_irqs(adapter);
291862306a36Sopenharmony_ci	}
291962306a36Sopenharmony_ci	adapter->state = VNIC_CLOSED;
292062306a36Sopenharmony_ci
292162306a36Sopenharmony_ci	if (reset_state == VNIC_CLOSED) {
292262306a36Sopenharmony_ci		rc = 0;
292362306a36Sopenharmony_ci		goto out;
292462306a36Sopenharmony_ci	}
292562306a36Sopenharmony_ci
292662306a36Sopenharmony_ci	rc = __ibmvnic_open(netdev);
292762306a36Sopenharmony_ci	if (rc) {
292862306a36Sopenharmony_ci		rc = IBMVNIC_OPEN_FAILED;
292962306a36Sopenharmony_ci		goto out;
293062306a36Sopenharmony_ci	}
293162306a36Sopenharmony_ci
293262306a36Sopenharmony_ci	/* refresh device's multicast list */
293362306a36Sopenharmony_ci	ibmvnic_set_multi(netdev);
293462306a36Sopenharmony_ci
293562306a36Sopenharmony_ci	if (adapter->reset_reason == VNIC_RESET_FAILOVER ||
293662306a36Sopenharmony_ci	    adapter->reset_reason == VNIC_RESET_MOBILITY)
293762306a36Sopenharmony_ci		__netdev_notify_peers(netdev);
293862306a36Sopenharmony_ci
293962306a36Sopenharmony_ci	rc = 0;
294062306a36Sopenharmony_ci
294162306a36Sopenharmony_ciout:
294262306a36Sopenharmony_ci	/* restore the adapter state if reset failed */
294362306a36Sopenharmony_ci	if (rc)
294462306a36Sopenharmony_ci		adapter->state = reset_state;
294562306a36Sopenharmony_ci	/* requestor of VNIC_RESET_CHANGE_PARAM should still hold the rtnl lock */
294662306a36Sopenharmony_ci	if (!(adapter->reset_reason == VNIC_RESET_CHANGE_PARAM))
294762306a36Sopenharmony_ci		rtnl_unlock();
294862306a36Sopenharmony_ci
294962306a36Sopenharmony_ci	netdev_dbg(adapter->netdev, "[S:%s FOP:%d] Reset done, rc %d\n",
295062306a36Sopenharmony_ci		   adapter_state_to_string(adapter->state),
295162306a36Sopenharmony_ci		   adapter->failover_pending, rc);
295262306a36Sopenharmony_ci	return rc;
295362306a36Sopenharmony_ci}
295462306a36Sopenharmony_ci
295562306a36Sopenharmony_cistatic int do_hard_reset(struct ibmvnic_adapter *adapter,
295662306a36Sopenharmony_ci			 struct ibmvnic_rwi *rwi, u32 reset_state)
295762306a36Sopenharmony_ci{
295862306a36Sopenharmony_ci	struct net_device *netdev = adapter->netdev;
295962306a36Sopenharmony_ci	int rc;
296062306a36Sopenharmony_ci
296162306a36Sopenharmony_ci	netdev_dbg(adapter->netdev, "Hard resetting driver (%s)\n",
296262306a36Sopenharmony_ci		   reset_reason_to_string(rwi->reset_reason));
296362306a36Sopenharmony_ci
296462306a36Sopenharmony_ci	/* read the state and check (again) after getting rtnl */
296562306a36Sopenharmony_ci	reset_state = adapter->state;
296662306a36Sopenharmony_ci
296762306a36Sopenharmony_ci	if (reset_state == VNIC_REMOVING || reset_state == VNIC_REMOVED) {
296862306a36Sopenharmony_ci		rc = -EBUSY;
296962306a36Sopenharmony_ci		goto out;
297062306a36Sopenharmony_ci	}
297162306a36Sopenharmony_ci
297262306a36Sopenharmony_ci	netif_carrier_off(netdev);
297362306a36Sopenharmony_ci	adapter->reset_reason = rwi->reset_reason;
297462306a36Sopenharmony_ci
297562306a36Sopenharmony_ci	ibmvnic_cleanup(netdev);
297662306a36Sopenharmony_ci	release_resources(adapter);
297762306a36Sopenharmony_ci	release_sub_crqs(adapter, 0);
297862306a36Sopenharmony_ci	release_crq_queue(adapter);
297962306a36Sopenharmony_ci
298062306a36Sopenharmony_ci	/* remove the closed state so when we call open it appears
298162306a36Sopenharmony_ci	 * we are coming from the probed state.
298262306a36Sopenharmony_ci	 */
298362306a36Sopenharmony_ci	adapter->state = VNIC_PROBED;
298462306a36Sopenharmony_ci
298562306a36Sopenharmony_ci	reinit_init_done(adapter);
298662306a36Sopenharmony_ci
298762306a36Sopenharmony_ci	rc = init_crq_queue(adapter);
298862306a36Sopenharmony_ci	if (rc) {
298962306a36Sopenharmony_ci		netdev_err(adapter->netdev,
299062306a36Sopenharmony_ci			   "Couldn't initialize crq. rc=%d\n", rc);
299162306a36Sopenharmony_ci		goto out;
299262306a36Sopenharmony_ci	}
299362306a36Sopenharmony_ci
299462306a36Sopenharmony_ci	rc = ibmvnic_reset_init(adapter, false);
299562306a36Sopenharmony_ci	if (rc)
299662306a36Sopenharmony_ci		goto out;
299762306a36Sopenharmony_ci
299862306a36Sopenharmony_ci	/* If the adapter was in PROBE or DOWN state prior to the reset,
299962306a36Sopenharmony_ci	 * exit here.
300062306a36Sopenharmony_ci	 */
300162306a36Sopenharmony_ci	if (reset_state == VNIC_PROBED || reset_state == VNIC_DOWN)
300262306a36Sopenharmony_ci		goto out;
300362306a36Sopenharmony_ci
300462306a36Sopenharmony_ci	rc = ibmvnic_login(netdev);
300562306a36Sopenharmony_ci	if (rc)
300662306a36Sopenharmony_ci		goto out;
300762306a36Sopenharmony_ci
300862306a36Sopenharmony_ci	rc = init_resources(adapter);
300962306a36Sopenharmony_ci	if (rc)
301062306a36Sopenharmony_ci		goto out;
301162306a36Sopenharmony_ci
301262306a36Sopenharmony_ci	ibmvnic_disable_irqs(adapter);
301362306a36Sopenharmony_ci	adapter->state = VNIC_CLOSED;
301462306a36Sopenharmony_ci
301562306a36Sopenharmony_ci	if (reset_state == VNIC_CLOSED)
301662306a36Sopenharmony_ci		goto out;
301762306a36Sopenharmony_ci
301862306a36Sopenharmony_ci	rc = __ibmvnic_open(netdev);
301962306a36Sopenharmony_ci	if (rc) {
302062306a36Sopenharmony_ci		rc = IBMVNIC_OPEN_FAILED;
302162306a36Sopenharmony_ci		goto out;
302262306a36Sopenharmony_ci	}
302362306a36Sopenharmony_ci
302462306a36Sopenharmony_ci	__netdev_notify_peers(netdev);
302562306a36Sopenharmony_ciout:
302662306a36Sopenharmony_ci	/* restore adapter state if reset failed */
302762306a36Sopenharmony_ci	if (rc)
302862306a36Sopenharmony_ci		adapter->state = reset_state;
302962306a36Sopenharmony_ci	netdev_dbg(adapter->netdev, "[S:%s FOP:%d] Hard reset done, rc %d\n",
303062306a36Sopenharmony_ci		   adapter_state_to_string(adapter->state),
303162306a36Sopenharmony_ci		   adapter->failover_pending, rc);
303262306a36Sopenharmony_ci	return rc;
303362306a36Sopenharmony_ci}
303462306a36Sopenharmony_ci
303562306a36Sopenharmony_cistatic struct ibmvnic_rwi *get_next_rwi(struct ibmvnic_adapter *adapter)
303662306a36Sopenharmony_ci{
303762306a36Sopenharmony_ci	struct ibmvnic_rwi *rwi;
303862306a36Sopenharmony_ci	unsigned long flags;
303962306a36Sopenharmony_ci
304062306a36Sopenharmony_ci	spin_lock_irqsave(&adapter->rwi_lock, flags);
304162306a36Sopenharmony_ci
304262306a36Sopenharmony_ci	if (!list_empty(&adapter->rwi_list)) {
304362306a36Sopenharmony_ci		rwi = list_first_entry(&adapter->rwi_list, struct ibmvnic_rwi,
304462306a36Sopenharmony_ci				       list);
304562306a36Sopenharmony_ci		list_del(&rwi->list);
304662306a36Sopenharmony_ci	} else {
304762306a36Sopenharmony_ci		rwi = NULL;
304862306a36Sopenharmony_ci	}
304962306a36Sopenharmony_ci
305062306a36Sopenharmony_ci	spin_unlock_irqrestore(&adapter->rwi_lock, flags);
305162306a36Sopenharmony_ci	return rwi;
305262306a36Sopenharmony_ci}
305362306a36Sopenharmony_ci
305462306a36Sopenharmony_ci/**
305562306a36Sopenharmony_ci * do_passive_init - complete probing when partner device is detected.
305662306a36Sopenharmony_ci * @adapter: ibmvnic_adapter struct
305762306a36Sopenharmony_ci *
305862306a36Sopenharmony_ci * If the ibmvnic device does not have a partner device to communicate with at boot
305962306a36Sopenharmony_ci * and that partner device comes online at a later time, this function is called
306062306a36Sopenharmony_ci * to complete the initialization process of ibmvnic device.
306162306a36Sopenharmony_ci * Caller is expected to hold rtnl_lock().
306262306a36Sopenharmony_ci *
306362306a36Sopenharmony_ci * Returns non-zero if sub-CRQs are not initialized properly leaving the device
306462306a36Sopenharmony_ci * in the down state.
306562306a36Sopenharmony_ci * Returns 0 upon success and the device is in PROBED state.
306662306a36Sopenharmony_ci */
306762306a36Sopenharmony_ci
306862306a36Sopenharmony_cistatic int do_passive_init(struct ibmvnic_adapter *adapter)
306962306a36Sopenharmony_ci{
307062306a36Sopenharmony_ci	unsigned long timeout = msecs_to_jiffies(30000);
307162306a36Sopenharmony_ci	struct net_device *netdev = adapter->netdev;
307262306a36Sopenharmony_ci	struct device *dev = &adapter->vdev->dev;
307362306a36Sopenharmony_ci	int rc;
307462306a36Sopenharmony_ci
307562306a36Sopenharmony_ci	netdev_dbg(netdev, "Partner device found, probing.\n");
307662306a36Sopenharmony_ci
307762306a36Sopenharmony_ci	adapter->state = VNIC_PROBING;
307862306a36Sopenharmony_ci	reinit_completion(&adapter->init_done);
307962306a36Sopenharmony_ci	adapter->init_done_rc = 0;
308062306a36Sopenharmony_ci	adapter->crq.active = true;
308162306a36Sopenharmony_ci
308262306a36Sopenharmony_ci	rc = send_crq_init_complete(adapter);
308362306a36Sopenharmony_ci	if (rc)
308462306a36Sopenharmony_ci		goto out;
308562306a36Sopenharmony_ci
308662306a36Sopenharmony_ci	rc = send_version_xchg(adapter);
308762306a36Sopenharmony_ci	if (rc)
308862306a36Sopenharmony_ci		netdev_dbg(adapter->netdev, "send_version_xchg failed, rc=%d\n", rc);
308962306a36Sopenharmony_ci
309062306a36Sopenharmony_ci	if (!wait_for_completion_timeout(&adapter->init_done, timeout)) {
309162306a36Sopenharmony_ci		dev_err(dev, "Initialization sequence timed out\n");
309262306a36Sopenharmony_ci		rc = -ETIMEDOUT;
309362306a36Sopenharmony_ci		goto out;
309462306a36Sopenharmony_ci	}
309562306a36Sopenharmony_ci
309662306a36Sopenharmony_ci	rc = init_sub_crqs(adapter);
309762306a36Sopenharmony_ci	if (rc) {
309862306a36Sopenharmony_ci		dev_err(dev, "Initialization of sub crqs failed, rc=%d\n", rc);
309962306a36Sopenharmony_ci		goto out;
310062306a36Sopenharmony_ci	}
310162306a36Sopenharmony_ci
310262306a36Sopenharmony_ci	rc = init_sub_crq_irqs(adapter);
310362306a36Sopenharmony_ci	if (rc) {
310462306a36Sopenharmony_ci		dev_err(dev, "Failed to initialize sub crq irqs\n, rc=%d", rc);
310562306a36Sopenharmony_ci		goto init_failed;
310662306a36Sopenharmony_ci	}
310762306a36Sopenharmony_ci
310862306a36Sopenharmony_ci	netdev->mtu = adapter->req_mtu - ETH_HLEN;
310962306a36Sopenharmony_ci	netdev->min_mtu = adapter->min_mtu - ETH_HLEN;
311062306a36Sopenharmony_ci	netdev->max_mtu = adapter->max_mtu - ETH_HLEN;
311162306a36Sopenharmony_ci
311262306a36Sopenharmony_ci	adapter->state = VNIC_PROBED;
311362306a36Sopenharmony_ci	netdev_dbg(netdev, "Probed successfully. Waiting for signal from partner device.\n");
311462306a36Sopenharmony_ci
311562306a36Sopenharmony_ci	return 0;
311662306a36Sopenharmony_ci
311762306a36Sopenharmony_ciinit_failed:
311862306a36Sopenharmony_ci	release_sub_crqs(adapter, 1);
311962306a36Sopenharmony_ciout:
312062306a36Sopenharmony_ci	adapter->state = VNIC_DOWN;
312162306a36Sopenharmony_ci	return rc;
312262306a36Sopenharmony_ci}
312362306a36Sopenharmony_ci
312462306a36Sopenharmony_cistatic void __ibmvnic_reset(struct work_struct *work)
312562306a36Sopenharmony_ci{
312662306a36Sopenharmony_ci	struct ibmvnic_adapter *adapter;
312762306a36Sopenharmony_ci	unsigned int timeout = 5000;
312862306a36Sopenharmony_ci	struct ibmvnic_rwi *tmprwi;
312962306a36Sopenharmony_ci	bool saved_state = false;
313062306a36Sopenharmony_ci	struct ibmvnic_rwi *rwi;
313162306a36Sopenharmony_ci	unsigned long flags;
313262306a36Sopenharmony_ci	struct device *dev;
313362306a36Sopenharmony_ci	bool need_reset;
313462306a36Sopenharmony_ci	int num_fails = 0;
313562306a36Sopenharmony_ci	u32 reset_state;
313662306a36Sopenharmony_ci	int rc = 0;
313762306a36Sopenharmony_ci
313862306a36Sopenharmony_ci	adapter = container_of(work, struct ibmvnic_adapter, ibmvnic_reset);
313962306a36Sopenharmony_ci		dev = &adapter->vdev->dev;
314062306a36Sopenharmony_ci
314162306a36Sopenharmony_ci	/* Wait for ibmvnic_probe() to complete. If probe is taking too long
314262306a36Sopenharmony_ci	 * or if another reset is in progress, defer work for now. If probe
314362306a36Sopenharmony_ci	 * eventually fails it will flush and terminate our work.
314462306a36Sopenharmony_ci	 *
314562306a36Sopenharmony_ci	 * Three possibilities here:
314662306a36Sopenharmony_ci	 * 1. Adpater being removed  - just return
314762306a36Sopenharmony_ci	 * 2. Timed out on probe or another reset in progress - delay the work
314862306a36Sopenharmony_ci	 * 3. Completed probe - perform any resets in queue
314962306a36Sopenharmony_ci	 */
315062306a36Sopenharmony_ci	if (adapter->state == VNIC_PROBING &&
315162306a36Sopenharmony_ci	    !wait_for_completion_timeout(&adapter->probe_done, timeout)) {
315262306a36Sopenharmony_ci		dev_err(dev, "Reset thread timed out on probe");
315362306a36Sopenharmony_ci		queue_delayed_work(system_long_wq,
315462306a36Sopenharmony_ci				   &adapter->ibmvnic_delayed_reset,
315562306a36Sopenharmony_ci				   IBMVNIC_RESET_DELAY);
315662306a36Sopenharmony_ci		return;
315762306a36Sopenharmony_ci	}
315862306a36Sopenharmony_ci
315962306a36Sopenharmony_ci	/* adapter is done with probe (i.e state is never VNIC_PROBING now) */
316062306a36Sopenharmony_ci	if (adapter->state == VNIC_REMOVING)
316162306a36Sopenharmony_ci		return;
316262306a36Sopenharmony_ci
316362306a36Sopenharmony_ci	/* ->rwi_list is stable now (no one else is removing entries) */
316462306a36Sopenharmony_ci
316562306a36Sopenharmony_ci	/* ibmvnic_probe() may have purged the reset queue after we were
316662306a36Sopenharmony_ci	 * scheduled to process a reset so there maybe no resets to process.
316762306a36Sopenharmony_ci	 * Before setting the ->resetting bit though, we have to make sure
316862306a36Sopenharmony_ci	 * that there is infact a reset to process. Otherwise we may race
316962306a36Sopenharmony_ci	 * with ibmvnic_open() and end up leaving the vnic down:
317062306a36Sopenharmony_ci	 *
317162306a36Sopenharmony_ci	 *	__ibmvnic_reset()	    ibmvnic_open()
317262306a36Sopenharmony_ci	 *	-----------------	    --------------
317362306a36Sopenharmony_ci	 *
317462306a36Sopenharmony_ci	 *  set ->resetting bit
317562306a36Sopenharmony_ci	 *  				find ->resetting bit is set
317662306a36Sopenharmony_ci	 *  				set ->state to IBMVNIC_OPEN (i.e
317762306a36Sopenharmony_ci	 *  				assume reset will open device)
317862306a36Sopenharmony_ci	 *  				return
317962306a36Sopenharmony_ci	 *  find reset queue empty
318062306a36Sopenharmony_ci	 *  return
318162306a36Sopenharmony_ci	 *
318262306a36Sopenharmony_ci	 *  	Neither performed vnic login/open and vnic stays down
318362306a36Sopenharmony_ci	 *
318462306a36Sopenharmony_ci	 * If we hold the lock and conditionally set the bit, either we
318562306a36Sopenharmony_ci	 * or ibmvnic_open() will complete the open.
318662306a36Sopenharmony_ci	 */
318762306a36Sopenharmony_ci	need_reset = false;
318862306a36Sopenharmony_ci	spin_lock(&adapter->rwi_lock);
318962306a36Sopenharmony_ci	if (!list_empty(&adapter->rwi_list)) {
319062306a36Sopenharmony_ci		if (test_and_set_bit_lock(0, &adapter->resetting)) {
319162306a36Sopenharmony_ci			queue_delayed_work(system_long_wq,
319262306a36Sopenharmony_ci					   &adapter->ibmvnic_delayed_reset,
319362306a36Sopenharmony_ci					   IBMVNIC_RESET_DELAY);
319462306a36Sopenharmony_ci		} else {
319562306a36Sopenharmony_ci			need_reset = true;
319662306a36Sopenharmony_ci		}
319762306a36Sopenharmony_ci	}
319862306a36Sopenharmony_ci	spin_unlock(&adapter->rwi_lock);
319962306a36Sopenharmony_ci
320062306a36Sopenharmony_ci	if (!need_reset)
320162306a36Sopenharmony_ci		return;
320262306a36Sopenharmony_ci
320362306a36Sopenharmony_ci	rwi = get_next_rwi(adapter);
320462306a36Sopenharmony_ci	while (rwi) {
320562306a36Sopenharmony_ci		spin_lock_irqsave(&adapter->state_lock, flags);
320662306a36Sopenharmony_ci
320762306a36Sopenharmony_ci		if (adapter->state == VNIC_REMOVING ||
320862306a36Sopenharmony_ci		    adapter->state == VNIC_REMOVED) {
320962306a36Sopenharmony_ci			spin_unlock_irqrestore(&adapter->state_lock, flags);
321062306a36Sopenharmony_ci			kfree(rwi);
321162306a36Sopenharmony_ci			rc = EBUSY;
321262306a36Sopenharmony_ci			break;
321362306a36Sopenharmony_ci		}
321462306a36Sopenharmony_ci
321562306a36Sopenharmony_ci		if (!saved_state) {
321662306a36Sopenharmony_ci			reset_state = adapter->state;
321762306a36Sopenharmony_ci			saved_state = true;
321862306a36Sopenharmony_ci		}
321962306a36Sopenharmony_ci		spin_unlock_irqrestore(&adapter->state_lock, flags);
322062306a36Sopenharmony_ci
322162306a36Sopenharmony_ci		if (rwi->reset_reason == VNIC_RESET_PASSIVE_INIT) {
322262306a36Sopenharmony_ci			rtnl_lock();
322362306a36Sopenharmony_ci			rc = do_passive_init(adapter);
322462306a36Sopenharmony_ci			rtnl_unlock();
322562306a36Sopenharmony_ci			if (!rc)
322662306a36Sopenharmony_ci				netif_carrier_on(adapter->netdev);
322762306a36Sopenharmony_ci		} else if (adapter->force_reset_recovery) {
322862306a36Sopenharmony_ci			/* Since we are doing a hard reset now, clear the
322962306a36Sopenharmony_ci			 * failover_pending flag so we don't ignore any
323062306a36Sopenharmony_ci			 * future MOBILITY or other resets.
323162306a36Sopenharmony_ci			 */
323262306a36Sopenharmony_ci			adapter->failover_pending = false;
323362306a36Sopenharmony_ci
323462306a36Sopenharmony_ci			/* Transport event occurred during previous reset */
323562306a36Sopenharmony_ci			if (adapter->wait_for_reset) {
323662306a36Sopenharmony_ci				/* Previous was CHANGE_PARAM; caller locked */
323762306a36Sopenharmony_ci				adapter->force_reset_recovery = false;
323862306a36Sopenharmony_ci				rc = do_hard_reset(adapter, rwi, reset_state);
323962306a36Sopenharmony_ci			} else {
324062306a36Sopenharmony_ci				rtnl_lock();
324162306a36Sopenharmony_ci				adapter->force_reset_recovery = false;
324262306a36Sopenharmony_ci				rc = do_hard_reset(adapter, rwi, reset_state);
324362306a36Sopenharmony_ci				rtnl_unlock();
324462306a36Sopenharmony_ci			}
324562306a36Sopenharmony_ci			if (rc)
324662306a36Sopenharmony_ci				num_fails++;
324762306a36Sopenharmony_ci			else
324862306a36Sopenharmony_ci				num_fails = 0;
324962306a36Sopenharmony_ci
325062306a36Sopenharmony_ci			/* If auto-priority-failover is enabled we can get
325162306a36Sopenharmony_ci			 * back to back failovers during resets, resulting
325262306a36Sopenharmony_ci			 * in at least two failed resets (from high-priority
325362306a36Sopenharmony_ci			 * backing device to low-priority one and then back)
325462306a36Sopenharmony_ci			 * If resets continue to fail beyond that, give the
325562306a36Sopenharmony_ci			 * adapter some time to settle down before retrying.
325662306a36Sopenharmony_ci			 */
325762306a36Sopenharmony_ci			if (num_fails >= 3) {
325862306a36Sopenharmony_ci				netdev_dbg(adapter->netdev,
325962306a36Sopenharmony_ci					   "[S:%s] Hard reset failed %d times, waiting 60 secs\n",
326062306a36Sopenharmony_ci					   adapter_state_to_string(adapter->state),
326162306a36Sopenharmony_ci					   num_fails);
326262306a36Sopenharmony_ci				set_current_state(TASK_UNINTERRUPTIBLE);
326362306a36Sopenharmony_ci				schedule_timeout(60 * HZ);
326462306a36Sopenharmony_ci			}
326562306a36Sopenharmony_ci		} else {
326662306a36Sopenharmony_ci			rc = do_reset(adapter, rwi, reset_state);
326762306a36Sopenharmony_ci		}
326862306a36Sopenharmony_ci		tmprwi = rwi;
326962306a36Sopenharmony_ci		adapter->last_reset_time = jiffies;
327062306a36Sopenharmony_ci
327162306a36Sopenharmony_ci		if (rc)
327262306a36Sopenharmony_ci			netdev_dbg(adapter->netdev, "Reset failed, rc=%d\n", rc);
327362306a36Sopenharmony_ci
327462306a36Sopenharmony_ci		rwi = get_next_rwi(adapter);
327562306a36Sopenharmony_ci
327662306a36Sopenharmony_ci		/*
327762306a36Sopenharmony_ci		 * If there are no resets queued and the previous reset failed,
327862306a36Sopenharmony_ci		 * the adapter would be in an undefined state. So retry the
327962306a36Sopenharmony_ci		 * previous reset as a hard reset.
328062306a36Sopenharmony_ci		 *
328162306a36Sopenharmony_ci		 * Else, free the previous rwi and, if there is another reset
328262306a36Sopenharmony_ci		 * queued, process the new reset even if previous reset failed
328362306a36Sopenharmony_ci		 * (the previous reset could have failed because of a fail
328462306a36Sopenharmony_ci		 * over for instance, so process the fail over).
328562306a36Sopenharmony_ci		 */
328662306a36Sopenharmony_ci		if (!rwi && rc)
328762306a36Sopenharmony_ci			rwi = tmprwi;
328862306a36Sopenharmony_ci		else
328962306a36Sopenharmony_ci			kfree(tmprwi);
329062306a36Sopenharmony_ci
329162306a36Sopenharmony_ci		if (rwi && (rwi->reset_reason == VNIC_RESET_FAILOVER ||
329262306a36Sopenharmony_ci			    rwi->reset_reason == VNIC_RESET_MOBILITY || rc))
329362306a36Sopenharmony_ci			adapter->force_reset_recovery = true;
329462306a36Sopenharmony_ci	}
329562306a36Sopenharmony_ci
329662306a36Sopenharmony_ci	if (adapter->wait_for_reset) {
329762306a36Sopenharmony_ci		adapter->reset_done_rc = rc;
329862306a36Sopenharmony_ci		complete(&adapter->reset_done);
329962306a36Sopenharmony_ci	}
330062306a36Sopenharmony_ci
330162306a36Sopenharmony_ci	clear_bit_unlock(0, &adapter->resetting);
330262306a36Sopenharmony_ci
330362306a36Sopenharmony_ci	netdev_dbg(adapter->netdev,
330462306a36Sopenharmony_ci		   "[S:%s FRR:%d WFR:%d] Done processing resets\n",
330562306a36Sopenharmony_ci		   adapter_state_to_string(adapter->state),
330662306a36Sopenharmony_ci		   adapter->force_reset_recovery,
330762306a36Sopenharmony_ci		   adapter->wait_for_reset);
330862306a36Sopenharmony_ci}
330962306a36Sopenharmony_ci
331062306a36Sopenharmony_cistatic void __ibmvnic_delayed_reset(struct work_struct *work)
331162306a36Sopenharmony_ci{
331262306a36Sopenharmony_ci	struct ibmvnic_adapter *adapter;
331362306a36Sopenharmony_ci
331462306a36Sopenharmony_ci	adapter = container_of(work, struct ibmvnic_adapter,
331562306a36Sopenharmony_ci			       ibmvnic_delayed_reset.work);
331662306a36Sopenharmony_ci	__ibmvnic_reset(&adapter->ibmvnic_reset);
331762306a36Sopenharmony_ci}
331862306a36Sopenharmony_ci
331962306a36Sopenharmony_cistatic void flush_reset_queue(struct ibmvnic_adapter *adapter)
332062306a36Sopenharmony_ci{
332162306a36Sopenharmony_ci	struct list_head *entry, *tmp_entry;
332262306a36Sopenharmony_ci
332362306a36Sopenharmony_ci	if (!list_empty(&adapter->rwi_list)) {
332462306a36Sopenharmony_ci		list_for_each_safe(entry, tmp_entry, &adapter->rwi_list) {
332562306a36Sopenharmony_ci			list_del(entry);
332662306a36Sopenharmony_ci			kfree(list_entry(entry, struct ibmvnic_rwi, list));
332762306a36Sopenharmony_ci		}
332862306a36Sopenharmony_ci	}
332962306a36Sopenharmony_ci}
333062306a36Sopenharmony_ci
333162306a36Sopenharmony_cistatic int ibmvnic_reset(struct ibmvnic_adapter *adapter,
333262306a36Sopenharmony_ci			 enum ibmvnic_reset_reason reason)
333362306a36Sopenharmony_ci{
333462306a36Sopenharmony_ci	struct net_device *netdev = adapter->netdev;
333562306a36Sopenharmony_ci	struct ibmvnic_rwi *rwi, *tmp;
333662306a36Sopenharmony_ci	unsigned long flags;
333762306a36Sopenharmony_ci	int ret;
333862306a36Sopenharmony_ci
333962306a36Sopenharmony_ci	spin_lock_irqsave(&adapter->rwi_lock, flags);
334062306a36Sopenharmony_ci
334162306a36Sopenharmony_ci	/* If failover is pending don't schedule any other reset.
334262306a36Sopenharmony_ci	 * Instead let the failover complete. If there is already a
334362306a36Sopenharmony_ci	 * a failover reset scheduled, we will detect and drop the
334462306a36Sopenharmony_ci	 * duplicate reset when walking the ->rwi_list below.
334562306a36Sopenharmony_ci	 */
334662306a36Sopenharmony_ci	if (adapter->state == VNIC_REMOVING ||
334762306a36Sopenharmony_ci	    adapter->state == VNIC_REMOVED ||
334862306a36Sopenharmony_ci	    (adapter->failover_pending && reason != VNIC_RESET_FAILOVER)) {
334962306a36Sopenharmony_ci		ret = EBUSY;
335062306a36Sopenharmony_ci		netdev_dbg(netdev, "Adapter removing or pending failover, skipping reset\n");
335162306a36Sopenharmony_ci		goto err;
335262306a36Sopenharmony_ci	}
335362306a36Sopenharmony_ci
335462306a36Sopenharmony_ci	list_for_each_entry(tmp, &adapter->rwi_list, list) {
335562306a36Sopenharmony_ci		if (tmp->reset_reason == reason) {
335662306a36Sopenharmony_ci			netdev_dbg(netdev, "Skipping matching reset, reason=%s\n",
335762306a36Sopenharmony_ci				   reset_reason_to_string(reason));
335862306a36Sopenharmony_ci			ret = EBUSY;
335962306a36Sopenharmony_ci			goto err;
336062306a36Sopenharmony_ci		}
336162306a36Sopenharmony_ci	}
336262306a36Sopenharmony_ci
336362306a36Sopenharmony_ci	rwi = kzalloc(sizeof(*rwi), GFP_ATOMIC);
336462306a36Sopenharmony_ci	if (!rwi) {
336562306a36Sopenharmony_ci		ret = ENOMEM;
336662306a36Sopenharmony_ci		goto err;
336762306a36Sopenharmony_ci	}
336862306a36Sopenharmony_ci	/* if we just received a transport event,
336962306a36Sopenharmony_ci	 * flush reset queue and process this reset
337062306a36Sopenharmony_ci	 */
337162306a36Sopenharmony_ci	if (adapter->force_reset_recovery)
337262306a36Sopenharmony_ci		flush_reset_queue(adapter);
337362306a36Sopenharmony_ci
337462306a36Sopenharmony_ci	rwi->reset_reason = reason;
337562306a36Sopenharmony_ci	list_add_tail(&rwi->list, &adapter->rwi_list);
337662306a36Sopenharmony_ci	netdev_dbg(adapter->netdev, "Scheduling reset (reason %s)\n",
337762306a36Sopenharmony_ci		   reset_reason_to_string(reason));
337862306a36Sopenharmony_ci	queue_work(system_long_wq, &adapter->ibmvnic_reset);
337962306a36Sopenharmony_ci
338062306a36Sopenharmony_ci	ret = 0;
338162306a36Sopenharmony_cierr:
338262306a36Sopenharmony_ci	/* ibmvnic_close() below can block, so drop the lock first */
338362306a36Sopenharmony_ci	spin_unlock_irqrestore(&adapter->rwi_lock, flags);
338462306a36Sopenharmony_ci
338562306a36Sopenharmony_ci	if (ret == ENOMEM)
338662306a36Sopenharmony_ci		ibmvnic_close(netdev);
338762306a36Sopenharmony_ci
338862306a36Sopenharmony_ci	return -ret;
338962306a36Sopenharmony_ci}
339062306a36Sopenharmony_ci
339162306a36Sopenharmony_cistatic void ibmvnic_tx_timeout(struct net_device *dev, unsigned int txqueue)
339262306a36Sopenharmony_ci{
339362306a36Sopenharmony_ci	struct ibmvnic_adapter *adapter = netdev_priv(dev);
339462306a36Sopenharmony_ci
339562306a36Sopenharmony_ci	if (test_bit(0, &adapter->resetting)) {
339662306a36Sopenharmony_ci		netdev_err(adapter->netdev,
339762306a36Sopenharmony_ci			   "Adapter is resetting, skip timeout reset\n");
339862306a36Sopenharmony_ci		return;
339962306a36Sopenharmony_ci	}
340062306a36Sopenharmony_ci	/* No queuing up reset until at least 5 seconds (default watchdog val)
340162306a36Sopenharmony_ci	 * after last reset
340262306a36Sopenharmony_ci	 */
340362306a36Sopenharmony_ci	if (time_before(jiffies, (adapter->last_reset_time + dev->watchdog_timeo))) {
340462306a36Sopenharmony_ci		netdev_dbg(dev, "Not yet time to tx timeout.\n");
340562306a36Sopenharmony_ci		return;
340662306a36Sopenharmony_ci	}
340762306a36Sopenharmony_ci	ibmvnic_reset(adapter, VNIC_RESET_TIMEOUT);
340862306a36Sopenharmony_ci}
340962306a36Sopenharmony_ci
341062306a36Sopenharmony_cistatic void remove_buff_from_pool(struct ibmvnic_adapter *adapter,
341162306a36Sopenharmony_ci				  struct ibmvnic_rx_buff *rx_buff)
341262306a36Sopenharmony_ci{
341362306a36Sopenharmony_ci	struct ibmvnic_rx_pool *pool = &adapter->rx_pool[rx_buff->pool_index];
341462306a36Sopenharmony_ci
341562306a36Sopenharmony_ci	rx_buff->skb = NULL;
341662306a36Sopenharmony_ci
341762306a36Sopenharmony_ci	pool->free_map[pool->next_alloc] = (int)(rx_buff - pool->rx_buff);
341862306a36Sopenharmony_ci	pool->next_alloc = (pool->next_alloc + 1) % pool->size;
341962306a36Sopenharmony_ci
342062306a36Sopenharmony_ci	atomic_dec(&pool->available);
342162306a36Sopenharmony_ci}
342262306a36Sopenharmony_ci
342362306a36Sopenharmony_cistatic int ibmvnic_poll(struct napi_struct *napi, int budget)
342462306a36Sopenharmony_ci{
342562306a36Sopenharmony_ci	struct ibmvnic_sub_crq_queue *rx_scrq;
342662306a36Sopenharmony_ci	struct ibmvnic_adapter *adapter;
342762306a36Sopenharmony_ci	struct net_device *netdev;
342862306a36Sopenharmony_ci	int frames_processed;
342962306a36Sopenharmony_ci	int scrq_num;
343062306a36Sopenharmony_ci
343162306a36Sopenharmony_ci	netdev = napi->dev;
343262306a36Sopenharmony_ci	adapter = netdev_priv(netdev);
343362306a36Sopenharmony_ci	scrq_num = (int)(napi - adapter->napi);
343462306a36Sopenharmony_ci	frames_processed = 0;
343562306a36Sopenharmony_ci	rx_scrq = adapter->rx_scrq[scrq_num];
343662306a36Sopenharmony_ci
343762306a36Sopenharmony_cirestart_poll:
343862306a36Sopenharmony_ci	while (frames_processed < budget) {
343962306a36Sopenharmony_ci		struct sk_buff *skb;
344062306a36Sopenharmony_ci		struct ibmvnic_rx_buff *rx_buff;
344162306a36Sopenharmony_ci		union sub_crq *next;
344262306a36Sopenharmony_ci		u32 length;
344362306a36Sopenharmony_ci		u16 offset;
344462306a36Sopenharmony_ci		u8 flags = 0;
344562306a36Sopenharmony_ci
344662306a36Sopenharmony_ci		if (unlikely(test_bit(0, &adapter->resetting) &&
344762306a36Sopenharmony_ci			     adapter->reset_reason != VNIC_RESET_NON_FATAL)) {
344862306a36Sopenharmony_ci			enable_scrq_irq(adapter, rx_scrq);
344962306a36Sopenharmony_ci			napi_complete_done(napi, frames_processed);
345062306a36Sopenharmony_ci			return frames_processed;
345162306a36Sopenharmony_ci		}
345262306a36Sopenharmony_ci
345362306a36Sopenharmony_ci		if (!pending_scrq(adapter, rx_scrq))
345462306a36Sopenharmony_ci			break;
345562306a36Sopenharmony_ci		next = ibmvnic_next_scrq(adapter, rx_scrq);
345662306a36Sopenharmony_ci		rx_buff = (struct ibmvnic_rx_buff *)
345762306a36Sopenharmony_ci			  be64_to_cpu(next->rx_comp.correlator);
345862306a36Sopenharmony_ci		/* do error checking */
345962306a36Sopenharmony_ci		if (next->rx_comp.rc) {
346062306a36Sopenharmony_ci			netdev_dbg(netdev, "rx buffer returned with rc %x\n",
346162306a36Sopenharmony_ci				   be16_to_cpu(next->rx_comp.rc));
346262306a36Sopenharmony_ci			/* free the entry */
346362306a36Sopenharmony_ci			next->rx_comp.first = 0;
346462306a36Sopenharmony_ci			dev_kfree_skb_any(rx_buff->skb);
346562306a36Sopenharmony_ci			remove_buff_from_pool(adapter, rx_buff);
346662306a36Sopenharmony_ci			continue;
346762306a36Sopenharmony_ci		} else if (!rx_buff->skb) {
346862306a36Sopenharmony_ci			/* free the entry */
346962306a36Sopenharmony_ci			next->rx_comp.first = 0;
347062306a36Sopenharmony_ci			remove_buff_from_pool(adapter, rx_buff);
347162306a36Sopenharmony_ci			continue;
347262306a36Sopenharmony_ci		}
347362306a36Sopenharmony_ci
347462306a36Sopenharmony_ci		length = be32_to_cpu(next->rx_comp.len);
347562306a36Sopenharmony_ci		offset = be16_to_cpu(next->rx_comp.off_frame_data);
347662306a36Sopenharmony_ci		flags = next->rx_comp.flags;
347762306a36Sopenharmony_ci		skb = rx_buff->skb;
347862306a36Sopenharmony_ci		/* load long_term_buff before copying to skb */
347962306a36Sopenharmony_ci		dma_rmb();
348062306a36Sopenharmony_ci		skb_copy_to_linear_data(skb, rx_buff->data + offset,
348162306a36Sopenharmony_ci					length);
348262306a36Sopenharmony_ci
348362306a36Sopenharmony_ci		/* VLAN Header has been stripped by the system firmware and
348462306a36Sopenharmony_ci		 * needs to be inserted by the driver
348562306a36Sopenharmony_ci		 */
348662306a36Sopenharmony_ci		if (adapter->rx_vlan_header_insertion &&
348762306a36Sopenharmony_ci		    (flags & IBMVNIC_VLAN_STRIPPED))
348862306a36Sopenharmony_ci			__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
348962306a36Sopenharmony_ci					       ntohs(next->rx_comp.vlan_tci));
349062306a36Sopenharmony_ci
349162306a36Sopenharmony_ci		/* free the entry */
349262306a36Sopenharmony_ci		next->rx_comp.first = 0;
349362306a36Sopenharmony_ci		remove_buff_from_pool(adapter, rx_buff);
349462306a36Sopenharmony_ci
349562306a36Sopenharmony_ci		skb_put(skb, length);
349662306a36Sopenharmony_ci		skb->protocol = eth_type_trans(skb, netdev);
349762306a36Sopenharmony_ci		skb_record_rx_queue(skb, scrq_num);
349862306a36Sopenharmony_ci
349962306a36Sopenharmony_ci		if (flags & IBMVNIC_IP_CHKSUM_GOOD &&
350062306a36Sopenharmony_ci		    flags & IBMVNIC_TCP_UDP_CHKSUM_GOOD) {
350162306a36Sopenharmony_ci			skb->ip_summed = CHECKSUM_UNNECESSARY;
350262306a36Sopenharmony_ci		}
350362306a36Sopenharmony_ci
350462306a36Sopenharmony_ci		length = skb->len;
350562306a36Sopenharmony_ci		napi_gro_receive(napi, skb); /* send it up */
350662306a36Sopenharmony_ci		netdev->stats.rx_packets++;
350762306a36Sopenharmony_ci		netdev->stats.rx_bytes += length;
350862306a36Sopenharmony_ci		adapter->rx_stats_buffers[scrq_num].packets++;
350962306a36Sopenharmony_ci		adapter->rx_stats_buffers[scrq_num].bytes += length;
351062306a36Sopenharmony_ci		frames_processed++;
351162306a36Sopenharmony_ci	}
351262306a36Sopenharmony_ci
351362306a36Sopenharmony_ci	if (adapter->state != VNIC_CLOSING &&
351462306a36Sopenharmony_ci	    ((atomic_read(&adapter->rx_pool[scrq_num].available) <
351562306a36Sopenharmony_ci	      adapter->req_rx_add_entries_per_subcrq / 2) ||
351662306a36Sopenharmony_ci	      frames_processed < budget))
351762306a36Sopenharmony_ci		replenish_rx_pool(adapter, &adapter->rx_pool[scrq_num]);
351862306a36Sopenharmony_ci	if (frames_processed < budget) {
351962306a36Sopenharmony_ci		if (napi_complete_done(napi, frames_processed)) {
352062306a36Sopenharmony_ci			enable_scrq_irq(adapter, rx_scrq);
352162306a36Sopenharmony_ci			if (pending_scrq(adapter, rx_scrq)) {
352262306a36Sopenharmony_ci				if (napi_reschedule(napi)) {
352362306a36Sopenharmony_ci					disable_scrq_irq(adapter, rx_scrq);
352462306a36Sopenharmony_ci					goto restart_poll;
352562306a36Sopenharmony_ci				}
352662306a36Sopenharmony_ci			}
352762306a36Sopenharmony_ci		}
352862306a36Sopenharmony_ci	}
352962306a36Sopenharmony_ci	return frames_processed;
353062306a36Sopenharmony_ci}
353162306a36Sopenharmony_ci
353262306a36Sopenharmony_cistatic int wait_for_reset(struct ibmvnic_adapter *adapter)
353362306a36Sopenharmony_ci{
353462306a36Sopenharmony_ci	int rc, ret;
353562306a36Sopenharmony_ci
353662306a36Sopenharmony_ci	adapter->fallback.mtu = adapter->req_mtu;
353762306a36Sopenharmony_ci	adapter->fallback.rx_queues = adapter->req_rx_queues;
353862306a36Sopenharmony_ci	adapter->fallback.tx_queues = adapter->req_tx_queues;
353962306a36Sopenharmony_ci	adapter->fallback.rx_entries = adapter->req_rx_add_entries_per_subcrq;
354062306a36Sopenharmony_ci	adapter->fallback.tx_entries = adapter->req_tx_entries_per_subcrq;
354162306a36Sopenharmony_ci
354262306a36Sopenharmony_ci	reinit_completion(&adapter->reset_done);
354362306a36Sopenharmony_ci	adapter->wait_for_reset = true;
354462306a36Sopenharmony_ci	rc = ibmvnic_reset(adapter, VNIC_RESET_CHANGE_PARAM);
354562306a36Sopenharmony_ci
354662306a36Sopenharmony_ci	if (rc) {
354762306a36Sopenharmony_ci		ret = rc;
354862306a36Sopenharmony_ci		goto out;
354962306a36Sopenharmony_ci	}
355062306a36Sopenharmony_ci	rc = ibmvnic_wait_for_completion(adapter, &adapter->reset_done, 60000);
355162306a36Sopenharmony_ci	if (rc) {
355262306a36Sopenharmony_ci		ret = -ENODEV;
355362306a36Sopenharmony_ci		goto out;
355462306a36Sopenharmony_ci	}
355562306a36Sopenharmony_ci
355662306a36Sopenharmony_ci	ret = 0;
355762306a36Sopenharmony_ci	if (adapter->reset_done_rc) {
355862306a36Sopenharmony_ci		ret = -EIO;
355962306a36Sopenharmony_ci		adapter->desired.mtu = adapter->fallback.mtu;
356062306a36Sopenharmony_ci		adapter->desired.rx_queues = adapter->fallback.rx_queues;
356162306a36Sopenharmony_ci		adapter->desired.tx_queues = adapter->fallback.tx_queues;
356262306a36Sopenharmony_ci		adapter->desired.rx_entries = adapter->fallback.rx_entries;
356362306a36Sopenharmony_ci		adapter->desired.tx_entries = adapter->fallback.tx_entries;
356462306a36Sopenharmony_ci
356562306a36Sopenharmony_ci		reinit_completion(&adapter->reset_done);
356662306a36Sopenharmony_ci		adapter->wait_for_reset = true;
356762306a36Sopenharmony_ci		rc = ibmvnic_reset(adapter, VNIC_RESET_CHANGE_PARAM);
356862306a36Sopenharmony_ci		if (rc) {
356962306a36Sopenharmony_ci			ret = rc;
357062306a36Sopenharmony_ci			goto out;
357162306a36Sopenharmony_ci		}
357262306a36Sopenharmony_ci		rc = ibmvnic_wait_for_completion(adapter, &adapter->reset_done,
357362306a36Sopenharmony_ci						 60000);
357462306a36Sopenharmony_ci		if (rc) {
357562306a36Sopenharmony_ci			ret = -ENODEV;
357662306a36Sopenharmony_ci			goto out;
357762306a36Sopenharmony_ci		}
357862306a36Sopenharmony_ci	}
357962306a36Sopenharmony_ciout:
358062306a36Sopenharmony_ci	adapter->wait_for_reset = false;
358162306a36Sopenharmony_ci
358262306a36Sopenharmony_ci	return ret;
358362306a36Sopenharmony_ci}
358462306a36Sopenharmony_ci
358562306a36Sopenharmony_cistatic int ibmvnic_change_mtu(struct net_device *netdev, int new_mtu)
358662306a36Sopenharmony_ci{
358762306a36Sopenharmony_ci	struct ibmvnic_adapter *adapter = netdev_priv(netdev);
358862306a36Sopenharmony_ci
358962306a36Sopenharmony_ci	adapter->desired.mtu = new_mtu + ETH_HLEN;
359062306a36Sopenharmony_ci
359162306a36Sopenharmony_ci	return wait_for_reset(adapter);
359262306a36Sopenharmony_ci}
359362306a36Sopenharmony_ci
359462306a36Sopenharmony_cistatic netdev_features_t ibmvnic_features_check(struct sk_buff *skb,
359562306a36Sopenharmony_ci						struct net_device *dev,
359662306a36Sopenharmony_ci						netdev_features_t features)
359762306a36Sopenharmony_ci{
359862306a36Sopenharmony_ci	/* Some backing hardware adapters can not
359962306a36Sopenharmony_ci	 * handle packets with a MSS less than 224
360062306a36Sopenharmony_ci	 * or with only one segment.
360162306a36Sopenharmony_ci	 */
360262306a36Sopenharmony_ci	if (skb_is_gso(skb)) {
360362306a36Sopenharmony_ci		if (skb_shinfo(skb)->gso_size < 224 ||
360462306a36Sopenharmony_ci		    skb_shinfo(skb)->gso_segs == 1)
360562306a36Sopenharmony_ci			features &= ~NETIF_F_GSO_MASK;
360662306a36Sopenharmony_ci	}
360762306a36Sopenharmony_ci
360862306a36Sopenharmony_ci	return features;
360962306a36Sopenharmony_ci}
361062306a36Sopenharmony_ci
361162306a36Sopenharmony_cistatic const struct net_device_ops ibmvnic_netdev_ops = {
361262306a36Sopenharmony_ci	.ndo_open		= ibmvnic_open,
361362306a36Sopenharmony_ci	.ndo_stop		= ibmvnic_close,
361462306a36Sopenharmony_ci	.ndo_start_xmit		= ibmvnic_xmit,
361562306a36Sopenharmony_ci	.ndo_set_rx_mode	= ibmvnic_set_multi,
361662306a36Sopenharmony_ci	.ndo_set_mac_address	= ibmvnic_set_mac,
361762306a36Sopenharmony_ci	.ndo_validate_addr	= eth_validate_addr,
361862306a36Sopenharmony_ci	.ndo_tx_timeout		= ibmvnic_tx_timeout,
361962306a36Sopenharmony_ci	.ndo_change_mtu		= ibmvnic_change_mtu,
362062306a36Sopenharmony_ci	.ndo_features_check     = ibmvnic_features_check,
362162306a36Sopenharmony_ci};
362262306a36Sopenharmony_ci
362362306a36Sopenharmony_ci/* ethtool functions */
362462306a36Sopenharmony_ci
362562306a36Sopenharmony_cistatic int ibmvnic_get_link_ksettings(struct net_device *netdev,
362662306a36Sopenharmony_ci				      struct ethtool_link_ksettings *cmd)
362762306a36Sopenharmony_ci{
362862306a36Sopenharmony_ci	struct ibmvnic_adapter *adapter = netdev_priv(netdev);
362962306a36Sopenharmony_ci	int rc;
363062306a36Sopenharmony_ci
363162306a36Sopenharmony_ci	rc = send_query_phys_parms(adapter);
363262306a36Sopenharmony_ci	if (rc) {
363362306a36Sopenharmony_ci		adapter->speed = SPEED_UNKNOWN;
363462306a36Sopenharmony_ci		adapter->duplex = DUPLEX_UNKNOWN;
363562306a36Sopenharmony_ci	}
363662306a36Sopenharmony_ci	cmd->base.speed = adapter->speed;
363762306a36Sopenharmony_ci	cmd->base.duplex = adapter->duplex;
363862306a36Sopenharmony_ci	cmd->base.port = PORT_FIBRE;
363962306a36Sopenharmony_ci	cmd->base.phy_address = 0;
364062306a36Sopenharmony_ci	cmd->base.autoneg = AUTONEG_ENABLE;
364162306a36Sopenharmony_ci
364262306a36Sopenharmony_ci	return 0;
364362306a36Sopenharmony_ci}
364462306a36Sopenharmony_ci
364562306a36Sopenharmony_cistatic void ibmvnic_get_drvinfo(struct net_device *netdev,
364662306a36Sopenharmony_ci				struct ethtool_drvinfo *info)
364762306a36Sopenharmony_ci{
364862306a36Sopenharmony_ci	struct ibmvnic_adapter *adapter = netdev_priv(netdev);
364962306a36Sopenharmony_ci
365062306a36Sopenharmony_ci	strscpy(info->driver, ibmvnic_driver_name, sizeof(info->driver));
365162306a36Sopenharmony_ci	strscpy(info->version, IBMVNIC_DRIVER_VERSION, sizeof(info->version));
365262306a36Sopenharmony_ci	strscpy(info->fw_version, adapter->fw_version,
365362306a36Sopenharmony_ci		sizeof(info->fw_version));
365462306a36Sopenharmony_ci}
365562306a36Sopenharmony_ci
365662306a36Sopenharmony_cistatic u32 ibmvnic_get_msglevel(struct net_device *netdev)
365762306a36Sopenharmony_ci{
365862306a36Sopenharmony_ci	struct ibmvnic_adapter *adapter = netdev_priv(netdev);
365962306a36Sopenharmony_ci
366062306a36Sopenharmony_ci	return adapter->msg_enable;
366162306a36Sopenharmony_ci}
366262306a36Sopenharmony_ci
366362306a36Sopenharmony_cistatic void ibmvnic_set_msglevel(struct net_device *netdev, u32 data)
366462306a36Sopenharmony_ci{
366562306a36Sopenharmony_ci	struct ibmvnic_adapter *adapter = netdev_priv(netdev);
366662306a36Sopenharmony_ci
366762306a36Sopenharmony_ci	adapter->msg_enable = data;
366862306a36Sopenharmony_ci}
366962306a36Sopenharmony_ci
367062306a36Sopenharmony_cistatic u32 ibmvnic_get_link(struct net_device *netdev)
367162306a36Sopenharmony_ci{
367262306a36Sopenharmony_ci	struct ibmvnic_adapter *adapter = netdev_priv(netdev);
367362306a36Sopenharmony_ci
367462306a36Sopenharmony_ci	/* Don't need to send a query because we request a logical link up at
367562306a36Sopenharmony_ci	 * init and then we wait for link state indications
367662306a36Sopenharmony_ci	 */
367762306a36Sopenharmony_ci	return adapter->logical_link_state;
367862306a36Sopenharmony_ci}
367962306a36Sopenharmony_ci
368062306a36Sopenharmony_cistatic void ibmvnic_get_ringparam(struct net_device *netdev,
368162306a36Sopenharmony_ci				  struct ethtool_ringparam *ring,
368262306a36Sopenharmony_ci				  struct kernel_ethtool_ringparam *kernel_ring,
368362306a36Sopenharmony_ci				  struct netlink_ext_ack *extack)
368462306a36Sopenharmony_ci{
368562306a36Sopenharmony_ci	struct ibmvnic_adapter *adapter = netdev_priv(netdev);
368662306a36Sopenharmony_ci
368762306a36Sopenharmony_ci	ring->rx_max_pending = adapter->max_rx_add_entries_per_subcrq;
368862306a36Sopenharmony_ci	ring->tx_max_pending = adapter->max_tx_entries_per_subcrq;
368962306a36Sopenharmony_ci	ring->rx_mini_max_pending = 0;
369062306a36Sopenharmony_ci	ring->rx_jumbo_max_pending = 0;
369162306a36Sopenharmony_ci	ring->rx_pending = adapter->req_rx_add_entries_per_subcrq;
369262306a36Sopenharmony_ci	ring->tx_pending = adapter->req_tx_entries_per_subcrq;
369362306a36Sopenharmony_ci	ring->rx_mini_pending = 0;
369462306a36Sopenharmony_ci	ring->rx_jumbo_pending = 0;
369562306a36Sopenharmony_ci}
369662306a36Sopenharmony_ci
369762306a36Sopenharmony_cistatic int ibmvnic_set_ringparam(struct net_device *netdev,
369862306a36Sopenharmony_ci				 struct ethtool_ringparam *ring,
369962306a36Sopenharmony_ci				 struct kernel_ethtool_ringparam *kernel_ring,
370062306a36Sopenharmony_ci				 struct netlink_ext_ack *extack)
370162306a36Sopenharmony_ci{
370262306a36Sopenharmony_ci	struct ibmvnic_adapter *adapter = netdev_priv(netdev);
370362306a36Sopenharmony_ci
370462306a36Sopenharmony_ci	if (ring->rx_pending > adapter->max_rx_add_entries_per_subcrq  ||
370562306a36Sopenharmony_ci	    ring->tx_pending > adapter->max_tx_entries_per_subcrq) {
370662306a36Sopenharmony_ci		netdev_err(netdev, "Invalid request.\n");
370762306a36Sopenharmony_ci		netdev_err(netdev, "Max tx buffers = %llu\n",
370862306a36Sopenharmony_ci			   adapter->max_rx_add_entries_per_subcrq);
370962306a36Sopenharmony_ci		netdev_err(netdev, "Max rx buffers = %llu\n",
371062306a36Sopenharmony_ci			   adapter->max_tx_entries_per_subcrq);
371162306a36Sopenharmony_ci		return -EINVAL;
371262306a36Sopenharmony_ci	}
371362306a36Sopenharmony_ci
371462306a36Sopenharmony_ci	adapter->desired.rx_entries = ring->rx_pending;
371562306a36Sopenharmony_ci	adapter->desired.tx_entries = ring->tx_pending;
371662306a36Sopenharmony_ci
371762306a36Sopenharmony_ci	return wait_for_reset(adapter);
371862306a36Sopenharmony_ci}
371962306a36Sopenharmony_ci
372062306a36Sopenharmony_cistatic void ibmvnic_get_channels(struct net_device *netdev,
372162306a36Sopenharmony_ci				 struct ethtool_channels *channels)
372262306a36Sopenharmony_ci{
372362306a36Sopenharmony_ci	struct ibmvnic_adapter *adapter = netdev_priv(netdev);
372462306a36Sopenharmony_ci
372562306a36Sopenharmony_ci	channels->max_rx = adapter->max_rx_queues;
372662306a36Sopenharmony_ci	channels->max_tx = adapter->max_tx_queues;
372762306a36Sopenharmony_ci	channels->max_other = 0;
372862306a36Sopenharmony_ci	channels->max_combined = 0;
372962306a36Sopenharmony_ci	channels->rx_count = adapter->req_rx_queues;
373062306a36Sopenharmony_ci	channels->tx_count = adapter->req_tx_queues;
373162306a36Sopenharmony_ci	channels->other_count = 0;
373262306a36Sopenharmony_ci	channels->combined_count = 0;
373362306a36Sopenharmony_ci}
373462306a36Sopenharmony_ci
373562306a36Sopenharmony_cistatic int ibmvnic_set_channels(struct net_device *netdev,
373662306a36Sopenharmony_ci				struct ethtool_channels *channels)
373762306a36Sopenharmony_ci{
373862306a36Sopenharmony_ci	struct ibmvnic_adapter *adapter = netdev_priv(netdev);
373962306a36Sopenharmony_ci
374062306a36Sopenharmony_ci	adapter->desired.rx_queues = channels->rx_count;
374162306a36Sopenharmony_ci	adapter->desired.tx_queues = channels->tx_count;
374262306a36Sopenharmony_ci
374362306a36Sopenharmony_ci	return wait_for_reset(adapter);
374462306a36Sopenharmony_ci}
374562306a36Sopenharmony_ci
374662306a36Sopenharmony_cistatic void ibmvnic_get_strings(struct net_device *dev, u32 stringset, u8 *data)
374762306a36Sopenharmony_ci{
374862306a36Sopenharmony_ci	struct ibmvnic_adapter *adapter = netdev_priv(dev);
374962306a36Sopenharmony_ci	int i;
375062306a36Sopenharmony_ci
375162306a36Sopenharmony_ci	if (stringset != ETH_SS_STATS)
375262306a36Sopenharmony_ci		return;
375362306a36Sopenharmony_ci
375462306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(ibmvnic_stats); i++, data += ETH_GSTRING_LEN)
375562306a36Sopenharmony_ci		memcpy(data, ibmvnic_stats[i].name, ETH_GSTRING_LEN);
375662306a36Sopenharmony_ci
375762306a36Sopenharmony_ci	for (i = 0; i < adapter->req_tx_queues; i++) {
375862306a36Sopenharmony_ci		snprintf(data, ETH_GSTRING_LEN, "tx%d_packets", i);
375962306a36Sopenharmony_ci		data += ETH_GSTRING_LEN;
376062306a36Sopenharmony_ci
376162306a36Sopenharmony_ci		snprintf(data, ETH_GSTRING_LEN, "tx%d_bytes", i);
376262306a36Sopenharmony_ci		data += ETH_GSTRING_LEN;
376362306a36Sopenharmony_ci
376462306a36Sopenharmony_ci		snprintf(data, ETH_GSTRING_LEN, "tx%d_dropped_packets", i);
376562306a36Sopenharmony_ci		data += ETH_GSTRING_LEN;
376662306a36Sopenharmony_ci	}
376762306a36Sopenharmony_ci
376862306a36Sopenharmony_ci	for (i = 0; i < adapter->req_rx_queues; i++) {
376962306a36Sopenharmony_ci		snprintf(data, ETH_GSTRING_LEN, "rx%d_packets", i);
377062306a36Sopenharmony_ci		data += ETH_GSTRING_LEN;
377162306a36Sopenharmony_ci
377262306a36Sopenharmony_ci		snprintf(data, ETH_GSTRING_LEN, "rx%d_bytes", i);
377362306a36Sopenharmony_ci		data += ETH_GSTRING_LEN;
377462306a36Sopenharmony_ci
377562306a36Sopenharmony_ci		snprintf(data, ETH_GSTRING_LEN, "rx%d_interrupts", i);
377662306a36Sopenharmony_ci		data += ETH_GSTRING_LEN;
377762306a36Sopenharmony_ci	}
377862306a36Sopenharmony_ci}
377962306a36Sopenharmony_ci
378062306a36Sopenharmony_cistatic int ibmvnic_get_sset_count(struct net_device *dev, int sset)
378162306a36Sopenharmony_ci{
378262306a36Sopenharmony_ci	struct ibmvnic_adapter *adapter = netdev_priv(dev);
378362306a36Sopenharmony_ci
378462306a36Sopenharmony_ci	switch (sset) {
378562306a36Sopenharmony_ci	case ETH_SS_STATS:
378662306a36Sopenharmony_ci		return ARRAY_SIZE(ibmvnic_stats) +
378762306a36Sopenharmony_ci		       adapter->req_tx_queues * NUM_TX_STATS +
378862306a36Sopenharmony_ci		       adapter->req_rx_queues * NUM_RX_STATS;
378962306a36Sopenharmony_ci	default:
379062306a36Sopenharmony_ci		return -EOPNOTSUPP;
379162306a36Sopenharmony_ci	}
379262306a36Sopenharmony_ci}
379362306a36Sopenharmony_ci
379462306a36Sopenharmony_cistatic void ibmvnic_get_ethtool_stats(struct net_device *dev,
379562306a36Sopenharmony_ci				      struct ethtool_stats *stats, u64 *data)
379662306a36Sopenharmony_ci{
379762306a36Sopenharmony_ci	struct ibmvnic_adapter *adapter = netdev_priv(dev);
379862306a36Sopenharmony_ci	union ibmvnic_crq crq;
379962306a36Sopenharmony_ci	int i, j;
380062306a36Sopenharmony_ci	int rc;
380162306a36Sopenharmony_ci
380262306a36Sopenharmony_ci	memset(&crq, 0, sizeof(crq));
380362306a36Sopenharmony_ci	crq.request_statistics.first = IBMVNIC_CRQ_CMD;
380462306a36Sopenharmony_ci	crq.request_statistics.cmd = REQUEST_STATISTICS;
380562306a36Sopenharmony_ci	crq.request_statistics.ioba = cpu_to_be32(adapter->stats_token);
380662306a36Sopenharmony_ci	crq.request_statistics.len =
380762306a36Sopenharmony_ci	    cpu_to_be32(sizeof(struct ibmvnic_statistics));
380862306a36Sopenharmony_ci
380962306a36Sopenharmony_ci	/* Wait for data to be written */
381062306a36Sopenharmony_ci	reinit_completion(&adapter->stats_done);
381162306a36Sopenharmony_ci	rc = ibmvnic_send_crq(adapter, &crq);
381262306a36Sopenharmony_ci	if (rc)
381362306a36Sopenharmony_ci		return;
381462306a36Sopenharmony_ci	rc = ibmvnic_wait_for_completion(adapter, &adapter->stats_done, 10000);
381562306a36Sopenharmony_ci	if (rc)
381662306a36Sopenharmony_ci		return;
381762306a36Sopenharmony_ci
381862306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(ibmvnic_stats); i++)
381962306a36Sopenharmony_ci		data[i] = be64_to_cpu(IBMVNIC_GET_STAT
382062306a36Sopenharmony_ci				      (adapter, ibmvnic_stats[i].offset));
382162306a36Sopenharmony_ci
382262306a36Sopenharmony_ci	for (j = 0; j < adapter->req_tx_queues; j++) {
382362306a36Sopenharmony_ci		data[i] = adapter->tx_stats_buffers[j].packets;
382462306a36Sopenharmony_ci		i++;
382562306a36Sopenharmony_ci		data[i] = adapter->tx_stats_buffers[j].bytes;
382662306a36Sopenharmony_ci		i++;
382762306a36Sopenharmony_ci		data[i] = adapter->tx_stats_buffers[j].dropped_packets;
382862306a36Sopenharmony_ci		i++;
382962306a36Sopenharmony_ci	}
383062306a36Sopenharmony_ci
383162306a36Sopenharmony_ci	for (j = 0; j < adapter->req_rx_queues; j++) {
383262306a36Sopenharmony_ci		data[i] = adapter->rx_stats_buffers[j].packets;
383362306a36Sopenharmony_ci		i++;
383462306a36Sopenharmony_ci		data[i] = adapter->rx_stats_buffers[j].bytes;
383562306a36Sopenharmony_ci		i++;
383662306a36Sopenharmony_ci		data[i] = adapter->rx_stats_buffers[j].interrupts;
383762306a36Sopenharmony_ci		i++;
383862306a36Sopenharmony_ci	}
383962306a36Sopenharmony_ci}
384062306a36Sopenharmony_ci
384162306a36Sopenharmony_cistatic const struct ethtool_ops ibmvnic_ethtool_ops = {
384262306a36Sopenharmony_ci	.get_drvinfo		= ibmvnic_get_drvinfo,
384362306a36Sopenharmony_ci	.get_msglevel		= ibmvnic_get_msglevel,
384462306a36Sopenharmony_ci	.set_msglevel		= ibmvnic_set_msglevel,
384562306a36Sopenharmony_ci	.get_link		= ibmvnic_get_link,
384662306a36Sopenharmony_ci	.get_ringparam		= ibmvnic_get_ringparam,
384762306a36Sopenharmony_ci	.set_ringparam		= ibmvnic_set_ringparam,
384862306a36Sopenharmony_ci	.get_channels		= ibmvnic_get_channels,
384962306a36Sopenharmony_ci	.set_channels		= ibmvnic_set_channels,
385062306a36Sopenharmony_ci	.get_strings            = ibmvnic_get_strings,
385162306a36Sopenharmony_ci	.get_sset_count         = ibmvnic_get_sset_count,
385262306a36Sopenharmony_ci	.get_ethtool_stats	= ibmvnic_get_ethtool_stats,
385362306a36Sopenharmony_ci	.get_link_ksettings	= ibmvnic_get_link_ksettings,
385462306a36Sopenharmony_ci};
385562306a36Sopenharmony_ci
385662306a36Sopenharmony_ci/* Routines for managing CRQs/sCRQs  */
385762306a36Sopenharmony_ci
385862306a36Sopenharmony_cistatic int reset_one_sub_crq_queue(struct ibmvnic_adapter *adapter,
385962306a36Sopenharmony_ci				   struct ibmvnic_sub_crq_queue *scrq)
386062306a36Sopenharmony_ci{
386162306a36Sopenharmony_ci	int rc;
386262306a36Sopenharmony_ci
386362306a36Sopenharmony_ci	if (!scrq) {
386462306a36Sopenharmony_ci		netdev_dbg(adapter->netdev, "Invalid scrq reset.\n");
386562306a36Sopenharmony_ci		return -EINVAL;
386662306a36Sopenharmony_ci	}
386762306a36Sopenharmony_ci
386862306a36Sopenharmony_ci	if (scrq->irq) {
386962306a36Sopenharmony_ci		free_irq(scrq->irq, scrq);
387062306a36Sopenharmony_ci		irq_dispose_mapping(scrq->irq);
387162306a36Sopenharmony_ci		scrq->irq = 0;
387262306a36Sopenharmony_ci	}
387362306a36Sopenharmony_ci
387462306a36Sopenharmony_ci	if (scrq->msgs) {
387562306a36Sopenharmony_ci		memset(scrq->msgs, 0, 4 * PAGE_SIZE);
387662306a36Sopenharmony_ci		atomic_set(&scrq->used, 0);
387762306a36Sopenharmony_ci		scrq->cur = 0;
387862306a36Sopenharmony_ci		scrq->ind_buf.index = 0;
387962306a36Sopenharmony_ci	} else {
388062306a36Sopenharmony_ci		netdev_dbg(adapter->netdev, "Invalid scrq reset\n");
388162306a36Sopenharmony_ci		return -EINVAL;
388262306a36Sopenharmony_ci	}
388362306a36Sopenharmony_ci
388462306a36Sopenharmony_ci	rc = h_reg_sub_crq(adapter->vdev->unit_address, scrq->msg_token,
388562306a36Sopenharmony_ci			   4 * PAGE_SIZE, &scrq->crq_num, &scrq->hw_irq);
388662306a36Sopenharmony_ci	return rc;
388762306a36Sopenharmony_ci}
388862306a36Sopenharmony_ci
388962306a36Sopenharmony_cistatic int reset_sub_crq_queues(struct ibmvnic_adapter *adapter)
389062306a36Sopenharmony_ci{
389162306a36Sopenharmony_ci	int i, rc;
389262306a36Sopenharmony_ci
389362306a36Sopenharmony_ci	if (!adapter->tx_scrq || !adapter->rx_scrq)
389462306a36Sopenharmony_ci		return -EINVAL;
389562306a36Sopenharmony_ci
389662306a36Sopenharmony_ci	ibmvnic_clean_affinity(adapter);
389762306a36Sopenharmony_ci
389862306a36Sopenharmony_ci	for (i = 0; i < adapter->req_tx_queues; i++) {
389962306a36Sopenharmony_ci		netdev_dbg(adapter->netdev, "Re-setting tx_scrq[%d]\n", i);
390062306a36Sopenharmony_ci		rc = reset_one_sub_crq_queue(adapter, adapter->tx_scrq[i]);
390162306a36Sopenharmony_ci		if (rc)
390262306a36Sopenharmony_ci			return rc;
390362306a36Sopenharmony_ci	}
390462306a36Sopenharmony_ci
390562306a36Sopenharmony_ci	for (i = 0; i < adapter->req_rx_queues; i++) {
390662306a36Sopenharmony_ci		netdev_dbg(adapter->netdev, "Re-setting rx_scrq[%d]\n", i);
390762306a36Sopenharmony_ci		rc = reset_one_sub_crq_queue(adapter, adapter->rx_scrq[i]);
390862306a36Sopenharmony_ci		if (rc)
390962306a36Sopenharmony_ci			return rc;
391062306a36Sopenharmony_ci	}
391162306a36Sopenharmony_ci
391262306a36Sopenharmony_ci	return rc;
391362306a36Sopenharmony_ci}
391462306a36Sopenharmony_ci
391562306a36Sopenharmony_cistatic void release_sub_crq_queue(struct ibmvnic_adapter *adapter,
391662306a36Sopenharmony_ci				  struct ibmvnic_sub_crq_queue *scrq,
391762306a36Sopenharmony_ci				  bool do_h_free)
391862306a36Sopenharmony_ci{
391962306a36Sopenharmony_ci	struct device *dev = &adapter->vdev->dev;
392062306a36Sopenharmony_ci	long rc;
392162306a36Sopenharmony_ci
392262306a36Sopenharmony_ci	netdev_dbg(adapter->netdev, "Releasing sub-CRQ\n");
392362306a36Sopenharmony_ci
392462306a36Sopenharmony_ci	if (do_h_free) {
392562306a36Sopenharmony_ci		/* Close the sub-crqs */
392662306a36Sopenharmony_ci		do {
392762306a36Sopenharmony_ci			rc = plpar_hcall_norets(H_FREE_SUB_CRQ,
392862306a36Sopenharmony_ci						adapter->vdev->unit_address,
392962306a36Sopenharmony_ci						scrq->crq_num);
393062306a36Sopenharmony_ci		} while (rc == H_BUSY || H_IS_LONG_BUSY(rc));
393162306a36Sopenharmony_ci
393262306a36Sopenharmony_ci		if (rc) {
393362306a36Sopenharmony_ci			netdev_err(adapter->netdev,
393462306a36Sopenharmony_ci				   "Failed to release sub-CRQ %16lx, rc = %ld\n",
393562306a36Sopenharmony_ci				   scrq->crq_num, rc);
393662306a36Sopenharmony_ci		}
393762306a36Sopenharmony_ci	}
393862306a36Sopenharmony_ci
393962306a36Sopenharmony_ci	dma_free_coherent(dev,
394062306a36Sopenharmony_ci			  IBMVNIC_IND_ARR_SZ,
394162306a36Sopenharmony_ci			  scrq->ind_buf.indir_arr,
394262306a36Sopenharmony_ci			  scrq->ind_buf.indir_dma);
394362306a36Sopenharmony_ci
394462306a36Sopenharmony_ci	dma_unmap_single(dev, scrq->msg_token, 4 * PAGE_SIZE,
394562306a36Sopenharmony_ci			 DMA_BIDIRECTIONAL);
394662306a36Sopenharmony_ci	free_pages((unsigned long)scrq->msgs, 2);
394762306a36Sopenharmony_ci	free_cpumask_var(scrq->affinity_mask);
394862306a36Sopenharmony_ci	kfree(scrq);
394962306a36Sopenharmony_ci}
395062306a36Sopenharmony_ci
395162306a36Sopenharmony_cistatic struct ibmvnic_sub_crq_queue *init_sub_crq_queue(struct ibmvnic_adapter
395262306a36Sopenharmony_ci							*adapter)
395362306a36Sopenharmony_ci{
395462306a36Sopenharmony_ci	struct device *dev = &adapter->vdev->dev;
395562306a36Sopenharmony_ci	struct ibmvnic_sub_crq_queue *scrq;
395662306a36Sopenharmony_ci	int rc;
395762306a36Sopenharmony_ci
395862306a36Sopenharmony_ci	scrq = kzalloc(sizeof(*scrq), GFP_KERNEL);
395962306a36Sopenharmony_ci	if (!scrq)
396062306a36Sopenharmony_ci		return NULL;
396162306a36Sopenharmony_ci
396262306a36Sopenharmony_ci	scrq->msgs =
396362306a36Sopenharmony_ci		(union sub_crq *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 2);
396462306a36Sopenharmony_ci	if (!scrq->msgs) {
396562306a36Sopenharmony_ci		dev_warn(dev, "Couldn't allocate crq queue messages page\n");
396662306a36Sopenharmony_ci		goto zero_page_failed;
396762306a36Sopenharmony_ci	}
396862306a36Sopenharmony_ci	if (!zalloc_cpumask_var(&scrq->affinity_mask, GFP_KERNEL))
396962306a36Sopenharmony_ci		goto cpumask_alloc_failed;
397062306a36Sopenharmony_ci
397162306a36Sopenharmony_ci	scrq->msg_token = dma_map_single(dev, scrq->msgs, 4 * PAGE_SIZE,
397262306a36Sopenharmony_ci					 DMA_BIDIRECTIONAL);
397362306a36Sopenharmony_ci	if (dma_mapping_error(dev, scrq->msg_token)) {
397462306a36Sopenharmony_ci		dev_warn(dev, "Couldn't map crq queue messages page\n");
397562306a36Sopenharmony_ci		goto map_failed;
397662306a36Sopenharmony_ci	}
397762306a36Sopenharmony_ci
397862306a36Sopenharmony_ci	rc = h_reg_sub_crq(adapter->vdev->unit_address, scrq->msg_token,
397962306a36Sopenharmony_ci			   4 * PAGE_SIZE, &scrq->crq_num, &scrq->hw_irq);
398062306a36Sopenharmony_ci
398162306a36Sopenharmony_ci	if (rc == H_RESOURCE)
398262306a36Sopenharmony_ci		rc = ibmvnic_reset_crq(adapter);
398362306a36Sopenharmony_ci
398462306a36Sopenharmony_ci	if (rc == H_CLOSED) {
398562306a36Sopenharmony_ci		dev_warn(dev, "Partner adapter not ready, waiting.\n");
398662306a36Sopenharmony_ci	} else if (rc) {
398762306a36Sopenharmony_ci		dev_warn(dev, "Error %d registering sub-crq\n", rc);
398862306a36Sopenharmony_ci		goto reg_failed;
398962306a36Sopenharmony_ci	}
399062306a36Sopenharmony_ci
399162306a36Sopenharmony_ci	scrq->adapter = adapter;
399262306a36Sopenharmony_ci	scrq->size = 4 * PAGE_SIZE / sizeof(*scrq->msgs);
399362306a36Sopenharmony_ci	scrq->ind_buf.index = 0;
399462306a36Sopenharmony_ci
399562306a36Sopenharmony_ci	scrq->ind_buf.indir_arr =
399662306a36Sopenharmony_ci		dma_alloc_coherent(dev,
399762306a36Sopenharmony_ci				   IBMVNIC_IND_ARR_SZ,
399862306a36Sopenharmony_ci				   &scrq->ind_buf.indir_dma,
399962306a36Sopenharmony_ci				   GFP_KERNEL);
400062306a36Sopenharmony_ci
400162306a36Sopenharmony_ci	if (!scrq->ind_buf.indir_arr)
400262306a36Sopenharmony_ci		goto indir_failed;
400362306a36Sopenharmony_ci
400462306a36Sopenharmony_ci	spin_lock_init(&scrq->lock);
400562306a36Sopenharmony_ci
400662306a36Sopenharmony_ci	netdev_dbg(adapter->netdev,
400762306a36Sopenharmony_ci		   "sub-crq initialized, num %lx, hw_irq=%lx, irq=%x\n",
400862306a36Sopenharmony_ci		   scrq->crq_num, scrq->hw_irq, scrq->irq);
400962306a36Sopenharmony_ci
401062306a36Sopenharmony_ci	return scrq;
401162306a36Sopenharmony_ci
401262306a36Sopenharmony_ciindir_failed:
401362306a36Sopenharmony_ci	do {
401462306a36Sopenharmony_ci		rc = plpar_hcall_norets(H_FREE_SUB_CRQ,
401562306a36Sopenharmony_ci					adapter->vdev->unit_address,
401662306a36Sopenharmony_ci					scrq->crq_num);
401762306a36Sopenharmony_ci	} while (rc == H_BUSY || rc == H_IS_LONG_BUSY(rc));
401862306a36Sopenharmony_cireg_failed:
401962306a36Sopenharmony_ci	dma_unmap_single(dev, scrq->msg_token, 4 * PAGE_SIZE,
402062306a36Sopenharmony_ci			 DMA_BIDIRECTIONAL);
402162306a36Sopenharmony_cimap_failed:
402262306a36Sopenharmony_ci	free_cpumask_var(scrq->affinity_mask);
402362306a36Sopenharmony_cicpumask_alloc_failed:
402462306a36Sopenharmony_ci	free_pages((unsigned long)scrq->msgs, 2);
402562306a36Sopenharmony_cizero_page_failed:
402662306a36Sopenharmony_ci	kfree(scrq);
402762306a36Sopenharmony_ci
402862306a36Sopenharmony_ci	return NULL;
402962306a36Sopenharmony_ci}
403062306a36Sopenharmony_ci
403162306a36Sopenharmony_cistatic void release_sub_crqs(struct ibmvnic_adapter *adapter, bool do_h_free)
403262306a36Sopenharmony_ci{
403362306a36Sopenharmony_ci	int i;
403462306a36Sopenharmony_ci
403562306a36Sopenharmony_ci	ibmvnic_clean_affinity(adapter);
403662306a36Sopenharmony_ci	if (adapter->tx_scrq) {
403762306a36Sopenharmony_ci		for (i = 0; i < adapter->num_active_tx_scrqs; i++) {
403862306a36Sopenharmony_ci			if (!adapter->tx_scrq[i])
403962306a36Sopenharmony_ci				continue;
404062306a36Sopenharmony_ci
404162306a36Sopenharmony_ci			netdev_dbg(adapter->netdev, "Releasing tx_scrq[%d]\n",
404262306a36Sopenharmony_ci				   i);
404362306a36Sopenharmony_ci			ibmvnic_tx_scrq_clean_buffer(adapter, adapter->tx_scrq[i]);
404462306a36Sopenharmony_ci			if (adapter->tx_scrq[i]->irq) {
404562306a36Sopenharmony_ci				free_irq(adapter->tx_scrq[i]->irq,
404662306a36Sopenharmony_ci					 adapter->tx_scrq[i]);
404762306a36Sopenharmony_ci				irq_dispose_mapping(adapter->tx_scrq[i]->irq);
404862306a36Sopenharmony_ci				adapter->tx_scrq[i]->irq = 0;
404962306a36Sopenharmony_ci			}
405062306a36Sopenharmony_ci
405162306a36Sopenharmony_ci			release_sub_crq_queue(adapter, adapter->tx_scrq[i],
405262306a36Sopenharmony_ci					      do_h_free);
405362306a36Sopenharmony_ci		}
405462306a36Sopenharmony_ci
405562306a36Sopenharmony_ci		kfree(adapter->tx_scrq);
405662306a36Sopenharmony_ci		adapter->tx_scrq = NULL;
405762306a36Sopenharmony_ci		adapter->num_active_tx_scrqs = 0;
405862306a36Sopenharmony_ci	}
405962306a36Sopenharmony_ci
406062306a36Sopenharmony_ci	if (adapter->rx_scrq) {
406162306a36Sopenharmony_ci		for (i = 0; i < adapter->num_active_rx_scrqs; i++) {
406262306a36Sopenharmony_ci			if (!adapter->rx_scrq[i])
406362306a36Sopenharmony_ci				continue;
406462306a36Sopenharmony_ci
406562306a36Sopenharmony_ci			netdev_dbg(adapter->netdev, "Releasing rx_scrq[%d]\n",
406662306a36Sopenharmony_ci				   i);
406762306a36Sopenharmony_ci			if (adapter->rx_scrq[i]->irq) {
406862306a36Sopenharmony_ci				free_irq(adapter->rx_scrq[i]->irq,
406962306a36Sopenharmony_ci					 adapter->rx_scrq[i]);
407062306a36Sopenharmony_ci				irq_dispose_mapping(adapter->rx_scrq[i]->irq);
407162306a36Sopenharmony_ci				adapter->rx_scrq[i]->irq = 0;
407262306a36Sopenharmony_ci			}
407362306a36Sopenharmony_ci
407462306a36Sopenharmony_ci			release_sub_crq_queue(adapter, adapter->rx_scrq[i],
407562306a36Sopenharmony_ci					      do_h_free);
407662306a36Sopenharmony_ci		}
407762306a36Sopenharmony_ci
407862306a36Sopenharmony_ci		kfree(adapter->rx_scrq);
407962306a36Sopenharmony_ci		adapter->rx_scrq = NULL;
408062306a36Sopenharmony_ci		adapter->num_active_rx_scrqs = 0;
408162306a36Sopenharmony_ci	}
408262306a36Sopenharmony_ci}
408362306a36Sopenharmony_ci
408462306a36Sopenharmony_cistatic int disable_scrq_irq(struct ibmvnic_adapter *adapter,
408562306a36Sopenharmony_ci			    struct ibmvnic_sub_crq_queue *scrq)
408662306a36Sopenharmony_ci{
408762306a36Sopenharmony_ci	struct device *dev = &adapter->vdev->dev;
408862306a36Sopenharmony_ci	unsigned long rc;
408962306a36Sopenharmony_ci
409062306a36Sopenharmony_ci	rc = plpar_hcall_norets(H_VIOCTL, adapter->vdev->unit_address,
409162306a36Sopenharmony_ci				H_DISABLE_VIO_INTERRUPT, scrq->hw_irq, 0, 0);
409262306a36Sopenharmony_ci	if (rc)
409362306a36Sopenharmony_ci		dev_err(dev, "Couldn't disable scrq irq 0x%lx. rc=%ld\n",
409462306a36Sopenharmony_ci			scrq->hw_irq, rc);
409562306a36Sopenharmony_ci	return rc;
409662306a36Sopenharmony_ci}
409762306a36Sopenharmony_ci
409862306a36Sopenharmony_ci/* We can not use the IRQ chip EOI handler because that has the
409962306a36Sopenharmony_ci * unintended effect of changing the interrupt priority.
410062306a36Sopenharmony_ci */
410162306a36Sopenharmony_cistatic void ibmvnic_xics_eoi(struct device *dev, struct ibmvnic_sub_crq_queue *scrq)
410262306a36Sopenharmony_ci{
410362306a36Sopenharmony_ci	u64 val = 0xff000000 | scrq->hw_irq;
410462306a36Sopenharmony_ci	unsigned long rc;
410562306a36Sopenharmony_ci
410662306a36Sopenharmony_ci	rc = plpar_hcall_norets(H_EOI, val);
410762306a36Sopenharmony_ci	if (rc)
410862306a36Sopenharmony_ci		dev_err(dev, "H_EOI FAILED irq 0x%llx. rc=%ld\n", val, rc);
410962306a36Sopenharmony_ci}
411062306a36Sopenharmony_ci
411162306a36Sopenharmony_ci/* Due to a firmware bug, the hypervisor can send an interrupt to a
411262306a36Sopenharmony_ci * transmit or receive queue just prior to a partition migration.
411362306a36Sopenharmony_ci * Force an EOI after migration.
411462306a36Sopenharmony_ci */
411562306a36Sopenharmony_cistatic void ibmvnic_clear_pending_interrupt(struct device *dev,
411662306a36Sopenharmony_ci					    struct ibmvnic_sub_crq_queue *scrq)
411762306a36Sopenharmony_ci{
411862306a36Sopenharmony_ci	if (!xive_enabled())
411962306a36Sopenharmony_ci		ibmvnic_xics_eoi(dev, scrq);
412062306a36Sopenharmony_ci}
412162306a36Sopenharmony_ci
412262306a36Sopenharmony_cistatic int enable_scrq_irq(struct ibmvnic_adapter *adapter,
412362306a36Sopenharmony_ci			   struct ibmvnic_sub_crq_queue *scrq)
412462306a36Sopenharmony_ci{
412562306a36Sopenharmony_ci	struct device *dev = &adapter->vdev->dev;
412662306a36Sopenharmony_ci	unsigned long rc;
412762306a36Sopenharmony_ci
412862306a36Sopenharmony_ci	if (scrq->hw_irq > 0x100000000ULL) {
412962306a36Sopenharmony_ci		dev_err(dev, "bad hw_irq = %lx\n", scrq->hw_irq);
413062306a36Sopenharmony_ci		return 1;
413162306a36Sopenharmony_ci	}
413262306a36Sopenharmony_ci
413362306a36Sopenharmony_ci	if (test_bit(0, &adapter->resetting) &&
413462306a36Sopenharmony_ci	    adapter->reset_reason == VNIC_RESET_MOBILITY) {
413562306a36Sopenharmony_ci		ibmvnic_clear_pending_interrupt(dev, scrq);
413662306a36Sopenharmony_ci	}
413762306a36Sopenharmony_ci
413862306a36Sopenharmony_ci	rc = plpar_hcall_norets(H_VIOCTL, adapter->vdev->unit_address,
413962306a36Sopenharmony_ci				H_ENABLE_VIO_INTERRUPT, scrq->hw_irq, 0, 0);
414062306a36Sopenharmony_ci	if (rc)
414162306a36Sopenharmony_ci		dev_err(dev, "Couldn't enable scrq irq 0x%lx. rc=%ld\n",
414262306a36Sopenharmony_ci			scrq->hw_irq, rc);
414362306a36Sopenharmony_ci	return rc;
414462306a36Sopenharmony_ci}
414562306a36Sopenharmony_ci
414662306a36Sopenharmony_cistatic int ibmvnic_complete_tx(struct ibmvnic_adapter *adapter,
414762306a36Sopenharmony_ci			       struct ibmvnic_sub_crq_queue *scrq)
414862306a36Sopenharmony_ci{
414962306a36Sopenharmony_ci	struct device *dev = &adapter->vdev->dev;
415062306a36Sopenharmony_ci	struct ibmvnic_tx_pool *tx_pool;
415162306a36Sopenharmony_ci	struct ibmvnic_tx_buff *txbuff;
415262306a36Sopenharmony_ci	struct netdev_queue *txq;
415362306a36Sopenharmony_ci	union sub_crq *next;
415462306a36Sopenharmony_ci	int index;
415562306a36Sopenharmony_ci	int i;
415662306a36Sopenharmony_ci
415762306a36Sopenharmony_cirestart_loop:
415862306a36Sopenharmony_ci	while (pending_scrq(adapter, scrq)) {
415962306a36Sopenharmony_ci		unsigned int pool = scrq->pool_index;
416062306a36Sopenharmony_ci		int num_entries = 0;
416162306a36Sopenharmony_ci		int total_bytes = 0;
416262306a36Sopenharmony_ci		int num_packets = 0;
416362306a36Sopenharmony_ci
416462306a36Sopenharmony_ci		next = ibmvnic_next_scrq(adapter, scrq);
416562306a36Sopenharmony_ci		for (i = 0; i < next->tx_comp.num_comps; i++) {
416662306a36Sopenharmony_ci			index = be32_to_cpu(next->tx_comp.correlators[i]);
416762306a36Sopenharmony_ci			if (index & IBMVNIC_TSO_POOL_MASK) {
416862306a36Sopenharmony_ci				tx_pool = &adapter->tso_pool[pool];
416962306a36Sopenharmony_ci				index &= ~IBMVNIC_TSO_POOL_MASK;
417062306a36Sopenharmony_ci			} else {
417162306a36Sopenharmony_ci				tx_pool = &adapter->tx_pool[pool];
417262306a36Sopenharmony_ci			}
417362306a36Sopenharmony_ci
417462306a36Sopenharmony_ci			txbuff = &tx_pool->tx_buff[index];
417562306a36Sopenharmony_ci			num_packets++;
417662306a36Sopenharmony_ci			num_entries += txbuff->num_entries;
417762306a36Sopenharmony_ci			if (txbuff->skb) {
417862306a36Sopenharmony_ci				total_bytes += txbuff->skb->len;
417962306a36Sopenharmony_ci				if (next->tx_comp.rcs[i]) {
418062306a36Sopenharmony_ci					dev_err(dev, "tx error %x\n",
418162306a36Sopenharmony_ci						next->tx_comp.rcs[i]);
418262306a36Sopenharmony_ci					dev_kfree_skb_irq(txbuff->skb);
418362306a36Sopenharmony_ci				} else {
418462306a36Sopenharmony_ci					dev_consume_skb_irq(txbuff->skb);
418562306a36Sopenharmony_ci				}
418662306a36Sopenharmony_ci				txbuff->skb = NULL;
418762306a36Sopenharmony_ci			} else {
418862306a36Sopenharmony_ci				netdev_warn(adapter->netdev,
418962306a36Sopenharmony_ci					    "TX completion received with NULL socket buffer\n");
419062306a36Sopenharmony_ci			}
419162306a36Sopenharmony_ci			tx_pool->free_map[tx_pool->producer_index] = index;
419262306a36Sopenharmony_ci			tx_pool->producer_index =
419362306a36Sopenharmony_ci				(tx_pool->producer_index + 1) %
419462306a36Sopenharmony_ci					tx_pool->num_buffers;
419562306a36Sopenharmony_ci		}
419662306a36Sopenharmony_ci		/* remove tx_comp scrq*/
419762306a36Sopenharmony_ci		next->tx_comp.first = 0;
419862306a36Sopenharmony_ci
419962306a36Sopenharmony_ci		txq = netdev_get_tx_queue(adapter->netdev, scrq->pool_index);
420062306a36Sopenharmony_ci		netdev_tx_completed_queue(txq, num_packets, total_bytes);
420162306a36Sopenharmony_ci
420262306a36Sopenharmony_ci		if (atomic_sub_return(num_entries, &scrq->used) <=
420362306a36Sopenharmony_ci		    (adapter->req_tx_entries_per_subcrq / 2) &&
420462306a36Sopenharmony_ci		    __netif_subqueue_stopped(adapter->netdev,
420562306a36Sopenharmony_ci					     scrq->pool_index)) {
420662306a36Sopenharmony_ci			rcu_read_lock();
420762306a36Sopenharmony_ci			if (adapter->tx_queues_active) {
420862306a36Sopenharmony_ci				netif_wake_subqueue(adapter->netdev,
420962306a36Sopenharmony_ci						    scrq->pool_index);
421062306a36Sopenharmony_ci				netdev_dbg(adapter->netdev,
421162306a36Sopenharmony_ci					   "Started queue %d\n",
421262306a36Sopenharmony_ci					   scrq->pool_index);
421362306a36Sopenharmony_ci			}
421462306a36Sopenharmony_ci			rcu_read_unlock();
421562306a36Sopenharmony_ci		}
421662306a36Sopenharmony_ci	}
421762306a36Sopenharmony_ci
421862306a36Sopenharmony_ci	enable_scrq_irq(adapter, scrq);
421962306a36Sopenharmony_ci
422062306a36Sopenharmony_ci	if (pending_scrq(adapter, scrq)) {
422162306a36Sopenharmony_ci		disable_scrq_irq(adapter, scrq);
422262306a36Sopenharmony_ci		goto restart_loop;
422362306a36Sopenharmony_ci	}
422462306a36Sopenharmony_ci
422562306a36Sopenharmony_ci	return 0;
422662306a36Sopenharmony_ci}
422762306a36Sopenharmony_ci
422862306a36Sopenharmony_cistatic irqreturn_t ibmvnic_interrupt_tx(int irq, void *instance)
422962306a36Sopenharmony_ci{
423062306a36Sopenharmony_ci	struct ibmvnic_sub_crq_queue *scrq = instance;
423162306a36Sopenharmony_ci	struct ibmvnic_adapter *adapter = scrq->adapter;
423262306a36Sopenharmony_ci
423362306a36Sopenharmony_ci	disable_scrq_irq(adapter, scrq);
423462306a36Sopenharmony_ci	ibmvnic_complete_tx(adapter, scrq);
423562306a36Sopenharmony_ci
423662306a36Sopenharmony_ci	return IRQ_HANDLED;
423762306a36Sopenharmony_ci}
423862306a36Sopenharmony_ci
423962306a36Sopenharmony_cistatic irqreturn_t ibmvnic_interrupt_rx(int irq, void *instance)
424062306a36Sopenharmony_ci{
424162306a36Sopenharmony_ci	struct ibmvnic_sub_crq_queue *scrq = instance;
424262306a36Sopenharmony_ci	struct ibmvnic_adapter *adapter = scrq->adapter;
424362306a36Sopenharmony_ci
424462306a36Sopenharmony_ci	/* When booting a kdump kernel we can hit pending interrupts
424562306a36Sopenharmony_ci	 * prior to completing driver initialization.
424662306a36Sopenharmony_ci	 */
424762306a36Sopenharmony_ci	if (unlikely(adapter->state != VNIC_OPEN))
424862306a36Sopenharmony_ci		return IRQ_NONE;
424962306a36Sopenharmony_ci
425062306a36Sopenharmony_ci	adapter->rx_stats_buffers[scrq->scrq_num].interrupts++;
425162306a36Sopenharmony_ci
425262306a36Sopenharmony_ci	if (napi_schedule_prep(&adapter->napi[scrq->scrq_num])) {
425362306a36Sopenharmony_ci		disable_scrq_irq(adapter, scrq);
425462306a36Sopenharmony_ci		__napi_schedule(&adapter->napi[scrq->scrq_num]);
425562306a36Sopenharmony_ci	}
425662306a36Sopenharmony_ci
425762306a36Sopenharmony_ci	return IRQ_HANDLED;
425862306a36Sopenharmony_ci}
425962306a36Sopenharmony_ci
426062306a36Sopenharmony_cistatic int init_sub_crq_irqs(struct ibmvnic_adapter *adapter)
426162306a36Sopenharmony_ci{
426262306a36Sopenharmony_ci	struct device *dev = &adapter->vdev->dev;
426362306a36Sopenharmony_ci	struct ibmvnic_sub_crq_queue *scrq;
426462306a36Sopenharmony_ci	int i = 0, j = 0;
426562306a36Sopenharmony_ci	int rc = 0;
426662306a36Sopenharmony_ci
426762306a36Sopenharmony_ci	for (i = 0; i < adapter->req_tx_queues; i++) {
426862306a36Sopenharmony_ci		netdev_dbg(adapter->netdev, "Initializing tx_scrq[%d] irq\n",
426962306a36Sopenharmony_ci			   i);
427062306a36Sopenharmony_ci		scrq = adapter->tx_scrq[i];
427162306a36Sopenharmony_ci		scrq->irq = irq_create_mapping(NULL, scrq->hw_irq);
427262306a36Sopenharmony_ci
427362306a36Sopenharmony_ci		if (!scrq->irq) {
427462306a36Sopenharmony_ci			rc = -EINVAL;
427562306a36Sopenharmony_ci			dev_err(dev, "Error mapping irq\n");
427662306a36Sopenharmony_ci			goto req_tx_irq_failed;
427762306a36Sopenharmony_ci		}
427862306a36Sopenharmony_ci
427962306a36Sopenharmony_ci		snprintf(scrq->name, sizeof(scrq->name), "ibmvnic-%x-tx%d",
428062306a36Sopenharmony_ci			 adapter->vdev->unit_address, i);
428162306a36Sopenharmony_ci		rc = request_irq(scrq->irq, ibmvnic_interrupt_tx,
428262306a36Sopenharmony_ci				 0, scrq->name, scrq);
428362306a36Sopenharmony_ci
428462306a36Sopenharmony_ci		if (rc) {
428562306a36Sopenharmony_ci			dev_err(dev, "Couldn't register tx irq 0x%x. rc=%d\n",
428662306a36Sopenharmony_ci				scrq->irq, rc);
428762306a36Sopenharmony_ci			irq_dispose_mapping(scrq->irq);
428862306a36Sopenharmony_ci			goto req_tx_irq_failed;
428962306a36Sopenharmony_ci		}
429062306a36Sopenharmony_ci	}
429162306a36Sopenharmony_ci
429262306a36Sopenharmony_ci	for (i = 0; i < adapter->req_rx_queues; i++) {
429362306a36Sopenharmony_ci		netdev_dbg(adapter->netdev, "Initializing rx_scrq[%d] irq\n",
429462306a36Sopenharmony_ci			   i);
429562306a36Sopenharmony_ci		scrq = adapter->rx_scrq[i];
429662306a36Sopenharmony_ci		scrq->irq = irq_create_mapping(NULL, scrq->hw_irq);
429762306a36Sopenharmony_ci		if (!scrq->irq) {
429862306a36Sopenharmony_ci			rc = -EINVAL;
429962306a36Sopenharmony_ci			dev_err(dev, "Error mapping irq\n");
430062306a36Sopenharmony_ci			goto req_rx_irq_failed;
430162306a36Sopenharmony_ci		}
430262306a36Sopenharmony_ci		snprintf(scrq->name, sizeof(scrq->name), "ibmvnic-%x-rx%d",
430362306a36Sopenharmony_ci			 adapter->vdev->unit_address, i);
430462306a36Sopenharmony_ci		rc = request_irq(scrq->irq, ibmvnic_interrupt_rx,
430562306a36Sopenharmony_ci				 0, scrq->name, scrq);
430662306a36Sopenharmony_ci		if (rc) {
430762306a36Sopenharmony_ci			dev_err(dev, "Couldn't register rx irq 0x%x. rc=%d\n",
430862306a36Sopenharmony_ci				scrq->irq, rc);
430962306a36Sopenharmony_ci			irq_dispose_mapping(scrq->irq);
431062306a36Sopenharmony_ci			goto req_rx_irq_failed;
431162306a36Sopenharmony_ci		}
431262306a36Sopenharmony_ci	}
431362306a36Sopenharmony_ci
431462306a36Sopenharmony_ci	cpus_read_lock();
431562306a36Sopenharmony_ci	ibmvnic_set_affinity(adapter);
431662306a36Sopenharmony_ci	cpus_read_unlock();
431762306a36Sopenharmony_ci
431862306a36Sopenharmony_ci	return rc;
431962306a36Sopenharmony_ci
432062306a36Sopenharmony_cireq_rx_irq_failed:
432162306a36Sopenharmony_ci	for (j = 0; j < i; j++) {
432262306a36Sopenharmony_ci		free_irq(adapter->rx_scrq[j]->irq, adapter->rx_scrq[j]);
432362306a36Sopenharmony_ci		irq_dispose_mapping(adapter->rx_scrq[j]->irq);
432462306a36Sopenharmony_ci	}
432562306a36Sopenharmony_ci	i = adapter->req_tx_queues;
432662306a36Sopenharmony_cireq_tx_irq_failed:
432762306a36Sopenharmony_ci	for (j = 0; j < i; j++) {
432862306a36Sopenharmony_ci		free_irq(adapter->tx_scrq[j]->irq, adapter->tx_scrq[j]);
432962306a36Sopenharmony_ci		irq_dispose_mapping(adapter->tx_scrq[j]->irq);
433062306a36Sopenharmony_ci	}
433162306a36Sopenharmony_ci	release_sub_crqs(adapter, 1);
433262306a36Sopenharmony_ci	return rc;
433362306a36Sopenharmony_ci}
433462306a36Sopenharmony_ci
433562306a36Sopenharmony_cistatic int init_sub_crqs(struct ibmvnic_adapter *adapter)
433662306a36Sopenharmony_ci{
433762306a36Sopenharmony_ci	struct device *dev = &adapter->vdev->dev;
433862306a36Sopenharmony_ci	struct ibmvnic_sub_crq_queue **allqueues;
433962306a36Sopenharmony_ci	int registered_queues = 0;
434062306a36Sopenharmony_ci	int total_queues;
434162306a36Sopenharmony_ci	int more = 0;
434262306a36Sopenharmony_ci	int i;
434362306a36Sopenharmony_ci
434462306a36Sopenharmony_ci	total_queues = adapter->req_tx_queues + adapter->req_rx_queues;
434562306a36Sopenharmony_ci
434662306a36Sopenharmony_ci	allqueues = kcalloc(total_queues, sizeof(*allqueues), GFP_KERNEL);
434762306a36Sopenharmony_ci	if (!allqueues)
434862306a36Sopenharmony_ci		return -ENOMEM;
434962306a36Sopenharmony_ci
435062306a36Sopenharmony_ci	for (i = 0; i < total_queues; i++) {
435162306a36Sopenharmony_ci		allqueues[i] = init_sub_crq_queue(adapter);
435262306a36Sopenharmony_ci		if (!allqueues[i]) {
435362306a36Sopenharmony_ci			dev_warn(dev, "Couldn't allocate all sub-crqs\n");
435462306a36Sopenharmony_ci			break;
435562306a36Sopenharmony_ci		}
435662306a36Sopenharmony_ci		registered_queues++;
435762306a36Sopenharmony_ci	}
435862306a36Sopenharmony_ci
435962306a36Sopenharmony_ci	/* Make sure we were able to register the minimum number of queues */
436062306a36Sopenharmony_ci	if (registered_queues <
436162306a36Sopenharmony_ci	    adapter->min_tx_queues + adapter->min_rx_queues) {
436262306a36Sopenharmony_ci		dev_err(dev, "Fatal: Couldn't init  min number of sub-crqs\n");
436362306a36Sopenharmony_ci		goto tx_failed;
436462306a36Sopenharmony_ci	}
436562306a36Sopenharmony_ci
436662306a36Sopenharmony_ci	/* Distribute the failed allocated queues*/
436762306a36Sopenharmony_ci	for (i = 0; i < total_queues - registered_queues + more ; i++) {
436862306a36Sopenharmony_ci		netdev_dbg(adapter->netdev, "Reducing number of queues\n");
436962306a36Sopenharmony_ci		switch (i % 3) {
437062306a36Sopenharmony_ci		case 0:
437162306a36Sopenharmony_ci			if (adapter->req_rx_queues > adapter->min_rx_queues)
437262306a36Sopenharmony_ci				adapter->req_rx_queues--;
437362306a36Sopenharmony_ci			else
437462306a36Sopenharmony_ci				more++;
437562306a36Sopenharmony_ci			break;
437662306a36Sopenharmony_ci		case 1:
437762306a36Sopenharmony_ci			if (adapter->req_tx_queues > adapter->min_tx_queues)
437862306a36Sopenharmony_ci				adapter->req_tx_queues--;
437962306a36Sopenharmony_ci			else
438062306a36Sopenharmony_ci				more++;
438162306a36Sopenharmony_ci			break;
438262306a36Sopenharmony_ci		}
438362306a36Sopenharmony_ci	}
438462306a36Sopenharmony_ci
438562306a36Sopenharmony_ci	adapter->tx_scrq = kcalloc(adapter->req_tx_queues,
438662306a36Sopenharmony_ci				   sizeof(*adapter->tx_scrq), GFP_KERNEL);
438762306a36Sopenharmony_ci	if (!adapter->tx_scrq)
438862306a36Sopenharmony_ci		goto tx_failed;
438962306a36Sopenharmony_ci
439062306a36Sopenharmony_ci	for (i = 0; i < adapter->req_tx_queues; i++) {
439162306a36Sopenharmony_ci		adapter->tx_scrq[i] = allqueues[i];
439262306a36Sopenharmony_ci		adapter->tx_scrq[i]->pool_index = i;
439362306a36Sopenharmony_ci		adapter->num_active_tx_scrqs++;
439462306a36Sopenharmony_ci	}
439562306a36Sopenharmony_ci
439662306a36Sopenharmony_ci	adapter->rx_scrq = kcalloc(adapter->req_rx_queues,
439762306a36Sopenharmony_ci				   sizeof(*adapter->rx_scrq), GFP_KERNEL);
439862306a36Sopenharmony_ci	if (!adapter->rx_scrq)
439962306a36Sopenharmony_ci		goto rx_failed;
440062306a36Sopenharmony_ci
440162306a36Sopenharmony_ci	for (i = 0; i < adapter->req_rx_queues; i++) {
440262306a36Sopenharmony_ci		adapter->rx_scrq[i] = allqueues[i + adapter->req_tx_queues];
440362306a36Sopenharmony_ci		adapter->rx_scrq[i]->scrq_num = i;
440462306a36Sopenharmony_ci		adapter->num_active_rx_scrqs++;
440562306a36Sopenharmony_ci	}
440662306a36Sopenharmony_ci
440762306a36Sopenharmony_ci	kfree(allqueues);
440862306a36Sopenharmony_ci	return 0;
440962306a36Sopenharmony_ci
441062306a36Sopenharmony_cirx_failed:
441162306a36Sopenharmony_ci	kfree(adapter->tx_scrq);
441262306a36Sopenharmony_ci	adapter->tx_scrq = NULL;
441362306a36Sopenharmony_citx_failed:
441462306a36Sopenharmony_ci	for (i = 0; i < registered_queues; i++)
441562306a36Sopenharmony_ci		release_sub_crq_queue(adapter, allqueues[i], 1);
441662306a36Sopenharmony_ci	kfree(allqueues);
441762306a36Sopenharmony_ci	return -ENOMEM;
441862306a36Sopenharmony_ci}
441962306a36Sopenharmony_ci
442062306a36Sopenharmony_cistatic void send_request_cap(struct ibmvnic_adapter *adapter, int retry)
442162306a36Sopenharmony_ci{
442262306a36Sopenharmony_ci	struct device *dev = &adapter->vdev->dev;
442362306a36Sopenharmony_ci	union ibmvnic_crq crq;
442462306a36Sopenharmony_ci	int max_entries;
442562306a36Sopenharmony_ci	int cap_reqs;
442662306a36Sopenharmony_ci
442762306a36Sopenharmony_ci	/* We send out 6 or 7 REQUEST_CAPABILITY CRQs below (depending on
442862306a36Sopenharmony_ci	 * the PROMISC flag). Initialize this count upfront. When the tasklet
442962306a36Sopenharmony_ci	 * receives a response to all of these, it will send the next protocol
443062306a36Sopenharmony_ci	 * message (QUERY_IP_OFFLOAD).
443162306a36Sopenharmony_ci	 */
443262306a36Sopenharmony_ci	if (!(adapter->netdev->flags & IFF_PROMISC) ||
443362306a36Sopenharmony_ci	    adapter->promisc_supported)
443462306a36Sopenharmony_ci		cap_reqs = 7;
443562306a36Sopenharmony_ci	else
443662306a36Sopenharmony_ci		cap_reqs = 6;
443762306a36Sopenharmony_ci
443862306a36Sopenharmony_ci	if (!retry) {
443962306a36Sopenharmony_ci		/* Sub-CRQ entries are 32 byte long */
444062306a36Sopenharmony_ci		int entries_page = 4 * PAGE_SIZE / (sizeof(u64) * 4);
444162306a36Sopenharmony_ci
444262306a36Sopenharmony_ci		atomic_set(&adapter->running_cap_crqs, cap_reqs);
444362306a36Sopenharmony_ci
444462306a36Sopenharmony_ci		if (adapter->min_tx_entries_per_subcrq > entries_page ||
444562306a36Sopenharmony_ci		    adapter->min_rx_add_entries_per_subcrq > entries_page) {
444662306a36Sopenharmony_ci			dev_err(dev, "Fatal, invalid entries per sub-crq\n");
444762306a36Sopenharmony_ci			return;
444862306a36Sopenharmony_ci		}
444962306a36Sopenharmony_ci
445062306a36Sopenharmony_ci		if (adapter->desired.mtu)
445162306a36Sopenharmony_ci			adapter->req_mtu = adapter->desired.mtu;
445262306a36Sopenharmony_ci		else
445362306a36Sopenharmony_ci			adapter->req_mtu = adapter->netdev->mtu + ETH_HLEN;
445462306a36Sopenharmony_ci
445562306a36Sopenharmony_ci		if (!adapter->desired.tx_entries)
445662306a36Sopenharmony_ci			adapter->desired.tx_entries =
445762306a36Sopenharmony_ci					adapter->max_tx_entries_per_subcrq;
445862306a36Sopenharmony_ci		if (!adapter->desired.rx_entries)
445962306a36Sopenharmony_ci			adapter->desired.rx_entries =
446062306a36Sopenharmony_ci					adapter->max_rx_add_entries_per_subcrq;
446162306a36Sopenharmony_ci
446262306a36Sopenharmony_ci		max_entries = IBMVNIC_LTB_SET_SIZE /
446362306a36Sopenharmony_ci			      (adapter->req_mtu + IBMVNIC_BUFFER_HLEN);
446462306a36Sopenharmony_ci
446562306a36Sopenharmony_ci		if ((adapter->req_mtu + IBMVNIC_BUFFER_HLEN) *
446662306a36Sopenharmony_ci			adapter->desired.tx_entries > IBMVNIC_LTB_SET_SIZE) {
446762306a36Sopenharmony_ci			adapter->desired.tx_entries = max_entries;
446862306a36Sopenharmony_ci		}
446962306a36Sopenharmony_ci
447062306a36Sopenharmony_ci		if ((adapter->req_mtu + IBMVNIC_BUFFER_HLEN) *
447162306a36Sopenharmony_ci			adapter->desired.rx_entries > IBMVNIC_LTB_SET_SIZE) {
447262306a36Sopenharmony_ci			adapter->desired.rx_entries = max_entries;
447362306a36Sopenharmony_ci		}
447462306a36Sopenharmony_ci
447562306a36Sopenharmony_ci		if (adapter->desired.tx_entries)
447662306a36Sopenharmony_ci			adapter->req_tx_entries_per_subcrq =
447762306a36Sopenharmony_ci					adapter->desired.tx_entries;
447862306a36Sopenharmony_ci		else
447962306a36Sopenharmony_ci			adapter->req_tx_entries_per_subcrq =
448062306a36Sopenharmony_ci					adapter->max_tx_entries_per_subcrq;
448162306a36Sopenharmony_ci
448262306a36Sopenharmony_ci		if (adapter->desired.rx_entries)
448362306a36Sopenharmony_ci			adapter->req_rx_add_entries_per_subcrq =
448462306a36Sopenharmony_ci					adapter->desired.rx_entries;
448562306a36Sopenharmony_ci		else
448662306a36Sopenharmony_ci			adapter->req_rx_add_entries_per_subcrq =
448762306a36Sopenharmony_ci					adapter->max_rx_add_entries_per_subcrq;
448862306a36Sopenharmony_ci
448962306a36Sopenharmony_ci		if (adapter->desired.tx_queues)
449062306a36Sopenharmony_ci			adapter->req_tx_queues =
449162306a36Sopenharmony_ci					adapter->desired.tx_queues;
449262306a36Sopenharmony_ci		else
449362306a36Sopenharmony_ci			adapter->req_tx_queues =
449462306a36Sopenharmony_ci					adapter->opt_tx_comp_sub_queues;
449562306a36Sopenharmony_ci
449662306a36Sopenharmony_ci		if (adapter->desired.rx_queues)
449762306a36Sopenharmony_ci			adapter->req_rx_queues =
449862306a36Sopenharmony_ci					adapter->desired.rx_queues;
449962306a36Sopenharmony_ci		else
450062306a36Sopenharmony_ci			adapter->req_rx_queues =
450162306a36Sopenharmony_ci					adapter->opt_rx_comp_queues;
450262306a36Sopenharmony_ci
450362306a36Sopenharmony_ci		adapter->req_rx_add_queues = adapter->max_rx_add_queues;
450462306a36Sopenharmony_ci	} else {
450562306a36Sopenharmony_ci		atomic_add(cap_reqs, &adapter->running_cap_crqs);
450662306a36Sopenharmony_ci	}
450762306a36Sopenharmony_ci	memset(&crq, 0, sizeof(crq));
450862306a36Sopenharmony_ci	crq.request_capability.first = IBMVNIC_CRQ_CMD;
450962306a36Sopenharmony_ci	crq.request_capability.cmd = REQUEST_CAPABILITY;
451062306a36Sopenharmony_ci
451162306a36Sopenharmony_ci	crq.request_capability.capability = cpu_to_be16(REQ_TX_QUEUES);
451262306a36Sopenharmony_ci	crq.request_capability.number = cpu_to_be64(adapter->req_tx_queues);
451362306a36Sopenharmony_ci	cap_reqs--;
451462306a36Sopenharmony_ci	ibmvnic_send_crq(adapter, &crq);
451562306a36Sopenharmony_ci
451662306a36Sopenharmony_ci	crq.request_capability.capability = cpu_to_be16(REQ_RX_QUEUES);
451762306a36Sopenharmony_ci	crq.request_capability.number = cpu_to_be64(adapter->req_rx_queues);
451862306a36Sopenharmony_ci	cap_reqs--;
451962306a36Sopenharmony_ci	ibmvnic_send_crq(adapter, &crq);
452062306a36Sopenharmony_ci
452162306a36Sopenharmony_ci	crq.request_capability.capability = cpu_to_be16(REQ_RX_ADD_QUEUES);
452262306a36Sopenharmony_ci	crq.request_capability.number = cpu_to_be64(adapter->req_rx_add_queues);
452362306a36Sopenharmony_ci	cap_reqs--;
452462306a36Sopenharmony_ci	ibmvnic_send_crq(adapter, &crq);
452562306a36Sopenharmony_ci
452662306a36Sopenharmony_ci	crq.request_capability.capability =
452762306a36Sopenharmony_ci	    cpu_to_be16(REQ_TX_ENTRIES_PER_SUBCRQ);
452862306a36Sopenharmony_ci	crq.request_capability.number =
452962306a36Sopenharmony_ci	    cpu_to_be64(adapter->req_tx_entries_per_subcrq);
453062306a36Sopenharmony_ci	cap_reqs--;
453162306a36Sopenharmony_ci	ibmvnic_send_crq(adapter, &crq);
453262306a36Sopenharmony_ci
453362306a36Sopenharmony_ci	crq.request_capability.capability =
453462306a36Sopenharmony_ci	    cpu_to_be16(REQ_RX_ADD_ENTRIES_PER_SUBCRQ);
453562306a36Sopenharmony_ci	crq.request_capability.number =
453662306a36Sopenharmony_ci	    cpu_to_be64(adapter->req_rx_add_entries_per_subcrq);
453762306a36Sopenharmony_ci	cap_reqs--;
453862306a36Sopenharmony_ci	ibmvnic_send_crq(adapter, &crq);
453962306a36Sopenharmony_ci
454062306a36Sopenharmony_ci	crq.request_capability.capability = cpu_to_be16(REQ_MTU);
454162306a36Sopenharmony_ci	crq.request_capability.number = cpu_to_be64(adapter->req_mtu);
454262306a36Sopenharmony_ci	cap_reqs--;
454362306a36Sopenharmony_ci	ibmvnic_send_crq(adapter, &crq);
454462306a36Sopenharmony_ci
454562306a36Sopenharmony_ci	if (adapter->netdev->flags & IFF_PROMISC) {
454662306a36Sopenharmony_ci		if (adapter->promisc_supported) {
454762306a36Sopenharmony_ci			crq.request_capability.capability =
454862306a36Sopenharmony_ci			    cpu_to_be16(PROMISC_REQUESTED);
454962306a36Sopenharmony_ci			crq.request_capability.number = cpu_to_be64(1);
455062306a36Sopenharmony_ci			cap_reqs--;
455162306a36Sopenharmony_ci			ibmvnic_send_crq(adapter, &crq);
455262306a36Sopenharmony_ci		}
455362306a36Sopenharmony_ci	} else {
455462306a36Sopenharmony_ci		crq.request_capability.capability =
455562306a36Sopenharmony_ci		    cpu_to_be16(PROMISC_REQUESTED);
455662306a36Sopenharmony_ci		crq.request_capability.number = cpu_to_be64(0);
455762306a36Sopenharmony_ci		cap_reqs--;
455862306a36Sopenharmony_ci		ibmvnic_send_crq(adapter, &crq);
455962306a36Sopenharmony_ci	}
456062306a36Sopenharmony_ci
456162306a36Sopenharmony_ci	/* Keep at end to catch any discrepancy between expected and actual
456262306a36Sopenharmony_ci	 * CRQs sent.
456362306a36Sopenharmony_ci	 */
456462306a36Sopenharmony_ci	WARN_ON(cap_reqs != 0);
456562306a36Sopenharmony_ci}
456662306a36Sopenharmony_ci
456762306a36Sopenharmony_cistatic int pending_scrq(struct ibmvnic_adapter *adapter,
456862306a36Sopenharmony_ci			struct ibmvnic_sub_crq_queue *scrq)
456962306a36Sopenharmony_ci{
457062306a36Sopenharmony_ci	union sub_crq *entry = &scrq->msgs[scrq->cur];
457162306a36Sopenharmony_ci	int rc;
457262306a36Sopenharmony_ci
457362306a36Sopenharmony_ci	rc = !!(entry->generic.first & IBMVNIC_CRQ_CMD_RSP);
457462306a36Sopenharmony_ci
457562306a36Sopenharmony_ci	/* Ensure that the SCRQ valid flag is loaded prior to loading the
457662306a36Sopenharmony_ci	 * contents of the SCRQ descriptor
457762306a36Sopenharmony_ci	 */
457862306a36Sopenharmony_ci	dma_rmb();
457962306a36Sopenharmony_ci
458062306a36Sopenharmony_ci	return rc;
458162306a36Sopenharmony_ci}
458262306a36Sopenharmony_ci
458362306a36Sopenharmony_cistatic union sub_crq *ibmvnic_next_scrq(struct ibmvnic_adapter *adapter,
458462306a36Sopenharmony_ci					struct ibmvnic_sub_crq_queue *scrq)
458562306a36Sopenharmony_ci{
458662306a36Sopenharmony_ci	union sub_crq *entry;
458762306a36Sopenharmony_ci	unsigned long flags;
458862306a36Sopenharmony_ci
458962306a36Sopenharmony_ci	spin_lock_irqsave(&scrq->lock, flags);
459062306a36Sopenharmony_ci	entry = &scrq->msgs[scrq->cur];
459162306a36Sopenharmony_ci	if (entry->generic.first & IBMVNIC_CRQ_CMD_RSP) {
459262306a36Sopenharmony_ci		if (++scrq->cur == scrq->size)
459362306a36Sopenharmony_ci			scrq->cur = 0;
459462306a36Sopenharmony_ci	} else {
459562306a36Sopenharmony_ci		entry = NULL;
459662306a36Sopenharmony_ci	}
459762306a36Sopenharmony_ci	spin_unlock_irqrestore(&scrq->lock, flags);
459862306a36Sopenharmony_ci
459962306a36Sopenharmony_ci	/* Ensure that the SCRQ valid flag is loaded prior to loading the
460062306a36Sopenharmony_ci	 * contents of the SCRQ descriptor
460162306a36Sopenharmony_ci	 */
460262306a36Sopenharmony_ci	dma_rmb();
460362306a36Sopenharmony_ci
460462306a36Sopenharmony_ci	return entry;
460562306a36Sopenharmony_ci}
460662306a36Sopenharmony_ci
460762306a36Sopenharmony_cistatic union ibmvnic_crq *ibmvnic_next_crq(struct ibmvnic_adapter *adapter)
460862306a36Sopenharmony_ci{
460962306a36Sopenharmony_ci	struct ibmvnic_crq_queue *queue = &adapter->crq;
461062306a36Sopenharmony_ci	union ibmvnic_crq *crq;
461162306a36Sopenharmony_ci
461262306a36Sopenharmony_ci	crq = &queue->msgs[queue->cur];
461362306a36Sopenharmony_ci	if (crq->generic.first & IBMVNIC_CRQ_CMD_RSP) {
461462306a36Sopenharmony_ci		if (++queue->cur == queue->size)
461562306a36Sopenharmony_ci			queue->cur = 0;
461662306a36Sopenharmony_ci	} else {
461762306a36Sopenharmony_ci		crq = NULL;
461862306a36Sopenharmony_ci	}
461962306a36Sopenharmony_ci
462062306a36Sopenharmony_ci	return crq;
462162306a36Sopenharmony_ci}
462262306a36Sopenharmony_ci
462362306a36Sopenharmony_cistatic void print_subcrq_error(struct device *dev, int rc, const char *func)
462462306a36Sopenharmony_ci{
462562306a36Sopenharmony_ci	switch (rc) {
462662306a36Sopenharmony_ci	case H_PARAMETER:
462762306a36Sopenharmony_ci		dev_warn_ratelimited(dev,
462862306a36Sopenharmony_ci				     "%s failed: Send request is malformed or adapter failover pending. (rc=%d)\n",
462962306a36Sopenharmony_ci				     func, rc);
463062306a36Sopenharmony_ci		break;
463162306a36Sopenharmony_ci	case H_CLOSED:
463262306a36Sopenharmony_ci		dev_warn_ratelimited(dev,
463362306a36Sopenharmony_ci				     "%s failed: Backing queue closed. Adapter is down or failover pending. (rc=%d)\n",
463462306a36Sopenharmony_ci				     func, rc);
463562306a36Sopenharmony_ci		break;
463662306a36Sopenharmony_ci	default:
463762306a36Sopenharmony_ci		dev_err_ratelimited(dev, "%s failed: (rc=%d)\n", func, rc);
463862306a36Sopenharmony_ci		break;
463962306a36Sopenharmony_ci	}
464062306a36Sopenharmony_ci}
464162306a36Sopenharmony_ci
464262306a36Sopenharmony_cistatic int send_subcrq_indirect(struct ibmvnic_adapter *adapter,
464362306a36Sopenharmony_ci				u64 remote_handle, u64 ioba, u64 num_entries)
464462306a36Sopenharmony_ci{
464562306a36Sopenharmony_ci	unsigned int ua = adapter->vdev->unit_address;
464662306a36Sopenharmony_ci	struct device *dev = &adapter->vdev->dev;
464762306a36Sopenharmony_ci	int rc;
464862306a36Sopenharmony_ci
464962306a36Sopenharmony_ci	/* Make sure the hypervisor sees the complete request */
465062306a36Sopenharmony_ci	dma_wmb();
465162306a36Sopenharmony_ci	rc = plpar_hcall_norets(H_SEND_SUB_CRQ_INDIRECT, ua,
465262306a36Sopenharmony_ci				cpu_to_be64(remote_handle),
465362306a36Sopenharmony_ci				ioba, num_entries);
465462306a36Sopenharmony_ci
465562306a36Sopenharmony_ci	if (rc)
465662306a36Sopenharmony_ci		print_subcrq_error(dev, rc, __func__);
465762306a36Sopenharmony_ci
465862306a36Sopenharmony_ci	return rc;
465962306a36Sopenharmony_ci}
466062306a36Sopenharmony_ci
466162306a36Sopenharmony_cistatic int ibmvnic_send_crq(struct ibmvnic_adapter *adapter,
466262306a36Sopenharmony_ci			    union ibmvnic_crq *crq)
466362306a36Sopenharmony_ci{
466462306a36Sopenharmony_ci	unsigned int ua = adapter->vdev->unit_address;
466562306a36Sopenharmony_ci	struct device *dev = &adapter->vdev->dev;
466662306a36Sopenharmony_ci	u64 *u64_crq = (u64 *)crq;
466762306a36Sopenharmony_ci	int rc;
466862306a36Sopenharmony_ci
466962306a36Sopenharmony_ci	netdev_dbg(adapter->netdev, "Sending CRQ: %016lx %016lx\n",
467062306a36Sopenharmony_ci		   (unsigned long)cpu_to_be64(u64_crq[0]),
467162306a36Sopenharmony_ci		   (unsigned long)cpu_to_be64(u64_crq[1]));
467262306a36Sopenharmony_ci
467362306a36Sopenharmony_ci	if (!adapter->crq.active &&
467462306a36Sopenharmony_ci	    crq->generic.first != IBMVNIC_CRQ_INIT_CMD) {
467562306a36Sopenharmony_ci		dev_warn(dev, "Invalid request detected while CRQ is inactive, possible device state change during reset\n");
467662306a36Sopenharmony_ci		return -EINVAL;
467762306a36Sopenharmony_ci	}
467862306a36Sopenharmony_ci
467962306a36Sopenharmony_ci	/* Make sure the hypervisor sees the complete request */
468062306a36Sopenharmony_ci	dma_wmb();
468162306a36Sopenharmony_ci
468262306a36Sopenharmony_ci	rc = plpar_hcall_norets(H_SEND_CRQ, ua,
468362306a36Sopenharmony_ci				cpu_to_be64(u64_crq[0]),
468462306a36Sopenharmony_ci				cpu_to_be64(u64_crq[1]));
468562306a36Sopenharmony_ci
468662306a36Sopenharmony_ci	if (rc) {
468762306a36Sopenharmony_ci		if (rc == H_CLOSED) {
468862306a36Sopenharmony_ci			dev_warn(dev, "CRQ Queue closed\n");
468962306a36Sopenharmony_ci			/* do not reset, report the fail, wait for passive init from server */
469062306a36Sopenharmony_ci		}
469162306a36Sopenharmony_ci
469262306a36Sopenharmony_ci		dev_warn(dev, "Send error (rc=%d)\n", rc);
469362306a36Sopenharmony_ci	}
469462306a36Sopenharmony_ci
469562306a36Sopenharmony_ci	return rc;
469662306a36Sopenharmony_ci}
469762306a36Sopenharmony_ci
469862306a36Sopenharmony_cistatic int ibmvnic_send_crq_init(struct ibmvnic_adapter *adapter)
469962306a36Sopenharmony_ci{
470062306a36Sopenharmony_ci	struct device *dev = &adapter->vdev->dev;
470162306a36Sopenharmony_ci	union ibmvnic_crq crq;
470262306a36Sopenharmony_ci	int retries = 100;
470362306a36Sopenharmony_ci	int rc;
470462306a36Sopenharmony_ci
470562306a36Sopenharmony_ci	memset(&crq, 0, sizeof(crq));
470662306a36Sopenharmony_ci	crq.generic.first = IBMVNIC_CRQ_INIT_CMD;
470762306a36Sopenharmony_ci	crq.generic.cmd = IBMVNIC_CRQ_INIT;
470862306a36Sopenharmony_ci	netdev_dbg(adapter->netdev, "Sending CRQ init\n");
470962306a36Sopenharmony_ci
471062306a36Sopenharmony_ci	do {
471162306a36Sopenharmony_ci		rc = ibmvnic_send_crq(adapter, &crq);
471262306a36Sopenharmony_ci		if (rc != H_CLOSED)
471362306a36Sopenharmony_ci			break;
471462306a36Sopenharmony_ci		retries--;
471562306a36Sopenharmony_ci		msleep(50);
471662306a36Sopenharmony_ci
471762306a36Sopenharmony_ci	} while (retries > 0);
471862306a36Sopenharmony_ci
471962306a36Sopenharmony_ci	if (rc) {
472062306a36Sopenharmony_ci		dev_err(dev, "Failed to send init request, rc = %d\n", rc);
472162306a36Sopenharmony_ci		return rc;
472262306a36Sopenharmony_ci	}
472362306a36Sopenharmony_ci
472462306a36Sopenharmony_ci	return 0;
472562306a36Sopenharmony_ci}
472662306a36Sopenharmony_ci
472762306a36Sopenharmony_cistruct vnic_login_client_data {
472862306a36Sopenharmony_ci	u8	type;
472962306a36Sopenharmony_ci	__be16	len;
473062306a36Sopenharmony_ci	char	name[];
473162306a36Sopenharmony_ci} __packed;
473262306a36Sopenharmony_ci
473362306a36Sopenharmony_cistatic int vnic_client_data_len(struct ibmvnic_adapter *adapter)
473462306a36Sopenharmony_ci{
473562306a36Sopenharmony_ci	int len;
473662306a36Sopenharmony_ci
473762306a36Sopenharmony_ci	/* Calculate the amount of buffer space needed for the
473862306a36Sopenharmony_ci	 * vnic client data in the login buffer. There are four entries,
473962306a36Sopenharmony_ci	 * OS name, LPAR name, device name, and a null last entry.
474062306a36Sopenharmony_ci	 */
474162306a36Sopenharmony_ci	len = 4 * sizeof(struct vnic_login_client_data);
474262306a36Sopenharmony_ci	len += 6; /* "Linux" plus NULL */
474362306a36Sopenharmony_ci	len += strlen(utsname()->nodename) + 1;
474462306a36Sopenharmony_ci	len += strlen(adapter->netdev->name) + 1;
474562306a36Sopenharmony_ci
474662306a36Sopenharmony_ci	return len;
474762306a36Sopenharmony_ci}
474862306a36Sopenharmony_ci
474962306a36Sopenharmony_cistatic void vnic_add_client_data(struct ibmvnic_adapter *adapter,
475062306a36Sopenharmony_ci				 struct vnic_login_client_data *vlcd)
475162306a36Sopenharmony_ci{
475262306a36Sopenharmony_ci	const char *os_name = "Linux";
475362306a36Sopenharmony_ci	int len;
475462306a36Sopenharmony_ci
475562306a36Sopenharmony_ci	/* Type 1 - LPAR OS */
475662306a36Sopenharmony_ci	vlcd->type = 1;
475762306a36Sopenharmony_ci	len = strlen(os_name) + 1;
475862306a36Sopenharmony_ci	vlcd->len = cpu_to_be16(len);
475962306a36Sopenharmony_ci	strscpy(vlcd->name, os_name, len);
476062306a36Sopenharmony_ci	vlcd = (struct vnic_login_client_data *)(vlcd->name + len);
476162306a36Sopenharmony_ci
476262306a36Sopenharmony_ci	/* Type 2 - LPAR name */
476362306a36Sopenharmony_ci	vlcd->type = 2;
476462306a36Sopenharmony_ci	len = strlen(utsname()->nodename) + 1;
476562306a36Sopenharmony_ci	vlcd->len = cpu_to_be16(len);
476662306a36Sopenharmony_ci	strscpy(vlcd->name, utsname()->nodename, len);
476762306a36Sopenharmony_ci	vlcd = (struct vnic_login_client_data *)(vlcd->name + len);
476862306a36Sopenharmony_ci
476962306a36Sopenharmony_ci	/* Type 3 - device name */
477062306a36Sopenharmony_ci	vlcd->type = 3;
477162306a36Sopenharmony_ci	len = strlen(adapter->netdev->name) + 1;
477262306a36Sopenharmony_ci	vlcd->len = cpu_to_be16(len);
477362306a36Sopenharmony_ci	strscpy(vlcd->name, adapter->netdev->name, len);
477462306a36Sopenharmony_ci}
477562306a36Sopenharmony_ci
477662306a36Sopenharmony_cistatic int send_login(struct ibmvnic_adapter *adapter)
477762306a36Sopenharmony_ci{
477862306a36Sopenharmony_ci	struct ibmvnic_login_rsp_buffer *login_rsp_buffer;
477962306a36Sopenharmony_ci	struct ibmvnic_login_buffer *login_buffer;
478062306a36Sopenharmony_ci	struct device *dev = &adapter->vdev->dev;
478162306a36Sopenharmony_ci	struct vnic_login_client_data *vlcd;
478262306a36Sopenharmony_ci	dma_addr_t rsp_buffer_token;
478362306a36Sopenharmony_ci	dma_addr_t buffer_token;
478462306a36Sopenharmony_ci	size_t rsp_buffer_size;
478562306a36Sopenharmony_ci	union ibmvnic_crq crq;
478662306a36Sopenharmony_ci	int client_data_len;
478762306a36Sopenharmony_ci	size_t buffer_size;
478862306a36Sopenharmony_ci	__be64 *tx_list_p;
478962306a36Sopenharmony_ci	__be64 *rx_list_p;
479062306a36Sopenharmony_ci	int rc;
479162306a36Sopenharmony_ci	int i;
479262306a36Sopenharmony_ci
479362306a36Sopenharmony_ci	if (!adapter->tx_scrq || !adapter->rx_scrq) {
479462306a36Sopenharmony_ci		netdev_err(adapter->netdev,
479562306a36Sopenharmony_ci			   "RX or TX queues are not allocated, device login failed\n");
479662306a36Sopenharmony_ci		return -ENOMEM;
479762306a36Sopenharmony_ci	}
479862306a36Sopenharmony_ci
479962306a36Sopenharmony_ci	release_login_buffer(adapter);
480062306a36Sopenharmony_ci	release_login_rsp_buffer(adapter);
480162306a36Sopenharmony_ci
480262306a36Sopenharmony_ci	client_data_len = vnic_client_data_len(adapter);
480362306a36Sopenharmony_ci
480462306a36Sopenharmony_ci	buffer_size =
480562306a36Sopenharmony_ci	    sizeof(struct ibmvnic_login_buffer) +
480662306a36Sopenharmony_ci	    sizeof(u64) * (adapter->req_tx_queues + adapter->req_rx_queues) +
480762306a36Sopenharmony_ci	    client_data_len;
480862306a36Sopenharmony_ci
480962306a36Sopenharmony_ci	login_buffer = kzalloc(buffer_size, GFP_ATOMIC);
481062306a36Sopenharmony_ci	if (!login_buffer)
481162306a36Sopenharmony_ci		goto buf_alloc_failed;
481262306a36Sopenharmony_ci
481362306a36Sopenharmony_ci	buffer_token = dma_map_single(dev, login_buffer, buffer_size,
481462306a36Sopenharmony_ci				      DMA_TO_DEVICE);
481562306a36Sopenharmony_ci	if (dma_mapping_error(dev, buffer_token)) {
481662306a36Sopenharmony_ci		dev_err(dev, "Couldn't map login buffer\n");
481762306a36Sopenharmony_ci		goto buf_map_failed;
481862306a36Sopenharmony_ci	}
481962306a36Sopenharmony_ci
482062306a36Sopenharmony_ci	rsp_buffer_size = sizeof(struct ibmvnic_login_rsp_buffer) +
482162306a36Sopenharmony_ci			  sizeof(u64) * adapter->req_tx_queues +
482262306a36Sopenharmony_ci			  sizeof(u64) * adapter->req_rx_queues +
482362306a36Sopenharmony_ci			  sizeof(u64) * adapter->req_rx_queues +
482462306a36Sopenharmony_ci			  sizeof(u8) * IBMVNIC_TX_DESC_VERSIONS;
482562306a36Sopenharmony_ci
482662306a36Sopenharmony_ci	login_rsp_buffer = kmalloc(rsp_buffer_size, GFP_ATOMIC);
482762306a36Sopenharmony_ci	if (!login_rsp_buffer)
482862306a36Sopenharmony_ci		goto buf_rsp_alloc_failed;
482962306a36Sopenharmony_ci
483062306a36Sopenharmony_ci	rsp_buffer_token = dma_map_single(dev, login_rsp_buffer,
483162306a36Sopenharmony_ci					  rsp_buffer_size, DMA_FROM_DEVICE);
483262306a36Sopenharmony_ci	if (dma_mapping_error(dev, rsp_buffer_token)) {
483362306a36Sopenharmony_ci		dev_err(dev, "Couldn't map login rsp buffer\n");
483462306a36Sopenharmony_ci		goto buf_rsp_map_failed;
483562306a36Sopenharmony_ci	}
483662306a36Sopenharmony_ci
483762306a36Sopenharmony_ci	adapter->login_buf = login_buffer;
483862306a36Sopenharmony_ci	adapter->login_buf_token = buffer_token;
483962306a36Sopenharmony_ci	adapter->login_buf_sz = buffer_size;
484062306a36Sopenharmony_ci	adapter->login_rsp_buf = login_rsp_buffer;
484162306a36Sopenharmony_ci	adapter->login_rsp_buf_token = rsp_buffer_token;
484262306a36Sopenharmony_ci	adapter->login_rsp_buf_sz = rsp_buffer_size;
484362306a36Sopenharmony_ci
484462306a36Sopenharmony_ci	login_buffer->len = cpu_to_be32(buffer_size);
484562306a36Sopenharmony_ci	login_buffer->version = cpu_to_be32(INITIAL_VERSION_LB);
484662306a36Sopenharmony_ci	login_buffer->num_txcomp_subcrqs = cpu_to_be32(adapter->req_tx_queues);
484762306a36Sopenharmony_ci	login_buffer->off_txcomp_subcrqs =
484862306a36Sopenharmony_ci	    cpu_to_be32(sizeof(struct ibmvnic_login_buffer));
484962306a36Sopenharmony_ci	login_buffer->num_rxcomp_subcrqs = cpu_to_be32(adapter->req_rx_queues);
485062306a36Sopenharmony_ci	login_buffer->off_rxcomp_subcrqs =
485162306a36Sopenharmony_ci	    cpu_to_be32(sizeof(struct ibmvnic_login_buffer) +
485262306a36Sopenharmony_ci			sizeof(u64) * adapter->req_tx_queues);
485362306a36Sopenharmony_ci	login_buffer->login_rsp_ioba = cpu_to_be32(rsp_buffer_token);
485462306a36Sopenharmony_ci	login_buffer->login_rsp_len = cpu_to_be32(rsp_buffer_size);
485562306a36Sopenharmony_ci
485662306a36Sopenharmony_ci	tx_list_p = (__be64 *)((char *)login_buffer +
485762306a36Sopenharmony_ci				      sizeof(struct ibmvnic_login_buffer));
485862306a36Sopenharmony_ci	rx_list_p = (__be64 *)((char *)login_buffer +
485962306a36Sopenharmony_ci				      sizeof(struct ibmvnic_login_buffer) +
486062306a36Sopenharmony_ci				      sizeof(u64) * adapter->req_tx_queues);
486162306a36Sopenharmony_ci
486262306a36Sopenharmony_ci	for (i = 0; i < adapter->req_tx_queues; i++) {
486362306a36Sopenharmony_ci		if (adapter->tx_scrq[i]) {
486462306a36Sopenharmony_ci			tx_list_p[i] =
486562306a36Sopenharmony_ci				cpu_to_be64(adapter->tx_scrq[i]->crq_num);
486662306a36Sopenharmony_ci		}
486762306a36Sopenharmony_ci	}
486862306a36Sopenharmony_ci
486962306a36Sopenharmony_ci	for (i = 0; i < adapter->req_rx_queues; i++) {
487062306a36Sopenharmony_ci		if (adapter->rx_scrq[i]) {
487162306a36Sopenharmony_ci			rx_list_p[i] =
487262306a36Sopenharmony_ci				cpu_to_be64(adapter->rx_scrq[i]->crq_num);
487362306a36Sopenharmony_ci		}
487462306a36Sopenharmony_ci	}
487562306a36Sopenharmony_ci
487662306a36Sopenharmony_ci	/* Insert vNIC login client data */
487762306a36Sopenharmony_ci	vlcd = (struct vnic_login_client_data *)
487862306a36Sopenharmony_ci		((char *)rx_list_p + (sizeof(u64) * adapter->req_rx_queues));
487962306a36Sopenharmony_ci	login_buffer->client_data_offset =
488062306a36Sopenharmony_ci			cpu_to_be32((char *)vlcd - (char *)login_buffer);
488162306a36Sopenharmony_ci	login_buffer->client_data_len = cpu_to_be32(client_data_len);
488262306a36Sopenharmony_ci
488362306a36Sopenharmony_ci	vnic_add_client_data(adapter, vlcd);
488462306a36Sopenharmony_ci
488562306a36Sopenharmony_ci	netdev_dbg(adapter->netdev, "Login Buffer:\n");
488662306a36Sopenharmony_ci	for (i = 0; i < (adapter->login_buf_sz - 1) / 8 + 1; i++) {
488762306a36Sopenharmony_ci		netdev_dbg(adapter->netdev, "%016lx\n",
488862306a36Sopenharmony_ci			   ((unsigned long *)(adapter->login_buf))[i]);
488962306a36Sopenharmony_ci	}
489062306a36Sopenharmony_ci
489162306a36Sopenharmony_ci	memset(&crq, 0, sizeof(crq));
489262306a36Sopenharmony_ci	crq.login.first = IBMVNIC_CRQ_CMD;
489362306a36Sopenharmony_ci	crq.login.cmd = LOGIN;
489462306a36Sopenharmony_ci	crq.login.ioba = cpu_to_be32(buffer_token);
489562306a36Sopenharmony_ci	crq.login.len = cpu_to_be32(buffer_size);
489662306a36Sopenharmony_ci
489762306a36Sopenharmony_ci	adapter->login_pending = true;
489862306a36Sopenharmony_ci	rc = ibmvnic_send_crq(adapter, &crq);
489962306a36Sopenharmony_ci	if (rc) {
490062306a36Sopenharmony_ci		adapter->login_pending = false;
490162306a36Sopenharmony_ci		netdev_err(adapter->netdev, "Failed to send login, rc=%d\n", rc);
490262306a36Sopenharmony_ci		goto buf_send_failed;
490362306a36Sopenharmony_ci	}
490462306a36Sopenharmony_ci
490562306a36Sopenharmony_ci	return 0;
490662306a36Sopenharmony_ci
490762306a36Sopenharmony_cibuf_send_failed:
490862306a36Sopenharmony_ci	dma_unmap_single(dev, rsp_buffer_token, rsp_buffer_size,
490962306a36Sopenharmony_ci			 DMA_FROM_DEVICE);
491062306a36Sopenharmony_cibuf_rsp_map_failed:
491162306a36Sopenharmony_ci	kfree(login_rsp_buffer);
491262306a36Sopenharmony_ci	adapter->login_rsp_buf = NULL;
491362306a36Sopenharmony_cibuf_rsp_alloc_failed:
491462306a36Sopenharmony_ci	dma_unmap_single(dev, buffer_token, buffer_size, DMA_TO_DEVICE);
491562306a36Sopenharmony_cibuf_map_failed:
491662306a36Sopenharmony_ci	kfree(login_buffer);
491762306a36Sopenharmony_ci	adapter->login_buf = NULL;
491862306a36Sopenharmony_cibuf_alloc_failed:
491962306a36Sopenharmony_ci	return -ENOMEM;
492062306a36Sopenharmony_ci}
492162306a36Sopenharmony_ci
492262306a36Sopenharmony_cistatic int send_request_map(struct ibmvnic_adapter *adapter, dma_addr_t addr,
492362306a36Sopenharmony_ci			    u32 len, u8 map_id)
492462306a36Sopenharmony_ci{
492562306a36Sopenharmony_ci	union ibmvnic_crq crq;
492662306a36Sopenharmony_ci
492762306a36Sopenharmony_ci	memset(&crq, 0, sizeof(crq));
492862306a36Sopenharmony_ci	crq.request_map.first = IBMVNIC_CRQ_CMD;
492962306a36Sopenharmony_ci	crq.request_map.cmd = REQUEST_MAP;
493062306a36Sopenharmony_ci	crq.request_map.map_id = map_id;
493162306a36Sopenharmony_ci	crq.request_map.ioba = cpu_to_be32(addr);
493262306a36Sopenharmony_ci	crq.request_map.len = cpu_to_be32(len);
493362306a36Sopenharmony_ci	return ibmvnic_send_crq(adapter, &crq);
493462306a36Sopenharmony_ci}
493562306a36Sopenharmony_ci
493662306a36Sopenharmony_cistatic int send_request_unmap(struct ibmvnic_adapter *adapter, u8 map_id)
493762306a36Sopenharmony_ci{
493862306a36Sopenharmony_ci	union ibmvnic_crq crq;
493962306a36Sopenharmony_ci
494062306a36Sopenharmony_ci	memset(&crq, 0, sizeof(crq));
494162306a36Sopenharmony_ci	crq.request_unmap.first = IBMVNIC_CRQ_CMD;
494262306a36Sopenharmony_ci	crq.request_unmap.cmd = REQUEST_UNMAP;
494362306a36Sopenharmony_ci	crq.request_unmap.map_id = map_id;
494462306a36Sopenharmony_ci	return ibmvnic_send_crq(adapter, &crq);
494562306a36Sopenharmony_ci}
494662306a36Sopenharmony_ci
494762306a36Sopenharmony_cistatic void send_query_map(struct ibmvnic_adapter *adapter)
494862306a36Sopenharmony_ci{
494962306a36Sopenharmony_ci	union ibmvnic_crq crq;
495062306a36Sopenharmony_ci
495162306a36Sopenharmony_ci	memset(&crq, 0, sizeof(crq));
495262306a36Sopenharmony_ci	crq.query_map.first = IBMVNIC_CRQ_CMD;
495362306a36Sopenharmony_ci	crq.query_map.cmd = QUERY_MAP;
495462306a36Sopenharmony_ci	ibmvnic_send_crq(adapter, &crq);
495562306a36Sopenharmony_ci}
495662306a36Sopenharmony_ci
495762306a36Sopenharmony_ci/* Send a series of CRQs requesting various capabilities of the VNIC server */
495862306a36Sopenharmony_cistatic void send_query_cap(struct ibmvnic_adapter *adapter)
495962306a36Sopenharmony_ci{
496062306a36Sopenharmony_ci	union ibmvnic_crq crq;
496162306a36Sopenharmony_ci	int cap_reqs;
496262306a36Sopenharmony_ci
496362306a36Sopenharmony_ci	/* We send out 25 QUERY_CAPABILITY CRQs below.  Initialize this count
496462306a36Sopenharmony_ci	 * upfront. When the tasklet receives a response to all of these, it
496562306a36Sopenharmony_ci	 * can send out the next protocol messaage (REQUEST_CAPABILITY).
496662306a36Sopenharmony_ci	 */
496762306a36Sopenharmony_ci	cap_reqs = 25;
496862306a36Sopenharmony_ci
496962306a36Sopenharmony_ci	atomic_set(&adapter->running_cap_crqs, cap_reqs);
497062306a36Sopenharmony_ci
497162306a36Sopenharmony_ci	memset(&crq, 0, sizeof(crq));
497262306a36Sopenharmony_ci	crq.query_capability.first = IBMVNIC_CRQ_CMD;
497362306a36Sopenharmony_ci	crq.query_capability.cmd = QUERY_CAPABILITY;
497462306a36Sopenharmony_ci
497562306a36Sopenharmony_ci	crq.query_capability.capability = cpu_to_be16(MIN_TX_QUEUES);
497662306a36Sopenharmony_ci	ibmvnic_send_crq(adapter, &crq);
497762306a36Sopenharmony_ci	cap_reqs--;
497862306a36Sopenharmony_ci
497962306a36Sopenharmony_ci	crq.query_capability.capability = cpu_to_be16(MIN_RX_QUEUES);
498062306a36Sopenharmony_ci	ibmvnic_send_crq(adapter, &crq);
498162306a36Sopenharmony_ci	cap_reqs--;
498262306a36Sopenharmony_ci
498362306a36Sopenharmony_ci	crq.query_capability.capability = cpu_to_be16(MIN_RX_ADD_QUEUES);
498462306a36Sopenharmony_ci	ibmvnic_send_crq(adapter, &crq);
498562306a36Sopenharmony_ci	cap_reqs--;
498662306a36Sopenharmony_ci
498762306a36Sopenharmony_ci	crq.query_capability.capability = cpu_to_be16(MAX_TX_QUEUES);
498862306a36Sopenharmony_ci	ibmvnic_send_crq(adapter, &crq);
498962306a36Sopenharmony_ci	cap_reqs--;
499062306a36Sopenharmony_ci
499162306a36Sopenharmony_ci	crq.query_capability.capability = cpu_to_be16(MAX_RX_QUEUES);
499262306a36Sopenharmony_ci	ibmvnic_send_crq(adapter, &crq);
499362306a36Sopenharmony_ci	cap_reqs--;
499462306a36Sopenharmony_ci
499562306a36Sopenharmony_ci	crq.query_capability.capability = cpu_to_be16(MAX_RX_ADD_QUEUES);
499662306a36Sopenharmony_ci	ibmvnic_send_crq(adapter, &crq);
499762306a36Sopenharmony_ci	cap_reqs--;
499862306a36Sopenharmony_ci
499962306a36Sopenharmony_ci	crq.query_capability.capability =
500062306a36Sopenharmony_ci	    cpu_to_be16(MIN_TX_ENTRIES_PER_SUBCRQ);
500162306a36Sopenharmony_ci	ibmvnic_send_crq(adapter, &crq);
500262306a36Sopenharmony_ci	cap_reqs--;
500362306a36Sopenharmony_ci
500462306a36Sopenharmony_ci	crq.query_capability.capability =
500562306a36Sopenharmony_ci	    cpu_to_be16(MIN_RX_ADD_ENTRIES_PER_SUBCRQ);
500662306a36Sopenharmony_ci	ibmvnic_send_crq(adapter, &crq);
500762306a36Sopenharmony_ci	cap_reqs--;
500862306a36Sopenharmony_ci
500962306a36Sopenharmony_ci	crq.query_capability.capability =
501062306a36Sopenharmony_ci	    cpu_to_be16(MAX_TX_ENTRIES_PER_SUBCRQ);
501162306a36Sopenharmony_ci	ibmvnic_send_crq(adapter, &crq);
501262306a36Sopenharmony_ci	cap_reqs--;
501362306a36Sopenharmony_ci
501462306a36Sopenharmony_ci	crq.query_capability.capability =
501562306a36Sopenharmony_ci	    cpu_to_be16(MAX_RX_ADD_ENTRIES_PER_SUBCRQ);
501662306a36Sopenharmony_ci	ibmvnic_send_crq(adapter, &crq);
501762306a36Sopenharmony_ci	cap_reqs--;
501862306a36Sopenharmony_ci
501962306a36Sopenharmony_ci	crq.query_capability.capability = cpu_to_be16(TCP_IP_OFFLOAD);
502062306a36Sopenharmony_ci	ibmvnic_send_crq(adapter, &crq);
502162306a36Sopenharmony_ci	cap_reqs--;
502262306a36Sopenharmony_ci
502362306a36Sopenharmony_ci	crq.query_capability.capability = cpu_to_be16(PROMISC_SUPPORTED);
502462306a36Sopenharmony_ci	ibmvnic_send_crq(adapter, &crq);
502562306a36Sopenharmony_ci	cap_reqs--;
502662306a36Sopenharmony_ci
502762306a36Sopenharmony_ci	crq.query_capability.capability = cpu_to_be16(MIN_MTU);
502862306a36Sopenharmony_ci	ibmvnic_send_crq(adapter, &crq);
502962306a36Sopenharmony_ci	cap_reqs--;
503062306a36Sopenharmony_ci
503162306a36Sopenharmony_ci	crq.query_capability.capability = cpu_to_be16(MAX_MTU);
503262306a36Sopenharmony_ci	ibmvnic_send_crq(adapter, &crq);
503362306a36Sopenharmony_ci	cap_reqs--;
503462306a36Sopenharmony_ci
503562306a36Sopenharmony_ci	crq.query_capability.capability = cpu_to_be16(MAX_MULTICAST_FILTERS);
503662306a36Sopenharmony_ci	ibmvnic_send_crq(adapter, &crq);
503762306a36Sopenharmony_ci	cap_reqs--;
503862306a36Sopenharmony_ci
503962306a36Sopenharmony_ci	crq.query_capability.capability = cpu_to_be16(VLAN_HEADER_INSERTION);
504062306a36Sopenharmony_ci	ibmvnic_send_crq(adapter, &crq);
504162306a36Sopenharmony_ci	cap_reqs--;
504262306a36Sopenharmony_ci
504362306a36Sopenharmony_ci	crq.query_capability.capability = cpu_to_be16(RX_VLAN_HEADER_INSERTION);
504462306a36Sopenharmony_ci	ibmvnic_send_crq(adapter, &crq);
504562306a36Sopenharmony_ci	cap_reqs--;
504662306a36Sopenharmony_ci
504762306a36Sopenharmony_ci	crq.query_capability.capability = cpu_to_be16(MAX_TX_SG_ENTRIES);
504862306a36Sopenharmony_ci	ibmvnic_send_crq(adapter, &crq);
504962306a36Sopenharmony_ci	cap_reqs--;
505062306a36Sopenharmony_ci
505162306a36Sopenharmony_ci	crq.query_capability.capability = cpu_to_be16(RX_SG_SUPPORTED);
505262306a36Sopenharmony_ci	ibmvnic_send_crq(adapter, &crq);
505362306a36Sopenharmony_ci	cap_reqs--;
505462306a36Sopenharmony_ci
505562306a36Sopenharmony_ci	crq.query_capability.capability = cpu_to_be16(OPT_TX_COMP_SUB_QUEUES);
505662306a36Sopenharmony_ci	ibmvnic_send_crq(adapter, &crq);
505762306a36Sopenharmony_ci	cap_reqs--;
505862306a36Sopenharmony_ci
505962306a36Sopenharmony_ci	crq.query_capability.capability = cpu_to_be16(OPT_RX_COMP_QUEUES);
506062306a36Sopenharmony_ci	ibmvnic_send_crq(adapter, &crq);
506162306a36Sopenharmony_ci	cap_reqs--;
506262306a36Sopenharmony_ci
506362306a36Sopenharmony_ci	crq.query_capability.capability =
506462306a36Sopenharmony_ci			cpu_to_be16(OPT_RX_BUFADD_Q_PER_RX_COMP_Q);
506562306a36Sopenharmony_ci	ibmvnic_send_crq(adapter, &crq);
506662306a36Sopenharmony_ci	cap_reqs--;
506762306a36Sopenharmony_ci
506862306a36Sopenharmony_ci	crq.query_capability.capability =
506962306a36Sopenharmony_ci			cpu_to_be16(OPT_TX_ENTRIES_PER_SUBCRQ);
507062306a36Sopenharmony_ci	ibmvnic_send_crq(adapter, &crq);
507162306a36Sopenharmony_ci	cap_reqs--;
507262306a36Sopenharmony_ci
507362306a36Sopenharmony_ci	crq.query_capability.capability =
507462306a36Sopenharmony_ci			cpu_to_be16(OPT_RXBA_ENTRIES_PER_SUBCRQ);
507562306a36Sopenharmony_ci	ibmvnic_send_crq(adapter, &crq);
507662306a36Sopenharmony_ci	cap_reqs--;
507762306a36Sopenharmony_ci
507862306a36Sopenharmony_ci	crq.query_capability.capability = cpu_to_be16(TX_RX_DESC_REQ);
507962306a36Sopenharmony_ci
508062306a36Sopenharmony_ci	ibmvnic_send_crq(adapter, &crq);
508162306a36Sopenharmony_ci	cap_reqs--;
508262306a36Sopenharmony_ci
508362306a36Sopenharmony_ci	/* Keep at end to catch any discrepancy between expected and actual
508462306a36Sopenharmony_ci	 * CRQs sent.
508562306a36Sopenharmony_ci	 */
508662306a36Sopenharmony_ci	WARN_ON(cap_reqs != 0);
508762306a36Sopenharmony_ci}
508862306a36Sopenharmony_ci
508962306a36Sopenharmony_cistatic void send_query_ip_offload(struct ibmvnic_adapter *adapter)
509062306a36Sopenharmony_ci{
509162306a36Sopenharmony_ci	int buf_sz = sizeof(struct ibmvnic_query_ip_offload_buffer);
509262306a36Sopenharmony_ci	struct device *dev = &adapter->vdev->dev;
509362306a36Sopenharmony_ci	union ibmvnic_crq crq;
509462306a36Sopenharmony_ci
509562306a36Sopenharmony_ci	adapter->ip_offload_tok =
509662306a36Sopenharmony_ci		dma_map_single(dev,
509762306a36Sopenharmony_ci			       &adapter->ip_offload_buf,
509862306a36Sopenharmony_ci			       buf_sz,
509962306a36Sopenharmony_ci			       DMA_FROM_DEVICE);
510062306a36Sopenharmony_ci
510162306a36Sopenharmony_ci	if (dma_mapping_error(dev, adapter->ip_offload_tok)) {
510262306a36Sopenharmony_ci		if (!firmware_has_feature(FW_FEATURE_CMO))
510362306a36Sopenharmony_ci			dev_err(dev, "Couldn't map offload buffer\n");
510462306a36Sopenharmony_ci		return;
510562306a36Sopenharmony_ci	}
510662306a36Sopenharmony_ci
510762306a36Sopenharmony_ci	memset(&crq, 0, sizeof(crq));
510862306a36Sopenharmony_ci	crq.query_ip_offload.first = IBMVNIC_CRQ_CMD;
510962306a36Sopenharmony_ci	crq.query_ip_offload.cmd = QUERY_IP_OFFLOAD;
511062306a36Sopenharmony_ci	crq.query_ip_offload.len = cpu_to_be32(buf_sz);
511162306a36Sopenharmony_ci	crq.query_ip_offload.ioba =
511262306a36Sopenharmony_ci	    cpu_to_be32(adapter->ip_offload_tok);
511362306a36Sopenharmony_ci
511462306a36Sopenharmony_ci	ibmvnic_send_crq(adapter, &crq);
511562306a36Sopenharmony_ci}
511662306a36Sopenharmony_ci
511762306a36Sopenharmony_cistatic void send_control_ip_offload(struct ibmvnic_adapter *adapter)
511862306a36Sopenharmony_ci{
511962306a36Sopenharmony_ci	struct ibmvnic_control_ip_offload_buffer *ctrl_buf = &adapter->ip_offload_ctrl;
512062306a36Sopenharmony_ci	struct ibmvnic_query_ip_offload_buffer *buf = &adapter->ip_offload_buf;
512162306a36Sopenharmony_ci	struct device *dev = &adapter->vdev->dev;
512262306a36Sopenharmony_ci	netdev_features_t old_hw_features = 0;
512362306a36Sopenharmony_ci	union ibmvnic_crq crq;
512462306a36Sopenharmony_ci
512562306a36Sopenharmony_ci	adapter->ip_offload_ctrl_tok =
512662306a36Sopenharmony_ci		dma_map_single(dev,
512762306a36Sopenharmony_ci			       ctrl_buf,
512862306a36Sopenharmony_ci			       sizeof(adapter->ip_offload_ctrl),
512962306a36Sopenharmony_ci			       DMA_TO_DEVICE);
513062306a36Sopenharmony_ci
513162306a36Sopenharmony_ci	if (dma_mapping_error(dev, adapter->ip_offload_ctrl_tok)) {
513262306a36Sopenharmony_ci		dev_err(dev, "Couldn't map ip offload control buffer\n");
513362306a36Sopenharmony_ci		return;
513462306a36Sopenharmony_ci	}
513562306a36Sopenharmony_ci
513662306a36Sopenharmony_ci	ctrl_buf->len = cpu_to_be32(sizeof(adapter->ip_offload_ctrl));
513762306a36Sopenharmony_ci	ctrl_buf->version = cpu_to_be32(INITIAL_VERSION_IOB);
513862306a36Sopenharmony_ci	ctrl_buf->ipv4_chksum = buf->ipv4_chksum;
513962306a36Sopenharmony_ci	ctrl_buf->ipv6_chksum = buf->ipv6_chksum;
514062306a36Sopenharmony_ci	ctrl_buf->tcp_ipv4_chksum = buf->tcp_ipv4_chksum;
514162306a36Sopenharmony_ci	ctrl_buf->udp_ipv4_chksum = buf->udp_ipv4_chksum;
514262306a36Sopenharmony_ci	ctrl_buf->tcp_ipv6_chksum = buf->tcp_ipv6_chksum;
514362306a36Sopenharmony_ci	ctrl_buf->udp_ipv6_chksum = buf->udp_ipv6_chksum;
514462306a36Sopenharmony_ci	ctrl_buf->large_tx_ipv4 = buf->large_tx_ipv4;
514562306a36Sopenharmony_ci	ctrl_buf->large_tx_ipv6 = buf->large_tx_ipv6;
514662306a36Sopenharmony_ci
514762306a36Sopenharmony_ci	/* large_rx disabled for now, additional features needed */
514862306a36Sopenharmony_ci	ctrl_buf->large_rx_ipv4 = 0;
514962306a36Sopenharmony_ci	ctrl_buf->large_rx_ipv6 = 0;
515062306a36Sopenharmony_ci
515162306a36Sopenharmony_ci	if (adapter->state != VNIC_PROBING) {
515262306a36Sopenharmony_ci		old_hw_features = adapter->netdev->hw_features;
515362306a36Sopenharmony_ci		adapter->netdev->hw_features = 0;
515462306a36Sopenharmony_ci	}
515562306a36Sopenharmony_ci
515662306a36Sopenharmony_ci	adapter->netdev->hw_features = NETIF_F_SG | NETIF_F_GSO | NETIF_F_GRO;
515762306a36Sopenharmony_ci
515862306a36Sopenharmony_ci	if (buf->tcp_ipv4_chksum || buf->udp_ipv4_chksum)
515962306a36Sopenharmony_ci		adapter->netdev->hw_features |= NETIF_F_IP_CSUM;
516062306a36Sopenharmony_ci
516162306a36Sopenharmony_ci	if (buf->tcp_ipv6_chksum || buf->udp_ipv6_chksum)
516262306a36Sopenharmony_ci		adapter->netdev->hw_features |= NETIF_F_IPV6_CSUM;
516362306a36Sopenharmony_ci
516462306a36Sopenharmony_ci	if ((adapter->netdev->features &
516562306a36Sopenharmony_ci	    (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM)))
516662306a36Sopenharmony_ci		adapter->netdev->hw_features |= NETIF_F_RXCSUM;
516762306a36Sopenharmony_ci
516862306a36Sopenharmony_ci	if (buf->large_tx_ipv4)
516962306a36Sopenharmony_ci		adapter->netdev->hw_features |= NETIF_F_TSO;
517062306a36Sopenharmony_ci	if (buf->large_tx_ipv6)
517162306a36Sopenharmony_ci		adapter->netdev->hw_features |= NETIF_F_TSO6;
517262306a36Sopenharmony_ci
517362306a36Sopenharmony_ci	if (adapter->state == VNIC_PROBING) {
517462306a36Sopenharmony_ci		adapter->netdev->features |= adapter->netdev->hw_features;
517562306a36Sopenharmony_ci	} else if (old_hw_features != adapter->netdev->hw_features) {
517662306a36Sopenharmony_ci		netdev_features_t tmp = 0;
517762306a36Sopenharmony_ci
517862306a36Sopenharmony_ci		/* disable features no longer supported */
517962306a36Sopenharmony_ci		adapter->netdev->features &= adapter->netdev->hw_features;
518062306a36Sopenharmony_ci		/* turn on features now supported if previously enabled */
518162306a36Sopenharmony_ci		tmp = (old_hw_features ^ adapter->netdev->hw_features) &
518262306a36Sopenharmony_ci			adapter->netdev->hw_features;
518362306a36Sopenharmony_ci		adapter->netdev->features |=
518462306a36Sopenharmony_ci				tmp & adapter->netdev->wanted_features;
518562306a36Sopenharmony_ci	}
518662306a36Sopenharmony_ci
518762306a36Sopenharmony_ci	memset(&crq, 0, sizeof(crq));
518862306a36Sopenharmony_ci	crq.control_ip_offload.first = IBMVNIC_CRQ_CMD;
518962306a36Sopenharmony_ci	crq.control_ip_offload.cmd = CONTROL_IP_OFFLOAD;
519062306a36Sopenharmony_ci	crq.control_ip_offload.len =
519162306a36Sopenharmony_ci	    cpu_to_be32(sizeof(adapter->ip_offload_ctrl));
519262306a36Sopenharmony_ci	crq.control_ip_offload.ioba = cpu_to_be32(adapter->ip_offload_ctrl_tok);
519362306a36Sopenharmony_ci	ibmvnic_send_crq(adapter, &crq);
519462306a36Sopenharmony_ci}
519562306a36Sopenharmony_ci
519662306a36Sopenharmony_cistatic void handle_vpd_size_rsp(union ibmvnic_crq *crq,
519762306a36Sopenharmony_ci				struct ibmvnic_adapter *adapter)
519862306a36Sopenharmony_ci{
519962306a36Sopenharmony_ci	struct device *dev = &adapter->vdev->dev;
520062306a36Sopenharmony_ci
520162306a36Sopenharmony_ci	if (crq->get_vpd_size_rsp.rc.code) {
520262306a36Sopenharmony_ci		dev_err(dev, "Error retrieving VPD size, rc=%x\n",
520362306a36Sopenharmony_ci			crq->get_vpd_size_rsp.rc.code);
520462306a36Sopenharmony_ci		complete(&adapter->fw_done);
520562306a36Sopenharmony_ci		return;
520662306a36Sopenharmony_ci	}
520762306a36Sopenharmony_ci
520862306a36Sopenharmony_ci	adapter->vpd->len = be64_to_cpu(crq->get_vpd_size_rsp.len);
520962306a36Sopenharmony_ci	complete(&adapter->fw_done);
521062306a36Sopenharmony_ci}
521162306a36Sopenharmony_ci
521262306a36Sopenharmony_cistatic void handle_vpd_rsp(union ibmvnic_crq *crq,
521362306a36Sopenharmony_ci			   struct ibmvnic_adapter *adapter)
521462306a36Sopenharmony_ci{
521562306a36Sopenharmony_ci	struct device *dev = &adapter->vdev->dev;
521662306a36Sopenharmony_ci	unsigned char *substr = NULL;
521762306a36Sopenharmony_ci	u8 fw_level_len = 0;
521862306a36Sopenharmony_ci
521962306a36Sopenharmony_ci	memset(adapter->fw_version, 0, 32);
522062306a36Sopenharmony_ci
522162306a36Sopenharmony_ci	dma_unmap_single(dev, adapter->vpd->dma_addr, adapter->vpd->len,
522262306a36Sopenharmony_ci			 DMA_FROM_DEVICE);
522362306a36Sopenharmony_ci
522462306a36Sopenharmony_ci	if (crq->get_vpd_rsp.rc.code) {
522562306a36Sopenharmony_ci		dev_err(dev, "Error retrieving VPD from device, rc=%x\n",
522662306a36Sopenharmony_ci			crq->get_vpd_rsp.rc.code);
522762306a36Sopenharmony_ci		goto complete;
522862306a36Sopenharmony_ci	}
522962306a36Sopenharmony_ci
523062306a36Sopenharmony_ci	/* get the position of the firmware version info
523162306a36Sopenharmony_ci	 * located after the ASCII 'RM' substring in the buffer
523262306a36Sopenharmony_ci	 */
523362306a36Sopenharmony_ci	substr = strnstr(adapter->vpd->buff, "RM", adapter->vpd->len);
523462306a36Sopenharmony_ci	if (!substr) {
523562306a36Sopenharmony_ci		dev_info(dev, "Warning - No FW level has been provided in the VPD buffer by the VIOS Server\n");
523662306a36Sopenharmony_ci		goto complete;
523762306a36Sopenharmony_ci	}
523862306a36Sopenharmony_ci
523962306a36Sopenharmony_ci	/* get length of firmware level ASCII substring */
524062306a36Sopenharmony_ci	if ((substr + 2) < (adapter->vpd->buff + adapter->vpd->len)) {
524162306a36Sopenharmony_ci		fw_level_len = *(substr + 2);
524262306a36Sopenharmony_ci	} else {
524362306a36Sopenharmony_ci		dev_info(dev, "Length of FW substr extrapolated VDP buff\n");
524462306a36Sopenharmony_ci		goto complete;
524562306a36Sopenharmony_ci	}
524662306a36Sopenharmony_ci
524762306a36Sopenharmony_ci	/* copy firmware version string from vpd into adapter */
524862306a36Sopenharmony_ci	if ((substr + 3 + fw_level_len) <
524962306a36Sopenharmony_ci	    (adapter->vpd->buff + adapter->vpd->len)) {
525062306a36Sopenharmony_ci		strncpy((char *)adapter->fw_version, substr + 3, fw_level_len);
525162306a36Sopenharmony_ci	} else {
525262306a36Sopenharmony_ci		dev_info(dev, "FW substr extrapolated VPD buff\n");
525362306a36Sopenharmony_ci	}
525462306a36Sopenharmony_ci
525562306a36Sopenharmony_cicomplete:
525662306a36Sopenharmony_ci	if (adapter->fw_version[0] == '\0')
525762306a36Sopenharmony_ci		strscpy((char *)adapter->fw_version, "N/A", sizeof(adapter->fw_version));
525862306a36Sopenharmony_ci	complete(&adapter->fw_done);
525962306a36Sopenharmony_ci}
526062306a36Sopenharmony_ci
526162306a36Sopenharmony_cistatic void handle_query_ip_offload_rsp(struct ibmvnic_adapter *adapter)
526262306a36Sopenharmony_ci{
526362306a36Sopenharmony_ci	struct device *dev = &adapter->vdev->dev;
526462306a36Sopenharmony_ci	struct ibmvnic_query_ip_offload_buffer *buf = &adapter->ip_offload_buf;
526562306a36Sopenharmony_ci	int i;
526662306a36Sopenharmony_ci
526762306a36Sopenharmony_ci	dma_unmap_single(dev, adapter->ip_offload_tok,
526862306a36Sopenharmony_ci			 sizeof(adapter->ip_offload_buf), DMA_FROM_DEVICE);
526962306a36Sopenharmony_ci
527062306a36Sopenharmony_ci	netdev_dbg(adapter->netdev, "Query IP Offload Buffer:\n");
527162306a36Sopenharmony_ci	for (i = 0; i < (sizeof(adapter->ip_offload_buf) - 1) / 8 + 1; i++)
527262306a36Sopenharmony_ci		netdev_dbg(adapter->netdev, "%016lx\n",
527362306a36Sopenharmony_ci			   ((unsigned long *)(buf))[i]);
527462306a36Sopenharmony_ci
527562306a36Sopenharmony_ci	netdev_dbg(adapter->netdev, "ipv4_chksum = %d\n", buf->ipv4_chksum);
527662306a36Sopenharmony_ci	netdev_dbg(adapter->netdev, "ipv6_chksum = %d\n", buf->ipv6_chksum);
527762306a36Sopenharmony_ci	netdev_dbg(adapter->netdev, "tcp_ipv4_chksum = %d\n",
527862306a36Sopenharmony_ci		   buf->tcp_ipv4_chksum);
527962306a36Sopenharmony_ci	netdev_dbg(adapter->netdev, "tcp_ipv6_chksum = %d\n",
528062306a36Sopenharmony_ci		   buf->tcp_ipv6_chksum);
528162306a36Sopenharmony_ci	netdev_dbg(adapter->netdev, "udp_ipv4_chksum = %d\n",
528262306a36Sopenharmony_ci		   buf->udp_ipv4_chksum);
528362306a36Sopenharmony_ci	netdev_dbg(adapter->netdev, "udp_ipv6_chksum = %d\n",
528462306a36Sopenharmony_ci		   buf->udp_ipv6_chksum);
528562306a36Sopenharmony_ci	netdev_dbg(adapter->netdev, "large_tx_ipv4 = %d\n",
528662306a36Sopenharmony_ci		   buf->large_tx_ipv4);
528762306a36Sopenharmony_ci	netdev_dbg(adapter->netdev, "large_tx_ipv6 = %d\n",
528862306a36Sopenharmony_ci		   buf->large_tx_ipv6);
528962306a36Sopenharmony_ci	netdev_dbg(adapter->netdev, "large_rx_ipv4 = %d\n",
529062306a36Sopenharmony_ci		   buf->large_rx_ipv4);
529162306a36Sopenharmony_ci	netdev_dbg(adapter->netdev, "large_rx_ipv6 = %d\n",
529262306a36Sopenharmony_ci		   buf->large_rx_ipv6);
529362306a36Sopenharmony_ci	netdev_dbg(adapter->netdev, "max_ipv4_hdr_sz = %d\n",
529462306a36Sopenharmony_ci		   buf->max_ipv4_header_size);
529562306a36Sopenharmony_ci	netdev_dbg(adapter->netdev, "max_ipv6_hdr_sz = %d\n",
529662306a36Sopenharmony_ci		   buf->max_ipv6_header_size);
529762306a36Sopenharmony_ci	netdev_dbg(adapter->netdev, "max_tcp_hdr_size = %d\n",
529862306a36Sopenharmony_ci		   buf->max_tcp_header_size);
529962306a36Sopenharmony_ci	netdev_dbg(adapter->netdev, "max_udp_hdr_size = %d\n",
530062306a36Sopenharmony_ci		   buf->max_udp_header_size);
530162306a36Sopenharmony_ci	netdev_dbg(adapter->netdev, "max_large_tx_size = %d\n",
530262306a36Sopenharmony_ci		   buf->max_large_tx_size);
530362306a36Sopenharmony_ci	netdev_dbg(adapter->netdev, "max_large_rx_size = %d\n",
530462306a36Sopenharmony_ci		   buf->max_large_rx_size);
530562306a36Sopenharmony_ci	netdev_dbg(adapter->netdev, "ipv6_ext_hdr = %d\n",
530662306a36Sopenharmony_ci		   buf->ipv6_extension_header);
530762306a36Sopenharmony_ci	netdev_dbg(adapter->netdev, "tcp_pseudosum_req = %d\n",
530862306a36Sopenharmony_ci		   buf->tcp_pseudosum_req);
530962306a36Sopenharmony_ci	netdev_dbg(adapter->netdev, "num_ipv6_ext_hd = %d\n",
531062306a36Sopenharmony_ci		   buf->num_ipv6_ext_headers);
531162306a36Sopenharmony_ci	netdev_dbg(adapter->netdev, "off_ipv6_ext_hd = %d\n",
531262306a36Sopenharmony_ci		   buf->off_ipv6_ext_headers);
531362306a36Sopenharmony_ci
531462306a36Sopenharmony_ci	send_control_ip_offload(adapter);
531562306a36Sopenharmony_ci}
531662306a36Sopenharmony_ci
531762306a36Sopenharmony_cistatic const char *ibmvnic_fw_err_cause(u16 cause)
531862306a36Sopenharmony_ci{
531962306a36Sopenharmony_ci	switch (cause) {
532062306a36Sopenharmony_ci	case ADAPTER_PROBLEM:
532162306a36Sopenharmony_ci		return "adapter problem";
532262306a36Sopenharmony_ci	case BUS_PROBLEM:
532362306a36Sopenharmony_ci		return "bus problem";
532462306a36Sopenharmony_ci	case FW_PROBLEM:
532562306a36Sopenharmony_ci		return "firmware problem";
532662306a36Sopenharmony_ci	case DD_PROBLEM:
532762306a36Sopenharmony_ci		return "device driver problem";
532862306a36Sopenharmony_ci	case EEH_RECOVERY:
532962306a36Sopenharmony_ci		return "EEH recovery";
533062306a36Sopenharmony_ci	case FW_UPDATED:
533162306a36Sopenharmony_ci		return "firmware updated";
533262306a36Sopenharmony_ci	case LOW_MEMORY:
533362306a36Sopenharmony_ci		return "low Memory";
533462306a36Sopenharmony_ci	default:
533562306a36Sopenharmony_ci		return "unknown";
533662306a36Sopenharmony_ci	}
533762306a36Sopenharmony_ci}
533862306a36Sopenharmony_ci
533962306a36Sopenharmony_cistatic void handle_error_indication(union ibmvnic_crq *crq,
534062306a36Sopenharmony_ci				    struct ibmvnic_adapter *adapter)
534162306a36Sopenharmony_ci{
534262306a36Sopenharmony_ci	struct device *dev = &adapter->vdev->dev;
534362306a36Sopenharmony_ci	u16 cause;
534462306a36Sopenharmony_ci
534562306a36Sopenharmony_ci	cause = be16_to_cpu(crq->error_indication.error_cause);
534662306a36Sopenharmony_ci
534762306a36Sopenharmony_ci	dev_warn_ratelimited(dev,
534862306a36Sopenharmony_ci			     "Firmware reports %serror, cause: %s. Starting recovery...\n",
534962306a36Sopenharmony_ci			     crq->error_indication.flags
535062306a36Sopenharmony_ci				& IBMVNIC_FATAL_ERROR ? "FATAL " : "",
535162306a36Sopenharmony_ci			     ibmvnic_fw_err_cause(cause));
535262306a36Sopenharmony_ci
535362306a36Sopenharmony_ci	if (crq->error_indication.flags & IBMVNIC_FATAL_ERROR)
535462306a36Sopenharmony_ci		ibmvnic_reset(adapter, VNIC_RESET_FATAL);
535562306a36Sopenharmony_ci	else
535662306a36Sopenharmony_ci		ibmvnic_reset(adapter, VNIC_RESET_NON_FATAL);
535762306a36Sopenharmony_ci}
535862306a36Sopenharmony_ci
535962306a36Sopenharmony_cistatic int handle_change_mac_rsp(union ibmvnic_crq *crq,
536062306a36Sopenharmony_ci				 struct ibmvnic_adapter *adapter)
536162306a36Sopenharmony_ci{
536262306a36Sopenharmony_ci	struct net_device *netdev = adapter->netdev;
536362306a36Sopenharmony_ci	struct device *dev = &adapter->vdev->dev;
536462306a36Sopenharmony_ci	long rc;
536562306a36Sopenharmony_ci
536662306a36Sopenharmony_ci	rc = crq->change_mac_addr_rsp.rc.code;
536762306a36Sopenharmony_ci	if (rc) {
536862306a36Sopenharmony_ci		dev_err(dev, "Error %ld in CHANGE_MAC_ADDR_RSP\n", rc);
536962306a36Sopenharmony_ci		goto out;
537062306a36Sopenharmony_ci	}
537162306a36Sopenharmony_ci	/* crq->change_mac_addr.mac_addr is the requested one
537262306a36Sopenharmony_ci	 * crq->change_mac_addr_rsp.mac_addr is the returned valid one.
537362306a36Sopenharmony_ci	 */
537462306a36Sopenharmony_ci	eth_hw_addr_set(netdev, &crq->change_mac_addr_rsp.mac_addr[0]);
537562306a36Sopenharmony_ci	ether_addr_copy(adapter->mac_addr,
537662306a36Sopenharmony_ci			&crq->change_mac_addr_rsp.mac_addr[0]);
537762306a36Sopenharmony_ciout:
537862306a36Sopenharmony_ci	complete(&adapter->fw_done);
537962306a36Sopenharmony_ci	return rc;
538062306a36Sopenharmony_ci}
538162306a36Sopenharmony_ci
538262306a36Sopenharmony_cistatic void handle_request_cap_rsp(union ibmvnic_crq *crq,
538362306a36Sopenharmony_ci				   struct ibmvnic_adapter *adapter)
538462306a36Sopenharmony_ci{
538562306a36Sopenharmony_ci	struct device *dev = &adapter->vdev->dev;
538662306a36Sopenharmony_ci	u64 *req_value;
538762306a36Sopenharmony_ci	char *name;
538862306a36Sopenharmony_ci
538962306a36Sopenharmony_ci	atomic_dec(&adapter->running_cap_crqs);
539062306a36Sopenharmony_ci	netdev_dbg(adapter->netdev, "Outstanding request-caps: %d\n",
539162306a36Sopenharmony_ci		   atomic_read(&adapter->running_cap_crqs));
539262306a36Sopenharmony_ci	switch (be16_to_cpu(crq->request_capability_rsp.capability)) {
539362306a36Sopenharmony_ci	case REQ_TX_QUEUES:
539462306a36Sopenharmony_ci		req_value = &adapter->req_tx_queues;
539562306a36Sopenharmony_ci		name = "tx";
539662306a36Sopenharmony_ci		break;
539762306a36Sopenharmony_ci	case REQ_RX_QUEUES:
539862306a36Sopenharmony_ci		req_value = &adapter->req_rx_queues;
539962306a36Sopenharmony_ci		name = "rx";
540062306a36Sopenharmony_ci		break;
540162306a36Sopenharmony_ci	case REQ_RX_ADD_QUEUES:
540262306a36Sopenharmony_ci		req_value = &adapter->req_rx_add_queues;
540362306a36Sopenharmony_ci		name = "rx_add";
540462306a36Sopenharmony_ci		break;
540562306a36Sopenharmony_ci	case REQ_TX_ENTRIES_PER_SUBCRQ:
540662306a36Sopenharmony_ci		req_value = &adapter->req_tx_entries_per_subcrq;
540762306a36Sopenharmony_ci		name = "tx_entries_per_subcrq";
540862306a36Sopenharmony_ci		break;
540962306a36Sopenharmony_ci	case REQ_RX_ADD_ENTRIES_PER_SUBCRQ:
541062306a36Sopenharmony_ci		req_value = &adapter->req_rx_add_entries_per_subcrq;
541162306a36Sopenharmony_ci		name = "rx_add_entries_per_subcrq";
541262306a36Sopenharmony_ci		break;
541362306a36Sopenharmony_ci	case REQ_MTU:
541462306a36Sopenharmony_ci		req_value = &adapter->req_mtu;
541562306a36Sopenharmony_ci		name = "mtu";
541662306a36Sopenharmony_ci		break;
541762306a36Sopenharmony_ci	case PROMISC_REQUESTED:
541862306a36Sopenharmony_ci		req_value = &adapter->promisc;
541962306a36Sopenharmony_ci		name = "promisc";
542062306a36Sopenharmony_ci		break;
542162306a36Sopenharmony_ci	default:
542262306a36Sopenharmony_ci		dev_err(dev, "Got invalid cap request rsp %d\n",
542362306a36Sopenharmony_ci			crq->request_capability.capability);
542462306a36Sopenharmony_ci		return;
542562306a36Sopenharmony_ci	}
542662306a36Sopenharmony_ci
542762306a36Sopenharmony_ci	switch (crq->request_capability_rsp.rc.code) {
542862306a36Sopenharmony_ci	case SUCCESS:
542962306a36Sopenharmony_ci		break;
543062306a36Sopenharmony_ci	case PARTIALSUCCESS:
543162306a36Sopenharmony_ci		dev_info(dev, "req=%lld, rsp=%ld in %s queue, retrying.\n",
543262306a36Sopenharmony_ci			 *req_value,
543362306a36Sopenharmony_ci			 (long)be64_to_cpu(crq->request_capability_rsp.number),
543462306a36Sopenharmony_ci			 name);
543562306a36Sopenharmony_ci
543662306a36Sopenharmony_ci		if (be16_to_cpu(crq->request_capability_rsp.capability) ==
543762306a36Sopenharmony_ci		    REQ_MTU) {
543862306a36Sopenharmony_ci			pr_err("mtu of %llu is not supported. Reverting.\n",
543962306a36Sopenharmony_ci			       *req_value);
544062306a36Sopenharmony_ci			*req_value = adapter->fallback.mtu;
544162306a36Sopenharmony_ci		} else {
544262306a36Sopenharmony_ci			*req_value =
544362306a36Sopenharmony_ci				be64_to_cpu(crq->request_capability_rsp.number);
544462306a36Sopenharmony_ci		}
544562306a36Sopenharmony_ci
544662306a36Sopenharmony_ci		send_request_cap(adapter, 1);
544762306a36Sopenharmony_ci		return;
544862306a36Sopenharmony_ci	default:
544962306a36Sopenharmony_ci		dev_err(dev, "Error %d in request cap rsp\n",
545062306a36Sopenharmony_ci			crq->request_capability_rsp.rc.code);
545162306a36Sopenharmony_ci		return;
545262306a36Sopenharmony_ci	}
545362306a36Sopenharmony_ci
545462306a36Sopenharmony_ci	/* Done receiving requested capabilities, query IP offload support */
545562306a36Sopenharmony_ci	if (atomic_read(&adapter->running_cap_crqs) == 0)
545662306a36Sopenharmony_ci		send_query_ip_offload(adapter);
545762306a36Sopenharmony_ci}
545862306a36Sopenharmony_ci
545962306a36Sopenharmony_cistatic int handle_login_rsp(union ibmvnic_crq *login_rsp_crq,
546062306a36Sopenharmony_ci			    struct ibmvnic_adapter *adapter)
546162306a36Sopenharmony_ci{
546262306a36Sopenharmony_ci	struct device *dev = &adapter->vdev->dev;
546362306a36Sopenharmony_ci	struct net_device *netdev = adapter->netdev;
546462306a36Sopenharmony_ci	struct ibmvnic_login_rsp_buffer *login_rsp = adapter->login_rsp_buf;
546562306a36Sopenharmony_ci	struct ibmvnic_login_buffer *login = adapter->login_buf;
546662306a36Sopenharmony_ci	u64 *tx_handle_array;
546762306a36Sopenharmony_ci	u64 *rx_handle_array;
546862306a36Sopenharmony_ci	int num_tx_pools;
546962306a36Sopenharmony_ci	int num_rx_pools;
547062306a36Sopenharmony_ci	u64 *size_array;
547162306a36Sopenharmony_ci	u32 rsp_len;
547262306a36Sopenharmony_ci	int i;
547362306a36Sopenharmony_ci
547462306a36Sopenharmony_ci	/* CHECK: Test/set of login_pending does not need to be atomic
547562306a36Sopenharmony_ci	 * because only ibmvnic_tasklet tests/clears this.
547662306a36Sopenharmony_ci	 */
547762306a36Sopenharmony_ci	if (!adapter->login_pending) {
547862306a36Sopenharmony_ci		netdev_warn(netdev, "Ignoring unexpected login response\n");
547962306a36Sopenharmony_ci		return 0;
548062306a36Sopenharmony_ci	}
548162306a36Sopenharmony_ci	adapter->login_pending = false;
548262306a36Sopenharmony_ci
548362306a36Sopenharmony_ci	/* If the number of queues requested can't be allocated by the
548462306a36Sopenharmony_ci	 * server, the login response will return with code 1. We will need
548562306a36Sopenharmony_ci	 * to resend the login buffer with fewer queues requested.
548662306a36Sopenharmony_ci	 */
548762306a36Sopenharmony_ci	if (login_rsp_crq->generic.rc.code) {
548862306a36Sopenharmony_ci		adapter->init_done_rc = login_rsp_crq->generic.rc.code;
548962306a36Sopenharmony_ci		complete(&adapter->init_done);
549062306a36Sopenharmony_ci		return 0;
549162306a36Sopenharmony_ci	}
549262306a36Sopenharmony_ci
549362306a36Sopenharmony_ci	if (adapter->failover_pending) {
549462306a36Sopenharmony_ci		adapter->init_done_rc = -EAGAIN;
549562306a36Sopenharmony_ci		netdev_dbg(netdev, "Failover pending, ignoring login response\n");
549662306a36Sopenharmony_ci		complete(&adapter->init_done);
549762306a36Sopenharmony_ci		/* login response buffer will be released on reset */
549862306a36Sopenharmony_ci		return 0;
549962306a36Sopenharmony_ci	}
550062306a36Sopenharmony_ci
550162306a36Sopenharmony_ci	netdev->mtu = adapter->req_mtu - ETH_HLEN;
550262306a36Sopenharmony_ci
550362306a36Sopenharmony_ci	netdev_dbg(adapter->netdev, "Login Response Buffer:\n");
550462306a36Sopenharmony_ci	for (i = 0; i < (adapter->login_rsp_buf_sz - 1) / 8 + 1; i++) {
550562306a36Sopenharmony_ci		netdev_dbg(adapter->netdev, "%016lx\n",
550662306a36Sopenharmony_ci			   ((unsigned long *)(adapter->login_rsp_buf))[i]);
550762306a36Sopenharmony_ci	}
550862306a36Sopenharmony_ci
550962306a36Sopenharmony_ci	/* Sanity checks */
551062306a36Sopenharmony_ci	if (login->num_txcomp_subcrqs != login_rsp->num_txsubm_subcrqs ||
551162306a36Sopenharmony_ci	    (be32_to_cpu(login->num_rxcomp_subcrqs) *
551262306a36Sopenharmony_ci	     adapter->req_rx_add_queues !=
551362306a36Sopenharmony_ci	     be32_to_cpu(login_rsp->num_rxadd_subcrqs))) {
551462306a36Sopenharmony_ci		dev_err(dev, "FATAL: Inconsistent login and login rsp\n");
551562306a36Sopenharmony_ci		ibmvnic_reset(adapter, VNIC_RESET_FATAL);
551662306a36Sopenharmony_ci		return -EIO;
551762306a36Sopenharmony_ci	}
551862306a36Sopenharmony_ci
551962306a36Sopenharmony_ci	rsp_len = be32_to_cpu(login_rsp->len);
552062306a36Sopenharmony_ci	if (be32_to_cpu(login->login_rsp_len) < rsp_len ||
552162306a36Sopenharmony_ci	    rsp_len <= be32_to_cpu(login_rsp->off_txsubm_subcrqs) ||
552262306a36Sopenharmony_ci	    rsp_len <= be32_to_cpu(login_rsp->off_rxadd_subcrqs) ||
552362306a36Sopenharmony_ci	    rsp_len <= be32_to_cpu(login_rsp->off_rxadd_buff_size) ||
552462306a36Sopenharmony_ci	    rsp_len <= be32_to_cpu(login_rsp->off_supp_tx_desc)) {
552562306a36Sopenharmony_ci		/* This can happen if a login request times out and there are
552662306a36Sopenharmony_ci		 * 2 outstanding login requests sent, the LOGIN_RSP crq
552762306a36Sopenharmony_ci		 * could have been for the older login request. So we are
552862306a36Sopenharmony_ci		 * parsing the newer response buffer which may be incomplete
552962306a36Sopenharmony_ci		 */
553062306a36Sopenharmony_ci		dev_err(dev, "FATAL: Login rsp offsets/lengths invalid\n");
553162306a36Sopenharmony_ci		ibmvnic_reset(adapter, VNIC_RESET_FATAL);
553262306a36Sopenharmony_ci		return -EIO;
553362306a36Sopenharmony_ci	}
553462306a36Sopenharmony_ci
553562306a36Sopenharmony_ci	size_array = (u64 *)((u8 *)(adapter->login_rsp_buf) +
553662306a36Sopenharmony_ci		be32_to_cpu(adapter->login_rsp_buf->off_rxadd_buff_size));
553762306a36Sopenharmony_ci	/* variable buffer sizes are not supported, so just read the
553862306a36Sopenharmony_ci	 * first entry.
553962306a36Sopenharmony_ci	 */
554062306a36Sopenharmony_ci	adapter->cur_rx_buf_sz = be64_to_cpu(size_array[0]);
554162306a36Sopenharmony_ci
554262306a36Sopenharmony_ci	num_tx_pools = be32_to_cpu(adapter->login_rsp_buf->num_txsubm_subcrqs);
554362306a36Sopenharmony_ci	num_rx_pools = be32_to_cpu(adapter->login_rsp_buf->num_rxadd_subcrqs);
554462306a36Sopenharmony_ci
554562306a36Sopenharmony_ci	tx_handle_array = (u64 *)((u8 *)(adapter->login_rsp_buf) +
554662306a36Sopenharmony_ci				  be32_to_cpu(adapter->login_rsp_buf->off_txsubm_subcrqs));
554762306a36Sopenharmony_ci	rx_handle_array = (u64 *)((u8 *)(adapter->login_rsp_buf) +
554862306a36Sopenharmony_ci				  be32_to_cpu(adapter->login_rsp_buf->off_rxadd_subcrqs));
554962306a36Sopenharmony_ci
555062306a36Sopenharmony_ci	for (i = 0; i < num_tx_pools; i++)
555162306a36Sopenharmony_ci		adapter->tx_scrq[i]->handle = tx_handle_array[i];
555262306a36Sopenharmony_ci
555362306a36Sopenharmony_ci	for (i = 0; i < num_rx_pools; i++)
555462306a36Sopenharmony_ci		adapter->rx_scrq[i]->handle = rx_handle_array[i];
555562306a36Sopenharmony_ci
555662306a36Sopenharmony_ci	adapter->num_active_tx_scrqs = num_tx_pools;
555762306a36Sopenharmony_ci	adapter->num_active_rx_scrqs = num_rx_pools;
555862306a36Sopenharmony_ci	release_login_rsp_buffer(adapter);
555962306a36Sopenharmony_ci	release_login_buffer(adapter);
556062306a36Sopenharmony_ci	complete(&adapter->init_done);
556162306a36Sopenharmony_ci
556262306a36Sopenharmony_ci	return 0;
556362306a36Sopenharmony_ci}
556462306a36Sopenharmony_ci
556562306a36Sopenharmony_cistatic void handle_request_unmap_rsp(union ibmvnic_crq *crq,
556662306a36Sopenharmony_ci				     struct ibmvnic_adapter *adapter)
556762306a36Sopenharmony_ci{
556862306a36Sopenharmony_ci	struct device *dev = &adapter->vdev->dev;
556962306a36Sopenharmony_ci	long rc;
557062306a36Sopenharmony_ci
557162306a36Sopenharmony_ci	rc = crq->request_unmap_rsp.rc.code;
557262306a36Sopenharmony_ci	if (rc)
557362306a36Sopenharmony_ci		dev_err(dev, "Error %ld in REQUEST_UNMAP_RSP\n", rc);
557462306a36Sopenharmony_ci}
557562306a36Sopenharmony_ci
557662306a36Sopenharmony_cistatic void handle_query_map_rsp(union ibmvnic_crq *crq,
557762306a36Sopenharmony_ci				 struct ibmvnic_adapter *adapter)
557862306a36Sopenharmony_ci{
557962306a36Sopenharmony_ci	struct net_device *netdev = adapter->netdev;
558062306a36Sopenharmony_ci	struct device *dev = &adapter->vdev->dev;
558162306a36Sopenharmony_ci	long rc;
558262306a36Sopenharmony_ci
558362306a36Sopenharmony_ci	rc = crq->query_map_rsp.rc.code;
558462306a36Sopenharmony_ci	if (rc) {
558562306a36Sopenharmony_ci		dev_err(dev, "Error %ld in QUERY_MAP_RSP\n", rc);
558662306a36Sopenharmony_ci		return;
558762306a36Sopenharmony_ci	}
558862306a36Sopenharmony_ci	netdev_dbg(netdev, "page_size = %d\ntot_pages = %u\nfree_pages = %u\n",
558962306a36Sopenharmony_ci		   crq->query_map_rsp.page_size,
559062306a36Sopenharmony_ci		   __be32_to_cpu(crq->query_map_rsp.tot_pages),
559162306a36Sopenharmony_ci		   __be32_to_cpu(crq->query_map_rsp.free_pages));
559262306a36Sopenharmony_ci}
559362306a36Sopenharmony_ci
559462306a36Sopenharmony_cistatic void handle_query_cap_rsp(union ibmvnic_crq *crq,
559562306a36Sopenharmony_ci				 struct ibmvnic_adapter *adapter)
559662306a36Sopenharmony_ci{
559762306a36Sopenharmony_ci	struct net_device *netdev = adapter->netdev;
559862306a36Sopenharmony_ci	struct device *dev = &adapter->vdev->dev;
559962306a36Sopenharmony_ci	long rc;
560062306a36Sopenharmony_ci
560162306a36Sopenharmony_ci	atomic_dec(&adapter->running_cap_crqs);
560262306a36Sopenharmony_ci	netdev_dbg(netdev, "Outstanding queries: %d\n",
560362306a36Sopenharmony_ci		   atomic_read(&adapter->running_cap_crqs));
560462306a36Sopenharmony_ci	rc = crq->query_capability.rc.code;
560562306a36Sopenharmony_ci	if (rc) {
560662306a36Sopenharmony_ci		dev_err(dev, "Error %ld in QUERY_CAP_RSP\n", rc);
560762306a36Sopenharmony_ci		goto out;
560862306a36Sopenharmony_ci	}
560962306a36Sopenharmony_ci
561062306a36Sopenharmony_ci	switch (be16_to_cpu(crq->query_capability.capability)) {
561162306a36Sopenharmony_ci	case MIN_TX_QUEUES:
561262306a36Sopenharmony_ci		adapter->min_tx_queues =
561362306a36Sopenharmony_ci		    be64_to_cpu(crq->query_capability.number);
561462306a36Sopenharmony_ci		netdev_dbg(netdev, "min_tx_queues = %lld\n",
561562306a36Sopenharmony_ci			   adapter->min_tx_queues);
561662306a36Sopenharmony_ci		break;
561762306a36Sopenharmony_ci	case MIN_RX_QUEUES:
561862306a36Sopenharmony_ci		adapter->min_rx_queues =
561962306a36Sopenharmony_ci		    be64_to_cpu(crq->query_capability.number);
562062306a36Sopenharmony_ci		netdev_dbg(netdev, "min_rx_queues = %lld\n",
562162306a36Sopenharmony_ci			   adapter->min_rx_queues);
562262306a36Sopenharmony_ci		break;
562362306a36Sopenharmony_ci	case MIN_RX_ADD_QUEUES:
562462306a36Sopenharmony_ci		adapter->min_rx_add_queues =
562562306a36Sopenharmony_ci		    be64_to_cpu(crq->query_capability.number);
562662306a36Sopenharmony_ci		netdev_dbg(netdev, "min_rx_add_queues = %lld\n",
562762306a36Sopenharmony_ci			   adapter->min_rx_add_queues);
562862306a36Sopenharmony_ci		break;
562962306a36Sopenharmony_ci	case MAX_TX_QUEUES:
563062306a36Sopenharmony_ci		adapter->max_tx_queues =
563162306a36Sopenharmony_ci		    be64_to_cpu(crq->query_capability.number);
563262306a36Sopenharmony_ci		netdev_dbg(netdev, "max_tx_queues = %lld\n",
563362306a36Sopenharmony_ci			   adapter->max_tx_queues);
563462306a36Sopenharmony_ci		break;
563562306a36Sopenharmony_ci	case MAX_RX_QUEUES:
563662306a36Sopenharmony_ci		adapter->max_rx_queues =
563762306a36Sopenharmony_ci		    be64_to_cpu(crq->query_capability.number);
563862306a36Sopenharmony_ci		netdev_dbg(netdev, "max_rx_queues = %lld\n",
563962306a36Sopenharmony_ci			   adapter->max_rx_queues);
564062306a36Sopenharmony_ci		break;
564162306a36Sopenharmony_ci	case MAX_RX_ADD_QUEUES:
564262306a36Sopenharmony_ci		adapter->max_rx_add_queues =
564362306a36Sopenharmony_ci		    be64_to_cpu(crq->query_capability.number);
564462306a36Sopenharmony_ci		netdev_dbg(netdev, "max_rx_add_queues = %lld\n",
564562306a36Sopenharmony_ci			   adapter->max_rx_add_queues);
564662306a36Sopenharmony_ci		break;
564762306a36Sopenharmony_ci	case MIN_TX_ENTRIES_PER_SUBCRQ:
564862306a36Sopenharmony_ci		adapter->min_tx_entries_per_subcrq =
564962306a36Sopenharmony_ci		    be64_to_cpu(crq->query_capability.number);
565062306a36Sopenharmony_ci		netdev_dbg(netdev, "min_tx_entries_per_subcrq = %lld\n",
565162306a36Sopenharmony_ci			   adapter->min_tx_entries_per_subcrq);
565262306a36Sopenharmony_ci		break;
565362306a36Sopenharmony_ci	case MIN_RX_ADD_ENTRIES_PER_SUBCRQ:
565462306a36Sopenharmony_ci		adapter->min_rx_add_entries_per_subcrq =
565562306a36Sopenharmony_ci		    be64_to_cpu(crq->query_capability.number);
565662306a36Sopenharmony_ci		netdev_dbg(netdev, "min_rx_add_entrs_per_subcrq = %lld\n",
565762306a36Sopenharmony_ci			   adapter->min_rx_add_entries_per_subcrq);
565862306a36Sopenharmony_ci		break;
565962306a36Sopenharmony_ci	case MAX_TX_ENTRIES_PER_SUBCRQ:
566062306a36Sopenharmony_ci		adapter->max_tx_entries_per_subcrq =
566162306a36Sopenharmony_ci		    be64_to_cpu(crq->query_capability.number);
566262306a36Sopenharmony_ci		netdev_dbg(netdev, "max_tx_entries_per_subcrq = %lld\n",
566362306a36Sopenharmony_ci			   adapter->max_tx_entries_per_subcrq);
566462306a36Sopenharmony_ci		break;
566562306a36Sopenharmony_ci	case MAX_RX_ADD_ENTRIES_PER_SUBCRQ:
566662306a36Sopenharmony_ci		adapter->max_rx_add_entries_per_subcrq =
566762306a36Sopenharmony_ci		    be64_to_cpu(crq->query_capability.number);
566862306a36Sopenharmony_ci		netdev_dbg(netdev, "max_rx_add_entrs_per_subcrq = %lld\n",
566962306a36Sopenharmony_ci			   adapter->max_rx_add_entries_per_subcrq);
567062306a36Sopenharmony_ci		break;
567162306a36Sopenharmony_ci	case TCP_IP_OFFLOAD:
567262306a36Sopenharmony_ci		adapter->tcp_ip_offload =
567362306a36Sopenharmony_ci		    be64_to_cpu(crq->query_capability.number);
567462306a36Sopenharmony_ci		netdev_dbg(netdev, "tcp_ip_offload = %lld\n",
567562306a36Sopenharmony_ci			   adapter->tcp_ip_offload);
567662306a36Sopenharmony_ci		break;
567762306a36Sopenharmony_ci	case PROMISC_SUPPORTED:
567862306a36Sopenharmony_ci		adapter->promisc_supported =
567962306a36Sopenharmony_ci		    be64_to_cpu(crq->query_capability.number);
568062306a36Sopenharmony_ci		netdev_dbg(netdev, "promisc_supported = %lld\n",
568162306a36Sopenharmony_ci			   adapter->promisc_supported);
568262306a36Sopenharmony_ci		break;
568362306a36Sopenharmony_ci	case MIN_MTU:
568462306a36Sopenharmony_ci		adapter->min_mtu = be64_to_cpu(crq->query_capability.number);
568562306a36Sopenharmony_ci		netdev->min_mtu = adapter->min_mtu - ETH_HLEN;
568662306a36Sopenharmony_ci		netdev_dbg(netdev, "min_mtu = %lld\n", adapter->min_mtu);
568762306a36Sopenharmony_ci		break;
568862306a36Sopenharmony_ci	case MAX_MTU:
568962306a36Sopenharmony_ci		adapter->max_mtu = be64_to_cpu(crq->query_capability.number);
569062306a36Sopenharmony_ci		netdev->max_mtu = adapter->max_mtu - ETH_HLEN;
569162306a36Sopenharmony_ci		netdev_dbg(netdev, "max_mtu = %lld\n", adapter->max_mtu);
569262306a36Sopenharmony_ci		break;
569362306a36Sopenharmony_ci	case MAX_MULTICAST_FILTERS:
569462306a36Sopenharmony_ci		adapter->max_multicast_filters =
569562306a36Sopenharmony_ci		    be64_to_cpu(crq->query_capability.number);
569662306a36Sopenharmony_ci		netdev_dbg(netdev, "max_multicast_filters = %lld\n",
569762306a36Sopenharmony_ci			   adapter->max_multicast_filters);
569862306a36Sopenharmony_ci		break;
569962306a36Sopenharmony_ci	case VLAN_HEADER_INSERTION:
570062306a36Sopenharmony_ci		adapter->vlan_header_insertion =
570162306a36Sopenharmony_ci		    be64_to_cpu(crq->query_capability.number);
570262306a36Sopenharmony_ci		if (adapter->vlan_header_insertion)
570362306a36Sopenharmony_ci			netdev->features |= NETIF_F_HW_VLAN_STAG_TX;
570462306a36Sopenharmony_ci		netdev_dbg(netdev, "vlan_header_insertion = %lld\n",
570562306a36Sopenharmony_ci			   adapter->vlan_header_insertion);
570662306a36Sopenharmony_ci		break;
570762306a36Sopenharmony_ci	case RX_VLAN_HEADER_INSERTION:
570862306a36Sopenharmony_ci		adapter->rx_vlan_header_insertion =
570962306a36Sopenharmony_ci		    be64_to_cpu(crq->query_capability.number);
571062306a36Sopenharmony_ci		netdev_dbg(netdev, "rx_vlan_header_insertion = %lld\n",
571162306a36Sopenharmony_ci			   adapter->rx_vlan_header_insertion);
571262306a36Sopenharmony_ci		break;
571362306a36Sopenharmony_ci	case MAX_TX_SG_ENTRIES:
571462306a36Sopenharmony_ci		adapter->max_tx_sg_entries =
571562306a36Sopenharmony_ci		    be64_to_cpu(crq->query_capability.number);
571662306a36Sopenharmony_ci		netdev_dbg(netdev, "max_tx_sg_entries = %lld\n",
571762306a36Sopenharmony_ci			   adapter->max_tx_sg_entries);
571862306a36Sopenharmony_ci		break;
571962306a36Sopenharmony_ci	case RX_SG_SUPPORTED:
572062306a36Sopenharmony_ci		adapter->rx_sg_supported =
572162306a36Sopenharmony_ci		    be64_to_cpu(crq->query_capability.number);
572262306a36Sopenharmony_ci		netdev_dbg(netdev, "rx_sg_supported = %lld\n",
572362306a36Sopenharmony_ci			   adapter->rx_sg_supported);
572462306a36Sopenharmony_ci		break;
572562306a36Sopenharmony_ci	case OPT_TX_COMP_SUB_QUEUES:
572662306a36Sopenharmony_ci		adapter->opt_tx_comp_sub_queues =
572762306a36Sopenharmony_ci		    be64_to_cpu(crq->query_capability.number);
572862306a36Sopenharmony_ci		netdev_dbg(netdev, "opt_tx_comp_sub_queues = %lld\n",
572962306a36Sopenharmony_ci			   adapter->opt_tx_comp_sub_queues);
573062306a36Sopenharmony_ci		break;
573162306a36Sopenharmony_ci	case OPT_RX_COMP_QUEUES:
573262306a36Sopenharmony_ci		adapter->opt_rx_comp_queues =
573362306a36Sopenharmony_ci		    be64_to_cpu(crq->query_capability.number);
573462306a36Sopenharmony_ci		netdev_dbg(netdev, "opt_rx_comp_queues = %lld\n",
573562306a36Sopenharmony_ci			   adapter->opt_rx_comp_queues);
573662306a36Sopenharmony_ci		break;
573762306a36Sopenharmony_ci	case OPT_RX_BUFADD_Q_PER_RX_COMP_Q:
573862306a36Sopenharmony_ci		adapter->opt_rx_bufadd_q_per_rx_comp_q =
573962306a36Sopenharmony_ci		    be64_to_cpu(crq->query_capability.number);
574062306a36Sopenharmony_ci		netdev_dbg(netdev, "opt_rx_bufadd_q_per_rx_comp_q = %lld\n",
574162306a36Sopenharmony_ci			   adapter->opt_rx_bufadd_q_per_rx_comp_q);
574262306a36Sopenharmony_ci		break;
574362306a36Sopenharmony_ci	case OPT_TX_ENTRIES_PER_SUBCRQ:
574462306a36Sopenharmony_ci		adapter->opt_tx_entries_per_subcrq =
574562306a36Sopenharmony_ci		    be64_to_cpu(crq->query_capability.number);
574662306a36Sopenharmony_ci		netdev_dbg(netdev, "opt_tx_entries_per_subcrq = %lld\n",
574762306a36Sopenharmony_ci			   adapter->opt_tx_entries_per_subcrq);
574862306a36Sopenharmony_ci		break;
574962306a36Sopenharmony_ci	case OPT_RXBA_ENTRIES_PER_SUBCRQ:
575062306a36Sopenharmony_ci		adapter->opt_rxba_entries_per_subcrq =
575162306a36Sopenharmony_ci		    be64_to_cpu(crq->query_capability.number);
575262306a36Sopenharmony_ci		netdev_dbg(netdev, "opt_rxba_entries_per_subcrq = %lld\n",
575362306a36Sopenharmony_ci			   adapter->opt_rxba_entries_per_subcrq);
575462306a36Sopenharmony_ci		break;
575562306a36Sopenharmony_ci	case TX_RX_DESC_REQ:
575662306a36Sopenharmony_ci		adapter->tx_rx_desc_req = crq->query_capability.number;
575762306a36Sopenharmony_ci		netdev_dbg(netdev, "tx_rx_desc_req = %llx\n",
575862306a36Sopenharmony_ci			   adapter->tx_rx_desc_req);
575962306a36Sopenharmony_ci		break;
576062306a36Sopenharmony_ci
576162306a36Sopenharmony_ci	default:
576262306a36Sopenharmony_ci		netdev_err(netdev, "Got invalid cap rsp %d\n",
576362306a36Sopenharmony_ci			   crq->query_capability.capability);
576462306a36Sopenharmony_ci	}
576562306a36Sopenharmony_ci
576662306a36Sopenharmony_ciout:
576762306a36Sopenharmony_ci	if (atomic_read(&adapter->running_cap_crqs) == 0)
576862306a36Sopenharmony_ci		send_request_cap(adapter, 0);
576962306a36Sopenharmony_ci}
577062306a36Sopenharmony_ci
577162306a36Sopenharmony_cistatic int send_query_phys_parms(struct ibmvnic_adapter *adapter)
577262306a36Sopenharmony_ci{
577362306a36Sopenharmony_ci	union ibmvnic_crq crq;
577462306a36Sopenharmony_ci	int rc;
577562306a36Sopenharmony_ci
577662306a36Sopenharmony_ci	memset(&crq, 0, sizeof(crq));
577762306a36Sopenharmony_ci	crq.query_phys_parms.first = IBMVNIC_CRQ_CMD;
577862306a36Sopenharmony_ci	crq.query_phys_parms.cmd = QUERY_PHYS_PARMS;
577962306a36Sopenharmony_ci
578062306a36Sopenharmony_ci	mutex_lock(&adapter->fw_lock);
578162306a36Sopenharmony_ci	adapter->fw_done_rc = 0;
578262306a36Sopenharmony_ci	reinit_completion(&adapter->fw_done);
578362306a36Sopenharmony_ci
578462306a36Sopenharmony_ci	rc = ibmvnic_send_crq(adapter, &crq);
578562306a36Sopenharmony_ci	if (rc) {
578662306a36Sopenharmony_ci		mutex_unlock(&adapter->fw_lock);
578762306a36Sopenharmony_ci		return rc;
578862306a36Sopenharmony_ci	}
578962306a36Sopenharmony_ci
579062306a36Sopenharmony_ci	rc = ibmvnic_wait_for_completion(adapter, &adapter->fw_done, 10000);
579162306a36Sopenharmony_ci	if (rc) {
579262306a36Sopenharmony_ci		mutex_unlock(&adapter->fw_lock);
579362306a36Sopenharmony_ci		return rc;
579462306a36Sopenharmony_ci	}
579562306a36Sopenharmony_ci
579662306a36Sopenharmony_ci	mutex_unlock(&adapter->fw_lock);
579762306a36Sopenharmony_ci	return adapter->fw_done_rc ? -EIO : 0;
579862306a36Sopenharmony_ci}
579962306a36Sopenharmony_ci
580062306a36Sopenharmony_cistatic int handle_query_phys_parms_rsp(union ibmvnic_crq *crq,
580162306a36Sopenharmony_ci				       struct ibmvnic_adapter *adapter)
580262306a36Sopenharmony_ci{
580362306a36Sopenharmony_ci	struct net_device *netdev = adapter->netdev;
580462306a36Sopenharmony_ci	int rc;
580562306a36Sopenharmony_ci	__be32 rspeed = cpu_to_be32(crq->query_phys_parms_rsp.speed);
580662306a36Sopenharmony_ci
580762306a36Sopenharmony_ci	rc = crq->query_phys_parms_rsp.rc.code;
580862306a36Sopenharmony_ci	if (rc) {
580962306a36Sopenharmony_ci		netdev_err(netdev, "Error %d in QUERY_PHYS_PARMS\n", rc);
581062306a36Sopenharmony_ci		return rc;
581162306a36Sopenharmony_ci	}
581262306a36Sopenharmony_ci	switch (rspeed) {
581362306a36Sopenharmony_ci	case IBMVNIC_10MBPS:
581462306a36Sopenharmony_ci		adapter->speed = SPEED_10;
581562306a36Sopenharmony_ci		break;
581662306a36Sopenharmony_ci	case IBMVNIC_100MBPS:
581762306a36Sopenharmony_ci		adapter->speed = SPEED_100;
581862306a36Sopenharmony_ci		break;
581962306a36Sopenharmony_ci	case IBMVNIC_1GBPS:
582062306a36Sopenharmony_ci		adapter->speed = SPEED_1000;
582162306a36Sopenharmony_ci		break;
582262306a36Sopenharmony_ci	case IBMVNIC_10GBPS:
582362306a36Sopenharmony_ci		adapter->speed = SPEED_10000;
582462306a36Sopenharmony_ci		break;
582562306a36Sopenharmony_ci	case IBMVNIC_25GBPS:
582662306a36Sopenharmony_ci		adapter->speed = SPEED_25000;
582762306a36Sopenharmony_ci		break;
582862306a36Sopenharmony_ci	case IBMVNIC_40GBPS:
582962306a36Sopenharmony_ci		adapter->speed = SPEED_40000;
583062306a36Sopenharmony_ci		break;
583162306a36Sopenharmony_ci	case IBMVNIC_50GBPS:
583262306a36Sopenharmony_ci		adapter->speed = SPEED_50000;
583362306a36Sopenharmony_ci		break;
583462306a36Sopenharmony_ci	case IBMVNIC_100GBPS:
583562306a36Sopenharmony_ci		adapter->speed = SPEED_100000;
583662306a36Sopenharmony_ci		break;
583762306a36Sopenharmony_ci	case IBMVNIC_200GBPS:
583862306a36Sopenharmony_ci		adapter->speed = SPEED_200000;
583962306a36Sopenharmony_ci		break;
584062306a36Sopenharmony_ci	default:
584162306a36Sopenharmony_ci		if (netif_carrier_ok(netdev))
584262306a36Sopenharmony_ci			netdev_warn(netdev, "Unknown speed 0x%08x\n", rspeed);
584362306a36Sopenharmony_ci		adapter->speed = SPEED_UNKNOWN;
584462306a36Sopenharmony_ci	}
584562306a36Sopenharmony_ci	if (crq->query_phys_parms_rsp.flags1 & IBMVNIC_FULL_DUPLEX)
584662306a36Sopenharmony_ci		adapter->duplex = DUPLEX_FULL;
584762306a36Sopenharmony_ci	else if (crq->query_phys_parms_rsp.flags1 & IBMVNIC_HALF_DUPLEX)
584862306a36Sopenharmony_ci		adapter->duplex = DUPLEX_HALF;
584962306a36Sopenharmony_ci	else
585062306a36Sopenharmony_ci		adapter->duplex = DUPLEX_UNKNOWN;
585162306a36Sopenharmony_ci
585262306a36Sopenharmony_ci	return rc;
585362306a36Sopenharmony_ci}
585462306a36Sopenharmony_ci
585562306a36Sopenharmony_cistatic void ibmvnic_handle_crq(union ibmvnic_crq *crq,
585662306a36Sopenharmony_ci			       struct ibmvnic_adapter *adapter)
585762306a36Sopenharmony_ci{
585862306a36Sopenharmony_ci	struct ibmvnic_generic_crq *gen_crq = &crq->generic;
585962306a36Sopenharmony_ci	struct net_device *netdev = adapter->netdev;
586062306a36Sopenharmony_ci	struct device *dev = &adapter->vdev->dev;
586162306a36Sopenharmony_ci	u64 *u64_crq = (u64 *)crq;
586262306a36Sopenharmony_ci	long rc;
586362306a36Sopenharmony_ci
586462306a36Sopenharmony_ci	netdev_dbg(netdev, "Handling CRQ: %016lx %016lx\n",
586562306a36Sopenharmony_ci		   (unsigned long)cpu_to_be64(u64_crq[0]),
586662306a36Sopenharmony_ci		   (unsigned long)cpu_to_be64(u64_crq[1]));
586762306a36Sopenharmony_ci	switch (gen_crq->first) {
586862306a36Sopenharmony_ci	case IBMVNIC_CRQ_INIT_RSP:
586962306a36Sopenharmony_ci		switch (gen_crq->cmd) {
587062306a36Sopenharmony_ci		case IBMVNIC_CRQ_INIT:
587162306a36Sopenharmony_ci			dev_info(dev, "Partner initialized\n");
587262306a36Sopenharmony_ci			adapter->from_passive_init = true;
587362306a36Sopenharmony_ci			/* Discard any stale login responses from prev reset.
587462306a36Sopenharmony_ci			 * CHECK: should we clear even on INIT_COMPLETE?
587562306a36Sopenharmony_ci			 */
587662306a36Sopenharmony_ci			adapter->login_pending = false;
587762306a36Sopenharmony_ci
587862306a36Sopenharmony_ci			if (adapter->state == VNIC_DOWN)
587962306a36Sopenharmony_ci				rc = ibmvnic_reset(adapter, VNIC_RESET_PASSIVE_INIT);
588062306a36Sopenharmony_ci			else
588162306a36Sopenharmony_ci				rc = ibmvnic_reset(adapter, VNIC_RESET_FAILOVER);
588262306a36Sopenharmony_ci
588362306a36Sopenharmony_ci			if (rc && rc != -EBUSY) {
588462306a36Sopenharmony_ci				/* We were unable to schedule the failover
588562306a36Sopenharmony_ci				 * reset either because the adapter was still
588662306a36Sopenharmony_ci				 * probing (eg: during kexec) or we could not
588762306a36Sopenharmony_ci				 * allocate memory. Clear the failover_pending
588862306a36Sopenharmony_ci				 * flag since no one else will. We ignore
588962306a36Sopenharmony_ci				 * EBUSY because it means either FAILOVER reset
589062306a36Sopenharmony_ci				 * is already scheduled or the adapter is
589162306a36Sopenharmony_ci				 * being removed.
589262306a36Sopenharmony_ci				 */
589362306a36Sopenharmony_ci				netdev_err(netdev,
589462306a36Sopenharmony_ci					   "Error %ld scheduling failover reset\n",
589562306a36Sopenharmony_ci					   rc);
589662306a36Sopenharmony_ci				adapter->failover_pending = false;
589762306a36Sopenharmony_ci			}
589862306a36Sopenharmony_ci
589962306a36Sopenharmony_ci			if (!completion_done(&adapter->init_done)) {
590062306a36Sopenharmony_ci				if (!adapter->init_done_rc)
590162306a36Sopenharmony_ci					adapter->init_done_rc = -EAGAIN;
590262306a36Sopenharmony_ci				complete(&adapter->init_done);
590362306a36Sopenharmony_ci			}
590462306a36Sopenharmony_ci
590562306a36Sopenharmony_ci			break;
590662306a36Sopenharmony_ci		case IBMVNIC_CRQ_INIT_COMPLETE:
590762306a36Sopenharmony_ci			dev_info(dev, "Partner initialization complete\n");
590862306a36Sopenharmony_ci			adapter->crq.active = true;
590962306a36Sopenharmony_ci			send_version_xchg(adapter);
591062306a36Sopenharmony_ci			break;
591162306a36Sopenharmony_ci		default:
591262306a36Sopenharmony_ci			dev_err(dev, "Unknown crq cmd: %d\n", gen_crq->cmd);
591362306a36Sopenharmony_ci		}
591462306a36Sopenharmony_ci		return;
591562306a36Sopenharmony_ci	case IBMVNIC_CRQ_XPORT_EVENT:
591662306a36Sopenharmony_ci		netif_carrier_off(netdev);
591762306a36Sopenharmony_ci		adapter->crq.active = false;
591862306a36Sopenharmony_ci		/* terminate any thread waiting for a response
591962306a36Sopenharmony_ci		 * from the device
592062306a36Sopenharmony_ci		 */
592162306a36Sopenharmony_ci		if (!completion_done(&adapter->fw_done)) {
592262306a36Sopenharmony_ci			adapter->fw_done_rc = -EIO;
592362306a36Sopenharmony_ci			complete(&adapter->fw_done);
592462306a36Sopenharmony_ci		}
592562306a36Sopenharmony_ci
592662306a36Sopenharmony_ci		/* if we got here during crq-init, retry crq-init */
592762306a36Sopenharmony_ci		if (!completion_done(&adapter->init_done)) {
592862306a36Sopenharmony_ci			adapter->init_done_rc = -EAGAIN;
592962306a36Sopenharmony_ci			complete(&adapter->init_done);
593062306a36Sopenharmony_ci		}
593162306a36Sopenharmony_ci
593262306a36Sopenharmony_ci		if (!completion_done(&adapter->stats_done))
593362306a36Sopenharmony_ci			complete(&adapter->stats_done);
593462306a36Sopenharmony_ci		if (test_bit(0, &adapter->resetting))
593562306a36Sopenharmony_ci			adapter->force_reset_recovery = true;
593662306a36Sopenharmony_ci		if (gen_crq->cmd == IBMVNIC_PARTITION_MIGRATED) {
593762306a36Sopenharmony_ci			dev_info(dev, "Migrated, re-enabling adapter\n");
593862306a36Sopenharmony_ci			ibmvnic_reset(adapter, VNIC_RESET_MOBILITY);
593962306a36Sopenharmony_ci		} else if (gen_crq->cmd == IBMVNIC_DEVICE_FAILOVER) {
594062306a36Sopenharmony_ci			dev_info(dev, "Backing device failover detected\n");
594162306a36Sopenharmony_ci			adapter->failover_pending = true;
594262306a36Sopenharmony_ci		} else {
594362306a36Sopenharmony_ci			/* The adapter lost the connection */
594462306a36Sopenharmony_ci			dev_err(dev, "Virtual Adapter failed (rc=%d)\n",
594562306a36Sopenharmony_ci				gen_crq->cmd);
594662306a36Sopenharmony_ci			ibmvnic_reset(adapter, VNIC_RESET_FATAL);
594762306a36Sopenharmony_ci		}
594862306a36Sopenharmony_ci		return;
594962306a36Sopenharmony_ci	case IBMVNIC_CRQ_CMD_RSP:
595062306a36Sopenharmony_ci		break;
595162306a36Sopenharmony_ci	default:
595262306a36Sopenharmony_ci		dev_err(dev, "Got an invalid msg type 0x%02x\n",
595362306a36Sopenharmony_ci			gen_crq->first);
595462306a36Sopenharmony_ci		return;
595562306a36Sopenharmony_ci	}
595662306a36Sopenharmony_ci
595762306a36Sopenharmony_ci	switch (gen_crq->cmd) {
595862306a36Sopenharmony_ci	case VERSION_EXCHANGE_RSP:
595962306a36Sopenharmony_ci		rc = crq->version_exchange_rsp.rc.code;
596062306a36Sopenharmony_ci		if (rc) {
596162306a36Sopenharmony_ci			dev_err(dev, "Error %ld in VERSION_EXCHG_RSP\n", rc);
596262306a36Sopenharmony_ci			break;
596362306a36Sopenharmony_ci		}
596462306a36Sopenharmony_ci		ibmvnic_version =
596562306a36Sopenharmony_ci			    be16_to_cpu(crq->version_exchange_rsp.version);
596662306a36Sopenharmony_ci		dev_info(dev, "Partner protocol version is %d\n",
596762306a36Sopenharmony_ci			 ibmvnic_version);
596862306a36Sopenharmony_ci		send_query_cap(adapter);
596962306a36Sopenharmony_ci		break;
597062306a36Sopenharmony_ci	case QUERY_CAPABILITY_RSP:
597162306a36Sopenharmony_ci		handle_query_cap_rsp(crq, adapter);
597262306a36Sopenharmony_ci		break;
597362306a36Sopenharmony_ci	case QUERY_MAP_RSP:
597462306a36Sopenharmony_ci		handle_query_map_rsp(crq, adapter);
597562306a36Sopenharmony_ci		break;
597662306a36Sopenharmony_ci	case REQUEST_MAP_RSP:
597762306a36Sopenharmony_ci		adapter->fw_done_rc = crq->request_map_rsp.rc.code;
597862306a36Sopenharmony_ci		complete(&adapter->fw_done);
597962306a36Sopenharmony_ci		break;
598062306a36Sopenharmony_ci	case REQUEST_UNMAP_RSP:
598162306a36Sopenharmony_ci		handle_request_unmap_rsp(crq, adapter);
598262306a36Sopenharmony_ci		break;
598362306a36Sopenharmony_ci	case REQUEST_CAPABILITY_RSP:
598462306a36Sopenharmony_ci		handle_request_cap_rsp(crq, adapter);
598562306a36Sopenharmony_ci		break;
598662306a36Sopenharmony_ci	case LOGIN_RSP:
598762306a36Sopenharmony_ci		netdev_dbg(netdev, "Got Login Response\n");
598862306a36Sopenharmony_ci		handle_login_rsp(crq, adapter);
598962306a36Sopenharmony_ci		break;
599062306a36Sopenharmony_ci	case LOGICAL_LINK_STATE_RSP:
599162306a36Sopenharmony_ci		netdev_dbg(netdev,
599262306a36Sopenharmony_ci			   "Got Logical Link State Response, state: %d rc: %d\n",
599362306a36Sopenharmony_ci			   crq->logical_link_state_rsp.link_state,
599462306a36Sopenharmony_ci			   crq->logical_link_state_rsp.rc.code);
599562306a36Sopenharmony_ci		adapter->logical_link_state =
599662306a36Sopenharmony_ci		    crq->logical_link_state_rsp.link_state;
599762306a36Sopenharmony_ci		adapter->init_done_rc = crq->logical_link_state_rsp.rc.code;
599862306a36Sopenharmony_ci		complete(&adapter->init_done);
599962306a36Sopenharmony_ci		break;
600062306a36Sopenharmony_ci	case LINK_STATE_INDICATION:
600162306a36Sopenharmony_ci		netdev_dbg(netdev, "Got Logical Link State Indication\n");
600262306a36Sopenharmony_ci		adapter->phys_link_state =
600362306a36Sopenharmony_ci		    crq->link_state_indication.phys_link_state;
600462306a36Sopenharmony_ci		adapter->logical_link_state =
600562306a36Sopenharmony_ci		    crq->link_state_indication.logical_link_state;
600662306a36Sopenharmony_ci		if (adapter->phys_link_state && adapter->logical_link_state)
600762306a36Sopenharmony_ci			netif_carrier_on(netdev);
600862306a36Sopenharmony_ci		else
600962306a36Sopenharmony_ci			netif_carrier_off(netdev);
601062306a36Sopenharmony_ci		break;
601162306a36Sopenharmony_ci	case CHANGE_MAC_ADDR_RSP:
601262306a36Sopenharmony_ci		netdev_dbg(netdev, "Got MAC address change Response\n");
601362306a36Sopenharmony_ci		adapter->fw_done_rc = handle_change_mac_rsp(crq, adapter);
601462306a36Sopenharmony_ci		break;
601562306a36Sopenharmony_ci	case ERROR_INDICATION:
601662306a36Sopenharmony_ci		netdev_dbg(netdev, "Got Error Indication\n");
601762306a36Sopenharmony_ci		handle_error_indication(crq, adapter);
601862306a36Sopenharmony_ci		break;
601962306a36Sopenharmony_ci	case REQUEST_STATISTICS_RSP:
602062306a36Sopenharmony_ci		netdev_dbg(netdev, "Got Statistics Response\n");
602162306a36Sopenharmony_ci		complete(&adapter->stats_done);
602262306a36Sopenharmony_ci		break;
602362306a36Sopenharmony_ci	case QUERY_IP_OFFLOAD_RSP:
602462306a36Sopenharmony_ci		netdev_dbg(netdev, "Got Query IP offload Response\n");
602562306a36Sopenharmony_ci		handle_query_ip_offload_rsp(adapter);
602662306a36Sopenharmony_ci		break;
602762306a36Sopenharmony_ci	case MULTICAST_CTRL_RSP:
602862306a36Sopenharmony_ci		netdev_dbg(netdev, "Got multicast control Response\n");
602962306a36Sopenharmony_ci		break;
603062306a36Sopenharmony_ci	case CONTROL_IP_OFFLOAD_RSP:
603162306a36Sopenharmony_ci		netdev_dbg(netdev, "Got Control IP offload Response\n");
603262306a36Sopenharmony_ci		dma_unmap_single(dev, adapter->ip_offload_ctrl_tok,
603362306a36Sopenharmony_ci				 sizeof(adapter->ip_offload_ctrl),
603462306a36Sopenharmony_ci				 DMA_TO_DEVICE);
603562306a36Sopenharmony_ci		complete(&adapter->init_done);
603662306a36Sopenharmony_ci		break;
603762306a36Sopenharmony_ci	case COLLECT_FW_TRACE_RSP:
603862306a36Sopenharmony_ci		netdev_dbg(netdev, "Got Collect firmware trace Response\n");
603962306a36Sopenharmony_ci		complete(&adapter->fw_done);
604062306a36Sopenharmony_ci		break;
604162306a36Sopenharmony_ci	case GET_VPD_SIZE_RSP:
604262306a36Sopenharmony_ci		handle_vpd_size_rsp(crq, adapter);
604362306a36Sopenharmony_ci		break;
604462306a36Sopenharmony_ci	case GET_VPD_RSP:
604562306a36Sopenharmony_ci		handle_vpd_rsp(crq, adapter);
604662306a36Sopenharmony_ci		break;
604762306a36Sopenharmony_ci	case QUERY_PHYS_PARMS_RSP:
604862306a36Sopenharmony_ci		adapter->fw_done_rc = handle_query_phys_parms_rsp(crq, adapter);
604962306a36Sopenharmony_ci		complete(&adapter->fw_done);
605062306a36Sopenharmony_ci		break;
605162306a36Sopenharmony_ci	default:
605262306a36Sopenharmony_ci		netdev_err(netdev, "Got an invalid cmd type 0x%02x\n",
605362306a36Sopenharmony_ci			   gen_crq->cmd);
605462306a36Sopenharmony_ci	}
605562306a36Sopenharmony_ci}
605662306a36Sopenharmony_ci
605762306a36Sopenharmony_cistatic irqreturn_t ibmvnic_interrupt(int irq, void *instance)
605862306a36Sopenharmony_ci{
605962306a36Sopenharmony_ci	struct ibmvnic_adapter *adapter = instance;
606062306a36Sopenharmony_ci
606162306a36Sopenharmony_ci	tasklet_schedule(&adapter->tasklet);
606262306a36Sopenharmony_ci	return IRQ_HANDLED;
606362306a36Sopenharmony_ci}
606462306a36Sopenharmony_ci
606562306a36Sopenharmony_cistatic void ibmvnic_tasklet(struct tasklet_struct *t)
606662306a36Sopenharmony_ci{
606762306a36Sopenharmony_ci	struct ibmvnic_adapter *adapter = from_tasklet(adapter, t, tasklet);
606862306a36Sopenharmony_ci	struct ibmvnic_crq_queue *queue = &adapter->crq;
606962306a36Sopenharmony_ci	union ibmvnic_crq *crq;
607062306a36Sopenharmony_ci	unsigned long flags;
607162306a36Sopenharmony_ci
607262306a36Sopenharmony_ci	spin_lock_irqsave(&queue->lock, flags);
607362306a36Sopenharmony_ci
607462306a36Sopenharmony_ci	/* Pull all the valid messages off the CRQ */
607562306a36Sopenharmony_ci	while ((crq = ibmvnic_next_crq(adapter)) != NULL) {
607662306a36Sopenharmony_ci		/* This barrier makes sure ibmvnic_next_crq()'s
607762306a36Sopenharmony_ci		 * crq->generic.first & IBMVNIC_CRQ_CMD_RSP is loaded
607862306a36Sopenharmony_ci		 * before ibmvnic_handle_crq()'s
607962306a36Sopenharmony_ci		 * switch(gen_crq->first) and switch(gen_crq->cmd).
608062306a36Sopenharmony_ci		 */
608162306a36Sopenharmony_ci		dma_rmb();
608262306a36Sopenharmony_ci		ibmvnic_handle_crq(crq, adapter);
608362306a36Sopenharmony_ci		crq->generic.first = 0;
608462306a36Sopenharmony_ci	}
608562306a36Sopenharmony_ci
608662306a36Sopenharmony_ci	spin_unlock_irqrestore(&queue->lock, flags);
608762306a36Sopenharmony_ci}
608862306a36Sopenharmony_ci
608962306a36Sopenharmony_cistatic int ibmvnic_reenable_crq_queue(struct ibmvnic_adapter *adapter)
609062306a36Sopenharmony_ci{
609162306a36Sopenharmony_ci	struct vio_dev *vdev = adapter->vdev;
609262306a36Sopenharmony_ci	int rc;
609362306a36Sopenharmony_ci
609462306a36Sopenharmony_ci	do {
609562306a36Sopenharmony_ci		rc = plpar_hcall_norets(H_ENABLE_CRQ, vdev->unit_address);
609662306a36Sopenharmony_ci	} while (rc == H_IN_PROGRESS || rc == H_BUSY || H_IS_LONG_BUSY(rc));
609762306a36Sopenharmony_ci
609862306a36Sopenharmony_ci	if (rc)
609962306a36Sopenharmony_ci		dev_err(&vdev->dev, "Error enabling adapter (rc=%d)\n", rc);
610062306a36Sopenharmony_ci
610162306a36Sopenharmony_ci	return rc;
610262306a36Sopenharmony_ci}
610362306a36Sopenharmony_ci
610462306a36Sopenharmony_cistatic int ibmvnic_reset_crq(struct ibmvnic_adapter *adapter)
610562306a36Sopenharmony_ci{
610662306a36Sopenharmony_ci	struct ibmvnic_crq_queue *crq = &adapter->crq;
610762306a36Sopenharmony_ci	struct device *dev = &adapter->vdev->dev;
610862306a36Sopenharmony_ci	struct vio_dev *vdev = adapter->vdev;
610962306a36Sopenharmony_ci	int rc;
611062306a36Sopenharmony_ci
611162306a36Sopenharmony_ci	/* Close the CRQ */
611262306a36Sopenharmony_ci	do {
611362306a36Sopenharmony_ci		rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
611462306a36Sopenharmony_ci	} while (rc == H_BUSY || H_IS_LONG_BUSY(rc));
611562306a36Sopenharmony_ci
611662306a36Sopenharmony_ci	/* Clean out the queue */
611762306a36Sopenharmony_ci	if (!crq->msgs)
611862306a36Sopenharmony_ci		return -EINVAL;
611962306a36Sopenharmony_ci
612062306a36Sopenharmony_ci	memset(crq->msgs, 0, PAGE_SIZE);
612162306a36Sopenharmony_ci	crq->cur = 0;
612262306a36Sopenharmony_ci	crq->active = false;
612362306a36Sopenharmony_ci
612462306a36Sopenharmony_ci	/* And re-open it again */
612562306a36Sopenharmony_ci	rc = plpar_hcall_norets(H_REG_CRQ, vdev->unit_address,
612662306a36Sopenharmony_ci				crq->msg_token, PAGE_SIZE);
612762306a36Sopenharmony_ci
612862306a36Sopenharmony_ci	if (rc == H_CLOSED)
612962306a36Sopenharmony_ci		/* Adapter is good, but other end is not ready */
613062306a36Sopenharmony_ci		dev_warn(dev, "Partner adapter not ready\n");
613162306a36Sopenharmony_ci	else if (rc != 0)
613262306a36Sopenharmony_ci		dev_warn(dev, "Couldn't register crq (rc=%d)\n", rc);
613362306a36Sopenharmony_ci
613462306a36Sopenharmony_ci	return rc;
613562306a36Sopenharmony_ci}
613662306a36Sopenharmony_ci
613762306a36Sopenharmony_cistatic void release_crq_queue(struct ibmvnic_adapter *adapter)
613862306a36Sopenharmony_ci{
613962306a36Sopenharmony_ci	struct ibmvnic_crq_queue *crq = &adapter->crq;
614062306a36Sopenharmony_ci	struct vio_dev *vdev = adapter->vdev;
614162306a36Sopenharmony_ci	long rc;
614262306a36Sopenharmony_ci
614362306a36Sopenharmony_ci	if (!crq->msgs)
614462306a36Sopenharmony_ci		return;
614562306a36Sopenharmony_ci
614662306a36Sopenharmony_ci	netdev_dbg(adapter->netdev, "Releasing CRQ\n");
614762306a36Sopenharmony_ci	free_irq(vdev->irq, adapter);
614862306a36Sopenharmony_ci	tasklet_kill(&adapter->tasklet);
614962306a36Sopenharmony_ci	do {
615062306a36Sopenharmony_ci		rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
615162306a36Sopenharmony_ci	} while (rc == H_BUSY || H_IS_LONG_BUSY(rc));
615262306a36Sopenharmony_ci
615362306a36Sopenharmony_ci	dma_unmap_single(&vdev->dev, crq->msg_token, PAGE_SIZE,
615462306a36Sopenharmony_ci			 DMA_BIDIRECTIONAL);
615562306a36Sopenharmony_ci	free_page((unsigned long)crq->msgs);
615662306a36Sopenharmony_ci	crq->msgs = NULL;
615762306a36Sopenharmony_ci	crq->active = false;
615862306a36Sopenharmony_ci}
615962306a36Sopenharmony_ci
616062306a36Sopenharmony_cistatic int init_crq_queue(struct ibmvnic_adapter *adapter)
616162306a36Sopenharmony_ci{
616262306a36Sopenharmony_ci	struct ibmvnic_crq_queue *crq = &adapter->crq;
616362306a36Sopenharmony_ci	struct device *dev = &adapter->vdev->dev;
616462306a36Sopenharmony_ci	struct vio_dev *vdev = adapter->vdev;
616562306a36Sopenharmony_ci	int rc, retrc = -ENOMEM;
616662306a36Sopenharmony_ci
616762306a36Sopenharmony_ci	if (crq->msgs)
616862306a36Sopenharmony_ci		return 0;
616962306a36Sopenharmony_ci
617062306a36Sopenharmony_ci	crq->msgs = (union ibmvnic_crq *)get_zeroed_page(GFP_KERNEL);
617162306a36Sopenharmony_ci	/* Should we allocate more than one page? */
617262306a36Sopenharmony_ci
617362306a36Sopenharmony_ci	if (!crq->msgs)
617462306a36Sopenharmony_ci		return -ENOMEM;
617562306a36Sopenharmony_ci
617662306a36Sopenharmony_ci	crq->size = PAGE_SIZE / sizeof(*crq->msgs);
617762306a36Sopenharmony_ci	crq->msg_token = dma_map_single(dev, crq->msgs, PAGE_SIZE,
617862306a36Sopenharmony_ci					DMA_BIDIRECTIONAL);
617962306a36Sopenharmony_ci	if (dma_mapping_error(dev, crq->msg_token))
618062306a36Sopenharmony_ci		goto map_failed;
618162306a36Sopenharmony_ci
618262306a36Sopenharmony_ci	rc = plpar_hcall_norets(H_REG_CRQ, vdev->unit_address,
618362306a36Sopenharmony_ci				crq->msg_token, PAGE_SIZE);
618462306a36Sopenharmony_ci
618562306a36Sopenharmony_ci	if (rc == H_RESOURCE)
618662306a36Sopenharmony_ci		/* maybe kexecing and resource is busy. try a reset */
618762306a36Sopenharmony_ci		rc = ibmvnic_reset_crq(adapter);
618862306a36Sopenharmony_ci	retrc = rc;
618962306a36Sopenharmony_ci
619062306a36Sopenharmony_ci	if (rc == H_CLOSED) {
619162306a36Sopenharmony_ci		dev_warn(dev, "Partner adapter not ready\n");
619262306a36Sopenharmony_ci	} else if (rc) {
619362306a36Sopenharmony_ci		dev_warn(dev, "Error %d opening adapter\n", rc);
619462306a36Sopenharmony_ci		goto reg_crq_failed;
619562306a36Sopenharmony_ci	}
619662306a36Sopenharmony_ci
619762306a36Sopenharmony_ci	retrc = 0;
619862306a36Sopenharmony_ci
619962306a36Sopenharmony_ci	tasklet_setup(&adapter->tasklet, (void *)ibmvnic_tasklet);
620062306a36Sopenharmony_ci
620162306a36Sopenharmony_ci	netdev_dbg(adapter->netdev, "registering irq 0x%x\n", vdev->irq);
620262306a36Sopenharmony_ci	snprintf(crq->name, sizeof(crq->name), "ibmvnic-%x",
620362306a36Sopenharmony_ci		 adapter->vdev->unit_address);
620462306a36Sopenharmony_ci	rc = request_irq(vdev->irq, ibmvnic_interrupt, 0, crq->name, adapter);
620562306a36Sopenharmony_ci	if (rc) {
620662306a36Sopenharmony_ci		dev_err(dev, "Couldn't register irq 0x%x. rc=%d\n",
620762306a36Sopenharmony_ci			vdev->irq, rc);
620862306a36Sopenharmony_ci		goto req_irq_failed;
620962306a36Sopenharmony_ci	}
621062306a36Sopenharmony_ci
621162306a36Sopenharmony_ci	rc = vio_enable_interrupts(vdev);
621262306a36Sopenharmony_ci	if (rc) {
621362306a36Sopenharmony_ci		dev_err(dev, "Error %d enabling interrupts\n", rc);
621462306a36Sopenharmony_ci		goto req_irq_failed;
621562306a36Sopenharmony_ci	}
621662306a36Sopenharmony_ci
621762306a36Sopenharmony_ci	crq->cur = 0;
621862306a36Sopenharmony_ci	spin_lock_init(&crq->lock);
621962306a36Sopenharmony_ci
622062306a36Sopenharmony_ci	/* process any CRQs that were queued before we enabled interrupts */
622162306a36Sopenharmony_ci	tasklet_schedule(&adapter->tasklet);
622262306a36Sopenharmony_ci
622362306a36Sopenharmony_ci	return retrc;
622462306a36Sopenharmony_ci
622562306a36Sopenharmony_cireq_irq_failed:
622662306a36Sopenharmony_ci	tasklet_kill(&adapter->tasklet);
622762306a36Sopenharmony_ci	do {
622862306a36Sopenharmony_ci		rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
622962306a36Sopenharmony_ci	} while (rc == H_BUSY || H_IS_LONG_BUSY(rc));
623062306a36Sopenharmony_cireg_crq_failed:
623162306a36Sopenharmony_ci	dma_unmap_single(dev, crq->msg_token, PAGE_SIZE, DMA_BIDIRECTIONAL);
623262306a36Sopenharmony_cimap_failed:
623362306a36Sopenharmony_ci	free_page((unsigned long)crq->msgs);
623462306a36Sopenharmony_ci	crq->msgs = NULL;
623562306a36Sopenharmony_ci	return retrc;
623662306a36Sopenharmony_ci}
623762306a36Sopenharmony_ci
623862306a36Sopenharmony_cistatic int ibmvnic_reset_init(struct ibmvnic_adapter *adapter, bool reset)
623962306a36Sopenharmony_ci{
624062306a36Sopenharmony_ci	struct device *dev = &adapter->vdev->dev;
624162306a36Sopenharmony_ci	unsigned long timeout = msecs_to_jiffies(20000);
624262306a36Sopenharmony_ci	u64 old_num_rx_queues = adapter->req_rx_queues;
624362306a36Sopenharmony_ci	u64 old_num_tx_queues = adapter->req_tx_queues;
624462306a36Sopenharmony_ci	int rc;
624562306a36Sopenharmony_ci
624662306a36Sopenharmony_ci	adapter->from_passive_init = false;
624762306a36Sopenharmony_ci
624862306a36Sopenharmony_ci	rc = ibmvnic_send_crq_init(adapter);
624962306a36Sopenharmony_ci	if (rc) {
625062306a36Sopenharmony_ci		dev_err(dev, "Send crq init failed with error %d\n", rc);
625162306a36Sopenharmony_ci		return rc;
625262306a36Sopenharmony_ci	}
625362306a36Sopenharmony_ci
625462306a36Sopenharmony_ci	if (!wait_for_completion_timeout(&adapter->init_done, timeout)) {
625562306a36Sopenharmony_ci		dev_err(dev, "Initialization sequence timed out\n");
625662306a36Sopenharmony_ci		return -ETIMEDOUT;
625762306a36Sopenharmony_ci	}
625862306a36Sopenharmony_ci
625962306a36Sopenharmony_ci	if (adapter->init_done_rc) {
626062306a36Sopenharmony_ci		release_crq_queue(adapter);
626162306a36Sopenharmony_ci		dev_err(dev, "CRQ-init failed, %d\n", adapter->init_done_rc);
626262306a36Sopenharmony_ci		return adapter->init_done_rc;
626362306a36Sopenharmony_ci	}
626462306a36Sopenharmony_ci
626562306a36Sopenharmony_ci	if (adapter->from_passive_init) {
626662306a36Sopenharmony_ci		adapter->state = VNIC_OPEN;
626762306a36Sopenharmony_ci		adapter->from_passive_init = false;
626862306a36Sopenharmony_ci		dev_err(dev, "CRQ-init failed, passive-init\n");
626962306a36Sopenharmony_ci		return -EINVAL;
627062306a36Sopenharmony_ci	}
627162306a36Sopenharmony_ci
627262306a36Sopenharmony_ci	if (reset &&
627362306a36Sopenharmony_ci	    test_bit(0, &adapter->resetting) && !adapter->wait_for_reset &&
627462306a36Sopenharmony_ci	    adapter->reset_reason != VNIC_RESET_MOBILITY) {
627562306a36Sopenharmony_ci		if (adapter->req_rx_queues != old_num_rx_queues ||
627662306a36Sopenharmony_ci		    adapter->req_tx_queues != old_num_tx_queues) {
627762306a36Sopenharmony_ci			release_sub_crqs(adapter, 0);
627862306a36Sopenharmony_ci			rc = init_sub_crqs(adapter);
627962306a36Sopenharmony_ci		} else {
628062306a36Sopenharmony_ci			/* no need to reinitialize completely, but we do
628162306a36Sopenharmony_ci			 * need to clean up transmits that were in flight
628262306a36Sopenharmony_ci			 * when we processed the reset.  Failure to do so
628362306a36Sopenharmony_ci			 * will confound the upper layer, usually TCP, by
628462306a36Sopenharmony_ci			 * creating the illusion of transmits that are
628562306a36Sopenharmony_ci			 * awaiting completion.
628662306a36Sopenharmony_ci			 */
628762306a36Sopenharmony_ci			clean_tx_pools(adapter);
628862306a36Sopenharmony_ci
628962306a36Sopenharmony_ci			rc = reset_sub_crq_queues(adapter);
629062306a36Sopenharmony_ci		}
629162306a36Sopenharmony_ci	} else {
629262306a36Sopenharmony_ci		rc = init_sub_crqs(adapter);
629362306a36Sopenharmony_ci	}
629462306a36Sopenharmony_ci
629562306a36Sopenharmony_ci	if (rc) {
629662306a36Sopenharmony_ci		dev_err(dev, "Initialization of sub crqs failed\n");
629762306a36Sopenharmony_ci		release_crq_queue(adapter);
629862306a36Sopenharmony_ci		return rc;
629962306a36Sopenharmony_ci	}
630062306a36Sopenharmony_ci
630162306a36Sopenharmony_ci	rc = init_sub_crq_irqs(adapter);
630262306a36Sopenharmony_ci	if (rc) {
630362306a36Sopenharmony_ci		dev_err(dev, "Failed to initialize sub crq irqs\n");
630462306a36Sopenharmony_ci		release_crq_queue(adapter);
630562306a36Sopenharmony_ci	}
630662306a36Sopenharmony_ci
630762306a36Sopenharmony_ci	return rc;
630862306a36Sopenharmony_ci}
630962306a36Sopenharmony_ci
631062306a36Sopenharmony_cistatic struct device_attribute dev_attr_failover;
631162306a36Sopenharmony_ci
631262306a36Sopenharmony_cistatic int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
631362306a36Sopenharmony_ci{
631462306a36Sopenharmony_ci	struct ibmvnic_adapter *adapter;
631562306a36Sopenharmony_ci	struct net_device *netdev;
631662306a36Sopenharmony_ci	unsigned char *mac_addr_p;
631762306a36Sopenharmony_ci	unsigned long flags;
631862306a36Sopenharmony_ci	bool init_success;
631962306a36Sopenharmony_ci	int rc;
632062306a36Sopenharmony_ci
632162306a36Sopenharmony_ci	dev_dbg(&dev->dev, "entering ibmvnic_probe for UA 0x%x\n",
632262306a36Sopenharmony_ci		dev->unit_address);
632362306a36Sopenharmony_ci
632462306a36Sopenharmony_ci	mac_addr_p = (unsigned char *)vio_get_attribute(dev,
632562306a36Sopenharmony_ci							VETH_MAC_ADDR, NULL);
632662306a36Sopenharmony_ci	if (!mac_addr_p) {
632762306a36Sopenharmony_ci		dev_err(&dev->dev,
632862306a36Sopenharmony_ci			"(%s:%3.3d) ERROR: Can't find MAC_ADDR attribute\n",
632962306a36Sopenharmony_ci			__FILE__, __LINE__);
633062306a36Sopenharmony_ci		return 0;
633162306a36Sopenharmony_ci	}
633262306a36Sopenharmony_ci
633362306a36Sopenharmony_ci	netdev = alloc_etherdev_mq(sizeof(struct ibmvnic_adapter),
633462306a36Sopenharmony_ci				   IBMVNIC_MAX_QUEUES);
633562306a36Sopenharmony_ci	if (!netdev)
633662306a36Sopenharmony_ci		return -ENOMEM;
633762306a36Sopenharmony_ci
633862306a36Sopenharmony_ci	adapter = netdev_priv(netdev);
633962306a36Sopenharmony_ci	adapter->state = VNIC_PROBING;
634062306a36Sopenharmony_ci	dev_set_drvdata(&dev->dev, netdev);
634162306a36Sopenharmony_ci	adapter->vdev = dev;
634262306a36Sopenharmony_ci	adapter->netdev = netdev;
634362306a36Sopenharmony_ci	adapter->login_pending = false;
634462306a36Sopenharmony_ci	memset(&adapter->map_ids, 0, sizeof(adapter->map_ids));
634562306a36Sopenharmony_ci	/* map_ids start at 1, so ensure map_id 0 is always "in-use" */
634662306a36Sopenharmony_ci	bitmap_set(adapter->map_ids, 0, 1);
634762306a36Sopenharmony_ci
634862306a36Sopenharmony_ci	ether_addr_copy(adapter->mac_addr, mac_addr_p);
634962306a36Sopenharmony_ci	eth_hw_addr_set(netdev, adapter->mac_addr);
635062306a36Sopenharmony_ci	netdev->irq = dev->irq;
635162306a36Sopenharmony_ci	netdev->netdev_ops = &ibmvnic_netdev_ops;
635262306a36Sopenharmony_ci	netdev->ethtool_ops = &ibmvnic_ethtool_ops;
635362306a36Sopenharmony_ci	SET_NETDEV_DEV(netdev, &dev->dev);
635462306a36Sopenharmony_ci
635562306a36Sopenharmony_ci	INIT_WORK(&adapter->ibmvnic_reset, __ibmvnic_reset);
635662306a36Sopenharmony_ci	INIT_DELAYED_WORK(&adapter->ibmvnic_delayed_reset,
635762306a36Sopenharmony_ci			  __ibmvnic_delayed_reset);
635862306a36Sopenharmony_ci	INIT_LIST_HEAD(&adapter->rwi_list);
635962306a36Sopenharmony_ci	spin_lock_init(&adapter->rwi_lock);
636062306a36Sopenharmony_ci	spin_lock_init(&adapter->state_lock);
636162306a36Sopenharmony_ci	mutex_init(&adapter->fw_lock);
636262306a36Sopenharmony_ci	init_completion(&adapter->probe_done);
636362306a36Sopenharmony_ci	init_completion(&adapter->init_done);
636462306a36Sopenharmony_ci	init_completion(&adapter->fw_done);
636562306a36Sopenharmony_ci	init_completion(&adapter->reset_done);
636662306a36Sopenharmony_ci	init_completion(&adapter->stats_done);
636762306a36Sopenharmony_ci	clear_bit(0, &adapter->resetting);
636862306a36Sopenharmony_ci	adapter->prev_rx_buf_sz = 0;
636962306a36Sopenharmony_ci	adapter->prev_mtu = 0;
637062306a36Sopenharmony_ci
637162306a36Sopenharmony_ci	init_success = false;
637262306a36Sopenharmony_ci	do {
637362306a36Sopenharmony_ci		reinit_init_done(adapter);
637462306a36Sopenharmony_ci
637562306a36Sopenharmony_ci		/* clear any failovers we got in the previous pass
637662306a36Sopenharmony_ci		 * since we are reinitializing the CRQ
637762306a36Sopenharmony_ci		 */
637862306a36Sopenharmony_ci		adapter->failover_pending = false;
637962306a36Sopenharmony_ci
638062306a36Sopenharmony_ci		/* If we had already initialized CRQ, we may have one or
638162306a36Sopenharmony_ci		 * more resets queued already. Discard those and release
638262306a36Sopenharmony_ci		 * the CRQ before initializing the CRQ again.
638362306a36Sopenharmony_ci		 */
638462306a36Sopenharmony_ci		release_crq_queue(adapter);
638562306a36Sopenharmony_ci
638662306a36Sopenharmony_ci		/* Since we are still in PROBING state, __ibmvnic_reset()
638762306a36Sopenharmony_ci		 * will not access the ->rwi_list and since we released CRQ,
638862306a36Sopenharmony_ci		 * we won't get _new_ transport events. But there maybe an
638962306a36Sopenharmony_ci		 * ongoing ibmvnic_reset() call. So serialize access to
639062306a36Sopenharmony_ci		 * rwi_list. If we win the race, ibvmnic_reset() could add
639162306a36Sopenharmony_ci		 * a reset after we purged but thats ok - we just may end
639262306a36Sopenharmony_ci		 * up with an extra reset (i.e similar to having two or more
639362306a36Sopenharmony_ci		 * resets in the queue at once).
639462306a36Sopenharmony_ci		 * CHECK.
639562306a36Sopenharmony_ci		 */
639662306a36Sopenharmony_ci		spin_lock_irqsave(&adapter->rwi_lock, flags);
639762306a36Sopenharmony_ci		flush_reset_queue(adapter);
639862306a36Sopenharmony_ci		spin_unlock_irqrestore(&adapter->rwi_lock, flags);
639962306a36Sopenharmony_ci
640062306a36Sopenharmony_ci		rc = init_crq_queue(adapter);
640162306a36Sopenharmony_ci		if (rc) {
640262306a36Sopenharmony_ci			dev_err(&dev->dev, "Couldn't initialize crq. rc=%d\n",
640362306a36Sopenharmony_ci				rc);
640462306a36Sopenharmony_ci			goto ibmvnic_init_fail;
640562306a36Sopenharmony_ci		}
640662306a36Sopenharmony_ci
640762306a36Sopenharmony_ci		rc = ibmvnic_reset_init(adapter, false);
640862306a36Sopenharmony_ci	} while (rc == -EAGAIN);
640962306a36Sopenharmony_ci
641062306a36Sopenharmony_ci	/* We are ignoring the error from ibmvnic_reset_init() assuming that the
641162306a36Sopenharmony_ci	 * partner is not ready. CRQ is not active. When the partner becomes
641262306a36Sopenharmony_ci	 * ready, we will do the passive init reset.
641362306a36Sopenharmony_ci	 */
641462306a36Sopenharmony_ci
641562306a36Sopenharmony_ci	if (!rc)
641662306a36Sopenharmony_ci		init_success = true;
641762306a36Sopenharmony_ci
641862306a36Sopenharmony_ci	rc = init_stats_buffers(adapter);
641962306a36Sopenharmony_ci	if (rc)
642062306a36Sopenharmony_ci		goto ibmvnic_init_fail;
642162306a36Sopenharmony_ci
642262306a36Sopenharmony_ci	rc = init_stats_token(adapter);
642362306a36Sopenharmony_ci	if (rc)
642462306a36Sopenharmony_ci		goto ibmvnic_stats_fail;
642562306a36Sopenharmony_ci
642662306a36Sopenharmony_ci	rc = device_create_file(&dev->dev, &dev_attr_failover);
642762306a36Sopenharmony_ci	if (rc)
642862306a36Sopenharmony_ci		goto ibmvnic_dev_file_err;
642962306a36Sopenharmony_ci
643062306a36Sopenharmony_ci	netif_carrier_off(netdev);
643162306a36Sopenharmony_ci
643262306a36Sopenharmony_ci	if (init_success) {
643362306a36Sopenharmony_ci		adapter->state = VNIC_PROBED;
643462306a36Sopenharmony_ci		netdev->mtu = adapter->req_mtu - ETH_HLEN;
643562306a36Sopenharmony_ci		netdev->min_mtu = adapter->min_mtu - ETH_HLEN;
643662306a36Sopenharmony_ci		netdev->max_mtu = adapter->max_mtu - ETH_HLEN;
643762306a36Sopenharmony_ci	} else {
643862306a36Sopenharmony_ci		adapter->state = VNIC_DOWN;
643962306a36Sopenharmony_ci	}
644062306a36Sopenharmony_ci
644162306a36Sopenharmony_ci	adapter->wait_for_reset = false;
644262306a36Sopenharmony_ci	adapter->last_reset_time = jiffies;
644362306a36Sopenharmony_ci
644462306a36Sopenharmony_ci	rc = register_netdev(netdev);
644562306a36Sopenharmony_ci	if (rc) {
644662306a36Sopenharmony_ci		dev_err(&dev->dev, "failed to register netdev rc=%d\n", rc);
644762306a36Sopenharmony_ci		goto ibmvnic_register_fail;
644862306a36Sopenharmony_ci	}
644962306a36Sopenharmony_ci	dev_info(&dev->dev, "ibmvnic registered\n");
645062306a36Sopenharmony_ci
645162306a36Sopenharmony_ci	rc = ibmvnic_cpu_notif_add(adapter);
645262306a36Sopenharmony_ci	if (rc) {
645362306a36Sopenharmony_ci		netdev_err(netdev, "Registering cpu notifier failed\n");
645462306a36Sopenharmony_ci		goto cpu_notif_add_failed;
645562306a36Sopenharmony_ci	}
645662306a36Sopenharmony_ci
645762306a36Sopenharmony_ci	complete(&adapter->probe_done);
645862306a36Sopenharmony_ci
645962306a36Sopenharmony_ci	return 0;
646062306a36Sopenharmony_ci
646162306a36Sopenharmony_cicpu_notif_add_failed:
646262306a36Sopenharmony_ci	unregister_netdev(netdev);
646362306a36Sopenharmony_ci
646462306a36Sopenharmony_ciibmvnic_register_fail:
646562306a36Sopenharmony_ci	device_remove_file(&dev->dev, &dev_attr_failover);
646662306a36Sopenharmony_ci
646762306a36Sopenharmony_ciibmvnic_dev_file_err:
646862306a36Sopenharmony_ci	release_stats_token(adapter);
646962306a36Sopenharmony_ci
647062306a36Sopenharmony_ciibmvnic_stats_fail:
647162306a36Sopenharmony_ci	release_stats_buffers(adapter);
647262306a36Sopenharmony_ci
647362306a36Sopenharmony_ciibmvnic_init_fail:
647462306a36Sopenharmony_ci	release_sub_crqs(adapter, 1);
647562306a36Sopenharmony_ci	release_crq_queue(adapter);
647662306a36Sopenharmony_ci
647762306a36Sopenharmony_ci	/* cleanup worker thread after releasing CRQ so we don't get
647862306a36Sopenharmony_ci	 * transport events (i.e new work items for the worker thread).
647962306a36Sopenharmony_ci	 */
648062306a36Sopenharmony_ci	adapter->state = VNIC_REMOVING;
648162306a36Sopenharmony_ci	complete(&adapter->probe_done);
648262306a36Sopenharmony_ci	flush_work(&adapter->ibmvnic_reset);
648362306a36Sopenharmony_ci	flush_delayed_work(&adapter->ibmvnic_delayed_reset);
648462306a36Sopenharmony_ci
648562306a36Sopenharmony_ci	flush_reset_queue(adapter);
648662306a36Sopenharmony_ci
648762306a36Sopenharmony_ci	mutex_destroy(&adapter->fw_lock);
648862306a36Sopenharmony_ci	free_netdev(netdev);
648962306a36Sopenharmony_ci
649062306a36Sopenharmony_ci	return rc;
649162306a36Sopenharmony_ci}
649262306a36Sopenharmony_ci
649362306a36Sopenharmony_cistatic void ibmvnic_remove(struct vio_dev *dev)
649462306a36Sopenharmony_ci{
649562306a36Sopenharmony_ci	struct net_device *netdev = dev_get_drvdata(&dev->dev);
649662306a36Sopenharmony_ci	struct ibmvnic_adapter *adapter = netdev_priv(netdev);
649762306a36Sopenharmony_ci	unsigned long flags;
649862306a36Sopenharmony_ci
649962306a36Sopenharmony_ci	spin_lock_irqsave(&adapter->state_lock, flags);
650062306a36Sopenharmony_ci
650162306a36Sopenharmony_ci	/* If ibmvnic_reset() is scheduling a reset, wait for it to
650262306a36Sopenharmony_ci	 * finish. Then, set the state to REMOVING to prevent it from
650362306a36Sopenharmony_ci	 * scheduling any more work and to have reset functions ignore
650462306a36Sopenharmony_ci	 * any resets that have already been scheduled. Drop the lock
650562306a36Sopenharmony_ci	 * after setting state, so __ibmvnic_reset() which is called
650662306a36Sopenharmony_ci	 * from the flush_work() below, can make progress.
650762306a36Sopenharmony_ci	 */
650862306a36Sopenharmony_ci	spin_lock(&adapter->rwi_lock);
650962306a36Sopenharmony_ci	adapter->state = VNIC_REMOVING;
651062306a36Sopenharmony_ci	spin_unlock(&adapter->rwi_lock);
651162306a36Sopenharmony_ci
651262306a36Sopenharmony_ci	spin_unlock_irqrestore(&adapter->state_lock, flags);
651362306a36Sopenharmony_ci
651462306a36Sopenharmony_ci	ibmvnic_cpu_notif_remove(adapter);
651562306a36Sopenharmony_ci
651662306a36Sopenharmony_ci	flush_work(&adapter->ibmvnic_reset);
651762306a36Sopenharmony_ci	flush_delayed_work(&adapter->ibmvnic_delayed_reset);
651862306a36Sopenharmony_ci
651962306a36Sopenharmony_ci	rtnl_lock();
652062306a36Sopenharmony_ci	unregister_netdevice(netdev);
652162306a36Sopenharmony_ci
652262306a36Sopenharmony_ci	release_resources(adapter);
652362306a36Sopenharmony_ci	release_rx_pools(adapter);
652462306a36Sopenharmony_ci	release_tx_pools(adapter);
652562306a36Sopenharmony_ci	release_sub_crqs(adapter, 1);
652662306a36Sopenharmony_ci	release_crq_queue(adapter);
652762306a36Sopenharmony_ci
652862306a36Sopenharmony_ci	release_stats_token(adapter);
652962306a36Sopenharmony_ci	release_stats_buffers(adapter);
653062306a36Sopenharmony_ci
653162306a36Sopenharmony_ci	adapter->state = VNIC_REMOVED;
653262306a36Sopenharmony_ci
653362306a36Sopenharmony_ci	rtnl_unlock();
653462306a36Sopenharmony_ci	mutex_destroy(&adapter->fw_lock);
653562306a36Sopenharmony_ci	device_remove_file(&dev->dev, &dev_attr_failover);
653662306a36Sopenharmony_ci	free_netdev(netdev);
653762306a36Sopenharmony_ci	dev_set_drvdata(&dev->dev, NULL);
653862306a36Sopenharmony_ci}
653962306a36Sopenharmony_ci
654062306a36Sopenharmony_cistatic ssize_t failover_store(struct device *dev, struct device_attribute *attr,
654162306a36Sopenharmony_ci			      const char *buf, size_t count)
654262306a36Sopenharmony_ci{
654362306a36Sopenharmony_ci	struct net_device *netdev = dev_get_drvdata(dev);
654462306a36Sopenharmony_ci	struct ibmvnic_adapter *adapter = netdev_priv(netdev);
654562306a36Sopenharmony_ci	unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
654662306a36Sopenharmony_ci	__be64 session_token;
654762306a36Sopenharmony_ci	long rc;
654862306a36Sopenharmony_ci
654962306a36Sopenharmony_ci	if (!sysfs_streq(buf, "1"))
655062306a36Sopenharmony_ci		return -EINVAL;
655162306a36Sopenharmony_ci
655262306a36Sopenharmony_ci	rc = plpar_hcall(H_VIOCTL, retbuf, adapter->vdev->unit_address,
655362306a36Sopenharmony_ci			 H_GET_SESSION_TOKEN, 0, 0, 0);
655462306a36Sopenharmony_ci	if (rc) {
655562306a36Sopenharmony_ci		netdev_err(netdev, "Couldn't retrieve session token, rc %ld\n",
655662306a36Sopenharmony_ci			   rc);
655762306a36Sopenharmony_ci		goto last_resort;
655862306a36Sopenharmony_ci	}
655962306a36Sopenharmony_ci
656062306a36Sopenharmony_ci	session_token = (__be64)retbuf[0];
656162306a36Sopenharmony_ci	netdev_dbg(netdev, "Initiating client failover, session id %llx\n",
656262306a36Sopenharmony_ci		   be64_to_cpu(session_token));
656362306a36Sopenharmony_ci	rc = plpar_hcall_norets(H_VIOCTL, adapter->vdev->unit_address,
656462306a36Sopenharmony_ci				H_SESSION_ERR_DETECTED, session_token, 0, 0);
656562306a36Sopenharmony_ci	if (rc) {
656662306a36Sopenharmony_ci		netdev_err(netdev,
656762306a36Sopenharmony_ci			   "H_VIOCTL initiated failover failed, rc %ld\n",
656862306a36Sopenharmony_ci			   rc);
656962306a36Sopenharmony_ci		goto last_resort;
657062306a36Sopenharmony_ci	}
657162306a36Sopenharmony_ci
657262306a36Sopenharmony_ci	return count;
657362306a36Sopenharmony_ci
657462306a36Sopenharmony_cilast_resort:
657562306a36Sopenharmony_ci	netdev_dbg(netdev, "Trying to send CRQ_CMD, the last resort\n");
657662306a36Sopenharmony_ci	ibmvnic_reset(adapter, VNIC_RESET_FAILOVER);
657762306a36Sopenharmony_ci
657862306a36Sopenharmony_ci	return count;
657962306a36Sopenharmony_ci}
658062306a36Sopenharmony_cistatic DEVICE_ATTR_WO(failover);
658162306a36Sopenharmony_ci
658262306a36Sopenharmony_cistatic unsigned long ibmvnic_get_desired_dma(struct vio_dev *vdev)
658362306a36Sopenharmony_ci{
658462306a36Sopenharmony_ci	struct net_device *netdev = dev_get_drvdata(&vdev->dev);
658562306a36Sopenharmony_ci	struct ibmvnic_adapter *adapter;
658662306a36Sopenharmony_ci	struct iommu_table *tbl;
658762306a36Sopenharmony_ci	unsigned long ret = 0;
658862306a36Sopenharmony_ci	int i;
658962306a36Sopenharmony_ci
659062306a36Sopenharmony_ci	tbl = get_iommu_table_base(&vdev->dev);
659162306a36Sopenharmony_ci
659262306a36Sopenharmony_ci	/* netdev inits at probe time along with the structures we need below*/
659362306a36Sopenharmony_ci	if (!netdev)
659462306a36Sopenharmony_ci		return IOMMU_PAGE_ALIGN(IBMVNIC_IO_ENTITLEMENT_DEFAULT, tbl);
659562306a36Sopenharmony_ci
659662306a36Sopenharmony_ci	adapter = netdev_priv(netdev);
659762306a36Sopenharmony_ci
659862306a36Sopenharmony_ci	ret += PAGE_SIZE; /* the crq message queue */
659962306a36Sopenharmony_ci	ret += IOMMU_PAGE_ALIGN(sizeof(struct ibmvnic_statistics), tbl);
660062306a36Sopenharmony_ci
660162306a36Sopenharmony_ci	for (i = 0; i < adapter->req_tx_queues + adapter->req_rx_queues; i++)
660262306a36Sopenharmony_ci		ret += 4 * PAGE_SIZE; /* the scrq message queue */
660362306a36Sopenharmony_ci
660462306a36Sopenharmony_ci	for (i = 0; i < adapter->num_active_rx_pools; i++)
660562306a36Sopenharmony_ci		ret += adapter->rx_pool[i].size *
660662306a36Sopenharmony_ci		    IOMMU_PAGE_ALIGN(adapter->rx_pool[i].buff_size, tbl);
660762306a36Sopenharmony_ci
660862306a36Sopenharmony_ci	return ret;
660962306a36Sopenharmony_ci}
661062306a36Sopenharmony_ci
661162306a36Sopenharmony_cistatic int ibmvnic_resume(struct device *dev)
661262306a36Sopenharmony_ci{
661362306a36Sopenharmony_ci	struct net_device *netdev = dev_get_drvdata(dev);
661462306a36Sopenharmony_ci	struct ibmvnic_adapter *adapter = netdev_priv(netdev);
661562306a36Sopenharmony_ci
661662306a36Sopenharmony_ci	if (adapter->state != VNIC_OPEN)
661762306a36Sopenharmony_ci		return 0;
661862306a36Sopenharmony_ci
661962306a36Sopenharmony_ci	tasklet_schedule(&adapter->tasklet);
662062306a36Sopenharmony_ci
662162306a36Sopenharmony_ci	return 0;
662262306a36Sopenharmony_ci}
662362306a36Sopenharmony_ci
662462306a36Sopenharmony_cistatic const struct vio_device_id ibmvnic_device_table[] = {
662562306a36Sopenharmony_ci	{"network", "IBM,vnic"},
662662306a36Sopenharmony_ci	{"", "" }
662762306a36Sopenharmony_ci};
662862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(vio, ibmvnic_device_table);
662962306a36Sopenharmony_ci
663062306a36Sopenharmony_cistatic const struct dev_pm_ops ibmvnic_pm_ops = {
663162306a36Sopenharmony_ci	.resume = ibmvnic_resume
663262306a36Sopenharmony_ci};
663362306a36Sopenharmony_ci
663462306a36Sopenharmony_cistatic struct vio_driver ibmvnic_driver = {
663562306a36Sopenharmony_ci	.id_table       = ibmvnic_device_table,
663662306a36Sopenharmony_ci	.probe          = ibmvnic_probe,
663762306a36Sopenharmony_ci	.remove         = ibmvnic_remove,
663862306a36Sopenharmony_ci	.get_desired_dma = ibmvnic_get_desired_dma,
663962306a36Sopenharmony_ci	.name		= ibmvnic_driver_name,
664062306a36Sopenharmony_ci	.pm		= &ibmvnic_pm_ops,
664162306a36Sopenharmony_ci};
664262306a36Sopenharmony_ci
664362306a36Sopenharmony_ci/* module functions */
664462306a36Sopenharmony_cistatic int __init ibmvnic_module_init(void)
664562306a36Sopenharmony_ci{
664662306a36Sopenharmony_ci	int ret;
664762306a36Sopenharmony_ci
664862306a36Sopenharmony_ci	ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, "net/ibmvnic:online",
664962306a36Sopenharmony_ci				      ibmvnic_cpu_online,
665062306a36Sopenharmony_ci				      ibmvnic_cpu_down_prep);
665162306a36Sopenharmony_ci	if (ret < 0)
665262306a36Sopenharmony_ci		goto out;
665362306a36Sopenharmony_ci	ibmvnic_online = ret;
665462306a36Sopenharmony_ci	ret = cpuhp_setup_state_multi(CPUHP_IBMVNIC_DEAD, "net/ibmvnic:dead",
665562306a36Sopenharmony_ci				      NULL, ibmvnic_cpu_dead);
665662306a36Sopenharmony_ci	if (ret)
665762306a36Sopenharmony_ci		goto err_dead;
665862306a36Sopenharmony_ci
665962306a36Sopenharmony_ci	ret = vio_register_driver(&ibmvnic_driver);
666062306a36Sopenharmony_ci	if (ret)
666162306a36Sopenharmony_ci		goto err_vio_register;
666262306a36Sopenharmony_ci
666362306a36Sopenharmony_ci	pr_info("%s: %s %s\n", ibmvnic_driver_name, ibmvnic_driver_string,
666462306a36Sopenharmony_ci		IBMVNIC_DRIVER_VERSION);
666562306a36Sopenharmony_ci
666662306a36Sopenharmony_ci	return 0;
666762306a36Sopenharmony_cierr_vio_register:
666862306a36Sopenharmony_ci	cpuhp_remove_multi_state(CPUHP_IBMVNIC_DEAD);
666962306a36Sopenharmony_cierr_dead:
667062306a36Sopenharmony_ci	cpuhp_remove_multi_state(ibmvnic_online);
667162306a36Sopenharmony_ciout:
667262306a36Sopenharmony_ci	return ret;
667362306a36Sopenharmony_ci}
667462306a36Sopenharmony_ci
667562306a36Sopenharmony_cistatic void __exit ibmvnic_module_exit(void)
667662306a36Sopenharmony_ci{
667762306a36Sopenharmony_ci	vio_unregister_driver(&ibmvnic_driver);
667862306a36Sopenharmony_ci	cpuhp_remove_multi_state(CPUHP_IBMVNIC_DEAD);
667962306a36Sopenharmony_ci	cpuhp_remove_multi_state(ibmvnic_online);
668062306a36Sopenharmony_ci}
668162306a36Sopenharmony_ci
668262306a36Sopenharmony_cimodule_init(ibmvnic_module_init);
668362306a36Sopenharmony_cimodule_exit(ibmvnic_module_exit);
6684