162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/* Copyright(c) 2017 - 2019 Pensando Systems, Inc */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <linux/ethtool.h>
562306a36Sopenharmony_ci#include <linux/printk.h>
662306a36Sopenharmony_ci#include <linux/dynamic_debug.h>
762306a36Sopenharmony_ci#include <linux/netdevice.h>
862306a36Sopenharmony_ci#include <linux/etherdevice.h>
962306a36Sopenharmony_ci#include <linux/if_vlan.h>
1062306a36Sopenharmony_ci#include <linux/rtnetlink.h>
1162306a36Sopenharmony_ci#include <linux/interrupt.h>
1262306a36Sopenharmony_ci#include <linux/pci.h>
1362306a36Sopenharmony_ci#include <linux/cpumask.h>
1462306a36Sopenharmony_ci#include <linux/crash_dump.h>
1562306a36Sopenharmony_ci#include <linux/vmalloc.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include "ionic.h"
1862306a36Sopenharmony_ci#include "ionic_bus.h"
1962306a36Sopenharmony_ci#include "ionic_dev.h"
2062306a36Sopenharmony_ci#include "ionic_lif.h"
2162306a36Sopenharmony_ci#include "ionic_txrx.h"
2262306a36Sopenharmony_ci#include "ionic_ethtool.h"
2362306a36Sopenharmony_ci#include "ionic_debugfs.h"
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci/* queuetype support level */
2662306a36Sopenharmony_cistatic const u8 ionic_qtype_versions[IONIC_QTYPE_MAX] = {
2762306a36Sopenharmony_ci	[IONIC_QTYPE_ADMINQ]  = 0,   /* 0 = Base version with CQ support */
2862306a36Sopenharmony_ci	[IONIC_QTYPE_NOTIFYQ] = 0,   /* 0 = Base version */
2962306a36Sopenharmony_ci	[IONIC_QTYPE_RXQ]     = 2,   /* 0 = Base version with CQ+SG support
3062306a36Sopenharmony_ci				      * 2 =       ... with CMB rings
3162306a36Sopenharmony_ci				      */
3262306a36Sopenharmony_ci	[IONIC_QTYPE_TXQ]     = 3,   /* 0 = Base version with CQ+SG support
3362306a36Sopenharmony_ci				      * 1 =       ... with Tx SG version 1
3462306a36Sopenharmony_ci				      * 3 =       ... with CMB rings
3562306a36Sopenharmony_ci				      */
3662306a36Sopenharmony_ci};
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_cistatic void ionic_link_status_check(struct ionic_lif *lif);
3962306a36Sopenharmony_cistatic void ionic_lif_handle_fw_down(struct ionic_lif *lif);
4062306a36Sopenharmony_cistatic void ionic_lif_handle_fw_up(struct ionic_lif *lif);
4162306a36Sopenharmony_cistatic void ionic_lif_set_netdev_info(struct ionic_lif *lif);
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistatic void ionic_txrx_deinit(struct ionic_lif *lif);
4462306a36Sopenharmony_cistatic int ionic_txrx_init(struct ionic_lif *lif);
4562306a36Sopenharmony_cistatic int ionic_start_queues(struct ionic_lif *lif);
4662306a36Sopenharmony_cistatic void ionic_stop_queues(struct ionic_lif *lif);
4762306a36Sopenharmony_cistatic void ionic_lif_queue_identify(struct ionic_lif *lif);
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistatic void ionic_dim_work(struct work_struct *work)
5062306a36Sopenharmony_ci{
5162306a36Sopenharmony_ci	struct dim *dim = container_of(work, struct dim, work);
5262306a36Sopenharmony_ci	struct ionic_intr_info *intr;
5362306a36Sopenharmony_ci	struct dim_cq_moder cur_moder;
5462306a36Sopenharmony_ci	struct ionic_qcq *qcq;
5562306a36Sopenharmony_ci	struct ionic_lif *lif;
5662306a36Sopenharmony_ci	u32 new_coal;
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	cur_moder = net_dim_get_rx_moderation(dim->mode, dim->profile_ix);
5962306a36Sopenharmony_ci	qcq = container_of(dim, struct ionic_qcq, dim);
6062306a36Sopenharmony_ci	lif = qcq->q.lif;
6162306a36Sopenharmony_ci	new_coal = ionic_coal_usec_to_hw(lif->ionic, cur_moder.usec);
6262306a36Sopenharmony_ci	new_coal = new_coal ? new_coal : 1;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	intr = &qcq->intr;
6562306a36Sopenharmony_ci	if (intr->dim_coal_hw != new_coal) {
6662306a36Sopenharmony_ci		intr->dim_coal_hw = new_coal;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci		ionic_intr_coal_init(lif->ionic->idev.intr_ctrl,
6962306a36Sopenharmony_ci				     intr->index, intr->dim_coal_hw);
7062306a36Sopenharmony_ci	}
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	dim->state = DIM_START_MEASURE;
7362306a36Sopenharmony_ci}
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_cistatic void ionic_lif_deferred_work(struct work_struct *work)
7662306a36Sopenharmony_ci{
7762306a36Sopenharmony_ci	struct ionic_lif *lif = container_of(work, struct ionic_lif, deferred.work);
7862306a36Sopenharmony_ci	struct ionic_deferred *def = &lif->deferred;
7962306a36Sopenharmony_ci	struct ionic_deferred_work *w = NULL;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	do {
8262306a36Sopenharmony_ci		spin_lock_bh(&def->lock);
8362306a36Sopenharmony_ci		if (!list_empty(&def->list)) {
8462306a36Sopenharmony_ci			w = list_first_entry(&def->list,
8562306a36Sopenharmony_ci					     struct ionic_deferred_work, list);
8662306a36Sopenharmony_ci			list_del(&w->list);
8762306a36Sopenharmony_ci		}
8862306a36Sopenharmony_ci		spin_unlock_bh(&def->lock);
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci		if (!w)
9162306a36Sopenharmony_ci			break;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci		switch (w->type) {
9462306a36Sopenharmony_ci		case IONIC_DW_TYPE_RX_MODE:
9562306a36Sopenharmony_ci			ionic_lif_rx_mode(lif);
9662306a36Sopenharmony_ci			break;
9762306a36Sopenharmony_ci		case IONIC_DW_TYPE_LINK_STATUS:
9862306a36Sopenharmony_ci			ionic_link_status_check(lif);
9962306a36Sopenharmony_ci			break;
10062306a36Sopenharmony_ci		case IONIC_DW_TYPE_LIF_RESET:
10162306a36Sopenharmony_ci			if (w->fw_status) {
10262306a36Sopenharmony_ci				ionic_lif_handle_fw_up(lif);
10362306a36Sopenharmony_ci			} else {
10462306a36Sopenharmony_ci				ionic_lif_handle_fw_down(lif);
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci				/* Fire off another watchdog to see
10762306a36Sopenharmony_ci				 * if the FW is already back rather than
10862306a36Sopenharmony_ci				 * waiting another whole cycle
10962306a36Sopenharmony_ci				 */
11062306a36Sopenharmony_ci				mod_timer(&lif->ionic->watchdog_timer, jiffies + 1);
11162306a36Sopenharmony_ci			}
11262306a36Sopenharmony_ci			break;
11362306a36Sopenharmony_ci		default:
11462306a36Sopenharmony_ci			break;
11562306a36Sopenharmony_ci		}
11662306a36Sopenharmony_ci		kfree(w);
11762306a36Sopenharmony_ci		w = NULL;
11862306a36Sopenharmony_ci	} while (true);
11962306a36Sopenharmony_ci}
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_civoid ionic_lif_deferred_enqueue(struct ionic_deferred *def,
12262306a36Sopenharmony_ci				struct ionic_deferred_work *work)
12362306a36Sopenharmony_ci{
12462306a36Sopenharmony_ci	spin_lock_bh(&def->lock);
12562306a36Sopenharmony_ci	list_add_tail(&work->list, &def->list);
12662306a36Sopenharmony_ci	spin_unlock_bh(&def->lock);
12762306a36Sopenharmony_ci	schedule_work(&def->work);
12862306a36Sopenharmony_ci}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_cistatic void ionic_link_status_check(struct ionic_lif *lif)
13162306a36Sopenharmony_ci{
13262306a36Sopenharmony_ci	struct net_device *netdev = lif->netdev;
13362306a36Sopenharmony_ci	u16 link_status;
13462306a36Sopenharmony_ci	bool link_up;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	if (!test_bit(IONIC_LIF_F_LINK_CHECK_REQUESTED, lif->state))
13762306a36Sopenharmony_ci		return;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	/* Don't put carrier back up if we're in a broken state */
14062306a36Sopenharmony_ci	if (test_bit(IONIC_LIF_F_BROKEN, lif->state)) {
14162306a36Sopenharmony_ci		clear_bit(IONIC_LIF_F_LINK_CHECK_REQUESTED, lif->state);
14262306a36Sopenharmony_ci		return;
14362306a36Sopenharmony_ci	}
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	link_status = le16_to_cpu(lif->info->status.link_status);
14662306a36Sopenharmony_ci	link_up = link_status == IONIC_PORT_OPER_STATUS_UP;
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	if (link_up) {
14962306a36Sopenharmony_ci		int err = 0;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci		if (netdev->flags & IFF_UP && netif_running(netdev)) {
15262306a36Sopenharmony_ci			mutex_lock(&lif->queue_lock);
15362306a36Sopenharmony_ci			err = ionic_start_queues(lif);
15462306a36Sopenharmony_ci			if (err && err != -EBUSY) {
15562306a36Sopenharmony_ci				netdev_err(netdev,
15662306a36Sopenharmony_ci					   "Failed to start queues: %d\n", err);
15762306a36Sopenharmony_ci				set_bit(IONIC_LIF_F_BROKEN, lif->state);
15862306a36Sopenharmony_ci				netif_carrier_off(lif->netdev);
15962306a36Sopenharmony_ci			}
16062306a36Sopenharmony_ci			mutex_unlock(&lif->queue_lock);
16162306a36Sopenharmony_ci		}
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci		if (!err && !netif_carrier_ok(netdev)) {
16462306a36Sopenharmony_ci			ionic_port_identify(lif->ionic);
16562306a36Sopenharmony_ci			netdev_info(netdev, "Link up - %d Gbps\n",
16662306a36Sopenharmony_ci				    le32_to_cpu(lif->info->status.link_speed) / 1000);
16762306a36Sopenharmony_ci			netif_carrier_on(netdev);
16862306a36Sopenharmony_ci		}
16962306a36Sopenharmony_ci	} else {
17062306a36Sopenharmony_ci		if (netif_carrier_ok(netdev)) {
17162306a36Sopenharmony_ci			lif->link_down_count++;
17262306a36Sopenharmony_ci			netdev_info(netdev, "Link down\n");
17362306a36Sopenharmony_ci			netif_carrier_off(netdev);
17462306a36Sopenharmony_ci		}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci		if (netdev->flags & IFF_UP && netif_running(netdev)) {
17762306a36Sopenharmony_ci			mutex_lock(&lif->queue_lock);
17862306a36Sopenharmony_ci			ionic_stop_queues(lif);
17962306a36Sopenharmony_ci			mutex_unlock(&lif->queue_lock);
18062306a36Sopenharmony_ci		}
18162306a36Sopenharmony_ci	}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	clear_bit(IONIC_LIF_F_LINK_CHECK_REQUESTED, lif->state);
18462306a36Sopenharmony_ci}
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_civoid ionic_link_status_check_request(struct ionic_lif *lif, bool can_sleep)
18762306a36Sopenharmony_ci{
18862306a36Sopenharmony_ci	struct ionic_deferred_work *work;
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	/* we only need one request outstanding at a time */
19162306a36Sopenharmony_ci	if (test_and_set_bit(IONIC_LIF_F_LINK_CHECK_REQUESTED, lif->state))
19262306a36Sopenharmony_ci		return;
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	if (!can_sleep) {
19562306a36Sopenharmony_ci		work = kzalloc(sizeof(*work), GFP_ATOMIC);
19662306a36Sopenharmony_ci		if (!work) {
19762306a36Sopenharmony_ci			clear_bit(IONIC_LIF_F_LINK_CHECK_REQUESTED, lif->state);
19862306a36Sopenharmony_ci			return;
19962306a36Sopenharmony_ci		}
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci		work->type = IONIC_DW_TYPE_LINK_STATUS;
20262306a36Sopenharmony_ci		ionic_lif_deferred_enqueue(&lif->deferred, work);
20362306a36Sopenharmony_ci	} else {
20462306a36Sopenharmony_ci		ionic_link_status_check(lif);
20562306a36Sopenharmony_ci	}
20662306a36Sopenharmony_ci}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_cistatic void ionic_napi_deadline(struct timer_list *timer)
20962306a36Sopenharmony_ci{
21062306a36Sopenharmony_ci	struct ionic_qcq *qcq = container_of(timer, struct ionic_qcq, napi_deadline);
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	napi_schedule(&qcq->napi);
21362306a36Sopenharmony_ci}
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_cistatic irqreturn_t ionic_isr(int irq, void *data)
21662306a36Sopenharmony_ci{
21762306a36Sopenharmony_ci	struct napi_struct *napi = data;
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	napi_schedule_irqoff(napi);
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	return IRQ_HANDLED;
22262306a36Sopenharmony_ci}
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_cistatic int ionic_request_irq(struct ionic_lif *lif, struct ionic_qcq *qcq)
22562306a36Sopenharmony_ci{
22662306a36Sopenharmony_ci	struct ionic_intr_info *intr = &qcq->intr;
22762306a36Sopenharmony_ci	struct device *dev = lif->ionic->dev;
22862306a36Sopenharmony_ci	struct ionic_queue *q = &qcq->q;
22962306a36Sopenharmony_ci	const char *name;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	if (lif->registered)
23262306a36Sopenharmony_ci		name = lif->netdev->name;
23362306a36Sopenharmony_ci	else
23462306a36Sopenharmony_ci		name = dev_name(dev);
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	snprintf(intr->name, sizeof(intr->name),
23762306a36Sopenharmony_ci		 "%s-%s-%s", IONIC_DRV_NAME, name, q->name);
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	return devm_request_irq(dev, intr->vector, ionic_isr,
24062306a36Sopenharmony_ci				0, intr->name, &qcq->napi);
24162306a36Sopenharmony_ci}
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_cistatic int ionic_intr_alloc(struct ionic_lif *lif, struct ionic_intr_info *intr)
24462306a36Sopenharmony_ci{
24562306a36Sopenharmony_ci	struct ionic *ionic = lif->ionic;
24662306a36Sopenharmony_ci	int index;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	index = find_first_zero_bit(ionic->intrs, ionic->nintrs);
24962306a36Sopenharmony_ci	if (index == ionic->nintrs) {
25062306a36Sopenharmony_ci		netdev_warn(lif->netdev, "%s: no intr, index=%d nintrs=%d\n",
25162306a36Sopenharmony_ci			    __func__, index, ionic->nintrs);
25262306a36Sopenharmony_ci		return -ENOSPC;
25362306a36Sopenharmony_ci	}
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	set_bit(index, ionic->intrs);
25662306a36Sopenharmony_ci	ionic_intr_init(&ionic->idev, intr, index);
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	return 0;
25962306a36Sopenharmony_ci}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_cistatic void ionic_intr_free(struct ionic *ionic, int index)
26262306a36Sopenharmony_ci{
26362306a36Sopenharmony_ci	if (index != IONIC_INTR_INDEX_NOT_ASSIGNED && index < ionic->nintrs)
26462306a36Sopenharmony_ci		clear_bit(index, ionic->intrs);
26562306a36Sopenharmony_ci}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_cistatic int ionic_qcq_enable(struct ionic_qcq *qcq)
26862306a36Sopenharmony_ci{
26962306a36Sopenharmony_ci	struct ionic_queue *q = &qcq->q;
27062306a36Sopenharmony_ci	struct ionic_lif *lif = q->lif;
27162306a36Sopenharmony_ci	struct ionic_dev *idev;
27262306a36Sopenharmony_ci	struct device *dev;
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	struct ionic_admin_ctx ctx = {
27562306a36Sopenharmony_ci		.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
27662306a36Sopenharmony_ci		.cmd.q_control = {
27762306a36Sopenharmony_ci			.opcode = IONIC_CMD_Q_CONTROL,
27862306a36Sopenharmony_ci			.lif_index = cpu_to_le16(lif->index),
27962306a36Sopenharmony_ci			.type = q->type,
28062306a36Sopenharmony_ci			.index = cpu_to_le32(q->index),
28162306a36Sopenharmony_ci			.oper = IONIC_Q_ENABLE,
28262306a36Sopenharmony_ci		},
28362306a36Sopenharmony_ci	};
28462306a36Sopenharmony_ci	int ret;
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	idev = &lif->ionic->idev;
28762306a36Sopenharmony_ci	dev = lif->ionic->dev;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	dev_dbg(dev, "q_enable.index %d q_enable.qtype %d\n",
29062306a36Sopenharmony_ci		ctx.cmd.q_control.index, ctx.cmd.q_control.type);
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	if (qcq->flags & IONIC_QCQ_F_INTR)
29362306a36Sopenharmony_ci		ionic_intr_clean(idev->intr_ctrl, qcq->intr.index);
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	ret = ionic_adminq_post_wait(lif, &ctx);
29662306a36Sopenharmony_ci	if (ret)
29762306a36Sopenharmony_ci		return ret;
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	if (qcq->napi.poll)
30062306a36Sopenharmony_ci		napi_enable(&qcq->napi);
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	if (qcq->flags & IONIC_QCQ_F_INTR) {
30362306a36Sopenharmony_ci		irq_set_affinity_hint(qcq->intr.vector,
30462306a36Sopenharmony_ci				      &qcq->intr.affinity_mask);
30562306a36Sopenharmony_ci		ionic_intr_mask(idev->intr_ctrl, qcq->intr.index,
30662306a36Sopenharmony_ci				IONIC_INTR_MASK_CLEAR);
30762306a36Sopenharmony_ci	}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	return 0;
31062306a36Sopenharmony_ci}
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_cistatic int ionic_qcq_disable(struct ionic_lif *lif, struct ionic_qcq *qcq, int fw_err)
31362306a36Sopenharmony_ci{
31462306a36Sopenharmony_ci	struct ionic_queue *q;
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	struct ionic_admin_ctx ctx = {
31762306a36Sopenharmony_ci		.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
31862306a36Sopenharmony_ci		.cmd.q_control = {
31962306a36Sopenharmony_ci			.opcode = IONIC_CMD_Q_CONTROL,
32062306a36Sopenharmony_ci			.oper = IONIC_Q_DISABLE,
32162306a36Sopenharmony_ci		},
32262306a36Sopenharmony_ci	};
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	if (!qcq) {
32562306a36Sopenharmony_ci		netdev_err(lif->netdev, "%s: bad qcq\n", __func__);
32662306a36Sopenharmony_ci		return -ENXIO;
32762306a36Sopenharmony_ci	}
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	q = &qcq->q;
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	if (qcq->flags & IONIC_QCQ_F_INTR) {
33262306a36Sopenharmony_ci		struct ionic_dev *idev = &lif->ionic->idev;
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci		cancel_work_sync(&qcq->dim.work);
33562306a36Sopenharmony_ci		ionic_intr_mask(idev->intr_ctrl, qcq->intr.index,
33662306a36Sopenharmony_ci				IONIC_INTR_MASK_SET);
33762306a36Sopenharmony_ci		synchronize_irq(qcq->intr.vector);
33862306a36Sopenharmony_ci		irq_set_affinity_hint(qcq->intr.vector, NULL);
33962306a36Sopenharmony_ci		napi_disable(&qcq->napi);
34062306a36Sopenharmony_ci		del_timer_sync(&qcq->napi_deadline);
34162306a36Sopenharmony_ci	}
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	/* If there was a previous fw communcation error, don't bother with
34462306a36Sopenharmony_ci	 * sending the adminq command and just return the same error value.
34562306a36Sopenharmony_ci	 */
34662306a36Sopenharmony_ci	if (fw_err == -ETIMEDOUT || fw_err == -ENXIO)
34762306a36Sopenharmony_ci		return fw_err;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	ctx.cmd.q_control.lif_index = cpu_to_le16(lif->index);
35062306a36Sopenharmony_ci	ctx.cmd.q_control.type = q->type;
35162306a36Sopenharmony_ci	ctx.cmd.q_control.index = cpu_to_le32(q->index);
35262306a36Sopenharmony_ci	dev_dbg(lif->ionic->dev, "q_disable.index %d q_disable.qtype %d\n",
35362306a36Sopenharmony_ci		ctx.cmd.q_control.index, ctx.cmd.q_control.type);
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	return ionic_adminq_post_wait(lif, &ctx);
35662306a36Sopenharmony_ci}
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_cistatic void ionic_lif_qcq_deinit(struct ionic_lif *lif, struct ionic_qcq *qcq)
35962306a36Sopenharmony_ci{
36062306a36Sopenharmony_ci	struct ionic_dev *idev = &lif->ionic->idev;
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	if (!qcq)
36362306a36Sopenharmony_ci		return;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	if (!(qcq->flags & IONIC_QCQ_F_INITED))
36662306a36Sopenharmony_ci		return;
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	if (qcq->flags & IONIC_QCQ_F_INTR) {
36962306a36Sopenharmony_ci		ionic_intr_mask(idev->intr_ctrl, qcq->intr.index,
37062306a36Sopenharmony_ci				IONIC_INTR_MASK_SET);
37162306a36Sopenharmony_ci		netif_napi_del(&qcq->napi);
37262306a36Sopenharmony_ci	}
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	qcq->flags &= ~IONIC_QCQ_F_INITED;
37562306a36Sopenharmony_ci}
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_cistatic void ionic_qcq_intr_free(struct ionic_lif *lif, struct ionic_qcq *qcq)
37862306a36Sopenharmony_ci{
37962306a36Sopenharmony_ci	if (!(qcq->flags & IONIC_QCQ_F_INTR) || qcq->intr.vector == 0)
38062306a36Sopenharmony_ci		return;
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	irq_set_affinity_hint(qcq->intr.vector, NULL);
38362306a36Sopenharmony_ci	devm_free_irq(lif->ionic->dev, qcq->intr.vector, &qcq->napi);
38462306a36Sopenharmony_ci	qcq->intr.vector = 0;
38562306a36Sopenharmony_ci	ionic_intr_free(lif->ionic, qcq->intr.index);
38662306a36Sopenharmony_ci	qcq->intr.index = IONIC_INTR_INDEX_NOT_ASSIGNED;
38762306a36Sopenharmony_ci}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_cistatic void ionic_qcq_free(struct ionic_lif *lif, struct ionic_qcq *qcq)
39062306a36Sopenharmony_ci{
39162306a36Sopenharmony_ci	struct device *dev = lif->ionic->dev;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	if (!qcq)
39462306a36Sopenharmony_ci		return;
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	ionic_debugfs_del_qcq(qcq);
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	if (qcq->q_base) {
39962306a36Sopenharmony_ci		dma_free_coherent(dev, qcq->q_size, qcq->q_base, qcq->q_base_pa);
40062306a36Sopenharmony_ci		qcq->q_base = NULL;
40162306a36Sopenharmony_ci		qcq->q_base_pa = 0;
40262306a36Sopenharmony_ci	}
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	if (qcq->cmb_q_base) {
40562306a36Sopenharmony_ci		iounmap(qcq->cmb_q_base);
40662306a36Sopenharmony_ci		ionic_put_cmb(lif, qcq->cmb_pgid, qcq->cmb_order);
40762306a36Sopenharmony_ci		qcq->cmb_pgid = 0;
40862306a36Sopenharmony_ci		qcq->cmb_order = 0;
40962306a36Sopenharmony_ci		qcq->cmb_q_base = NULL;
41062306a36Sopenharmony_ci		qcq->cmb_q_base_pa = 0;
41162306a36Sopenharmony_ci	}
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	if (qcq->cq_base) {
41462306a36Sopenharmony_ci		dma_free_coherent(dev, qcq->cq_size, qcq->cq_base, qcq->cq_base_pa);
41562306a36Sopenharmony_ci		qcq->cq_base = NULL;
41662306a36Sopenharmony_ci		qcq->cq_base_pa = 0;
41762306a36Sopenharmony_ci	}
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	if (qcq->sg_base) {
42062306a36Sopenharmony_ci		dma_free_coherent(dev, qcq->sg_size, qcq->sg_base, qcq->sg_base_pa);
42162306a36Sopenharmony_ci		qcq->sg_base = NULL;
42262306a36Sopenharmony_ci		qcq->sg_base_pa = 0;
42362306a36Sopenharmony_ci	}
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	ionic_qcq_intr_free(lif, qcq);
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	if (qcq->cq.info) {
42862306a36Sopenharmony_ci		vfree(qcq->cq.info);
42962306a36Sopenharmony_ci		qcq->cq.info = NULL;
43062306a36Sopenharmony_ci	}
43162306a36Sopenharmony_ci	if (qcq->q.info) {
43262306a36Sopenharmony_ci		vfree(qcq->q.info);
43362306a36Sopenharmony_ci		qcq->q.info = NULL;
43462306a36Sopenharmony_ci	}
43562306a36Sopenharmony_ci}
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_civoid ionic_qcqs_free(struct ionic_lif *lif)
43862306a36Sopenharmony_ci{
43962306a36Sopenharmony_ci	struct device *dev = lif->ionic->dev;
44062306a36Sopenharmony_ci	struct ionic_qcq *adminqcq;
44162306a36Sopenharmony_ci	unsigned long irqflags;
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	if (lif->notifyqcq) {
44462306a36Sopenharmony_ci		ionic_qcq_free(lif, lif->notifyqcq);
44562306a36Sopenharmony_ci		devm_kfree(dev, lif->notifyqcq);
44662306a36Sopenharmony_ci		lif->notifyqcq = NULL;
44762306a36Sopenharmony_ci	}
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	if (lif->adminqcq) {
45062306a36Sopenharmony_ci		spin_lock_irqsave(&lif->adminq_lock, irqflags);
45162306a36Sopenharmony_ci		adminqcq = READ_ONCE(lif->adminqcq);
45262306a36Sopenharmony_ci		lif->adminqcq = NULL;
45362306a36Sopenharmony_ci		spin_unlock_irqrestore(&lif->adminq_lock, irqflags);
45462306a36Sopenharmony_ci		if (adminqcq) {
45562306a36Sopenharmony_ci			ionic_qcq_free(lif, adminqcq);
45662306a36Sopenharmony_ci			devm_kfree(dev, adminqcq);
45762306a36Sopenharmony_ci		}
45862306a36Sopenharmony_ci	}
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	if (lif->rxqcqs) {
46162306a36Sopenharmony_ci		devm_kfree(dev, lif->rxqstats);
46262306a36Sopenharmony_ci		lif->rxqstats = NULL;
46362306a36Sopenharmony_ci		devm_kfree(dev, lif->rxqcqs);
46462306a36Sopenharmony_ci		lif->rxqcqs = NULL;
46562306a36Sopenharmony_ci	}
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	if (lif->txqcqs) {
46862306a36Sopenharmony_ci		devm_kfree(dev, lif->txqstats);
46962306a36Sopenharmony_ci		lif->txqstats = NULL;
47062306a36Sopenharmony_ci		devm_kfree(dev, lif->txqcqs);
47162306a36Sopenharmony_ci		lif->txqcqs = NULL;
47262306a36Sopenharmony_ci	}
47362306a36Sopenharmony_ci}
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_cistatic void ionic_link_qcq_interrupts(struct ionic_qcq *src_qcq,
47662306a36Sopenharmony_ci				      struct ionic_qcq *n_qcq)
47762306a36Sopenharmony_ci{
47862306a36Sopenharmony_ci	n_qcq->intr.vector = src_qcq->intr.vector;
47962306a36Sopenharmony_ci	n_qcq->intr.index = src_qcq->intr.index;
48062306a36Sopenharmony_ci	n_qcq->napi_qcq = src_qcq->napi_qcq;
48162306a36Sopenharmony_ci}
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_cistatic int ionic_alloc_qcq_interrupt(struct ionic_lif *lif, struct ionic_qcq *qcq)
48462306a36Sopenharmony_ci{
48562306a36Sopenharmony_ci	int err;
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	if (!(qcq->flags & IONIC_QCQ_F_INTR)) {
48862306a36Sopenharmony_ci		qcq->intr.index = IONIC_INTR_INDEX_NOT_ASSIGNED;
48962306a36Sopenharmony_ci		return 0;
49062306a36Sopenharmony_ci	}
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	err = ionic_intr_alloc(lif, &qcq->intr);
49362306a36Sopenharmony_ci	if (err) {
49462306a36Sopenharmony_ci		netdev_warn(lif->netdev, "no intr for %s: %d\n",
49562306a36Sopenharmony_ci			    qcq->q.name, err);
49662306a36Sopenharmony_ci		goto err_out;
49762306a36Sopenharmony_ci	}
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	err = ionic_bus_get_irq(lif->ionic, qcq->intr.index);
50062306a36Sopenharmony_ci	if (err < 0) {
50162306a36Sopenharmony_ci		netdev_warn(lif->netdev, "no vector for %s: %d\n",
50262306a36Sopenharmony_ci			    qcq->q.name, err);
50362306a36Sopenharmony_ci		goto err_out_free_intr;
50462306a36Sopenharmony_ci	}
50562306a36Sopenharmony_ci	qcq->intr.vector = err;
50662306a36Sopenharmony_ci	ionic_intr_mask_assert(lif->ionic->idev.intr_ctrl, qcq->intr.index,
50762306a36Sopenharmony_ci			       IONIC_INTR_MASK_SET);
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	err = ionic_request_irq(lif, qcq);
51062306a36Sopenharmony_ci	if (err) {
51162306a36Sopenharmony_ci		netdev_warn(lif->netdev, "irq request failed %d\n", err);
51262306a36Sopenharmony_ci		goto err_out_free_intr;
51362306a36Sopenharmony_ci	}
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	/* try to get the irq on the local numa node first */
51662306a36Sopenharmony_ci	qcq->intr.cpu = cpumask_local_spread(qcq->intr.index,
51762306a36Sopenharmony_ci					     dev_to_node(lif->ionic->dev));
51862306a36Sopenharmony_ci	if (qcq->intr.cpu != -1)
51962306a36Sopenharmony_ci		cpumask_set_cpu(qcq->intr.cpu, &qcq->intr.affinity_mask);
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	netdev_dbg(lif->netdev, "%s: Interrupt index %d\n", qcq->q.name, qcq->intr.index);
52262306a36Sopenharmony_ci	return 0;
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_cierr_out_free_intr:
52562306a36Sopenharmony_ci	ionic_intr_free(lif->ionic, qcq->intr.index);
52662306a36Sopenharmony_cierr_out:
52762306a36Sopenharmony_ci	return err;
52862306a36Sopenharmony_ci}
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_cistatic int ionic_qcq_alloc(struct ionic_lif *lif, unsigned int type,
53162306a36Sopenharmony_ci			   unsigned int index,
53262306a36Sopenharmony_ci			   const char *name, unsigned int flags,
53362306a36Sopenharmony_ci			   unsigned int num_descs, unsigned int desc_size,
53462306a36Sopenharmony_ci			   unsigned int cq_desc_size,
53562306a36Sopenharmony_ci			   unsigned int sg_desc_size,
53662306a36Sopenharmony_ci			   unsigned int pid, struct ionic_qcq **qcq)
53762306a36Sopenharmony_ci{
53862306a36Sopenharmony_ci	struct ionic_dev *idev = &lif->ionic->idev;
53962306a36Sopenharmony_ci	struct device *dev = lif->ionic->dev;
54062306a36Sopenharmony_ci	void *q_base, *cq_base, *sg_base;
54162306a36Sopenharmony_ci	dma_addr_t cq_base_pa = 0;
54262306a36Sopenharmony_ci	dma_addr_t sg_base_pa = 0;
54362306a36Sopenharmony_ci	dma_addr_t q_base_pa = 0;
54462306a36Sopenharmony_ci	struct ionic_qcq *new;
54562306a36Sopenharmony_ci	int err;
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	*qcq = NULL;
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	new = devm_kzalloc(dev, sizeof(*new), GFP_KERNEL);
55062306a36Sopenharmony_ci	if (!new) {
55162306a36Sopenharmony_ci		netdev_err(lif->netdev, "Cannot allocate queue structure\n");
55262306a36Sopenharmony_ci		err = -ENOMEM;
55362306a36Sopenharmony_ci		goto err_out;
55462306a36Sopenharmony_ci	}
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	new->q.dev = dev;
55762306a36Sopenharmony_ci	new->flags = flags;
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	new->q.info = vcalloc(num_descs, sizeof(*new->q.info));
56062306a36Sopenharmony_ci	if (!new->q.info) {
56162306a36Sopenharmony_ci		netdev_err(lif->netdev, "Cannot allocate queue info\n");
56262306a36Sopenharmony_ci		err = -ENOMEM;
56362306a36Sopenharmony_ci		goto err_out_free_qcq;
56462306a36Sopenharmony_ci	}
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	new->q.type = type;
56762306a36Sopenharmony_ci	new->q.max_sg_elems = lif->qtype_info[type].max_sg_elems;
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	err = ionic_q_init(lif, idev, &new->q, index, name, num_descs,
57062306a36Sopenharmony_ci			   desc_size, sg_desc_size, pid);
57162306a36Sopenharmony_ci	if (err) {
57262306a36Sopenharmony_ci		netdev_err(lif->netdev, "Cannot initialize queue\n");
57362306a36Sopenharmony_ci		goto err_out_free_q_info;
57462306a36Sopenharmony_ci	}
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	err = ionic_alloc_qcq_interrupt(lif, new);
57762306a36Sopenharmony_ci	if (err)
57862306a36Sopenharmony_ci		goto err_out;
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	new->cq.info = vcalloc(num_descs, sizeof(*new->cq.info));
58162306a36Sopenharmony_ci	if (!new->cq.info) {
58262306a36Sopenharmony_ci		netdev_err(lif->netdev, "Cannot allocate completion queue info\n");
58362306a36Sopenharmony_ci		err = -ENOMEM;
58462306a36Sopenharmony_ci		goto err_out_free_irq;
58562306a36Sopenharmony_ci	}
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	err = ionic_cq_init(lif, &new->cq, &new->intr, num_descs, cq_desc_size);
58862306a36Sopenharmony_ci	if (err) {
58962306a36Sopenharmony_ci		netdev_err(lif->netdev, "Cannot initialize completion queue\n");
59062306a36Sopenharmony_ci		goto err_out_free_cq_info;
59162306a36Sopenharmony_ci	}
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	if (flags & IONIC_QCQ_F_NOTIFYQ) {
59462306a36Sopenharmony_ci		int q_size;
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci		/* q & cq need to be contiguous in NotifyQ, so alloc it all in q
59762306a36Sopenharmony_ci		 * and don't alloc qc.  We leave new->qc_size and new->qc_base
59862306a36Sopenharmony_ci		 * as 0 to be sure we don't try to free it later.
59962306a36Sopenharmony_ci		 */
60062306a36Sopenharmony_ci		q_size = ALIGN(num_descs * desc_size, PAGE_SIZE);
60162306a36Sopenharmony_ci		new->q_size = PAGE_SIZE + q_size +
60262306a36Sopenharmony_ci			      ALIGN(num_descs * cq_desc_size, PAGE_SIZE);
60362306a36Sopenharmony_ci		new->q_base = dma_alloc_coherent(dev, new->q_size,
60462306a36Sopenharmony_ci						 &new->q_base_pa, GFP_KERNEL);
60562306a36Sopenharmony_ci		if (!new->q_base) {
60662306a36Sopenharmony_ci			netdev_err(lif->netdev, "Cannot allocate qcq DMA memory\n");
60762306a36Sopenharmony_ci			err = -ENOMEM;
60862306a36Sopenharmony_ci			goto err_out_free_cq_info;
60962306a36Sopenharmony_ci		}
61062306a36Sopenharmony_ci		q_base = PTR_ALIGN(new->q_base, PAGE_SIZE);
61162306a36Sopenharmony_ci		q_base_pa = ALIGN(new->q_base_pa, PAGE_SIZE);
61262306a36Sopenharmony_ci		ionic_q_map(&new->q, q_base, q_base_pa);
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci		cq_base = PTR_ALIGN(q_base + q_size, PAGE_SIZE);
61562306a36Sopenharmony_ci		cq_base_pa = ALIGN(new->q_base_pa + q_size, PAGE_SIZE);
61662306a36Sopenharmony_ci		ionic_cq_map(&new->cq, cq_base, cq_base_pa);
61762306a36Sopenharmony_ci		ionic_cq_bind(&new->cq, &new->q);
61862306a36Sopenharmony_ci	} else {
61962306a36Sopenharmony_ci		/* regular DMA q descriptors */
62062306a36Sopenharmony_ci		new->q_size = PAGE_SIZE + (num_descs * desc_size);
62162306a36Sopenharmony_ci		new->q_base = dma_alloc_coherent(dev, new->q_size, &new->q_base_pa,
62262306a36Sopenharmony_ci						 GFP_KERNEL);
62362306a36Sopenharmony_ci		if (!new->q_base) {
62462306a36Sopenharmony_ci			netdev_err(lif->netdev, "Cannot allocate queue DMA memory\n");
62562306a36Sopenharmony_ci			err = -ENOMEM;
62662306a36Sopenharmony_ci			goto err_out_free_cq_info;
62762306a36Sopenharmony_ci		}
62862306a36Sopenharmony_ci		q_base = PTR_ALIGN(new->q_base, PAGE_SIZE);
62962306a36Sopenharmony_ci		q_base_pa = ALIGN(new->q_base_pa, PAGE_SIZE);
63062306a36Sopenharmony_ci		ionic_q_map(&new->q, q_base, q_base_pa);
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci		if (flags & IONIC_QCQ_F_CMB_RINGS) {
63362306a36Sopenharmony_ci			/* on-chip CMB q descriptors */
63462306a36Sopenharmony_ci			new->cmb_q_size = num_descs * desc_size;
63562306a36Sopenharmony_ci			new->cmb_order = order_base_2(new->cmb_q_size / PAGE_SIZE);
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci			err = ionic_get_cmb(lif, &new->cmb_pgid, &new->cmb_q_base_pa,
63862306a36Sopenharmony_ci					    new->cmb_order);
63962306a36Sopenharmony_ci			if (err) {
64062306a36Sopenharmony_ci				netdev_err(lif->netdev,
64162306a36Sopenharmony_ci					   "Cannot allocate queue order %d from cmb: err %d\n",
64262306a36Sopenharmony_ci					   new->cmb_order, err);
64362306a36Sopenharmony_ci				goto err_out_free_q;
64462306a36Sopenharmony_ci			}
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci			new->cmb_q_base = ioremap_wc(new->cmb_q_base_pa, new->cmb_q_size);
64762306a36Sopenharmony_ci			if (!new->cmb_q_base) {
64862306a36Sopenharmony_ci				netdev_err(lif->netdev, "Cannot map queue from cmb\n");
64962306a36Sopenharmony_ci				ionic_put_cmb(lif, new->cmb_pgid, new->cmb_order);
65062306a36Sopenharmony_ci				err = -ENOMEM;
65162306a36Sopenharmony_ci				goto err_out_free_q;
65262306a36Sopenharmony_ci			}
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci			new->cmb_q_base_pa -= idev->phy_cmb_pages;
65562306a36Sopenharmony_ci			ionic_q_cmb_map(&new->q, new->cmb_q_base, new->cmb_q_base_pa);
65662306a36Sopenharmony_ci		}
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci		/* cq DMA descriptors */
65962306a36Sopenharmony_ci		new->cq_size = PAGE_SIZE + (num_descs * cq_desc_size);
66062306a36Sopenharmony_ci		new->cq_base = dma_alloc_coherent(dev, new->cq_size, &new->cq_base_pa,
66162306a36Sopenharmony_ci						  GFP_KERNEL);
66262306a36Sopenharmony_ci		if (!new->cq_base) {
66362306a36Sopenharmony_ci			netdev_err(lif->netdev, "Cannot allocate cq DMA memory\n");
66462306a36Sopenharmony_ci			err = -ENOMEM;
66562306a36Sopenharmony_ci			goto err_out_free_q;
66662306a36Sopenharmony_ci		}
66762306a36Sopenharmony_ci		cq_base = PTR_ALIGN(new->cq_base, PAGE_SIZE);
66862306a36Sopenharmony_ci		cq_base_pa = ALIGN(new->cq_base_pa, PAGE_SIZE);
66962306a36Sopenharmony_ci		ionic_cq_map(&new->cq, cq_base, cq_base_pa);
67062306a36Sopenharmony_ci		ionic_cq_bind(&new->cq, &new->q);
67162306a36Sopenharmony_ci	}
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	if (flags & IONIC_QCQ_F_SG) {
67462306a36Sopenharmony_ci		new->sg_size = PAGE_SIZE + (num_descs * sg_desc_size);
67562306a36Sopenharmony_ci		new->sg_base = dma_alloc_coherent(dev, new->sg_size, &new->sg_base_pa,
67662306a36Sopenharmony_ci						  GFP_KERNEL);
67762306a36Sopenharmony_ci		if (!new->sg_base) {
67862306a36Sopenharmony_ci			netdev_err(lif->netdev, "Cannot allocate sg DMA memory\n");
67962306a36Sopenharmony_ci			err = -ENOMEM;
68062306a36Sopenharmony_ci			goto err_out_free_cq;
68162306a36Sopenharmony_ci		}
68262306a36Sopenharmony_ci		sg_base = PTR_ALIGN(new->sg_base, PAGE_SIZE);
68362306a36Sopenharmony_ci		sg_base_pa = ALIGN(new->sg_base_pa, PAGE_SIZE);
68462306a36Sopenharmony_ci		ionic_q_sg_map(&new->q, sg_base, sg_base_pa);
68562306a36Sopenharmony_ci	}
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	INIT_WORK(&new->dim.work, ionic_dim_work);
68862306a36Sopenharmony_ci	new->dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE;
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	*qcq = new;
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	return 0;
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_cierr_out_free_cq:
69562306a36Sopenharmony_ci	dma_free_coherent(dev, new->cq_size, new->cq_base, new->cq_base_pa);
69662306a36Sopenharmony_cierr_out_free_q:
69762306a36Sopenharmony_ci	if (new->cmb_q_base) {
69862306a36Sopenharmony_ci		iounmap(new->cmb_q_base);
69962306a36Sopenharmony_ci		ionic_put_cmb(lif, new->cmb_pgid, new->cmb_order);
70062306a36Sopenharmony_ci	}
70162306a36Sopenharmony_ci	dma_free_coherent(dev, new->q_size, new->q_base, new->q_base_pa);
70262306a36Sopenharmony_cierr_out_free_cq_info:
70362306a36Sopenharmony_ci	vfree(new->cq.info);
70462306a36Sopenharmony_cierr_out_free_irq:
70562306a36Sopenharmony_ci	if (flags & IONIC_QCQ_F_INTR) {
70662306a36Sopenharmony_ci		devm_free_irq(dev, new->intr.vector, &new->napi);
70762306a36Sopenharmony_ci		ionic_intr_free(lif->ionic, new->intr.index);
70862306a36Sopenharmony_ci	}
70962306a36Sopenharmony_cierr_out_free_q_info:
71062306a36Sopenharmony_ci	vfree(new->q.info);
71162306a36Sopenharmony_cierr_out_free_qcq:
71262306a36Sopenharmony_ci	devm_kfree(dev, new);
71362306a36Sopenharmony_cierr_out:
71462306a36Sopenharmony_ci	dev_err(dev, "qcq alloc of %s%d failed %d\n", name, index, err);
71562306a36Sopenharmony_ci	return err;
71662306a36Sopenharmony_ci}
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_cistatic int ionic_qcqs_alloc(struct ionic_lif *lif)
71962306a36Sopenharmony_ci{
72062306a36Sopenharmony_ci	struct device *dev = lif->ionic->dev;
72162306a36Sopenharmony_ci	unsigned int flags;
72262306a36Sopenharmony_ci	int err;
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci	flags = IONIC_QCQ_F_INTR;
72562306a36Sopenharmony_ci	err = ionic_qcq_alloc(lif, IONIC_QTYPE_ADMINQ, 0, "admin", flags,
72662306a36Sopenharmony_ci			      IONIC_ADMINQ_LENGTH,
72762306a36Sopenharmony_ci			      sizeof(struct ionic_admin_cmd),
72862306a36Sopenharmony_ci			      sizeof(struct ionic_admin_comp),
72962306a36Sopenharmony_ci			      0, lif->kern_pid, &lif->adminqcq);
73062306a36Sopenharmony_ci	if (err)
73162306a36Sopenharmony_ci		return err;
73262306a36Sopenharmony_ci	ionic_debugfs_add_qcq(lif, lif->adminqcq);
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci	if (lif->ionic->nnqs_per_lif) {
73562306a36Sopenharmony_ci		flags = IONIC_QCQ_F_NOTIFYQ;
73662306a36Sopenharmony_ci		err = ionic_qcq_alloc(lif, IONIC_QTYPE_NOTIFYQ, 0, "notifyq",
73762306a36Sopenharmony_ci				      flags, IONIC_NOTIFYQ_LENGTH,
73862306a36Sopenharmony_ci				      sizeof(struct ionic_notifyq_cmd),
73962306a36Sopenharmony_ci				      sizeof(union ionic_notifyq_comp),
74062306a36Sopenharmony_ci				      0, lif->kern_pid, &lif->notifyqcq);
74162306a36Sopenharmony_ci		if (err)
74262306a36Sopenharmony_ci			goto err_out;
74362306a36Sopenharmony_ci		ionic_debugfs_add_qcq(lif, lif->notifyqcq);
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci		/* Let the notifyq ride on the adminq interrupt */
74662306a36Sopenharmony_ci		ionic_link_qcq_interrupts(lif->adminqcq, lif->notifyqcq);
74762306a36Sopenharmony_ci	}
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci	err = -ENOMEM;
75062306a36Sopenharmony_ci	lif->txqcqs = devm_kcalloc(dev, lif->ionic->ntxqs_per_lif,
75162306a36Sopenharmony_ci				   sizeof(*lif->txqcqs), GFP_KERNEL);
75262306a36Sopenharmony_ci	if (!lif->txqcqs)
75362306a36Sopenharmony_ci		goto err_out;
75462306a36Sopenharmony_ci	lif->rxqcqs = devm_kcalloc(dev, lif->ionic->nrxqs_per_lif,
75562306a36Sopenharmony_ci				   sizeof(*lif->rxqcqs), GFP_KERNEL);
75662306a36Sopenharmony_ci	if (!lif->rxqcqs)
75762306a36Sopenharmony_ci		goto err_out;
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_ci	lif->txqstats = devm_kcalloc(dev, lif->ionic->ntxqs_per_lif + 1,
76062306a36Sopenharmony_ci				     sizeof(*lif->txqstats), GFP_KERNEL);
76162306a36Sopenharmony_ci	if (!lif->txqstats)
76262306a36Sopenharmony_ci		goto err_out;
76362306a36Sopenharmony_ci	lif->rxqstats = devm_kcalloc(dev, lif->ionic->nrxqs_per_lif + 1,
76462306a36Sopenharmony_ci				     sizeof(*lif->rxqstats), GFP_KERNEL);
76562306a36Sopenharmony_ci	if (!lif->rxqstats)
76662306a36Sopenharmony_ci		goto err_out;
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci	return 0;
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_cierr_out:
77162306a36Sopenharmony_ci	ionic_qcqs_free(lif);
77262306a36Sopenharmony_ci	return err;
77362306a36Sopenharmony_ci}
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_cistatic void ionic_qcq_sanitize(struct ionic_qcq *qcq)
77662306a36Sopenharmony_ci{
77762306a36Sopenharmony_ci	qcq->q.tail_idx = 0;
77862306a36Sopenharmony_ci	qcq->q.head_idx = 0;
77962306a36Sopenharmony_ci	qcq->cq.tail_idx = 0;
78062306a36Sopenharmony_ci	qcq->cq.done_color = 1;
78162306a36Sopenharmony_ci	memset(qcq->q_base, 0, qcq->q_size);
78262306a36Sopenharmony_ci	if (qcq->cmb_q_base)
78362306a36Sopenharmony_ci		memset_io(qcq->cmb_q_base, 0, qcq->cmb_q_size);
78462306a36Sopenharmony_ci	memset(qcq->cq_base, 0, qcq->cq_size);
78562306a36Sopenharmony_ci	memset(qcq->sg_base, 0, qcq->sg_size);
78662306a36Sopenharmony_ci}
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_cistatic int ionic_lif_txq_init(struct ionic_lif *lif, struct ionic_qcq *qcq)
78962306a36Sopenharmony_ci{
79062306a36Sopenharmony_ci	struct device *dev = lif->ionic->dev;
79162306a36Sopenharmony_ci	struct ionic_queue *q = &qcq->q;
79262306a36Sopenharmony_ci	struct ionic_cq *cq = &qcq->cq;
79362306a36Sopenharmony_ci	struct ionic_admin_ctx ctx = {
79462306a36Sopenharmony_ci		.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
79562306a36Sopenharmony_ci		.cmd.q_init = {
79662306a36Sopenharmony_ci			.opcode = IONIC_CMD_Q_INIT,
79762306a36Sopenharmony_ci			.lif_index = cpu_to_le16(lif->index),
79862306a36Sopenharmony_ci			.type = q->type,
79962306a36Sopenharmony_ci			.ver = lif->qtype_info[q->type].version,
80062306a36Sopenharmony_ci			.index = cpu_to_le32(q->index),
80162306a36Sopenharmony_ci			.flags = cpu_to_le16(IONIC_QINIT_F_IRQ |
80262306a36Sopenharmony_ci					     IONIC_QINIT_F_SG),
80362306a36Sopenharmony_ci			.intr_index = cpu_to_le16(qcq->intr.index),
80462306a36Sopenharmony_ci			.pid = cpu_to_le16(q->pid),
80562306a36Sopenharmony_ci			.ring_size = ilog2(q->num_descs),
80662306a36Sopenharmony_ci			.ring_base = cpu_to_le64(q->base_pa),
80762306a36Sopenharmony_ci			.cq_ring_base = cpu_to_le64(cq->base_pa),
80862306a36Sopenharmony_ci			.sg_ring_base = cpu_to_le64(q->sg_base_pa),
80962306a36Sopenharmony_ci			.features = cpu_to_le64(q->features),
81062306a36Sopenharmony_ci		},
81162306a36Sopenharmony_ci	};
81262306a36Sopenharmony_ci	int err;
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	if (qcq->flags & IONIC_QCQ_F_CMB_RINGS) {
81562306a36Sopenharmony_ci		ctx.cmd.q_init.flags |= cpu_to_le16(IONIC_QINIT_F_CMB);
81662306a36Sopenharmony_ci		ctx.cmd.q_init.ring_base = cpu_to_le64(qcq->cmb_q_base_pa);
81762306a36Sopenharmony_ci	}
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci	dev_dbg(dev, "txq_init.pid %d\n", ctx.cmd.q_init.pid);
82062306a36Sopenharmony_ci	dev_dbg(dev, "txq_init.index %d\n", ctx.cmd.q_init.index);
82162306a36Sopenharmony_ci	dev_dbg(dev, "txq_init.ring_base 0x%llx\n", ctx.cmd.q_init.ring_base);
82262306a36Sopenharmony_ci	dev_dbg(dev, "txq_init.ring_size %d\n", ctx.cmd.q_init.ring_size);
82362306a36Sopenharmony_ci	dev_dbg(dev, "txq_init.cq_ring_base 0x%llx\n", ctx.cmd.q_init.cq_ring_base);
82462306a36Sopenharmony_ci	dev_dbg(dev, "txq_init.sg_ring_base 0x%llx\n", ctx.cmd.q_init.sg_ring_base);
82562306a36Sopenharmony_ci	dev_dbg(dev, "txq_init.flags 0x%x\n", ctx.cmd.q_init.flags);
82662306a36Sopenharmony_ci	dev_dbg(dev, "txq_init.ver %d\n", ctx.cmd.q_init.ver);
82762306a36Sopenharmony_ci	dev_dbg(dev, "txq_init.intr_index %d\n", ctx.cmd.q_init.intr_index);
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	ionic_qcq_sanitize(qcq);
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci	err = ionic_adminq_post_wait(lif, &ctx);
83262306a36Sopenharmony_ci	if (err)
83362306a36Sopenharmony_ci		return err;
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci	q->hw_type = ctx.comp.q_init.hw_type;
83662306a36Sopenharmony_ci	q->hw_index = le32_to_cpu(ctx.comp.q_init.hw_index);
83762306a36Sopenharmony_ci	q->dbval = IONIC_DBELL_QID(q->hw_index);
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci	dev_dbg(dev, "txq->hw_type %d\n", q->hw_type);
84062306a36Sopenharmony_ci	dev_dbg(dev, "txq->hw_index %d\n", q->hw_index);
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci	q->dbell_deadline = IONIC_TX_DOORBELL_DEADLINE;
84362306a36Sopenharmony_ci	q->dbell_jiffies = jiffies;
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci	if (test_bit(IONIC_LIF_F_SPLIT_INTR, lif->state)) {
84662306a36Sopenharmony_ci		netif_napi_add(lif->netdev, &qcq->napi, ionic_tx_napi);
84762306a36Sopenharmony_ci		qcq->napi_qcq = qcq;
84862306a36Sopenharmony_ci		timer_setup(&qcq->napi_deadline, ionic_napi_deadline, 0);
84962306a36Sopenharmony_ci	}
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	qcq->flags |= IONIC_QCQ_F_INITED;
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	return 0;
85462306a36Sopenharmony_ci}
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_cistatic int ionic_lif_rxq_init(struct ionic_lif *lif, struct ionic_qcq *qcq)
85762306a36Sopenharmony_ci{
85862306a36Sopenharmony_ci	struct device *dev = lif->ionic->dev;
85962306a36Sopenharmony_ci	struct ionic_queue *q = &qcq->q;
86062306a36Sopenharmony_ci	struct ionic_cq *cq = &qcq->cq;
86162306a36Sopenharmony_ci	struct ionic_admin_ctx ctx = {
86262306a36Sopenharmony_ci		.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
86362306a36Sopenharmony_ci		.cmd.q_init = {
86462306a36Sopenharmony_ci			.opcode = IONIC_CMD_Q_INIT,
86562306a36Sopenharmony_ci			.lif_index = cpu_to_le16(lif->index),
86662306a36Sopenharmony_ci			.type = q->type,
86762306a36Sopenharmony_ci			.ver = lif->qtype_info[q->type].version,
86862306a36Sopenharmony_ci			.index = cpu_to_le32(q->index),
86962306a36Sopenharmony_ci			.flags = cpu_to_le16(IONIC_QINIT_F_IRQ |
87062306a36Sopenharmony_ci					     IONIC_QINIT_F_SG),
87162306a36Sopenharmony_ci			.intr_index = cpu_to_le16(cq->bound_intr->index),
87262306a36Sopenharmony_ci			.pid = cpu_to_le16(q->pid),
87362306a36Sopenharmony_ci			.ring_size = ilog2(q->num_descs),
87462306a36Sopenharmony_ci			.ring_base = cpu_to_le64(q->base_pa),
87562306a36Sopenharmony_ci			.cq_ring_base = cpu_to_le64(cq->base_pa),
87662306a36Sopenharmony_ci			.sg_ring_base = cpu_to_le64(q->sg_base_pa),
87762306a36Sopenharmony_ci			.features = cpu_to_le64(q->features),
87862306a36Sopenharmony_ci		},
87962306a36Sopenharmony_ci	};
88062306a36Sopenharmony_ci	int err;
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_ci	if (qcq->flags & IONIC_QCQ_F_CMB_RINGS) {
88362306a36Sopenharmony_ci		ctx.cmd.q_init.flags |= cpu_to_le16(IONIC_QINIT_F_CMB);
88462306a36Sopenharmony_ci		ctx.cmd.q_init.ring_base = cpu_to_le64(qcq->cmb_q_base_pa);
88562306a36Sopenharmony_ci	}
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	dev_dbg(dev, "rxq_init.pid %d\n", ctx.cmd.q_init.pid);
88862306a36Sopenharmony_ci	dev_dbg(dev, "rxq_init.index %d\n", ctx.cmd.q_init.index);
88962306a36Sopenharmony_ci	dev_dbg(dev, "rxq_init.ring_base 0x%llx\n", ctx.cmd.q_init.ring_base);
89062306a36Sopenharmony_ci	dev_dbg(dev, "rxq_init.ring_size %d\n", ctx.cmd.q_init.ring_size);
89162306a36Sopenharmony_ci	dev_dbg(dev, "rxq_init.flags 0x%x\n", ctx.cmd.q_init.flags);
89262306a36Sopenharmony_ci	dev_dbg(dev, "rxq_init.ver %d\n", ctx.cmd.q_init.ver);
89362306a36Sopenharmony_ci	dev_dbg(dev, "rxq_init.intr_index %d\n", ctx.cmd.q_init.intr_index);
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci	ionic_qcq_sanitize(qcq);
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci	err = ionic_adminq_post_wait(lif, &ctx);
89862306a36Sopenharmony_ci	if (err)
89962306a36Sopenharmony_ci		return err;
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci	q->hw_type = ctx.comp.q_init.hw_type;
90262306a36Sopenharmony_ci	q->hw_index = le32_to_cpu(ctx.comp.q_init.hw_index);
90362306a36Sopenharmony_ci	q->dbval = IONIC_DBELL_QID(q->hw_index);
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_ci	dev_dbg(dev, "rxq->hw_type %d\n", q->hw_type);
90662306a36Sopenharmony_ci	dev_dbg(dev, "rxq->hw_index %d\n", q->hw_index);
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci	q->dbell_deadline = IONIC_RX_MIN_DOORBELL_DEADLINE;
90962306a36Sopenharmony_ci	q->dbell_jiffies = jiffies;
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci	if (test_bit(IONIC_LIF_F_SPLIT_INTR, lif->state))
91262306a36Sopenharmony_ci		netif_napi_add(lif->netdev, &qcq->napi, ionic_rx_napi);
91362306a36Sopenharmony_ci	else
91462306a36Sopenharmony_ci		netif_napi_add(lif->netdev, &qcq->napi, ionic_txrx_napi);
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci	qcq->napi_qcq = qcq;
91762306a36Sopenharmony_ci	timer_setup(&qcq->napi_deadline, ionic_napi_deadline, 0);
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci	qcq->flags |= IONIC_QCQ_F_INITED;
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci	return 0;
92262306a36Sopenharmony_ci}
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_ciint ionic_lif_create_hwstamp_txq(struct ionic_lif *lif)
92562306a36Sopenharmony_ci{
92662306a36Sopenharmony_ci	unsigned int num_desc, desc_sz, comp_sz, sg_desc_sz;
92762306a36Sopenharmony_ci	unsigned int txq_i, flags;
92862306a36Sopenharmony_ci	struct ionic_qcq *txq;
92962306a36Sopenharmony_ci	u64 features;
93062306a36Sopenharmony_ci	int err;
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci	if (lif->hwstamp_txq)
93362306a36Sopenharmony_ci		return 0;
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci	features = IONIC_Q_F_2X_CQ_DESC | IONIC_TXQ_F_HWSTAMP;
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ci	num_desc = IONIC_MIN_TXRX_DESC;
93862306a36Sopenharmony_ci	desc_sz = sizeof(struct ionic_txq_desc);
93962306a36Sopenharmony_ci	comp_sz = 2 * sizeof(struct ionic_txq_comp);
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci	if (lif->qtype_info[IONIC_QTYPE_TXQ].version >= 1 &&
94262306a36Sopenharmony_ci	    lif->qtype_info[IONIC_QTYPE_TXQ].sg_desc_sz == sizeof(struct ionic_txq_sg_desc_v1))
94362306a36Sopenharmony_ci		sg_desc_sz = sizeof(struct ionic_txq_sg_desc_v1);
94462306a36Sopenharmony_ci	else
94562306a36Sopenharmony_ci		sg_desc_sz = sizeof(struct ionic_txq_sg_desc);
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci	txq_i = lif->ionic->ntxqs_per_lif;
94862306a36Sopenharmony_ci	flags = IONIC_QCQ_F_TX_STATS | IONIC_QCQ_F_SG;
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci	err = ionic_qcq_alloc(lif, IONIC_QTYPE_TXQ, txq_i, "hwstamp_tx", flags,
95162306a36Sopenharmony_ci			      num_desc, desc_sz, comp_sz, sg_desc_sz,
95262306a36Sopenharmony_ci			      lif->kern_pid, &txq);
95362306a36Sopenharmony_ci	if (err)
95462306a36Sopenharmony_ci		goto err_qcq_alloc;
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci	txq->q.features = features;
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci	ionic_link_qcq_interrupts(lif->adminqcq, txq);
95962306a36Sopenharmony_ci	ionic_debugfs_add_qcq(lif, txq);
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci	lif->hwstamp_txq = txq;
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci	if (netif_running(lif->netdev)) {
96462306a36Sopenharmony_ci		err = ionic_lif_txq_init(lif, txq);
96562306a36Sopenharmony_ci		if (err)
96662306a36Sopenharmony_ci			goto err_qcq_init;
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci		if (test_bit(IONIC_LIF_F_UP, lif->state)) {
96962306a36Sopenharmony_ci			err = ionic_qcq_enable(txq);
97062306a36Sopenharmony_ci			if (err)
97162306a36Sopenharmony_ci				goto err_qcq_enable;
97262306a36Sopenharmony_ci		}
97362306a36Sopenharmony_ci	}
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	return 0;
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_cierr_qcq_enable:
97862306a36Sopenharmony_ci	ionic_lif_qcq_deinit(lif, txq);
97962306a36Sopenharmony_cierr_qcq_init:
98062306a36Sopenharmony_ci	lif->hwstamp_txq = NULL;
98162306a36Sopenharmony_ci	ionic_debugfs_del_qcq(txq);
98262306a36Sopenharmony_ci	ionic_qcq_free(lif, txq);
98362306a36Sopenharmony_ci	devm_kfree(lif->ionic->dev, txq);
98462306a36Sopenharmony_cierr_qcq_alloc:
98562306a36Sopenharmony_ci	return err;
98662306a36Sopenharmony_ci}
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ciint ionic_lif_create_hwstamp_rxq(struct ionic_lif *lif)
98962306a36Sopenharmony_ci{
99062306a36Sopenharmony_ci	unsigned int num_desc, desc_sz, comp_sz, sg_desc_sz;
99162306a36Sopenharmony_ci	unsigned int rxq_i, flags;
99262306a36Sopenharmony_ci	struct ionic_qcq *rxq;
99362306a36Sopenharmony_ci	u64 features;
99462306a36Sopenharmony_ci	int err;
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_ci	if (lif->hwstamp_rxq)
99762306a36Sopenharmony_ci		return 0;
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_ci	features = IONIC_Q_F_2X_CQ_DESC | IONIC_RXQ_F_HWSTAMP;
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_ci	num_desc = IONIC_MIN_TXRX_DESC;
100262306a36Sopenharmony_ci	desc_sz = sizeof(struct ionic_rxq_desc);
100362306a36Sopenharmony_ci	comp_sz = 2 * sizeof(struct ionic_rxq_comp);
100462306a36Sopenharmony_ci	sg_desc_sz = sizeof(struct ionic_rxq_sg_desc);
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_ci	rxq_i = lif->ionic->nrxqs_per_lif;
100762306a36Sopenharmony_ci	flags = IONIC_QCQ_F_RX_STATS | IONIC_QCQ_F_SG;
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci	err = ionic_qcq_alloc(lif, IONIC_QTYPE_RXQ, rxq_i, "hwstamp_rx", flags,
101062306a36Sopenharmony_ci			      num_desc, desc_sz, comp_sz, sg_desc_sz,
101162306a36Sopenharmony_ci			      lif->kern_pid, &rxq);
101262306a36Sopenharmony_ci	if (err)
101362306a36Sopenharmony_ci		goto err_qcq_alloc;
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci	rxq->q.features = features;
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci	ionic_link_qcq_interrupts(lif->adminqcq, rxq);
101862306a36Sopenharmony_ci	ionic_debugfs_add_qcq(lif, rxq);
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci	lif->hwstamp_rxq = rxq;
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci	if (netif_running(lif->netdev)) {
102362306a36Sopenharmony_ci		err = ionic_lif_rxq_init(lif, rxq);
102462306a36Sopenharmony_ci		if (err)
102562306a36Sopenharmony_ci			goto err_qcq_init;
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci		if (test_bit(IONIC_LIF_F_UP, lif->state)) {
102862306a36Sopenharmony_ci			ionic_rx_fill(&rxq->q);
102962306a36Sopenharmony_ci			err = ionic_qcq_enable(rxq);
103062306a36Sopenharmony_ci			if (err)
103162306a36Sopenharmony_ci				goto err_qcq_enable;
103262306a36Sopenharmony_ci		}
103362306a36Sopenharmony_ci	}
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci	return 0;
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_cierr_qcq_enable:
103862306a36Sopenharmony_ci	ionic_lif_qcq_deinit(lif, rxq);
103962306a36Sopenharmony_cierr_qcq_init:
104062306a36Sopenharmony_ci	lif->hwstamp_rxq = NULL;
104162306a36Sopenharmony_ci	ionic_debugfs_del_qcq(rxq);
104262306a36Sopenharmony_ci	ionic_qcq_free(lif, rxq);
104362306a36Sopenharmony_ci	devm_kfree(lif->ionic->dev, rxq);
104462306a36Sopenharmony_cierr_qcq_alloc:
104562306a36Sopenharmony_ci	return err;
104662306a36Sopenharmony_ci}
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ciint ionic_lif_config_hwstamp_rxq_all(struct ionic_lif *lif, bool rx_all)
104962306a36Sopenharmony_ci{
105062306a36Sopenharmony_ci	struct ionic_queue_params qparam;
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci	ionic_init_queue_params(lif, &qparam);
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_ci	if (rx_all)
105562306a36Sopenharmony_ci		qparam.rxq_features = IONIC_Q_F_2X_CQ_DESC | IONIC_RXQ_F_HWSTAMP;
105662306a36Sopenharmony_ci	else
105762306a36Sopenharmony_ci		qparam.rxq_features = 0;
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci	/* if we're not running, just set the values and return */
106062306a36Sopenharmony_ci	if (!netif_running(lif->netdev)) {
106162306a36Sopenharmony_ci		lif->rxq_features = qparam.rxq_features;
106262306a36Sopenharmony_ci		return 0;
106362306a36Sopenharmony_ci	}
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci	return ionic_reconfigure_queues(lif, &qparam);
106662306a36Sopenharmony_ci}
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_ciint ionic_lif_set_hwstamp_txmode(struct ionic_lif *lif, u16 txstamp_mode)
106962306a36Sopenharmony_ci{
107062306a36Sopenharmony_ci	struct ionic_admin_ctx ctx = {
107162306a36Sopenharmony_ci		.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
107262306a36Sopenharmony_ci		.cmd.lif_setattr = {
107362306a36Sopenharmony_ci			.opcode = IONIC_CMD_LIF_SETATTR,
107462306a36Sopenharmony_ci			.index = cpu_to_le16(lif->index),
107562306a36Sopenharmony_ci			.attr = IONIC_LIF_ATTR_TXSTAMP,
107662306a36Sopenharmony_ci			.txstamp_mode = cpu_to_le16(txstamp_mode),
107762306a36Sopenharmony_ci		},
107862306a36Sopenharmony_ci	};
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_ci	return ionic_adminq_post_wait(lif, &ctx);
108162306a36Sopenharmony_ci}
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_cistatic void ionic_lif_del_hwstamp_rxfilt(struct ionic_lif *lif)
108462306a36Sopenharmony_ci{
108562306a36Sopenharmony_ci	struct ionic_admin_ctx ctx = {
108662306a36Sopenharmony_ci		.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
108762306a36Sopenharmony_ci		.cmd.rx_filter_del = {
108862306a36Sopenharmony_ci			.opcode = IONIC_CMD_RX_FILTER_DEL,
108962306a36Sopenharmony_ci			.lif_index = cpu_to_le16(lif->index),
109062306a36Sopenharmony_ci		},
109162306a36Sopenharmony_ci	};
109262306a36Sopenharmony_ci	struct ionic_rx_filter *f;
109362306a36Sopenharmony_ci	u32 filter_id;
109462306a36Sopenharmony_ci	int err;
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci	spin_lock_bh(&lif->rx_filters.lock);
109762306a36Sopenharmony_ci
109862306a36Sopenharmony_ci	f = ionic_rx_filter_rxsteer(lif);
109962306a36Sopenharmony_ci	if (!f) {
110062306a36Sopenharmony_ci		spin_unlock_bh(&lif->rx_filters.lock);
110162306a36Sopenharmony_ci		return;
110262306a36Sopenharmony_ci	}
110362306a36Sopenharmony_ci
110462306a36Sopenharmony_ci	filter_id = f->filter_id;
110562306a36Sopenharmony_ci	ionic_rx_filter_free(lif, f);
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_ci	spin_unlock_bh(&lif->rx_filters.lock);
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_ci	netdev_dbg(lif->netdev, "rx_filter del RXSTEER (id %d)\n", filter_id);
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ci	ctx.cmd.rx_filter_del.filter_id = cpu_to_le32(filter_id);
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ci	err = ionic_adminq_post_wait(lif, &ctx);
111462306a36Sopenharmony_ci	if (err && err != -EEXIST)
111562306a36Sopenharmony_ci		netdev_dbg(lif->netdev, "failed to delete rx_filter RXSTEER (id %d)\n", filter_id);
111662306a36Sopenharmony_ci}
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_cistatic int ionic_lif_add_hwstamp_rxfilt(struct ionic_lif *lif, u64 pkt_class)
111962306a36Sopenharmony_ci{
112062306a36Sopenharmony_ci	struct ionic_admin_ctx ctx = {
112162306a36Sopenharmony_ci		.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
112262306a36Sopenharmony_ci		.cmd.rx_filter_add = {
112362306a36Sopenharmony_ci			.opcode = IONIC_CMD_RX_FILTER_ADD,
112462306a36Sopenharmony_ci			.lif_index = cpu_to_le16(lif->index),
112562306a36Sopenharmony_ci			.match = cpu_to_le16(IONIC_RX_FILTER_STEER_PKTCLASS),
112662306a36Sopenharmony_ci			.pkt_class = cpu_to_le64(pkt_class),
112762306a36Sopenharmony_ci		},
112862306a36Sopenharmony_ci	};
112962306a36Sopenharmony_ci	u8 qtype;
113062306a36Sopenharmony_ci	u32 qid;
113162306a36Sopenharmony_ci	int err;
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_ci	if (!lif->hwstamp_rxq)
113462306a36Sopenharmony_ci		return -EINVAL;
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_ci	qtype = lif->hwstamp_rxq->q.type;
113762306a36Sopenharmony_ci	ctx.cmd.rx_filter_add.qtype = qtype;
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci	qid = lif->hwstamp_rxq->q.index;
114062306a36Sopenharmony_ci	ctx.cmd.rx_filter_add.qid = cpu_to_le32(qid);
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ci	netdev_dbg(lif->netdev, "rx_filter add RXSTEER\n");
114362306a36Sopenharmony_ci	err = ionic_adminq_post_wait(lif, &ctx);
114462306a36Sopenharmony_ci	if (err && err != -EEXIST)
114562306a36Sopenharmony_ci		return err;
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_ci	spin_lock_bh(&lif->rx_filters.lock);
114862306a36Sopenharmony_ci	err = ionic_rx_filter_save(lif, 0, qid, 0, &ctx, IONIC_FILTER_STATE_SYNCED);
114962306a36Sopenharmony_ci	spin_unlock_bh(&lif->rx_filters.lock);
115062306a36Sopenharmony_ci
115162306a36Sopenharmony_ci	return err;
115262306a36Sopenharmony_ci}
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_ciint ionic_lif_set_hwstamp_rxfilt(struct ionic_lif *lif, u64 pkt_class)
115562306a36Sopenharmony_ci{
115662306a36Sopenharmony_ci	ionic_lif_del_hwstamp_rxfilt(lif);
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_ci	if (!pkt_class)
115962306a36Sopenharmony_ci		return 0;
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci	return ionic_lif_add_hwstamp_rxfilt(lif, pkt_class);
116262306a36Sopenharmony_ci}
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_cistatic bool ionic_notifyq_service(struct ionic_cq *cq,
116562306a36Sopenharmony_ci				  struct ionic_cq_info *cq_info)
116662306a36Sopenharmony_ci{
116762306a36Sopenharmony_ci	union ionic_notifyq_comp *comp = cq_info->cq_desc;
116862306a36Sopenharmony_ci	struct ionic_deferred_work *work;
116962306a36Sopenharmony_ci	struct net_device *netdev;
117062306a36Sopenharmony_ci	struct ionic_queue *q;
117162306a36Sopenharmony_ci	struct ionic_lif *lif;
117262306a36Sopenharmony_ci	u64 eid;
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_ci	q = cq->bound_q;
117562306a36Sopenharmony_ci	lif = q->info[0].cb_arg;
117662306a36Sopenharmony_ci	netdev = lif->netdev;
117762306a36Sopenharmony_ci	eid = le64_to_cpu(comp->event.eid);
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci	/* Have we run out of new completions to process? */
118062306a36Sopenharmony_ci	if ((s64)(eid - lif->last_eid) <= 0)
118162306a36Sopenharmony_ci		return false;
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci	lif->last_eid = eid;
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_ci	dev_dbg(lif->ionic->dev, "notifyq event:\n");
118662306a36Sopenharmony_ci	dynamic_hex_dump("event ", DUMP_PREFIX_OFFSET, 16, 1,
118762306a36Sopenharmony_ci			 comp, sizeof(*comp), true);
118862306a36Sopenharmony_ci
118962306a36Sopenharmony_ci	switch (le16_to_cpu(comp->event.ecode)) {
119062306a36Sopenharmony_ci	case IONIC_EVENT_LINK_CHANGE:
119162306a36Sopenharmony_ci		ionic_link_status_check_request(lif, CAN_NOT_SLEEP);
119262306a36Sopenharmony_ci		break;
119362306a36Sopenharmony_ci	case IONIC_EVENT_RESET:
119462306a36Sopenharmony_ci		if (lif->ionic->idev.fw_status_ready &&
119562306a36Sopenharmony_ci		    !test_bit(IONIC_LIF_F_FW_RESET, lif->state) &&
119662306a36Sopenharmony_ci		    !test_and_set_bit(IONIC_LIF_F_FW_STOPPING, lif->state)) {
119762306a36Sopenharmony_ci			work = kzalloc(sizeof(*work), GFP_ATOMIC);
119862306a36Sopenharmony_ci			if (!work) {
119962306a36Sopenharmony_ci				netdev_err(lif->netdev, "Reset event dropped\n");
120062306a36Sopenharmony_ci				clear_bit(IONIC_LIF_F_FW_STOPPING, lif->state);
120162306a36Sopenharmony_ci			} else {
120262306a36Sopenharmony_ci				work->type = IONIC_DW_TYPE_LIF_RESET;
120362306a36Sopenharmony_ci				ionic_lif_deferred_enqueue(&lif->deferred, work);
120462306a36Sopenharmony_ci			}
120562306a36Sopenharmony_ci		}
120662306a36Sopenharmony_ci		break;
120762306a36Sopenharmony_ci	default:
120862306a36Sopenharmony_ci		netdev_warn(netdev, "Notifyq event ecode=%d eid=%lld\n",
120962306a36Sopenharmony_ci			    comp->event.ecode, eid);
121062306a36Sopenharmony_ci		break;
121162306a36Sopenharmony_ci	}
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_ci	return true;
121462306a36Sopenharmony_ci}
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_cistatic bool ionic_adminq_service(struct ionic_cq *cq,
121762306a36Sopenharmony_ci				 struct ionic_cq_info *cq_info)
121862306a36Sopenharmony_ci{
121962306a36Sopenharmony_ci	struct ionic_admin_comp *comp = cq_info->cq_desc;
122062306a36Sopenharmony_ci
122162306a36Sopenharmony_ci	if (!color_match(comp->color, cq->done_color))
122262306a36Sopenharmony_ci		return false;
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci	ionic_q_service(cq->bound_q, cq_info, le16_to_cpu(comp->comp_index));
122562306a36Sopenharmony_ci
122662306a36Sopenharmony_ci	return true;
122762306a36Sopenharmony_ci}
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_cistatic int ionic_adminq_napi(struct napi_struct *napi, int budget)
123062306a36Sopenharmony_ci{
123162306a36Sopenharmony_ci	struct ionic_intr_info *intr = napi_to_cq(napi)->bound_intr;
123262306a36Sopenharmony_ci	struct ionic_lif *lif = napi_to_cq(napi)->lif;
123362306a36Sopenharmony_ci	struct ionic_dev *idev = &lif->ionic->idev;
123462306a36Sopenharmony_ci	unsigned long irqflags;
123562306a36Sopenharmony_ci	unsigned int flags = 0;
123662306a36Sopenharmony_ci	bool resched = false;
123762306a36Sopenharmony_ci	int rx_work = 0;
123862306a36Sopenharmony_ci	int tx_work = 0;
123962306a36Sopenharmony_ci	int n_work = 0;
124062306a36Sopenharmony_ci	int a_work = 0;
124162306a36Sopenharmony_ci	int work_done;
124262306a36Sopenharmony_ci	int credits;
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ci	if (lif->notifyqcq && lif->notifyqcq->flags & IONIC_QCQ_F_INITED)
124562306a36Sopenharmony_ci		n_work = ionic_cq_service(&lif->notifyqcq->cq, budget,
124662306a36Sopenharmony_ci					  ionic_notifyq_service, NULL, NULL);
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_ci	spin_lock_irqsave(&lif->adminq_lock, irqflags);
124962306a36Sopenharmony_ci	if (lif->adminqcq && lif->adminqcq->flags & IONIC_QCQ_F_INITED)
125062306a36Sopenharmony_ci		a_work = ionic_cq_service(&lif->adminqcq->cq, budget,
125162306a36Sopenharmony_ci					  ionic_adminq_service, NULL, NULL);
125262306a36Sopenharmony_ci	spin_unlock_irqrestore(&lif->adminq_lock, irqflags);
125362306a36Sopenharmony_ci
125462306a36Sopenharmony_ci	if (lif->hwstamp_rxq)
125562306a36Sopenharmony_ci		rx_work = ionic_cq_service(&lif->hwstamp_rxq->cq, budget,
125662306a36Sopenharmony_ci					   ionic_rx_service, NULL, NULL);
125762306a36Sopenharmony_ci
125862306a36Sopenharmony_ci	if (lif->hwstamp_txq)
125962306a36Sopenharmony_ci		tx_work = ionic_cq_service(&lif->hwstamp_txq->cq, budget,
126062306a36Sopenharmony_ci					   ionic_tx_service, NULL, NULL);
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_ci	work_done = max(max(n_work, a_work), max(rx_work, tx_work));
126362306a36Sopenharmony_ci	if (work_done < budget && napi_complete_done(napi, work_done)) {
126462306a36Sopenharmony_ci		flags |= IONIC_INTR_CRED_UNMASK;
126562306a36Sopenharmony_ci		intr->rearm_count++;
126662306a36Sopenharmony_ci	}
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_ci	if (work_done || flags) {
126962306a36Sopenharmony_ci		flags |= IONIC_INTR_CRED_RESET_COALESCE;
127062306a36Sopenharmony_ci		credits = n_work + a_work + rx_work + tx_work;
127162306a36Sopenharmony_ci		ionic_intr_credits(idev->intr_ctrl, intr->index, credits, flags);
127262306a36Sopenharmony_ci	}
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_ci	if (!a_work && ionic_adminq_poke_doorbell(&lif->adminqcq->q))
127562306a36Sopenharmony_ci		resched = true;
127662306a36Sopenharmony_ci	if (lif->hwstamp_rxq && !rx_work && ionic_rxq_poke_doorbell(&lif->hwstamp_rxq->q))
127762306a36Sopenharmony_ci		resched = true;
127862306a36Sopenharmony_ci	if (lif->hwstamp_txq && !tx_work && ionic_txq_poke_doorbell(&lif->hwstamp_txq->q))
127962306a36Sopenharmony_ci		resched = true;
128062306a36Sopenharmony_ci	if (resched)
128162306a36Sopenharmony_ci		mod_timer(&lif->adminqcq->napi_deadline,
128262306a36Sopenharmony_ci			  jiffies + IONIC_NAPI_DEADLINE);
128362306a36Sopenharmony_ci
128462306a36Sopenharmony_ci	return work_done;
128562306a36Sopenharmony_ci}
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_civoid ionic_get_stats64(struct net_device *netdev,
128862306a36Sopenharmony_ci		       struct rtnl_link_stats64 *ns)
128962306a36Sopenharmony_ci{
129062306a36Sopenharmony_ci	struct ionic_lif *lif = netdev_priv(netdev);
129162306a36Sopenharmony_ci	struct ionic_lif_stats *ls;
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ci	memset(ns, 0, sizeof(*ns));
129462306a36Sopenharmony_ci	ls = &lif->info->stats;
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_ci	ns->rx_packets = le64_to_cpu(ls->rx_ucast_packets) +
129762306a36Sopenharmony_ci			 le64_to_cpu(ls->rx_mcast_packets) +
129862306a36Sopenharmony_ci			 le64_to_cpu(ls->rx_bcast_packets);
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_ci	ns->tx_packets = le64_to_cpu(ls->tx_ucast_packets) +
130162306a36Sopenharmony_ci			 le64_to_cpu(ls->tx_mcast_packets) +
130262306a36Sopenharmony_ci			 le64_to_cpu(ls->tx_bcast_packets);
130362306a36Sopenharmony_ci
130462306a36Sopenharmony_ci	ns->rx_bytes = le64_to_cpu(ls->rx_ucast_bytes) +
130562306a36Sopenharmony_ci		       le64_to_cpu(ls->rx_mcast_bytes) +
130662306a36Sopenharmony_ci		       le64_to_cpu(ls->rx_bcast_bytes);
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ci	ns->tx_bytes = le64_to_cpu(ls->tx_ucast_bytes) +
130962306a36Sopenharmony_ci		       le64_to_cpu(ls->tx_mcast_bytes) +
131062306a36Sopenharmony_ci		       le64_to_cpu(ls->tx_bcast_bytes);
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_ci	ns->rx_dropped = le64_to_cpu(ls->rx_ucast_drop_packets) +
131362306a36Sopenharmony_ci			 le64_to_cpu(ls->rx_mcast_drop_packets) +
131462306a36Sopenharmony_ci			 le64_to_cpu(ls->rx_bcast_drop_packets);
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_ci	ns->tx_dropped = le64_to_cpu(ls->tx_ucast_drop_packets) +
131762306a36Sopenharmony_ci			 le64_to_cpu(ls->tx_mcast_drop_packets) +
131862306a36Sopenharmony_ci			 le64_to_cpu(ls->tx_bcast_drop_packets);
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_ci	ns->multicast = le64_to_cpu(ls->rx_mcast_packets);
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci	ns->rx_over_errors = le64_to_cpu(ls->rx_queue_empty);
132362306a36Sopenharmony_ci
132462306a36Sopenharmony_ci	ns->rx_missed_errors = le64_to_cpu(ls->rx_dma_error) +
132562306a36Sopenharmony_ci			       le64_to_cpu(ls->rx_queue_disabled) +
132662306a36Sopenharmony_ci			       le64_to_cpu(ls->rx_desc_fetch_error) +
132762306a36Sopenharmony_ci			       le64_to_cpu(ls->rx_desc_data_error);
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_ci	ns->tx_aborted_errors = le64_to_cpu(ls->tx_dma_error) +
133062306a36Sopenharmony_ci				le64_to_cpu(ls->tx_queue_disabled) +
133162306a36Sopenharmony_ci				le64_to_cpu(ls->tx_desc_fetch_error) +
133262306a36Sopenharmony_ci				le64_to_cpu(ls->tx_desc_data_error);
133362306a36Sopenharmony_ci
133462306a36Sopenharmony_ci	ns->rx_errors = ns->rx_over_errors +
133562306a36Sopenharmony_ci			ns->rx_missed_errors;
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_ci	ns->tx_errors = ns->tx_aborted_errors;
133862306a36Sopenharmony_ci}
133962306a36Sopenharmony_ci
134062306a36Sopenharmony_cistatic int ionic_addr_add(struct net_device *netdev, const u8 *addr)
134162306a36Sopenharmony_ci{
134262306a36Sopenharmony_ci	return ionic_lif_list_addr(netdev_priv(netdev), addr, ADD_ADDR);
134362306a36Sopenharmony_ci}
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_cistatic int ionic_addr_del(struct net_device *netdev, const u8 *addr)
134662306a36Sopenharmony_ci{
134762306a36Sopenharmony_ci	/* Don't delete our own address from the uc list */
134862306a36Sopenharmony_ci	if (ether_addr_equal(addr, netdev->dev_addr))
134962306a36Sopenharmony_ci		return 0;
135062306a36Sopenharmony_ci
135162306a36Sopenharmony_ci	return ionic_lif_list_addr(netdev_priv(netdev), addr, DEL_ADDR);
135262306a36Sopenharmony_ci}
135362306a36Sopenharmony_ci
135462306a36Sopenharmony_civoid ionic_lif_rx_mode(struct ionic_lif *lif)
135562306a36Sopenharmony_ci{
135662306a36Sopenharmony_ci	struct net_device *netdev = lif->netdev;
135762306a36Sopenharmony_ci	unsigned int nfilters;
135862306a36Sopenharmony_ci	unsigned int nd_flags;
135962306a36Sopenharmony_ci	char buf[128];
136062306a36Sopenharmony_ci	u16 rx_mode;
136162306a36Sopenharmony_ci	int i;
136262306a36Sopenharmony_ci#define REMAIN(__x) (sizeof(buf) - (__x))
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_ci	mutex_lock(&lif->config_lock);
136562306a36Sopenharmony_ci
136662306a36Sopenharmony_ci	/* grab the flags once for local use */
136762306a36Sopenharmony_ci	nd_flags = netdev->flags;
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_ci	rx_mode = IONIC_RX_MODE_F_UNICAST;
137062306a36Sopenharmony_ci	rx_mode |= (nd_flags & IFF_MULTICAST) ? IONIC_RX_MODE_F_MULTICAST : 0;
137162306a36Sopenharmony_ci	rx_mode |= (nd_flags & IFF_BROADCAST) ? IONIC_RX_MODE_F_BROADCAST : 0;
137262306a36Sopenharmony_ci	rx_mode |= (nd_flags & IFF_PROMISC) ? IONIC_RX_MODE_F_PROMISC : 0;
137362306a36Sopenharmony_ci	rx_mode |= (nd_flags & IFF_ALLMULTI) ? IONIC_RX_MODE_F_ALLMULTI : 0;
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_ci	/* sync the filters */
137662306a36Sopenharmony_ci	ionic_rx_filter_sync(lif);
137762306a36Sopenharmony_ci
137862306a36Sopenharmony_ci	/* check for overflow state
137962306a36Sopenharmony_ci	 *    if so, we track that we overflowed and enable NIC PROMISC
138062306a36Sopenharmony_ci	 *    else if the overflow is set and not needed
138162306a36Sopenharmony_ci	 *       we remove our overflow flag and check the netdev flags
138262306a36Sopenharmony_ci	 *       to see if we can disable NIC PROMISC
138362306a36Sopenharmony_ci	 */
138462306a36Sopenharmony_ci	nfilters = le32_to_cpu(lif->identity->eth.max_ucast_filters);
138562306a36Sopenharmony_ci
138662306a36Sopenharmony_ci	if (((lif->nucast + lif->nmcast) >= nfilters) ||
138762306a36Sopenharmony_ci	    (lif->max_vlans && lif->nvlans >= lif->max_vlans)) {
138862306a36Sopenharmony_ci		rx_mode |= IONIC_RX_MODE_F_PROMISC;
138962306a36Sopenharmony_ci		rx_mode |= IONIC_RX_MODE_F_ALLMULTI;
139062306a36Sopenharmony_ci	} else {
139162306a36Sopenharmony_ci		if (!(nd_flags & IFF_PROMISC))
139262306a36Sopenharmony_ci			rx_mode &= ~IONIC_RX_MODE_F_PROMISC;
139362306a36Sopenharmony_ci		if (!(nd_flags & IFF_ALLMULTI))
139462306a36Sopenharmony_ci			rx_mode &= ~IONIC_RX_MODE_F_ALLMULTI;
139562306a36Sopenharmony_ci	}
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_ci	i = scnprintf(buf, sizeof(buf), "rx_mode 0x%04x -> 0x%04x:",
139862306a36Sopenharmony_ci		      lif->rx_mode, rx_mode);
139962306a36Sopenharmony_ci	if (rx_mode & IONIC_RX_MODE_F_UNICAST)
140062306a36Sopenharmony_ci		i += scnprintf(&buf[i], REMAIN(i), " RX_MODE_F_UNICAST");
140162306a36Sopenharmony_ci	if (rx_mode & IONIC_RX_MODE_F_MULTICAST)
140262306a36Sopenharmony_ci		i += scnprintf(&buf[i], REMAIN(i), " RX_MODE_F_MULTICAST");
140362306a36Sopenharmony_ci	if (rx_mode & IONIC_RX_MODE_F_BROADCAST)
140462306a36Sopenharmony_ci		i += scnprintf(&buf[i], REMAIN(i), " RX_MODE_F_BROADCAST");
140562306a36Sopenharmony_ci	if (rx_mode & IONIC_RX_MODE_F_PROMISC)
140662306a36Sopenharmony_ci		i += scnprintf(&buf[i], REMAIN(i), " RX_MODE_F_PROMISC");
140762306a36Sopenharmony_ci	if (rx_mode & IONIC_RX_MODE_F_ALLMULTI)
140862306a36Sopenharmony_ci		i += scnprintf(&buf[i], REMAIN(i), " RX_MODE_F_ALLMULTI");
140962306a36Sopenharmony_ci	if (rx_mode & IONIC_RX_MODE_F_RDMA_SNIFFER)
141062306a36Sopenharmony_ci		i += scnprintf(&buf[i], REMAIN(i), " RX_MODE_F_RDMA_SNIFFER");
141162306a36Sopenharmony_ci	netdev_dbg(netdev, "lif%d %s\n", lif->index, buf);
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_ci	if (lif->rx_mode != rx_mode) {
141462306a36Sopenharmony_ci		struct ionic_admin_ctx ctx = {
141562306a36Sopenharmony_ci			.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
141662306a36Sopenharmony_ci			.cmd.rx_mode_set = {
141762306a36Sopenharmony_ci				.opcode = IONIC_CMD_RX_MODE_SET,
141862306a36Sopenharmony_ci				.lif_index = cpu_to_le16(lif->index),
141962306a36Sopenharmony_ci			},
142062306a36Sopenharmony_ci		};
142162306a36Sopenharmony_ci		int err;
142262306a36Sopenharmony_ci
142362306a36Sopenharmony_ci		ctx.cmd.rx_mode_set.rx_mode = cpu_to_le16(rx_mode);
142462306a36Sopenharmony_ci		err = ionic_adminq_post_wait(lif, &ctx);
142562306a36Sopenharmony_ci		if (err)
142662306a36Sopenharmony_ci			netdev_warn(netdev, "set rx_mode 0x%04x failed: %d\n",
142762306a36Sopenharmony_ci				    rx_mode, err);
142862306a36Sopenharmony_ci		else
142962306a36Sopenharmony_ci			lif->rx_mode = rx_mode;
143062306a36Sopenharmony_ci	}
143162306a36Sopenharmony_ci
143262306a36Sopenharmony_ci	mutex_unlock(&lif->config_lock);
143362306a36Sopenharmony_ci}
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_cistatic void ionic_ndo_set_rx_mode(struct net_device *netdev)
143662306a36Sopenharmony_ci{
143762306a36Sopenharmony_ci	struct ionic_lif *lif = netdev_priv(netdev);
143862306a36Sopenharmony_ci	struct ionic_deferred_work *work;
143962306a36Sopenharmony_ci
144062306a36Sopenharmony_ci	/* Sync the kernel filter list with the driver filter list */
144162306a36Sopenharmony_ci	__dev_uc_sync(netdev, ionic_addr_add, ionic_addr_del);
144262306a36Sopenharmony_ci	__dev_mc_sync(netdev, ionic_addr_add, ionic_addr_del);
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci	/* Shove off the rest of the rxmode work to the work task
144562306a36Sopenharmony_ci	 * which will include syncing the filters to the firmware.
144662306a36Sopenharmony_ci	 */
144762306a36Sopenharmony_ci	work = kzalloc(sizeof(*work), GFP_ATOMIC);
144862306a36Sopenharmony_ci	if (!work) {
144962306a36Sopenharmony_ci		netdev_err(lif->netdev, "rxmode change dropped\n");
145062306a36Sopenharmony_ci		return;
145162306a36Sopenharmony_ci	}
145262306a36Sopenharmony_ci	work->type = IONIC_DW_TYPE_RX_MODE;
145362306a36Sopenharmony_ci	netdev_dbg(lif->netdev, "deferred: rx_mode\n");
145462306a36Sopenharmony_ci	ionic_lif_deferred_enqueue(&lif->deferred, work);
145562306a36Sopenharmony_ci}
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_cistatic __le64 ionic_netdev_features_to_nic(netdev_features_t features)
145862306a36Sopenharmony_ci{
145962306a36Sopenharmony_ci	u64 wanted = 0;
146062306a36Sopenharmony_ci
146162306a36Sopenharmony_ci	if (features & NETIF_F_HW_VLAN_CTAG_TX)
146262306a36Sopenharmony_ci		wanted |= IONIC_ETH_HW_VLAN_TX_TAG;
146362306a36Sopenharmony_ci	if (features & NETIF_F_HW_VLAN_CTAG_RX)
146462306a36Sopenharmony_ci		wanted |= IONIC_ETH_HW_VLAN_RX_STRIP;
146562306a36Sopenharmony_ci	if (features & NETIF_F_HW_VLAN_CTAG_FILTER)
146662306a36Sopenharmony_ci		wanted |= IONIC_ETH_HW_VLAN_RX_FILTER;
146762306a36Sopenharmony_ci	if (features & NETIF_F_RXHASH)
146862306a36Sopenharmony_ci		wanted |= IONIC_ETH_HW_RX_HASH;
146962306a36Sopenharmony_ci	if (features & NETIF_F_RXCSUM)
147062306a36Sopenharmony_ci		wanted |= IONIC_ETH_HW_RX_CSUM;
147162306a36Sopenharmony_ci	if (features & NETIF_F_SG)
147262306a36Sopenharmony_ci		wanted |= IONIC_ETH_HW_TX_SG;
147362306a36Sopenharmony_ci	if (features & NETIF_F_HW_CSUM)
147462306a36Sopenharmony_ci		wanted |= IONIC_ETH_HW_TX_CSUM;
147562306a36Sopenharmony_ci	if (features & NETIF_F_TSO)
147662306a36Sopenharmony_ci		wanted |= IONIC_ETH_HW_TSO;
147762306a36Sopenharmony_ci	if (features & NETIF_F_TSO6)
147862306a36Sopenharmony_ci		wanted |= IONIC_ETH_HW_TSO_IPV6;
147962306a36Sopenharmony_ci	if (features & NETIF_F_TSO_ECN)
148062306a36Sopenharmony_ci		wanted |= IONIC_ETH_HW_TSO_ECN;
148162306a36Sopenharmony_ci	if (features & NETIF_F_GSO_GRE)
148262306a36Sopenharmony_ci		wanted |= IONIC_ETH_HW_TSO_GRE;
148362306a36Sopenharmony_ci	if (features & NETIF_F_GSO_GRE_CSUM)
148462306a36Sopenharmony_ci		wanted |= IONIC_ETH_HW_TSO_GRE_CSUM;
148562306a36Sopenharmony_ci	if (features & NETIF_F_GSO_IPXIP4)
148662306a36Sopenharmony_ci		wanted |= IONIC_ETH_HW_TSO_IPXIP4;
148762306a36Sopenharmony_ci	if (features & NETIF_F_GSO_IPXIP6)
148862306a36Sopenharmony_ci		wanted |= IONIC_ETH_HW_TSO_IPXIP6;
148962306a36Sopenharmony_ci	if (features & NETIF_F_GSO_UDP_TUNNEL)
149062306a36Sopenharmony_ci		wanted |= IONIC_ETH_HW_TSO_UDP;
149162306a36Sopenharmony_ci	if (features & NETIF_F_GSO_UDP_TUNNEL_CSUM)
149262306a36Sopenharmony_ci		wanted |= IONIC_ETH_HW_TSO_UDP_CSUM;
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_ci	return cpu_to_le64(wanted);
149562306a36Sopenharmony_ci}
149662306a36Sopenharmony_ci
149762306a36Sopenharmony_cistatic int ionic_set_nic_features(struct ionic_lif *lif,
149862306a36Sopenharmony_ci				  netdev_features_t features)
149962306a36Sopenharmony_ci{
150062306a36Sopenharmony_ci	struct device *dev = lif->ionic->dev;
150162306a36Sopenharmony_ci	struct ionic_admin_ctx ctx = {
150262306a36Sopenharmony_ci		.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
150362306a36Sopenharmony_ci		.cmd.lif_setattr = {
150462306a36Sopenharmony_ci			.opcode = IONIC_CMD_LIF_SETATTR,
150562306a36Sopenharmony_ci			.index = cpu_to_le16(lif->index),
150662306a36Sopenharmony_ci			.attr = IONIC_LIF_ATTR_FEATURES,
150762306a36Sopenharmony_ci		},
150862306a36Sopenharmony_ci	};
150962306a36Sopenharmony_ci	u64 vlan_flags = IONIC_ETH_HW_VLAN_TX_TAG |
151062306a36Sopenharmony_ci			 IONIC_ETH_HW_VLAN_RX_STRIP |
151162306a36Sopenharmony_ci			 IONIC_ETH_HW_VLAN_RX_FILTER;
151262306a36Sopenharmony_ci	u64 old_hw_features;
151362306a36Sopenharmony_ci	int err;
151462306a36Sopenharmony_ci
151562306a36Sopenharmony_ci	ctx.cmd.lif_setattr.features = ionic_netdev_features_to_nic(features);
151662306a36Sopenharmony_ci
151762306a36Sopenharmony_ci	if (lif->phc)
151862306a36Sopenharmony_ci		ctx.cmd.lif_setattr.features |= cpu_to_le64(IONIC_ETH_HW_TIMESTAMP);
151962306a36Sopenharmony_ci
152062306a36Sopenharmony_ci	err = ionic_adminq_post_wait(lif, &ctx);
152162306a36Sopenharmony_ci	if (err)
152262306a36Sopenharmony_ci		return err;
152362306a36Sopenharmony_ci
152462306a36Sopenharmony_ci	old_hw_features = lif->hw_features;
152562306a36Sopenharmony_ci	lif->hw_features = le64_to_cpu(ctx.cmd.lif_setattr.features &
152662306a36Sopenharmony_ci				       ctx.comp.lif_setattr.features);
152762306a36Sopenharmony_ci
152862306a36Sopenharmony_ci	if ((old_hw_features ^ lif->hw_features) & IONIC_ETH_HW_RX_HASH)
152962306a36Sopenharmony_ci		ionic_lif_rss_config(lif, lif->rss_types, NULL, NULL);
153062306a36Sopenharmony_ci
153162306a36Sopenharmony_ci	if ((vlan_flags & le64_to_cpu(ctx.cmd.lif_setattr.features)) &&
153262306a36Sopenharmony_ci	    !(vlan_flags & le64_to_cpu(ctx.comp.lif_setattr.features)))
153362306a36Sopenharmony_ci		dev_info_once(lif->ionic->dev, "NIC is not supporting vlan offload, likely in SmartNIC mode\n");
153462306a36Sopenharmony_ci
153562306a36Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_VLAN_TX_TAG)
153662306a36Sopenharmony_ci		dev_dbg(dev, "feature ETH_HW_VLAN_TX_TAG\n");
153762306a36Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_VLAN_RX_STRIP)
153862306a36Sopenharmony_ci		dev_dbg(dev, "feature ETH_HW_VLAN_RX_STRIP\n");
153962306a36Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_VLAN_RX_FILTER)
154062306a36Sopenharmony_ci		dev_dbg(dev, "feature ETH_HW_VLAN_RX_FILTER\n");
154162306a36Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_RX_HASH)
154262306a36Sopenharmony_ci		dev_dbg(dev, "feature ETH_HW_RX_HASH\n");
154362306a36Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_TX_SG)
154462306a36Sopenharmony_ci		dev_dbg(dev, "feature ETH_HW_TX_SG\n");
154562306a36Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_TX_CSUM)
154662306a36Sopenharmony_ci		dev_dbg(dev, "feature ETH_HW_TX_CSUM\n");
154762306a36Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_RX_CSUM)
154862306a36Sopenharmony_ci		dev_dbg(dev, "feature ETH_HW_RX_CSUM\n");
154962306a36Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_TSO)
155062306a36Sopenharmony_ci		dev_dbg(dev, "feature ETH_HW_TSO\n");
155162306a36Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_TSO_IPV6)
155262306a36Sopenharmony_ci		dev_dbg(dev, "feature ETH_HW_TSO_IPV6\n");
155362306a36Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_TSO_ECN)
155462306a36Sopenharmony_ci		dev_dbg(dev, "feature ETH_HW_TSO_ECN\n");
155562306a36Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_TSO_GRE)
155662306a36Sopenharmony_ci		dev_dbg(dev, "feature ETH_HW_TSO_GRE\n");
155762306a36Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_TSO_GRE_CSUM)
155862306a36Sopenharmony_ci		dev_dbg(dev, "feature ETH_HW_TSO_GRE_CSUM\n");
155962306a36Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_TSO_IPXIP4)
156062306a36Sopenharmony_ci		dev_dbg(dev, "feature ETH_HW_TSO_IPXIP4\n");
156162306a36Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_TSO_IPXIP6)
156262306a36Sopenharmony_ci		dev_dbg(dev, "feature ETH_HW_TSO_IPXIP6\n");
156362306a36Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_TSO_UDP)
156462306a36Sopenharmony_ci		dev_dbg(dev, "feature ETH_HW_TSO_UDP\n");
156562306a36Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_TSO_UDP_CSUM)
156662306a36Sopenharmony_ci		dev_dbg(dev, "feature ETH_HW_TSO_UDP_CSUM\n");
156762306a36Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_TIMESTAMP)
156862306a36Sopenharmony_ci		dev_dbg(dev, "feature ETH_HW_TIMESTAMP\n");
156962306a36Sopenharmony_ci
157062306a36Sopenharmony_ci	return 0;
157162306a36Sopenharmony_ci}
157262306a36Sopenharmony_ci
157362306a36Sopenharmony_cistatic int ionic_init_nic_features(struct ionic_lif *lif)
157462306a36Sopenharmony_ci{
157562306a36Sopenharmony_ci	struct net_device *netdev = lif->netdev;
157662306a36Sopenharmony_ci	netdev_features_t features;
157762306a36Sopenharmony_ci	int err;
157862306a36Sopenharmony_ci
157962306a36Sopenharmony_ci	/* set up what we expect to support by default */
158062306a36Sopenharmony_ci	features = NETIF_F_HW_VLAN_CTAG_TX |
158162306a36Sopenharmony_ci		   NETIF_F_HW_VLAN_CTAG_RX |
158262306a36Sopenharmony_ci		   NETIF_F_HW_VLAN_CTAG_FILTER |
158362306a36Sopenharmony_ci		   NETIF_F_SG |
158462306a36Sopenharmony_ci		   NETIF_F_HW_CSUM |
158562306a36Sopenharmony_ci		   NETIF_F_RXCSUM |
158662306a36Sopenharmony_ci		   NETIF_F_TSO |
158762306a36Sopenharmony_ci		   NETIF_F_TSO6 |
158862306a36Sopenharmony_ci		   NETIF_F_TSO_ECN |
158962306a36Sopenharmony_ci		   NETIF_F_GSO_GRE |
159062306a36Sopenharmony_ci		   NETIF_F_GSO_GRE_CSUM |
159162306a36Sopenharmony_ci		   NETIF_F_GSO_IPXIP4 |
159262306a36Sopenharmony_ci		   NETIF_F_GSO_IPXIP6 |
159362306a36Sopenharmony_ci		   NETIF_F_GSO_UDP_TUNNEL |
159462306a36Sopenharmony_ci		   NETIF_F_GSO_UDP_TUNNEL_CSUM;
159562306a36Sopenharmony_ci
159662306a36Sopenharmony_ci	if (lif->nxqs > 1)
159762306a36Sopenharmony_ci		features |= NETIF_F_RXHASH;
159862306a36Sopenharmony_ci
159962306a36Sopenharmony_ci	err = ionic_set_nic_features(lif, features);
160062306a36Sopenharmony_ci	if (err)
160162306a36Sopenharmony_ci		return err;
160262306a36Sopenharmony_ci
160362306a36Sopenharmony_ci	/* tell the netdev what we actually can support */
160462306a36Sopenharmony_ci	netdev->features |= NETIF_F_HIGHDMA;
160562306a36Sopenharmony_ci
160662306a36Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_VLAN_TX_TAG)
160762306a36Sopenharmony_ci		netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_TX;
160862306a36Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_VLAN_RX_STRIP)
160962306a36Sopenharmony_ci		netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_RX;
161062306a36Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_VLAN_RX_FILTER)
161162306a36Sopenharmony_ci		netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER;
161262306a36Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_RX_HASH)
161362306a36Sopenharmony_ci		netdev->hw_features |= NETIF_F_RXHASH;
161462306a36Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_TX_SG)
161562306a36Sopenharmony_ci		netdev->hw_features |= NETIF_F_SG;
161662306a36Sopenharmony_ci
161762306a36Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_TX_CSUM)
161862306a36Sopenharmony_ci		netdev->hw_enc_features |= NETIF_F_HW_CSUM;
161962306a36Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_RX_CSUM)
162062306a36Sopenharmony_ci		netdev->hw_enc_features |= NETIF_F_RXCSUM;
162162306a36Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_TSO)
162262306a36Sopenharmony_ci		netdev->hw_enc_features |= NETIF_F_TSO;
162362306a36Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_TSO_IPV6)
162462306a36Sopenharmony_ci		netdev->hw_enc_features |= NETIF_F_TSO6;
162562306a36Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_TSO_ECN)
162662306a36Sopenharmony_ci		netdev->hw_enc_features |= NETIF_F_TSO_ECN;
162762306a36Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_TSO_GRE)
162862306a36Sopenharmony_ci		netdev->hw_enc_features |= NETIF_F_GSO_GRE;
162962306a36Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_TSO_GRE_CSUM)
163062306a36Sopenharmony_ci		netdev->hw_enc_features |= NETIF_F_GSO_GRE_CSUM;
163162306a36Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_TSO_IPXIP4)
163262306a36Sopenharmony_ci		netdev->hw_enc_features |= NETIF_F_GSO_IPXIP4;
163362306a36Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_TSO_IPXIP6)
163462306a36Sopenharmony_ci		netdev->hw_enc_features |= NETIF_F_GSO_IPXIP6;
163562306a36Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_TSO_UDP)
163662306a36Sopenharmony_ci		netdev->hw_enc_features |= NETIF_F_GSO_UDP_TUNNEL;
163762306a36Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_TSO_UDP_CSUM)
163862306a36Sopenharmony_ci		netdev->hw_enc_features |= NETIF_F_GSO_UDP_TUNNEL_CSUM;
163962306a36Sopenharmony_ci
164062306a36Sopenharmony_ci	netdev->hw_features |= netdev->hw_enc_features;
164162306a36Sopenharmony_ci	netdev->features |= netdev->hw_features;
164262306a36Sopenharmony_ci	netdev->vlan_features |= netdev->features & ~NETIF_F_VLAN_FEATURES;
164362306a36Sopenharmony_ci
164462306a36Sopenharmony_ci	netdev->priv_flags |= IFF_UNICAST_FLT |
164562306a36Sopenharmony_ci			      IFF_LIVE_ADDR_CHANGE;
164662306a36Sopenharmony_ci
164762306a36Sopenharmony_ci	return 0;
164862306a36Sopenharmony_ci}
164962306a36Sopenharmony_ci
165062306a36Sopenharmony_cistatic int ionic_set_features(struct net_device *netdev,
165162306a36Sopenharmony_ci			      netdev_features_t features)
165262306a36Sopenharmony_ci{
165362306a36Sopenharmony_ci	struct ionic_lif *lif = netdev_priv(netdev);
165462306a36Sopenharmony_ci	int err;
165562306a36Sopenharmony_ci
165662306a36Sopenharmony_ci	netdev_dbg(netdev, "%s: lif->features=0x%08llx new_features=0x%08llx\n",
165762306a36Sopenharmony_ci		   __func__, (u64)lif->netdev->features, (u64)features);
165862306a36Sopenharmony_ci
165962306a36Sopenharmony_ci	err = ionic_set_nic_features(lif, features);
166062306a36Sopenharmony_ci
166162306a36Sopenharmony_ci	return err;
166262306a36Sopenharmony_ci}
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_cistatic int ionic_set_attr_mac(struct ionic_lif *lif, u8 *mac)
166562306a36Sopenharmony_ci{
166662306a36Sopenharmony_ci	struct ionic_admin_ctx ctx = {
166762306a36Sopenharmony_ci		.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
166862306a36Sopenharmony_ci		.cmd.lif_setattr = {
166962306a36Sopenharmony_ci			.opcode = IONIC_CMD_LIF_SETATTR,
167062306a36Sopenharmony_ci			.index = cpu_to_le16(lif->index),
167162306a36Sopenharmony_ci			.attr = IONIC_LIF_ATTR_MAC,
167262306a36Sopenharmony_ci		},
167362306a36Sopenharmony_ci	};
167462306a36Sopenharmony_ci
167562306a36Sopenharmony_ci	ether_addr_copy(ctx.cmd.lif_setattr.mac, mac);
167662306a36Sopenharmony_ci	return ionic_adminq_post_wait(lif, &ctx);
167762306a36Sopenharmony_ci}
167862306a36Sopenharmony_ci
167962306a36Sopenharmony_cistatic int ionic_get_attr_mac(struct ionic_lif *lif, u8 *mac_addr)
168062306a36Sopenharmony_ci{
168162306a36Sopenharmony_ci	struct ionic_admin_ctx ctx = {
168262306a36Sopenharmony_ci		.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
168362306a36Sopenharmony_ci		.cmd.lif_getattr = {
168462306a36Sopenharmony_ci			.opcode = IONIC_CMD_LIF_GETATTR,
168562306a36Sopenharmony_ci			.index = cpu_to_le16(lif->index),
168662306a36Sopenharmony_ci			.attr = IONIC_LIF_ATTR_MAC,
168762306a36Sopenharmony_ci		},
168862306a36Sopenharmony_ci	};
168962306a36Sopenharmony_ci	int err;
169062306a36Sopenharmony_ci
169162306a36Sopenharmony_ci	err = ionic_adminq_post_wait(lif, &ctx);
169262306a36Sopenharmony_ci	if (err)
169362306a36Sopenharmony_ci		return err;
169462306a36Sopenharmony_ci
169562306a36Sopenharmony_ci	ether_addr_copy(mac_addr, ctx.comp.lif_getattr.mac);
169662306a36Sopenharmony_ci	return 0;
169762306a36Sopenharmony_ci}
169862306a36Sopenharmony_ci
169962306a36Sopenharmony_cistatic int ionic_program_mac(struct ionic_lif *lif, u8 *mac)
170062306a36Sopenharmony_ci{
170162306a36Sopenharmony_ci	u8  get_mac[ETH_ALEN];
170262306a36Sopenharmony_ci	int err;
170362306a36Sopenharmony_ci
170462306a36Sopenharmony_ci	err = ionic_set_attr_mac(lif, mac);
170562306a36Sopenharmony_ci	if (err)
170662306a36Sopenharmony_ci		return err;
170762306a36Sopenharmony_ci
170862306a36Sopenharmony_ci	err = ionic_get_attr_mac(lif, get_mac);
170962306a36Sopenharmony_ci	if (err)
171062306a36Sopenharmony_ci		return err;
171162306a36Sopenharmony_ci
171262306a36Sopenharmony_ci	/* To deal with older firmware that silently ignores the set attr mac:
171362306a36Sopenharmony_ci	 * doesn't actually change the mac and doesn't return an error, so we
171462306a36Sopenharmony_ci	 * do the get attr to verify whether or not the set actually happened
171562306a36Sopenharmony_ci	 */
171662306a36Sopenharmony_ci	if (!ether_addr_equal(get_mac, mac))
171762306a36Sopenharmony_ci		return 1;
171862306a36Sopenharmony_ci
171962306a36Sopenharmony_ci	return 0;
172062306a36Sopenharmony_ci}
172162306a36Sopenharmony_ci
172262306a36Sopenharmony_cistatic int ionic_set_mac_address(struct net_device *netdev, void *sa)
172362306a36Sopenharmony_ci{
172462306a36Sopenharmony_ci	struct ionic_lif *lif = netdev_priv(netdev);
172562306a36Sopenharmony_ci	struct sockaddr *addr = sa;
172662306a36Sopenharmony_ci	u8 *mac;
172762306a36Sopenharmony_ci	int err;
172862306a36Sopenharmony_ci
172962306a36Sopenharmony_ci	mac = (u8 *)addr->sa_data;
173062306a36Sopenharmony_ci	if (ether_addr_equal(netdev->dev_addr, mac))
173162306a36Sopenharmony_ci		return 0;
173262306a36Sopenharmony_ci
173362306a36Sopenharmony_ci	err = ionic_program_mac(lif, mac);
173462306a36Sopenharmony_ci	if (err < 0)
173562306a36Sopenharmony_ci		return err;
173662306a36Sopenharmony_ci
173762306a36Sopenharmony_ci	if (err > 0)
173862306a36Sopenharmony_ci		netdev_dbg(netdev, "%s: SET and GET ATTR Mac are not equal-due to old FW running\n",
173962306a36Sopenharmony_ci			   __func__);
174062306a36Sopenharmony_ci
174162306a36Sopenharmony_ci	err = eth_prepare_mac_addr_change(netdev, addr);
174262306a36Sopenharmony_ci	if (err)
174362306a36Sopenharmony_ci		return err;
174462306a36Sopenharmony_ci
174562306a36Sopenharmony_ci	if (!is_zero_ether_addr(netdev->dev_addr)) {
174662306a36Sopenharmony_ci		netdev_info(netdev, "deleting mac addr %pM\n",
174762306a36Sopenharmony_ci			    netdev->dev_addr);
174862306a36Sopenharmony_ci		ionic_lif_addr_del(netdev_priv(netdev), netdev->dev_addr);
174962306a36Sopenharmony_ci	}
175062306a36Sopenharmony_ci
175162306a36Sopenharmony_ci	eth_commit_mac_addr_change(netdev, addr);
175262306a36Sopenharmony_ci	netdev_info(netdev, "updating mac addr %pM\n", mac);
175362306a36Sopenharmony_ci
175462306a36Sopenharmony_ci	return ionic_lif_addr_add(netdev_priv(netdev), mac);
175562306a36Sopenharmony_ci}
175662306a36Sopenharmony_ci
175762306a36Sopenharmony_civoid ionic_stop_queues_reconfig(struct ionic_lif *lif)
175862306a36Sopenharmony_ci{
175962306a36Sopenharmony_ci	/* Stop and clean the queues before reconfiguration */
176062306a36Sopenharmony_ci	netif_device_detach(lif->netdev);
176162306a36Sopenharmony_ci	ionic_stop_queues(lif);
176262306a36Sopenharmony_ci	ionic_txrx_deinit(lif);
176362306a36Sopenharmony_ci}
176462306a36Sopenharmony_ci
176562306a36Sopenharmony_cistatic int ionic_start_queues_reconfig(struct ionic_lif *lif)
176662306a36Sopenharmony_ci{
176762306a36Sopenharmony_ci	int err;
176862306a36Sopenharmony_ci
176962306a36Sopenharmony_ci	/* Re-init the queues after reconfiguration */
177062306a36Sopenharmony_ci
177162306a36Sopenharmony_ci	/* The only way txrx_init can fail here is if communication
177262306a36Sopenharmony_ci	 * with FW is suddenly broken.  There's not much we can do
177362306a36Sopenharmony_ci	 * at this point - error messages have already been printed,
177462306a36Sopenharmony_ci	 * so we can continue on and the user can eventually do a
177562306a36Sopenharmony_ci	 * DOWN and UP to try to reset and clear the issue.
177662306a36Sopenharmony_ci	 */
177762306a36Sopenharmony_ci	err = ionic_txrx_init(lif);
177862306a36Sopenharmony_ci	ionic_link_status_check_request(lif, CAN_NOT_SLEEP);
177962306a36Sopenharmony_ci	netif_device_attach(lif->netdev);
178062306a36Sopenharmony_ci
178162306a36Sopenharmony_ci	return err;
178262306a36Sopenharmony_ci}
178362306a36Sopenharmony_ci
178462306a36Sopenharmony_cistatic int ionic_change_mtu(struct net_device *netdev, int new_mtu)
178562306a36Sopenharmony_ci{
178662306a36Sopenharmony_ci	struct ionic_lif *lif = netdev_priv(netdev);
178762306a36Sopenharmony_ci	struct ionic_admin_ctx ctx = {
178862306a36Sopenharmony_ci		.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
178962306a36Sopenharmony_ci		.cmd.lif_setattr = {
179062306a36Sopenharmony_ci			.opcode = IONIC_CMD_LIF_SETATTR,
179162306a36Sopenharmony_ci			.index = cpu_to_le16(lif->index),
179262306a36Sopenharmony_ci			.attr = IONIC_LIF_ATTR_MTU,
179362306a36Sopenharmony_ci			.mtu = cpu_to_le32(new_mtu),
179462306a36Sopenharmony_ci		},
179562306a36Sopenharmony_ci	};
179662306a36Sopenharmony_ci	int err;
179762306a36Sopenharmony_ci
179862306a36Sopenharmony_ci	err = ionic_adminq_post_wait(lif, &ctx);
179962306a36Sopenharmony_ci	if (err)
180062306a36Sopenharmony_ci		return err;
180162306a36Sopenharmony_ci
180262306a36Sopenharmony_ci	/* if we're not running, nothing more to do */
180362306a36Sopenharmony_ci	if (!netif_running(netdev)) {
180462306a36Sopenharmony_ci		netdev->mtu = new_mtu;
180562306a36Sopenharmony_ci		return 0;
180662306a36Sopenharmony_ci	}
180762306a36Sopenharmony_ci
180862306a36Sopenharmony_ci	mutex_lock(&lif->queue_lock);
180962306a36Sopenharmony_ci	ionic_stop_queues_reconfig(lif);
181062306a36Sopenharmony_ci	netdev->mtu = new_mtu;
181162306a36Sopenharmony_ci	err = ionic_start_queues_reconfig(lif);
181262306a36Sopenharmony_ci	mutex_unlock(&lif->queue_lock);
181362306a36Sopenharmony_ci
181462306a36Sopenharmony_ci	return err;
181562306a36Sopenharmony_ci}
181662306a36Sopenharmony_ci
181762306a36Sopenharmony_cistatic void ionic_tx_timeout_work(struct work_struct *ws)
181862306a36Sopenharmony_ci{
181962306a36Sopenharmony_ci	struct ionic_lif *lif = container_of(ws, struct ionic_lif, tx_timeout_work);
182062306a36Sopenharmony_ci	int err;
182162306a36Sopenharmony_ci
182262306a36Sopenharmony_ci	if (test_bit(IONIC_LIF_F_FW_RESET, lif->state))
182362306a36Sopenharmony_ci		return;
182462306a36Sopenharmony_ci
182562306a36Sopenharmony_ci	/* if we were stopped before this scheduled job was launched,
182662306a36Sopenharmony_ci	 * don't bother the queues as they are already stopped.
182762306a36Sopenharmony_ci	 */
182862306a36Sopenharmony_ci	if (!netif_running(lif->netdev))
182962306a36Sopenharmony_ci		return;
183062306a36Sopenharmony_ci
183162306a36Sopenharmony_ci	mutex_lock(&lif->queue_lock);
183262306a36Sopenharmony_ci	ionic_stop_queues_reconfig(lif);
183362306a36Sopenharmony_ci	err = ionic_start_queues_reconfig(lif);
183462306a36Sopenharmony_ci	mutex_unlock(&lif->queue_lock);
183562306a36Sopenharmony_ci
183662306a36Sopenharmony_ci	if (err)
183762306a36Sopenharmony_ci		dev_err(lif->ionic->dev, "%s: Restarting queues failed\n", __func__);
183862306a36Sopenharmony_ci}
183962306a36Sopenharmony_ci
184062306a36Sopenharmony_cistatic void ionic_tx_timeout(struct net_device *netdev, unsigned int txqueue)
184162306a36Sopenharmony_ci{
184262306a36Sopenharmony_ci	struct ionic_lif *lif = netdev_priv(netdev);
184362306a36Sopenharmony_ci
184462306a36Sopenharmony_ci	netdev_info(lif->netdev, "Tx Timeout triggered - txq %d\n", txqueue);
184562306a36Sopenharmony_ci	schedule_work(&lif->tx_timeout_work);
184662306a36Sopenharmony_ci}
184762306a36Sopenharmony_ci
184862306a36Sopenharmony_cistatic int ionic_vlan_rx_add_vid(struct net_device *netdev, __be16 proto,
184962306a36Sopenharmony_ci				 u16 vid)
185062306a36Sopenharmony_ci{
185162306a36Sopenharmony_ci	struct ionic_lif *lif = netdev_priv(netdev);
185262306a36Sopenharmony_ci	int err;
185362306a36Sopenharmony_ci
185462306a36Sopenharmony_ci	err = ionic_lif_vlan_add(lif, vid);
185562306a36Sopenharmony_ci	if (err)
185662306a36Sopenharmony_ci		return err;
185762306a36Sopenharmony_ci
185862306a36Sopenharmony_ci	ionic_lif_rx_mode(lif);
185962306a36Sopenharmony_ci
186062306a36Sopenharmony_ci	return 0;
186162306a36Sopenharmony_ci}
186262306a36Sopenharmony_ci
186362306a36Sopenharmony_cistatic int ionic_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto,
186462306a36Sopenharmony_ci				  u16 vid)
186562306a36Sopenharmony_ci{
186662306a36Sopenharmony_ci	struct ionic_lif *lif = netdev_priv(netdev);
186762306a36Sopenharmony_ci	int err;
186862306a36Sopenharmony_ci
186962306a36Sopenharmony_ci	err = ionic_lif_vlan_del(lif, vid);
187062306a36Sopenharmony_ci	if (err)
187162306a36Sopenharmony_ci		return err;
187262306a36Sopenharmony_ci
187362306a36Sopenharmony_ci	ionic_lif_rx_mode(lif);
187462306a36Sopenharmony_ci
187562306a36Sopenharmony_ci	return 0;
187662306a36Sopenharmony_ci}
187762306a36Sopenharmony_ci
187862306a36Sopenharmony_ciint ionic_lif_rss_config(struct ionic_lif *lif, const u16 types,
187962306a36Sopenharmony_ci			 const u8 *key, const u32 *indir)
188062306a36Sopenharmony_ci{
188162306a36Sopenharmony_ci	struct ionic_admin_ctx ctx = {
188262306a36Sopenharmony_ci		.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
188362306a36Sopenharmony_ci		.cmd.lif_setattr = {
188462306a36Sopenharmony_ci			.opcode = IONIC_CMD_LIF_SETATTR,
188562306a36Sopenharmony_ci			.attr = IONIC_LIF_ATTR_RSS,
188662306a36Sopenharmony_ci			.rss.addr = cpu_to_le64(lif->rss_ind_tbl_pa),
188762306a36Sopenharmony_ci		},
188862306a36Sopenharmony_ci	};
188962306a36Sopenharmony_ci	unsigned int i, tbl_sz;
189062306a36Sopenharmony_ci
189162306a36Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_RX_HASH) {
189262306a36Sopenharmony_ci		lif->rss_types = types;
189362306a36Sopenharmony_ci		ctx.cmd.lif_setattr.rss.types = cpu_to_le16(types);
189462306a36Sopenharmony_ci	}
189562306a36Sopenharmony_ci
189662306a36Sopenharmony_ci	if (key)
189762306a36Sopenharmony_ci		memcpy(lif->rss_hash_key, key, IONIC_RSS_HASH_KEY_SIZE);
189862306a36Sopenharmony_ci
189962306a36Sopenharmony_ci	if (indir) {
190062306a36Sopenharmony_ci		tbl_sz = le16_to_cpu(lif->ionic->ident.lif.eth.rss_ind_tbl_sz);
190162306a36Sopenharmony_ci		for (i = 0; i < tbl_sz; i++)
190262306a36Sopenharmony_ci			lif->rss_ind_tbl[i] = indir[i];
190362306a36Sopenharmony_ci	}
190462306a36Sopenharmony_ci
190562306a36Sopenharmony_ci	memcpy(ctx.cmd.lif_setattr.rss.key, lif->rss_hash_key,
190662306a36Sopenharmony_ci	       IONIC_RSS_HASH_KEY_SIZE);
190762306a36Sopenharmony_ci
190862306a36Sopenharmony_ci	return ionic_adminq_post_wait(lif, &ctx);
190962306a36Sopenharmony_ci}
191062306a36Sopenharmony_ci
191162306a36Sopenharmony_cistatic int ionic_lif_rss_init(struct ionic_lif *lif)
191262306a36Sopenharmony_ci{
191362306a36Sopenharmony_ci	unsigned int tbl_sz;
191462306a36Sopenharmony_ci	unsigned int i;
191562306a36Sopenharmony_ci
191662306a36Sopenharmony_ci	lif->rss_types = IONIC_RSS_TYPE_IPV4     |
191762306a36Sopenharmony_ci			 IONIC_RSS_TYPE_IPV4_TCP |
191862306a36Sopenharmony_ci			 IONIC_RSS_TYPE_IPV4_UDP |
191962306a36Sopenharmony_ci			 IONIC_RSS_TYPE_IPV6     |
192062306a36Sopenharmony_ci			 IONIC_RSS_TYPE_IPV6_TCP |
192162306a36Sopenharmony_ci			 IONIC_RSS_TYPE_IPV6_UDP;
192262306a36Sopenharmony_ci
192362306a36Sopenharmony_ci	/* Fill indirection table with 'default' values */
192462306a36Sopenharmony_ci	tbl_sz = le16_to_cpu(lif->ionic->ident.lif.eth.rss_ind_tbl_sz);
192562306a36Sopenharmony_ci	for (i = 0; i < tbl_sz; i++)
192662306a36Sopenharmony_ci		lif->rss_ind_tbl[i] = ethtool_rxfh_indir_default(i, lif->nxqs);
192762306a36Sopenharmony_ci
192862306a36Sopenharmony_ci	return ionic_lif_rss_config(lif, lif->rss_types, NULL, NULL);
192962306a36Sopenharmony_ci}
193062306a36Sopenharmony_ci
193162306a36Sopenharmony_cistatic void ionic_lif_rss_deinit(struct ionic_lif *lif)
193262306a36Sopenharmony_ci{
193362306a36Sopenharmony_ci	int tbl_sz;
193462306a36Sopenharmony_ci
193562306a36Sopenharmony_ci	tbl_sz = le16_to_cpu(lif->ionic->ident.lif.eth.rss_ind_tbl_sz);
193662306a36Sopenharmony_ci	memset(lif->rss_ind_tbl, 0, tbl_sz);
193762306a36Sopenharmony_ci	memset(lif->rss_hash_key, 0, IONIC_RSS_HASH_KEY_SIZE);
193862306a36Sopenharmony_ci
193962306a36Sopenharmony_ci	ionic_lif_rss_config(lif, 0x0, NULL, NULL);
194062306a36Sopenharmony_ci}
194162306a36Sopenharmony_ci
194262306a36Sopenharmony_cistatic void ionic_lif_quiesce(struct ionic_lif *lif)
194362306a36Sopenharmony_ci{
194462306a36Sopenharmony_ci	struct ionic_admin_ctx ctx = {
194562306a36Sopenharmony_ci		.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
194662306a36Sopenharmony_ci		.cmd.lif_setattr = {
194762306a36Sopenharmony_ci			.opcode = IONIC_CMD_LIF_SETATTR,
194862306a36Sopenharmony_ci			.index = cpu_to_le16(lif->index),
194962306a36Sopenharmony_ci			.attr = IONIC_LIF_ATTR_STATE,
195062306a36Sopenharmony_ci			.state = IONIC_LIF_QUIESCE,
195162306a36Sopenharmony_ci		},
195262306a36Sopenharmony_ci	};
195362306a36Sopenharmony_ci	int err;
195462306a36Sopenharmony_ci
195562306a36Sopenharmony_ci	err = ionic_adminq_post_wait(lif, &ctx);
195662306a36Sopenharmony_ci	if (err)
195762306a36Sopenharmony_ci		netdev_dbg(lif->netdev, "lif quiesce failed %d\n", err);
195862306a36Sopenharmony_ci}
195962306a36Sopenharmony_ci
196062306a36Sopenharmony_cistatic void ionic_txrx_disable(struct ionic_lif *lif)
196162306a36Sopenharmony_ci{
196262306a36Sopenharmony_ci	unsigned int i;
196362306a36Sopenharmony_ci	int err = 0;
196462306a36Sopenharmony_ci
196562306a36Sopenharmony_ci	if (lif->txqcqs) {
196662306a36Sopenharmony_ci		for (i = 0; i < lif->nxqs; i++)
196762306a36Sopenharmony_ci			err = ionic_qcq_disable(lif, lif->txqcqs[i], err);
196862306a36Sopenharmony_ci	}
196962306a36Sopenharmony_ci
197062306a36Sopenharmony_ci	if (lif->hwstamp_txq)
197162306a36Sopenharmony_ci		err = ionic_qcq_disable(lif, lif->hwstamp_txq, err);
197262306a36Sopenharmony_ci
197362306a36Sopenharmony_ci	if (lif->rxqcqs) {
197462306a36Sopenharmony_ci		for (i = 0; i < lif->nxqs; i++)
197562306a36Sopenharmony_ci			err = ionic_qcq_disable(lif, lif->rxqcqs[i], err);
197662306a36Sopenharmony_ci	}
197762306a36Sopenharmony_ci
197862306a36Sopenharmony_ci	if (lif->hwstamp_rxq)
197962306a36Sopenharmony_ci		err = ionic_qcq_disable(lif, lif->hwstamp_rxq, err);
198062306a36Sopenharmony_ci
198162306a36Sopenharmony_ci	ionic_lif_quiesce(lif);
198262306a36Sopenharmony_ci}
198362306a36Sopenharmony_ci
198462306a36Sopenharmony_cistatic void ionic_txrx_deinit(struct ionic_lif *lif)
198562306a36Sopenharmony_ci{
198662306a36Sopenharmony_ci	unsigned int i;
198762306a36Sopenharmony_ci
198862306a36Sopenharmony_ci	if (lif->txqcqs) {
198962306a36Sopenharmony_ci		for (i = 0; i < lif->nxqs && lif->txqcqs[i]; i++) {
199062306a36Sopenharmony_ci			ionic_lif_qcq_deinit(lif, lif->txqcqs[i]);
199162306a36Sopenharmony_ci			ionic_tx_flush(&lif->txqcqs[i]->cq);
199262306a36Sopenharmony_ci			ionic_tx_empty(&lif->txqcqs[i]->q);
199362306a36Sopenharmony_ci		}
199462306a36Sopenharmony_ci	}
199562306a36Sopenharmony_ci
199662306a36Sopenharmony_ci	if (lif->rxqcqs) {
199762306a36Sopenharmony_ci		for (i = 0; i < lif->nxqs && lif->rxqcqs[i]; i++) {
199862306a36Sopenharmony_ci			ionic_lif_qcq_deinit(lif, lif->rxqcqs[i]);
199962306a36Sopenharmony_ci			ionic_rx_empty(&lif->rxqcqs[i]->q);
200062306a36Sopenharmony_ci		}
200162306a36Sopenharmony_ci	}
200262306a36Sopenharmony_ci	lif->rx_mode = 0;
200362306a36Sopenharmony_ci
200462306a36Sopenharmony_ci	if (lif->hwstamp_txq) {
200562306a36Sopenharmony_ci		ionic_lif_qcq_deinit(lif, lif->hwstamp_txq);
200662306a36Sopenharmony_ci		ionic_tx_flush(&lif->hwstamp_txq->cq);
200762306a36Sopenharmony_ci		ionic_tx_empty(&lif->hwstamp_txq->q);
200862306a36Sopenharmony_ci	}
200962306a36Sopenharmony_ci
201062306a36Sopenharmony_ci	if (lif->hwstamp_rxq) {
201162306a36Sopenharmony_ci		ionic_lif_qcq_deinit(lif, lif->hwstamp_rxq);
201262306a36Sopenharmony_ci		ionic_rx_empty(&lif->hwstamp_rxq->q);
201362306a36Sopenharmony_ci	}
201462306a36Sopenharmony_ci}
201562306a36Sopenharmony_ci
201662306a36Sopenharmony_civoid ionic_txrx_free(struct ionic_lif *lif)
201762306a36Sopenharmony_ci{
201862306a36Sopenharmony_ci	unsigned int i;
201962306a36Sopenharmony_ci
202062306a36Sopenharmony_ci	if (lif->txqcqs) {
202162306a36Sopenharmony_ci		for (i = 0; i < lif->ionic->ntxqs_per_lif && lif->txqcqs[i]; i++) {
202262306a36Sopenharmony_ci			ionic_qcq_free(lif, lif->txqcqs[i]);
202362306a36Sopenharmony_ci			devm_kfree(lif->ionic->dev, lif->txqcqs[i]);
202462306a36Sopenharmony_ci			lif->txqcqs[i] = NULL;
202562306a36Sopenharmony_ci		}
202662306a36Sopenharmony_ci	}
202762306a36Sopenharmony_ci
202862306a36Sopenharmony_ci	if (lif->rxqcqs) {
202962306a36Sopenharmony_ci		for (i = 0; i < lif->ionic->nrxqs_per_lif && lif->rxqcqs[i]; i++) {
203062306a36Sopenharmony_ci			ionic_qcq_free(lif, lif->rxqcqs[i]);
203162306a36Sopenharmony_ci			devm_kfree(lif->ionic->dev, lif->rxqcqs[i]);
203262306a36Sopenharmony_ci			lif->rxqcqs[i] = NULL;
203362306a36Sopenharmony_ci		}
203462306a36Sopenharmony_ci	}
203562306a36Sopenharmony_ci
203662306a36Sopenharmony_ci	if (lif->hwstamp_txq) {
203762306a36Sopenharmony_ci		ionic_qcq_free(lif, lif->hwstamp_txq);
203862306a36Sopenharmony_ci		devm_kfree(lif->ionic->dev, lif->hwstamp_txq);
203962306a36Sopenharmony_ci		lif->hwstamp_txq = NULL;
204062306a36Sopenharmony_ci	}
204162306a36Sopenharmony_ci
204262306a36Sopenharmony_ci	if (lif->hwstamp_rxq) {
204362306a36Sopenharmony_ci		ionic_qcq_free(lif, lif->hwstamp_rxq);
204462306a36Sopenharmony_ci		devm_kfree(lif->ionic->dev, lif->hwstamp_rxq);
204562306a36Sopenharmony_ci		lif->hwstamp_rxq = NULL;
204662306a36Sopenharmony_ci	}
204762306a36Sopenharmony_ci}
204862306a36Sopenharmony_ci
204962306a36Sopenharmony_cistatic int ionic_txrx_alloc(struct ionic_lif *lif)
205062306a36Sopenharmony_ci{
205162306a36Sopenharmony_ci	unsigned int comp_sz, desc_sz, num_desc, sg_desc_sz;
205262306a36Sopenharmony_ci	unsigned int flags, i;
205362306a36Sopenharmony_ci	int err = 0;
205462306a36Sopenharmony_ci
205562306a36Sopenharmony_ci	num_desc = lif->ntxq_descs;
205662306a36Sopenharmony_ci	desc_sz = sizeof(struct ionic_txq_desc);
205762306a36Sopenharmony_ci	comp_sz = sizeof(struct ionic_txq_comp);
205862306a36Sopenharmony_ci
205962306a36Sopenharmony_ci	if (lif->qtype_info[IONIC_QTYPE_TXQ].version >= 1 &&
206062306a36Sopenharmony_ci	    lif->qtype_info[IONIC_QTYPE_TXQ].sg_desc_sz ==
206162306a36Sopenharmony_ci					  sizeof(struct ionic_txq_sg_desc_v1))
206262306a36Sopenharmony_ci		sg_desc_sz = sizeof(struct ionic_txq_sg_desc_v1);
206362306a36Sopenharmony_ci	else
206462306a36Sopenharmony_ci		sg_desc_sz = sizeof(struct ionic_txq_sg_desc);
206562306a36Sopenharmony_ci
206662306a36Sopenharmony_ci	flags = IONIC_QCQ_F_TX_STATS | IONIC_QCQ_F_SG;
206762306a36Sopenharmony_ci
206862306a36Sopenharmony_ci	if (test_bit(IONIC_LIF_F_CMB_TX_RINGS, lif->state))
206962306a36Sopenharmony_ci		flags |= IONIC_QCQ_F_CMB_RINGS;
207062306a36Sopenharmony_ci
207162306a36Sopenharmony_ci	if (test_bit(IONIC_LIF_F_SPLIT_INTR, lif->state))
207262306a36Sopenharmony_ci		flags |= IONIC_QCQ_F_INTR;
207362306a36Sopenharmony_ci
207462306a36Sopenharmony_ci	for (i = 0; i < lif->nxqs; i++) {
207562306a36Sopenharmony_ci		err = ionic_qcq_alloc(lif, IONIC_QTYPE_TXQ, i, "tx", flags,
207662306a36Sopenharmony_ci				      num_desc, desc_sz, comp_sz, sg_desc_sz,
207762306a36Sopenharmony_ci				      lif->kern_pid, &lif->txqcqs[i]);
207862306a36Sopenharmony_ci		if (err)
207962306a36Sopenharmony_ci			goto err_out;
208062306a36Sopenharmony_ci
208162306a36Sopenharmony_ci		if (flags & IONIC_QCQ_F_INTR) {
208262306a36Sopenharmony_ci			ionic_intr_coal_init(lif->ionic->idev.intr_ctrl,
208362306a36Sopenharmony_ci					     lif->txqcqs[i]->intr.index,
208462306a36Sopenharmony_ci					     lif->tx_coalesce_hw);
208562306a36Sopenharmony_ci			if (test_bit(IONIC_LIF_F_TX_DIM_INTR, lif->state))
208662306a36Sopenharmony_ci				lif->txqcqs[i]->intr.dim_coal_hw = lif->tx_coalesce_hw;
208762306a36Sopenharmony_ci		}
208862306a36Sopenharmony_ci
208962306a36Sopenharmony_ci		ionic_debugfs_add_qcq(lif, lif->txqcqs[i]);
209062306a36Sopenharmony_ci	}
209162306a36Sopenharmony_ci
209262306a36Sopenharmony_ci	flags = IONIC_QCQ_F_RX_STATS | IONIC_QCQ_F_SG | IONIC_QCQ_F_INTR;
209362306a36Sopenharmony_ci
209462306a36Sopenharmony_ci	if (test_bit(IONIC_LIF_F_CMB_RX_RINGS, lif->state))
209562306a36Sopenharmony_ci		flags |= IONIC_QCQ_F_CMB_RINGS;
209662306a36Sopenharmony_ci
209762306a36Sopenharmony_ci	num_desc = lif->nrxq_descs;
209862306a36Sopenharmony_ci	desc_sz = sizeof(struct ionic_rxq_desc);
209962306a36Sopenharmony_ci	comp_sz = sizeof(struct ionic_rxq_comp);
210062306a36Sopenharmony_ci	sg_desc_sz = sizeof(struct ionic_rxq_sg_desc);
210162306a36Sopenharmony_ci
210262306a36Sopenharmony_ci	if (lif->rxq_features & IONIC_Q_F_2X_CQ_DESC)
210362306a36Sopenharmony_ci		comp_sz *= 2;
210462306a36Sopenharmony_ci
210562306a36Sopenharmony_ci	for (i = 0; i < lif->nxqs; i++) {
210662306a36Sopenharmony_ci		err = ionic_qcq_alloc(lif, IONIC_QTYPE_RXQ, i, "rx", flags,
210762306a36Sopenharmony_ci				      num_desc, desc_sz, comp_sz, sg_desc_sz,
210862306a36Sopenharmony_ci				      lif->kern_pid, &lif->rxqcqs[i]);
210962306a36Sopenharmony_ci		if (err)
211062306a36Sopenharmony_ci			goto err_out;
211162306a36Sopenharmony_ci
211262306a36Sopenharmony_ci		lif->rxqcqs[i]->q.features = lif->rxq_features;
211362306a36Sopenharmony_ci
211462306a36Sopenharmony_ci		ionic_intr_coal_init(lif->ionic->idev.intr_ctrl,
211562306a36Sopenharmony_ci				     lif->rxqcqs[i]->intr.index,
211662306a36Sopenharmony_ci				     lif->rx_coalesce_hw);
211762306a36Sopenharmony_ci		if (test_bit(IONIC_LIF_F_RX_DIM_INTR, lif->state))
211862306a36Sopenharmony_ci			lif->rxqcqs[i]->intr.dim_coal_hw = lif->rx_coalesce_hw;
211962306a36Sopenharmony_ci
212062306a36Sopenharmony_ci		if (!test_bit(IONIC_LIF_F_SPLIT_INTR, lif->state))
212162306a36Sopenharmony_ci			ionic_link_qcq_interrupts(lif->rxqcqs[i],
212262306a36Sopenharmony_ci						  lif->txqcqs[i]);
212362306a36Sopenharmony_ci
212462306a36Sopenharmony_ci		ionic_debugfs_add_qcq(lif, lif->rxqcqs[i]);
212562306a36Sopenharmony_ci	}
212662306a36Sopenharmony_ci
212762306a36Sopenharmony_ci	return 0;
212862306a36Sopenharmony_ci
212962306a36Sopenharmony_cierr_out:
213062306a36Sopenharmony_ci	ionic_txrx_free(lif);
213162306a36Sopenharmony_ci
213262306a36Sopenharmony_ci	return err;
213362306a36Sopenharmony_ci}
213462306a36Sopenharmony_ci
213562306a36Sopenharmony_cistatic int ionic_txrx_init(struct ionic_lif *lif)
213662306a36Sopenharmony_ci{
213762306a36Sopenharmony_ci	unsigned int i;
213862306a36Sopenharmony_ci	int err;
213962306a36Sopenharmony_ci
214062306a36Sopenharmony_ci	for (i = 0; i < lif->nxqs; i++) {
214162306a36Sopenharmony_ci		err = ionic_lif_txq_init(lif, lif->txqcqs[i]);
214262306a36Sopenharmony_ci		if (err)
214362306a36Sopenharmony_ci			goto err_out;
214462306a36Sopenharmony_ci
214562306a36Sopenharmony_ci		err = ionic_lif_rxq_init(lif, lif->rxqcqs[i]);
214662306a36Sopenharmony_ci		if (err) {
214762306a36Sopenharmony_ci			ionic_lif_qcq_deinit(lif, lif->txqcqs[i]);
214862306a36Sopenharmony_ci			goto err_out;
214962306a36Sopenharmony_ci		}
215062306a36Sopenharmony_ci	}
215162306a36Sopenharmony_ci
215262306a36Sopenharmony_ci	if (lif->netdev->features & NETIF_F_RXHASH)
215362306a36Sopenharmony_ci		ionic_lif_rss_init(lif);
215462306a36Sopenharmony_ci
215562306a36Sopenharmony_ci	ionic_lif_rx_mode(lif);
215662306a36Sopenharmony_ci
215762306a36Sopenharmony_ci	return 0;
215862306a36Sopenharmony_ci
215962306a36Sopenharmony_cierr_out:
216062306a36Sopenharmony_ci	while (i--) {
216162306a36Sopenharmony_ci		ionic_lif_qcq_deinit(lif, lif->txqcqs[i]);
216262306a36Sopenharmony_ci		ionic_lif_qcq_deinit(lif, lif->rxqcqs[i]);
216362306a36Sopenharmony_ci	}
216462306a36Sopenharmony_ci
216562306a36Sopenharmony_ci	return err;
216662306a36Sopenharmony_ci}
216762306a36Sopenharmony_ci
216862306a36Sopenharmony_cistatic int ionic_txrx_enable(struct ionic_lif *lif)
216962306a36Sopenharmony_ci{
217062306a36Sopenharmony_ci	int derr = 0;
217162306a36Sopenharmony_ci	int i, err;
217262306a36Sopenharmony_ci
217362306a36Sopenharmony_ci	for (i = 0; i < lif->nxqs; i++) {
217462306a36Sopenharmony_ci		if (!(lif->rxqcqs[i] && lif->txqcqs[i])) {
217562306a36Sopenharmony_ci			dev_err(lif->ionic->dev, "%s: bad qcq %d\n", __func__, i);
217662306a36Sopenharmony_ci			err = -ENXIO;
217762306a36Sopenharmony_ci			goto err_out;
217862306a36Sopenharmony_ci		}
217962306a36Sopenharmony_ci
218062306a36Sopenharmony_ci		ionic_rx_fill(&lif->rxqcqs[i]->q);
218162306a36Sopenharmony_ci		err = ionic_qcq_enable(lif->rxqcqs[i]);
218262306a36Sopenharmony_ci		if (err)
218362306a36Sopenharmony_ci			goto err_out;
218462306a36Sopenharmony_ci
218562306a36Sopenharmony_ci		err = ionic_qcq_enable(lif->txqcqs[i]);
218662306a36Sopenharmony_ci		if (err) {
218762306a36Sopenharmony_ci			derr = ionic_qcq_disable(lif, lif->rxqcqs[i], err);
218862306a36Sopenharmony_ci			goto err_out;
218962306a36Sopenharmony_ci		}
219062306a36Sopenharmony_ci	}
219162306a36Sopenharmony_ci
219262306a36Sopenharmony_ci	if (lif->hwstamp_rxq) {
219362306a36Sopenharmony_ci		ionic_rx_fill(&lif->hwstamp_rxq->q);
219462306a36Sopenharmony_ci		err = ionic_qcq_enable(lif->hwstamp_rxq);
219562306a36Sopenharmony_ci		if (err)
219662306a36Sopenharmony_ci			goto err_out_hwstamp_rx;
219762306a36Sopenharmony_ci	}
219862306a36Sopenharmony_ci
219962306a36Sopenharmony_ci	if (lif->hwstamp_txq) {
220062306a36Sopenharmony_ci		err = ionic_qcq_enable(lif->hwstamp_txq);
220162306a36Sopenharmony_ci		if (err)
220262306a36Sopenharmony_ci			goto err_out_hwstamp_tx;
220362306a36Sopenharmony_ci	}
220462306a36Sopenharmony_ci
220562306a36Sopenharmony_ci	return 0;
220662306a36Sopenharmony_ci
220762306a36Sopenharmony_cierr_out_hwstamp_tx:
220862306a36Sopenharmony_ci	if (lif->hwstamp_rxq)
220962306a36Sopenharmony_ci		derr = ionic_qcq_disable(lif, lif->hwstamp_rxq, derr);
221062306a36Sopenharmony_cierr_out_hwstamp_rx:
221162306a36Sopenharmony_ci	i = lif->nxqs;
221262306a36Sopenharmony_cierr_out:
221362306a36Sopenharmony_ci	while (i--) {
221462306a36Sopenharmony_ci		derr = ionic_qcq_disable(lif, lif->txqcqs[i], derr);
221562306a36Sopenharmony_ci		derr = ionic_qcq_disable(lif, lif->rxqcqs[i], derr);
221662306a36Sopenharmony_ci	}
221762306a36Sopenharmony_ci
221862306a36Sopenharmony_ci	return err;
221962306a36Sopenharmony_ci}
222062306a36Sopenharmony_ci
222162306a36Sopenharmony_cistatic int ionic_start_queues(struct ionic_lif *lif)
222262306a36Sopenharmony_ci{
222362306a36Sopenharmony_ci	int err;
222462306a36Sopenharmony_ci
222562306a36Sopenharmony_ci	if (test_bit(IONIC_LIF_F_BROKEN, lif->state))
222662306a36Sopenharmony_ci		return -EIO;
222762306a36Sopenharmony_ci
222862306a36Sopenharmony_ci	if (test_bit(IONIC_LIF_F_FW_RESET, lif->state))
222962306a36Sopenharmony_ci		return -EBUSY;
223062306a36Sopenharmony_ci
223162306a36Sopenharmony_ci	if (test_and_set_bit(IONIC_LIF_F_UP, lif->state))
223262306a36Sopenharmony_ci		return 0;
223362306a36Sopenharmony_ci
223462306a36Sopenharmony_ci	err = ionic_txrx_enable(lif);
223562306a36Sopenharmony_ci	if (err) {
223662306a36Sopenharmony_ci		clear_bit(IONIC_LIF_F_UP, lif->state);
223762306a36Sopenharmony_ci		return err;
223862306a36Sopenharmony_ci	}
223962306a36Sopenharmony_ci	netif_tx_wake_all_queues(lif->netdev);
224062306a36Sopenharmony_ci
224162306a36Sopenharmony_ci	return 0;
224262306a36Sopenharmony_ci}
224362306a36Sopenharmony_ci
224462306a36Sopenharmony_cistatic int ionic_open(struct net_device *netdev)
224562306a36Sopenharmony_ci{
224662306a36Sopenharmony_ci	struct ionic_lif *lif = netdev_priv(netdev);
224762306a36Sopenharmony_ci	int err;
224862306a36Sopenharmony_ci
224962306a36Sopenharmony_ci	/* If recovering from a broken state, clear the bit and we'll try again */
225062306a36Sopenharmony_ci	if (test_and_clear_bit(IONIC_LIF_F_BROKEN, lif->state))
225162306a36Sopenharmony_ci		netdev_info(netdev, "clearing broken state\n");
225262306a36Sopenharmony_ci
225362306a36Sopenharmony_ci	mutex_lock(&lif->queue_lock);
225462306a36Sopenharmony_ci
225562306a36Sopenharmony_ci	err = ionic_txrx_alloc(lif);
225662306a36Sopenharmony_ci	if (err)
225762306a36Sopenharmony_ci		goto err_unlock;
225862306a36Sopenharmony_ci
225962306a36Sopenharmony_ci	err = ionic_txrx_init(lif);
226062306a36Sopenharmony_ci	if (err)
226162306a36Sopenharmony_ci		goto err_txrx_free;
226262306a36Sopenharmony_ci
226362306a36Sopenharmony_ci	err = netif_set_real_num_tx_queues(netdev, lif->nxqs);
226462306a36Sopenharmony_ci	if (err)
226562306a36Sopenharmony_ci		goto err_txrx_deinit;
226662306a36Sopenharmony_ci
226762306a36Sopenharmony_ci	err = netif_set_real_num_rx_queues(netdev, lif->nxqs);
226862306a36Sopenharmony_ci	if (err)
226962306a36Sopenharmony_ci		goto err_txrx_deinit;
227062306a36Sopenharmony_ci
227162306a36Sopenharmony_ci	/* don't start the queues until we have link */
227262306a36Sopenharmony_ci	if (netif_carrier_ok(netdev)) {
227362306a36Sopenharmony_ci		err = ionic_start_queues(lif);
227462306a36Sopenharmony_ci		if (err)
227562306a36Sopenharmony_ci			goto err_txrx_deinit;
227662306a36Sopenharmony_ci	}
227762306a36Sopenharmony_ci
227862306a36Sopenharmony_ci	/* If hardware timestamping is enabled, but the queues were freed by
227962306a36Sopenharmony_ci	 * ionic_stop, those need to be reallocated and initialized, too.
228062306a36Sopenharmony_ci	 */
228162306a36Sopenharmony_ci	ionic_lif_hwstamp_recreate_queues(lif);
228262306a36Sopenharmony_ci
228362306a36Sopenharmony_ci	mutex_unlock(&lif->queue_lock);
228462306a36Sopenharmony_ci
228562306a36Sopenharmony_ci	return 0;
228662306a36Sopenharmony_ci
228762306a36Sopenharmony_cierr_txrx_deinit:
228862306a36Sopenharmony_ci	ionic_txrx_deinit(lif);
228962306a36Sopenharmony_cierr_txrx_free:
229062306a36Sopenharmony_ci	ionic_txrx_free(lif);
229162306a36Sopenharmony_cierr_unlock:
229262306a36Sopenharmony_ci	mutex_unlock(&lif->queue_lock);
229362306a36Sopenharmony_ci	return err;
229462306a36Sopenharmony_ci}
229562306a36Sopenharmony_ci
229662306a36Sopenharmony_cistatic void ionic_stop_queues(struct ionic_lif *lif)
229762306a36Sopenharmony_ci{
229862306a36Sopenharmony_ci	if (!test_and_clear_bit(IONIC_LIF_F_UP, lif->state))
229962306a36Sopenharmony_ci		return;
230062306a36Sopenharmony_ci
230162306a36Sopenharmony_ci	netif_tx_disable(lif->netdev);
230262306a36Sopenharmony_ci	ionic_txrx_disable(lif);
230362306a36Sopenharmony_ci}
230462306a36Sopenharmony_ci
230562306a36Sopenharmony_cistatic int ionic_stop(struct net_device *netdev)
230662306a36Sopenharmony_ci{
230762306a36Sopenharmony_ci	struct ionic_lif *lif = netdev_priv(netdev);
230862306a36Sopenharmony_ci
230962306a36Sopenharmony_ci	if (test_bit(IONIC_LIF_F_FW_RESET, lif->state))
231062306a36Sopenharmony_ci		return 0;
231162306a36Sopenharmony_ci
231262306a36Sopenharmony_ci	mutex_lock(&lif->queue_lock);
231362306a36Sopenharmony_ci	ionic_stop_queues(lif);
231462306a36Sopenharmony_ci	ionic_txrx_deinit(lif);
231562306a36Sopenharmony_ci	ionic_txrx_free(lif);
231662306a36Sopenharmony_ci	mutex_unlock(&lif->queue_lock);
231762306a36Sopenharmony_ci
231862306a36Sopenharmony_ci	return 0;
231962306a36Sopenharmony_ci}
232062306a36Sopenharmony_ci
232162306a36Sopenharmony_cistatic int ionic_eth_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
232262306a36Sopenharmony_ci{
232362306a36Sopenharmony_ci	struct ionic_lif *lif = netdev_priv(netdev);
232462306a36Sopenharmony_ci
232562306a36Sopenharmony_ci	switch (cmd) {
232662306a36Sopenharmony_ci	case SIOCSHWTSTAMP:
232762306a36Sopenharmony_ci		return ionic_lif_hwstamp_set(lif, ifr);
232862306a36Sopenharmony_ci	case SIOCGHWTSTAMP:
232962306a36Sopenharmony_ci		return ionic_lif_hwstamp_get(lif, ifr);
233062306a36Sopenharmony_ci	default:
233162306a36Sopenharmony_ci		return -EOPNOTSUPP;
233262306a36Sopenharmony_ci	}
233362306a36Sopenharmony_ci}
233462306a36Sopenharmony_ci
233562306a36Sopenharmony_cistatic int ionic_get_fw_vf_config(struct ionic *ionic, int vf, struct ionic_vf *vfdata)
233662306a36Sopenharmony_ci{
233762306a36Sopenharmony_ci	struct ionic_vf_getattr_comp comp = { 0 };
233862306a36Sopenharmony_ci	int err;
233962306a36Sopenharmony_ci	u8 attr;
234062306a36Sopenharmony_ci
234162306a36Sopenharmony_ci	attr = IONIC_VF_ATTR_VLAN;
234262306a36Sopenharmony_ci	err = ionic_dev_cmd_vf_getattr(ionic, vf, attr, &comp);
234362306a36Sopenharmony_ci	if (err && comp.status != IONIC_RC_ENOSUPP)
234462306a36Sopenharmony_ci		goto err_out;
234562306a36Sopenharmony_ci	if (!err)
234662306a36Sopenharmony_ci		vfdata->vlanid = comp.vlanid;
234762306a36Sopenharmony_ci
234862306a36Sopenharmony_ci	attr = IONIC_VF_ATTR_SPOOFCHK;
234962306a36Sopenharmony_ci	err = ionic_dev_cmd_vf_getattr(ionic, vf, attr, &comp);
235062306a36Sopenharmony_ci	if (err && comp.status != IONIC_RC_ENOSUPP)
235162306a36Sopenharmony_ci		goto err_out;
235262306a36Sopenharmony_ci	if (!err)
235362306a36Sopenharmony_ci		vfdata->spoofchk = comp.spoofchk;
235462306a36Sopenharmony_ci
235562306a36Sopenharmony_ci	attr = IONIC_VF_ATTR_LINKSTATE;
235662306a36Sopenharmony_ci	err = ionic_dev_cmd_vf_getattr(ionic, vf, attr, &comp);
235762306a36Sopenharmony_ci	if (err && comp.status != IONIC_RC_ENOSUPP)
235862306a36Sopenharmony_ci		goto err_out;
235962306a36Sopenharmony_ci	if (!err) {
236062306a36Sopenharmony_ci		switch (comp.linkstate) {
236162306a36Sopenharmony_ci		case IONIC_VF_LINK_STATUS_UP:
236262306a36Sopenharmony_ci			vfdata->linkstate = IFLA_VF_LINK_STATE_ENABLE;
236362306a36Sopenharmony_ci			break;
236462306a36Sopenharmony_ci		case IONIC_VF_LINK_STATUS_DOWN:
236562306a36Sopenharmony_ci			vfdata->linkstate = IFLA_VF_LINK_STATE_DISABLE;
236662306a36Sopenharmony_ci			break;
236762306a36Sopenharmony_ci		case IONIC_VF_LINK_STATUS_AUTO:
236862306a36Sopenharmony_ci			vfdata->linkstate = IFLA_VF_LINK_STATE_AUTO;
236962306a36Sopenharmony_ci			break;
237062306a36Sopenharmony_ci		default:
237162306a36Sopenharmony_ci			dev_warn(ionic->dev, "Unexpected link state %u\n", comp.linkstate);
237262306a36Sopenharmony_ci			break;
237362306a36Sopenharmony_ci		}
237462306a36Sopenharmony_ci	}
237562306a36Sopenharmony_ci
237662306a36Sopenharmony_ci	attr = IONIC_VF_ATTR_RATE;
237762306a36Sopenharmony_ci	err = ionic_dev_cmd_vf_getattr(ionic, vf, attr, &comp);
237862306a36Sopenharmony_ci	if (err && comp.status != IONIC_RC_ENOSUPP)
237962306a36Sopenharmony_ci		goto err_out;
238062306a36Sopenharmony_ci	if (!err)
238162306a36Sopenharmony_ci		vfdata->maxrate = comp.maxrate;
238262306a36Sopenharmony_ci
238362306a36Sopenharmony_ci	attr = IONIC_VF_ATTR_TRUST;
238462306a36Sopenharmony_ci	err = ionic_dev_cmd_vf_getattr(ionic, vf, attr, &comp);
238562306a36Sopenharmony_ci	if (err && comp.status != IONIC_RC_ENOSUPP)
238662306a36Sopenharmony_ci		goto err_out;
238762306a36Sopenharmony_ci	if (!err)
238862306a36Sopenharmony_ci		vfdata->trusted = comp.trust;
238962306a36Sopenharmony_ci
239062306a36Sopenharmony_ci	attr = IONIC_VF_ATTR_MAC;
239162306a36Sopenharmony_ci	err = ionic_dev_cmd_vf_getattr(ionic, vf, attr, &comp);
239262306a36Sopenharmony_ci	if (err && comp.status != IONIC_RC_ENOSUPP)
239362306a36Sopenharmony_ci		goto err_out;
239462306a36Sopenharmony_ci	if (!err)
239562306a36Sopenharmony_ci		ether_addr_copy(vfdata->macaddr, comp.macaddr);
239662306a36Sopenharmony_ci
239762306a36Sopenharmony_cierr_out:
239862306a36Sopenharmony_ci	if (err)
239962306a36Sopenharmony_ci		dev_err(ionic->dev, "Failed to get %s for VF %d\n",
240062306a36Sopenharmony_ci			ionic_vf_attr_to_str(attr), vf);
240162306a36Sopenharmony_ci
240262306a36Sopenharmony_ci	return err;
240362306a36Sopenharmony_ci}
240462306a36Sopenharmony_ci
240562306a36Sopenharmony_cistatic int ionic_get_vf_config(struct net_device *netdev,
240662306a36Sopenharmony_ci			       int vf, struct ifla_vf_info *ivf)
240762306a36Sopenharmony_ci{
240862306a36Sopenharmony_ci	struct ionic_lif *lif = netdev_priv(netdev);
240962306a36Sopenharmony_ci	struct ionic *ionic = lif->ionic;
241062306a36Sopenharmony_ci	struct ionic_vf vfdata = { 0 };
241162306a36Sopenharmony_ci	int ret = 0;
241262306a36Sopenharmony_ci
241362306a36Sopenharmony_ci	if (!netif_device_present(netdev))
241462306a36Sopenharmony_ci		return -EBUSY;
241562306a36Sopenharmony_ci
241662306a36Sopenharmony_ci	down_read(&ionic->vf_op_lock);
241762306a36Sopenharmony_ci
241862306a36Sopenharmony_ci	if (vf >= pci_num_vf(ionic->pdev) || !ionic->vfs) {
241962306a36Sopenharmony_ci		ret = -EINVAL;
242062306a36Sopenharmony_ci	} else {
242162306a36Sopenharmony_ci		ivf->vf = vf;
242262306a36Sopenharmony_ci		ivf->qos = 0;
242362306a36Sopenharmony_ci
242462306a36Sopenharmony_ci		ret = ionic_get_fw_vf_config(ionic, vf, &vfdata);
242562306a36Sopenharmony_ci		if (!ret) {
242662306a36Sopenharmony_ci			ivf->vlan         = le16_to_cpu(vfdata.vlanid);
242762306a36Sopenharmony_ci			ivf->spoofchk     = vfdata.spoofchk;
242862306a36Sopenharmony_ci			ivf->linkstate    = vfdata.linkstate;
242962306a36Sopenharmony_ci			ivf->max_tx_rate  = le32_to_cpu(vfdata.maxrate);
243062306a36Sopenharmony_ci			ivf->trusted      = vfdata.trusted;
243162306a36Sopenharmony_ci			ether_addr_copy(ivf->mac, vfdata.macaddr);
243262306a36Sopenharmony_ci		}
243362306a36Sopenharmony_ci	}
243462306a36Sopenharmony_ci
243562306a36Sopenharmony_ci	up_read(&ionic->vf_op_lock);
243662306a36Sopenharmony_ci	return ret;
243762306a36Sopenharmony_ci}
243862306a36Sopenharmony_ci
243962306a36Sopenharmony_cistatic int ionic_get_vf_stats(struct net_device *netdev, int vf,
244062306a36Sopenharmony_ci			      struct ifla_vf_stats *vf_stats)
244162306a36Sopenharmony_ci{
244262306a36Sopenharmony_ci	struct ionic_lif *lif = netdev_priv(netdev);
244362306a36Sopenharmony_ci	struct ionic *ionic = lif->ionic;
244462306a36Sopenharmony_ci	struct ionic_lif_stats *vs;
244562306a36Sopenharmony_ci	int ret = 0;
244662306a36Sopenharmony_ci
244762306a36Sopenharmony_ci	if (!netif_device_present(netdev))
244862306a36Sopenharmony_ci		return -EBUSY;
244962306a36Sopenharmony_ci
245062306a36Sopenharmony_ci	down_read(&ionic->vf_op_lock);
245162306a36Sopenharmony_ci
245262306a36Sopenharmony_ci	if (vf >= pci_num_vf(ionic->pdev) || !ionic->vfs) {
245362306a36Sopenharmony_ci		ret = -EINVAL;
245462306a36Sopenharmony_ci	} else {
245562306a36Sopenharmony_ci		memset(vf_stats, 0, sizeof(*vf_stats));
245662306a36Sopenharmony_ci		vs = &ionic->vfs[vf].stats;
245762306a36Sopenharmony_ci
245862306a36Sopenharmony_ci		vf_stats->rx_packets = le64_to_cpu(vs->rx_ucast_packets);
245962306a36Sopenharmony_ci		vf_stats->tx_packets = le64_to_cpu(vs->tx_ucast_packets);
246062306a36Sopenharmony_ci		vf_stats->rx_bytes   = le64_to_cpu(vs->rx_ucast_bytes);
246162306a36Sopenharmony_ci		vf_stats->tx_bytes   = le64_to_cpu(vs->tx_ucast_bytes);
246262306a36Sopenharmony_ci		vf_stats->broadcast  = le64_to_cpu(vs->rx_bcast_packets);
246362306a36Sopenharmony_ci		vf_stats->multicast  = le64_to_cpu(vs->rx_mcast_packets);
246462306a36Sopenharmony_ci		vf_stats->rx_dropped = le64_to_cpu(vs->rx_ucast_drop_packets) +
246562306a36Sopenharmony_ci				       le64_to_cpu(vs->rx_mcast_drop_packets) +
246662306a36Sopenharmony_ci				       le64_to_cpu(vs->rx_bcast_drop_packets);
246762306a36Sopenharmony_ci		vf_stats->tx_dropped = le64_to_cpu(vs->tx_ucast_drop_packets) +
246862306a36Sopenharmony_ci				       le64_to_cpu(vs->tx_mcast_drop_packets) +
246962306a36Sopenharmony_ci				       le64_to_cpu(vs->tx_bcast_drop_packets);
247062306a36Sopenharmony_ci	}
247162306a36Sopenharmony_ci
247262306a36Sopenharmony_ci	up_read(&ionic->vf_op_lock);
247362306a36Sopenharmony_ci	return ret;
247462306a36Sopenharmony_ci}
247562306a36Sopenharmony_ci
247662306a36Sopenharmony_cistatic int ionic_set_vf_mac(struct net_device *netdev, int vf, u8 *mac)
247762306a36Sopenharmony_ci{
247862306a36Sopenharmony_ci	struct ionic_vf_setattr_cmd vfc = { .attr = IONIC_VF_ATTR_MAC };
247962306a36Sopenharmony_ci	struct ionic_lif *lif = netdev_priv(netdev);
248062306a36Sopenharmony_ci	struct ionic *ionic = lif->ionic;
248162306a36Sopenharmony_ci	int ret;
248262306a36Sopenharmony_ci
248362306a36Sopenharmony_ci	if (!(is_zero_ether_addr(mac) || is_valid_ether_addr(mac)))
248462306a36Sopenharmony_ci		return -EINVAL;
248562306a36Sopenharmony_ci
248662306a36Sopenharmony_ci	if (!netif_device_present(netdev))
248762306a36Sopenharmony_ci		return -EBUSY;
248862306a36Sopenharmony_ci
248962306a36Sopenharmony_ci	down_write(&ionic->vf_op_lock);
249062306a36Sopenharmony_ci
249162306a36Sopenharmony_ci	if (vf >= pci_num_vf(ionic->pdev) || !ionic->vfs) {
249262306a36Sopenharmony_ci		ret = -EINVAL;
249362306a36Sopenharmony_ci	} else {
249462306a36Sopenharmony_ci		ether_addr_copy(vfc.macaddr, mac);
249562306a36Sopenharmony_ci		dev_dbg(ionic->dev, "%s: vf %d macaddr %pM\n",
249662306a36Sopenharmony_ci			__func__, vf, vfc.macaddr);
249762306a36Sopenharmony_ci
249862306a36Sopenharmony_ci		ret = ionic_set_vf_config(ionic, vf, &vfc);
249962306a36Sopenharmony_ci		if (!ret)
250062306a36Sopenharmony_ci			ether_addr_copy(ionic->vfs[vf].macaddr, mac);
250162306a36Sopenharmony_ci	}
250262306a36Sopenharmony_ci
250362306a36Sopenharmony_ci	up_write(&ionic->vf_op_lock);
250462306a36Sopenharmony_ci	return ret;
250562306a36Sopenharmony_ci}
250662306a36Sopenharmony_ci
250762306a36Sopenharmony_cistatic int ionic_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan,
250862306a36Sopenharmony_ci			     u8 qos, __be16 proto)
250962306a36Sopenharmony_ci{
251062306a36Sopenharmony_ci	struct ionic_vf_setattr_cmd vfc = { .attr = IONIC_VF_ATTR_VLAN };
251162306a36Sopenharmony_ci	struct ionic_lif *lif = netdev_priv(netdev);
251262306a36Sopenharmony_ci	struct ionic *ionic = lif->ionic;
251362306a36Sopenharmony_ci	int ret;
251462306a36Sopenharmony_ci
251562306a36Sopenharmony_ci	/* until someday when we support qos */
251662306a36Sopenharmony_ci	if (qos)
251762306a36Sopenharmony_ci		return -EINVAL;
251862306a36Sopenharmony_ci
251962306a36Sopenharmony_ci	if (vlan > 4095)
252062306a36Sopenharmony_ci		return -EINVAL;
252162306a36Sopenharmony_ci
252262306a36Sopenharmony_ci	if (proto != htons(ETH_P_8021Q))
252362306a36Sopenharmony_ci		return -EPROTONOSUPPORT;
252462306a36Sopenharmony_ci
252562306a36Sopenharmony_ci	if (!netif_device_present(netdev))
252662306a36Sopenharmony_ci		return -EBUSY;
252762306a36Sopenharmony_ci
252862306a36Sopenharmony_ci	down_write(&ionic->vf_op_lock);
252962306a36Sopenharmony_ci
253062306a36Sopenharmony_ci	if (vf >= pci_num_vf(ionic->pdev) || !ionic->vfs) {
253162306a36Sopenharmony_ci		ret = -EINVAL;
253262306a36Sopenharmony_ci	} else {
253362306a36Sopenharmony_ci		vfc.vlanid = cpu_to_le16(vlan);
253462306a36Sopenharmony_ci		dev_dbg(ionic->dev, "%s: vf %d vlan %d\n",
253562306a36Sopenharmony_ci			__func__, vf, le16_to_cpu(vfc.vlanid));
253662306a36Sopenharmony_ci
253762306a36Sopenharmony_ci		ret = ionic_set_vf_config(ionic, vf, &vfc);
253862306a36Sopenharmony_ci		if (!ret)
253962306a36Sopenharmony_ci			ionic->vfs[vf].vlanid = cpu_to_le16(vlan);
254062306a36Sopenharmony_ci	}
254162306a36Sopenharmony_ci
254262306a36Sopenharmony_ci	up_write(&ionic->vf_op_lock);
254362306a36Sopenharmony_ci	return ret;
254462306a36Sopenharmony_ci}
254562306a36Sopenharmony_ci
254662306a36Sopenharmony_cistatic int ionic_set_vf_rate(struct net_device *netdev, int vf,
254762306a36Sopenharmony_ci			     int tx_min, int tx_max)
254862306a36Sopenharmony_ci{
254962306a36Sopenharmony_ci	struct ionic_vf_setattr_cmd vfc = { .attr = IONIC_VF_ATTR_RATE };
255062306a36Sopenharmony_ci	struct ionic_lif *lif = netdev_priv(netdev);
255162306a36Sopenharmony_ci	struct ionic *ionic = lif->ionic;
255262306a36Sopenharmony_ci	int ret;
255362306a36Sopenharmony_ci
255462306a36Sopenharmony_ci	/* setting the min just seems silly */
255562306a36Sopenharmony_ci	if (tx_min)
255662306a36Sopenharmony_ci		return -EINVAL;
255762306a36Sopenharmony_ci
255862306a36Sopenharmony_ci	if (!netif_device_present(netdev))
255962306a36Sopenharmony_ci		return -EBUSY;
256062306a36Sopenharmony_ci
256162306a36Sopenharmony_ci	down_write(&ionic->vf_op_lock);
256262306a36Sopenharmony_ci
256362306a36Sopenharmony_ci	if (vf >= pci_num_vf(ionic->pdev) || !ionic->vfs) {
256462306a36Sopenharmony_ci		ret = -EINVAL;
256562306a36Sopenharmony_ci	} else {
256662306a36Sopenharmony_ci		vfc.maxrate = cpu_to_le32(tx_max);
256762306a36Sopenharmony_ci		dev_dbg(ionic->dev, "%s: vf %d maxrate %d\n",
256862306a36Sopenharmony_ci			__func__, vf, le32_to_cpu(vfc.maxrate));
256962306a36Sopenharmony_ci
257062306a36Sopenharmony_ci		ret = ionic_set_vf_config(ionic, vf, &vfc);
257162306a36Sopenharmony_ci		if (!ret)
257262306a36Sopenharmony_ci			ionic->vfs[vf].maxrate = cpu_to_le32(tx_max);
257362306a36Sopenharmony_ci	}
257462306a36Sopenharmony_ci
257562306a36Sopenharmony_ci	up_write(&ionic->vf_op_lock);
257662306a36Sopenharmony_ci	return ret;
257762306a36Sopenharmony_ci}
257862306a36Sopenharmony_ci
257962306a36Sopenharmony_cistatic int ionic_set_vf_spoofchk(struct net_device *netdev, int vf, bool set)
258062306a36Sopenharmony_ci{
258162306a36Sopenharmony_ci	struct ionic_vf_setattr_cmd vfc = { .attr = IONIC_VF_ATTR_SPOOFCHK };
258262306a36Sopenharmony_ci	struct ionic_lif *lif = netdev_priv(netdev);
258362306a36Sopenharmony_ci	struct ionic *ionic = lif->ionic;
258462306a36Sopenharmony_ci	int ret;
258562306a36Sopenharmony_ci
258662306a36Sopenharmony_ci	if (!netif_device_present(netdev))
258762306a36Sopenharmony_ci		return -EBUSY;
258862306a36Sopenharmony_ci
258962306a36Sopenharmony_ci	down_write(&ionic->vf_op_lock);
259062306a36Sopenharmony_ci
259162306a36Sopenharmony_ci	if (vf >= pci_num_vf(ionic->pdev) || !ionic->vfs) {
259262306a36Sopenharmony_ci		ret = -EINVAL;
259362306a36Sopenharmony_ci	} else {
259462306a36Sopenharmony_ci		vfc.spoofchk = set;
259562306a36Sopenharmony_ci		dev_dbg(ionic->dev, "%s: vf %d spoof %d\n",
259662306a36Sopenharmony_ci			__func__, vf, vfc.spoofchk);
259762306a36Sopenharmony_ci
259862306a36Sopenharmony_ci		ret = ionic_set_vf_config(ionic, vf, &vfc);
259962306a36Sopenharmony_ci		if (!ret)
260062306a36Sopenharmony_ci			ionic->vfs[vf].spoofchk = set;
260162306a36Sopenharmony_ci	}
260262306a36Sopenharmony_ci
260362306a36Sopenharmony_ci	up_write(&ionic->vf_op_lock);
260462306a36Sopenharmony_ci	return ret;
260562306a36Sopenharmony_ci}
260662306a36Sopenharmony_ci
260762306a36Sopenharmony_cistatic int ionic_set_vf_trust(struct net_device *netdev, int vf, bool set)
260862306a36Sopenharmony_ci{
260962306a36Sopenharmony_ci	struct ionic_vf_setattr_cmd vfc = { .attr = IONIC_VF_ATTR_TRUST };
261062306a36Sopenharmony_ci	struct ionic_lif *lif = netdev_priv(netdev);
261162306a36Sopenharmony_ci	struct ionic *ionic = lif->ionic;
261262306a36Sopenharmony_ci	int ret;
261362306a36Sopenharmony_ci
261462306a36Sopenharmony_ci	if (!netif_device_present(netdev))
261562306a36Sopenharmony_ci		return -EBUSY;
261662306a36Sopenharmony_ci
261762306a36Sopenharmony_ci	down_write(&ionic->vf_op_lock);
261862306a36Sopenharmony_ci
261962306a36Sopenharmony_ci	if (vf >= pci_num_vf(ionic->pdev) || !ionic->vfs) {
262062306a36Sopenharmony_ci		ret = -EINVAL;
262162306a36Sopenharmony_ci	} else {
262262306a36Sopenharmony_ci		vfc.trust = set;
262362306a36Sopenharmony_ci		dev_dbg(ionic->dev, "%s: vf %d trust %d\n",
262462306a36Sopenharmony_ci			__func__, vf, vfc.trust);
262562306a36Sopenharmony_ci
262662306a36Sopenharmony_ci		ret = ionic_set_vf_config(ionic, vf, &vfc);
262762306a36Sopenharmony_ci		if (!ret)
262862306a36Sopenharmony_ci			ionic->vfs[vf].trusted = set;
262962306a36Sopenharmony_ci	}
263062306a36Sopenharmony_ci
263162306a36Sopenharmony_ci	up_write(&ionic->vf_op_lock);
263262306a36Sopenharmony_ci	return ret;
263362306a36Sopenharmony_ci}
263462306a36Sopenharmony_ci
263562306a36Sopenharmony_cistatic int ionic_set_vf_link_state(struct net_device *netdev, int vf, int set)
263662306a36Sopenharmony_ci{
263762306a36Sopenharmony_ci	struct ionic_vf_setattr_cmd vfc = { .attr = IONIC_VF_ATTR_LINKSTATE };
263862306a36Sopenharmony_ci	struct ionic_lif *lif = netdev_priv(netdev);
263962306a36Sopenharmony_ci	struct ionic *ionic = lif->ionic;
264062306a36Sopenharmony_ci	u8 vfls;
264162306a36Sopenharmony_ci	int ret;
264262306a36Sopenharmony_ci
264362306a36Sopenharmony_ci	switch (set) {
264462306a36Sopenharmony_ci	case IFLA_VF_LINK_STATE_ENABLE:
264562306a36Sopenharmony_ci		vfls = IONIC_VF_LINK_STATUS_UP;
264662306a36Sopenharmony_ci		break;
264762306a36Sopenharmony_ci	case IFLA_VF_LINK_STATE_DISABLE:
264862306a36Sopenharmony_ci		vfls = IONIC_VF_LINK_STATUS_DOWN;
264962306a36Sopenharmony_ci		break;
265062306a36Sopenharmony_ci	case IFLA_VF_LINK_STATE_AUTO:
265162306a36Sopenharmony_ci		vfls = IONIC_VF_LINK_STATUS_AUTO;
265262306a36Sopenharmony_ci		break;
265362306a36Sopenharmony_ci	default:
265462306a36Sopenharmony_ci		return -EINVAL;
265562306a36Sopenharmony_ci	}
265662306a36Sopenharmony_ci
265762306a36Sopenharmony_ci	if (!netif_device_present(netdev))
265862306a36Sopenharmony_ci		return -EBUSY;
265962306a36Sopenharmony_ci
266062306a36Sopenharmony_ci	down_write(&ionic->vf_op_lock);
266162306a36Sopenharmony_ci
266262306a36Sopenharmony_ci	if (vf >= pci_num_vf(ionic->pdev) || !ionic->vfs) {
266362306a36Sopenharmony_ci		ret = -EINVAL;
266462306a36Sopenharmony_ci	} else {
266562306a36Sopenharmony_ci		vfc.linkstate = vfls;
266662306a36Sopenharmony_ci		dev_dbg(ionic->dev, "%s: vf %d linkstate %d\n",
266762306a36Sopenharmony_ci			__func__, vf, vfc.linkstate);
266862306a36Sopenharmony_ci
266962306a36Sopenharmony_ci		ret = ionic_set_vf_config(ionic, vf, &vfc);
267062306a36Sopenharmony_ci		if (!ret)
267162306a36Sopenharmony_ci			ionic->vfs[vf].linkstate = set;
267262306a36Sopenharmony_ci	}
267362306a36Sopenharmony_ci
267462306a36Sopenharmony_ci	up_write(&ionic->vf_op_lock);
267562306a36Sopenharmony_ci	return ret;
267662306a36Sopenharmony_ci}
267762306a36Sopenharmony_ci
267862306a36Sopenharmony_cistatic void ionic_vf_attr_replay(struct ionic_lif *lif)
267962306a36Sopenharmony_ci{
268062306a36Sopenharmony_ci	struct ionic_vf_setattr_cmd vfc = { };
268162306a36Sopenharmony_ci	struct ionic *ionic = lif->ionic;
268262306a36Sopenharmony_ci	struct ionic_vf *v;
268362306a36Sopenharmony_ci	int i;
268462306a36Sopenharmony_ci
268562306a36Sopenharmony_ci	if (!ionic->vfs)
268662306a36Sopenharmony_ci		return;
268762306a36Sopenharmony_ci
268862306a36Sopenharmony_ci	down_read(&ionic->vf_op_lock);
268962306a36Sopenharmony_ci
269062306a36Sopenharmony_ci	for (i = 0; i < ionic->num_vfs; i++) {
269162306a36Sopenharmony_ci		v = &ionic->vfs[i];
269262306a36Sopenharmony_ci
269362306a36Sopenharmony_ci		if (v->stats_pa) {
269462306a36Sopenharmony_ci			vfc.attr = IONIC_VF_ATTR_STATSADDR;
269562306a36Sopenharmony_ci			vfc.stats_pa = cpu_to_le64(v->stats_pa);
269662306a36Sopenharmony_ci			ionic_set_vf_config(ionic, i, &vfc);
269762306a36Sopenharmony_ci			vfc.stats_pa = 0;
269862306a36Sopenharmony_ci		}
269962306a36Sopenharmony_ci
270062306a36Sopenharmony_ci		if (!is_zero_ether_addr(v->macaddr)) {
270162306a36Sopenharmony_ci			vfc.attr = IONIC_VF_ATTR_MAC;
270262306a36Sopenharmony_ci			ether_addr_copy(vfc.macaddr, v->macaddr);
270362306a36Sopenharmony_ci			ionic_set_vf_config(ionic, i, &vfc);
270462306a36Sopenharmony_ci			eth_zero_addr(vfc.macaddr);
270562306a36Sopenharmony_ci		}
270662306a36Sopenharmony_ci
270762306a36Sopenharmony_ci		if (v->vlanid) {
270862306a36Sopenharmony_ci			vfc.attr = IONIC_VF_ATTR_VLAN;
270962306a36Sopenharmony_ci			vfc.vlanid = v->vlanid;
271062306a36Sopenharmony_ci			ionic_set_vf_config(ionic, i, &vfc);
271162306a36Sopenharmony_ci			vfc.vlanid = 0;
271262306a36Sopenharmony_ci		}
271362306a36Sopenharmony_ci
271462306a36Sopenharmony_ci		if (v->maxrate) {
271562306a36Sopenharmony_ci			vfc.attr = IONIC_VF_ATTR_RATE;
271662306a36Sopenharmony_ci			vfc.maxrate = v->maxrate;
271762306a36Sopenharmony_ci			ionic_set_vf_config(ionic, i, &vfc);
271862306a36Sopenharmony_ci			vfc.maxrate = 0;
271962306a36Sopenharmony_ci		}
272062306a36Sopenharmony_ci
272162306a36Sopenharmony_ci		if (v->spoofchk) {
272262306a36Sopenharmony_ci			vfc.attr = IONIC_VF_ATTR_SPOOFCHK;
272362306a36Sopenharmony_ci			vfc.spoofchk = v->spoofchk;
272462306a36Sopenharmony_ci			ionic_set_vf_config(ionic, i, &vfc);
272562306a36Sopenharmony_ci			vfc.spoofchk = 0;
272662306a36Sopenharmony_ci		}
272762306a36Sopenharmony_ci
272862306a36Sopenharmony_ci		if (v->trusted) {
272962306a36Sopenharmony_ci			vfc.attr = IONIC_VF_ATTR_TRUST;
273062306a36Sopenharmony_ci			vfc.trust = v->trusted;
273162306a36Sopenharmony_ci			ionic_set_vf_config(ionic, i, &vfc);
273262306a36Sopenharmony_ci			vfc.trust = 0;
273362306a36Sopenharmony_ci		}
273462306a36Sopenharmony_ci
273562306a36Sopenharmony_ci		if (v->linkstate) {
273662306a36Sopenharmony_ci			vfc.attr = IONIC_VF_ATTR_LINKSTATE;
273762306a36Sopenharmony_ci			vfc.linkstate = v->linkstate;
273862306a36Sopenharmony_ci			ionic_set_vf_config(ionic, i, &vfc);
273962306a36Sopenharmony_ci			vfc.linkstate = 0;
274062306a36Sopenharmony_ci		}
274162306a36Sopenharmony_ci	}
274262306a36Sopenharmony_ci
274362306a36Sopenharmony_ci	up_read(&ionic->vf_op_lock);
274462306a36Sopenharmony_ci
274562306a36Sopenharmony_ci	ionic_vf_start(ionic);
274662306a36Sopenharmony_ci}
274762306a36Sopenharmony_ci
274862306a36Sopenharmony_cistatic const struct net_device_ops ionic_netdev_ops = {
274962306a36Sopenharmony_ci	.ndo_open               = ionic_open,
275062306a36Sopenharmony_ci	.ndo_stop               = ionic_stop,
275162306a36Sopenharmony_ci	.ndo_eth_ioctl		= ionic_eth_ioctl,
275262306a36Sopenharmony_ci	.ndo_start_xmit		= ionic_start_xmit,
275362306a36Sopenharmony_ci	.ndo_get_stats64	= ionic_get_stats64,
275462306a36Sopenharmony_ci	.ndo_set_rx_mode	= ionic_ndo_set_rx_mode,
275562306a36Sopenharmony_ci	.ndo_set_features	= ionic_set_features,
275662306a36Sopenharmony_ci	.ndo_set_mac_address	= ionic_set_mac_address,
275762306a36Sopenharmony_ci	.ndo_validate_addr	= eth_validate_addr,
275862306a36Sopenharmony_ci	.ndo_tx_timeout         = ionic_tx_timeout,
275962306a36Sopenharmony_ci	.ndo_change_mtu         = ionic_change_mtu,
276062306a36Sopenharmony_ci	.ndo_vlan_rx_add_vid    = ionic_vlan_rx_add_vid,
276162306a36Sopenharmony_ci	.ndo_vlan_rx_kill_vid   = ionic_vlan_rx_kill_vid,
276262306a36Sopenharmony_ci	.ndo_set_vf_vlan	= ionic_set_vf_vlan,
276362306a36Sopenharmony_ci	.ndo_set_vf_trust	= ionic_set_vf_trust,
276462306a36Sopenharmony_ci	.ndo_set_vf_mac		= ionic_set_vf_mac,
276562306a36Sopenharmony_ci	.ndo_set_vf_rate	= ionic_set_vf_rate,
276662306a36Sopenharmony_ci	.ndo_set_vf_spoofchk	= ionic_set_vf_spoofchk,
276762306a36Sopenharmony_ci	.ndo_get_vf_config	= ionic_get_vf_config,
276862306a36Sopenharmony_ci	.ndo_set_vf_link_state	= ionic_set_vf_link_state,
276962306a36Sopenharmony_ci	.ndo_get_vf_stats       = ionic_get_vf_stats,
277062306a36Sopenharmony_ci};
277162306a36Sopenharmony_ci
277262306a36Sopenharmony_cistatic int ionic_cmb_reconfig(struct ionic_lif *lif,
277362306a36Sopenharmony_ci			      struct ionic_queue_params *qparam)
277462306a36Sopenharmony_ci{
277562306a36Sopenharmony_ci	struct ionic_queue_params start_qparams;
277662306a36Sopenharmony_ci	int err = 0;
277762306a36Sopenharmony_ci
277862306a36Sopenharmony_ci	/* When changing CMB queue parameters, we're using limited
277962306a36Sopenharmony_ci	 * on-device memory and don't have extra memory to use for
278062306a36Sopenharmony_ci	 * duplicate allocations, so we free it all first then
278162306a36Sopenharmony_ci	 * re-allocate with the new parameters.
278262306a36Sopenharmony_ci	 */
278362306a36Sopenharmony_ci
278462306a36Sopenharmony_ci	/* Checkpoint for possible unwind */
278562306a36Sopenharmony_ci	ionic_init_queue_params(lif, &start_qparams);
278662306a36Sopenharmony_ci
278762306a36Sopenharmony_ci	/* Stop and free the queues */
278862306a36Sopenharmony_ci	ionic_stop_queues_reconfig(lif);
278962306a36Sopenharmony_ci	ionic_txrx_free(lif);
279062306a36Sopenharmony_ci
279162306a36Sopenharmony_ci	/* Set up new qparams */
279262306a36Sopenharmony_ci	ionic_set_queue_params(lif, qparam);
279362306a36Sopenharmony_ci
279462306a36Sopenharmony_ci	if (netif_running(lif->netdev)) {
279562306a36Sopenharmony_ci		/* Alloc and start the new configuration */
279662306a36Sopenharmony_ci		err = ionic_txrx_alloc(lif);
279762306a36Sopenharmony_ci		if (err) {
279862306a36Sopenharmony_ci			dev_warn(lif->ionic->dev,
279962306a36Sopenharmony_ci				 "CMB reconfig failed, restoring values: %d\n", err);
280062306a36Sopenharmony_ci
280162306a36Sopenharmony_ci			/* Back out the changes */
280262306a36Sopenharmony_ci			ionic_set_queue_params(lif, &start_qparams);
280362306a36Sopenharmony_ci			err = ionic_txrx_alloc(lif);
280462306a36Sopenharmony_ci			if (err) {
280562306a36Sopenharmony_ci				dev_err(lif->ionic->dev,
280662306a36Sopenharmony_ci					"CMB restore failed: %d\n", err);
280762306a36Sopenharmony_ci				goto err_out;
280862306a36Sopenharmony_ci			}
280962306a36Sopenharmony_ci		}
281062306a36Sopenharmony_ci
281162306a36Sopenharmony_ci		err = ionic_start_queues_reconfig(lif);
281262306a36Sopenharmony_ci		if (err) {
281362306a36Sopenharmony_ci			dev_err(lif->ionic->dev,
281462306a36Sopenharmony_ci				"CMB reconfig failed: %d\n", err);
281562306a36Sopenharmony_ci			goto err_out;
281662306a36Sopenharmony_ci		}
281762306a36Sopenharmony_ci	}
281862306a36Sopenharmony_ci
281962306a36Sopenharmony_cierr_out:
282062306a36Sopenharmony_ci	/* This was detached in ionic_stop_queues_reconfig() */
282162306a36Sopenharmony_ci	netif_device_attach(lif->netdev);
282262306a36Sopenharmony_ci
282362306a36Sopenharmony_ci	return err;
282462306a36Sopenharmony_ci}
282562306a36Sopenharmony_ci
282662306a36Sopenharmony_cistatic void ionic_swap_queues(struct ionic_qcq *a, struct ionic_qcq *b)
282762306a36Sopenharmony_ci{
282862306a36Sopenharmony_ci	/* only swapping the queues, not the napi, flags, or other stuff */
282962306a36Sopenharmony_ci	swap(a->q.features,   b->q.features);
283062306a36Sopenharmony_ci	swap(a->q.num_descs,  b->q.num_descs);
283162306a36Sopenharmony_ci	swap(a->q.desc_size,  b->q.desc_size);
283262306a36Sopenharmony_ci	swap(a->q.base,       b->q.base);
283362306a36Sopenharmony_ci	swap(a->q.base_pa,    b->q.base_pa);
283462306a36Sopenharmony_ci	swap(a->q.info,       b->q.info);
283562306a36Sopenharmony_ci	swap(a->q_base,       b->q_base);
283662306a36Sopenharmony_ci	swap(a->q_base_pa,    b->q_base_pa);
283762306a36Sopenharmony_ci	swap(a->q_size,       b->q_size);
283862306a36Sopenharmony_ci
283962306a36Sopenharmony_ci	swap(a->q.sg_desc_size, b->q.sg_desc_size);
284062306a36Sopenharmony_ci	swap(a->q.sg_base,    b->q.sg_base);
284162306a36Sopenharmony_ci	swap(a->q.sg_base_pa, b->q.sg_base_pa);
284262306a36Sopenharmony_ci	swap(a->sg_base,      b->sg_base);
284362306a36Sopenharmony_ci	swap(a->sg_base_pa,   b->sg_base_pa);
284462306a36Sopenharmony_ci	swap(a->sg_size,      b->sg_size);
284562306a36Sopenharmony_ci
284662306a36Sopenharmony_ci	swap(a->cq.num_descs, b->cq.num_descs);
284762306a36Sopenharmony_ci	swap(a->cq.desc_size, b->cq.desc_size);
284862306a36Sopenharmony_ci	swap(a->cq.base,      b->cq.base);
284962306a36Sopenharmony_ci	swap(a->cq.base_pa,   b->cq.base_pa);
285062306a36Sopenharmony_ci	swap(a->cq.info,      b->cq.info);
285162306a36Sopenharmony_ci	swap(a->cq_base,      b->cq_base);
285262306a36Sopenharmony_ci	swap(a->cq_base_pa,   b->cq_base_pa);
285362306a36Sopenharmony_ci	swap(a->cq_size,      b->cq_size);
285462306a36Sopenharmony_ci
285562306a36Sopenharmony_ci	ionic_debugfs_del_qcq(a);
285662306a36Sopenharmony_ci	ionic_debugfs_add_qcq(a->q.lif, a);
285762306a36Sopenharmony_ci}
285862306a36Sopenharmony_ci
285962306a36Sopenharmony_ciint ionic_reconfigure_queues(struct ionic_lif *lif,
286062306a36Sopenharmony_ci			     struct ionic_queue_params *qparam)
286162306a36Sopenharmony_ci{
286262306a36Sopenharmony_ci	unsigned int comp_sz, desc_sz, num_desc, sg_desc_sz;
286362306a36Sopenharmony_ci	struct ionic_qcq **tx_qcqs = NULL;
286462306a36Sopenharmony_ci	struct ionic_qcq **rx_qcqs = NULL;
286562306a36Sopenharmony_ci	unsigned int flags, i;
286662306a36Sopenharmony_ci	int err = 0;
286762306a36Sopenharmony_ci
286862306a36Sopenharmony_ci	/* Are we changing q params while CMB is on */
286962306a36Sopenharmony_ci	if ((test_bit(IONIC_LIF_F_CMB_TX_RINGS, lif->state) && qparam->cmb_tx) ||
287062306a36Sopenharmony_ci	    (test_bit(IONIC_LIF_F_CMB_RX_RINGS, lif->state) && qparam->cmb_rx))
287162306a36Sopenharmony_ci		return ionic_cmb_reconfig(lif, qparam);
287262306a36Sopenharmony_ci
287362306a36Sopenharmony_ci	/* allocate temporary qcq arrays to hold new queue structs */
287462306a36Sopenharmony_ci	if (qparam->nxqs != lif->nxqs || qparam->ntxq_descs != lif->ntxq_descs) {
287562306a36Sopenharmony_ci		tx_qcqs = devm_kcalloc(lif->ionic->dev, lif->ionic->ntxqs_per_lif,
287662306a36Sopenharmony_ci				       sizeof(struct ionic_qcq *), GFP_KERNEL);
287762306a36Sopenharmony_ci		if (!tx_qcqs) {
287862306a36Sopenharmony_ci			err = -ENOMEM;
287962306a36Sopenharmony_ci			goto err_out;
288062306a36Sopenharmony_ci		}
288162306a36Sopenharmony_ci	}
288262306a36Sopenharmony_ci	if (qparam->nxqs != lif->nxqs ||
288362306a36Sopenharmony_ci	    qparam->nrxq_descs != lif->nrxq_descs ||
288462306a36Sopenharmony_ci	    qparam->rxq_features != lif->rxq_features) {
288562306a36Sopenharmony_ci		rx_qcqs = devm_kcalloc(lif->ionic->dev, lif->ionic->nrxqs_per_lif,
288662306a36Sopenharmony_ci				       sizeof(struct ionic_qcq *), GFP_KERNEL);
288762306a36Sopenharmony_ci		if (!rx_qcqs) {
288862306a36Sopenharmony_ci			err = -ENOMEM;
288962306a36Sopenharmony_ci			goto err_out;
289062306a36Sopenharmony_ci		}
289162306a36Sopenharmony_ci	}
289262306a36Sopenharmony_ci
289362306a36Sopenharmony_ci	/* allocate new desc_info and rings, but leave the interrupt setup
289462306a36Sopenharmony_ci	 * until later so as to not mess with the still-running queues
289562306a36Sopenharmony_ci	 */
289662306a36Sopenharmony_ci	if (tx_qcqs) {
289762306a36Sopenharmony_ci		num_desc = qparam->ntxq_descs;
289862306a36Sopenharmony_ci		desc_sz = sizeof(struct ionic_txq_desc);
289962306a36Sopenharmony_ci		comp_sz = sizeof(struct ionic_txq_comp);
290062306a36Sopenharmony_ci
290162306a36Sopenharmony_ci		if (lif->qtype_info[IONIC_QTYPE_TXQ].version >= 1 &&
290262306a36Sopenharmony_ci		    lif->qtype_info[IONIC_QTYPE_TXQ].sg_desc_sz ==
290362306a36Sopenharmony_ci		    sizeof(struct ionic_txq_sg_desc_v1))
290462306a36Sopenharmony_ci			sg_desc_sz = sizeof(struct ionic_txq_sg_desc_v1);
290562306a36Sopenharmony_ci		else
290662306a36Sopenharmony_ci			sg_desc_sz = sizeof(struct ionic_txq_sg_desc);
290762306a36Sopenharmony_ci
290862306a36Sopenharmony_ci		for (i = 0; i < qparam->nxqs; i++) {
290962306a36Sopenharmony_ci			/* If missing, short placeholder qcq needed for swap */
291062306a36Sopenharmony_ci			if (!lif->txqcqs[i]) {
291162306a36Sopenharmony_ci				flags = IONIC_QCQ_F_TX_STATS | IONIC_QCQ_F_SG;
291262306a36Sopenharmony_ci				err = ionic_qcq_alloc(lif, IONIC_QTYPE_TXQ, i, "tx", flags,
291362306a36Sopenharmony_ci						      4, desc_sz, comp_sz, sg_desc_sz,
291462306a36Sopenharmony_ci						      lif->kern_pid, &lif->txqcqs[i]);
291562306a36Sopenharmony_ci				if (err)
291662306a36Sopenharmony_ci					goto err_out;
291762306a36Sopenharmony_ci			}
291862306a36Sopenharmony_ci
291962306a36Sopenharmony_ci			flags = lif->txqcqs[i]->flags & ~IONIC_QCQ_F_INTR;
292062306a36Sopenharmony_ci			err = ionic_qcq_alloc(lif, IONIC_QTYPE_TXQ, i, "tx", flags,
292162306a36Sopenharmony_ci					      num_desc, desc_sz, comp_sz, sg_desc_sz,
292262306a36Sopenharmony_ci					      lif->kern_pid, &tx_qcqs[i]);
292362306a36Sopenharmony_ci			if (err)
292462306a36Sopenharmony_ci				goto err_out;
292562306a36Sopenharmony_ci		}
292662306a36Sopenharmony_ci	}
292762306a36Sopenharmony_ci
292862306a36Sopenharmony_ci	if (rx_qcqs) {
292962306a36Sopenharmony_ci		num_desc = qparam->nrxq_descs;
293062306a36Sopenharmony_ci		desc_sz = sizeof(struct ionic_rxq_desc);
293162306a36Sopenharmony_ci		comp_sz = sizeof(struct ionic_rxq_comp);
293262306a36Sopenharmony_ci		sg_desc_sz = sizeof(struct ionic_rxq_sg_desc);
293362306a36Sopenharmony_ci
293462306a36Sopenharmony_ci		if (qparam->rxq_features & IONIC_Q_F_2X_CQ_DESC)
293562306a36Sopenharmony_ci			comp_sz *= 2;
293662306a36Sopenharmony_ci
293762306a36Sopenharmony_ci		for (i = 0; i < qparam->nxqs; i++) {
293862306a36Sopenharmony_ci			/* If missing, short placeholder qcq needed for swap */
293962306a36Sopenharmony_ci			if (!lif->rxqcqs[i]) {
294062306a36Sopenharmony_ci				flags = IONIC_QCQ_F_RX_STATS | IONIC_QCQ_F_SG;
294162306a36Sopenharmony_ci				err = ionic_qcq_alloc(lif, IONIC_QTYPE_RXQ, i, "rx", flags,
294262306a36Sopenharmony_ci						      4, desc_sz, comp_sz, sg_desc_sz,
294362306a36Sopenharmony_ci						      lif->kern_pid, &lif->rxqcqs[i]);
294462306a36Sopenharmony_ci				if (err)
294562306a36Sopenharmony_ci					goto err_out;
294662306a36Sopenharmony_ci			}
294762306a36Sopenharmony_ci
294862306a36Sopenharmony_ci			flags = lif->rxqcqs[i]->flags & ~IONIC_QCQ_F_INTR;
294962306a36Sopenharmony_ci			err = ionic_qcq_alloc(lif, IONIC_QTYPE_RXQ, i, "rx", flags,
295062306a36Sopenharmony_ci					      num_desc, desc_sz, comp_sz, sg_desc_sz,
295162306a36Sopenharmony_ci					      lif->kern_pid, &rx_qcqs[i]);
295262306a36Sopenharmony_ci			if (err)
295362306a36Sopenharmony_ci				goto err_out;
295462306a36Sopenharmony_ci
295562306a36Sopenharmony_ci			rx_qcqs[i]->q.features = qparam->rxq_features;
295662306a36Sopenharmony_ci		}
295762306a36Sopenharmony_ci	}
295862306a36Sopenharmony_ci
295962306a36Sopenharmony_ci	/* stop and clean the queues */
296062306a36Sopenharmony_ci	ionic_stop_queues_reconfig(lif);
296162306a36Sopenharmony_ci
296262306a36Sopenharmony_ci	if (qparam->nxqs != lif->nxqs) {
296362306a36Sopenharmony_ci		err = netif_set_real_num_tx_queues(lif->netdev, qparam->nxqs);
296462306a36Sopenharmony_ci		if (err)
296562306a36Sopenharmony_ci			goto err_out_reinit_unlock;
296662306a36Sopenharmony_ci		err = netif_set_real_num_rx_queues(lif->netdev, qparam->nxqs);
296762306a36Sopenharmony_ci		if (err) {
296862306a36Sopenharmony_ci			netif_set_real_num_tx_queues(lif->netdev, lif->nxqs);
296962306a36Sopenharmony_ci			goto err_out_reinit_unlock;
297062306a36Sopenharmony_ci		}
297162306a36Sopenharmony_ci	}
297262306a36Sopenharmony_ci
297362306a36Sopenharmony_ci	/* swap new desc_info and rings, keeping existing interrupt config */
297462306a36Sopenharmony_ci	if (tx_qcqs) {
297562306a36Sopenharmony_ci		lif->ntxq_descs = qparam->ntxq_descs;
297662306a36Sopenharmony_ci		for (i = 0; i < qparam->nxqs; i++)
297762306a36Sopenharmony_ci			ionic_swap_queues(lif->txqcqs[i], tx_qcqs[i]);
297862306a36Sopenharmony_ci	}
297962306a36Sopenharmony_ci
298062306a36Sopenharmony_ci	if (rx_qcqs) {
298162306a36Sopenharmony_ci		lif->nrxq_descs = qparam->nrxq_descs;
298262306a36Sopenharmony_ci		for (i = 0; i < qparam->nxqs; i++)
298362306a36Sopenharmony_ci			ionic_swap_queues(lif->rxqcqs[i], rx_qcqs[i]);
298462306a36Sopenharmony_ci	}
298562306a36Sopenharmony_ci
298662306a36Sopenharmony_ci	/* if we need to change the interrupt layout, this is the time */
298762306a36Sopenharmony_ci	if (qparam->intr_split != test_bit(IONIC_LIF_F_SPLIT_INTR, lif->state) ||
298862306a36Sopenharmony_ci	    qparam->nxqs != lif->nxqs) {
298962306a36Sopenharmony_ci		if (qparam->intr_split) {
299062306a36Sopenharmony_ci			set_bit(IONIC_LIF_F_SPLIT_INTR, lif->state);
299162306a36Sopenharmony_ci		} else {
299262306a36Sopenharmony_ci			clear_bit(IONIC_LIF_F_SPLIT_INTR, lif->state);
299362306a36Sopenharmony_ci			lif->tx_coalesce_usecs = lif->rx_coalesce_usecs;
299462306a36Sopenharmony_ci			lif->tx_coalesce_hw = lif->rx_coalesce_hw;
299562306a36Sopenharmony_ci		}
299662306a36Sopenharmony_ci
299762306a36Sopenharmony_ci		/* Clear existing interrupt assignments.  We check for NULL here
299862306a36Sopenharmony_ci		 * because we're checking the whole array for potential qcqs, not
299962306a36Sopenharmony_ci		 * just those qcqs that have just been set up.
300062306a36Sopenharmony_ci		 */
300162306a36Sopenharmony_ci		for (i = 0; i < lif->ionic->ntxqs_per_lif; i++) {
300262306a36Sopenharmony_ci			if (lif->txqcqs[i])
300362306a36Sopenharmony_ci				ionic_qcq_intr_free(lif, lif->txqcqs[i]);
300462306a36Sopenharmony_ci			if (lif->rxqcqs[i])
300562306a36Sopenharmony_ci				ionic_qcq_intr_free(lif, lif->rxqcqs[i]);
300662306a36Sopenharmony_ci		}
300762306a36Sopenharmony_ci
300862306a36Sopenharmony_ci		/* re-assign the interrupts */
300962306a36Sopenharmony_ci		for (i = 0; i < qparam->nxqs; i++) {
301062306a36Sopenharmony_ci			lif->rxqcqs[i]->flags |= IONIC_QCQ_F_INTR;
301162306a36Sopenharmony_ci			err = ionic_alloc_qcq_interrupt(lif, lif->rxqcqs[i]);
301262306a36Sopenharmony_ci			ionic_intr_coal_init(lif->ionic->idev.intr_ctrl,
301362306a36Sopenharmony_ci					     lif->rxqcqs[i]->intr.index,
301462306a36Sopenharmony_ci					     lif->rx_coalesce_hw);
301562306a36Sopenharmony_ci
301662306a36Sopenharmony_ci			if (qparam->intr_split) {
301762306a36Sopenharmony_ci				lif->txqcqs[i]->flags |= IONIC_QCQ_F_INTR;
301862306a36Sopenharmony_ci				err = ionic_alloc_qcq_interrupt(lif, lif->txqcqs[i]);
301962306a36Sopenharmony_ci				ionic_intr_coal_init(lif->ionic->idev.intr_ctrl,
302062306a36Sopenharmony_ci						     lif->txqcqs[i]->intr.index,
302162306a36Sopenharmony_ci						     lif->tx_coalesce_hw);
302262306a36Sopenharmony_ci				if (test_bit(IONIC_LIF_F_TX_DIM_INTR, lif->state))
302362306a36Sopenharmony_ci					lif->txqcqs[i]->intr.dim_coal_hw = lif->tx_coalesce_hw;
302462306a36Sopenharmony_ci			} else {
302562306a36Sopenharmony_ci				lif->txqcqs[i]->flags &= ~IONIC_QCQ_F_INTR;
302662306a36Sopenharmony_ci				ionic_link_qcq_interrupts(lif->rxqcqs[i], lif->txqcqs[i]);
302762306a36Sopenharmony_ci			}
302862306a36Sopenharmony_ci		}
302962306a36Sopenharmony_ci	}
303062306a36Sopenharmony_ci
303162306a36Sopenharmony_ci	/* now we can rework the debugfs mappings */
303262306a36Sopenharmony_ci	if (tx_qcqs) {
303362306a36Sopenharmony_ci		for (i = 0; i < qparam->nxqs; i++) {
303462306a36Sopenharmony_ci			ionic_debugfs_del_qcq(lif->txqcqs[i]);
303562306a36Sopenharmony_ci			ionic_debugfs_add_qcq(lif, lif->txqcqs[i]);
303662306a36Sopenharmony_ci		}
303762306a36Sopenharmony_ci	}
303862306a36Sopenharmony_ci
303962306a36Sopenharmony_ci	if (rx_qcqs) {
304062306a36Sopenharmony_ci		for (i = 0; i < qparam->nxqs; i++) {
304162306a36Sopenharmony_ci			ionic_debugfs_del_qcq(lif->rxqcqs[i]);
304262306a36Sopenharmony_ci			ionic_debugfs_add_qcq(lif, lif->rxqcqs[i]);
304362306a36Sopenharmony_ci		}
304462306a36Sopenharmony_ci	}
304562306a36Sopenharmony_ci
304662306a36Sopenharmony_ci	swap(lif->nxqs, qparam->nxqs);
304762306a36Sopenharmony_ci	swap(lif->rxq_features, qparam->rxq_features);
304862306a36Sopenharmony_ci
304962306a36Sopenharmony_cierr_out_reinit_unlock:
305062306a36Sopenharmony_ci	/* re-init the queues, but don't lose an error code */
305162306a36Sopenharmony_ci	if (err)
305262306a36Sopenharmony_ci		ionic_start_queues_reconfig(lif);
305362306a36Sopenharmony_ci	else
305462306a36Sopenharmony_ci		err = ionic_start_queues_reconfig(lif);
305562306a36Sopenharmony_ci
305662306a36Sopenharmony_cierr_out:
305762306a36Sopenharmony_ci	/* free old allocs without cleaning intr */
305862306a36Sopenharmony_ci	for (i = 0; i < qparam->nxqs; i++) {
305962306a36Sopenharmony_ci		if (tx_qcqs && tx_qcqs[i]) {
306062306a36Sopenharmony_ci			tx_qcqs[i]->flags &= ~IONIC_QCQ_F_INTR;
306162306a36Sopenharmony_ci			ionic_qcq_free(lif, tx_qcqs[i]);
306262306a36Sopenharmony_ci			devm_kfree(lif->ionic->dev, tx_qcqs[i]);
306362306a36Sopenharmony_ci			tx_qcqs[i] = NULL;
306462306a36Sopenharmony_ci		}
306562306a36Sopenharmony_ci		if (rx_qcqs && rx_qcqs[i]) {
306662306a36Sopenharmony_ci			rx_qcqs[i]->flags &= ~IONIC_QCQ_F_INTR;
306762306a36Sopenharmony_ci			ionic_qcq_free(lif, rx_qcqs[i]);
306862306a36Sopenharmony_ci			devm_kfree(lif->ionic->dev, rx_qcqs[i]);
306962306a36Sopenharmony_ci			rx_qcqs[i] = NULL;
307062306a36Sopenharmony_ci		}
307162306a36Sopenharmony_ci	}
307262306a36Sopenharmony_ci
307362306a36Sopenharmony_ci	/* free q array */
307462306a36Sopenharmony_ci	if (rx_qcqs) {
307562306a36Sopenharmony_ci		devm_kfree(lif->ionic->dev, rx_qcqs);
307662306a36Sopenharmony_ci		rx_qcqs = NULL;
307762306a36Sopenharmony_ci	}
307862306a36Sopenharmony_ci	if (tx_qcqs) {
307962306a36Sopenharmony_ci		devm_kfree(lif->ionic->dev, tx_qcqs);
308062306a36Sopenharmony_ci		tx_qcqs = NULL;
308162306a36Sopenharmony_ci	}
308262306a36Sopenharmony_ci
308362306a36Sopenharmony_ci	/* clean the unused dma and info allocations when new set is smaller
308462306a36Sopenharmony_ci	 * than the full array, but leave the qcq shells in place
308562306a36Sopenharmony_ci	 */
308662306a36Sopenharmony_ci	for (i = lif->nxqs; i < lif->ionic->ntxqs_per_lif; i++) {
308762306a36Sopenharmony_ci		if (lif->txqcqs && lif->txqcqs[i]) {
308862306a36Sopenharmony_ci			lif->txqcqs[i]->flags &= ~IONIC_QCQ_F_INTR;
308962306a36Sopenharmony_ci			ionic_qcq_free(lif, lif->txqcqs[i]);
309062306a36Sopenharmony_ci		}
309162306a36Sopenharmony_ci
309262306a36Sopenharmony_ci		if (lif->rxqcqs && lif->rxqcqs[i]) {
309362306a36Sopenharmony_ci			lif->rxqcqs[i]->flags &= ~IONIC_QCQ_F_INTR;
309462306a36Sopenharmony_ci			ionic_qcq_free(lif, lif->rxqcqs[i]);
309562306a36Sopenharmony_ci		}
309662306a36Sopenharmony_ci	}
309762306a36Sopenharmony_ci
309862306a36Sopenharmony_ci	if (err)
309962306a36Sopenharmony_ci		netdev_info(lif->netdev, "%s: failed %d\n", __func__, err);
310062306a36Sopenharmony_ci
310162306a36Sopenharmony_ci	return err;
310262306a36Sopenharmony_ci}
310362306a36Sopenharmony_ci
310462306a36Sopenharmony_ciint ionic_lif_alloc(struct ionic *ionic)
310562306a36Sopenharmony_ci{
310662306a36Sopenharmony_ci	struct device *dev = ionic->dev;
310762306a36Sopenharmony_ci	union ionic_lif_identity *lid;
310862306a36Sopenharmony_ci	struct net_device *netdev;
310962306a36Sopenharmony_ci	struct ionic_lif *lif;
311062306a36Sopenharmony_ci	int tbl_sz;
311162306a36Sopenharmony_ci	int err;
311262306a36Sopenharmony_ci
311362306a36Sopenharmony_ci	lid = kzalloc(sizeof(*lid), GFP_KERNEL);
311462306a36Sopenharmony_ci	if (!lid)
311562306a36Sopenharmony_ci		return -ENOMEM;
311662306a36Sopenharmony_ci
311762306a36Sopenharmony_ci	netdev = alloc_etherdev_mqs(sizeof(*lif),
311862306a36Sopenharmony_ci				    ionic->ntxqs_per_lif, ionic->ntxqs_per_lif);
311962306a36Sopenharmony_ci	if (!netdev) {
312062306a36Sopenharmony_ci		dev_err(dev, "Cannot allocate netdev, aborting\n");
312162306a36Sopenharmony_ci		err = -ENOMEM;
312262306a36Sopenharmony_ci		goto err_out_free_lid;
312362306a36Sopenharmony_ci	}
312462306a36Sopenharmony_ci
312562306a36Sopenharmony_ci	SET_NETDEV_DEV(netdev, dev);
312662306a36Sopenharmony_ci
312762306a36Sopenharmony_ci	lif = netdev_priv(netdev);
312862306a36Sopenharmony_ci	lif->netdev = netdev;
312962306a36Sopenharmony_ci	ionic->lif = lif;
313062306a36Sopenharmony_ci	netdev->netdev_ops = &ionic_netdev_ops;
313162306a36Sopenharmony_ci	ionic_ethtool_set_ops(netdev);
313262306a36Sopenharmony_ci
313362306a36Sopenharmony_ci	netdev->watchdog_timeo = 2 * HZ;
313462306a36Sopenharmony_ci	netif_carrier_off(netdev);
313562306a36Sopenharmony_ci
313662306a36Sopenharmony_ci	lif->identity = lid;
313762306a36Sopenharmony_ci	lif->lif_type = IONIC_LIF_TYPE_CLASSIC;
313862306a36Sopenharmony_ci	err = ionic_lif_identify(ionic, lif->lif_type, lif->identity);
313962306a36Sopenharmony_ci	if (err) {
314062306a36Sopenharmony_ci		dev_err(ionic->dev, "Cannot identify type %d: %d\n",
314162306a36Sopenharmony_ci			lif->lif_type, err);
314262306a36Sopenharmony_ci		goto err_out_free_netdev;
314362306a36Sopenharmony_ci	}
314462306a36Sopenharmony_ci	lif->netdev->min_mtu = max_t(unsigned int, ETH_MIN_MTU,
314562306a36Sopenharmony_ci				     le32_to_cpu(lif->identity->eth.min_frame_size));
314662306a36Sopenharmony_ci	lif->netdev->max_mtu =
314762306a36Sopenharmony_ci		le32_to_cpu(lif->identity->eth.max_frame_size) - ETH_HLEN - VLAN_HLEN;
314862306a36Sopenharmony_ci
314962306a36Sopenharmony_ci	lif->neqs = ionic->neqs_per_lif;
315062306a36Sopenharmony_ci	lif->nxqs = ionic->ntxqs_per_lif;
315162306a36Sopenharmony_ci
315262306a36Sopenharmony_ci	lif->ionic = ionic;
315362306a36Sopenharmony_ci	lif->index = 0;
315462306a36Sopenharmony_ci
315562306a36Sopenharmony_ci	if (is_kdump_kernel()) {
315662306a36Sopenharmony_ci		lif->ntxq_descs = IONIC_MIN_TXRX_DESC;
315762306a36Sopenharmony_ci		lif->nrxq_descs = IONIC_MIN_TXRX_DESC;
315862306a36Sopenharmony_ci	} else {
315962306a36Sopenharmony_ci		lif->ntxq_descs = IONIC_DEF_TXRX_DESC;
316062306a36Sopenharmony_ci		lif->nrxq_descs = IONIC_DEF_TXRX_DESC;
316162306a36Sopenharmony_ci	}
316262306a36Sopenharmony_ci
316362306a36Sopenharmony_ci	/* Convert the default coalesce value to actual hw resolution */
316462306a36Sopenharmony_ci	lif->rx_coalesce_usecs = IONIC_ITR_COAL_USEC_DEFAULT;
316562306a36Sopenharmony_ci	lif->rx_coalesce_hw = ionic_coal_usec_to_hw(lif->ionic,
316662306a36Sopenharmony_ci						    lif->rx_coalesce_usecs);
316762306a36Sopenharmony_ci	lif->tx_coalesce_usecs = lif->rx_coalesce_usecs;
316862306a36Sopenharmony_ci	lif->tx_coalesce_hw = lif->rx_coalesce_hw;
316962306a36Sopenharmony_ci	set_bit(IONIC_LIF_F_RX_DIM_INTR, lif->state);
317062306a36Sopenharmony_ci	set_bit(IONIC_LIF_F_TX_DIM_INTR, lif->state);
317162306a36Sopenharmony_ci
317262306a36Sopenharmony_ci	snprintf(lif->name, sizeof(lif->name), "lif%u", lif->index);
317362306a36Sopenharmony_ci
317462306a36Sopenharmony_ci	mutex_init(&lif->queue_lock);
317562306a36Sopenharmony_ci	mutex_init(&lif->config_lock);
317662306a36Sopenharmony_ci
317762306a36Sopenharmony_ci	spin_lock_init(&lif->adminq_lock);
317862306a36Sopenharmony_ci
317962306a36Sopenharmony_ci	spin_lock_init(&lif->deferred.lock);
318062306a36Sopenharmony_ci	INIT_LIST_HEAD(&lif->deferred.list);
318162306a36Sopenharmony_ci	INIT_WORK(&lif->deferred.work, ionic_lif_deferred_work);
318262306a36Sopenharmony_ci
318362306a36Sopenharmony_ci	/* allocate lif info */
318462306a36Sopenharmony_ci	lif->info_sz = ALIGN(sizeof(*lif->info), PAGE_SIZE);
318562306a36Sopenharmony_ci	lif->info = dma_alloc_coherent(dev, lif->info_sz,
318662306a36Sopenharmony_ci				       &lif->info_pa, GFP_KERNEL);
318762306a36Sopenharmony_ci	if (!lif->info) {
318862306a36Sopenharmony_ci		dev_err(dev, "Failed to allocate lif info, aborting\n");
318962306a36Sopenharmony_ci		err = -ENOMEM;
319062306a36Sopenharmony_ci		goto err_out_free_mutex;
319162306a36Sopenharmony_ci	}
319262306a36Sopenharmony_ci
319362306a36Sopenharmony_ci	ionic_debugfs_add_lif(lif);
319462306a36Sopenharmony_ci
319562306a36Sopenharmony_ci	/* allocate control queues and txrx queue arrays */
319662306a36Sopenharmony_ci	ionic_lif_queue_identify(lif);
319762306a36Sopenharmony_ci	err = ionic_qcqs_alloc(lif);
319862306a36Sopenharmony_ci	if (err)
319962306a36Sopenharmony_ci		goto err_out_free_lif_info;
320062306a36Sopenharmony_ci
320162306a36Sopenharmony_ci	/* allocate rss indirection table */
320262306a36Sopenharmony_ci	tbl_sz = le16_to_cpu(lif->ionic->ident.lif.eth.rss_ind_tbl_sz);
320362306a36Sopenharmony_ci	lif->rss_ind_tbl_sz = sizeof(*lif->rss_ind_tbl) * tbl_sz;
320462306a36Sopenharmony_ci	lif->rss_ind_tbl = dma_alloc_coherent(dev, lif->rss_ind_tbl_sz,
320562306a36Sopenharmony_ci					      &lif->rss_ind_tbl_pa,
320662306a36Sopenharmony_ci					      GFP_KERNEL);
320762306a36Sopenharmony_ci
320862306a36Sopenharmony_ci	if (!lif->rss_ind_tbl) {
320962306a36Sopenharmony_ci		err = -ENOMEM;
321062306a36Sopenharmony_ci		dev_err(dev, "Failed to allocate rss indirection table, aborting\n");
321162306a36Sopenharmony_ci		goto err_out_free_qcqs;
321262306a36Sopenharmony_ci	}
321362306a36Sopenharmony_ci	netdev_rss_key_fill(lif->rss_hash_key, IONIC_RSS_HASH_KEY_SIZE);
321462306a36Sopenharmony_ci
321562306a36Sopenharmony_ci	ionic_lif_alloc_phc(lif);
321662306a36Sopenharmony_ci
321762306a36Sopenharmony_ci	return 0;
321862306a36Sopenharmony_ci
321962306a36Sopenharmony_cierr_out_free_qcqs:
322062306a36Sopenharmony_ci	ionic_qcqs_free(lif);
322162306a36Sopenharmony_cierr_out_free_lif_info:
322262306a36Sopenharmony_ci	dma_free_coherent(dev, lif->info_sz, lif->info, lif->info_pa);
322362306a36Sopenharmony_ci	lif->info = NULL;
322462306a36Sopenharmony_ci	lif->info_pa = 0;
322562306a36Sopenharmony_cierr_out_free_mutex:
322662306a36Sopenharmony_ci	mutex_destroy(&lif->config_lock);
322762306a36Sopenharmony_ci	mutex_destroy(&lif->queue_lock);
322862306a36Sopenharmony_cierr_out_free_netdev:
322962306a36Sopenharmony_ci	free_netdev(lif->netdev);
323062306a36Sopenharmony_ci	lif = NULL;
323162306a36Sopenharmony_cierr_out_free_lid:
323262306a36Sopenharmony_ci	kfree(lid);
323362306a36Sopenharmony_ci
323462306a36Sopenharmony_ci	return err;
323562306a36Sopenharmony_ci}
323662306a36Sopenharmony_ci
323762306a36Sopenharmony_cistatic void ionic_lif_reset(struct ionic_lif *lif)
323862306a36Sopenharmony_ci{
323962306a36Sopenharmony_ci	struct ionic_dev *idev = &lif->ionic->idev;
324062306a36Sopenharmony_ci
324162306a36Sopenharmony_ci	if (!ionic_is_fw_running(idev))
324262306a36Sopenharmony_ci		return;
324362306a36Sopenharmony_ci
324462306a36Sopenharmony_ci	mutex_lock(&lif->ionic->dev_cmd_lock);
324562306a36Sopenharmony_ci	ionic_dev_cmd_lif_reset(idev, lif->index);
324662306a36Sopenharmony_ci	ionic_dev_cmd_wait(lif->ionic, DEVCMD_TIMEOUT);
324762306a36Sopenharmony_ci	mutex_unlock(&lif->ionic->dev_cmd_lock);
324862306a36Sopenharmony_ci}
324962306a36Sopenharmony_ci
325062306a36Sopenharmony_cistatic void ionic_lif_handle_fw_down(struct ionic_lif *lif)
325162306a36Sopenharmony_ci{
325262306a36Sopenharmony_ci	struct ionic *ionic = lif->ionic;
325362306a36Sopenharmony_ci
325462306a36Sopenharmony_ci	if (test_and_set_bit(IONIC_LIF_F_FW_RESET, lif->state))
325562306a36Sopenharmony_ci		return;
325662306a36Sopenharmony_ci
325762306a36Sopenharmony_ci	dev_info(ionic->dev, "FW Down: Stopping LIFs\n");
325862306a36Sopenharmony_ci
325962306a36Sopenharmony_ci	netif_device_detach(lif->netdev);
326062306a36Sopenharmony_ci
326162306a36Sopenharmony_ci	mutex_lock(&lif->queue_lock);
326262306a36Sopenharmony_ci	if (test_bit(IONIC_LIF_F_UP, lif->state)) {
326362306a36Sopenharmony_ci		dev_info(ionic->dev, "Surprise FW stop, stopping queues\n");
326462306a36Sopenharmony_ci		ionic_stop_queues(lif);
326562306a36Sopenharmony_ci	}
326662306a36Sopenharmony_ci
326762306a36Sopenharmony_ci	if (netif_running(lif->netdev)) {
326862306a36Sopenharmony_ci		ionic_txrx_deinit(lif);
326962306a36Sopenharmony_ci		ionic_txrx_free(lif);
327062306a36Sopenharmony_ci	}
327162306a36Sopenharmony_ci	ionic_lif_deinit(lif);
327262306a36Sopenharmony_ci	ionic_reset(ionic);
327362306a36Sopenharmony_ci	ionic_qcqs_free(lif);
327462306a36Sopenharmony_ci
327562306a36Sopenharmony_ci	mutex_unlock(&lif->queue_lock);
327662306a36Sopenharmony_ci
327762306a36Sopenharmony_ci	clear_bit(IONIC_LIF_F_FW_STOPPING, lif->state);
327862306a36Sopenharmony_ci	dev_info(ionic->dev, "FW Down: LIFs stopped\n");
327962306a36Sopenharmony_ci}
328062306a36Sopenharmony_ci
328162306a36Sopenharmony_ciint ionic_restart_lif(struct ionic_lif *lif)
328262306a36Sopenharmony_ci{
328362306a36Sopenharmony_ci	struct ionic *ionic = lif->ionic;
328462306a36Sopenharmony_ci	int err;
328562306a36Sopenharmony_ci
328662306a36Sopenharmony_ci	mutex_lock(&lif->queue_lock);
328762306a36Sopenharmony_ci
328862306a36Sopenharmony_ci	if (test_and_clear_bit(IONIC_LIF_F_BROKEN, lif->state))
328962306a36Sopenharmony_ci		dev_info(ionic->dev, "FW Up: clearing broken state\n");
329062306a36Sopenharmony_ci
329162306a36Sopenharmony_ci	err = ionic_qcqs_alloc(lif);
329262306a36Sopenharmony_ci	if (err)
329362306a36Sopenharmony_ci		goto err_unlock;
329462306a36Sopenharmony_ci
329562306a36Sopenharmony_ci	err = ionic_lif_init(lif);
329662306a36Sopenharmony_ci	if (err)
329762306a36Sopenharmony_ci		goto err_qcqs_free;
329862306a36Sopenharmony_ci
329962306a36Sopenharmony_ci	ionic_vf_attr_replay(lif);
330062306a36Sopenharmony_ci
330162306a36Sopenharmony_ci	if (lif->registered)
330262306a36Sopenharmony_ci		ionic_lif_set_netdev_info(lif);
330362306a36Sopenharmony_ci
330462306a36Sopenharmony_ci	ionic_rx_filter_replay(lif);
330562306a36Sopenharmony_ci
330662306a36Sopenharmony_ci	if (netif_running(lif->netdev)) {
330762306a36Sopenharmony_ci		err = ionic_txrx_alloc(lif);
330862306a36Sopenharmony_ci		if (err)
330962306a36Sopenharmony_ci			goto err_lifs_deinit;
331062306a36Sopenharmony_ci
331162306a36Sopenharmony_ci		err = ionic_txrx_init(lif);
331262306a36Sopenharmony_ci		if (err)
331362306a36Sopenharmony_ci			goto err_txrx_free;
331462306a36Sopenharmony_ci	}
331562306a36Sopenharmony_ci
331662306a36Sopenharmony_ci	mutex_unlock(&lif->queue_lock);
331762306a36Sopenharmony_ci
331862306a36Sopenharmony_ci	clear_bit(IONIC_LIF_F_FW_RESET, lif->state);
331962306a36Sopenharmony_ci	ionic_link_status_check_request(lif, CAN_SLEEP);
332062306a36Sopenharmony_ci	netif_device_attach(lif->netdev);
332162306a36Sopenharmony_ci
332262306a36Sopenharmony_ci	return 0;
332362306a36Sopenharmony_ci
332462306a36Sopenharmony_cierr_txrx_free:
332562306a36Sopenharmony_ci	ionic_txrx_free(lif);
332662306a36Sopenharmony_cierr_lifs_deinit:
332762306a36Sopenharmony_ci	ionic_lif_deinit(lif);
332862306a36Sopenharmony_cierr_qcqs_free:
332962306a36Sopenharmony_ci	ionic_qcqs_free(lif);
333062306a36Sopenharmony_cierr_unlock:
333162306a36Sopenharmony_ci	mutex_unlock(&lif->queue_lock);
333262306a36Sopenharmony_ci
333362306a36Sopenharmony_ci	return err;
333462306a36Sopenharmony_ci}
333562306a36Sopenharmony_ci
333662306a36Sopenharmony_cistatic void ionic_lif_handle_fw_up(struct ionic_lif *lif)
333762306a36Sopenharmony_ci{
333862306a36Sopenharmony_ci	struct ionic *ionic = lif->ionic;
333962306a36Sopenharmony_ci	int err;
334062306a36Sopenharmony_ci
334162306a36Sopenharmony_ci	if (!test_bit(IONIC_LIF_F_FW_RESET, lif->state))
334262306a36Sopenharmony_ci		return;
334362306a36Sopenharmony_ci
334462306a36Sopenharmony_ci	dev_info(ionic->dev, "FW Up: restarting LIFs\n");
334562306a36Sopenharmony_ci
334662306a36Sopenharmony_ci	/* This is a little different from what happens at
334762306a36Sopenharmony_ci	 * probe time because the LIF already exists so we
334862306a36Sopenharmony_ci	 * just need to reanimate it.
334962306a36Sopenharmony_ci	 */
335062306a36Sopenharmony_ci	ionic_init_devinfo(ionic);
335162306a36Sopenharmony_ci	err = ionic_identify(ionic);
335262306a36Sopenharmony_ci	if (err)
335362306a36Sopenharmony_ci		goto err_out;
335462306a36Sopenharmony_ci	err = ionic_port_identify(ionic);
335562306a36Sopenharmony_ci	if (err)
335662306a36Sopenharmony_ci		goto err_out;
335762306a36Sopenharmony_ci	err = ionic_port_init(ionic);
335862306a36Sopenharmony_ci	if (err)
335962306a36Sopenharmony_ci		goto err_out;
336062306a36Sopenharmony_ci
336162306a36Sopenharmony_ci	err = ionic_restart_lif(lif);
336262306a36Sopenharmony_ci	if (err)
336362306a36Sopenharmony_ci		goto err_out;
336462306a36Sopenharmony_ci
336562306a36Sopenharmony_ci	dev_info(ionic->dev, "FW Up: LIFs restarted\n");
336662306a36Sopenharmony_ci
336762306a36Sopenharmony_ci	/* restore the hardware timestamping queues */
336862306a36Sopenharmony_ci	ionic_lif_hwstamp_replay(lif);
336962306a36Sopenharmony_ci
337062306a36Sopenharmony_ci	return;
337162306a36Sopenharmony_ci
337262306a36Sopenharmony_cierr_out:
337362306a36Sopenharmony_ci	dev_err(ionic->dev, "FW Up: LIFs restart failed - err %d\n", err);
337462306a36Sopenharmony_ci}
337562306a36Sopenharmony_ci
337662306a36Sopenharmony_civoid ionic_lif_free(struct ionic_lif *lif)
337762306a36Sopenharmony_ci{
337862306a36Sopenharmony_ci	struct device *dev = lif->ionic->dev;
337962306a36Sopenharmony_ci
338062306a36Sopenharmony_ci	ionic_lif_free_phc(lif);
338162306a36Sopenharmony_ci
338262306a36Sopenharmony_ci	/* free rss indirection table */
338362306a36Sopenharmony_ci	dma_free_coherent(dev, lif->rss_ind_tbl_sz, lif->rss_ind_tbl,
338462306a36Sopenharmony_ci			  lif->rss_ind_tbl_pa);
338562306a36Sopenharmony_ci	lif->rss_ind_tbl = NULL;
338662306a36Sopenharmony_ci	lif->rss_ind_tbl_pa = 0;
338762306a36Sopenharmony_ci
338862306a36Sopenharmony_ci	/* free queues */
338962306a36Sopenharmony_ci	ionic_qcqs_free(lif);
339062306a36Sopenharmony_ci	if (!test_bit(IONIC_LIF_F_FW_RESET, lif->state))
339162306a36Sopenharmony_ci		ionic_lif_reset(lif);
339262306a36Sopenharmony_ci
339362306a36Sopenharmony_ci	/* free lif info */
339462306a36Sopenharmony_ci	kfree(lif->identity);
339562306a36Sopenharmony_ci	dma_free_coherent(dev, lif->info_sz, lif->info, lif->info_pa);
339662306a36Sopenharmony_ci	lif->info = NULL;
339762306a36Sopenharmony_ci	lif->info_pa = 0;
339862306a36Sopenharmony_ci
339962306a36Sopenharmony_ci	/* unmap doorbell page */
340062306a36Sopenharmony_ci	ionic_bus_unmap_dbpage(lif->ionic, lif->kern_dbpage);
340162306a36Sopenharmony_ci	lif->kern_dbpage = NULL;
340262306a36Sopenharmony_ci
340362306a36Sopenharmony_ci	mutex_destroy(&lif->config_lock);
340462306a36Sopenharmony_ci	mutex_destroy(&lif->queue_lock);
340562306a36Sopenharmony_ci
340662306a36Sopenharmony_ci	/* free netdev & lif */
340762306a36Sopenharmony_ci	ionic_debugfs_del_lif(lif);
340862306a36Sopenharmony_ci	free_netdev(lif->netdev);
340962306a36Sopenharmony_ci}
341062306a36Sopenharmony_ci
341162306a36Sopenharmony_civoid ionic_lif_deinit(struct ionic_lif *lif)
341262306a36Sopenharmony_ci{
341362306a36Sopenharmony_ci	if (!test_and_clear_bit(IONIC_LIF_F_INITED, lif->state))
341462306a36Sopenharmony_ci		return;
341562306a36Sopenharmony_ci
341662306a36Sopenharmony_ci	if (!test_bit(IONIC_LIF_F_FW_RESET, lif->state)) {
341762306a36Sopenharmony_ci		cancel_work_sync(&lif->deferred.work);
341862306a36Sopenharmony_ci		cancel_work_sync(&lif->tx_timeout_work);
341962306a36Sopenharmony_ci		ionic_rx_filters_deinit(lif);
342062306a36Sopenharmony_ci		if (lif->netdev->features & NETIF_F_RXHASH)
342162306a36Sopenharmony_ci			ionic_lif_rss_deinit(lif);
342262306a36Sopenharmony_ci	}
342362306a36Sopenharmony_ci
342462306a36Sopenharmony_ci	napi_disable(&lif->adminqcq->napi);
342562306a36Sopenharmony_ci	ionic_lif_qcq_deinit(lif, lif->notifyqcq);
342662306a36Sopenharmony_ci	ionic_lif_qcq_deinit(lif, lif->adminqcq);
342762306a36Sopenharmony_ci
342862306a36Sopenharmony_ci	ionic_lif_reset(lif);
342962306a36Sopenharmony_ci}
343062306a36Sopenharmony_ci
343162306a36Sopenharmony_cistatic int ionic_lif_adminq_init(struct ionic_lif *lif)
343262306a36Sopenharmony_ci{
343362306a36Sopenharmony_ci	struct device *dev = lif->ionic->dev;
343462306a36Sopenharmony_ci	struct ionic_q_init_comp comp;
343562306a36Sopenharmony_ci	struct ionic_dev *idev;
343662306a36Sopenharmony_ci	struct ionic_qcq *qcq;
343762306a36Sopenharmony_ci	struct ionic_queue *q;
343862306a36Sopenharmony_ci	int err;
343962306a36Sopenharmony_ci
344062306a36Sopenharmony_ci	idev = &lif->ionic->idev;
344162306a36Sopenharmony_ci	qcq = lif->adminqcq;
344262306a36Sopenharmony_ci	q = &qcq->q;
344362306a36Sopenharmony_ci
344462306a36Sopenharmony_ci	mutex_lock(&lif->ionic->dev_cmd_lock);
344562306a36Sopenharmony_ci	ionic_dev_cmd_adminq_init(idev, qcq, lif->index, qcq->intr.index);
344662306a36Sopenharmony_ci	err = ionic_dev_cmd_wait(lif->ionic, DEVCMD_TIMEOUT);
344762306a36Sopenharmony_ci	ionic_dev_cmd_comp(idev, (union ionic_dev_cmd_comp *)&comp);
344862306a36Sopenharmony_ci	mutex_unlock(&lif->ionic->dev_cmd_lock);
344962306a36Sopenharmony_ci	if (err) {
345062306a36Sopenharmony_ci		netdev_err(lif->netdev, "adminq init failed %d\n", err);
345162306a36Sopenharmony_ci		return err;
345262306a36Sopenharmony_ci	}
345362306a36Sopenharmony_ci
345462306a36Sopenharmony_ci	q->hw_type = comp.hw_type;
345562306a36Sopenharmony_ci	q->hw_index = le32_to_cpu(comp.hw_index);
345662306a36Sopenharmony_ci	q->dbval = IONIC_DBELL_QID(q->hw_index);
345762306a36Sopenharmony_ci
345862306a36Sopenharmony_ci	dev_dbg(dev, "adminq->hw_type %d\n", q->hw_type);
345962306a36Sopenharmony_ci	dev_dbg(dev, "adminq->hw_index %d\n", q->hw_index);
346062306a36Sopenharmony_ci
346162306a36Sopenharmony_ci	q->dbell_deadline = IONIC_ADMIN_DOORBELL_DEADLINE;
346262306a36Sopenharmony_ci	q->dbell_jiffies = jiffies;
346362306a36Sopenharmony_ci
346462306a36Sopenharmony_ci	netif_napi_add(lif->netdev, &qcq->napi, ionic_adminq_napi);
346562306a36Sopenharmony_ci
346662306a36Sopenharmony_ci	qcq->napi_qcq = qcq;
346762306a36Sopenharmony_ci	timer_setup(&qcq->napi_deadline, ionic_napi_deadline, 0);
346862306a36Sopenharmony_ci
346962306a36Sopenharmony_ci	napi_enable(&qcq->napi);
347062306a36Sopenharmony_ci
347162306a36Sopenharmony_ci	if (qcq->flags & IONIC_QCQ_F_INTR)
347262306a36Sopenharmony_ci		ionic_intr_mask(idev->intr_ctrl, qcq->intr.index,
347362306a36Sopenharmony_ci				IONIC_INTR_MASK_CLEAR);
347462306a36Sopenharmony_ci
347562306a36Sopenharmony_ci	qcq->flags |= IONIC_QCQ_F_INITED;
347662306a36Sopenharmony_ci
347762306a36Sopenharmony_ci	return 0;
347862306a36Sopenharmony_ci}
347962306a36Sopenharmony_ci
348062306a36Sopenharmony_cistatic int ionic_lif_notifyq_init(struct ionic_lif *lif)
348162306a36Sopenharmony_ci{
348262306a36Sopenharmony_ci	struct ionic_qcq *qcq = lif->notifyqcq;
348362306a36Sopenharmony_ci	struct device *dev = lif->ionic->dev;
348462306a36Sopenharmony_ci	struct ionic_queue *q = &qcq->q;
348562306a36Sopenharmony_ci	int err;
348662306a36Sopenharmony_ci
348762306a36Sopenharmony_ci	struct ionic_admin_ctx ctx = {
348862306a36Sopenharmony_ci		.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
348962306a36Sopenharmony_ci		.cmd.q_init = {
349062306a36Sopenharmony_ci			.opcode = IONIC_CMD_Q_INIT,
349162306a36Sopenharmony_ci			.lif_index = cpu_to_le16(lif->index),
349262306a36Sopenharmony_ci			.type = q->type,
349362306a36Sopenharmony_ci			.ver = lif->qtype_info[q->type].version,
349462306a36Sopenharmony_ci			.index = cpu_to_le32(q->index),
349562306a36Sopenharmony_ci			.flags = cpu_to_le16(IONIC_QINIT_F_IRQ |
349662306a36Sopenharmony_ci					     IONIC_QINIT_F_ENA),
349762306a36Sopenharmony_ci			.intr_index = cpu_to_le16(lif->adminqcq->intr.index),
349862306a36Sopenharmony_ci			.pid = cpu_to_le16(q->pid),
349962306a36Sopenharmony_ci			.ring_size = ilog2(q->num_descs),
350062306a36Sopenharmony_ci			.ring_base = cpu_to_le64(q->base_pa),
350162306a36Sopenharmony_ci		}
350262306a36Sopenharmony_ci	};
350362306a36Sopenharmony_ci
350462306a36Sopenharmony_ci	dev_dbg(dev, "notifyq_init.pid %d\n", ctx.cmd.q_init.pid);
350562306a36Sopenharmony_ci	dev_dbg(dev, "notifyq_init.index %d\n", ctx.cmd.q_init.index);
350662306a36Sopenharmony_ci	dev_dbg(dev, "notifyq_init.ring_base 0x%llx\n", ctx.cmd.q_init.ring_base);
350762306a36Sopenharmony_ci	dev_dbg(dev, "notifyq_init.ring_size %d\n", ctx.cmd.q_init.ring_size);
350862306a36Sopenharmony_ci
350962306a36Sopenharmony_ci	err = ionic_adminq_post_wait(lif, &ctx);
351062306a36Sopenharmony_ci	if (err)
351162306a36Sopenharmony_ci		return err;
351262306a36Sopenharmony_ci
351362306a36Sopenharmony_ci	lif->last_eid = 0;
351462306a36Sopenharmony_ci	q->hw_type = ctx.comp.q_init.hw_type;
351562306a36Sopenharmony_ci	q->hw_index = le32_to_cpu(ctx.comp.q_init.hw_index);
351662306a36Sopenharmony_ci	q->dbval = IONIC_DBELL_QID(q->hw_index);
351762306a36Sopenharmony_ci
351862306a36Sopenharmony_ci	dev_dbg(dev, "notifyq->hw_type %d\n", q->hw_type);
351962306a36Sopenharmony_ci	dev_dbg(dev, "notifyq->hw_index %d\n", q->hw_index);
352062306a36Sopenharmony_ci
352162306a36Sopenharmony_ci	/* preset the callback info */
352262306a36Sopenharmony_ci	q->info[0].cb_arg = lif;
352362306a36Sopenharmony_ci
352462306a36Sopenharmony_ci	qcq->flags |= IONIC_QCQ_F_INITED;
352562306a36Sopenharmony_ci
352662306a36Sopenharmony_ci	return 0;
352762306a36Sopenharmony_ci}
352862306a36Sopenharmony_ci
352962306a36Sopenharmony_cistatic int ionic_station_set(struct ionic_lif *lif)
353062306a36Sopenharmony_ci{
353162306a36Sopenharmony_ci	struct net_device *netdev = lif->netdev;
353262306a36Sopenharmony_ci	struct ionic_admin_ctx ctx = {
353362306a36Sopenharmony_ci		.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
353462306a36Sopenharmony_ci		.cmd.lif_getattr = {
353562306a36Sopenharmony_ci			.opcode = IONIC_CMD_LIF_GETATTR,
353662306a36Sopenharmony_ci			.index = cpu_to_le16(lif->index),
353762306a36Sopenharmony_ci			.attr = IONIC_LIF_ATTR_MAC,
353862306a36Sopenharmony_ci		},
353962306a36Sopenharmony_ci	};
354062306a36Sopenharmony_ci	u8 mac_address[ETH_ALEN];
354162306a36Sopenharmony_ci	struct sockaddr addr;
354262306a36Sopenharmony_ci	int err;
354362306a36Sopenharmony_ci
354462306a36Sopenharmony_ci	err = ionic_adminq_post_wait(lif, &ctx);
354562306a36Sopenharmony_ci	if (err)
354662306a36Sopenharmony_ci		return err;
354762306a36Sopenharmony_ci	netdev_dbg(lif->netdev, "found initial MAC addr %pM\n",
354862306a36Sopenharmony_ci		   ctx.comp.lif_getattr.mac);
354962306a36Sopenharmony_ci	ether_addr_copy(mac_address, ctx.comp.lif_getattr.mac);
355062306a36Sopenharmony_ci
355162306a36Sopenharmony_ci	if (is_zero_ether_addr(mac_address)) {
355262306a36Sopenharmony_ci		eth_hw_addr_random(netdev);
355362306a36Sopenharmony_ci		netdev_dbg(netdev, "Random Mac generated: %pM\n", netdev->dev_addr);
355462306a36Sopenharmony_ci		ether_addr_copy(mac_address, netdev->dev_addr);
355562306a36Sopenharmony_ci
355662306a36Sopenharmony_ci		err = ionic_program_mac(lif, mac_address);
355762306a36Sopenharmony_ci		if (err < 0)
355862306a36Sopenharmony_ci			return err;
355962306a36Sopenharmony_ci
356062306a36Sopenharmony_ci		if (err > 0) {
356162306a36Sopenharmony_ci			netdev_dbg(netdev, "%s:SET/GET ATTR Mac are not same-due to old FW running\n",
356262306a36Sopenharmony_ci				   __func__);
356362306a36Sopenharmony_ci			return 0;
356462306a36Sopenharmony_ci		}
356562306a36Sopenharmony_ci	}
356662306a36Sopenharmony_ci
356762306a36Sopenharmony_ci	if (!is_zero_ether_addr(netdev->dev_addr)) {
356862306a36Sopenharmony_ci		/* If the netdev mac is non-zero and doesn't match the default
356962306a36Sopenharmony_ci		 * device address, it was set by something earlier and we're
357062306a36Sopenharmony_ci		 * likely here again after a fw-upgrade reset.  We need to be
357162306a36Sopenharmony_ci		 * sure the netdev mac is in our filter list.
357262306a36Sopenharmony_ci		 */
357362306a36Sopenharmony_ci		if (!ether_addr_equal(mac_address, netdev->dev_addr))
357462306a36Sopenharmony_ci			ionic_lif_addr_add(lif, netdev->dev_addr);
357562306a36Sopenharmony_ci	} else {
357662306a36Sopenharmony_ci		/* Update the netdev mac with the device's mac */
357762306a36Sopenharmony_ci		ether_addr_copy(addr.sa_data, mac_address);
357862306a36Sopenharmony_ci		addr.sa_family = AF_INET;
357962306a36Sopenharmony_ci		err = eth_prepare_mac_addr_change(netdev, &addr);
358062306a36Sopenharmony_ci		if (err) {
358162306a36Sopenharmony_ci			netdev_warn(lif->netdev, "ignoring bad MAC addr from NIC %pM - err %d\n",
358262306a36Sopenharmony_ci				    addr.sa_data, err);
358362306a36Sopenharmony_ci			return 0;
358462306a36Sopenharmony_ci		}
358562306a36Sopenharmony_ci
358662306a36Sopenharmony_ci		eth_commit_mac_addr_change(netdev, &addr);
358762306a36Sopenharmony_ci	}
358862306a36Sopenharmony_ci
358962306a36Sopenharmony_ci	netdev_dbg(lif->netdev, "adding station MAC addr %pM\n",
359062306a36Sopenharmony_ci		   netdev->dev_addr);
359162306a36Sopenharmony_ci	ionic_lif_addr_add(lif, netdev->dev_addr);
359262306a36Sopenharmony_ci
359362306a36Sopenharmony_ci	return 0;
359462306a36Sopenharmony_ci}
359562306a36Sopenharmony_ci
359662306a36Sopenharmony_ciint ionic_lif_init(struct ionic_lif *lif)
359762306a36Sopenharmony_ci{
359862306a36Sopenharmony_ci	struct ionic_dev *idev = &lif->ionic->idev;
359962306a36Sopenharmony_ci	struct device *dev = lif->ionic->dev;
360062306a36Sopenharmony_ci	struct ionic_lif_init_comp comp;
360162306a36Sopenharmony_ci	int dbpage_num;
360262306a36Sopenharmony_ci	int err;
360362306a36Sopenharmony_ci
360462306a36Sopenharmony_ci	mutex_lock(&lif->ionic->dev_cmd_lock);
360562306a36Sopenharmony_ci	ionic_dev_cmd_lif_init(idev, lif->index, lif->info_pa);
360662306a36Sopenharmony_ci	err = ionic_dev_cmd_wait(lif->ionic, DEVCMD_TIMEOUT);
360762306a36Sopenharmony_ci	ionic_dev_cmd_comp(idev, (union ionic_dev_cmd_comp *)&comp);
360862306a36Sopenharmony_ci	mutex_unlock(&lif->ionic->dev_cmd_lock);
360962306a36Sopenharmony_ci	if (err)
361062306a36Sopenharmony_ci		return err;
361162306a36Sopenharmony_ci
361262306a36Sopenharmony_ci	lif->hw_index = le16_to_cpu(comp.hw_index);
361362306a36Sopenharmony_ci
361462306a36Sopenharmony_ci	/* now that we have the hw_index we can figure out our doorbell page */
361562306a36Sopenharmony_ci	lif->dbid_count = le32_to_cpu(lif->ionic->ident.dev.ndbpgs_per_lif);
361662306a36Sopenharmony_ci	if (!lif->dbid_count) {
361762306a36Sopenharmony_ci		dev_err(dev, "No doorbell pages, aborting\n");
361862306a36Sopenharmony_ci		return -EINVAL;
361962306a36Sopenharmony_ci	}
362062306a36Sopenharmony_ci
362162306a36Sopenharmony_ci	lif->kern_pid = 0;
362262306a36Sopenharmony_ci	dbpage_num = ionic_db_page_num(lif, lif->kern_pid);
362362306a36Sopenharmony_ci	lif->kern_dbpage = ionic_bus_map_dbpage(lif->ionic, dbpage_num);
362462306a36Sopenharmony_ci	if (!lif->kern_dbpage) {
362562306a36Sopenharmony_ci		dev_err(dev, "Cannot map dbpage, aborting\n");
362662306a36Sopenharmony_ci		return -ENOMEM;
362762306a36Sopenharmony_ci	}
362862306a36Sopenharmony_ci
362962306a36Sopenharmony_ci	err = ionic_lif_adminq_init(lif);
363062306a36Sopenharmony_ci	if (err)
363162306a36Sopenharmony_ci		goto err_out_adminq_deinit;
363262306a36Sopenharmony_ci
363362306a36Sopenharmony_ci	if (lif->ionic->nnqs_per_lif) {
363462306a36Sopenharmony_ci		err = ionic_lif_notifyq_init(lif);
363562306a36Sopenharmony_ci		if (err)
363662306a36Sopenharmony_ci			goto err_out_notifyq_deinit;
363762306a36Sopenharmony_ci	}
363862306a36Sopenharmony_ci
363962306a36Sopenharmony_ci	err = ionic_init_nic_features(lif);
364062306a36Sopenharmony_ci	if (err)
364162306a36Sopenharmony_ci		goto err_out_notifyq_deinit;
364262306a36Sopenharmony_ci
364362306a36Sopenharmony_ci	if (!test_bit(IONIC_LIF_F_FW_RESET, lif->state)) {
364462306a36Sopenharmony_ci		err = ionic_rx_filters_init(lif);
364562306a36Sopenharmony_ci		if (err)
364662306a36Sopenharmony_ci			goto err_out_notifyq_deinit;
364762306a36Sopenharmony_ci	}
364862306a36Sopenharmony_ci
364962306a36Sopenharmony_ci	err = ionic_station_set(lif);
365062306a36Sopenharmony_ci	if (err)
365162306a36Sopenharmony_ci		goto err_out_notifyq_deinit;
365262306a36Sopenharmony_ci
365362306a36Sopenharmony_ci	lif->rx_copybreak = IONIC_RX_COPYBREAK_DEFAULT;
365462306a36Sopenharmony_ci
365562306a36Sopenharmony_ci	set_bit(IONIC_LIF_F_INITED, lif->state);
365662306a36Sopenharmony_ci
365762306a36Sopenharmony_ci	INIT_WORK(&lif->tx_timeout_work, ionic_tx_timeout_work);
365862306a36Sopenharmony_ci
365962306a36Sopenharmony_ci	return 0;
366062306a36Sopenharmony_ci
366162306a36Sopenharmony_cierr_out_notifyq_deinit:
366262306a36Sopenharmony_ci	napi_disable(&lif->adminqcq->napi);
366362306a36Sopenharmony_ci	ionic_lif_qcq_deinit(lif, lif->notifyqcq);
366462306a36Sopenharmony_cierr_out_adminq_deinit:
366562306a36Sopenharmony_ci	ionic_lif_qcq_deinit(lif, lif->adminqcq);
366662306a36Sopenharmony_ci	ionic_lif_reset(lif);
366762306a36Sopenharmony_ci	ionic_bus_unmap_dbpage(lif->ionic, lif->kern_dbpage);
366862306a36Sopenharmony_ci	lif->kern_dbpage = NULL;
366962306a36Sopenharmony_ci
367062306a36Sopenharmony_ci	return err;
367162306a36Sopenharmony_ci}
367262306a36Sopenharmony_ci
367362306a36Sopenharmony_cistatic void ionic_lif_notify_work(struct work_struct *ws)
367462306a36Sopenharmony_ci{
367562306a36Sopenharmony_ci}
367662306a36Sopenharmony_ci
367762306a36Sopenharmony_cistatic void ionic_lif_set_netdev_info(struct ionic_lif *lif)
367862306a36Sopenharmony_ci{
367962306a36Sopenharmony_ci	struct ionic_admin_ctx ctx = {
368062306a36Sopenharmony_ci		.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
368162306a36Sopenharmony_ci		.cmd.lif_setattr = {
368262306a36Sopenharmony_ci			.opcode = IONIC_CMD_LIF_SETATTR,
368362306a36Sopenharmony_ci			.index = cpu_to_le16(lif->index),
368462306a36Sopenharmony_ci			.attr = IONIC_LIF_ATTR_NAME,
368562306a36Sopenharmony_ci		},
368662306a36Sopenharmony_ci	};
368762306a36Sopenharmony_ci
368862306a36Sopenharmony_ci	strscpy(ctx.cmd.lif_setattr.name, lif->netdev->name,
368962306a36Sopenharmony_ci		sizeof(ctx.cmd.lif_setattr.name));
369062306a36Sopenharmony_ci
369162306a36Sopenharmony_ci	ionic_adminq_post_wait(lif, &ctx);
369262306a36Sopenharmony_ci}
369362306a36Sopenharmony_ci
369462306a36Sopenharmony_cistatic struct ionic_lif *ionic_netdev_lif(struct net_device *netdev)
369562306a36Sopenharmony_ci{
369662306a36Sopenharmony_ci	if (!netdev || netdev->netdev_ops->ndo_start_xmit != ionic_start_xmit)
369762306a36Sopenharmony_ci		return NULL;
369862306a36Sopenharmony_ci
369962306a36Sopenharmony_ci	return netdev_priv(netdev);
370062306a36Sopenharmony_ci}
370162306a36Sopenharmony_ci
370262306a36Sopenharmony_cistatic int ionic_lif_notify(struct notifier_block *nb,
370362306a36Sopenharmony_ci			    unsigned long event, void *info)
370462306a36Sopenharmony_ci{
370562306a36Sopenharmony_ci	struct net_device *ndev = netdev_notifier_info_to_dev(info);
370662306a36Sopenharmony_ci	struct ionic *ionic = container_of(nb, struct ionic, nb);
370762306a36Sopenharmony_ci	struct ionic_lif *lif = ionic_netdev_lif(ndev);
370862306a36Sopenharmony_ci
370962306a36Sopenharmony_ci	if (!lif || lif->ionic != ionic)
371062306a36Sopenharmony_ci		return NOTIFY_DONE;
371162306a36Sopenharmony_ci
371262306a36Sopenharmony_ci	switch (event) {
371362306a36Sopenharmony_ci	case NETDEV_CHANGENAME:
371462306a36Sopenharmony_ci		ionic_lif_set_netdev_info(lif);
371562306a36Sopenharmony_ci		break;
371662306a36Sopenharmony_ci	}
371762306a36Sopenharmony_ci
371862306a36Sopenharmony_ci	return NOTIFY_DONE;
371962306a36Sopenharmony_ci}
372062306a36Sopenharmony_ci
372162306a36Sopenharmony_ciint ionic_lif_register(struct ionic_lif *lif)
372262306a36Sopenharmony_ci{
372362306a36Sopenharmony_ci	int err;
372462306a36Sopenharmony_ci
372562306a36Sopenharmony_ci	ionic_lif_register_phc(lif);
372662306a36Sopenharmony_ci
372762306a36Sopenharmony_ci	INIT_WORK(&lif->ionic->nb_work, ionic_lif_notify_work);
372862306a36Sopenharmony_ci
372962306a36Sopenharmony_ci	lif->ionic->nb.notifier_call = ionic_lif_notify;
373062306a36Sopenharmony_ci
373162306a36Sopenharmony_ci	err = register_netdevice_notifier(&lif->ionic->nb);
373262306a36Sopenharmony_ci	if (err)
373362306a36Sopenharmony_ci		lif->ionic->nb.notifier_call = NULL;
373462306a36Sopenharmony_ci
373562306a36Sopenharmony_ci	/* only register LIF0 for now */
373662306a36Sopenharmony_ci	err = register_netdev(lif->netdev);
373762306a36Sopenharmony_ci	if (err) {
373862306a36Sopenharmony_ci		dev_err(lif->ionic->dev, "Cannot register net device, aborting\n");
373962306a36Sopenharmony_ci		ionic_lif_unregister_phc(lif);
374062306a36Sopenharmony_ci		return err;
374162306a36Sopenharmony_ci	}
374262306a36Sopenharmony_ci
374362306a36Sopenharmony_ci	ionic_link_status_check_request(lif, CAN_SLEEP);
374462306a36Sopenharmony_ci	lif->registered = true;
374562306a36Sopenharmony_ci	ionic_lif_set_netdev_info(lif);
374662306a36Sopenharmony_ci
374762306a36Sopenharmony_ci	return 0;
374862306a36Sopenharmony_ci}
374962306a36Sopenharmony_ci
375062306a36Sopenharmony_civoid ionic_lif_unregister(struct ionic_lif *lif)
375162306a36Sopenharmony_ci{
375262306a36Sopenharmony_ci	if (lif->ionic->nb.notifier_call) {
375362306a36Sopenharmony_ci		unregister_netdevice_notifier(&lif->ionic->nb);
375462306a36Sopenharmony_ci		cancel_work_sync(&lif->ionic->nb_work);
375562306a36Sopenharmony_ci		lif->ionic->nb.notifier_call = NULL;
375662306a36Sopenharmony_ci	}
375762306a36Sopenharmony_ci
375862306a36Sopenharmony_ci	if (lif->netdev->reg_state == NETREG_REGISTERED)
375962306a36Sopenharmony_ci		unregister_netdev(lif->netdev);
376062306a36Sopenharmony_ci
376162306a36Sopenharmony_ci	ionic_lif_unregister_phc(lif);
376262306a36Sopenharmony_ci
376362306a36Sopenharmony_ci	lif->registered = false;
376462306a36Sopenharmony_ci}
376562306a36Sopenharmony_ci
376662306a36Sopenharmony_cistatic void ionic_lif_queue_identify(struct ionic_lif *lif)
376762306a36Sopenharmony_ci{
376862306a36Sopenharmony_ci	union ionic_q_identity __iomem *q_ident;
376962306a36Sopenharmony_ci	struct ionic *ionic = lif->ionic;
377062306a36Sopenharmony_ci	struct ionic_dev *idev;
377162306a36Sopenharmony_ci	int qtype;
377262306a36Sopenharmony_ci	int err;
377362306a36Sopenharmony_ci
377462306a36Sopenharmony_ci	idev = &lif->ionic->idev;
377562306a36Sopenharmony_ci	q_ident = (union ionic_q_identity __iomem *)&idev->dev_cmd_regs->data;
377662306a36Sopenharmony_ci
377762306a36Sopenharmony_ci	for (qtype = 0; qtype < ARRAY_SIZE(ionic_qtype_versions); qtype++) {
377862306a36Sopenharmony_ci		struct ionic_qtype_info *qti = &lif->qtype_info[qtype];
377962306a36Sopenharmony_ci
378062306a36Sopenharmony_ci		/* filter out the ones we know about */
378162306a36Sopenharmony_ci		switch (qtype) {
378262306a36Sopenharmony_ci		case IONIC_QTYPE_ADMINQ:
378362306a36Sopenharmony_ci		case IONIC_QTYPE_NOTIFYQ:
378462306a36Sopenharmony_ci		case IONIC_QTYPE_RXQ:
378562306a36Sopenharmony_ci		case IONIC_QTYPE_TXQ:
378662306a36Sopenharmony_ci			break;
378762306a36Sopenharmony_ci		default:
378862306a36Sopenharmony_ci			continue;
378962306a36Sopenharmony_ci		}
379062306a36Sopenharmony_ci
379162306a36Sopenharmony_ci		memset(qti, 0, sizeof(*qti));
379262306a36Sopenharmony_ci
379362306a36Sopenharmony_ci		mutex_lock(&ionic->dev_cmd_lock);
379462306a36Sopenharmony_ci		ionic_dev_cmd_queue_identify(idev, lif->lif_type, qtype,
379562306a36Sopenharmony_ci					     ionic_qtype_versions[qtype]);
379662306a36Sopenharmony_ci		err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT);
379762306a36Sopenharmony_ci		if (!err) {
379862306a36Sopenharmony_ci			qti->version   = readb(&q_ident->version);
379962306a36Sopenharmony_ci			qti->supported = readb(&q_ident->supported);
380062306a36Sopenharmony_ci			qti->features  = readq(&q_ident->features);
380162306a36Sopenharmony_ci			qti->desc_sz   = readw(&q_ident->desc_sz);
380262306a36Sopenharmony_ci			qti->comp_sz   = readw(&q_ident->comp_sz);
380362306a36Sopenharmony_ci			qti->sg_desc_sz   = readw(&q_ident->sg_desc_sz);
380462306a36Sopenharmony_ci			qti->max_sg_elems = readw(&q_ident->max_sg_elems);
380562306a36Sopenharmony_ci			qti->sg_desc_stride = readw(&q_ident->sg_desc_stride);
380662306a36Sopenharmony_ci		}
380762306a36Sopenharmony_ci		mutex_unlock(&ionic->dev_cmd_lock);
380862306a36Sopenharmony_ci
380962306a36Sopenharmony_ci		if (err == -EINVAL) {
381062306a36Sopenharmony_ci			dev_err(ionic->dev, "qtype %d not supported\n", qtype);
381162306a36Sopenharmony_ci			continue;
381262306a36Sopenharmony_ci		} else if (err == -EIO) {
381362306a36Sopenharmony_ci			dev_err(ionic->dev, "q_ident failed, not supported on older FW\n");
381462306a36Sopenharmony_ci			return;
381562306a36Sopenharmony_ci		} else if (err) {
381662306a36Sopenharmony_ci			dev_err(ionic->dev, "q_ident failed, qtype %d: %d\n",
381762306a36Sopenharmony_ci				qtype, err);
381862306a36Sopenharmony_ci			return;
381962306a36Sopenharmony_ci		}
382062306a36Sopenharmony_ci
382162306a36Sopenharmony_ci		dev_dbg(ionic->dev, " qtype[%d].version = %d\n",
382262306a36Sopenharmony_ci			qtype, qti->version);
382362306a36Sopenharmony_ci		dev_dbg(ionic->dev, " qtype[%d].supported = 0x%02x\n",
382462306a36Sopenharmony_ci			qtype, qti->supported);
382562306a36Sopenharmony_ci		dev_dbg(ionic->dev, " qtype[%d].features = 0x%04llx\n",
382662306a36Sopenharmony_ci			qtype, qti->features);
382762306a36Sopenharmony_ci		dev_dbg(ionic->dev, " qtype[%d].desc_sz = %d\n",
382862306a36Sopenharmony_ci			qtype, qti->desc_sz);
382962306a36Sopenharmony_ci		dev_dbg(ionic->dev, " qtype[%d].comp_sz = %d\n",
383062306a36Sopenharmony_ci			qtype, qti->comp_sz);
383162306a36Sopenharmony_ci		dev_dbg(ionic->dev, " qtype[%d].sg_desc_sz = %d\n",
383262306a36Sopenharmony_ci			qtype, qti->sg_desc_sz);
383362306a36Sopenharmony_ci		dev_dbg(ionic->dev, " qtype[%d].max_sg_elems = %d\n",
383462306a36Sopenharmony_ci			qtype, qti->max_sg_elems);
383562306a36Sopenharmony_ci		dev_dbg(ionic->dev, " qtype[%d].sg_desc_stride = %d\n",
383662306a36Sopenharmony_ci			qtype, qti->sg_desc_stride);
383762306a36Sopenharmony_ci	}
383862306a36Sopenharmony_ci}
383962306a36Sopenharmony_ci
384062306a36Sopenharmony_ciint ionic_lif_identify(struct ionic *ionic, u8 lif_type,
384162306a36Sopenharmony_ci		       union ionic_lif_identity *lid)
384262306a36Sopenharmony_ci{
384362306a36Sopenharmony_ci	struct ionic_dev *idev = &ionic->idev;
384462306a36Sopenharmony_ci	size_t sz;
384562306a36Sopenharmony_ci	int err;
384662306a36Sopenharmony_ci
384762306a36Sopenharmony_ci	sz = min(sizeof(*lid), sizeof(idev->dev_cmd_regs->data));
384862306a36Sopenharmony_ci
384962306a36Sopenharmony_ci	mutex_lock(&ionic->dev_cmd_lock);
385062306a36Sopenharmony_ci	ionic_dev_cmd_lif_identify(idev, lif_type, IONIC_IDENTITY_VERSION_1);
385162306a36Sopenharmony_ci	err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT);
385262306a36Sopenharmony_ci	memcpy_fromio(lid, &idev->dev_cmd_regs->data, sz);
385362306a36Sopenharmony_ci	mutex_unlock(&ionic->dev_cmd_lock);
385462306a36Sopenharmony_ci	if (err)
385562306a36Sopenharmony_ci		return (err);
385662306a36Sopenharmony_ci
385762306a36Sopenharmony_ci	dev_dbg(ionic->dev, "capabilities 0x%llx\n",
385862306a36Sopenharmony_ci		le64_to_cpu(lid->capabilities));
385962306a36Sopenharmony_ci
386062306a36Sopenharmony_ci	dev_dbg(ionic->dev, "eth.max_ucast_filters %d\n",
386162306a36Sopenharmony_ci		le32_to_cpu(lid->eth.max_ucast_filters));
386262306a36Sopenharmony_ci	dev_dbg(ionic->dev, "eth.max_mcast_filters %d\n",
386362306a36Sopenharmony_ci		le32_to_cpu(lid->eth.max_mcast_filters));
386462306a36Sopenharmony_ci	dev_dbg(ionic->dev, "eth.features 0x%llx\n",
386562306a36Sopenharmony_ci		le64_to_cpu(lid->eth.config.features));
386662306a36Sopenharmony_ci	dev_dbg(ionic->dev, "eth.queue_count[IONIC_QTYPE_ADMINQ] %d\n",
386762306a36Sopenharmony_ci		le32_to_cpu(lid->eth.config.queue_count[IONIC_QTYPE_ADMINQ]));
386862306a36Sopenharmony_ci	dev_dbg(ionic->dev, "eth.queue_count[IONIC_QTYPE_NOTIFYQ] %d\n",
386962306a36Sopenharmony_ci		le32_to_cpu(lid->eth.config.queue_count[IONIC_QTYPE_NOTIFYQ]));
387062306a36Sopenharmony_ci	dev_dbg(ionic->dev, "eth.queue_count[IONIC_QTYPE_RXQ] %d\n",
387162306a36Sopenharmony_ci		le32_to_cpu(lid->eth.config.queue_count[IONIC_QTYPE_RXQ]));
387262306a36Sopenharmony_ci	dev_dbg(ionic->dev, "eth.queue_count[IONIC_QTYPE_TXQ] %d\n",
387362306a36Sopenharmony_ci		le32_to_cpu(lid->eth.config.queue_count[IONIC_QTYPE_TXQ]));
387462306a36Sopenharmony_ci	dev_dbg(ionic->dev, "eth.config.name %s\n", lid->eth.config.name);
387562306a36Sopenharmony_ci	dev_dbg(ionic->dev, "eth.config.mac %pM\n", lid->eth.config.mac);
387662306a36Sopenharmony_ci	dev_dbg(ionic->dev, "eth.config.mtu %d\n",
387762306a36Sopenharmony_ci		le32_to_cpu(lid->eth.config.mtu));
387862306a36Sopenharmony_ci
387962306a36Sopenharmony_ci	return 0;
388062306a36Sopenharmony_ci}
388162306a36Sopenharmony_ci
388262306a36Sopenharmony_ciint ionic_lif_size(struct ionic *ionic)
388362306a36Sopenharmony_ci{
388462306a36Sopenharmony_ci	struct ionic_identity *ident = &ionic->ident;
388562306a36Sopenharmony_ci	unsigned int nintrs, dev_nintrs;
388662306a36Sopenharmony_ci	union ionic_lif_config *lc;
388762306a36Sopenharmony_ci	unsigned int ntxqs_per_lif;
388862306a36Sopenharmony_ci	unsigned int nrxqs_per_lif;
388962306a36Sopenharmony_ci	unsigned int neqs_per_lif;
389062306a36Sopenharmony_ci	unsigned int nnqs_per_lif;
389162306a36Sopenharmony_ci	unsigned int nxqs, neqs;
389262306a36Sopenharmony_ci	unsigned int min_intrs;
389362306a36Sopenharmony_ci	int err;
389462306a36Sopenharmony_ci
389562306a36Sopenharmony_ci	/* retrieve basic values from FW */
389662306a36Sopenharmony_ci	lc = &ident->lif.eth.config;
389762306a36Sopenharmony_ci	dev_nintrs = le32_to_cpu(ident->dev.nintrs);
389862306a36Sopenharmony_ci	neqs_per_lif = le32_to_cpu(ident->lif.rdma.eq_qtype.qid_count);
389962306a36Sopenharmony_ci	nnqs_per_lif = le32_to_cpu(lc->queue_count[IONIC_QTYPE_NOTIFYQ]);
390062306a36Sopenharmony_ci	ntxqs_per_lif = le32_to_cpu(lc->queue_count[IONIC_QTYPE_TXQ]);
390162306a36Sopenharmony_ci	nrxqs_per_lif = le32_to_cpu(lc->queue_count[IONIC_QTYPE_RXQ]);
390262306a36Sopenharmony_ci
390362306a36Sopenharmony_ci	/* limit values to play nice with kdump */
390462306a36Sopenharmony_ci	if (is_kdump_kernel()) {
390562306a36Sopenharmony_ci		dev_nintrs = 2;
390662306a36Sopenharmony_ci		neqs_per_lif = 0;
390762306a36Sopenharmony_ci		nnqs_per_lif = 0;
390862306a36Sopenharmony_ci		ntxqs_per_lif = 1;
390962306a36Sopenharmony_ci		nrxqs_per_lif = 1;
391062306a36Sopenharmony_ci	}
391162306a36Sopenharmony_ci
391262306a36Sopenharmony_ci	/* reserve last queue id for hardware timestamping */
391362306a36Sopenharmony_ci	if (lc->features & cpu_to_le64(IONIC_ETH_HW_TIMESTAMP)) {
391462306a36Sopenharmony_ci		if (ntxqs_per_lif <= 1 || nrxqs_per_lif <= 1) {
391562306a36Sopenharmony_ci			lc->features &= cpu_to_le64(~IONIC_ETH_HW_TIMESTAMP);
391662306a36Sopenharmony_ci		} else {
391762306a36Sopenharmony_ci			ntxqs_per_lif -= 1;
391862306a36Sopenharmony_ci			nrxqs_per_lif -= 1;
391962306a36Sopenharmony_ci		}
392062306a36Sopenharmony_ci	}
392162306a36Sopenharmony_ci
392262306a36Sopenharmony_ci	nxqs = min(ntxqs_per_lif, nrxqs_per_lif);
392362306a36Sopenharmony_ci	nxqs = min(nxqs, num_online_cpus());
392462306a36Sopenharmony_ci	neqs = min(neqs_per_lif, num_online_cpus());
392562306a36Sopenharmony_ci
392662306a36Sopenharmony_citry_again:
392762306a36Sopenharmony_ci	/* interrupt usage:
392862306a36Sopenharmony_ci	 *    1 for master lif adminq/notifyq
392962306a36Sopenharmony_ci	 *    1 for each CPU for master lif TxRx queue pairs
393062306a36Sopenharmony_ci	 *    whatever's left is for RDMA queues
393162306a36Sopenharmony_ci	 */
393262306a36Sopenharmony_ci	nintrs = 1 + nxqs + neqs;
393362306a36Sopenharmony_ci	min_intrs = 2;  /* adminq + 1 TxRx queue pair */
393462306a36Sopenharmony_ci
393562306a36Sopenharmony_ci	if (nintrs > dev_nintrs)
393662306a36Sopenharmony_ci		goto try_fewer;
393762306a36Sopenharmony_ci
393862306a36Sopenharmony_ci	err = ionic_bus_alloc_irq_vectors(ionic, nintrs);
393962306a36Sopenharmony_ci	if (err < 0 && err != -ENOSPC) {
394062306a36Sopenharmony_ci		dev_err(ionic->dev, "Can't get intrs from OS: %d\n", err);
394162306a36Sopenharmony_ci		return err;
394262306a36Sopenharmony_ci	}
394362306a36Sopenharmony_ci	if (err == -ENOSPC)
394462306a36Sopenharmony_ci		goto try_fewer;
394562306a36Sopenharmony_ci
394662306a36Sopenharmony_ci	if (err != nintrs) {
394762306a36Sopenharmony_ci		ionic_bus_free_irq_vectors(ionic);
394862306a36Sopenharmony_ci		goto try_fewer;
394962306a36Sopenharmony_ci	}
395062306a36Sopenharmony_ci
395162306a36Sopenharmony_ci	ionic->nnqs_per_lif = nnqs_per_lif;
395262306a36Sopenharmony_ci	ionic->neqs_per_lif = neqs;
395362306a36Sopenharmony_ci	ionic->ntxqs_per_lif = nxqs;
395462306a36Sopenharmony_ci	ionic->nrxqs_per_lif = nxqs;
395562306a36Sopenharmony_ci	ionic->nintrs = nintrs;
395662306a36Sopenharmony_ci
395762306a36Sopenharmony_ci	ionic_debugfs_add_sizes(ionic);
395862306a36Sopenharmony_ci
395962306a36Sopenharmony_ci	return 0;
396062306a36Sopenharmony_ci
396162306a36Sopenharmony_citry_fewer:
396262306a36Sopenharmony_ci	if (nnqs_per_lif > 1) {
396362306a36Sopenharmony_ci		nnqs_per_lif >>= 1;
396462306a36Sopenharmony_ci		goto try_again;
396562306a36Sopenharmony_ci	}
396662306a36Sopenharmony_ci	if (neqs > 1) {
396762306a36Sopenharmony_ci		neqs >>= 1;
396862306a36Sopenharmony_ci		goto try_again;
396962306a36Sopenharmony_ci	}
397062306a36Sopenharmony_ci	if (nxqs > 1) {
397162306a36Sopenharmony_ci		nxqs >>= 1;
397262306a36Sopenharmony_ci		goto try_again;
397362306a36Sopenharmony_ci	}
397462306a36Sopenharmony_ci	dev_err(ionic->dev, "Can't get minimum %d intrs from OS\n", min_intrs);
397562306a36Sopenharmony_ci	return -ENOSPC;
397662306a36Sopenharmony_ci}
3977