18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/* Copyright(c) 2017 - 2019 Pensando Systems, Inc */
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci#include <linux/printk.h>
58c2ecf20Sopenharmony_ci#include <linux/dynamic_debug.h>
68c2ecf20Sopenharmony_ci#include <linux/netdevice.h>
78c2ecf20Sopenharmony_ci#include <linux/etherdevice.h>
88c2ecf20Sopenharmony_ci#include <linux/if_vlan.h>
98c2ecf20Sopenharmony_ci#include <linux/rtnetlink.h>
108c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
118c2ecf20Sopenharmony_ci#include <linux/pci.h>
128c2ecf20Sopenharmony_ci#include <linux/cpumask.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include "ionic.h"
158c2ecf20Sopenharmony_ci#include "ionic_bus.h"
168c2ecf20Sopenharmony_ci#include "ionic_lif.h"
178c2ecf20Sopenharmony_ci#include "ionic_txrx.h"
188c2ecf20Sopenharmony_ci#include "ionic_ethtool.h"
198c2ecf20Sopenharmony_ci#include "ionic_debugfs.h"
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci/* queuetype support level */
228c2ecf20Sopenharmony_cistatic const u8 ionic_qtype_versions[IONIC_QTYPE_MAX] = {
238c2ecf20Sopenharmony_ci	[IONIC_QTYPE_ADMINQ]  = 0,   /* 0 = Base version with CQ support */
248c2ecf20Sopenharmony_ci	[IONIC_QTYPE_NOTIFYQ] = 0,   /* 0 = Base version */
258c2ecf20Sopenharmony_ci	[IONIC_QTYPE_RXQ]     = 0,   /* 0 = Base version with CQ+SG support */
268c2ecf20Sopenharmony_ci	[IONIC_QTYPE_TXQ]     = 1,   /* 0 = Base version with CQ+SG support
278c2ecf20Sopenharmony_ci				      * 1 =   ... with Tx SG version 1
288c2ecf20Sopenharmony_ci				      */
298c2ecf20Sopenharmony_ci};
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_cistatic void ionic_lif_rx_mode(struct ionic_lif *lif, unsigned int rx_mode);
328c2ecf20Sopenharmony_cistatic int ionic_lif_addr_add(struct ionic_lif *lif, const u8 *addr);
338c2ecf20Sopenharmony_cistatic int ionic_lif_addr_del(struct ionic_lif *lif, const u8 *addr);
348c2ecf20Sopenharmony_cistatic void ionic_link_status_check(struct ionic_lif *lif);
358c2ecf20Sopenharmony_cistatic void ionic_lif_handle_fw_down(struct ionic_lif *lif);
368c2ecf20Sopenharmony_cistatic void ionic_lif_handle_fw_up(struct ionic_lif *lif);
378c2ecf20Sopenharmony_cistatic void ionic_lif_set_netdev_info(struct ionic_lif *lif);
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cistatic void ionic_txrx_deinit(struct ionic_lif *lif);
408c2ecf20Sopenharmony_cistatic int ionic_txrx_init(struct ionic_lif *lif);
418c2ecf20Sopenharmony_cistatic int ionic_start_queues(struct ionic_lif *lif);
428c2ecf20Sopenharmony_cistatic void ionic_stop_queues(struct ionic_lif *lif);
438c2ecf20Sopenharmony_cistatic void ionic_lif_queue_identify(struct ionic_lif *lif);
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_cistatic void ionic_dim_work(struct work_struct *work)
468c2ecf20Sopenharmony_ci{
478c2ecf20Sopenharmony_ci	struct dim *dim = container_of(work, struct dim, work);
488c2ecf20Sopenharmony_ci	struct ionic_intr_info *intr;
498c2ecf20Sopenharmony_ci	struct dim_cq_moder cur_moder;
508c2ecf20Sopenharmony_ci	struct ionic_qcq *qcq;
518c2ecf20Sopenharmony_ci	struct ionic_lif *lif;
528c2ecf20Sopenharmony_ci	u32 new_coal;
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	cur_moder = net_dim_get_rx_moderation(dim->mode, dim->profile_ix);
558c2ecf20Sopenharmony_ci	qcq = container_of(dim, struct ionic_qcq, dim);
568c2ecf20Sopenharmony_ci	lif = qcq->q.lif;
578c2ecf20Sopenharmony_ci	new_coal = ionic_coal_usec_to_hw(lif->ionic, cur_moder.usec);
588c2ecf20Sopenharmony_ci	new_coal = new_coal ? new_coal : 1;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	intr = &qcq->intr;
618c2ecf20Sopenharmony_ci	if (intr->dim_coal_hw != new_coal) {
628c2ecf20Sopenharmony_ci		intr->dim_coal_hw = new_coal;
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci		ionic_intr_coal_init(lif->ionic->idev.intr_ctrl,
658c2ecf20Sopenharmony_ci				     intr->index, intr->dim_coal_hw);
668c2ecf20Sopenharmony_ci	}
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	dim->state = DIM_START_MEASURE;
698c2ecf20Sopenharmony_ci}
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_cistatic void ionic_lif_deferred_work(struct work_struct *work)
728c2ecf20Sopenharmony_ci{
738c2ecf20Sopenharmony_ci	struct ionic_lif *lif = container_of(work, struct ionic_lif, deferred.work);
748c2ecf20Sopenharmony_ci	struct ionic_deferred *def = &lif->deferred;
758c2ecf20Sopenharmony_ci	struct ionic_deferred_work *w = NULL;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	do {
788c2ecf20Sopenharmony_ci		spin_lock_bh(&def->lock);
798c2ecf20Sopenharmony_ci		if (!list_empty(&def->list)) {
808c2ecf20Sopenharmony_ci			w = list_first_entry(&def->list,
818c2ecf20Sopenharmony_ci					     struct ionic_deferred_work, list);
828c2ecf20Sopenharmony_ci			list_del(&w->list);
838c2ecf20Sopenharmony_ci		}
848c2ecf20Sopenharmony_ci		spin_unlock_bh(&def->lock);
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci		if (!w)
878c2ecf20Sopenharmony_ci			break;
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci		switch (w->type) {
908c2ecf20Sopenharmony_ci		case IONIC_DW_TYPE_RX_MODE:
918c2ecf20Sopenharmony_ci			ionic_lif_rx_mode(lif, w->rx_mode);
928c2ecf20Sopenharmony_ci			break;
938c2ecf20Sopenharmony_ci		case IONIC_DW_TYPE_RX_ADDR_ADD:
948c2ecf20Sopenharmony_ci			ionic_lif_addr_add(lif, w->addr);
958c2ecf20Sopenharmony_ci			break;
968c2ecf20Sopenharmony_ci		case IONIC_DW_TYPE_RX_ADDR_DEL:
978c2ecf20Sopenharmony_ci			ionic_lif_addr_del(lif, w->addr);
988c2ecf20Sopenharmony_ci			break;
998c2ecf20Sopenharmony_ci		case IONIC_DW_TYPE_LINK_STATUS:
1008c2ecf20Sopenharmony_ci			ionic_link_status_check(lif);
1018c2ecf20Sopenharmony_ci			break;
1028c2ecf20Sopenharmony_ci		case IONIC_DW_TYPE_LIF_RESET:
1038c2ecf20Sopenharmony_ci			if (w->fw_status)
1048c2ecf20Sopenharmony_ci				ionic_lif_handle_fw_up(lif);
1058c2ecf20Sopenharmony_ci			else
1068c2ecf20Sopenharmony_ci				ionic_lif_handle_fw_down(lif);
1078c2ecf20Sopenharmony_ci			break;
1088c2ecf20Sopenharmony_ci		default:
1098c2ecf20Sopenharmony_ci			break;
1108c2ecf20Sopenharmony_ci		}
1118c2ecf20Sopenharmony_ci		kfree(w);
1128c2ecf20Sopenharmony_ci		w = NULL;
1138c2ecf20Sopenharmony_ci	} while (true);
1148c2ecf20Sopenharmony_ci}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_civoid ionic_lif_deferred_enqueue(struct ionic_deferred *def,
1178c2ecf20Sopenharmony_ci				struct ionic_deferred_work *work)
1188c2ecf20Sopenharmony_ci{
1198c2ecf20Sopenharmony_ci	spin_lock_bh(&def->lock);
1208c2ecf20Sopenharmony_ci	list_add_tail(&work->list, &def->list);
1218c2ecf20Sopenharmony_ci	spin_unlock_bh(&def->lock);
1228c2ecf20Sopenharmony_ci	schedule_work(&def->work);
1238c2ecf20Sopenharmony_ci}
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_cistatic void ionic_link_status_check(struct ionic_lif *lif)
1268c2ecf20Sopenharmony_ci{
1278c2ecf20Sopenharmony_ci	struct net_device *netdev = lif->netdev;
1288c2ecf20Sopenharmony_ci	u16 link_status;
1298c2ecf20Sopenharmony_ci	bool link_up;
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	if (!test_bit(IONIC_LIF_F_LINK_CHECK_REQUESTED, lif->state))
1328c2ecf20Sopenharmony_ci		return;
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	link_status = le16_to_cpu(lif->info->status.link_status);
1358c2ecf20Sopenharmony_ci	link_up = link_status == IONIC_PORT_OPER_STATUS_UP;
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	if (link_up) {
1388c2ecf20Sopenharmony_ci		if (lif->netdev->flags & IFF_UP && netif_running(lif->netdev)) {
1398c2ecf20Sopenharmony_ci			mutex_lock(&lif->queue_lock);
1408c2ecf20Sopenharmony_ci			ionic_start_queues(lif);
1418c2ecf20Sopenharmony_ci			mutex_unlock(&lif->queue_lock);
1428c2ecf20Sopenharmony_ci		}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci		if (!netif_carrier_ok(netdev)) {
1458c2ecf20Sopenharmony_ci			u32 link_speed;
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci			ionic_port_identify(lif->ionic);
1488c2ecf20Sopenharmony_ci			link_speed = le32_to_cpu(lif->info->status.link_speed);
1498c2ecf20Sopenharmony_ci			netdev_info(netdev, "Link up - %d Gbps\n",
1508c2ecf20Sopenharmony_ci				    link_speed / 1000);
1518c2ecf20Sopenharmony_ci			netif_carrier_on(netdev);
1528c2ecf20Sopenharmony_ci		}
1538c2ecf20Sopenharmony_ci	} else {
1548c2ecf20Sopenharmony_ci		if (netif_carrier_ok(netdev)) {
1558c2ecf20Sopenharmony_ci			netdev_info(netdev, "Link down\n");
1568c2ecf20Sopenharmony_ci			netif_carrier_off(netdev);
1578c2ecf20Sopenharmony_ci		}
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci		if (lif->netdev->flags & IFF_UP && netif_running(lif->netdev)) {
1608c2ecf20Sopenharmony_ci			mutex_lock(&lif->queue_lock);
1618c2ecf20Sopenharmony_ci			ionic_stop_queues(lif);
1628c2ecf20Sopenharmony_ci			mutex_unlock(&lif->queue_lock);
1638c2ecf20Sopenharmony_ci		}
1648c2ecf20Sopenharmony_ci	}
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	clear_bit(IONIC_LIF_F_LINK_CHECK_REQUESTED, lif->state);
1678c2ecf20Sopenharmony_ci}
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_civoid ionic_link_status_check_request(struct ionic_lif *lif, bool can_sleep)
1708c2ecf20Sopenharmony_ci{
1718c2ecf20Sopenharmony_ci	struct ionic_deferred_work *work;
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	/* we only need one request outstanding at a time */
1748c2ecf20Sopenharmony_ci	if (test_and_set_bit(IONIC_LIF_F_LINK_CHECK_REQUESTED, lif->state))
1758c2ecf20Sopenharmony_ci		return;
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	if (!can_sleep) {
1788c2ecf20Sopenharmony_ci		work = kzalloc(sizeof(*work), GFP_ATOMIC);
1798c2ecf20Sopenharmony_ci		if (!work) {
1808c2ecf20Sopenharmony_ci			clear_bit(IONIC_LIF_F_LINK_CHECK_REQUESTED, lif->state);
1818c2ecf20Sopenharmony_ci			return;
1828c2ecf20Sopenharmony_ci		}
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci		work->type = IONIC_DW_TYPE_LINK_STATUS;
1858c2ecf20Sopenharmony_ci		ionic_lif_deferred_enqueue(&lif->deferred, work);
1868c2ecf20Sopenharmony_ci	} else {
1878c2ecf20Sopenharmony_ci		ionic_link_status_check(lif);
1888c2ecf20Sopenharmony_ci	}
1898c2ecf20Sopenharmony_ci}
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_cistatic irqreturn_t ionic_isr(int irq, void *data)
1928c2ecf20Sopenharmony_ci{
1938c2ecf20Sopenharmony_ci	struct napi_struct *napi = data;
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	napi_schedule_irqoff(napi);
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
1988c2ecf20Sopenharmony_ci}
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_cistatic int ionic_request_irq(struct ionic_lif *lif, struct ionic_qcq *qcq)
2018c2ecf20Sopenharmony_ci{
2028c2ecf20Sopenharmony_ci	struct ionic_intr_info *intr = &qcq->intr;
2038c2ecf20Sopenharmony_ci	struct device *dev = lif->ionic->dev;
2048c2ecf20Sopenharmony_ci	struct ionic_queue *q = &qcq->q;
2058c2ecf20Sopenharmony_ci	const char *name;
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	if (lif->registered)
2088c2ecf20Sopenharmony_ci		name = lif->netdev->name;
2098c2ecf20Sopenharmony_ci	else
2108c2ecf20Sopenharmony_ci		name = dev_name(dev);
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	snprintf(intr->name, sizeof(intr->name),
2138c2ecf20Sopenharmony_ci		 "%s-%s-%s", IONIC_DRV_NAME, name, q->name);
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	return devm_request_irq(dev, intr->vector, ionic_isr,
2168c2ecf20Sopenharmony_ci				0, intr->name, &qcq->napi);
2178c2ecf20Sopenharmony_ci}
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_cistatic int ionic_intr_alloc(struct ionic_lif *lif, struct ionic_intr_info *intr)
2208c2ecf20Sopenharmony_ci{
2218c2ecf20Sopenharmony_ci	struct ionic *ionic = lif->ionic;
2228c2ecf20Sopenharmony_ci	int index;
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	index = find_first_zero_bit(ionic->intrs, ionic->nintrs);
2258c2ecf20Sopenharmony_ci	if (index == ionic->nintrs) {
2268c2ecf20Sopenharmony_ci		netdev_warn(lif->netdev, "%s: no intr, index=%d nintrs=%d\n",
2278c2ecf20Sopenharmony_ci			    __func__, index, ionic->nintrs);
2288c2ecf20Sopenharmony_ci		return -ENOSPC;
2298c2ecf20Sopenharmony_ci	}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	set_bit(index, ionic->intrs);
2328c2ecf20Sopenharmony_ci	ionic_intr_init(&ionic->idev, intr, index);
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	return 0;
2358c2ecf20Sopenharmony_ci}
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_cistatic void ionic_intr_free(struct ionic *ionic, int index)
2388c2ecf20Sopenharmony_ci{
2398c2ecf20Sopenharmony_ci	if (index != IONIC_INTR_INDEX_NOT_ASSIGNED && index < ionic->nintrs)
2408c2ecf20Sopenharmony_ci		clear_bit(index, ionic->intrs);
2418c2ecf20Sopenharmony_ci}
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_cistatic int ionic_qcq_enable(struct ionic_qcq *qcq)
2448c2ecf20Sopenharmony_ci{
2458c2ecf20Sopenharmony_ci	struct ionic_queue *q = &qcq->q;
2468c2ecf20Sopenharmony_ci	struct ionic_lif *lif = q->lif;
2478c2ecf20Sopenharmony_ci	struct ionic_dev *idev;
2488c2ecf20Sopenharmony_ci	struct device *dev;
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	struct ionic_admin_ctx ctx = {
2518c2ecf20Sopenharmony_ci		.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
2528c2ecf20Sopenharmony_ci		.cmd.q_control = {
2538c2ecf20Sopenharmony_ci			.opcode = IONIC_CMD_Q_CONTROL,
2548c2ecf20Sopenharmony_ci			.lif_index = cpu_to_le16(lif->index),
2558c2ecf20Sopenharmony_ci			.type = q->type,
2568c2ecf20Sopenharmony_ci			.index = cpu_to_le32(q->index),
2578c2ecf20Sopenharmony_ci			.oper = IONIC_Q_ENABLE,
2588c2ecf20Sopenharmony_ci		},
2598c2ecf20Sopenharmony_ci	};
2608c2ecf20Sopenharmony_ci	int ret;
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	idev = &lif->ionic->idev;
2638c2ecf20Sopenharmony_ci	dev = lif->ionic->dev;
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	dev_dbg(dev, "q_enable.index %d q_enable.qtype %d\n",
2668c2ecf20Sopenharmony_ci		ctx.cmd.q_control.index, ctx.cmd.q_control.type);
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	if (qcq->flags & IONIC_QCQ_F_INTR)
2698c2ecf20Sopenharmony_ci		ionic_intr_clean(idev->intr_ctrl, qcq->intr.index);
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	ret = ionic_adminq_post_wait(lif, &ctx);
2728c2ecf20Sopenharmony_ci	if (ret)
2738c2ecf20Sopenharmony_ci		return ret;
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	if (qcq->napi.poll)
2768c2ecf20Sopenharmony_ci		napi_enable(&qcq->napi);
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	if (qcq->flags & IONIC_QCQ_F_INTR) {
2798c2ecf20Sopenharmony_ci		irq_set_affinity_hint(qcq->intr.vector,
2808c2ecf20Sopenharmony_ci				      &qcq->intr.affinity_mask);
2818c2ecf20Sopenharmony_ci		ionic_intr_mask(idev->intr_ctrl, qcq->intr.index,
2828c2ecf20Sopenharmony_ci				IONIC_INTR_MASK_CLEAR);
2838c2ecf20Sopenharmony_ci	}
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	return 0;
2868c2ecf20Sopenharmony_ci}
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_cistatic int ionic_qcq_disable(struct ionic_qcq *qcq, bool send_to_hw)
2898c2ecf20Sopenharmony_ci{
2908c2ecf20Sopenharmony_ci	struct ionic_queue *q;
2918c2ecf20Sopenharmony_ci	struct ionic_lif *lif;
2928c2ecf20Sopenharmony_ci	int err = 0;
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	struct ionic_admin_ctx ctx = {
2958c2ecf20Sopenharmony_ci		.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
2968c2ecf20Sopenharmony_ci		.cmd.q_control = {
2978c2ecf20Sopenharmony_ci			.opcode = IONIC_CMD_Q_CONTROL,
2988c2ecf20Sopenharmony_ci			.oper = IONIC_Q_DISABLE,
2998c2ecf20Sopenharmony_ci		},
3008c2ecf20Sopenharmony_ci	};
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	if (!qcq)
3038c2ecf20Sopenharmony_ci		return -ENXIO;
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	q = &qcq->q;
3068c2ecf20Sopenharmony_ci	lif = q->lif;
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	if (qcq->flags & IONIC_QCQ_F_INTR) {
3098c2ecf20Sopenharmony_ci		struct ionic_dev *idev = &lif->ionic->idev;
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci		cancel_work_sync(&qcq->dim.work);
3128c2ecf20Sopenharmony_ci		ionic_intr_mask(idev->intr_ctrl, qcq->intr.index,
3138c2ecf20Sopenharmony_ci				IONIC_INTR_MASK_SET);
3148c2ecf20Sopenharmony_ci		synchronize_irq(qcq->intr.vector);
3158c2ecf20Sopenharmony_ci		irq_set_affinity_hint(qcq->intr.vector, NULL);
3168c2ecf20Sopenharmony_ci		napi_disable(&qcq->napi);
3178c2ecf20Sopenharmony_ci	}
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	if (send_to_hw) {
3208c2ecf20Sopenharmony_ci		ctx.cmd.q_control.lif_index = cpu_to_le16(lif->index);
3218c2ecf20Sopenharmony_ci		ctx.cmd.q_control.type = q->type;
3228c2ecf20Sopenharmony_ci		ctx.cmd.q_control.index = cpu_to_le32(q->index);
3238c2ecf20Sopenharmony_ci		dev_dbg(lif->ionic->dev, "q_disable.index %d q_disable.qtype %d\n",
3248c2ecf20Sopenharmony_ci			ctx.cmd.q_control.index, ctx.cmd.q_control.type);
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci		err = ionic_adminq_post_wait(lif, &ctx);
3278c2ecf20Sopenharmony_ci	}
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	return err;
3308c2ecf20Sopenharmony_ci}
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_cistatic void ionic_lif_qcq_deinit(struct ionic_lif *lif, struct ionic_qcq *qcq)
3338c2ecf20Sopenharmony_ci{
3348c2ecf20Sopenharmony_ci	struct ionic_dev *idev = &lif->ionic->idev;
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	if (!qcq)
3378c2ecf20Sopenharmony_ci		return;
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	if (!(qcq->flags & IONIC_QCQ_F_INITED))
3408c2ecf20Sopenharmony_ci		return;
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	if (qcq->flags & IONIC_QCQ_F_INTR) {
3438c2ecf20Sopenharmony_ci		ionic_intr_mask(idev->intr_ctrl, qcq->intr.index,
3448c2ecf20Sopenharmony_ci				IONIC_INTR_MASK_SET);
3458c2ecf20Sopenharmony_ci		netif_napi_del(&qcq->napi);
3468c2ecf20Sopenharmony_ci	}
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	qcq->flags &= ~IONIC_QCQ_F_INITED;
3498c2ecf20Sopenharmony_ci}
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_cistatic void ionic_qcq_intr_free(struct ionic_lif *lif, struct ionic_qcq *qcq)
3528c2ecf20Sopenharmony_ci{
3538c2ecf20Sopenharmony_ci	if (!(qcq->flags & IONIC_QCQ_F_INTR) || qcq->intr.vector == 0)
3548c2ecf20Sopenharmony_ci		return;
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	irq_set_affinity_hint(qcq->intr.vector, NULL);
3578c2ecf20Sopenharmony_ci	devm_free_irq(lif->ionic->dev, qcq->intr.vector, &qcq->napi);
3588c2ecf20Sopenharmony_ci	qcq->intr.vector = 0;
3598c2ecf20Sopenharmony_ci	ionic_intr_free(lif->ionic, qcq->intr.index);
3608c2ecf20Sopenharmony_ci	qcq->intr.index = IONIC_INTR_INDEX_NOT_ASSIGNED;
3618c2ecf20Sopenharmony_ci}
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_cistatic void ionic_qcq_free(struct ionic_lif *lif, struct ionic_qcq *qcq)
3648c2ecf20Sopenharmony_ci{
3658c2ecf20Sopenharmony_ci	struct device *dev = lif->ionic->dev;
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	if (!qcq)
3688c2ecf20Sopenharmony_ci		return;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	ionic_debugfs_del_qcq(qcq);
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	if (qcq->q_base) {
3738c2ecf20Sopenharmony_ci		dma_free_coherent(dev, qcq->q_size, qcq->q_base, qcq->q_base_pa);
3748c2ecf20Sopenharmony_ci		qcq->q_base = NULL;
3758c2ecf20Sopenharmony_ci		qcq->q_base_pa = 0;
3768c2ecf20Sopenharmony_ci	}
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	if (qcq->cq_base) {
3798c2ecf20Sopenharmony_ci		dma_free_coherent(dev, qcq->cq_size, qcq->cq_base, qcq->cq_base_pa);
3808c2ecf20Sopenharmony_ci		qcq->cq_base = NULL;
3818c2ecf20Sopenharmony_ci		qcq->cq_base_pa = 0;
3828c2ecf20Sopenharmony_ci	}
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	if (qcq->sg_base) {
3858c2ecf20Sopenharmony_ci		dma_free_coherent(dev, qcq->sg_size, qcq->sg_base, qcq->sg_base_pa);
3868c2ecf20Sopenharmony_ci		qcq->sg_base = NULL;
3878c2ecf20Sopenharmony_ci		qcq->sg_base_pa = 0;
3888c2ecf20Sopenharmony_ci	}
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	ionic_qcq_intr_free(lif, qcq);
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	if (qcq->cq.info) {
3938c2ecf20Sopenharmony_ci		devm_kfree(dev, qcq->cq.info);
3948c2ecf20Sopenharmony_ci		qcq->cq.info = NULL;
3958c2ecf20Sopenharmony_ci	}
3968c2ecf20Sopenharmony_ci	if (qcq->q.info) {
3978c2ecf20Sopenharmony_ci		devm_kfree(dev, qcq->q.info);
3988c2ecf20Sopenharmony_ci		qcq->q.info = NULL;
3998c2ecf20Sopenharmony_ci	}
4008c2ecf20Sopenharmony_ci}
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_cistatic void ionic_qcqs_free(struct ionic_lif *lif)
4038c2ecf20Sopenharmony_ci{
4048c2ecf20Sopenharmony_ci	struct device *dev = lif->ionic->dev;
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	if (lif->notifyqcq) {
4078c2ecf20Sopenharmony_ci		ionic_qcq_free(lif, lif->notifyqcq);
4088c2ecf20Sopenharmony_ci		devm_kfree(dev, lif->notifyqcq);
4098c2ecf20Sopenharmony_ci		lif->notifyqcq = NULL;
4108c2ecf20Sopenharmony_ci	}
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	if (lif->adminqcq) {
4138c2ecf20Sopenharmony_ci		ionic_qcq_free(lif, lif->adminqcq);
4148c2ecf20Sopenharmony_ci		devm_kfree(dev, lif->adminqcq);
4158c2ecf20Sopenharmony_ci		lif->adminqcq = NULL;
4168c2ecf20Sopenharmony_ci	}
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	if (lif->rxqcqs) {
4198c2ecf20Sopenharmony_ci		devm_kfree(dev, lif->rxqstats);
4208c2ecf20Sopenharmony_ci		lif->rxqstats = NULL;
4218c2ecf20Sopenharmony_ci		devm_kfree(dev, lif->rxqcqs);
4228c2ecf20Sopenharmony_ci		lif->rxqcqs = NULL;
4238c2ecf20Sopenharmony_ci	}
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci	if (lif->txqcqs) {
4268c2ecf20Sopenharmony_ci		devm_kfree(dev, lif->txqstats);
4278c2ecf20Sopenharmony_ci		lif->txqstats = NULL;
4288c2ecf20Sopenharmony_ci		devm_kfree(dev, lif->txqcqs);
4298c2ecf20Sopenharmony_ci		lif->txqcqs = NULL;
4308c2ecf20Sopenharmony_ci	}
4318c2ecf20Sopenharmony_ci}
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_cistatic void ionic_link_qcq_interrupts(struct ionic_qcq *src_qcq,
4348c2ecf20Sopenharmony_ci				      struct ionic_qcq *n_qcq)
4358c2ecf20Sopenharmony_ci{
4368c2ecf20Sopenharmony_ci	n_qcq->intr.vector = src_qcq->intr.vector;
4378c2ecf20Sopenharmony_ci	n_qcq->intr.index = src_qcq->intr.index;
4388c2ecf20Sopenharmony_ci}
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_cistatic int ionic_alloc_qcq_interrupt(struct ionic_lif *lif, struct ionic_qcq *qcq)
4418c2ecf20Sopenharmony_ci{
4428c2ecf20Sopenharmony_ci	int err;
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	if (!(qcq->flags & IONIC_QCQ_F_INTR)) {
4458c2ecf20Sopenharmony_ci		qcq->intr.index = IONIC_INTR_INDEX_NOT_ASSIGNED;
4468c2ecf20Sopenharmony_ci		return 0;
4478c2ecf20Sopenharmony_ci	}
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	err = ionic_intr_alloc(lif, &qcq->intr);
4508c2ecf20Sopenharmony_ci	if (err) {
4518c2ecf20Sopenharmony_ci		netdev_warn(lif->netdev, "no intr for %s: %d\n",
4528c2ecf20Sopenharmony_ci			    qcq->q.name, err);
4538c2ecf20Sopenharmony_ci		goto err_out;
4548c2ecf20Sopenharmony_ci	}
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci	err = ionic_bus_get_irq(lif->ionic, qcq->intr.index);
4578c2ecf20Sopenharmony_ci	if (err < 0) {
4588c2ecf20Sopenharmony_ci		netdev_warn(lif->netdev, "no vector for %s: %d\n",
4598c2ecf20Sopenharmony_ci			    qcq->q.name, err);
4608c2ecf20Sopenharmony_ci		goto err_out_free_intr;
4618c2ecf20Sopenharmony_ci	}
4628c2ecf20Sopenharmony_ci	qcq->intr.vector = err;
4638c2ecf20Sopenharmony_ci	ionic_intr_mask_assert(lif->ionic->idev.intr_ctrl, qcq->intr.index,
4648c2ecf20Sopenharmony_ci			       IONIC_INTR_MASK_SET);
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	err = ionic_request_irq(lif, qcq);
4678c2ecf20Sopenharmony_ci	if (err) {
4688c2ecf20Sopenharmony_ci		netdev_warn(lif->netdev, "irq request failed %d\n", err);
4698c2ecf20Sopenharmony_ci		goto err_out_free_intr;
4708c2ecf20Sopenharmony_ci	}
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	/* try to get the irq on the local numa node first */
4738c2ecf20Sopenharmony_ci	qcq->intr.cpu = cpumask_local_spread(qcq->intr.index,
4748c2ecf20Sopenharmony_ci					     dev_to_node(lif->ionic->dev));
4758c2ecf20Sopenharmony_ci	if (qcq->intr.cpu != -1)
4768c2ecf20Sopenharmony_ci		cpumask_set_cpu(qcq->intr.cpu, &qcq->intr.affinity_mask);
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci	netdev_dbg(lif->netdev, "%s: Interrupt index %d\n", qcq->q.name, qcq->intr.index);
4798c2ecf20Sopenharmony_ci	return 0;
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_cierr_out_free_intr:
4828c2ecf20Sopenharmony_ci	ionic_intr_free(lif->ionic, qcq->intr.index);
4838c2ecf20Sopenharmony_cierr_out:
4848c2ecf20Sopenharmony_ci	return err;
4858c2ecf20Sopenharmony_ci}
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_cistatic int ionic_qcq_alloc(struct ionic_lif *lif, unsigned int type,
4888c2ecf20Sopenharmony_ci			   unsigned int index,
4898c2ecf20Sopenharmony_ci			   const char *name, unsigned int flags,
4908c2ecf20Sopenharmony_ci			   unsigned int num_descs, unsigned int desc_size,
4918c2ecf20Sopenharmony_ci			   unsigned int cq_desc_size,
4928c2ecf20Sopenharmony_ci			   unsigned int sg_desc_size,
4938c2ecf20Sopenharmony_ci			   unsigned int pid, struct ionic_qcq **qcq)
4948c2ecf20Sopenharmony_ci{
4958c2ecf20Sopenharmony_ci	struct ionic_dev *idev = &lif->ionic->idev;
4968c2ecf20Sopenharmony_ci	struct device *dev = lif->ionic->dev;
4978c2ecf20Sopenharmony_ci	void *q_base, *cq_base, *sg_base;
4988c2ecf20Sopenharmony_ci	dma_addr_t cq_base_pa = 0;
4998c2ecf20Sopenharmony_ci	dma_addr_t sg_base_pa = 0;
5008c2ecf20Sopenharmony_ci	dma_addr_t q_base_pa = 0;
5018c2ecf20Sopenharmony_ci	struct ionic_qcq *new;
5028c2ecf20Sopenharmony_ci	int err;
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci	*qcq = NULL;
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	new = devm_kzalloc(dev, sizeof(*new), GFP_KERNEL);
5078c2ecf20Sopenharmony_ci	if (!new) {
5088c2ecf20Sopenharmony_ci		netdev_err(lif->netdev, "Cannot allocate queue structure\n");
5098c2ecf20Sopenharmony_ci		err = -ENOMEM;
5108c2ecf20Sopenharmony_ci		goto err_out;
5118c2ecf20Sopenharmony_ci	}
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci	new->flags = flags;
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	new->q.info = devm_kcalloc(dev, num_descs, sizeof(*new->q.info),
5168c2ecf20Sopenharmony_ci				   GFP_KERNEL);
5178c2ecf20Sopenharmony_ci	if (!new->q.info) {
5188c2ecf20Sopenharmony_ci		netdev_err(lif->netdev, "Cannot allocate queue info\n");
5198c2ecf20Sopenharmony_ci		err = -ENOMEM;
5208c2ecf20Sopenharmony_ci		goto err_out_free_qcq;
5218c2ecf20Sopenharmony_ci	}
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci	new->q.type = type;
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	err = ionic_q_init(lif, idev, &new->q, index, name, num_descs,
5268c2ecf20Sopenharmony_ci			   desc_size, sg_desc_size, pid);
5278c2ecf20Sopenharmony_ci	if (err) {
5288c2ecf20Sopenharmony_ci		netdev_err(lif->netdev, "Cannot initialize queue\n");
5298c2ecf20Sopenharmony_ci		goto err_out_free_q_info;
5308c2ecf20Sopenharmony_ci	}
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	err = ionic_alloc_qcq_interrupt(lif, new);
5338c2ecf20Sopenharmony_ci	if (err)
5348c2ecf20Sopenharmony_ci		goto err_out;
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci	new->cq.info = devm_kcalloc(dev, num_descs, sizeof(*new->cq.info),
5378c2ecf20Sopenharmony_ci				    GFP_KERNEL);
5388c2ecf20Sopenharmony_ci	if (!new->cq.info) {
5398c2ecf20Sopenharmony_ci		netdev_err(lif->netdev, "Cannot allocate completion queue info\n");
5408c2ecf20Sopenharmony_ci		err = -ENOMEM;
5418c2ecf20Sopenharmony_ci		goto err_out_free_irq;
5428c2ecf20Sopenharmony_ci	}
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci	err = ionic_cq_init(lif, &new->cq, &new->intr, num_descs, cq_desc_size);
5458c2ecf20Sopenharmony_ci	if (err) {
5468c2ecf20Sopenharmony_ci		netdev_err(lif->netdev, "Cannot initialize completion queue\n");
5478c2ecf20Sopenharmony_ci		goto err_out_free_cq_info;
5488c2ecf20Sopenharmony_ci	}
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	if (flags & IONIC_QCQ_F_NOTIFYQ) {
5518c2ecf20Sopenharmony_ci		int q_size, cq_size;
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci		/* q & cq need to be contiguous in case of notifyq */
5548c2ecf20Sopenharmony_ci		q_size = ALIGN(num_descs * desc_size, PAGE_SIZE);
5558c2ecf20Sopenharmony_ci		cq_size = ALIGN(num_descs * cq_desc_size, PAGE_SIZE);
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci		new->q_size = PAGE_SIZE + q_size + cq_size;
5588c2ecf20Sopenharmony_ci		new->q_base = dma_alloc_coherent(dev, new->q_size,
5598c2ecf20Sopenharmony_ci						 &new->q_base_pa, GFP_KERNEL);
5608c2ecf20Sopenharmony_ci		if (!new->q_base) {
5618c2ecf20Sopenharmony_ci			netdev_err(lif->netdev, "Cannot allocate qcq DMA memory\n");
5628c2ecf20Sopenharmony_ci			err = -ENOMEM;
5638c2ecf20Sopenharmony_ci			goto err_out_free_cq_info;
5648c2ecf20Sopenharmony_ci		}
5658c2ecf20Sopenharmony_ci		q_base = PTR_ALIGN(new->q_base, PAGE_SIZE);
5668c2ecf20Sopenharmony_ci		q_base_pa = ALIGN(new->q_base_pa, PAGE_SIZE);
5678c2ecf20Sopenharmony_ci		ionic_q_map(&new->q, q_base, q_base_pa);
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci		cq_base = PTR_ALIGN(q_base + q_size, PAGE_SIZE);
5708c2ecf20Sopenharmony_ci		cq_base_pa = ALIGN(new->q_base_pa + q_size, PAGE_SIZE);
5718c2ecf20Sopenharmony_ci		ionic_cq_map(&new->cq, cq_base, cq_base_pa);
5728c2ecf20Sopenharmony_ci		ionic_cq_bind(&new->cq, &new->q);
5738c2ecf20Sopenharmony_ci	} else {
5748c2ecf20Sopenharmony_ci		new->q_size = PAGE_SIZE + (num_descs * desc_size);
5758c2ecf20Sopenharmony_ci		new->q_base = dma_alloc_coherent(dev, new->q_size, &new->q_base_pa,
5768c2ecf20Sopenharmony_ci						 GFP_KERNEL);
5778c2ecf20Sopenharmony_ci		if (!new->q_base) {
5788c2ecf20Sopenharmony_ci			netdev_err(lif->netdev, "Cannot allocate queue DMA memory\n");
5798c2ecf20Sopenharmony_ci			err = -ENOMEM;
5808c2ecf20Sopenharmony_ci			goto err_out_free_cq_info;
5818c2ecf20Sopenharmony_ci		}
5828c2ecf20Sopenharmony_ci		q_base = PTR_ALIGN(new->q_base, PAGE_SIZE);
5838c2ecf20Sopenharmony_ci		q_base_pa = ALIGN(new->q_base_pa, PAGE_SIZE);
5848c2ecf20Sopenharmony_ci		ionic_q_map(&new->q, q_base, q_base_pa);
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci		new->cq_size = PAGE_SIZE + (num_descs * cq_desc_size);
5878c2ecf20Sopenharmony_ci		new->cq_base = dma_alloc_coherent(dev, new->cq_size, &new->cq_base_pa,
5888c2ecf20Sopenharmony_ci						  GFP_KERNEL);
5898c2ecf20Sopenharmony_ci		if (!new->cq_base) {
5908c2ecf20Sopenharmony_ci			netdev_err(lif->netdev, "Cannot allocate cq DMA memory\n");
5918c2ecf20Sopenharmony_ci			err = -ENOMEM;
5928c2ecf20Sopenharmony_ci			goto err_out_free_q;
5938c2ecf20Sopenharmony_ci		}
5948c2ecf20Sopenharmony_ci		cq_base = PTR_ALIGN(new->cq_base, PAGE_SIZE);
5958c2ecf20Sopenharmony_ci		cq_base_pa = ALIGN(new->cq_base_pa, PAGE_SIZE);
5968c2ecf20Sopenharmony_ci		ionic_cq_map(&new->cq, cq_base, cq_base_pa);
5978c2ecf20Sopenharmony_ci		ionic_cq_bind(&new->cq, &new->q);
5988c2ecf20Sopenharmony_ci	}
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci	if (flags & IONIC_QCQ_F_SG) {
6018c2ecf20Sopenharmony_ci		new->sg_size = PAGE_SIZE + (num_descs * sg_desc_size);
6028c2ecf20Sopenharmony_ci		new->sg_base = dma_alloc_coherent(dev, new->sg_size, &new->sg_base_pa,
6038c2ecf20Sopenharmony_ci						  GFP_KERNEL);
6048c2ecf20Sopenharmony_ci		if (!new->sg_base) {
6058c2ecf20Sopenharmony_ci			netdev_err(lif->netdev, "Cannot allocate sg DMA memory\n");
6068c2ecf20Sopenharmony_ci			err = -ENOMEM;
6078c2ecf20Sopenharmony_ci			goto err_out_free_cq;
6088c2ecf20Sopenharmony_ci		}
6098c2ecf20Sopenharmony_ci		sg_base = PTR_ALIGN(new->sg_base, PAGE_SIZE);
6108c2ecf20Sopenharmony_ci		sg_base_pa = ALIGN(new->sg_base_pa, PAGE_SIZE);
6118c2ecf20Sopenharmony_ci		ionic_q_sg_map(&new->q, sg_base, sg_base_pa);
6128c2ecf20Sopenharmony_ci	}
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci	INIT_WORK(&new->dim.work, ionic_dim_work);
6158c2ecf20Sopenharmony_ci	new->dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE;
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ci	*qcq = new;
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci	return 0;
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_cierr_out_free_cq:
6228c2ecf20Sopenharmony_ci	dma_free_coherent(dev, new->cq_size, new->cq_base, new->cq_base_pa);
6238c2ecf20Sopenharmony_cierr_out_free_q:
6248c2ecf20Sopenharmony_ci	dma_free_coherent(dev, new->q_size, new->q_base, new->q_base_pa);
6258c2ecf20Sopenharmony_cierr_out_free_cq_info:
6268c2ecf20Sopenharmony_ci	devm_kfree(dev, new->cq.info);
6278c2ecf20Sopenharmony_cierr_out_free_irq:
6288c2ecf20Sopenharmony_ci	if (flags & IONIC_QCQ_F_INTR) {
6298c2ecf20Sopenharmony_ci		devm_free_irq(dev, new->intr.vector, &new->napi);
6308c2ecf20Sopenharmony_ci		ionic_intr_free(lif->ionic, new->intr.index);
6318c2ecf20Sopenharmony_ci	}
6328c2ecf20Sopenharmony_cierr_out_free_q_info:
6338c2ecf20Sopenharmony_ci	devm_kfree(dev, new->q.info);
6348c2ecf20Sopenharmony_cierr_out_free_qcq:
6358c2ecf20Sopenharmony_ci	devm_kfree(dev, new);
6368c2ecf20Sopenharmony_cierr_out:
6378c2ecf20Sopenharmony_ci	dev_err(dev, "qcq alloc of %s%d failed %d\n", name, index, err);
6388c2ecf20Sopenharmony_ci	return err;
6398c2ecf20Sopenharmony_ci}
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_cistatic int ionic_qcqs_alloc(struct ionic_lif *lif)
6428c2ecf20Sopenharmony_ci{
6438c2ecf20Sopenharmony_ci	struct device *dev = lif->ionic->dev;
6448c2ecf20Sopenharmony_ci	unsigned int flags;
6458c2ecf20Sopenharmony_ci	int err;
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci	flags = IONIC_QCQ_F_INTR;
6488c2ecf20Sopenharmony_ci	err = ionic_qcq_alloc(lif, IONIC_QTYPE_ADMINQ, 0, "admin", flags,
6498c2ecf20Sopenharmony_ci			      IONIC_ADMINQ_LENGTH,
6508c2ecf20Sopenharmony_ci			      sizeof(struct ionic_admin_cmd),
6518c2ecf20Sopenharmony_ci			      sizeof(struct ionic_admin_comp),
6528c2ecf20Sopenharmony_ci			      0, lif->kern_pid, &lif->adminqcq);
6538c2ecf20Sopenharmony_ci	if (err)
6548c2ecf20Sopenharmony_ci		return err;
6558c2ecf20Sopenharmony_ci	ionic_debugfs_add_qcq(lif, lif->adminqcq);
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_ci	if (lif->ionic->nnqs_per_lif) {
6588c2ecf20Sopenharmony_ci		flags = IONIC_QCQ_F_NOTIFYQ;
6598c2ecf20Sopenharmony_ci		err = ionic_qcq_alloc(lif, IONIC_QTYPE_NOTIFYQ, 0, "notifyq",
6608c2ecf20Sopenharmony_ci				      flags, IONIC_NOTIFYQ_LENGTH,
6618c2ecf20Sopenharmony_ci				      sizeof(struct ionic_notifyq_cmd),
6628c2ecf20Sopenharmony_ci				      sizeof(union ionic_notifyq_comp),
6638c2ecf20Sopenharmony_ci				      0, lif->kern_pid, &lif->notifyqcq);
6648c2ecf20Sopenharmony_ci		if (err)
6658c2ecf20Sopenharmony_ci			goto err_out;
6668c2ecf20Sopenharmony_ci		ionic_debugfs_add_qcq(lif, lif->notifyqcq);
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ci		/* Let the notifyq ride on the adminq interrupt */
6698c2ecf20Sopenharmony_ci		ionic_link_qcq_interrupts(lif->adminqcq, lif->notifyqcq);
6708c2ecf20Sopenharmony_ci	}
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	err = -ENOMEM;
6738c2ecf20Sopenharmony_ci	lif->txqcqs = devm_kcalloc(dev, lif->ionic->ntxqs_per_lif,
6748c2ecf20Sopenharmony_ci				   sizeof(struct ionic_qcq *), GFP_KERNEL);
6758c2ecf20Sopenharmony_ci	if (!lif->txqcqs)
6768c2ecf20Sopenharmony_ci		goto err_out;
6778c2ecf20Sopenharmony_ci	lif->rxqcqs = devm_kcalloc(dev, lif->ionic->nrxqs_per_lif,
6788c2ecf20Sopenharmony_ci				   sizeof(struct ionic_qcq *), GFP_KERNEL);
6798c2ecf20Sopenharmony_ci	if (!lif->rxqcqs)
6808c2ecf20Sopenharmony_ci		goto err_out;
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ci	lif->txqstats = devm_kcalloc(dev, lif->ionic->ntxqs_per_lif,
6838c2ecf20Sopenharmony_ci				     sizeof(struct ionic_tx_stats), GFP_KERNEL);
6848c2ecf20Sopenharmony_ci	if (!lif->txqstats)
6858c2ecf20Sopenharmony_ci		goto err_out;
6868c2ecf20Sopenharmony_ci	lif->rxqstats = devm_kcalloc(dev, lif->ionic->nrxqs_per_lif,
6878c2ecf20Sopenharmony_ci				     sizeof(struct ionic_rx_stats), GFP_KERNEL);
6888c2ecf20Sopenharmony_ci	if (!lif->rxqstats)
6898c2ecf20Sopenharmony_ci		goto err_out;
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci	return 0;
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_cierr_out:
6948c2ecf20Sopenharmony_ci	ionic_qcqs_free(lif);
6958c2ecf20Sopenharmony_ci	return err;
6968c2ecf20Sopenharmony_ci}
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_cistatic void ionic_qcq_sanitize(struct ionic_qcq *qcq)
6998c2ecf20Sopenharmony_ci{
7008c2ecf20Sopenharmony_ci	qcq->q.tail_idx = 0;
7018c2ecf20Sopenharmony_ci	qcq->q.head_idx = 0;
7028c2ecf20Sopenharmony_ci	qcq->cq.tail_idx = 0;
7038c2ecf20Sopenharmony_ci	qcq->cq.done_color = 1;
7048c2ecf20Sopenharmony_ci	memset(qcq->q_base, 0, qcq->q_size);
7058c2ecf20Sopenharmony_ci	memset(qcq->cq_base, 0, qcq->cq_size);
7068c2ecf20Sopenharmony_ci	memset(qcq->sg_base, 0, qcq->sg_size);
7078c2ecf20Sopenharmony_ci}
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_cistatic int ionic_lif_txq_init(struct ionic_lif *lif, struct ionic_qcq *qcq)
7108c2ecf20Sopenharmony_ci{
7118c2ecf20Sopenharmony_ci	struct device *dev = lif->ionic->dev;
7128c2ecf20Sopenharmony_ci	struct ionic_queue *q = &qcq->q;
7138c2ecf20Sopenharmony_ci	struct ionic_cq *cq = &qcq->cq;
7148c2ecf20Sopenharmony_ci	struct ionic_admin_ctx ctx = {
7158c2ecf20Sopenharmony_ci		.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
7168c2ecf20Sopenharmony_ci		.cmd.q_init = {
7178c2ecf20Sopenharmony_ci			.opcode = IONIC_CMD_Q_INIT,
7188c2ecf20Sopenharmony_ci			.lif_index = cpu_to_le16(lif->index),
7198c2ecf20Sopenharmony_ci			.type = q->type,
7208c2ecf20Sopenharmony_ci			.ver = lif->qtype_info[q->type].version,
7218c2ecf20Sopenharmony_ci			.index = cpu_to_le32(q->index),
7228c2ecf20Sopenharmony_ci			.flags = cpu_to_le16(IONIC_QINIT_F_IRQ |
7238c2ecf20Sopenharmony_ci					     IONIC_QINIT_F_SG),
7248c2ecf20Sopenharmony_ci			.pid = cpu_to_le16(q->pid),
7258c2ecf20Sopenharmony_ci			.ring_size = ilog2(q->num_descs),
7268c2ecf20Sopenharmony_ci			.ring_base = cpu_to_le64(q->base_pa),
7278c2ecf20Sopenharmony_ci			.cq_ring_base = cpu_to_le64(cq->base_pa),
7288c2ecf20Sopenharmony_ci			.sg_ring_base = cpu_to_le64(q->sg_base_pa),
7298c2ecf20Sopenharmony_ci		},
7308c2ecf20Sopenharmony_ci	};
7318c2ecf20Sopenharmony_ci	unsigned int intr_index;
7328c2ecf20Sopenharmony_ci	int err;
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci	if (qcq->flags & IONIC_QCQ_F_INTR)
7358c2ecf20Sopenharmony_ci		intr_index = qcq->intr.index;
7368c2ecf20Sopenharmony_ci	else
7378c2ecf20Sopenharmony_ci		intr_index = lif->rxqcqs[q->index]->intr.index;
7388c2ecf20Sopenharmony_ci	ctx.cmd.q_init.intr_index = cpu_to_le16(intr_index);
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci	dev_dbg(dev, "txq_init.pid %d\n", ctx.cmd.q_init.pid);
7418c2ecf20Sopenharmony_ci	dev_dbg(dev, "txq_init.index %d\n", ctx.cmd.q_init.index);
7428c2ecf20Sopenharmony_ci	dev_dbg(dev, "txq_init.ring_base 0x%llx\n", ctx.cmd.q_init.ring_base);
7438c2ecf20Sopenharmony_ci	dev_dbg(dev, "txq_init.ring_size %d\n", ctx.cmd.q_init.ring_size);
7448c2ecf20Sopenharmony_ci	dev_dbg(dev, "txq_init.flags 0x%x\n", ctx.cmd.q_init.flags);
7458c2ecf20Sopenharmony_ci	dev_dbg(dev, "txq_init.ver %d\n", ctx.cmd.q_init.ver);
7468c2ecf20Sopenharmony_ci	dev_dbg(dev, "txq_init.intr_index %d\n", ctx.cmd.q_init.intr_index);
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_ci	ionic_qcq_sanitize(qcq);
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_ci	err = ionic_adminq_post_wait(lif, &ctx);
7518c2ecf20Sopenharmony_ci	if (err)
7528c2ecf20Sopenharmony_ci		return err;
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_ci	q->hw_type = ctx.comp.q_init.hw_type;
7558c2ecf20Sopenharmony_ci	q->hw_index = le32_to_cpu(ctx.comp.q_init.hw_index);
7568c2ecf20Sopenharmony_ci	q->dbval = IONIC_DBELL_QID(q->hw_index);
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci	dev_dbg(dev, "txq->hw_type %d\n", q->hw_type);
7598c2ecf20Sopenharmony_ci	dev_dbg(dev, "txq->hw_index %d\n", q->hw_index);
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci	if (test_bit(IONIC_LIF_F_SPLIT_INTR, lif->state))
7628c2ecf20Sopenharmony_ci		netif_napi_add(lif->netdev, &qcq->napi, ionic_tx_napi,
7638c2ecf20Sopenharmony_ci			       NAPI_POLL_WEIGHT);
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ci	qcq->flags |= IONIC_QCQ_F_INITED;
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci	return 0;
7688c2ecf20Sopenharmony_ci}
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_cistatic int ionic_lif_rxq_init(struct ionic_lif *lif, struct ionic_qcq *qcq)
7718c2ecf20Sopenharmony_ci{
7728c2ecf20Sopenharmony_ci	struct device *dev = lif->ionic->dev;
7738c2ecf20Sopenharmony_ci	struct ionic_queue *q = &qcq->q;
7748c2ecf20Sopenharmony_ci	struct ionic_cq *cq = &qcq->cq;
7758c2ecf20Sopenharmony_ci	struct ionic_admin_ctx ctx = {
7768c2ecf20Sopenharmony_ci		.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
7778c2ecf20Sopenharmony_ci		.cmd.q_init = {
7788c2ecf20Sopenharmony_ci			.opcode = IONIC_CMD_Q_INIT,
7798c2ecf20Sopenharmony_ci			.lif_index = cpu_to_le16(lif->index),
7808c2ecf20Sopenharmony_ci			.type = q->type,
7818c2ecf20Sopenharmony_ci			.ver = lif->qtype_info[q->type].version,
7828c2ecf20Sopenharmony_ci			.index = cpu_to_le32(q->index),
7838c2ecf20Sopenharmony_ci			.flags = cpu_to_le16(IONIC_QINIT_F_IRQ |
7848c2ecf20Sopenharmony_ci					     IONIC_QINIT_F_SG),
7858c2ecf20Sopenharmony_ci			.intr_index = cpu_to_le16(cq->bound_intr->index),
7868c2ecf20Sopenharmony_ci			.pid = cpu_to_le16(q->pid),
7878c2ecf20Sopenharmony_ci			.ring_size = ilog2(q->num_descs),
7888c2ecf20Sopenharmony_ci			.ring_base = cpu_to_le64(q->base_pa),
7898c2ecf20Sopenharmony_ci			.cq_ring_base = cpu_to_le64(cq->base_pa),
7908c2ecf20Sopenharmony_ci			.sg_ring_base = cpu_to_le64(q->sg_base_pa),
7918c2ecf20Sopenharmony_ci		},
7928c2ecf20Sopenharmony_ci	};
7938c2ecf20Sopenharmony_ci	int err;
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_ci	dev_dbg(dev, "rxq_init.pid %d\n", ctx.cmd.q_init.pid);
7968c2ecf20Sopenharmony_ci	dev_dbg(dev, "rxq_init.index %d\n", ctx.cmd.q_init.index);
7978c2ecf20Sopenharmony_ci	dev_dbg(dev, "rxq_init.ring_base 0x%llx\n", ctx.cmd.q_init.ring_base);
7988c2ecf20Sopenharmony_ci	dev_dbg(dev, "rxq_init.ring_size %d\n", ctx.cmd.q_init.ring_size);
7998c2ecf20Sopenharmony_ci	dev_dbg(dev, "rxq_init.flags 0x%x\n", ctx.cmd.q_init.flags);
8008c2ecf20Sopenharmony_ci	dev_dbg(dev, "rxq_init.ver %d\n", ctx.cmd.q_init.ver);
8018c2ecf20Sopenharmony_ci	dev_dbg(dev, "rxq_init.intr_index %d\n", ctx.cmd.q_init.intr_index);
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_ci	ionic_qcq_sanitize(qcq);
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci	err = ionic_adminq_post_wait(lif, &ctx);
8068c2ecf20Sopenharmony_ci	if (err)
8078c2ecf20Sopenharmony_ci		return err;
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci	q->hw_type = ctx.comp.q_init.hw_type;
8108c2ecf20Sopenharmony_ci	q->hw_index = le32_to_cpu(ctx.comp.q_init.hw_index);
8118c2ecf20Sopenharmony_ci	q->dbval = IONIC_DBELL_QID(q->hw_index);
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ci	dev_dbg(dev, "rxq->hw_type %d\n", q->hw_type);
8148c2ecf20Sopenharmony_ci	dev_dbg(dev, "rxq->hw_index %d\n", q->hw_index);
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_ci	if (test_bit(IONIC_LIF_F_SPLIT_INTR, lif->state))
8178c2ecf20Sopenharmony_ci		netif_napi_add(lif->netdev, &qcq->napi, ionic_rx_napi,
8188c2ecf20Sopenharmony_ci			       NAPI_POLL_WEIGHT);
8198c2ecf20Sopenharmony_ci	else
8208c2ecf20Sopenharmony_ci		netif_napi_add(lif->netdev, &qcq->napi, ionic_txrx_napi,
8218c2ecf20Sopenharmony_ci			       NAPI_POLL_WEIGHT);
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci	qcq->flags |= IONIC_QCQ_F_INITED;
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci	return 0;
8268c2ecf20Sopenharmony_ci}
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_cistatic bool ionic_notifyq_service(struct ionic_cq *cq,
8298c2ecf20Sopenharmony_ci				  struct ionic_cq_info *cq_info)
8308c2ecf20Sopenharmony_ci{
8318c2ecf20Sopenharmony_ci	union ionic_notifyq_comp *comp = cq_info->cq_desc;
8328c2ecf20Sopenharmony_ci	struct ionic_deferred_work *work;
8338c2ecf20Sopenharmony_ci	struct net_device *netdev;
8348c2ecf20Sopenharmony_ci	struct ionic_queue *q;
8358c2ecf20Sopenharmony_ci	struct ionic_lif *lif;
8368c2ecf20Sopenharmony_ci	u64 eid;
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_ci	q = cq->bound_q;
8398c2ecf20Sopenharmony_ci	lif = q->info[0].cb_arg;
8408c2ecf20Sopenharmony_ci	netdev = lif->netdev;
8418c2ecf20Sopenharmony_ci	eid = le64_to_cpu(comp->event.eid);
8428c2ecf20Sopenharmony_ci
8438c2ecf20Sopenharmony_ci	/* Have we run out of new completions to process? */
8448c2ecf20Sopenharmony_ci	if ((s64)(eid - lif->last_eid) <= 0)
8458c2ecf20Sopenharmony_ci		return false;
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ci	lif->last_eid = eid;
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_ci	dev_dbg(lif->ionic->dev, "notifyq event:\n");
8508c2ecf20Sopenharmony_ci	dynamic_hex_dump("event ", DUMP_PREFIX_OFFSET, 16, 1,
8518c2ecf20Sopenharmony_ci			 comp, sizeof(*comp), true);
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_ci	switch (le16_to_cpu(comp->event.ecode)) {
8548c2ecf20Sopenharmony_ci	case IONIC_EVENT_LINK_CHANGE:
8558c2ecf20Sopenharmony_ci		ionic_link_status_check_request(lif, false);
8568c2ecf20Sopenharmony_ci		break;
8578c2ecf20Sopenharmony_ci	case IONIC_EVENT_RESET:
8588c2ecf20Sopenharmony_ci		work = kzalloc(sizeof(*work), GFP_ATOMIC);
8598c2ecf20Sopenharmony_ci		if (!work) {
8608c2ecf20Sopenharmony_ci			netdev_err(lif->netdev, "%s OOM\n", __func__);
8618c2ecf20Sopenharmony_ci		} else {
8628c2ecf20Sopenharmony_ci			work->type = IONIC_DW_TYPE_LIF_RESET;
8638c2ecf20Sopenharmony_ci			ionic_lif_deferred_enqueue(&lif->deferred, work);
8648c2ecf20Sopenharmony_ci		}
8658c2ecf20Sopenharmony_ci		break;
8668c2ecf20Sopenharmony_ci	default:
8678c2ecf20Sopenharmony_ci		netdev_warn(netdev, "Notifyq event ecode=%d eid=%lld\n",
8688c2ecf20Sopenharmony_ci			    comp->event.ecode, eid);
8698c2ecf20Sopenharmony_ci		break;
8708c2ecf20Sopenharmony_ci	}
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_ci	return true;
8738c2ecf20Sopenharmony_ci}
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_cistatic bool ionic_adminq_service(struct ionic_cq *cq,
8768c2ecf20Sopenharmony_ci				 struct ionic_cq_info *cq_info)
8778c2ecf20Sopenharmony_ci{
8788c2ecf20Sopenharmony_ci	struct ionic_admin_comp *comp = cq_info->cq_desc;
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_ci	if (!color_match(comp->color, cq->done_color))
8818c2ecf20Sopenharmony_ci		return false;
8828c2ecf20Sopenharmony_ci
8838c2ecf20Sopenharmony_ci	ionic_q_service(cq->bound_q, cq_info, le16_to_cpu(comp->comp_index));
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_ci	return true;
8868c2ecf20Sopenharmony_ci}
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_cistatic int ionic_adminq_napi(struct napi_struct *napi, int budget)
8898c2ecf20Sopenharmony_ci{
8908c2ecf20Sopenharmony_ci	struct ionic_intr_info *intr = napi_to_cq(napi)->bound_intr;
8918c2ecf20Sopenharmony_ci	struct ionic_lif *lif = napi_to_cq(napi)->lif;
8928c2ecf20Sopenharmony_ci	struct ionic_dev *idev = &lif->ionic->idev;
8938c2ecf20Sopenharmony_ci	unsigned int flags = 0;
8948c2ecf20Sopenharmony_ci	int n_work = 0;
8958c2ecf20Sopenharmony_ci	int a_work = 0;
8968c2ecf20Sopenharmony_ci	int work_done;
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci	if (lif->notifyqcq && lif->notifyqcq->flags & IONIC_QCQ_F_INITED)
8998c2ecf20Sopenharmony_ci		n_work = ionic_cq_service(&lif->notifyqcq->cq, budget,
9008c2ecf20Sopenharmony_ci					  ionic_notifyq_service, NULL, NULL);
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ci	if (lif->adminqcq && lif->adminqcq->flags & IONIC_QCQ_F_INITED)
9038c2ecf20Sopenharmony_ci		a_work = ionic_cq_service(&lif->adminqcq->cq, budget,
9048c2ecf20Sopenharmony_ci					  ionic_adminq_service, NULL, NULL);
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_ci	work_done = max(n_work, a_work);
9078c2ecf20Sopenharmony_ci	if (work_done < budget && napi_complete_done(napi, work_done)) {
9088c2ecf20Sopenharmony_ci		flags |= IONIC_INTR_CRED_UNMASK;
9098c2ecf20Sopenharmony_ci		lif->adminqcq->cq.bound_intr->rearm_count++;
9108c2ecf20Sopenharmony_ci	}
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci	if (work_done || flags) {
9138c2ecf20Sopenharmony_ci		flags |= IONIC_INTR_CRED_RESET_COALESCE;
9148c2ecf20Sopenharmony_ci		ionic_intr_credits(idev->intr_ctrl,
9158c2ecf20Sopenharmony_ci				   intr->index,
9168c2ecf20Sopenharmony_ci				   n_work + a_work, flags);
9178c2ecf20Sopenharmony_ci	}
9188c2ecf20Sopenharmony_ci
9198c2ecf20Sopenharmony_ci	return work_done;
9208c2ecf20Sopenharmony_ci}
9218c2ecf20Sopenharmony_ci
9228c2ecf20Sopenharmony_civoid ionic_get_stats64(struct net_device *netdev,
9238c2ecf20Sopenharmony_ci		       struct rtnl_link_stats64 *ns)
9248c2ecf20Sopenharmony_ci{
9258c2ecf20Sopenharmony_ci	struct ionic_lif *lif = netdev_priv(netdev);
9268c2ecf20Sopenharmony_ci	struct ionic_lif_stats *ls;
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ci	memset(ns, 0, sizeof(*ns));
9298c2ecf20Sopenharmony_ci	ls = &lif->info->stats;
9308c2ecf20Sopenharmony_ci
9318c2ecf20Sopenharmony_ci	ns->rx_packets = le64_to_cpu(ls->rx_ucast_packets) +
9328c2ecf20Sopenharmony_ci			 le64_to_cpu(ls->rx_mcast_packets) +
9338c2ecf20Sopenharmony_ci			 le64_to_cpu(ls->rx_bcast_packets);
9348c2ecf20Sopenharmony_ci
9358c2ecf20Sopenharmony_ci	ns->tx_packets = le64_to_cpu(ls->tx_ucast_packets) +
9368c2ecf20Sopenharmony_ci			 le64_to_cpu(ls->tx_mcast_packets) +
9378c2ecf20Sopenharmony_ci			 le64_to_cpu(ls->tx_bcast_packets);
9388c2ecf20Sopenharmony_ci
9398c2ecf20Sopenharmony_ci	ns->rx_bytes = le64_to_cpu(ls->rx_ucast_bytes) +
9408c2ecf20Sopenharmony_ci		       le64_to_cpu(ls->rx_mcast_bytes) +
9418c2ecf20Sopenharmony_ci		       le64_to_cpu(ls->rx_bcast_bytes);
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci	ns->tx_bytes = le64_to_cpu(ls->tx_ucast_bytes) +
9448c2ecf20Sopenharmony_ci		       le64_to_cpu(ls->tx_mcast_bytes) +
9458c2ecf20Sopenharmony_ci		       le64_to_cpu(ls->tx_bcast_bytes);
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci	ns->rx_dropped = le64_to_cpu(ls->rx_ucast_drop_packets) +
9488c2ecf20Sopenharmony_ci			 le64_to_cpu(ls->rx_mcast_drop_packets) +
9498c2ecf20Sopenharmony_ci			 le64_to_cpu(ls->rx_bcast_drop_packets);
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci	ns->tx_dropped = le64_to_cpu(ls->tx_ucast_drop_packets) +
9528c2ecf20Sopenharmony_ci			 le64_to_cpu(ls->tx_mcast_drop_packets) +
9538c2ecf20Sopenharmony_ci			 le64_to_cpu(ls->tx_bcast_drop_packets);
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_ci	ns->multicast = le64_to_cpu(ls->rx_mcast_packets);
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_ci	ns->rx_over_errors = le64_to_cpu(ls->rx_queue_empty);
9588c2ecf20Sopenharmony_ci
9598c2ecf20Sopenharmony_ci	ns->rx_missed_errors = le64_to_cpu(ls->rx_dma_error) +
9608c2ecf20Sopenharmony_ci			       le64_to_cpu(ls->rx_queue_disabled) +
9618c2ecf20Sopenharmony_ci			       le64_to_cpu(ls->rx_desc_fetch_error) +
9628c2ecf20Sopenharmony_ci			       le64_to_cpu(ls->rx_desc_data_error);
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_ci	ns->tx_aborted_errors = le64_to_cpu(ls->tx_dma_error) +
9658c2ecf20Sopenharmony_ci				le64_to_cpu(ls->tx_queue_disabled) +
9668c2ecf20Sopenharmony_ci				le64_to_cpu(ls->tx_desc_fetch_error) +
9678c2ecf20Sopenharmony_ci				le64_to_cpu(ls->tx_desc_data_error);
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_ci	ns->rx_errors = ns->rx_over_errors +
9708c2ecf20Sopenharmony_ci			ns->rx_missed_errors;
9718c2ecf20Sopenharmony_ci
9728c2ecf20Sopenharmony_ci	ns->tx_errors = ns->tx_aborted_errors;
9738c2ecf20Sopenharmony_ci}
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_cistatic int ionic_lif_addr_add(struct ionic_lif *lif, const u8 *addr)
9768c2ecf20Sopenharmony_ci{
9778c2ecf20Sopenharmony_ci	struct ionic_admin_ctx ctx = {
9788c2ecf20Sopenharmony_ci		.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
9798c2ecf20Sopenharmony_ci		.cmd.rx_filter_add = {
9808c2ecf20Sopenharmony_ci			.opcode = IONIC_CMD_RX_FILTER_ADD,
9818c2ecf20Sopenharmony_ci			.lif_index = cpu_to_le16(lif->index),
9828c2ecf20Sopenharmony_ci			.match = cpu_to_le16(IONIC_RX_FILTER_MATCH_MAC),
9838c2ecf20Sopenharmony_ci		},
9848c2ecf20Sopenharmony_ci	};
9858c2ecf20Sopenharmony_ci	struct ionic_rx_filter *f;
9868c2ecf20Sopenharmony_ci	int err;
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_ci	/* don't bother if we already have it */
9898c2ecf20Sopenharmony_ci	spin_lock_bh(&lif->rx_filters.lock);
9908c2ecf20Sopenharmony_ci	f = ionic_rx_filter_by_addr(lif, addr);
9918c2ecf20Sopenharmony_ci	spin_unlock_bh(&lif->rx_filters.lock);
9928c2ecf20Sopenharmony_ci	if (f)
9938c2ecf20Sopenharmony_ci		return 0;
9948c2ecf20Sopenharmony_ci
9958c2ecf20Sopenharmony_ci	netdev_dbg(lif->netdev, "rx_filter add ADDR %pM\n", addr);
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_ci	memcpy(ctx.cmd.rx_filter_add.mac.addr, addr, ETH_ALEN);
9988c2ecf20Sopenharmony_ci	err = ionic_adminq_post_wait(lif, &ctx);
9998c2ecf20Sopenharmony_ci	if (err && err != -EEXIST)
10008c2ecf20Sopenharmony_ci		return err;
10018c2ecf20Sopenharmony_ci
10028c2ecf20Sopenharmony_ci	return ionic_rx_filter_save(lif, 0, IONIC_RXQ_INDEX_ANY, 0, &ctx);
10038c2ecf20Sopenharmony_ci}
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_cistatic int ionic_lif_addr_del(struct ionic_lif *lif, const u8 *addr)
10068c2ecf20Sopenharmony_ci{
10078c2ecf20Sopenharmony_ci	struct ionic_admin_ctx ctx = {
10088c2ecf20Sopenharmony_ci		.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
10098c2ecf20Sopenharmony_ci		.cmd.rx_filter_del = {
10108c2ecf20Sopenharmony_ci			.opcode = IONIC_CMD_RX_FILTER_DEL,
10118c2ecf20Sopenharmony_ci			.lif_index = cpu_to_le16(lif->index),
10128c2ecf20Sopenharmony_ci		},
10138c2ecf20Sopenharmony_ci	};
10148c2ecf20Sopenharmony_ci	struct ionic_rx_filter *f;
10158c2ecf20Sopenharmony_ci	int err;
10168c2ecf20Sopenharmony_ci
10178c2ecf20Sopenharmony_ci	spin_lock_bh(&lif->rx_filters.lock);
10188c2ecf20Sopenharmony_ci	f = ionic_rx_filter_by_addr(lif, addr);
10198c2ecf20Sopenharmony_ci	if (!f) {
10208c2ecf20Sopenharmony_ci		spin_unlock_bh(&lif->rx_filters.lock);
10218c2ecf20Sopenharmony_ci		return -ENOENT;
10228c2ecf20Sopenharmony_ci	}
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_ci	netdev_dbg(lif->netdev, "rx_filter del ADDR %pM (id %d)\n",
10258c2ecf20Sopenharmony_ci		   addr, f->filter_id);
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_ci	ctx.cmd.rx_filter_del.filter_id = cpu_to_le32(f->filter_id);
10288c2ecf20Sopenharmony_ci	ionic_rx_filter_free(lif, f);
10298c2ecf20Sopenharmony_ci	spin_unlock_bh(&lif->rx_filters.lock);
10308c2ecf20Sopenharmony_ci
10318c2ecf20Sopenharmony_ci	err = ionic_adminq_post_wait(lif, &ctx);
10328c2ecf20Sopenharmony_ci	if (err && err != -EEXIST)
10338c2ecf20Sopenharmony_ci		return err;
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_ci	return 0;
10368c2ecf20Sopenharmony_ci}
10378c2ecf20Sopenharmony_ci
10388c2ecf20Sopenharmony_cistatic int ionic_lif_addr(struct ionic_lif *lif, const u8 *addr, bool add,
10398c2ecf20Sopenharmony_ci			  bool can_sleep)
10408c2ecf20Sopenharmony_ci{
10418c2ecf20Sopenharmony_ci	struct ionic_deferred_work *work;
10428c2ecf20Sopenharmony_ci	unsigned int nmfilters;
10438c2ecf20Sopenharmony_ci	unsigned int nufilters;
10448c2ecf20Sopenharmony_ci
10458c2ecf20Sopenharmony_ci	if (add) {
10468c2ecf20Sopenharmony_ci		/* Do we have space for this filter?  We test the counters
10478c2ecf20Sopenharmony_ci		 * here before checking the need for deferral so that we
10488c2ecf20Sopenharmony_ci		 * can return an overflow error to the stack.
10498c2ecf20Sopenharmony_ci		 */
10508c2ecf20Sopenharmony_ci		nmfilters = le32_to_cpu(lif->identity->eth.max_mcast_filters);
10518c2ecf20Sopenharmony_ci		nufilters = le32_to_cpu(lif->identity->eth.max_ucast_filters);
10528c2ecf20Sopenharmony_ci
10538c2ecf20Sopenharmony_ci		if ((is_multicast_ether_addr(addr) && lif->nmcast < nmfilters))
10548c2ecf20Sopenharmony_ci			lif->nmcast++;
10558c2ecf20Sopenharmony_ci		else if (!is_multicast_ether_addr(addr) &&
10568c2ecf20Sopenharmony_ci			 lif->nucast < nufilters)
10578c2ecf20Sopenharmony_ci			lif->nucast++;
10588c2ecf20Sopenharmony_ci		else
10598c2ecf20Sopenharmony_ci			return -ENOSPC;
10608c2ecf20Sopenharmony_ci	} else {
10618c2ecf20Sopenharmony_ci		if (is_multicast_ether_addr(addr) && lif->nmcast)
10628c2ecf20Sopenharmony_ci			lif->nmcast--;
10638c2ecf20Sopenharmony_ci		else if (!is_multicast_ether_addr(addr) && lif->nucast)
10648c2ecf20Sopenharmony_ci			lif->nucast--;
10658c2ecf20Sopenharmony_ci	}
10668c2ecf20Sopenharmony_ci
10678c2ecf20Sopenharmony_ci	if (!can_sleep) {
10688c2ecf20Sopenharmony_ci		work = kzalloc(sizeof(*work), GFP_ATOMIC);
10698c2ecf20Sopenharmony_ci		if (!work) {
10708c2ecf20Sopenharmony_ci			netdev_err(lif->netdev, "%s OOM\n", __func__);
10718c2ecf20Sopenharmony_ci			return -ENOMEM;
10728c2ecf20Sopenharmony_ci		}
10738c2ecf20Sopenharmony_ci		work->type = add ? IONIC_DW_TYPE_RX_ADDR_ADD :
10748c2ecf20Sopenharmony_ci				   IONIC_DW_TYPE_RX_ADDR_DEL;
10758c2ecf20Sopenharmony_ci		memcpy(work->addr, addr, ETH_ALEN);
10768c2ecf20Sopenharmony_ci		netdev_dbg(lif->netdev, "deferred: rx_filter %s %pM\n",
10778c2ecf20Sopenharmony_ci			   add ? "add" : "del", addr);
10788c2ecf20Sopenharmony_ci		ionic_lif_deferred_enqueue(&lif->deferred, work);
10798c2ecf20Sopenharmony_ci	} else {
10808c2ecf20Sopenharmony_ci		netdev_dbg(lif->netdev, "rx_filter %s %pM\n",
10818c2ecf20Sopenharmony_ci			   add ? "add" : "del", addr);
10828c2ecf20Sopenharmony_ci		if (add)
10838c2ecf20Sopenharmony_ci			return ionic_lif_addr_add(lif, addr);
10848c2ecf20Sopenharmony_ci		else
10858c2ecf20Sopenharmony_ci			return ionic_lif_addr_del(lif, addr);
10868c2ecf20Sopenharmony_ci	}
10878c2ecf20Sopenharmony_ci
10888c2ecf20Sopenharmony_ci	return 0;
10898c2ecf20Sopenharmony_ci}
10908c2ecf20Sopenharmony_ci
10918c2ecf20Sopenharmony_cistatic int ionic_addr_add(struct net_device *netdev, const u8 *addr)
10928c2ecf20Sopenharmony_ci{
10938c2ecf20Sopenharmony_ci	return ionic_lif_addr(netdev_priv(netdev), addr, true, true);
10948c2ecf20Sopenharmony_ci}
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_cistatic int ionic_ndo_addr_add(struct net_device *netdev, const u8 *addr)
10978c2ecf20Sopenharmony_ci{
10988c2ecf20Sopenharmony_ci	return ionic_lif_addr(netdev_priv(netdev), addr, true, false);
10998c2ecf20Sopenharmony_ci}
11008c2ecf20Sopenharmony_ci
11018c2ecf20Sopenharmony_cistatic int ionic_addr_del(struct net_device *netdev, const u8 *addr)
11028c2ecf20Sopenharmony_ci{
11038c2ecf20Sopenharmony_ci	/* Don't delete our own address from the uc list */
11048c2ecf20Sopenharmony_ci	if (ether_addr_equal(addr, netdev->dev_addr))
11058c2ecf20Sopenharmony_ci		return 0;
11068c2ecf20Sopenharmony_ci
11078c2ecf20Sopenharmony_ci	return ionic_lif_addr(netdev_priv(netdev), addr, false, true);
11088c2ecf20Sopenharmony_ci}
11098c2ecf20Sopenharmony_ci
11108c2ecf20Sopenharmony_cistatic int ionic_ndo_addr_del(struct net_device *netdev, const u8 *addr)
11118c2ecf20Sopenharmony_ci{
11128c2ecf20Sopenharmony_ci	return ionic_lif_addr(netdev_priv(netdev), addr, false, false);
11138c2ecf20Sopenharmony_ci}
11148c2ecf20Sopenharmony_ci
11158c2ecf20Sopenharmony_cistatic void ionic_lif_rx_mode(struct ionic_lif *lif, unsigned int rx_mode)
11168c2ecf20Sopenharmony_ci{
11178c2ecf20Sopenharmony_ci	struct ionic_admin_ctx ctx = {
11188c2ecf20Sopenharmony_ci		.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
11198c2ecf20Sopenharmony_ci		.cmd.rx_mode_set = {
11208c2ecf20Sopenharmony_ci			.opcode = IONIC_CMD_RX_MODE_SET,
11218c2ecf20Sopenharmony_ci			.lif_index = cpu_to_le16(lif->index),
11228c2ecf20Sopenharmony_ci			.rx_mode = cpu_to_le16(rx_mode),
11238c2ecf20Sopenharmony_ci		},
11248c2ecf20Sopenharmony_ci	};
11258c2ecf20Sopenharmony_ci	char buf[128];
11268c2ecf20Sopenharmony_ci	int err;
11278c2ecf20Sopenharmony_ci	int i;
11288c2ecf20Sopenharmony_ci#define REMAIN(__x) (sizeof(buf) - (__x))
11298c2ecf20Sopenharmony_ci
11308c2ecf20Sopenharmony_ci	i = scnprintf(buf, sizeof(buf), "rx_mode 0x%04x -> 0x%04x:",
11318c2ecf20Sopenharmony_ci		      lif->rx_mode, rx_mode);
11328c2ecf20Sopenharmony_ci	if (rx_mode & IONIC_RX_MODE_F_UNICAST)
11338c2ecf20Sopenharmony_ci		i += scnprintf(&buf[i], REMAIN(i), " RX_MODE_F_UNICAST");
11348c2ecf20Sopenharmony_ci	if (rx_mode & IONIC_RX_MODE_F_MULTICAST)
11358c2ecf20Sopenharmony_ci		i += scnprintf(&buf[i], REMAIN(i), " RX_MODE_F_MULTICAST");
11368c2ecf20Sopenharmony_ci	if (rx_mode & IONIC_RX_MODE_F_BROADCAST)
11378c2ecf20Sopenharmony_ci		i += scnprintf(&buf[i], REMAIN(i), " RX_MODE_F_BROADCAST");
11388c2ecf20Sopenharmony_ci	if (rx_mode & IONIC_RX_MODE_F_PROMISC)
11398c2ecf20Sopenharmony_ci		i += scnprintf(&buf[i], REMAIN(i), " RX_MODE_F_PROMISC");
11408c2ecf20Sopenharmony_ci	if (rx_mode & IONIC_RX_MODE_F_ALLMULTI)
11418c2ecf20Sopenharmony_ci		i += scnprintf(&buf[i], REMAIN(i), " RX_MODE_F_ALLMULTI");
11428c2ecf20Sopenharmony_ci	netdev_dbg(lif->netdev, "lif%d %s\n", lif->index, buf);
11438c2ecf20Sopenharmony_ci
11448c2ecf20Sopenharmony_ci	err = ionic_adminq_post_wait(lif, &ctx);
11458c2ecf20Sopenharmony_ci	if (err)
11468c2ecf20Sopenharmony_ci		netdev_warn(lif->netdev, "set rx_mode 0x%04x failed: %d\n",
11478c2ecf20Sopenharmony_ci			    rx_mode, err);
11488c2ecf20Sopenharmony_ci	else
11498c2ecf20Sopenharmony_ci		lif->rx_mode = rx_mode;
11508c2ecf20Sopenharmony_ci}
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_cistatic void ionic_set_rx_mode(struct net_device *netdev, bool can_sleep)
11538c2ecf20Sopenharmony_ci{
11548c2ecf20Sopenharmony_ci	struct ionic_lif *lif = netdev_priv(netdev);
11558c2ecf20Sopenharmony_ci	struct ionic_deferred_work *work;
11568c2ecf20Sopenharmony_ci	unsigned int nfilters;
11578c2ecf20Sopenharmony_ci	unsigned int rx_mode;
11588c2ecf20Sopenharmony_ci
11598c2ecf20Sopenharmony_ci	rx_mode = IONIC_RX_MODE_F_UNICAST;
11608c2ecf20Sopenharmony_ci	rx_mode |= (netdev->flags & IFF_MULTICAST) ? IONIC_RX_MODE_F_MULTICAST : 0;
11618c2ecf20Sopenharmony_ci	rx_mode |= (netdev->flags & IFF_BROADCAST) ? IONIC_RX_MODE_F_BROADCAST : 0;
11628c2ecf20Sopenharmony_ci	rx_mode |= (netdev->flags & IFF_PROMISC) ? IONIC_RX_MODE_F_PROMISC : 0;
11638c2ecf20Sopenharmony_ci	rx_mode |= (netdev->flags & IFF_ALLMULTI) ? IONIC_RX_MODE_F_ALLMULTI : 0;
11648c2ecf20Sopenharmony_ci
11658c2ecf20Sopenharmony_ci	/* sync unicast addresses
11668c2ecf20Sopenharmony_ci	 * next check to see if we're in an overflow state
11678c2ecf20Sopenharmony_ci	 *    if so, we track that we overflowed and enable NIC PROMISC
11688c2ecf20Sopenharmony_ci	 *    else if the overflow is set and not needed
11698c2ecf20Sopenharmony_ci	 *       we remove our overflow flag and check the netdev flags
11708c2ecf20Sopenharmony_ci	 *       to see if we can disable NIC PROMISC
11718c2ecf20Sopenharmony_ci	 */
11728c2ecf20Sopenharmony_ci	if (can_sleep)
11738c2ecf20Sopenharmony_ci		__dev_uc_sync(netdev, ionic_addr_add, ionic_addr_del);
11748c2ecf20Sopenharmony_ci	else
11758c2ecf20Sopenharmony_ci		__dev_uc_sync(netdev, ionic_ndo_addr_add, ionic_ndo_addr_del);
11768c2ecf20Sopenharmony_ci	nfilters = le32_to_cpu(lif->identity->eth.max_ucast_filters);
11778c2ecf20Sopenharmony_ci	if (netdev_uc_count(netdev) + 1 > nfilters) {
11788c2ecf20Sopenharmony_ci		rx_mode |= IONIC_RX_MODE_F_PROMISC;
11798c2ecf20Sopenharmony_ci		lif->uc_overflow = true;
11808c2ecf20Sopenharmony_ci	} else if (lif->uc_overflow) {
11818c2ecf20Sopenharmony_ci		lif->uc_overflow = false;
11828c2ecf20Sopenharmony_ci		if (!(netdev->flags & IFF_PROMISC))
11838c2ecf20Sopenharmony_ci			rx_mode &= ~IONIC_RX_MODE_F_PROMISC;
11848c2ecf20Sopenharmony_ci	}
11858c2ecf20Sopenharmony_ci
11868c2ecf20Sopenharmony_ci	/* same for multicast */
11878c2ecf20Sopenharmony_ci	if (can_sleep)
11888c2ecf20Sopenharmony_ci		__dev_mc_sync(netdev, ionic_addr_add, ionic_addr_del);
11898c2ecf20Sopenharmony_ci	else
11908c2ecf20Sopenharmony_ci		__dev_mc_sync(netdev, ionic_ndo_addr_add, ionic_ndo_addr_del);
11918c2ecf20Sopenharmony_ci	nfilters = le32_to_cpu(lif->identity->eth.max_mcast_filters);
11928c2ecf20Sopenharmony_ci	if (netdev_mc_count(netdev) > nfilters) {
11938c2ecf20Sopenharmony_ci		rx_mode |= IONIC_RX_MODE_F_ALLMULTI;
11948c2ecf20Sopenharmony_ci		lif->mc_overflow = true;
11958c2ecf20Sopenharmony_ci	} else if (lif->mc_overflow) {
11968c2ecf20Sopenharmony_ci		lif->mc_overflow = false;
11978c2ecf20Sopenharmony_ci		if (!(netdev->flags & IFF_ALLMULTI))
11988c2ecf20Sopenharmony_ci			rx_mode &= ~IONIC_RX_MODE_F_ALLMULTI;
11998c2ecf20Sopenharmony_ci	}
12008c2ecf20Sopenharmony_ci
12018c2ecf20Sopenharmony_ci	if (lif->rx_mode != rx_mode) {
12028c2ecf20Sopenharmony_ci		if (!can_sleep) {
12038c2ecf20Sopenharmony_ci			work = kzalloc(sizeof(*work), GFP_ATOMIC);
12048c2ecf20Sopenharmony_ci			if (!work) {
12058c2ecf20Sopenharmony_ci				netdev_err(lif->netdev, "%s OOM\n", __func__);
12068c2ecf20Sopenharmony_ci				return;
12078c2ecf20Sopenharmony_ci			}
12088c2ecf20Sopenharmony_ci			work->type = IONIC_DW_TYPE_RX_MODE;
12098c2ecf20Sopenharmony_ci			work->rx_mode = rx_mode;
12108c2ecf20Sopenharmony_ci			netdev_dbg(lif->netdev, "deferred: rx_mode\n");
12118c2ecf20Sopenharmony_ci			ionic_lif_deferred_enqueue(&lif->deferred, work);
12128c2ecf20Sopenharmony_ci		} else {
12138c2ecf20Sopenharmony_ci			ionic_lif_rx_mode(lif, rx_mode);
12148c2ecf20Sopenharmony_ci		}
12158c2ecf20Sopenharmony_ci	}
12168c2ecf20Sopenharmony_ci}
12178c2ecf20Sopenharmony_ci
12188c2ecf20Sopenharmony_cistatic void ionic_ndo_set_rx_mode(struct net_device *netdev)
12198c2ecf20Sopenharmony_ci{
12208c2ecf20Sopenharmony_ci	ionic_set_rx_mode(netdev, false);
12218c2ecf20Sopenharmony_ci}
12228c2ecf20Sopenharmony_ci
12238c2ecf20Sopenharmony_cistatic __le64 ionic_netdev_features_to_nic(netdev_features_t features)
12248c2ecf20Sopenharmony_ci{
12258c2ecf20Sopenharmony_ci	u64 wanted = 0;
12268c2ecf20Sopenharmony_ci
12278c2ecf20Sopenharmony_ci	if (features & NETIF_F_HW_VLAN_CTAG_TX)
12288c2ecf20Sopenharmony_ci		wanted |= IONIC_ETH_HW_VLAN_TX_TAG;
12298c2ecf20Sopenharmony_ci	if (features & NETIF_F_HW_VLAN_CTAG_RX)
12308c2ecf20Sopenharmony_ci		wanted |= IONIC_ETH_HW_VLAN_RX_STRIP;
12318c2ecf20Sopenharmony_ci	if (features & NETIF_F_HW_VLAN_CTAG_FILTER)
12328c2ecf20Sopenharmony_ci		wanted |= IONIC_ETH_HW_VLAN_RX_FILTER;
12338c2ecf20Sopenharmony_ci	if (features & NETIF_F_RXHASH)
12348c2ecf20Sopenharmony_ci		wanted |= IONIC_ETH_HW_RX_HASH;
12358c2ecf20Sopenharmony_ci	if (features & NETIF_F_RXCSUM)
12368c2ecf20Sopenharmony_ci		wanted |= IONIC_ETH_HW_RX_CSUM;
12378c2ecf20Sopenharmony_ci	if (features & NETIF_F_SG)
12388c2ecf20Sopenharmony_ci		wanted |= IONIC_ETH_HW_TX_SG;
12398c2ecf20Sopenharmony_ci	if (features & NETIF_F_HW_CSUM)
12408c2ecf20Sopenharmony_ci		wanted |= IONIC_ETH_HW_TX_CSUM;
12418c2ecf20Sopenharmony_ci	if (features & NETIF_F_TSO)
12428c2ecf20Sopenharmony_ci		wanted |= IONIC_ETH_HW_TSO;
12438c2ecf20Sopenharmony_ci	if (features & NETIF_F_TSO6)
12448c2ecf20Sopenharmony_ci		wanted |= IONIC_ETH_HW_TSO_IPV6;
12458c2ecf20Sopenharmony_ci	if (features & NETIF_F_TSO_ECN)
12468c2ecf20Sopenharmony_ci		wanted |= IONIC_ETH_HW_TSO_ECN;
12478c2ecf20Sopenharmony_ci	if (features & NETIF_F_GSO_GRE)
12488c2ecf20Sopenharmony_ci		wanted |= IONIC_ETH_HW_TSO_GRE;
12498c2ecf20Sopenharmony_ci	if (features & NETIF_F_GSO_GRE_CSUM)
12508c2ecf20Sopenharmony_ci		wanted |= IONIC_ETH_HW_TSO_GRE_CSUM;
12518c2ecf20Sopenharmony_ci	if (features & NETIF_F_GSO_IPXIP4)
12528c2ecf20Sopenharmony_ci		wanted |= IONIC_ETH_HW_TSO_IPXIP4;
12538c2ecf20Sopenharmony_ci	if (features & NETIF_F_GSO_IPXIP6)
12548c2ecf20Sopenharmony_ci		wanted |= IONIC_ETH_HW_TSO_IPXIP6;
12558c2ecf20Sopenharmony_ci	if (features & NETIF_F_GSO_UDP_TUNNEL)
12568c2ecf20Sopenharmony_ci		wanted |= IONIC_ETH_HW_TSO_UDP;
12578c2ecf20Sopenharmony_ci	if (features & NETIF_F_GSO_UDP_TUNNEL_CSUM)
12588c2ecf20Sopenharmony_ci		wanted |= IONIC_ETH_HW_TSO_UDP_CSUM;
12598c2ecf20Sopenharmony_ci
12608c2ecf20Sopenharmony_ci	return cpu_to_le64(wanted);
12618c2ecf20Sopenharmony_ci}
12628c2ecf20Sopenharmony_ci
12638c2ecf20Sopenharmony_cistatic int ionic_set_nic_features(struct ionic_lif *lif,
12648c2ecf20Sopenharmony_ci				  netdev_features_t features)
12658c2ecf20Sopenharmony_ci{
12668c2ecf20Sopenharmony_ci	struct device *dev = lif->ionic->dev;
12678c2ecf20Sopenharmony_ci	struct ionic_admin_ctx ctx = {
12688c2ecf20Sopenharmony_ci		.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
12698c2ecf20Sopenharmony_ci		.cmd.lif_setattr = {
12708c2ecf20Sopenharmony_ci			.opcode = IONIC_CMD_LIF_SETATTR,
12718c2ecf20Sopenharmony_ci			.index = cpu_to_le16(lif->index),
12728c2ecf20Sopenharmony_ci			.attr = IONIC_LIF_ATTR_FEATURES,
12738c2ecf20Sopenharmony_ci		},
12748c2ecf20Sopenharmony_ci	};
12758c2ecf20Sopenharmony_ci	u64 vlan_flags = IONIC_ETH_HW_VLAN_TX_TAG |
12768c2ecf20Sopenharmony_ci			 IONIC_ETH_HW_VLAN_RX_STRIP |
12778c2ecf20Sopenharmony_ci			 IONIC_ETH_HW_VLAN_RX_FILTER;
12788c2ecf20Sopenharmony_ci	u64 old_hw_features;
12798c2ecf20Sopenharmony_ci	int err;
12808c2ecf20Sopenharmony_ci
12818c2ecf20Sopenharmony_ci	ctx.cmd.lif_setattr.features = ionic_netdev_features_to_nic(features);
12828c2ecf20Sopenharmony_ci	err = ionic_adminq_post_wait(lif, &ctx);
12838c2ecf20Sopenharmony_ci	if (err)
12848c2ecf20Sopenharmony_ci		return err;
12858c2ecf20Sopenharmony_ci
12868c2ecf20Sopenharmony_ci	old_hw_features = lif->hw_features;
12878c2ecf20Sopenharmony_ci	lif->hw_features = le64_to_cpu(ctx.cmd.lif_setattr.features &
12888c2ecf20Sopenharmony_ci				       ctx.comp.lif_setattr.features);
12898c2ecf20Sopenharmony_ci
12908c2ecf20Sopenharmony_ci	if ((old_hw_features ^ lif->hw_features) & IONIC_ETH_HW_RX_HASH)
12918c2ecf20Sopenharmony_ci		ionic_lif_rss_config(lif, lif->rss_types, NULL, NULL);
12928c2ecf20Sopenharmony_ci
12938c2ecf20Sopenharmony_ci	if ((vlan_flags & le64_to_cpu(ctx.cmd.lif_setattr.features)) &&
12948c2ecf20Sopenharmony_ci	    !(vlan_flags & le64_to_cpu(ctx.comp.lif_setattr.features)))
12958c2ecf20Sopenharmony_ci		dev_info_once(lif->ionic->dev, "NIC is not supporting vlan offload, likely in SmartNIC mode\n");
12968c2ecf20Sopenharmony_ci
12978c2ecf20Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_VLAN_TX_TAG)
12988c2ecf20Sopenharmony_ci		dev_dbg(dev, "feature ETH_HW_VLAN_TX_TAG\n");
12998c2ecf20Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_VLAN_RX_STRIP)
13008c2ecf20Sopenharmony_ci		dev_dbg(dev, "feature ETH_HW_VLAN_RX_STRIP\n");
13018c2ecf20Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_VLAN_RX_FILTER)
13028c2ecf20Sopenharmony_ci		dev_dbg(dev, "feature ETH_HW_VLAN_RX_FILTER\n");
13038c2ecf20Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_RX_HASH)
13048c2ecf20Sopenharmony_ci		dev_dbg(dev, "feature ETH_HW_RX_HASH\n");
13058c2ecf20Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_TX_SG)
13068c2ecf20Sopenharmony_ci		dev_dbg(dev, "feature ETH_HW_TX_SG\n");
13078c2ecf20Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_TX_CSUM)
13088c2ecf20Sopenharmony_ci		dev_dbg(dev, "feature ETH_HW_TX_CSUM\n");
13098c2ecf20Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_RX_CSUM)
13108c2ecf20Sopenharmony_ci		dev_dbg(dev, "feature ETH_HW_RX_CSUM\n");
13118c2ecf20Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_TSO)
13128c2ecf20Sopenharmony_ci		dev_dbg(dev, "feature ETH_HW_TSO\n");
13138c2ecf20Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_TSO_IPV6)
13148c2ecf20Sopenharmony_ci		dev_dbg(dev, "feature ETH_HW_TSO_IPV6\n");
13158c2ecf20Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_TSO_ECN)
13168c2ecf20Sopenharmony_ci		dev_dbg(dev, "feature ETH_HW_TSO_ECN\n");
13178c2ecf20Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_TSO_GRE)
13188c2ecf20Sopenharmony_ci		dev_dbg(dev, "feature ETH_HW_TSO_GRE\n");
13198c2ecf20Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_TSO_GRE_CSUM)
13208c2ecf20Sopenharmony_ci		dev_dbg(dev, "feature ETH_HW_TSO_GRE_CSUM\n");
13218c2ecf20Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_TSO_IPXIP4)
13228c2ecf20Sopenharmony_ci		dev_dbg(dev, "feature ETH_HW_TSO_IPXIP4\n");
13238c2ecf20Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_TSO_IPXIP6)
13248c2ecf20Sopenharmony_ci		dev_dbg(dev, "feature ETH_HW_TSO_IPXIP6\n");
13258c2ecf20Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_TSO_UDP)
13268c2ecf20Sopenharmony_ci		dev_dbg(dev, "feature ETH_HW_TSO_UDP\n");
13278c2ecf20Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_TSO_UDP_CSUM)
13288c2ecf20Sopenharmony_ci		dev_dbg(dev, "feature ETH_HW_TSO_UDP_CSUM\n");
13298c2ecf20Sopenharmony_ci
13308c2ecf20Sopenharmony_ci	return 0;
13318c2ecf20Sopenharmony_ci}
13328c2ecf20Sopenharmony_ci
13338c2ecf20Sopenharmony_cistatic int ionic_init_nic_features(struct ionic_lif *lif)
13348c2ecf20Sopenharmony_ci{
13358c2ecf20Sopenharmony_ci	struct net_device *netdev = lif->netdev;
13368c2ecf20Sopenharmony_ci	netdev_features_t features;
13378c2ecf20Sopenharmony_ci	int err;
13388c2ecf20Sopenharmony_ci
13398c2ecf20Sopenharmony_ci	/* set up what we expect to support by default */
13408c2ecf20Sopenharmony_ci	features = NETIF_F_HW_VLAN_CTAG_TX |
13418c2ecf20Sopenharmony_ci		   NETIF_F_HW_VLAN_CTAG_RX |
13428c2ecf20Sopenharmony_ci		   NETIF_F_HW_VLAN_CTAG_FILTER |
13438c2ecf20Sopenharmony_ci		   NETIF_F_RXHASH |
13448c2ecf20Sopenharmony_ci		   NETIF_F_SG |
13458c2ecf20Sopenharmony_ci		   NETIF_F_HW_CSUM |
13468c2ecf20Sopenharmony_ci		   NETIF_F_RXCSUM |
13478c2ecf20Sopenharmony_ci		   NETIF_F_TSO |
13488c2ecf20Sopenharmony_ci		   NETIF_F_TSO6 |
13498c2ecf20Sopenharmony_ci		   NETIF_F_TSO_ECN;
13508c2ecf20Sopenharmony_ci
13518c2ecf20Sopenharmony_ci	err = ionic_set_nic_features(lif, features);
13528c2ecf20Sopenharmony_ci	if (err)
13538c2ecf20Sopenharmony_ci		return err;
13548c2ecf20Sopenharmony_ci
13558c2ecf20Sopenharmony_ci	/* tell the netdev what we actually can support */
13568c2ecf20Sopenharmony_ci	netdev->features |= NETIF_F_HIGHDMA;
13578c2ecf20Sopenharmony_ci
13588c2ecf20Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_VLAN_TX_TAG)
13598c2ecf20Sopenharmony_ci		netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_TX;
13608c2ecf20Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_VLAN_RX_STRIP)
13618c2ecf20Sopenharmony_ci		netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_RX;
13628c2ecf20Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_VLAN_RX_FILTER)
13638c2ecf20Sopenharmony_ci		netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER;
13648c2ecf20Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_RX_HASH)
13658c2ecf20Sopenharmony_ci		netdev->hw_features |= NETIF_F_RXHASH;
13668c2ecf20Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_TX_SG)
13678c2ecf20Sopenharmony_ci		netdev->hw_features |= NETIF_F_SG;
13688c2ecf20Sopenharmony_ci
13698c2ecf20Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_TX_CSUM)
13708c2ecf20Sopenharmony_ci		netdev->hw_enc_features |= NETIF_F_HW_CSUM;
13718c2ecf20Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_RX_CSUM)
13728c2ecf20Sopenharmony_ci		netdev->hw_enc_features |= NETIF_F_RXCSUM;
13738c2ecf20Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_TSO)
13748c2ecf20Sopenharmony_ci		netdev->hw_enc_features |= NETIF_F_TSO;
13758c2ecf20Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_TSO_IPV6)
13768c2ecf20Sopenharmony_ci		netdev->hw_enc_features |= NETIF_F_TSO6;
13778c2ecf20Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_TSO_ECN)
13788c2ecf20Sopenharmony_ci		netdev->hw_enc_features |= NETIF_F_TSO_ECN;
13798c2ecf20Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_TSO_GRE)
13808c2ecf20Sopenharmony_ci		netdev->hw_enc_features |= NETIF_F_GSO_GRE;
13818c2ecf20Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_TSO_GRE_CSUM)
13828c2ecf20Sopenharmony_ci		netdev->hw_enc_features |= NETIF_F_GSO_GRE_CSUM;
13838c2ecf20Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_TSO_IPXIP4)
13848c2ecf20Sopenharmony_ci		netdev->hw_enc_features |= NETIF_F_GSO_IPXIP4;
13858c2ecf20Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_TSO_IPXIP6)
13868c2ecf20Sopenharmony_ci		netdev->hw_enc_features |= NETIF_F_GSO_IPXIP6;
13878c2ecf20Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_TSO_UDP)
13888c2ecf20Sopenharmony_ci		netdev->hw_enc_features |= NETIF_F_GSO_UDP_TUNNEL;
13898c2ecf20Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_TSO_UDP_CSUM)
13908c2ecf20Sopenharmony_ci		netdev->hw_enc_features |= NETIF_F_GSO_UDP_TUNNEL_CSUM;
13918c2ecf20Sopenharmony_ci
13928c2ecf20Sopenharmony_ci	netdev->hw_features |= netdev->hw_enc_features;
13938c2ecf20Sopenharmony_ci	netdev->features |= netdev->hw_features;
13948c2ecf20Sopenharmony_ci	netdev->vlan_features |= netdev->features & ~NETIF_F_VLAN_FEATURES;
13958c2ecf20Sopenharmony_ci
13968c2ecf20Sopenharmony_ci	netdev->priv_flags |= IFF_UNICAST_FLT |
13978c2ecf20Sopenharmony_ci			      IFF_LIVE_ADDR_CHANGE;
13988c2ecf20Sopenharmony_ci
13998c2ecf20Sopenharmony_ci	return 0;
14008c2ecf20Sopenharmony_ci}
14018c2ecf20Sopenharmony_ci
14028c2ecf20Sopenharmony_cistatic int ionic_set_features(struct net_device *netdev,
14038c2ecf20Sopenharmony_ci			      netdev_features_t features)
14048c2ecf20Sopenharmony_ci{
14058c2ecf20Sopenharmony_ci	struct ionic_lif *lif = netdev_priv(netdev);
14068c2ecf20Sopenharmony_ci	int err;
14078c2ecf20Sopenharmony_ci
14088c2ecf20Sopenharmony_ci	netdev_dbg(netdev, "%s: lif->features=0x%08llx new_features=0x%08llx\n",
14098c2ecf20Sopenharmony_ci		   __func__, (u64)lif->netdev->features, (u64)features);
14108c2ecf20Sopenharmony_ci
14118c2ecf20Sopenharmony_ci	err = ionic_set_nic_features(lif, features);
14128c2ecf20Sopenharmony_ci
14138c2ecf20Sopenharmony_ci	return err;
14148c2ecf20Sopenharmony_ci}
14158c2ecf20Sopenharmony_ci
14168c2ecf20Sopenharmony_cistatic int ionic_set_mac_address(struct net_device *netdev, void *sa)
14178c2ecf20Sopenharmony_ci{
14188c2ecf20Sopenharmony_ci	struct sockaddr *addr = sa;
14198c2ecf20Sopenharmony_ci	u8 *mac;
14208c2ecf20Sopenharmony_ci	int err;
14218c2ecf20Sopenharmony_ci
14228c2ecf20Sopenharmony_ci	mac = (u8 *)addr->sa_data;
14238c2ecf20Sopenharmony_ci	if (ether_addr_equal(netdev->dev_addr, mac))
14248c2ecf20Sopenharmony_ci		return 0;
14258c2ecf20Sopenharmony_ci
14268c2ecf20Sopenharmony_ci	err = eth_prepare_mac_addr_change(netdev, addr);
14278c2ecf20Sopenharmony_ci	if (err)
14288c2ecf20Sopenharmony_ci		return err;
14298c2ecf20Sopenharmony_ci
14308c2ecf20Sopenharmony_ci	if (!is_zero_ether_addr(netdev->dev_addr)) {
14318c2ecf20Sopenharmony_ci		netdev_info(netdev, "deleting mac addr %pM\n",
14328c2ecf20Sopenharmony_ci			    netdev->dev_addr);
14338c2ecf20Sopenharmony_ci		ionic_addr_del(netdev, netdev->dev_addr);
14348c2ecf20Sopenharmony_ci	}
14358c2ecf20Sopenharmony_ci
14368c2ecf20Sopenharmony_ci	eth_commit_mac_addr_change(netdev, addr);
14378c2ecf20Sopenharmony_ci	netdev_info(netdev, "updating mac addr %pM\n", mac);
14388c2ecf20Sopenharmony_ci
14398c2ecf20Sopenharmony_ci	return ionic_addr_add(netdev, mac);
14408c2ecf20Sopenharmony_ci}
14418c2ecf20Sopenharmony_ci
14428c2ecf20Sopenharmony_cistatic void ionic_stop_queues_reconfig(struct ionic_lif *lif)
14438c2ecf20Sopenharmony_ci{
14448c2ecf20Sopenharmony_ci	/* Stop and clean the queues before reconfiguration */
14458c2ecf20Sopenharmony_ci	mutex_lock(&lif->queue_lock);
14468c2ecf20Sopenharmony_ci	netif_device_detach(lif->netdev);
14478c2ecf20Sopenharmony_ci	ionic_stop_queues(lif);
14488c2ecf20Sopenharmony_ci	ionic_txrx_deinit(lif);
14498c2ecf20Sopenharmony_ci}
14508c2ecf20Sopenharmony_ci
14518c2ecf20Sopenharmony_cistatic int ionic_start_queues_reconfig(struct ionic_lif *lif)
14528c2ecf20Sopenharmony_ci{
14538c2ecf20Sopenharmony_ci	int err;
14548c2ecf20Sopenharmony_ci
14558c2ecf20Sopenharmony_ci	/* Re-init the queues after reconfiguration */
14568c2ecf20Sopenharmony_ci
14578c2ecf20Sopenharmony_ci	/* The only way txrx_init can fail here is if communication
14588c2ecf20Sopenharmony_ci	 * with FW is suddenly broken.  There's not much we can do
14598c2ecf20Sopenharmony_ci	 * at this point - error messages have already been printed,
14608c2ecf20Sopenharmony_ci	 * so we can continue on and the user can eventually do a
14618c2ecf20Sopenharmony_ci	 * DOWN and UP to try to reset and clear the issue.
14628c2ecf20Sopenharmony_ci	 */
14638c2ecf20Sopenharmony_ci	err = ionic_txrx_init(lif);
14648c2ecf20Sopenharmony_ci	mutex_unlock(&lif->queue_lock);
14658c2ecf20Sopenharmony_ci	ionic_link_status_check_request(lif, true);
14668c2ecf20Sopenharmony_ci	netif_device_attach(lif->netdev);
14678c2ecf20Sopenharmony_ci
14688c2ecf20Sopenharmony_ci	return err;
14698c2ecf20Sopenharmony_ci}
14708c2ecf20Sopenharmony_ci
14718c2ecf20Sopenharmony_cistatic int ionic_change_mtu(struct net_device *netdev, int new_mtu)
14728c2ecf20Sopenharmony_ci{
14738c2ecf20Sopenharmony_ci	struct ionic_lif *lif = netdev_priv(netdev);
14748c2ecf20Sopenharmony_ci	struct ionic_admin_ctx ctx = {
14758c2ecf20Sopenharmony_ci		.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
14768c2ecf20Sopenharmony_ci		.cmd.lif_setattr = {
14778c2ecf20Sopenharmony_ci			.opcode = IONIC_CMD_LIF_SETATTR,
14788c2ecf20Sopenharmony_ci			.index = cpu_to_le16(lif->index),
14798c2ecf20Sopenharmony_ci			.attr = IONIC_LIF_ATTR_MTU,
14808c2ecf20Sopenharmony_ci			.mtu = cpu_to_le32(new_mtu),
14818c2ecf20Sopenharmony_ci		},
14828c2ecf20Sopenharmony_ci	};
14838c2ecf20Sopenharmony_ci	int err;
14848c2ecf20Sopenharmony_ci
14858c2ecf20Sopenharmony_ci	err = ionic_adminq_post_wait(lif, &ctx);
14868c2ecf20Sopenharmony_ci	if (err)
14878c2ecf20Sopenharmony_ci		return err;
14888c2ecf20Sopenharmony_ci
14898c2ecf20Sopenharmony_ci	netdev->mtu = new_mtu;
14908c2ecf20Sopenharmony_ci	/* if we're not running, nothing more to do */
14918c2ecf20Sopenharmony_ci	if (!netif_running(netdev))
14928c2ecf20Sopenharmony_ci		return 0;
14938c2ecf20Sopenharmony_ci
14948c2ecf20Sopenharmony_ci	ionic_stop_queues_reconfig(lif);
14958c2ecf20Sopenharmony_ci	return ionic_start_queues_reconfig(lif);
14968c2ecf20Sopenharmony_ci}
14978c2ecf20Sopenharmony_ci
14988c2ecf20Sopenharmony_cistatic void ionic_tx_timeout_work(struct work_struct *ws)
14998c2ecf20Sopenharmony_ci{
15008c2ecf20Sopenharmony_ci	struct ionic_lif *lif = container_of(ws, struct ionic_lif, tx_timeout_work);
15018c2ecf20Sopenharmony_ci
15028c2ecf20Sopenharmony_ci	netdev_info(lif->netdev, "Tx Timeout recovery\n");
15038c2ecf20Sopenharmony_ci
15048c2ecf20Sopenharmony_ci	/* if we were stopped before this scheduled job was launched,
15058c2ecf20Sopenharmony_ci	 * don't bother the queues as they are already stopped.
15068c2ecf20Sopenharmony_ci	 */
15078c2ecf20Sopenharmony_ci	if (!netif_running(lif->netdev))
15088c2ecf20Sopenharmony_ci		return;
15098c2ecf20Sopenharmony_ci
15108c2ecf20Sopenharmony_ci	ionic_stop_queues_reconfig(lif);
15118c2ecf20Sopenharmony_ci	ionic_start_queues_reconfig(lif);
15128c2ecf20Sopenharmony_ci}
15138c2ecf20Sopenharmony_ci
15148c2ecf20Sopenharmony_cistatic void ionic_tx_timeout(struct net_device *netdev, unsigned int txqueue)
15158c2ecf20Sopenharmony_ci{
15168c2ecf20Sopenharmony_ci	struct ionic_lif *lif = netdev_priv(netdev);
15178c2ecf20Sopenharmony_ci
15188c2ecf20Sopenharmony_ci	schedule_work(&lif->tx_timeout_work);
15198c2ecf20Sopenharmony_ci}
15208c2ecf20Sopenharmony_ci
15218c2ecf20Sopenharmony_cistatic int ionic_vlan_rx_add_vid(struct net_device *netdev, __be16 proto,
15228c2ecf20Sopenharmony_ci				 u16 vid)
15238c2ecf20Sopenharmony_ci{
15248c2ecf20Sopenharmony_ci	struct ionic_lif *lif = netdev_priv(netdev);
15258c2ecf20Sopenharmony_ci	struct ionic_admin_ctx ctx = {
15268c2ecf20Sopenharmony_ci		.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
15278c2ecf20Sopenharmony_ci		.cmd.rx_filter_add = {
15288c2ecf20Sopenharmony_ci			.opcode = IONIC_CMD_RX_FILTER_ADD,
15298c2ecf20Sopenharmony_ci			.lif_index = cpu_to_le16(lif->index),
15308c2ecf20Sopenharmony_ci			.match = cpu_to_le16(IONIC_RX_FILTER_MATCH_VLAN),
15318c2ecf20Sopenharmony_ci			.vlan.vlan = cpu_to_le16(vid),
15328c2ecf20Sopenharmony_ci		},
15338c2ecf20Sopenharmony_ci	};
15348c2ecf20Sopenharmony_ci	int err;
15358c2ecf20Sopenharmony_ci
15368c2ecf20Sopenharmony_ci	netdev_dbg(netdev, "rx_filter add VLAN %d\n", vid);
15378c2ecf20Sopenharmony_ci	err = ionic_adminq_post_wait(lif, &ctx);
15388c2ecf20Sopenharmony_ci	if (err)
15398c2ecf20Sopenharmony_ci		return err;
15408c2ecf20Sopenharmony_ci
15418c2ecf20Sopenharmony_ci	return ionic_rx_filter_save(lif, 0, IONIC_RXQ_INDEX_ANY, 0, &ctx);
15428c2ecf20Sopenharmony_ci}
15438c2ecf20Sopenharmony_ci
15448c2ecf20Sopenharmony_cistatic int ionic_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto,
15458c2ecf20Sopenharmony_ci				  u16 vid)
15468c2ecf20Sopenharmony_ci{
15478c2ecf20Sopenharmony_ci	struct ionic_lif *lif = netdev_priv(netdev);
15488c2ecf20Sopenharmony_ci	struct ionic_admin_ctx ctx = {
15498c2ecf20Sopenharmony_ci		.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
15508c2ecf20Sopenharmony_ci		.cmd.rx_filter_del = {
15518c2ecf20Sopenharmony_ci			.opcode = IONIC_CMD_RX_FILTER_DEL,
15528c2ecf20Sopenharmony_ci			.lif_index = cpu_to_le16(lif->index),
15538c2ecf20Sopenharmony_ci		},
15548c2ecf20Sopenharmony_ci	};
15558c2ecf20Sopenharmony_ci	struct ionic_rx_filter *f;
15568c2ecf20Sopenharmony_ci
15578c2ecf20Sopenharmony_ci	spin_lock_bh(&lif->rx_filters.lock);
15588c2ecf20Sopenharmony_ci
15598c2ecf20Sopenharmony_ci	f = ionic_rx_filter_by_vlan(lif, vid);
15608c2ecf20Sopenharmony_ci	if (!f) {
15618c2ecf20Sopenharmony_ci		spin_unlock_bh(&lif->rx_filters.lock);
15628c2ecf20Sopenharmony_ci		return -ENOENT;
15638c2ecf20Sopenharmony_ci	}
15648c2ecf20Sopenharmony_ci
15658c2ecf20Sopenharmony_ci	netdev_dbg(netdev, "rx_filter del VLAN %d (id %d)\n",
15668c2ecf20Sopenharmony_ci		   vid, f->filter_id);
15678c2ecf20Sopenharmony_ci
15688c2ecf20Sopenharmony_ci	ctx.cmd.rx_filter_del.filter_id = cpu_to_le32(f->filter_id);
15698c2ecf20Sopenharmony_ci	ionic_rx_filter_free(lif, f);
15708c2ecf20Sopenharmony_ci	spin_unlock_bh(&lif->rx_filters.lock);
15718c2ecf20Sopenharmony_ci
15728c2ecf20Sopenharmony_ci	return ionic_adminq_post_wait(lif, &ctx);
15738c2ecf20Sopenharmony_ci}
15748c2ecf20Sopenharmony_ci
15758c2ecf20Sopenharmony_ciint ionic_lif_rss_config(struct ionic_lif *lif, const u16 types,
15768c2ecf20Sopenharmony_ci			 const u8 *key, const u32 *indir)
15778c2ecf20Sopenharmony_ci{
15788c2ecf20Sopenharmony_ci	struct ionic_admin_ctx ctx = {
15798c2ecf20Sopenharmony_ci		.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
15808c2ecf20Sopenharmony_ci		.cmd.lif_setattr = {
15818c2ecf20Sopenharmony_ci			.opcode = IONIC_CMD_LIF_SETATTR,
15828c2ecf20Sopenharmony_ci			.attr = IONIC_LIF_ATTR_RSS,
15838c2ecf20Sopenharmony_ci			.rss.addr = cpu_to_le64(lif->rss_ind_tbl_pa),
15848c2ecf20Sopenharmony_ci		},
15858c2ecf20Sopenharmony_ci	};
15868c2ecf20Sopenharmony_ci	unsigned int i, tbl_sz;
15878c2ecf20Sopenharmony_ci
15888c2ecf20Sopenharmony_ci	if (lif->hw_features & IONIC_ETH_HW_RX_HASH) {
15898c2ecf20Sopenharmony_ci		lif->rss_types = types;
15908c2ecf20Sopenharmony_ci		ctx.cmd.lif_setattr.rss.types = cpu_to_le16(types);
15918c2ecf20Sopenharmony_ci	}
15928c2ecf20Sopenharmony_ci
15938c2ecf20Sopenharmony_ci	if (key)
15948c2ecf20Sopenharmony_ci		memcpy(lif->rss_hash_key, key, IONIC_RSS_HASH_KEY_SIZE);
15958c2ecf20Sopenharmony_ci
15968c2ecf20Sopenharmony_ci	if (indir) {
15978c2ecf20Sopenharmony_ci		tbl_sz = le16_to_cpu(lif->ionic->ident.lif.eth.rss_ind_tbl_sz);
15988c2ecf20Sopenharmony_ci		for (i = 0; i < tbl_sz; i++)
15998c2ecf20Sopenharmony_ci			lif->rss_ind_tbl[i] = indir[i];
16008c2ecf20Sopenharmony_ci	}
16018c2ecf20Sopenharmony_ci
16028c2ecf20Sopenharmony_ci	memcpy(ctx.cmd.lif_setattr.rss.key, lif->rss_hash_key,
16038c2ecf20Sopenharmony_ci	       IONIC_RSS_HASH_KEY_SIZE);
16048c2ecf20Sopenharmony_ci
16058c2ecf20Sopenharmony_ci	return ionic_adminq_post_wait(lif, &ctx);
16068c2ecf20Sopenharmony_ci}
16078c2ecf20Sopenharmony_ci
16088c2ecf20Sopenharmony_cistatic int ionic_lif_rss_init(struct ionic_lif *lif)
16098c2ecf20Sopenharmony_ci{
16108c2ecf20Sopenharmony_ci	unsigned int tbl_sz;
16118c2ecf20Sopenharmony_ci	unsigned int i;
16128c2ecf20Sopenharmony_ci
16138c2ecf20Sopenharmony_ci	lif->rss_types = IONIC_RSS_TYPE_IPV4     |
16148c2ecf20Sopenharmony_ci			 IONIC_RSS_TYPE_IPV4_TCP |
16158c2ecf20Sopenharmony_ci			 IONIC_RSS_TYPE_IPV4_UDP |
16168c2ecf20Sopenharmony_ci			 IONIC_RSS_TYPE_IPV6     |
16178c2ecf20Sopenharmony_ci			 IONIC_RSS_TYPE_IPV6_TCP |
16188c2ecf20Sopenharmony_ci			 IONIC_RSS_TYPE_IPV6_UDP;
16198c2ecf20Sopenharmony_ci
16208c2ecf20Sopenharmony_ci	/* Fill indirection table with 'default' values */
16218c2ecf20Sopenharmony_ci	tbl_sz = le16_to_cpu(lif->ionic->ident.lif.eth.rss_ind_tbl_sz);
16228c2ecf20Sopenharmony_ci	for (i = 0; i < tbl_sz; i++)
16238c2ecf20Sopenharmony_ci		lif->rss_ind_tbl[i] = ethtool_rxfh_indir_default(i, lif->nxqs);
16248c2ecf20Sopenharmony_ci
16258c2ecf20Sopenharmony_ci	return ionic_lif_rss_config(lif, lif->rss_types, NULL, NULL);
16268c2ecf20Sopenharmony_ci}
16278c2ecf20Sopenharmony_ci
16288c2ecf20Sopenharmony_cistatic void ionic_lif_rss_deinit(struct ionic_lif *lif)
16298c2ecf20Sopenharmony_ci{
16308c2ecf20Sopenharmony_ci	int tbl_sz;
16318c2ecf20Sopenharmony_ci
16328c2ecf20Sopenharmony_ci	tbl_sz = le16_to_cpu(lif->ionic->ident.lif.eth.rss_ind_tbl_sz);
16338c2ecf20Sopenharmony_ci	memset(lif->rss_ind_tbl, 0, tbl_sz);
16348c2ecf20Sopenharmony_ci	memset(lif->rss_hash_key, 0, IONIC_RSS_HASH_KEY_SIZE);
16358c2ecf20Sopenharmony_ci
16368c2ecf20Sopenharmony_ci	ionic_lif_rss_config(lif, 0x0, NULL, NULL);
16378c2ecf20Sopenharmony_ci}
16388c2ecf20Sopenharmony_ci
16398c2ecf20Sopenharmony_cistatic void ionic_txrx_disable(struct ionic_lif *lif)
16408c2ecf20Sopenharmony_ci{
16418c2ecf20Sopenharmony_ci	unsigned int i;
16428c2ecf20Sopenharmony_ci	int err = 0;
16438c2ecf20Sopenharmony_ci
16448c2ecf20Sopenharmony_ci	if (lif->txqcqs) {
16458c2ecf20Sopenharmony_ci		for (i = 0; i < lif->nxqs; i++)
16468c2ecf20Sopenharmony_ci			err = ionic_qcq_disable(lif->txqcqs[i], (err != -ETIMEDOUT));
16478c2ecf20Sopenharmony_ci	}
16488c2ecf20Sopenharmony_ci
16498c2ecf20Sopenharmony_ci	if (lif->rxqcqs) {
16508c2ecf20Sopenharmony_ci		for (i = 0; i < lif->nxqs; i++)
16518c2ecf20Sopenharmony_ci			err = ionic_qcq_disable(lif->rxqcqs[i], (err != -ETIMEDOUT));
16528c2ecf20Sopenharmony_ci	}
16538c2ecf20Sopenharmony_ci}
16548c2ecf20Sopenharmony_ci
16558c2ecf20Sopenharmony_cistatic void ionic_txrx_deinit(struct ionic_lif *lif)
16568c2ecf20Sopenharmony_ci{
16578c2ecf20Sopenharmony_ci	unsigned int i;
16588c2ecf20Sopenharmony_ci
16598c2ecf20Sopenharmony_ci	if (lif->txqcqs) {
16608c2ecf20Sopenharmony_ci		for (i = 0; i < lif->nxqs && lif->txqcqs[i]; i++) {
16618c2ecf20Sopenharmony_ci			ionic_lif_qcq_deinit(lif, lif->txqcqs[i]);
16628c2ecf20Sopenharmony_ci			ionic_tx_flush(&lif->txqcqs[i]->cq);
16638c2ecf20Sopenharmony_ci			ionic_tx_empty(&lif->txqcqs[i]->q);
16648c2ecf20Sopenharmony_ci		}
16658c2ecf20Sopenharmony_ci	}
16668c2ecf20Sopenharmony_ci
16678c2ecf20Sopenharmony_ci	if (lif->rxqcqs) {
16688c2ecf20Sopenharmony_ci		for (i = 0; i < lif->nxqs && lif->rxqcqs[i]; i++) {
16698c2ecf20Sopenharmony_ci			ionic_lif_qcq_deinit(lif, lif->rxqcqs[i]);
16708c2ecf20Sopenharmony_ci			ionic_rx_empty(&lif->rxqcqs[i]->q);
16718c2ecf20Sopenharmony_ci		}
16728c2ecf20Sopenharmony_ci	}
16738c2ecf20Sopenharmony_ci	lif->rx_mode = 0;
16748c2ecf20Sopenharmony_ci}
16758c2ecf20Sopenharmony_ci
16768c2ecf20Sopenharmony_cistatic void ionic_txrx_free(struct ionic_lif *lif)
16778c2ecf20Sopenharmony_ci{
16788c2ecf20Sopenharmony_ci	unsigned int i;
16798c2ecf20Sopenharmony_ci
16808c2ecf20Sopenharmony_ci	if (lif->txqcqs) {
16818c2ecf20Sopenharmony_ci		for (i = 0; i < lif->ionic->ntxqs_per_lif && lif->txqcqs[i]; i++) {
16828c2ecf20Sopenharmony_ci			ionic_qcq_free(lif, lif->txqcqs[i]);
16838c2ecf20Sopenharmony_ci			devm_kfree(lif->ionic->dev, lif->txqcqs[i]);
16848c2ecf20Sopenharmony_ci			lif->txqcqs[i] = NULL;
16858c2ecf20Sopenharmony_ci		}
16868c2ecf20Sopenharmony_ci	}
16878c2ecf20Sopenharmony_ci
16888c2ecf20Sopenharmony_ci	if (lif->rxqcqs) {
16898c2ecf20Sopenharmony_ci		for (i = 0; i < lif->ionic->nrxqs_per_lif && lif->rxqcqs[i]; i++) {
16908c2ecf20Sopenharmony_ci			ionic_qcq_free(lif, lif->rxqcqs[i]);
16918c2ecf20Sopenharmony_ci			devm_kfree(lif->ionic->dev, lif->rxqcqs[i]);
16928c2ecf20Sopenharmony_ci			lif->rxqcqs[i] = NULL;
16938c2ecf20Sopenharmony_ci		}
16948c2ecf20Sopenharmony_ci	}
16958c2ecf20Sopenharmony_ci}
16968c2ecf20Sopenharmony_ci
16978c2ecf20Sopenharmony_cistatic int ionic_txrx_alloc(struct ionic_lif *lif)
16988c2ecf20Sopenharmony_ci{
16998c2ecf20Sopenharmony_ci	unsigned int sg_desc_sz;
17008c2ecf20Sopenharmony_ci	unsigned int flags;
17018c2ecf20Sopenharmony_ci	unsigned int i;
17028c2ecf20Sopenharmony_ci	int err = 0;
17038c2ecf20Sopenharmony_ci
17048c2ecf20Sopenharmony_ci	if (lif->qtype_info[IONIC_QTYPE_TXQ].version >= 1 &&
17058c2ecf20Sopenharmony_ci	    lif->qtype_info[IONIC_QTYPE_TXQ].sg_desc_sz ==
17068c2ecf20Sopenharmony_ci					  sizeof(struct ionic_txq_sg_desc_v1))
17078c2ecf20Sopenharmony_ci		sg_desc_sz = sizeof(struct ionic_txq_sg_desc_v1);
17088c2ecf20Sopenharmony_ci	else
17098c2ecf20Sopenharmony_ci		sg_desc_sz = sizeof(struct ionic_txq_sg_desc);
17108c2ecf20Sopenharmony_ci
17118c2ecf20Sopenharmony_ci	flags = IONIC_QCQ_F_TX_STATS | IONIC_QCQ_F_SG;
17128c2ecf20Sopenharmony_ci	if (test_bit(IONIC_LIF_F_SPLIT_INTR, lif->state))
17138c2ecf20Sopenharmony_ci		flags |= IONIC_QCQ_F_INTR;
17148c2ecf20Sopenharmony_ci	for (i = 0; i < lif->nxqs; i++) {
17158c2ecf20Sopenharmony_ci		err = ionic_qcq_alloc(lif, IONIC_QTYPE_TXQ, i, "tx", flags,
17168c2ecf20Sopenharmony_ci				      lif->ntxq_descs,
17178c2ecf20Sopenharmony_ci				      sizeof(struct ionic_txq_desc),
17188c2ecf20Sopenharmony_ci				      sizeof(struct ionic_txq_comp),
17198c2ecf20Sopenharmony_ci				      sg_desc_sz,
17208c2ecf20Sopenharmony_ci				      lif->kern_pid, &lif->txqcqs[i]);
17218c2ecf20Sopenharmony_ci		if (err)
17228c2ecf20Sopenharmony_ci			goto err_out;
17238c2ecf20Sopenharmony_ci
17248c2ecf20Sopenharmony_ci		if (flags & IONIC_QCQ_F_INTR) {
17258c2ecf20Sopenharmony_ci			ionic_intr_coal_init(lif->ionic->idev.intr_ctrl,
17268c2ecf20Sopenharmony_ci					     lif->txqcqs[i]->intr.index,
17278c2ecf20Sopenharmony_ci					     lif->tx_coalesce_hw);
17288c2ecf20Sopenharmony_ci			if (test_bit(IONIC_LIF_F_TX_DIM_INTR, lif->state))
17298c2ecf20Sopenharmony_ci				lif->txqcqs[i]->intr.dim_coal_hw = lif->tx_coalesce_hw;
17308c2ecf20Sopenharmony_ci		}
17318c2ecf20Sopenharmony_ci
17328c2ecf20Sopenharmony_ci		ionic_debugfs_add_qcq(lif, lif->txqcqs[i]);
17338c2ecf20Sopenharmony_ci	}
17348c2ecf20Sopenharmony_ci
17358c2ecf20Sopenharmony_ci	flags = IONIC_QCQ_F_RX_STATS | IONIC_QCQ_F_SG | IONIC_QCQ_F_INTR;
17368c2ecf20Sopenharmony_ci	for (i = 0; i < lif->nxqs; i++) {
17378c2ecf20Sopenharmony_ci		err = ionic_qcq_alloc(lif, IONIC_QTYPE_RXQ, i, "rx", flags,
17388c2ecf20Sopenharmony_ci				      lif->nrxq_descs,
17398c2ecf20Sopenharmony_ci				      sizeof(struct ionic_rxq_desc),
17408c2ecf20Sopenharmony_ci				      sizeof(struct ionic_rxq_comp),
17418c2ecf20Sopenharmony_ci				      sizeof(struct ionic_rxq_sg_desc),
17428c2ecf20Sopenharmony_ci				      lif->kern_pid, &lif->rxqcqs[i]);
17438c2ecf20Sopenharmony_ci		if (err)
17448c2ecf20Sopenharmony_ci			goto err_out;
17458c2ecf20Sopenharmony_ci
17468c2ecf20Sopenharmony_ci		ionic_intr_coal_init(lif->ionic->idev.intr_ctrl,
17478c2ecf20Sopenharmony_ci				     lif->rxqcqs[i]->intr.index,
17488c2ecf20Sopenharmony_ci				     lif->rx_coalesce_hw);
17498c2ecf20Sopenharmony_ci		if (test_bit(IONIC_LIF_F_RX_DIM_INTR, lif->state))
17508c2ecf20Sopenharmony_ci			lif->rxqcqs[i]->intr.dim_coal_hw = lif->rx_coalesce_hw;
17518c2ecf20Sopenharmony_ci
17528c2ecf20Sopenharmony_ci		if (!test_bit(IONIC_LIF_F_SPLIT_INTR, lif->state))
17538c2ecf20Sopenharmony_ci			ionic_link_qcq_interrupts(lif->rxqcqs[i],
17548c2ecf20Sopenharmony_ci						  lif->txqcqs[i]);
17558c2ecf20Sopenharmony_ci
17568c2ecf20Sopenharmony_ci		ionic_debugfs_add_qcq(lif, lif->rxqcqs[i]);
17578c2ecf20Sopenharmony_ci	}
17588c2ecf20Sopenharmony_ci
17598c2ecf20Sopenharmony_ci	return 0;
17608c2ecf20Sopenharmony_ci
17618c2ecf20Sopenharmony_cierr_out:
17628c2ecf20Sopenharmony_ci	ionic_txrx_free(lif);
17638c2ecf20Sopenharmony_ci
17648c2ecf20Sopenharmony_ci	return err;
17658c2ecf20Sopenharmony_ci}
17668c2ecf20Sopenharmony_ci
17678c2ecf20Sopenharmony_cistatic int ionic_txrx_init(struct ionic_lif *lif)
17688c2ecf20Sopenharmony_ci{
17698c2ecf20Sopenharmony_ci	unsigned int i;
17708c2ecf20Sopenharmony_ci	int err;
17718c2ecf20Sopenharmony_ci
17728c2ecf20Sopenharmony_ci	for (i = 0; i < lif->nxqs; i++) {
17738c2ecf20Sopenharmony_ci		err = ionic_lif_txq_init(lif, lif->txqcqs[i]);
17748c2ecf20Sopenharmony_ci		if (err)
17758c2ecf20Sopenharmony_ci			goto err_out;
17768c2ecf20Sopenharmony_ci
17778c2ecf20Sopenharmony_ci		err = ionic_lif_rxq_init(lif, lif->rxqcqs[i]);
17788c2ecf20Sopenharmony_ci		if (err) {
17798c2ecf20Sopenharmony_ci			ionic_lif_qcq_deinit(lif, lif->txqcqs[i]);
17808c2ecf20Sopenharmony_ci			goto err_out;
17818c2ecf20Sopenharmony_ci		}
17828c2ecf20Sopenharmony_ci	}
17838c2ecf20Sopenharmony_ci
17848c2ecf20Sopenharmony_ci	if (lif->netdev->features & NETIF_F_RXHASH)
17858c2ecf20Sopenharmony_ci		ionic_lif_rss_init(lif);
17868c2ecf20Sopenharmony_ci
17878c2ecf20Sopenharmony_ci	ionic_set_rx_mode(lif->netdev, true);
17888c2ecf20Sopenharmony_ci
17898c2ecf20Sopenharmony_ci	return 0;
17908c2ecf20Sopenharmony_ci
17918c2ecf20Sopenharmony_cierr_out:
17928c2ecf20Sopenharmony_ci	while (i--) {
17938c2ecf20Sopenharmony_ci		ionic_lif_qcq_deinit(lif, lif->txqcqs[i]);
17948c2ecf20Sopenharmony_ci		ionic_lif_qcq_deinit(lif, lif->rxqcqs[i]);
17958c2ecf20Sopenharmony_ci	}
17968c2ecf20Sopenharmony_ci
17978c2ecf20Sopenharmony_ci	return err;
17988c2ecf20Sopenharmony_ci}
17998c2ecf20Sopenharmony_ci
18008c2ecf20Sopenharmony_cistatic int ionic_txrx_enable(struct ionic_lif *lif)
18018c2ecf20Sopenharmony_ci{
18028c2ecf20Sopenharmony_ci	int derr = 0;
18038c2ecf20Sopenharmony_ci	int i, err;
18048c2ecf20Sopenharmony_ci
18058c2ecf20Sopenharmony_ci	for (i = 0; i < lif->nxqs; i++) {
18068c2ecf20Sopenharmony_ci		if (!(lif->rxqcqs[i] && lif->txqcqs[i])) {
18078c2ecf20Sopenharmony_ci			dev_err(lif->ionic->dev, "%s: bad qcq %d\n", __func__, i);
18088c2ecf20Sopenharmony_ci			err = -ENXIO;
18098c2ecf20Sopenharmony_ci			goto err_out;
18108c2ecf20Sopenharmony_ci		}
18118c2ecf20Sopenharmony_ci
18128c2ecf20Sopenharmony_ci		ionic_rx_fill(&lif->rxqcqs[i]->q);
18138c2ecf20Sopenharmony_ci		err = ionic_qcq_enable(lif->rxqcqs[i]);
18148c2ecf20Sopenharmony_ci		if (err)
18158c2ecf20Sopenharmony_ci			goto err_out;
18168c2ecf20Sopenharmony_ci
18178c2ecf20Sopenharmony_ci		err = ionic_qcq_enable(lif->txqcqs[i]);
18188c2ecf20Sopenharmony_ci		if (err) {
18198c2ecf20Sopenharmony_ci			derr = ionic_qcq_disable(lif->rxqcqs[i], (err != -ETIMEDOUT));
18208c2ecf20Sopenharmony_ci			goto err_out;
18218c2ecf20Sopenharmony_ci		}
18228c2ecf20Sopenharmony_ci	}
18238c2ecf20Sopenharmony_ci
18248c2ecf20Sopenharmony_ci	return 0;
18258c2ecf20Sopenharmony_ci
18268c2ecf20Sopenharmony_cierr_out:
18278c2ecf20Sopenharmony_ci	while (i--) {
18288c2ecf20Sopenharmony_ci		derr = ionic_qcq_disable(lif->txqcqs[i], (derr != -ETIMEDOUT));
18298c2ecf20Sopenharmony_ci		derr = ionic_qcq_disable(lif->rxqcqs[i], (derr != -ETIMEDOUT));
18308c2ecf20Sopenharmony_ci	}
18318c2ecf20Sopenharmony_ci
18328c2ecf20Sopenharmony_ci	return err;
18338c2ecf20Sopenharmony_ci}
18348c2ecf20Sopenharmony_ci
18358c2ecf20Sopenharmony_cistatic int ionic_start_queues(struct ionic_lif *lif)
18368c2ecf20Sopenharmony_ci{
18378c2ecf20Sopenharmony_ci	int err;
18388c2ecf20Sopenharmony_ci
18398c2ecf20Sopenharmony_ci	if (test_and_set_bit(IONIC_LIF_F_UP, lif->state))
18408c2ecf20Sopenharmony_ci		return 0;
18418c2ecf20Sopenharmony_ci
18428c2ecf20Sopenharmony_ci	err = ionic_txrx_enable(lif);
18438c2ecf20Sopenharmony_ci	if (err) {
18448c2ecf20Sopenharmony_ci		clear_bit(IONIC_LIF_F_UP, lif->state);
18458c2ecf20Sopenharmony_ci		return err;
18468c2ecf20Sopenharmony_ci	}
18478c2ecf20Sopenharmony_ci	netif_tx_wake_all_queues(lif->netdev);
18488c2ecf20Sopenharmony_ci
18498c2ecf20Sopenharmony_ci	return 0;
18508c2ecf20Sopenharmony_ci}
18518c2ecf20Sopenharmony_ci
18528c2ecf20Sopenharmony_cistatic int ionic_open(struct net_device *netdev)
18538c2ecf20Sopenharmony_ci{
18548c2ecf20Sopenharmony_ci	struct ionic_lif *lif = netdev_priv(netdev);
18558c2ecf20Sopenharmony_ci	int err;
18568c2ecf20Sopenharmony_ci
18578c2ecf20Sopenharmony_ci	err = ionic_txrx_alloc(lif);
18588c2ecf20Sopenharmony_ci	if (err)
18598c2ecf20Sopenharmony_ci		return err;
18608c2ecf20Sopenharmony_ci
18618c2ecf20Sopenharmony_ci	err = ionic_txrx_init(lif);
18628c2ecf20Sopenharmony_ci	if (err)
18638c2ecf20Sopenharmony_ci		goto err_out;
18648c2ecf20Sopenharmony_ci
18658c2ecf20Sopenharmony_ci	err = netif_set_real_num_tx_queues(netdev, lif->nxqs);
18668c2ecf20Sopenharmony_ci	if (err)
18678c2ecf20Sopenharmony_ci		goto err_txrx_deinit;
18688c2ecf20Sopenharmony_ci
18698c2ecf20Sopenharmony_ci	err = netif_set_real_num_rx_queues(netdev, lif->nxqs);
18708c2ecf20Sopenharmony_ci	if (err)
18718c2ecf20Sopenharmony_ci		goto err_txrx_deinit;
18728c2ecf20Sopenharmony_ci
18738c2ecf20Sopenharmony_ci	/* don't start the queues until we have link */
18748c2ecf20Sopenharmony_ci	if (netif_carrier_ok(netdev)) {
18758c2ecf20Sopenharmony_ci		err = ionic_start_queues(lif);
18768c2ecf20Sopenharmony_ci		if (err)
18778c2ecf20Sopenharmony_ci			goto err_txrx_deinit;
18788c2ecf20Sopenharmony_ci	}
18798c2ecf20Sopenharmony_ci
18808c2ecf20Sopenharmony_ci	return 0;
18818c2ecf20Sopenharmony_ci
18828c2ecf20Sopenharmony_cierr_txrx_deinit:
18838c2ecf20Sopenharmony_ci	ionic_txrx_deinit(lif);
18848c2ecf20Sopenharmony_cierr_out:
18858c2ecf20Sopenharmony_ci	ionic_txrx_free(lif);
18868c2ecf20Sopenharmony_ci	return err;
18878c2ecf20Sopenharmony_ci}
18888c2ecf20Sopenharmony_ci
18898c2ecf20Sopenharmony_cistatic void ionic_stop_queues(struct ionic_lif *lif)
18908c2ecf20Sopenharmony_ci{
18918c2ecf20Sopenharmony_ci	if (!test_and_clear_bit(IONIC_LIF_F_UP, lif->state))
18928c2ecf20Sopenharmony_ci		return;
18938c2ecf20Sopenharmony_ci
18948c2ecf20Sopenharmony_ci	netif_tx_disable(lif->netdev);
18958c2ecf20Sopenharmony_ci	ionic_txrx_disable(lif);
18968c2ecf20Sopenharmony_ci}
18978c2ecf20Sopenharmony_ci
18988c2ecf20Sopenharmony_cistatic int ionic_stop(struct net_device *netdev)
18998c2ecf20Sopenharmony_ci{
19008c2ecf20Sopenharmony_ci	struct ionic_lif *lif = netdev_priv(netdev);
19018c2ecf20Sopenharmony_ci
19028c2ecf20Sopenharmony_ci	if (test_bit(IONIC_LIF_F_FW_RESET, lif->state))
19038c2ecf20Sopenharmony_ci		return 0;
19048c2ecf20Sopenharmony_ci
19058c2ecf20Sopenharmony_ci	ionic_stop_queues(lif);
19068c2ecf20Sopenharmony_ci	ionic_txrx_deinit(lif);
19078c2ecf20Sopenharmony_ci	ionic_txrx_free(lif);
19088c2ecf20Sopenharmony_ci
19098c2ecf20Sopenharmony_ci	return 0;
19108c2ecf20Sopenharmony_ci}
19118c2ecf20Sopenharmony_ci
19128c2ecf20Sopenharmony_cistatic int ionic_get_vf_config(struct net_device *netdev,
19138c2ecf20Sopenharmony_ci			       int vf, struct ifla_vf_info *ivf)
19148c2ecf20Sopenharmony_ci{
19158c2ecf20Sopenharmony_ci	struct ionic_lif *lif = netdev_priv(netdev);
19168c2ecf20Sopenharmony_ci	struct ionic *ionic = lif->ionic;
19178c2ecf20Sopenharmony_ci	int ret = 0;
19188c2ecf20Sopenharmony_ci
19198c2ecf20Sopenharmony_ci	if (!netif_device_present(netdev))
19208c2ecf20Sopenharmony_ci		return -EBUSY;
19218c2ecf20Sopenharmony_ci
19228c2ecf20Sopenharmony_ci	down_read(&ionic->vf_op_lock);
19238c2ecf20Sopenharmony_ci
19248c2ecf20Sopenharmony_ci	if (vf >= pci_num_vf(ionic->pdev) || !ionic->vfs) {
19258c2ecf20Sopenharmony_ci		ret = -EINVAL;
19268c2ecf20Sopenharmony_ci	} else {
19278c2ecf20Sopenharmony_ci		ivf->vf           = vf;
19288c2ecf20Sopenharmony_ci		ivf->vlan         = le16_to_cpu(ionic->vfs[vf].vlanid);
19298c2ecf20Sopenharmony_ci		ivf->qos	  = 0;
19308c2ecf20Sopenharmony_ci		ivf->spoofchk     = ionic->vfs[vf].spoofchk;
19318c2ecf20Sopenharmony_ci		ivf->linkstate    = ionic->vfs[vf].linkstate;
19328c2ecf20Sopenharmony_ci		ivf->max_tx_rate  = le32_to_cpu(ionic->vfs[vf].maxrate);
19338c2ecf20Sopenharmony_ci		ivf->trusted      = ionic->vfs[vf].trusted;
19348c2ecf20Sopenharmony_ci		ether_addr_copy(ivf->mac, ionic->vfs[vf].macaddr);
19358c2ecf20Sopenharmony_ci	}
19368c2ecf20Sopenharmony_ci
19378c2ecf20Sopenharmony_ci	up_read(&ionic->vf_op_lock);
19388c2ecf20Sopenharmony_ci	return ret;
19398c2ecf20Sopenharmony_ci}
19408c2ecf20Sopenharmony_ci
19418c2ecf20Sopenharmony_cistatic int ionic_get_vf_stats(struct net_device *netdev, int vf,
19428c2ecf20Sopenharmony_ci			      struct ifla_vf_stats *vf_stats)
19438c2ecf20Sopenharmony_ci{
19448c2ecf20Sopenharmony_ci	struct ionic_lif *lif = netdev_priv(netdev);
19458c2ecf20Sopenharmony_ci	struct ionic *ionic = lif->ionic;
19468c2ecf20Sopenharmony_ci	struct ionic_lif_stats *vs;
19478c2ecf20Sopenharmony_ci	int ret = 0;
19488c2ecf20Sopenharmony_ci
19498c2ecf20Sopenharmony_ci	if (!netif_device_present(netdev))
19508c2ecf20Sopenharmony_ci		return -EBUSY;
19518c2ecf20Sopenharmony_ci
19528c2ecf20Sopenharmony_ci	down_read(&ionic->vf_op_lock);
19538c2ecf20Sopenharmony_ci
19548c2ecf20Sopenharmony_ci	if (vf >= pci_num_vf(ionic->pdev) || !ionic->vfs) {
19558c2ecf20Sopenharmony_ci		ret = -EINVAL;
19568c2ecf20Sopenharmony_ci	} else {
19578c2ecf20Sopenharmony_ci		memset(vf_stats, 0, sizeof(*vf_stats));
19588c2ecf20Sopenharmony_ci		vs = &ionic->vfs[vf].stats;
19598c2ecf20Sopenharmony_ci
19608c2ecf20Sopenharmony_ci		vf_stats->rx_packets = le64_to_cpu(vs->rx_ucast_packets);
19618c2ecf20Sopenharmony_ci		vf_stats->tx_packets = le64_to_cpu(vs->tx_ucast_packets);
19628c2ecf20Sopenharmony_ci		vf_stats->rx_bytes   = le64_to_cpu(vs->rx_ucast_bytes);
19638c2ecf20Sopenharmony_ci		vf_stats->tx_bytes   = le64_to_cpu(vs->tx_ucast_bytes);
19648c2ecf20Sopenharmony_ci		vf_stats->broadcast  = le64_to_cpu(vs->rx_bcast_packets);
19658c2ecf20Sopenharmony_ci		vf_stats->multicast  = le64_to_cpu(vs->rx_mcast_packets);
19668c2ecf20Sopenharmony_ci		vf_stats->rx_dropped = le64_to_cpu(vs->rx_ucast_drop_packets) +
19678c2ecf20Sopenharmony_ci				       le64_to_cpu(vs->rx_mcast_drop_packets) +
19688c2ecf20Sopenharmony_ci				       le64_to_cpu(vs->rx_bcast_drop_packets);
19698c2ecf20Sopenharmony_ci		vf_stats->tx_dropped = le64_to_cpu(vs->tx_ucast_drop_packets) +
19708c2ecf20Sopenharmony_ci				       le64_to_cpu(vs->tx_mcast_drop_packets) +
19718c2ecf20Sopenharmony_ci				       le64_to_cpu(vs->tx_bcast_drop_packets);
19728c2ecf20Sopenharmony_ci	}
19738c2ecf20Sopenharmony_ci
19748c2ecf20Sopenharmony_ci	up_read(&ionic->vf_op_lock);
19758c2ecf20Sopenharmony_ci	return ret;
19768c2ecf20Sopenharmony_ci}
19778c2ecf20Sopenharmony_ci
19788c2ecf20Sopenharmony_cistatic int ionic_set_vf_mac(struct net_device *netdev, int vf, u8 *mac)
19798c2ecf20Sopenharmony_ci{
19808c2ecf20Sopenharmony_ci	struct ionic_lif *lif = netdev_priv(netdev);
19818c2ecf20Sopenharmony_ci	struct ionic *ionic = lif->ionic;
19828c2ecf20Sopenharmony_ci	int ret;
19838c2ecf20Sopenharmony_ci
19848c2ecf20Sopenharmony_ci	if (!(is_zero_ether_addr(mac) || is_valid_ether_addr(mac)))
19858c2ecf20Sopenharmony_ci		return -EINVAL;
19868c2ecf20Sopenharmony_ci
19878c2ecf20Sopenharmony_ci	if (!netif_device_present(netdev))
19888c2ecf20Sopenharmony_ci		return -EBUSY;
19898c2ecf20Sopenharmony_ci
19908c2ecf20Sopenharmony_ci	down_write(&ionic->vf_op_lock);
19918c2ecf20Sopenharmony_ci
19928c2ecf20Sopenharmony_ci	if (vf >= pci_num_vf(ionic->pdev) || !ionic->vfs) {
19938c2ecf20Sopenharmony_ci		ret = -EINVAL;
19948c2ecf20Sopenharmony_ci	} else {
19958c2ecf20Sopenharmony_ci		ret = ionic_set_vf_config(ionic, vf, IONIC_VF_ATTR_MAC, mac);
19968c2ecf20Sopenharmony_ci		if (!ret)
19978c2ecf20Sopenharmony_ci			ether_addr_copy(ionic->vfs[vf].macaddr, mac);
19988c2ecf20Sopenharmony_ci	}
19998c2ecf20Sopenharmony_ci
20008c2ecf20Sopenharmony_ci	up_write(&ionic->vf_op_lock);
20018c2ecf20Sopenharmony_ci	return ret;
20028c2ecf20Sopenharmony_ci}
20038c2ecf20Sopenharmony_ci
20048c2ecf20Sopenharmony_cistatic int ionic_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan,
20058c2ecf20Sopenharmony_ci			     u8 qos, __be16 proto)
20068c2ecf20Sopenharmony_ci{
20078c2ecf20Sopenharmony_ci	struct ionic_lif *lif = netdev_priv(netdev);
20088c2ecf20Sopenharmony_ci	struct ionic *ionic = lif->ionic;
20098c2ecf20Sopenharmony_ci	int ret;
20108c2ecf20Sopenharmony_ci
20118c2ecf20Sopenharmony_ci	/* until someday when we support qos */
20128c2ecf20Sopenharmony_ci	if (qos)
20138c2ecf20Sopenharmony_ci		return -EINVAL;
20148c2ecf20Sopenharmony_ci
20158c2ecf20Sopenharmony_ci	if (vlan > 4095)
20168c2ecf20Sopenharmony_ci		return -EINVAL;
20178c2ecf20Sopenharmony_ci
20188c2ecf20Sopenharmony_ci	if (proto != htons(ETH_P_8021Q))
20198c2ecf20Sopenharmony_ci		return -EPROTONOSUPPORT;
20208c2ecf20Sopenharmony_ci
20218c2ecf20Sopenharmony_ci	if (!netif_device_present(netdev))
20228c2ecf20Sopenharmony_ci		return -EBUSY;
20238c2ecf20Sopenharmony_ci
20248c2ecf20Sopenharmony_ci	down_write(&ionic->vf_op_lock);
20258c2ecf20Sopenharmony_ci
20268c2ecf20Sopenharmony_ci	if (vf >= pci_num_vf(ionic->pdev) || !ionic->vfs) {
20278c2ecf20Sopenharmony_ci		ret = -EINVAL;
20288c2ecf20Sopenharmony_ci	} else {
20298c2ecf20Sopenharmony_ci		ret = ionic_set_vf_config(ionic, vf,
20308c2ecf20Sopenharmony_ci					  IONIC_VF_ATTR_VLAN, (u8 *)&vlan);
20318c2ecf20Sopenharmony_ci		if (!ret)
20328c2ecf20Sopenharmony_ci			ionic->vfs[vf].vlanid = cpu_to_le16(vlan);
20338c2ecf20Sopenharmony_ci	}
20348c2ecf20Sopenharmony_ci
20358c2ecf20Sopenharmony_ci	up_write(&ionic->vf_op_lock);
20368c2ecf20Sopenharmony_ci	return ret;
20378c2ecf20Sopenharmony_ci}
20388c2ecf20Sopenharmony_ci
20398c2ecf20Sopenharmony_cistatic int ionic_set_vf_rate(struct net_device *netdev, int vf,
20408c2ecf20Sopenharmony_ci			     int tx_min, int tx_max)
20418c2ecf20Sopenharmony_ci{
20428c2ecf20Sopenharmony_ci	struct ionic_lif *lif = netdev_priv(netdev);
20438c2ecf20Sopenharmony_ci	struct ionic *ionic = lif->ionic;
20448c2ecf20Sopenharmony_ci	int ret;
20458c2ecf20Sopenharmony_ci
20468c2ecf20Sopenharmony_ci	/* setting the min just seems silly */
20478c2ecf20Sopenharmony_ci	if (tx_min)
20488c2ecf20Sopenharmony_ci		return -EINVAL;
20498c2ecf20Sopenharmony_ci
20508c2ecf20Sopenharmony_ci	if (!netif_device_present(netdev))
20518c2ecf20Sopenharmony_ci		return -EBUSY;
20528c2ecf20Sopenharmony_ci
20538c2ecf20Sopenharmony_ci	down_write(&ionic->vf_op_lock);
20548c2ecf20Sopenharmony_ci
20558c2ecf20Sopenharmony_ci	if (vf >= pci_num_vf(ionic->pdev) || !ionic->vfs) {
20568c2ecf20Sopenharmony_ci		ret = -EINVAL;
20578c2ecf20Sopenharmony_ci	} else {
20588c2ecf20Sopenharmony_ci		ret = ionic_set_vf_config(ionic, vf,
20598c2ecf20Sopenharmony_ci					  IONIC_VF_ATTR_RATE, (u8 *)&tx_max);
20608c2ecf20Sopenharmony_ci		if (!ret)
20618c2ecf20Sopenharmony_ci			lif->ionic->vfs[vf].maxrate = cpu_to_le32(tx_max);
20628c2ecf20Sopenharmony_ci	}
20638c2ecf20Sopenharmony_ci
20648c2ecf20Sopenharmony_ci	up_write(&ionic->vf_op_lock);
20658c2ecf20Sopenharmony_ci	return ret;
20668c2ecf20Sopenharmony_ci}
20678c2ecf20Sopenharmony_ci
20688c2ecf20Sopenharmony_cistatic int ionic_set_vf_spoofchk(struct net_device *netdev, int vf, bool set)
20698c2ecf20Sopenharmony_ci{
20708c2ecf20Sopenharmony_ci	struct ionic_lif *lif = netdev_priv(netdev);
20718c2ecf20Sopenharmony_ci	struct ionic *ionic = lif->ionic;
20728c2ecf20Sopenharmony_ci	u8 data = set;  /* convert to u8 for config */
20738c2ecf20Sopenharmony_ci	int ret;
20748c2ecf20Sopenharmony_ci
20758c2ecf20Sopenharmony_ci	if (!netif_device_present(netdev))
20768c2ecf20Sopenharmony_ci		return -EBUSY;
20778c2ecf20Sopenharmony_ci
20788c2ecf20Sopenharmony_ci	down_write(&ionic->vf_op_lock);
20798c2ecf20Sopenharmony_ci
20808c2ecf20Sopenharmony_ci	if (vf >= pci_num_vf(ionic->pdev) || !ionic->vfs) {
20818c2ecf20Sopenharmony_ci		ret = -EINVAL;
20828c2ecf20Sopenharmony_ci	} else {
20838c2ecf20Sopenharmony_ci		ret = ionic_set_vf_config(ionic, vf,
20848c2ecf20Sopenharmony_ci					  IONIC_VF_ATTR_SPOOFCHK, &data);
20858c2ecf20Sopenharmony_ci		if (!ret)
20868c2ecf20Sopenharmony_ci			ionic->vfs[vf].spoofchk = data;
20878c2ecf20Sopenharmony_ci	}
20888c2ecf20Sopenharmony_ci
20898c2ecf20Sopenharmony_ci	up_write(&ionic->vf_op_lock);
20908c2ecf20Sopenharmony_ci	return ret;
20918c2ecf20Sopenharmony_ci}
20928c2ecf20Sopenharmony_ci
20938c2ecf20Sopenharmony_cistatic int ionic_set_vf_trust(struct net_device *netdev, int vf, bool set)
20948c2ecf20Sopenharmony_ci{
20958c2ecf20Sopenharmony_ci	struct ionic_lif *lif = netdev_priv(netdev);
20968c2ecf20Sopenharmony_ci	struct ionic *ionic = lif->ionic;
20978c2ecf20Sopenharmony_ci	u8 data = set;  /* convert to u8 for config */
20988c2ecf20Sopenharmony_ci	int ret;
20998c2ecf20Sopenharmony_ci
21008c2ecf20Sopenharmony_ci	if (!netif_device_present(netdev))
21018c2ecf20Sopenharmony_ci		return -EBUSY;
21028c2ecf20Sopenharmony_ci
21038c2ecf20Sopenharmony_ci	down_write(&ionic->vf_op_lock);
21048c2ecf20Sopenharmony_ci
21058c2ecf20Sopenharmony_ci	if (vf >= pci_num_vf(ionic->pdev) || !ionic->vfs) {
21068c2ecf20Sopenharmony_ci		ret = -EINVAL;
21078c2ecf20Sopenharmony_ci	} else {
21088c2ecf20Sopenharmony_ci		ret = ionic_set_vf_config(ionic, vf,
21098c2ecf20Sopenharmony_ci					  IONIC_VF_ATTR_TRUST, &data);
21108c2ecf20Sopenharmony_ci		if (!ret)
21118c2ecf20Sopenharmony_ci			ionic->vfs[vf].trusted = data;
21128c2ecf20Sopenharmony_ci	}
21138c2ecf20Sopenharmony_ci
21148c2ecf20Sopenharmony_ci	up_write(&ionic->vf_op_lock);
21158c2ecf20Sopenharmony_ci	return ret;
21168c2ecf20Sopenharmony_ci}
21178c2ecf20Sopenharmony_ci
21188c2ecf20Sopenharmony_cistatic int ionic_set_vf_link_state(struct net_device *netdev, int vf, int set)
21198c2ecf20Sopenharmony_ci{
21208c2ecf20Sopenharmony_ci	struct ionic_lif *lif = netdev_priv(netdev);
21218c2ecf20Sopenharmony_ci	struct ionic *ionic = lif->ionic;
21228c2ecf20Sopenharmony_ci	u8 data;
21238c2ecf20Sopenharmony_ci	int ret;
21248c2ecf20Sopenharmony_ci
21258c2ecf20Sopenharmony_ci	switch (set) {
21268c2ecf20Sopenharmony_ci	case IFLA_VF_LINK_STATE_ENABLE:
21278c2ecf20Sopenharmony_ci		data = IONIC_VF_LINK_STATUS_UP;
21288c2ecf20Sopenharmony_ci		break;
21298c2ecf20Sopenharmony_ci	case IFLA_VF_LINK_STATE_DISABLE:
21308c2ecf20Sopenharmony_ci		data = IONIC_VF_LINK_STATUS_DOWN;
21318c2ecf20Sopenharmony_ci		break;
21328c2ecf20Sopenharmony_ci	case IFLA_VF_LINK_STATE_AUTO:
21338c2ecf20Sopenharmony_ci		data = IONIC_VF_LINK_STATUS_AUTO;
21348c2ecf20Sopenharmony_ci		break;
21358c2ecf20Sopenharmony_ci	default:
21368c2ecf20Sopenharmony_ci		return -EINVAL;
21378c2ecf20Sopenharmony_ci	}
21388c2ecf20Sopenharmony_ci
21398c2ecf20Sopenharmony_ci	if (!netif_device_present(netdev))
21408c2ecf20Sopenharmony_ci		return -EBUSY;
21418c2ecf20Sopenharmony_ci
21428c2ecf20Sopenharmony_ci	down_write(&ionic->vf_op_lock);
21438c2ecf20Sopenharmony_ci
21448c2ecf20Sopenharmony_ci	if (vf >= pci_num_vf(ionic->pdev) || !ionic->vfs) {
21458c2ecf20Sopenharmony_ci		ret = -EINVAL;
21468c2ecf20Sopenharmony_ci	} else {
21478c2ecf20Sopenharmony_ci		ret = ionic_set_vf_config(ionic, vf,
21488c2ecf20Sopenharmony_ci					  IONIC_VF_ATTR_LINKSTATE, &data);
21498c2ecf20Sopenharmony_ci		if (!ret)
21508c2ecf20Sopenharmony_ci			ionic->vfs[vf].linkstate = set;
21518c2ecf20Sopenharmony_ci	}
21528c2ecf20Sopenharmony_ci
21538c2ecf20Sopenharmony_ci	up_write(&ionic->vf_op_lock);
21548c2ecf20Sopenharmony_ci	return ret;
21558c2ecf20Sopenharmony_ci}
21568c2ecf20Sopenharmony_ci
21578c2ecf20Sopenharmony_cistatic const struct net_device_ops ionic_netdev_ops = {
21588c2ecf20Sopenharmony_ci	.ndo_open               = ionic_open,
21598c2ecf20Sopenharmony_ci	.ndo_stop               = ionic_stop,
21608c2ecf20Sopenharmony_ci	.ndo_start_xmit		= ionic_start_xmit,
21618c2ecf20Sopenharmony_ci	.ndo_get_stats64	= ionic_get_stats64,
21628c2ecf20Sopenharmony_ci	.ndo_set_rx_mode	= ionic_ndo_set_rx_mode,
21638c2ecf20Sopenharmony_ci	.ndo_set_features	= ionic_set_features,
21648c2ecf20Sopenharmony_ci	.ndo_set_mac_address	= ionic_set_mac_address,
21658c2ecf20Sopenharmony_ci	.ndo_validate_addr	= eth_validate_addr,
21668c2ecf20Sopenharmony_ci	.ndo_tx_timeout         = ionic_tx_timeout,
21678c2ecf20Sopenharmony_ci	.ndo_change_mtu         = ionic_change_mtu,
21688c2ecf20Sopenharmony_ci	.ndo_vlan_rx_add_vid    = ionic_vlan_rx_add_vid,
21698c2ecf20Sopenharmony_ci	.ndo_vlan_rx_kill_vid   = ionic_vlan_rx_kill_vid,
21708c2ecf20Sopenharmony_ci	.ndo_set_vf_vlan	= ionic_set_vf_vlan,
21718c2ecf20Sopenharmony_ci	.ndo_set_vf_trust	= ionic_set_vf_trust,
21728c2ecf20Sopenharmony_ci	.ndo_set_vf_mac		= ionic_set_vf_mac,
21738c2ecf20Sopenharmony_ci	.ndo_set_vf_rate	= ionic_set_vf_rate,
21748c2ecf20Sopenharmony_ci	.ndo_set_vf_spoofchk	= ionic_set_vf_spoofchk,
21758c2ecf20Sopenharmony_ci	.ndo_get_vf_config	= ionic_get_vf_config,
21768c2ecf20Sopenharmony_ci	.ndo_set_vf_link_state	= ionic_set_vf_link_state,
21778c2ecf20Sopenharmony_ci	.ndo_get_vf_stats       = ionic_get_vf_stats,
21788c2ecf20Sopenharmony_ci};
21798c2ecf20Sopenharmony_ci
21808c2ecf20Sopenharmony_cistatic void ionic_swap_queues(struct ionic_qcq *a, struct ionic_qcq *b)
21818c2ecf20Sopenharmony_ci{
21828c2ecf20Sopenharmony_ci	/* only swapping the queues, not the napi, flags, or other stuff */
21838c2ecf20Sopenharmony_ci	swap(a->q.num_descs,  b->q.num_descs);
21848c2ecf20Sopenharmony_ci	swap(a->q.base,       b->q.base);
21858c2ecf20Sopenharmony_ci	swap(a->q.base_pa,    b->q.base_pa);
21868c2ecf20Sopenharmony_ci	swap(a->q.info,       b->q.info);
21878c2ecf20Sopenharmony_ci	swap(a->q_base,       b->q_base);
21888c2ecf20Sopenharmony_ci	swap(a->q_base_pa,    b->q_base_pa);
21898c2ecf20Sopenharmony_ci	swap(a->q_size,       b->q_size);
21908c2ecf20Sopenharmony_ci
21918c2ecf20Sopenharmony_ci	swap(a->q.sg_base,    b->q.sg_base);
21928c2ecf20Sopenharmony_ci	swap(a->q.sg_base_pa, b->q.sg_base_pa);
21938c2ecf20Sopenharmony_ci	swap(a->sg_base,      b->sg_base);
21948c2ecf20Sopenharmony_ci	swap(a->sg_base_pa,   b->sg_base_pa);
21958c2ecf20Sopenharmony_ci	swap(a->sg_size,      b->sg_size);
21968c2ecf20Sopenharmony_ci
21978c2ecf20Sopenharmony_ci	swap(a->cq.num_descs, b->cq.num_descs);
21988c2ecf20Sopenharmony_ci	swap(a->cq.base,      b->cq.base);
21998c2ecf20Sopenharmony_ci	swap(a->cq.base_pa,   b->cq.base_pa);
22008c2ecf20Sopenharmony_ci	swap(a->cq.info,      b->cq.info);
22018c2ecf20Sopenharmony_ci	swap(a->cq_base,      b->cq_base);
22028c2ecf20Sopenharmony_ci	swap(a->cq_base_pa,   b->cq_base_pa);
22038c2ecf20Sopenharmony_ci	swap(a->cq_size,      b->cq_size);
22048c2ecf20Sopenharmony_ci}
22058c2ecf20Sopenharmony_ci
22068c2ecf20Sopenharmony_ciint ionic_reconfigure_queues(struct ionic_lif *lif,
22078c2ecf20Sopenharmony_ci			     struct ionic_queue_params *qparam)
22088c2ecf20Sopenharmony_ci{
22098c2ecf20Sopenharmony_ci	struct ionic_qcq **tx_qcqs = NULL;
22108c2ecf20Sopenharmony_ci	struct ionic_qcq **rx_qcqs = NULL;
22118c2ecf20Sopenharmony_ci	unsigned int sg_desc_sz;
22128c2ecf20Sopenharmony_ci	unsigned int flags;
22138c2ecf20Sopenharmony_ci	int err = -ENOMEM;
22148c2ecf20Sopenharmony_ci	unsigned int i;
22158c2ecf20Sopenharmony_ci
22168c2ecf20Sopenharmony_ci	/* allocate temporary qcq arrays to hold new queue structs */
22178c2ecf20Sopenharmony_ci	if (qparam->nxqs != lif->nxqs || qparam->ntxq_descs != lif->ntxq_descs) {
22188c2ecf20Sopenharmony_ci		tx_qcqs = devm_kcalloc(lif->ionic->dev, lif->ionic->ntxqs_per_lif,
22198c2ecf20Sopenharmony_ci				       sizeof(struct ionic_qcq *), GFP_KERNEL);
22208c2ecf20Sopenharmony_ci		if (!tx_qcqs)
22218c2ecf20Sopenharmony_ci			goto err_out;
22228c2ecf20Sopenharmony_ci	}
22238c2ecf20Sopenharmony_ci	if (qparam->nxqs != lif->nxqs || qparam->nrxq_descs != lif->nrxq_descs) {
22248c2ecf20Sopenharmony_ci		rx_qcqs = devm_kcalloc(lif->ionic->dev, lif->ionic->nrxqs_per_lif,
22258c2ecf20Sopenharmony_ci				       sizeof(struct ionic_qcq *), GFP_KERNEL);
22268c2ecf20Sopenharmony_ci		if (!rx_qcqs)
22278c2ecf20Sopenharmony_ci			goto err_out;
22288c2ecf20Sopenharmony_ci	}
22298c2ecf20Sopenharmony_ci
22308c2ecf20Sopenharmony_ci	/* allocate new desc_info and rings, but leave the interrupt setup
22318c2ecf20Sopenharmony_ci	 * until later so as to not mess with the still-running queues
22328c2ecf20Sopenharmony_ci	 */
22338c2ecf20Sopenharmony_ci	if (lif->qtype_info[IONIC_QTYPE_TXQ].version >= 1 &&
22348c2ecf20Sopenharmony_ci	    lif->qtype_info[IONIC_QTYPE_TXQ].sg_desc_sz ==
22358c2ecf20Sopenharmony_ci					  sizeof(struct ionic_txq_sg_desc_v1))
22368c2ecf20Sopenharmony_ci		sg_desc_sz = sizeof(struct ionic_txq_sg_desc_v1);
22378c2ecf20Sopenharmony_ci	else
22388c2ecf20Sopenharmony_ci		sg_desc_sz = sizeof(struct ionic_txq_sg_desc);
22398c2ecf20Sopenharmony_ci
22408c2ecf20Sopenharmony_ci	if (tx_qcqs) {
22418c2ecf20Sopenharmony_ci		for (i = 0; i < qparam->nxqs; i++) {
22428c2ecf20Sopenharmony_ci			flags = lif->txqcqs[i]->flags & ~IONIC_QCQ_F_INTR;
22438c2ecf20Sopenharmony_ci			err = ionic_qcq_alloc(lif, IONIC_QTYPE_TXQ, i, "tx", flags,
22448c2ecf20Sopenharmony_ci					      qparam->ntxq_descs,
22458c2ecf20Sopenharmony_ci					      sizeof(struct ionic_txq_desc),
22468c2ecf20Sopenharmony_ci					      sizeof(struct ionic_txq_comp),
22478c2ecf20Sopenharmony_ci					      sg_desc_sz,
22488c2ecf20Sopenharmony_ci					      lif->kern_pid, &tx_qcqs[i]);
22498c2ecf20Sopenharmony_ci			if (err)
22508c2ecf20Sopenharmony_ci				goto err_out;
22518c2ecf20Sopenharmony_ci		}
22528c2ecf20Sopenharmony_ci	}
22538c2ecf20Sopenharmony_ci
22548c2ecf20Sopenharmony_ci	if (rx_qcqs) {
22558c2ecf20Sopenharmony_ci		for (i = 0; i < qparam->nxqs; i++) {
22568c2ecf20Sopenharmony_ci			flags = lif->rxqcqs[i]->flags & ~IONIC_QCQ_F_INTR;
22578c2ecf20Sopenharmony_ci			err = ionic_qcq_alloc(lif, IONIC_QTYPE_RXQ, i, "rx", flags,
22588c2ecf20Sopenharmony_ci					      qparam->nrxq_descs,
22598c2ecf20Sopenharmony_ci					      sizeof(struct ionic_rxq_desc),
22608c2ecf20Sopenharmony_ci					      sizeof(struct ionic_rxq_comp),
22618c2ecf20Sopenharmony_ci					      sizeof(struct ionic_rxq_sg_desc),
22628c2ecf20Sopenharmony_ci					      lif->kern_pid, &rx_qcqs[i]);
22638c2ecf20Sopenharmony_ci			if (err)
22648c2ecf20Sopenharmony_ci				goto err_out;
22658c2ecf20Sopenharmony_ci		}
22668c2ecf20Sopenharmony_ci	}
22678c2ecf20Sopenharmony_ci
22688c2ecf20Sopenharmony_ci	/* stop and clean the queues */
22698c2ecf20Sopenharmony_ci	ionic_stop_queues_reconfig(lif);
22708c2ecf20Sopenharmony_ci
22718c2ecf20Sopenharmony_ci	if (qparam->nxqs != lif->nxqs) {
22728c2ecf20Sopenharmony_ci		err = netif_set_real_num_tx_queues(lif->netdev, qparam->nxqs);
22738c2ecf20Sopenharmony_ci		if (err)
22748c2ecf20Sopenharmony_ci			goto err_out_reinit_unlock;
22758c2ecf20Sopenharmony_ci		err = netif_set_real_num_rx_queues(lif->netdev, qparam->nxqs);
22768c2ecf20Sopenharmony_ci		if (err) {
22778c2ecf20Sopenharmony_ci			netif_set_real_num_tx_queues(lif->netdev, lif->nxqs);
22788c2ecf20Sopenharmony_ci			goto err_out_reinit_unlock;
22798c2ecf20Sopenharmony_ci		}
22808c2ecf20Sopenharmony_ci	}
22818c2ecf20Sopenharmony_ci
22828c2ecf20Sopenharmony_ci	/* swap new desc_info and rings, keeping existing interrupt config */
22838c2ecf20Sopenharmony_ci	if (tx_qcqs) {
22848c2ecf20Sopenharmony_ci		lif->ntxq_descs = qparam->ntxq_descs;
22858c2ecf20Sopenharmony_ci		for (i = 0; i < qparam->nxqs; i++)
22868c2ecf20Sopenharmony_ci			ionic_swap_queues(lif->txqcqs[i], tx_qcqs[i]);
22878c2ecf20Sopenharmony_ci	}
22888c2ecf20Sopenharmony_ci
22898c2ecf20Sopenharmony_ci	if (rx_qcqs) {
22908c2ecf20Sopenharmony_ci		lif->nrxq_descs = qparam->nrxq_descs;
22918c2ecf20Sopenharmony_ci		for (i = 0; i < qparam->nxqs; i++)
22928c2ecf20Sopenharmony_ci			ionic_swap_queues(lif->rxqcqs[i], rx_qcqs[i]);
22938c2ecf20Sopenharmony_ci	}
22948c2ecf20Sopenharmony_ci
22958c2ecf20Sopenharmony_ci	/* if we need to change the interrupt layout, this is the time */
22968c2ecf20Sopenharmony_ci	if (qparam->intr_split != test_bit(IONIC_LIF_F_SPLIT_INTR, lif->state) ||
22978c2ecf20Sopenharmony_ci	    qparam->nxqs != lif->nxqs) {
22988c2ecf20Sopenharmony_ci		if (qparam->intr_split) {
22998c2ecf20Sopenharmony_ci			set_bit(IONIC_LIF_F_SPLIT_INTR, lif->state);
23008c2ecf20Sopenharmony_ci		} else {
23018c2ecf20Sopenharmony_ci			clear_bit(IONIC_LIF_F_SPLIT_INTR, lif->state);
23028c2ecf20Sopenharmony_ci			lif->tx_coalesce_usecs = lif->rx_coalesce_usecs;
23038c2ecf20Sopenharmony_ci			lif->tx_coalesce_hw = lif->rx_coalesce_hw;
23048c2ecf20Sopenharmony_ci		}
23058c2ecf20Sopenharmony_ci
23068c2ecf20Sopenharmony_ci		/* clear existing interrupt assignments */
23078c2ecf20Sopenharmony_ci		for (i = 0; i < lif->ionic->ntxqs_per_lif; i++) {
23088c2ecf20Sopenharmony_ci			ionic_qcq_intr_free(lif, lif->txqcqs[i]);
23098c2ecf20Sopenharmony_ci			ionic_qcq_intr_free(lif, lif->rxqcqs[i]);
23108c2ecf20Sopenharmony_ci		}
23118c2ecf20Sopenharmony_ci
23128c2ecf20Sopenharmony_ci		/* re-assign the interrupts */
23138c2ecf20Sopenharmony_ci		for (i = 0; i < qparam->nxqs; i++) {
23148c2ecf20Sopenharmony_ci			lif->rxqcqs[i]->flags |= IONIC_QCQ_F_INTR;
23158c2ecf20Sopenharmony_ci			err = ionic_alloc_qcq_interrupt(lif, lif->rxqcqs[i]);
23168c2ecf20Sopenharmony_ci			ionic_intr_coal_init(lif->ionic->idev.intr_ctrl,
23178c2ecf20Sopenharmony_ci					     lif->rxqcqs[i]->intr.index,
23188c2ecf20Sopenharmony_ci					     lif->rx_coalesce_hw);
23198c2ecf20Sopenharmony_ci
23208c2ecf20Sopenharmony_ci			if (qparam->intr_split) {
23218c2ecf20Sopenharmony_ci				lif->txqcqs[i]->flags |= IONIC_QCQ_F_INTR;
23228c2ecf20Sopenharmony_ci				err = ionic_alloc_qcq_interrupt(lif, lif->txqcqs[i]);
23238c2ecf20Sopenharmony_ci				ionic_intr_coal_init(lif->ionic->idev.intr_ctrl,
23248c2ecf20Sopenharmony_ci						     lif->txqcqs[i]->intr.index,
23258c2ecf20Sopenharmony_ci						     lif->tx_coalesce_hw);
23268c2ecf20Sopenharmony_ci				if (test_bit(IONIC_LIF_F_TX_DIM_INTR, lif->state))
23278c2ecf20Sopenharmony_ci					lif->txqcqs[i]->intr.dim_coal_hw = lif->tx_coalesce_hw;
23288c2ecf20Sopenharmony_ci			} else {
23298c2ecf20Sopenharmony_ci				lif->txqcqs[i]->flags &= ~IONIC_QCQ_F_INTR;
23308c2ecf20Sopenharmony_ci				ionic_link_qcq_interrupts(lif->rxqcqs[i], lif->txqcqs[i]);
23318c2ecf20Sopenharmony_ci			}
23328c2ecf20Sopenharmony_ci		}
23338c2ecf20Sopenharmony_ci	}
23348c2ecf20Sopenharmony_ci
23358c2ecf20Sopenharmony_ci	/* now we can rework the debugfs mappings */
23368c2ecf20Sopenharmony_ci	if (tx_qcqs) {
23378c2ecf20Sopenharmony_ci		for (i = 0; i < qparam->nxqs; i++) {
23388c2ecf20Sopenharmony_ci			ionic_debugfs_del_qcq(lif->txqcqs[i]);
23398c2ecf20Sopenharmony_ci			ionic_debugfs_add_qcq(lif, lif->txqcqs[i]);
23408c2ecf20Sopenharmony_ci		}
23418c2ecf20Sopenharmony_ci	}
23428c2ecf20Sopenharmony_ci
23438c2ecf20Sopenharmony_ci	if (rx_qcqs) {
23448c2ecf20Sopenharmony_ci		for (i = 0; i < qparam->nxqs; i++) {
23458c2ecf20Sopenharmony_ci			ionic_debugfs_del_qcq(lif->rxqcqs[i]);
23468c2ecf20Sopenharmony_ci			ionic_debugfs_add_qcq(lif, lif->rxqcqs[i]);
23478c2ecf20Sopenharmony_ci		}
23488c2ecf20Sopenharmony_ci	}
23498c2ecf20Sopenharmony_ci
23508c2ecf20Sopenharmony_ci	swap(lif->nxqs, qparam->nxqs);
23518c2ecf20Sopenharmony_ci
23528c2ecf20Sopenharmony_cierr_out_reinit_unlock:
23538c2ecf20Sopenharmony_ci	/* re-init the queues, but don't loose an error code */
23548c2ecf20Sopenharmony_ci	if (err)
23558c2ecf20Sopenharmony_ci		ionic_start_queues_reconfig(lif);
23568c2ecf20Sopenharmony_ci	else
23578c2ecf20Sopenharmony_ci		err = ionic_start_queues_reconfig(lif);
23588c2ecf20Sopenharmony_ci
23598c2ecf20Sopenharmony_cierr_out:
23608c2ecf20Sopenharmony_ci	/* free old allocs without cleaning intr */
23618c2ecf20Sopenharmony_ci	for (i = 0; i < qparam->nxqs; i++) {
23628c2ecf20Sopenharmony_ci		if (tx_qcqs && tx_qcqs[i]) {
23638c2ecf20Sopenharmony_ci			tx_qcqs[i]->flags &= ~IONIC_QCQ_F_INTR;
23648c2ecf20Sopenharmony_ci			ionic_qcq_free(lif, tx_qcqs[i]);
23658c2ecf20Sopenharmony_ci			devm_kfree(lif->ionic->dev, tx_qcqs[i]);
23668c2ecf20Sopenharmony_ci			tx_qcqs[i] = NULL;
23678c2ecf20Sopenharmony_ci		}
23688c2ecf20Sopenharmony_ci		if (rx_qcqs && rx_qcqs[i]) {
23698c2ecf20Sopenharmony_ci			rx_qcqs[i]->flags &= ~IONIC_QCQ_F_INTR;
23708c2ecf20Sopenharmony_ci			ionic_qcq_free(lif, rx_qcqs[i]);
23718c2ecf20Sopenharmony_ci			devm_kfree(lif->ionic->dev, rx_qcqs[i]);
23728c2ecf20Sopenharmony_ci			rx_qcqs[i] = NULL;
23738c2ecf20Sopenharmony_ci		}
23748c2ecf20Sopenharmony_ci	}
23758c2ecf20Sopenharmony_ci
23768c2ecf20Sopenharmony_ci	/* free q array */
23778c2ecf20Sopenharmony_ci	if (rx_qcqs) {
23788c2ecf20Sopenharmony_ci		devm_kfree(lif->ionic->dev, rx_qcqs);
23798c2ecf20Sopenharmony_ci		rx_qcqs = NULL;
23808c2ecf20Sopenharmony_ci	}
23818c2ecf20Sopenharmony_ci	if (tx_qcqs) {
23828c2ecf20Sopenharmony_ci		devm_kfree(lif->ionic->dev, tx_qcqs);
23838c2ecf20Sopenharmony_ci		tx_qcqs = NULL;
23848c2ecf20Sopenharmony_ci	}
23858c2ecf20Sopenharmony_ci
23868c2ecf20Sopenharmony_ci	/* clean the unused dma and info allocations when new set is smaller
23878c2ecf20Sopenharmony_ci	 * than the full array, but leave the qcq shells in place
23888c2ecf20Sopenharmony_ci	 */
23898c2ecf20Sopenharmony_ci	for (i = lif->nxqs; i < lif->ionic->ntxqs_per_lif; i++) {
23908c2ecf20Sopenharmony_ci		if (lif->txqcqs && lif->txqcqs[i]) {
23918c2ecf20Sopenharmony_ci			lif->txqcqs[i]->flags &= ~IONIC_QCQ_F_INTR;
23928c2ecf20Sopenharmony_ci			ionic_qcq_free(lif, lif->txqcqs[i]);
23938c2ecf20Sopenharmony_ci		}
23948c2ecf20Sopenharmony_ci
23958c2ecf20Sopenharmony_ci		if (lif->rxqcqs && lif->rxqcqs[i]) {
23968c2ecf20Sopenharmony_ci			lif->rxqcqs[i]->flags &= ~IONIC_QCQ_F_INTR;
23978c2ecf20Sopenharmony_ci			ionic_qcq_free(lif, lif->rxqcqs[i]);
23988c2ecf20Sopenharmony_ci		}
23998c2ecf20Sopenharmony_ci	}
24008c2ecf20Sopenharmony_ci
24018c2ecf20Sopenharmony_ci	return err;
24028c2ecf20Sopenharmony_ci}
24038c2ecf20Sopenharmony_ci
24048c2ecf20Sopenharmony_ciint ionic_lif_alloc(struct ionic *ionic)
24058c2ecf20Sopenharmony_ci{
24068c2ecf20Sopenharmony_ci	struct device *dev = ionic->dev;
24078c2ecf20Sopenharmony_ci	union ionic_lif_identity *lid;
24088c2ecf20Sopenharmony_ci	struct net_device *netdev;
24098c2ecf20Sopenharmony_ci	struct ionic_lif *lif;
24108c2ecf20Sopenharmony_ci	int tbl_sz;
24118c2ecf20Sopenharmony_ci	int err;
24128c2ecf20Sopenharmony_ci
24138c2ecf20Sopenharmony_ci	lid = kzalloc(sizeof(*lid), GFP_KERNEL);
24148c2ecf20Sopenharmony_ci	if (!lid)
24158c2ecf20Sopenharmony_ci		return -ENOMEM;
24168c2ecf20Sopenharmony_ci
24178c2ecf20Sopenharmony_ci	netdev = alloc_etherdev_mqs(sizeof(*lif),
24188c2ecf20Sopenharmony_ci				    ionic->ntxqs_per_lif, ionic->ntxqs_per_lif);
24198c2ecf20Sopenharmony_ci	if (!netdev) {
24208c2ecf20Sopenharmony_ci		dev_err(dev, "Cannot allocate netdev, aborting\n");
24218c2ecf20Sopenharmony_ci		err = -ENOMEM;
24228c2ecf20Sopenharmony_ci		goto err_out_free_lid;
24238c2ecf20Sopenharmony_ci	}
24248c2ecf20Sopenharmony_ci
24258c2ecf20Sopenharmony_ci	SET_NETDEV_DEV(netdev, dev);
24268c2ecf20Sopenharmony_ci
24278c2ecf20Sopenharmony_ci	lif = netdev_priv(netdev);
24288c2ecf20Sopenharmony_ci	lif->netdev = netdev;
24298c2ecf20Sopenharmony_ci	ionic->lif = lif;
24308c2ecf20Sopenharmony_ci	netdev->netdev_ops = &ionic_netdev_ops;
24318c2ecf20Sopenharmony_ci	ionic_ethtool_set_ops(netdev);
24328c2ecf20Sopenharmony_ci
24338c2ecf20Sopenharmony_ci	netdev->watchdog_timeo = 2 * HZ;
24348c2ecf20Sopenharmony_ci	netif_carrier_off(netdev);
24358c2ecf20Sopenharmony_ci
24368c2ecf20Sopenharmony_ci	lif->identity = lid;
24378c2ecf20Sopenharmony_ci	lif->lif_type = IONIC_LIF_TYPE_CLASSIC;
24388c2ecf20Sopenharmony_ci	err = ionic_lif_identify(ionic, lif->lif_type, lif->identity);
24398c2ecf20Sopenharmony_ci	if (err) {
24408c2ecf20Sopenharmony_ci		dev_err(ionic->dev, "Cannot identify type %d: %d\n",
24418c2ecf20Sopenharmony_ci			lif->lif_type, err);
24428c2ecf20Sopenharmony_ci		goto err_out_free_netdev;
24438c2ecf20Sopenharmony_ci	}
24448c2ecf20Sopenharmony_ci	lif->netdev->min_mtu = max_t(unsigned int, ETH_MIN_MTU,
24458c2ecf20Sopenharmony_ci				     le32_to_cpu(lif->identity->eth.min_frame_size));
24468c2ecf20Sopenharmony_ci	lif->netdev->max_mtu =
24478c2ecf20Sopenharmony_ci		le32_to_cpu(lif->identity->eth.max_frame_size) - ETH_HLEN - VLAN_HLEN;
24488c2ecf20Sopenharmony_ci
24498c2ecf20Sopenharmony_ci	lif->neqs = ionic->neqs_per_lif;
24508c2ecf20Sopenharmony_ci	lif->nxqs = ionic->ntxqs_per_lif;
24518c2ecf20Sopenharmony_ci
24528c2ecf20Sopenharmony_ci	lif->ionic = ionic;
24538c2ecf20Sopenharmony_ci	lif->index = 0;
24548c2ecf20Sopenharmony_ci	lif->ntxq_descs = IONIC_DEF_TXRX_DESC;
24558c2ecf20Sopenharmony_ci	lif->nrxq_descs = IONIC_DEF_TXRX_DESC;
24568c2ecf20Sopenharmony_ci	lif->tx_budget = IONIC_TX_BUDGET_DEFAULT;
24578c2ecf20Sopenharmony_ci
24588c2ecf20Sopenharmony_ci	/* Convert the default coalesce value to actual hw resolution */
24598c2ecf20Sopenharmony_ci	lif->rx_coalesce_usecs = IONIC_ITR_COAL_USEC_DEFAULT;
24608c2ecf20Sopenharmony_ci	lif->rx_coalesce_hw = ionic_coal_usec_to_hw(lif->ionic,
24618c2ecf20Sopenharmony_ci						    lif->rx_coalesce_usecs);
24628c2ecf20Sopenharmony_ci	lif->tx_coalesce_usecs = lif->rx_coalesce_usecs;
24638c2ecf20Sopenharmony_ci	lif->tx_coalesce_hw = lif->rx_coalesce_hw;
24648c2ecf20Sopenharmony_ci	set_bit(IONIC_LIF_F_RX_DIM_INTR, lif->state);
24658c2ecf20Sopenharmony_ci	set_bit(IONIC_LIF_F_TX_DIM_INTR, lif->state);
24668c2ecf20Sopenharmony_ci
24678c2ecf20Sopenharmony_ci	snprintf(lif->name, sizeof(lif->name), "lif%u", lif->index);
24688c2ecf20Sopenharmony_ci
24698c2ecf20Sopenharmony_ci	spin_lock_init(&lif->adminq_lock);
24708c2ecf20Sopenharmony_ci
24718c2ecf20Sopenharmony_ci	spin_lock_init(&lif->deferred.lock);
24728c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&lif->deferred.list);
24738c2ecf20Sopenharmony_ci	INIT_WORK(&lif->deferred.work, ionic_lif_deferred_work);
24748c2ecf20Sopenharmony_ci
24758c2ecf20Sopenharmony_ci	/* allocate lif info */
24768c2ecf20Sopenharmony_ci	lif->info_sz = ALIGN(sizeof(*lif->info), PAGE_SIZE);
24778c2ecf20Sopenharmony_ci	lif->info = dma_alloc_coherent(dev, lif->info_sz,
24788c2ecf20Sopenharmony_ci				       &lif->info_pa, GFP_KERNEL);
24798c2ecf20Sopenharmony_ci	if (!lif->info) {
24808c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to allocate lif info, aborting\n");
24818c2ecf20Sopenharmony_ci		err = -ENOMEM;
24828c2ecf20Sopenharmony_ci		goto err_out_free_netdev;
24838c2ecf20Sopenharmony_ci	}
24848c2ecf20Sopenharmony_ci
24858c2ecf20Sopenharmony_ci	ionic_debugfs_add_lif(lif);
24868c2ecf20Sopenharmony_ci
24878c2ecf20Sopenharmony_ci	/* allocate control queues and txrx queue arrays */
24888c2ecf20Sopenharmony_ci	ionic_lif_queue_identify(lif);
24898c2ecf20Sopenharmony_ci	err = ionic_qcqs_alloc(lif);
24908c2ecf20Sopenharmony_ci	if (err)
24918c2ecf20Sopenharmony_ci		goto err_out_free_lif_info;
24928c2ecf20Sopenharmony_ci
24938c2ecf20Sopenharmony_ci	/* allocate rss indirection table */
24948c2ecf20Sopenharmony_ci	tbl_sz = le16_to_cpu(lif->ionic->ident.lif.eth.rss_ind_tbl_sz);
24958c2ecf20Sopenharmony_ci	lif->rss_ind_tbl_sz = sizeof(*lif->rss_ind_tbl) * tbl_sz;
24968c2ecf20Sopenharmony_ci	lif->rss_ind_tbl = dma_alloc_coherent(dev, lif->rss_ind_tbl_sz,
24978c2ecf20Sopenharmony_ci					      &lif->rss_ind_tbl_pa,
24988c2ecf20Sopenharmony_ci					      GFP_KERNEL);
24998c2ecf20Sopenharmony_ci
25008c2ecf20Sopenharmony_ci	if (!lif->rss_ind_tbl) {
25018c2ecf20Sopenharmony_ci		err = -ENOMEM;
25028c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to allocate rss indirection table, aborting\n");
25038c2ecf20Sopenharmony_ci		goto err_out_free_qcqs;
25048c2ecf20Sopenharmony_ci	}
25058c2ecf20Sopenharmony_ci	netdev_rss_key_fill(lif->rss_hash_key, IONIC_RSS_HASH_KEY_SIZE);
25068c2ecf20Sopenharmony_ci
25078c2ecf20Sopenharmony_ci	return 0;
25088c2ecf20Sopenharmony_ci
25098c2ecf20Sopenharmony_cierr_out_free_qcqs:
25108c2ecf20Sopenharmony_ci	ionic_qcqs_free(lif);
25118c2ecf20Sopenharmony_cierr_out_free_lif_info:
25128c2ecf20Sopenharmony_ci	dma_free_coherent(dev, lif->info_sz, lif->info, lif->info_pa);
25138c2ecf20Sopenharmony_ci	lif->info = NULL;
25148c2ecf20Sopenharmony_ci	lif->info_pa = 0;
25158c2ecf20Sopenharmony_cierr_out_free_netdev:
25168c2ecf20Sopenharmony_ci	free_netdev(lif->netdev);
25178c2ecf20Sopenharmony_ci	lif = NULL;
25188c2ecf20Sopenharmony_cierr_out_free_lid:
25198c2ecf20Sopenharmony_ci	kfree(lid);
25208c2ecf20Sopenharmony_ci
25218c2ecf20Sopenharmony_ci	return err;
25228c2ecf20Sopenharmony_ci}
25238c2ecf20Sopenharmony_ci
25248c2ecf20Sopenharmony_cistatic void ionic_lif_reset(struct ionic_lif *lif)
25258c2ecf20Sopenharmony_ci{
25268c2ecf20Sopenharmony_ci	struct ionic_dev *idev = &lif->ionic->idev;
25278c2ecf20Sopenharmony_ci
25288c2ecf20Sopenharmony_ci	mutex_lock(&lif->ionic->dev_cmd_lock);
25298c2ecf20Sopenharmony_ci	ionic_dev_cmd_lif_reset(idev, lif->index);
25308c2ecf20Sopenharmony_ci	ionic_dev_cmd_wait(lif->ionic, DEVCMD_TIMEOUT);
25318c2ecf20Sopenharmony_ci	mutex_unlock(&lif->ionic->dev_cmd_lock);
25328c2ecf20Sopenharmony_ci}
25338c2ecf20Sopenharmony_ci
25348c2ecf20Sopenharmony_cistatic void ionic_lif_handle_fw_down(struct ionic_lif *lif)
25358c2ecf20Sopenharmony_ci{
25368c2ecf20Sopenharmony_ci	struct ionic *ionic = lif->ionic;
25378c2ecf20Sopenharmony_ci
25388c2ecf20Sopenharmony_ci	if (test_and_set_bit(IONIC_LIF_F_FW_RESET, lif->state))
25398c2ecf20Sopenharmony_ci		return;
25408c2ecf20Sopenharmony_ci
25418c2ecf20Sopenharmony_ci	dev_info(ionic->dev, "FW Down: Stopping LIFs\n");
25428c2ecf20Sopenharmony_ci
25438c2ecf20Sopenharmony_ci	netif_device_detach(lif->netdev);
25448c2ecf20Sopenharmony_ci
25458c2ecf20Sopenharmony_ci	if (test_bit(IONIC_LIF_F_UP, lif->state)) {
25468c2ecf20Sopenharmony_ci		dev_info(ionic->dev, "Surprise FW stop, stopping queues\n");
25478c2ecf20Sopenharmony_ci		mutex_lock(&lif->queue_lock);
25488c2ecf20Sopenharmony_ci		ionic_stop_queues(lif);
25498c2ecf20Sopenharmony_ci		mutex_unlock(&lif->queue_lock);
25508c2ecf20Sopenharmony_ci	}
25518c2ecf20Sopenharmony_ci
25528c2ecf20Sopenharmony_ci	if (netif_running(lif->netdev)) {
25538c2ecf20Sopenharmony_ci		ionic_txrx_deinit(lif);
25548c2ecf20Sopenharmony_ci		ionic_txrx_free(lif);
25558c2ecf20Sopenharmony_ci	}
25568c2ecf20Sopenharmony_ci	ionic_lif_deinit(lif);
25578c2ecf20Sopenharmony_ci	ionic_reset(ionic);
25588c2ecf20Sopenharmony_ci	ionic_qcqs_free(lif);
25598c2ecf20Sopenharmony_ci
25608c2ecf20Sopenharmony_ci	dev_info(ionic->dev, "FW Down: LIFs stopped\n");
25618c2ecf20Sopenharmony_ci}
25628c2ecf20Sopenharmony_ci
25638c2ecf20Sopenharmony_cistatic void ionic_lif_handle_fw_up(struct ionic_lif *lif)
25648c2ecf20Sopenharmony_ci{
25658c2ecf20Sopenharmony_ci	struct ionic *ionic = lif->ionic;
25668c2ecf20Sopenharmony_ci	int err;
25678c2ecf20Sopenharmony_ci
25688c2ecf20Sopenharmony_ci	if (!test_bit(IONIC_LIF_F_FW_RESET, lif->state))
25698c2ecf20Sopenharmony_ci		return;
25708c2ecf20Sopenharmony_ci
25718c2ecf20Sopenharmony_ci	dev_info(ionic->dev, "FW Up: restarting LIFs\n");
25728c2ecf20Sopenharmony_ci
25738c2ecf20Sopenharmony_ci	ionic_init_devinfo(ionic);
25748c2ecf20Sopenharmony_ci	err = ionic_identify(ionic);
25758c2ecf20Sopenharmony_ci	if (err)
25768c2ecf20Sopenharmony_ci		goto err_out;
25778c2ecf20Sopenharmony_ci	err = ionic_port_identify(ionic);
25788c2ecf20Sopenharmony_ci	if (err)
25798c2ecf20Sopenharmony_ci		goto err_out;
25808c2ecf20Sopenharmony_ci	err = ionic_port_init(ionic);
25818c2ecf20Sopenharmony_ci	if (err)
25828c2ecf20Sopenharmony_ci		goto err_out;
25838c2ecf20Sopenharmony_ci	err = ionic_qcqs_alloc(lif);
25848c2ecf20Sopenharmony_ci	if (err)
25858c2ecf20Sopenharmony_ci		goto err_out;
25868c2ecf20Sopenharmony_ci
25878c2ecf20Sopenharmony_ci	err = ionic_lif_init(lif);
25888c2ecf20Sopenharmony_ci	if (err)
25898c2ecf20Sopenharmony_ci		goto err_qcqs_free;
25908c2ecf20Sopenharmony_ci
25918c2ecf20Sopenharmony_ci	if (lif->registered)
25928c2ecf20Sopenharmony_ci		ionic_lif_set_netdev_info(lif);
25938c2ecf20Sopenharmony_ci
25948c2ecf20Sopenharmony_ci	ionic_rx_filter_replay(lif);
25958c2ecf20Sopenharmony_ci
25968c2ecf20Sopenharmony_ci	if (netif_running(lif->netdev)) {
25978c2ecf20Sopenharmony_ci		err = ionic_txrx_alloc(lif);
25988c2ecf20Sopenharmony_ci		if (err)
25998c2ecf20Sopenharmony_ci			goto err_lifs_deinit;
26008c2ecf20Sopenharmony_ci
26018c2ecf20Sopenharmony_ci		err = ionic_txrx_init(lif);
26028c2ecf20Sopenharmony_ci		if (err)
26038c2ecf20Sopenharmony_ci			goto err_txrx_free;
26048c2ecf20Sopenharmony_ci	}
26058c2ecf20Sopenharmony_ci
26068c2ecf20Sopenharmony_ci	clear_bit(IONIC_LIF_F_FW_RESET, lif->state);
26078c2ecf20Sopenharmony_ci	ionic_link_status_check_request(lif, true);
26088c2ecf20Sopenharmony_ci	netif_device_attach(lif->netdev);
26098c2ecf20Sopenharmony_ci	dev_info(ionic->dev, "FW Up: LIFs restarted\n");
26108c2ecf20Sopenharmony_ci
26118c2ecf20Sopenharmony_ci	return;
26128c2ecf20Sopenharmony_ci
26138c2ecf20Sopenharmony_cierr_txrx_free:
26148c2ecf20Sopenharmony_ci	ionic_txrx_free(lif);
26158c2ecf20Sopenharmony_cierr_lifs_deinit:
26168c2ecf20Sopenharmony_ci	ionic_lif_deinit(lif);
26178c2ecf20Sopenharmony_cierr_qcqs_free:
26188c2ecf20Sopenharmony_ci	ionic_qcqs_free(lif);
26198c2ecf20Sopenharmony_cierr_out:
26208c2ecf20Sopenharmony_ci	dev_err(ionic->dev, "FW Up: LIFs restart failed - err %d\n", err);
26218c2ecf20Sopenharmony_ci}
26228c2ecf20Sopenharmony_ci
26238c2ecf20Sopenharmony_civoid ionic_lif_free(struct ionic_lif *lif)
26248c2ecf20Sopenharmony_ci{
26258c2ecf20Sopenharmony_ci	struct device *dev = lif->ionic->dev;
26268c2ecf20Sopenharmony_ci
26278c2ecf20Sopenharmony_ci	/* free rss indirection table */
26288c2ecf20Sopenharmony_ci	dma_free_coherent(dev, lif->rss_ind_tbl_sz, lif->rss_ind_tbl,
26298c2ecf20Sopenharmony_ci			  lif->rss_ind_tbl_pa);
26308c2ecf20Sopenharmony_ci	lif->rss_ind_tbl = NULL;
26318c2ecf20Sopenharmony_ci	lif->rss_ind_tbl_pa = 0;
26328c2ecf20Sopenharmony_ci
26338c2ecf20Sopenharmony_ci	/* free queues */
26348c2ecf20Sopenharmony_ci	ionic_qcqs_free(lif);
26358c2ecf20Sopenharmony_ci	if (!test_bit(IONIC_LIF_F_FW_RESET, lif->state))
26368c2ecf20Sopenharmony_ci		ionic_lif_reset(lif);
26378c2ecf20Sopenharmony_ci
26388c2ecf20Sopenharmony_ci	/* free lif info */
26398c2ecf20Sopenharmony_ci	kfree(lif->identity);
26408c2ecf20Sopenharmony_ci	dma_free_coherent(dev, lif->info_sz, lif->info, lif->info_pa);
26418c2ecf20Sopenharmony_ci	lif->info = NULL;
26428c2ecf20Sopenharmony_ci	lif->info_pa = 0;
26438c2ecf20Sopenharmony_ci
26448c2ecf20Sopenharmony_ci	/* unmap doorbell page */
26458c2ecf20Sopenharmony_ci	ionic_bus_unmap_dbpage(lif->ionic, lif->kern_dbpage);
26468c2ecf20Sopenharmony_ci	lif->kern_dbpage = NULL;
26478c2ecf20Sopenharmony_ci	kfree(lif->dbid_inuse);
26488c2ecf20Sopenharmony_ci	lif->dbid_inuse = NULL;
26498c2ecf20Sopenharmony_ci
26508c2ecf20Sopenharmony_ci	/* free netdev & lif */
26518c2ecf20Sopenharmony_ci	ionic_debugfs_del_lif(lif);
26528c2ecf20Sopenharmony_ci	free_netdev(lif->netdev);
26538c2ecf20Sopenharmony_ci}
26548c2ecf20Sopenharmony_ci
26558c2ecf20Sopenharmony_civoid ionic_lif_deinit(struct ionic_lif *lif)
26568c2ecf20Sopenharmony_ci{
26578c2ecf20Sopenharmony_ci	if (!test_and_clear_bit(IONIC_LIF_F_INITED, lif->state))
26588c2ecf20Sopenharmony_ci		return;
26598c2ecf20Sopenharmony_ci
26608c2ecf20Sopenharmony_ci	if (!test_bit(IONIC_LIF_F_FW_RESET, lif->state)) {
26618c2ecf20Sopenharmony_ci		cancel_work_sync(&lif->deferred.work);
26628c2ecf20Sopenharmony_ci		cancel_work_sync(&lif->tx_timeout_work);
26638c2ecf20Sopenharmony_ci		ionic_rx_filters_deinit(lif);
26648c2ecf20Sopenharmony_ci		if (lif->netdev->features & NETIF_F_RXHASH)
26658c2ecf20Sopenharmony_ci			ionic_lif_rss_deinit(lif);
26668c2ecf20Sopenharmony_ci	}
26678c2ecf20Sopenharmony_ci
26688c2ecf20Sopenharmony_ci	napi_disable(&lif->adminqcq->napi);
26698c2ecf20Sopenharmony_ci	ionic_lif_qcq_deinit(lif, lif->notifyqcq);
26708c2ecf20Sopenharmony_ci	ionic_lif_qcq_deinit(lif, lif->adminqcq);
26718c2ecf20Sopenharmony_ci
26728c2ecf20Sopenharmony_ci	mutex_destroy(&lif->queue_lock);
26738c2ecf20Sopenharmony_ci	ionic_lif_reset(lif);
26748c2ecf20Sopenharmony_ci}
26758c2ecf20Sopenharmony_ci
26768c2ecf20Sopenharmony_cistatic int ionic_lif_adminq_init(struct ionic_lif *lif)
26778c2ecf20Sopenharmony_ci{
26788c2ecf20Sopenharmony_ci	struct device *dev = lif->ionic->dev;
26798c2ecf20Sopenharmony_ci	struct ionic_q_init_comp comp;
26808c2ecf20Sopenharmony_ci	struct ionic_dev *idev;
26818c2ecf20Sopenharmony_ci	struct ionic_qcq *qcq;
26828c2ecf20Sopenharmony_ci	struct ionic_queue *q;
26838c2ecf20Sopenharmony_ci	int err;
26848c2ecf20Sopenharmony_ci
26858c2ecf20Sopenharmony_ci	idev = &lif->ionic->idev;
26868c2ecf20Sopenharmony_ci	qcq = lif->adminqcq;
26878c2ecf20Sopenharmony_ci	q = &qcq->q;
26888c2ecf20Sopenharmony_ci
26898c2ecf20Sopenharmony_ci	mutex_lock(&lif->ionic->dev_cmd_lock);
26908c2ecf20Sopenharmony_ci	ionic_dev_cmd_adminq_init(idev, qcq, lif->index, qcq->intr.index);
26918c2ecf20Sopenharmony_ci	err = ionic_dev_cmd_wait(lif->ionic, DEVCMD_TIMEOUT);
26928c2ecf20Sopenharmony_ci	ionic_dev_cmd_comp(idev, (union ionic_dev_cmd_comp *)&comp);
26938c2ecf20Sopenharmony_ci	mutex_unlock(&lif->ionic->dev_cmd_lock);
26948c2ecf20Sopenharmony_ci	if (err) {
26958c2ecf20Sopenharmony_ci		netdev_err(lif->netdev, "adminq init failed %d\n", err);
26968c2ecf20Sopenharmony_ci		return err;
26978c2ecf20Sopenharmony_ci	}
26988c2ecf20Sopenharmony_ci
26998c2ecf20Sopenharmony_ci	q->hw_type = comp.hw_type;
27008c2ecf20Sopenharmony_ci	q->hw_index = le32_to_cpu(comp.hw_index);
27018c2ecf20Sopenharmony_ci	q->dbval = IONIC_DBELL_QID(q->hw_index);
27028c2ecf20Sopenharmony_ci
27038c2ecf20Sopenharmony_ci	dev_dbg(dev, "adminq->hw_type %d\n", q->hw_type);
27048c2ecf20Sopenharmony_ci	dev_dbg(dev, "adminq->hw_index %d\n", q->hw_index);
27058c2ecf20Sopenharmony_ci
27068c2ecf20Sopenharmony_ci	netif_napi_add(lif->netdev, &qcq->napi, ionic_adminq_napi,
27078c2ecf20Sopenharmony_ci		       NAPI_POLL_WEIGHT);
27088c2ecf20Sopenharmony_ci
27098c2ecf20Sopenharmony_ci	napi_enable(&qcq->napi);
27108c2ecf20Sopenharmony_ci
27118c2ecf20Sopenharmony_ci	if (qcq->flags & IONIC_QCQ_F_INTR)
27128c2ecf20Sopenharmony_ci		ionic_intr_mask(idev->intr_ctrl, qcq->intr.index,
27138c2ecf20Sopenharmony_ci				IONIC_INTR_MASK_CLEAR);
27148c2ecf20Sopenharmony_ci
27158c2ecf20Sopenharmony_ci	qcq->flags |= IONIC_QCQ_F_INITED;
27168c2ecf20Sopenharmony_ci
27178c2ecf20Sopenharmony_ci	return 0;
27188c2ecf20Sopenharmony_ci}
27198c2ecf20Sopenharmony_ci
27208c2ecf20Sopenharmony_cistatic int ionic_lif_notifyq_init(struct ionic_lif *lif)
27218c2ecf20Sopenharmony_ci{
27228c2ecf20Sopenharmony_ci	struct ionic_qcq *qcq = lif->notifyqcq;
27238c2ecf20Sopenharmony_ci	struct device *dev = lif->ionic->dev;
27248c2ecf20Sopenharmony_ci	struct ionic_queue *q = &qcq->q;
27258c2ecf20Sopenharmony_ci	int err;
27268c2ecf20Sopenharmony_ci
27278c2ecf20Sopenharmony_ci	struct ionic_admin_ctx ctx = {
27288c2ecf20Sopenharmony_ci		.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
27298c2ecf20Sopenharmony_ci		.cmd.q_init = {
27308c2ecf20Sopenharmony_ci			.opcode = IONIC_CMD_Q_INIT,
27318c2ecf20Sopenharmony_ci			.lif_index = cpu_to_le16(lif->index),
27328c2ecf20Sopenharmony_ci			.type = q->type,
27338c2ecf20Sopenharmony_ci			.ver = lif->qtype_info[q->type].version,
27348c2ecf20Sopenharmony_ci			.index = cpu_to_le32(q->index),
27358c2ecf20Sopenharmony_ci			.flags = cpu_to_le16(IONIC_QINIT_F_IRQ |
27368c2ecf20Sopenharmony_ci					     IONIC_QINIT_F_ENA),
27378c2ecf20Sopenharmony_ci			.intr_index = cpu_to_le16(lif->adminqcq->intr.index),
27388c2ecf20Sopenharmony_ci			.pid = cpu_to_le16(q->pid),
27398c2ecf20Sopenharmony_ci			.ring_size = ilog2(q->num_descs),
27408c2ecf20Sopenharmony_ci			.ring_base = cpu_to_le64(q->base_pa),
27418c2ecf20Sopenharmony_ci		}
27428c2ecf20Sopenharmony_ci	};
27438c2ecf20Sopenharmony_ci
27448c2ecf20Sopenharmony_ci	dev_dbg(dev, "notifyq_init.pid %d\n", ctx.cmd.q_init.pid);
27458c2ecf20Sopenharmony_ci	dev_dbg(dev, "notifyq_init.index %d\n", ctx.cmd.q_init.index);
27468c2ecf20Sopenharmony_ci	dev_dbg(dev, "notifyq_init.ring_base 0x%llx\n", ctx.cmd.q_init.ring_base);
27478c2ecf20Sopenharmony_ci	dev_dbg(dev, "notifyq_init.ring_size %d\n", ctx.cmd.q_init.ring_size);
27488c2ecf20Sopenharmony_ci
27498c2ecf20Sopenharmony_ci	err = ionic_adminq_post_wait(lif, &ctx);
27508c2ecf20Sopenharmony_ci	if (err)
27518c2ecf20Sopenharmony_ci		return err;
27528c2ecf20Sopenharmony_ci
27538c2ecf20Sopenharmony_ci	lif->last_eid = 0;
27548c2ecf20Sopenharmony_ci	q->hw_type = ctx.comp.q_init.hw_type;
27558c2ecf20Sopenharmony_ci	q->hw_index = le32_to_cpu(ctx.comp.q_init.hw_index);
27568c2ecf20Sopenharmony_ci	q->dbval = IONIC_DBELL_QID(q->hw_index);
27578c2ecf20Sopenharmony_ci
27588c2ecf20Sopenharmony_ci	dev_dbg(dev, "notifyq->hw_type %d\n", q->hw_type);
27598c2ecf20Sopenharmony_ci	dev_dbg(dev, "notifyq->hw_index %d\n", q->hw_index);
27608c2ecf20Sopenharmony_ci
27618c2ecf20Sopenharmony_ci	/* preset the callback info */
27628c2ecf20Sopenharmony_ci	q->info[0].cb_arg = lif;
27638c2ecf20Sopenharmony_ci
27648c2ecf20Sopenharmony_ci	qcq->flags |= IONIC_QCQ_F_INITED;
27658c2ecf20Sopenharmony_ci
27668c2ecf20Sopenharmony_ci	return 0;
27678c2ecf20Sopenharmony_ci}
27688c2ecf20Sopenharmony_ci
27698c2ecf20Sopenharmony_cistatic int ionic_station_set(struct ionic_lif *lif)
27708c2ecf20Sopenharmony_ci{
27718c2ecf20Sopenharmony_ci	struct net_device *netdev = lif->netdev;
27728c2ecf20Sopenharmony_ci	struct ionic_admin_ctx ctx = {
27738c2ecf20Sopenharmony_ci		.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
27748c2ecf20Sopenharmony_ci		.cmd.lif_getattr = {
27758c2ecf20Sopenharmony_ci			.opcode = IONIC_CMD_LIF_GETATTR,
27768c2ecf20Sopenharmony_ci			.index = cpu_to_le16(lif->index),
27778c2ecf20Sopenharmony_ci			.attr = IONIC_LIF_ATTR_MAC,
27788c2ecf20Sopenharmony_ci		},
27798c2ecf20Sopenharmony_ci	};
27808c2ecf20Sopenharmony_ci	struct sockaddr addr;
27818c2ecf20Sopenharmony_ci	int err;
27828c2ecf20Sopenharmony_ci
27838c2ecf20Sopenharmony_ci	err = ionic_adminq_post_wait(lif, &ctx);
27848c2ecf20Sopenharmony_ci	if (err)
27858c2ecf20Sopenharmony_ci		return err;
27868c2ecf20Sopenharmony_ci	netdev_dbg(lif->netdev, "found initial MAC addr %pM\n",
27878c2ecf20Sopenharmony_ci		   ctx.comp.lif_getattr.mac);
27888c2ecf20Sopenharmony_ci	if (is_zero_ether_addr(ctx.comp.lif_getattr.mac))
27898c2ecf20Sopenharmony_ci		return 0;
27908c2ecf20Sopenharmony_ci
27918c2ecf20Sopenharmony_ci	if (!is_zero_ether_addr(netdev->dev_addr)) {
27928c2ecf20Sopenharmony_ci		/* If the netdev mac is non-zero and doesn't match the default
27938c2ecf20Sopenharmony_ci		 * device address, it was set by something earlier and we're
27948c2ecf20Sopenharmony_ci		 * likely here again after a fw-upgrade reset.  We need to be
27958c2ecf20Sopenharmony_ci		 * sure the netdev mac is in our filter list.
27968c2ecf20Sopenharmony_ci		 */
27978c2ecf20Sopenharmony_ci		if (!ether_addr_equal(ctx.comp.lif_getattr.mac,
27988c2ecf20Sopenharmony_ci				      netdev->dev_addr))
27998c2ecf20Sopenharmony_ci			ionic_lif_addr(lif, netdev->dev_addr, true, true);
28008c2ecf20Sopenharmony_ci	} else {
28018c2ecf20Sopenharmony_ci		/* Update the netdev mac with the device's mac */
28028c2ecf20Sopenharmony_ci		memcpy(addr.sa_data, ctx.comp.lif_getattr.mac, netdev->addr_len);
28038c2ecf20Sopenharmony_ci		addr.sa_family = AF_INET;
28048c2ecf20Sopenharmony_ci		err = eth_prepare_mac_addr_change(netdev, &addr);
28058c2ecf20Sopenharmony_ci		if (err) {
28068c2ecf20Sopenharmony_ci			netdev_warn(lif->netdev, "ignoring bad MAC addr from NIC %pM - err %d\n",
28078c2ecf20Sopenharmony_ci				    addr.sa_data, err);
28088c2ecf20Sopenharmony_ci			return 0;
28098c2ecf20Sopenharmony_ci		}
28108c2ecf20Sopenharmony_ci
28118c2ecf20Sopenharmony_ci		eth_commit_mac_addr_change(netdev, &addr);
28128c2ecf20Sopenharmony_ci	}
28138c2ecf20Sopenharmony_ci
28148c2ecf20Sopenharmony_ci	netdev_dbg(lif->netdev, "adding station MAC addr %pM\n",
28158c2ecf20Sopenharmony_ci		   netdev->dev_addr);
28168c2ecf20Sopenharmony_ci	ionic_lif_addr(lif, netdev->dev_addr, true, true);
28178c2ecf20Sopenharmony_ci
28188c2ecf20Sopenharmony_ci	return 0;
28198c2ecf20Sopenharmony_ci}
28208c2ecf20Sopenharmony_ci
28218c2ecf20Sopenharmony_ciint ionic_lif_init(struct ionic_lif *lif)
28228c2ecf20Sopenharmony_ci{
28238c2ecf20Sopenharmony_ci	struct ionic_dev *idev = &lif->ionic->idev;
28248c2ecf20Sopenharmony_ci	struct device *dev = lif->ionic->dev;
28258c2ecf20Sopenharmony_ci	struct ionic_lif_init_comp comp;
28268c2ecf20Sopenharmony_ci	int dbpage_num;
28278c2ecf20Sopenharmony_ci	int err;
28288c2ecf20Sopenharmony_ci
28298c2ecf20Sopenharmony_ci	mutex_lock(&lif->ionic->dev_cmd_lock);
28308c2ecf20Sopenharmony_ci	ionic_dev_cmd_lif_init(idev, lif->index, lif->info_pa);
28318c2ecf20Sopenharmony_ci	err = ionic_dev_cmd_wait(lif->ionic, DEVCMD_TIMEOUT);
28328c2ecf20Sopenharmony_ci	ionic_dev_cmd_comp(idev, (union ionic_dev_cmd_comp *)&comp);
28338c2ecf20Sopenharmony_ci	mutex_unlock(&lif->ionic->dev_cmd_lock);
28348c2ecf20Sopenharmony_ci	if (err)
28358c2ecf20Sopenharmony_ci		return err;
28368c2ecf20Sopenharmony_ci
28378c2ecf20Sopenharmony_ci	lif->hw_index = le16_to_cpu(comp.hw_index);
28388c2ecf20Sopenharmony_ci	mutex_init(&lif->queue_lock);
28398c2ecf20Sopenharmony_ci
28408c2ecf20Sopenharmony_ci	/* now that we have the hw_index we can figure out our doorbell page */
28418c2ecf20Sopenharmony_ci	lif->dbid_count = le32_to_cpu(lif->ionic->ident.dev.ndbpgs_per_lif);
28428c2ecf20Sopenharmony_ci	if (!lif->dbid_count) {
28438c2ecf20Sopenharmony_ci		dev_err(dev, "No doorbell pages, aborting\n");
28448c2ecf20Sopenharmony_ci		return -EINVAL;
28458c2ecf20Sopenharmony_ci	}
28468c2ecf20Sopenharmony_ci
28478c2ecf20Sopenharmony_ci	lif->dbid_inuse = bitmap_zalloc(lif->dbid_count, GFP_KERNEL);
28488c2ecf20Sopenharmony_ci	if (!lif->dbid_inuse) {
28498c2ecf20Sopenharmony_ci		dev_err(dev, "Failed alloc doorbell id bitmap, aborting\n");
28508c2ecf20Sopenharmony_ci		return -ENOMEM;
28518c2ecf20Sopenharmony_ci	}
28528c2ecf20Sopenharmony_ci
28538c2ecf20Sopenharmony_ci	/* first doorbell id reserved for kernel (dbid aka pid == zero) */
28548c2ecf20Sopenharmony_ci	set_bit(0, lif->dbid_inuse);
28558c2ecf20Sopenharmony_ci	lif->kern_pid = 0;
28568c2ecf20Sopenharmony_ci
28578c2ecf20Sopenharmony_ci	dbpage_num = ionic_db_page_num(lif, lif->kern_pid);
28588c2ecf20Sopenharmony_ci	lif->kern_dbpage = ionic_bus_map_dbpage(lif->ionic, dbpage_num);
28598c2ecf20Sopenharmony_ci	if (!lif->kern_dbpage) {
28608c2ecf20Sopenharmony_ci		dev_err(dev, "Cannot map dbpage, aborting\n");
28618c2ecf20Sopenharmony_ci		err = -ENOMEM;
28628c2ecf20Sopenharmony_ci		goto err_out_free_dbid;
28638c2ecf20Sopenharmony_ci	}
28648c2ecf20Sopenharmony_ci
28658c2ecf20Sopenharmony_ci	err = ionic_lif_adminq_init(lif);
28668c2ecf20Sopenharmony_ci	if (err)
28678c2ecf20Sopenharmony_ci		goto err_out_adminq_deinit;
28688c2ecf20Sopenharmony_ci
28698c2ecf20Sopenharmony_ci	if (lif->ionic->nnqs_per_lif) {
28708c2ecf20Sopenharmony_ci		err = ionic_lif_notifyq_init(lif);
28718c2ecf20Sopenharmony_ci		if (err)
28728c2ecf20Sopenharmony_ci			goto err_out_notifyq_deinit;
28738c2ecf20Sopenharmony_ci	}
28748c2ecf20Sopenharmony_ci
28758c2ecf20Sopenharmony_ci	err = ionic_init_nic_features(lif);
28768c2ecf20Sopenharmony_ci	if (err)
28778c2ecf20Sopenharmony_ci		goto err_out_notifyq_deinit;
28788c2ecf20Sopenharmony_ci
28798c2ecf20Sopenharmony_ci	if (!test_bit(IONIC_LIF_F_FW_RESET, lif->state)) {
28808c2ecf20Sopenharmony_ci		err = ionic_rx_filters_init(lif);
28818c2ecf20Sopenharmony_ci		if (err)
28828c2ecf20Sopenharmony_ci			goto err_out_notifyq_deinit;
28838c2ecf20Sopenharmony_ci	}
28848c2ecf20Sopenharmony_ci
28858c2ecf20Sopenharmony_ci	err = ionic_station_set(lif);
28868c2ecf20Sopenharmony_ci	if (err)
28878c2ecf20Sopenharmony_ci		goto err_out_notifyq_deinit;
28888c2ecf20Sopenharmony_ci
28898c2ecf20Sopenharmony_ci	lif->rx_copybreak = IONIC_RX_COPYBREAK_DEFAULT;
28908c2ecf20Sopenharmony_ci
28918c2ecf20Sopenharmony_ci	set_bit(IONIC_LIF_F_INITED, lif->state);
28928c2ecf20Sopenharmony_ci
28938c2ecf20Sopenharmony_ci	INIT_WORK(&lif->tx_timeout_work, ionic_tx_timeout_work);
28948c2ecf20Sopenharmony_ci
28958c2ecf20Sopenharmony_ci	return 0;
28968c2ecf20Sopenharmony_ci
28978c2ecf20Sopenharmony_cierr_out_notifyq_deinit:
28988c2ecf20Sopenharmony_ci	ionic_lif_qcq_deinit(lif, lif->notifyqcq);
28998c2ecf20Sopenharmony_cierr_out_adminq_deinit:
29008c2ecf20Sopenharmony_ci	ionic_lif_qcq_deinit(lif, lif->adminqcq);
29018c2ecf20Sopenharmony_ci	ionic_lif_reset(lif);
29028c2ecf20Sopenharmony_ci	ionic_bus_unmap_dbpage(lif->ionic, lif->kern_dbpage);
29038c2ecf20Sopenharmony_ci	lif->kern_dbpage = NULL;
29048c2ecf20Sopenharmony_cierr_out_free_dbid:
29058c2ecf20Sopenharmony_ci	kfree(lif->dbid_inuse);
29068c2ecf20Sopenharmony_ci	lif->dbid_inuse = NULL;
29078c2ecf20Sopenharmony_ci
29088c2ecf20Sopenharmony_ci	return err;
29098c2ecf20Sopenharmony_ci}
29108c2ecf20Sopenharmony_ci
29118c2ecf20Sopenharmony_cistatic void ionic_lif_notify_work(struct work_struct *ws)
29128c2ecf20Sopenharmony_ci{
29138c2ecf20Sopenharmony_ci}
29148c2ecf20Sopenharmony_ci
29158c2ecf20Sopenharmony_cistatic void ionic_lif_set_netdev_info(struct ionic_lif *lif)
29168c2ecf20Sopenharmony_ci{
29178c2ecf20Sopenharmony_ci	struct ionic_admin_ctx ctx = {
29188c2ecf20Sopenharmony_ci		.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
29198c2ecf20Sopenharmony_ci		.cmd.lif_setattr = {
29208c2ecf20Sopenharmony_ci			.opcode = IONIC_CMD_LIF_SETATTR,
29218c2ecf20Sopenharmony_ci			.index = cpu_to_le16(lif->index),
29228c2ecf20Sopenharmony_ci			.attr = IONIC_LIF_ATTR_NAME,
29238c2ecf20Sopenharmony_ci		},
29248c2ecf20Sopenharmony_ci	};
29258c2ecf20Sopenharmony_ci
29268c2ecf20Sopenharmony_ci	strlcpy(ctx.cmd.lif_setattr.name, lif->netdev->name,
29278c2ecf20Sopenharmony_ci		sizeof(ctx.cmd.lif_setattr.name));
29288c2ecf20Sopenharmony_ci
29298c2ecf20Sopenharmony_ci	ionic_adminq_post_wait(lif, &ctx);
29308c2ecf20Sopenharmony_ci}
29318c2ecf20Sopenharmony_ci
29328c2ecf20Sopenharmony_cistatic struct ionic_lif *ionic_netdev_lif(struct net_device *netdev)
29338c2ecf20Sopenharmony_ci{
29348c2ecf20Sopenharmony_ci	if (!netdev || netdev->netdev_ops->ndo_start_xmit != ionic_start_xmit)
29358c2ecf20Sopenharmony_ci		return NULL;
29368c2ecf20Sopenharmony_ci
29378c2ecf20Sopenharmony_ci	return netdev_priv(netdev);
29388c2ecf20Sopenharmony_ci}
29398c2ecf20Sopenharmony_ci
29408c2ecf20Sopenharmony_cistatic int ionic_lif_notify(struct notifier_block *nb,
29418c2ecf20Sopenharmony_ci			    unsigned long event, void *info)
29428c2ecf20Sopenharmony_ci{
29438c2ecf20Sopenharmony_ci	struct net_device *ndev = netdev_notifier_info_to_dev(info);
29448c2ecf20Sopenharmony_ci	struct ionic *ionic = container_of(nb, struct ionic, nb);
29458c2ecf20Sopenharmony_ci	struct ionic_lif *lif = ionic_netdev_lif(ndev);
29468c2ecf20Sopenharmony_ci
29478c2ecf20Sopenharmony_ci	if (!lif || lif->ionic != ionic)
29488c2ecf20Sopenharmony_ci		return NOTIFY_DONE;
29498c2ecf20Sopenharmony_ci
29508c2ecf20Sopenharmony_ci	switch (event) {
29518c2ecf20Sopenharmony_ci	case NETDEV_CHANGENAME:
29528c2ecf20Sopenharmony_ci		ionic_lif_set_netdev_info(lif);
29538c2ecf20Sopenharmony_ci		break;
29548c2ecf20Sopenharmony_ci	}
29558c2ecf20Sopenharmony_ci
29568c2ecf20Sopenharmony_ci	return NOTIFY_DONE;
29578c2ecf20Sopenharmony_ci}
29588c2ecf20Sopenharmony_ci
29598c2ecf20Sopenharmony_ciint ionic_lif_register(struct ionic_lif *lif)
29608c2ecf20Sopenharmony_ci{
29618c2ecf20Sopenharmony_ci	int err;
29628c2ecf20Sopenharmony_ci
29638c2ecf20Sopenharmony_ci	INIT_WORK(&lif->ionic->nb_work, ionic_lif_notify_work);
29648c2ecf20Sopenharmony_ci
29658c2ecf20Sopenharmony_ci	lif->ionic->nb.notifier_call = ionic_lif_notify;
29668c2ecf20Sopenharmony_ci
29678c2ecf20Sopenharmony_ci	err = register_netdevice_notifier(&lif->ionic->nb);
29688c2ecf20Sopenharmony_ci	if (err)
29698c2ecf20Sopenharmony_ci		lif->ionic->nb.notifier_call = NULL;
29708c2ecf20Sopenharmony_ci
29718c2ecf20Sopenharmony_ci	/* only register LIF0 for now */
29728c2ecf20Sopenharmony_ci	err = register_netdev(lif->netdev);
29738c2ecf20Sopenharmony_ci	if (err) {
29748c2ecf20Sopenharmony_ci		dev_err(lif->ionic->dev, "Cannot register net device, aborting\n");
29758c2ecf20Sopenharmony_ci		return err;
29768c2ecf20Sopenharmony_ci	}
29778c2ecf20Sopenharmony_ci	lif->registered = true;
29788c2ecf20Sopenharmony_ci	ionic_lif_set_netdev_info(lif);
29798c2ecf20Sopenharmony_ci
29808c2ecf20Sopenharmony_ci	return 0;
29818c2ecf20Sopenharmony_ci}
29828c2ecf20Sopenharmony_ci
29838c2ecf20Sopenharmony_civoid ionic_lif_unregister(struct ionic_lif *lif)
29848c2ecf20Sopenharmony_ci{
29858c2ecf20Sopenharmony_ci	if (lif->ionic->nb.notifier_call) {
29868c2ecf20Sopenharmony_ci		unregister_netdevice_notifier(&lif->ionic->nb);
29878c2ecf20Sopenharmony_ci		cancel_work_sync(&lif->ionic->nb_work);
29888c2ecf20Sopenharmony_ci		lif->ionic->nb.notifier_call = NULL;
29898c2ecf20Sopenharmony_ci	}
29908c2ecf20Sopenharmony_ci
29918c2ecf20Sopenharmony_ci	if (lif->netdev->reg_state == NETREG_REGISTERED)
29928c2ecf20Sopenharmony_ci		unregister_netdev(lif->netdev);
29938c2ecf20Sopenharmony_ci	lif->registered = false;
29948c2ecf20Sopenharmony_ci}
29958c2ecf20Sopenharmony_ci
29968c2ecf20Sopenharmony_cistatic void ionic_lif_queue_identify(struct ionic_lif *lif)
29978c2ecf20Sopenharmony_ci{
29988c2ecf20Sopenharmony_ci	union ionic_q_identity __iomem *q_ident;
29998c2ecf20Sopenharmony_ci	struct ionic *ionic = lif->ionic;
30008c2ecf20Sopenharmony_ci	struct ionic_dev *idev;
30018c2ecf20Sopenharmony_ci	int qtype;
30028c2ecf20Sopenharmony_ci	int err;
30038c2ecf20Sopenharmony_ci
30048c2ecf20Sopenharmony_ci	idev = &lif->ionic->idev;
30058c2ecf20Sopenharmony_ci	q_ident = (union ionic_q_identity __iomem *)&idev->dev_cmd_regs->data;
30068c2ecf20Sopenharmony_ci
30078c2ecf20Sopenharmony_ci	for (qtype = 0; qtype < ARRAY_SIZE(ionic_qtype_versions); qtype++) {
30088c2ecf20Sopenharmony_ci		struct ionic_qtype_info *qti = &lif->qtype_info[qtype];
30098c2ecf20Sopenharmony_ci
30108c2ecf20Sopenharmony_ci		/* filter out the ones we know about */
30118c2ecf20Sopenharmony_ci		switch (qtype) {
30128c2ecf20Sopenharmony_ci		case IONIC_QTYPE_ADMINQ:
30138c2ecf20Sopenharmony_ci		case IONIC_QTYPE_NOTIFYQ:
30148c2ecf20Sopenharmony_ci		case IONIC_QTYPE_RXQ:
30158c2ecf20Sopenharmony_ci		case IONIC_QTYPE_TXQ:
30168c2ecf20Sopenharmony_ci			break;
30178c2ecf20Sopenharmony_ci		default:
30188c2ecf20Sopenharmony_ci			continue;
30198c2ecf20Sopenharmony_ci		}
30208c2ecf20Sopenharmony_ci
30218c2ecf20Sopenharmony_ci		memset(qti, 0, sizeof(*qti));
30228c2ecf20Sopenharmony_ci
30238c2ecf20Sopenharmony_ci		mutex_lock(&ionic->dev_cmd_lock);
30248c2ecf20Sopenharmony_ci		ionic_dev_cmd_queue_identify(idev, lif->lif_type, qtype,
30258c2ecf20Sopenharmony_ci					     ionic_qtype_versions[qtype]);
30268c2ecf20Sopenharmony_ci		err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT);
30278c2ecf20Sopenharmony_ci		if (!err) {
30288c2ecf20Sopenharmony_ci			qti->version   = readb(&q_ident->version);
30298c2ecf20Sopenharmony_ci			qti->supported = readb(&q_ident->supported);
30308c2ecf20Sopenharmony_ci			qti->features  = readq(&q_ident->features);
30318c2ecf20Sopenharmony_ci			qti->desc_sz   = readw(&q_ident->desc_sz);
30328c2ecf20Sopenharmony_ci			qti->comp_sz   = readw(&q_ident->comp_sz);
30338c2ecf20Sopenharmony_ci			qti->sg_desc_sz   = readw(&q_ident->sg_desc_sz);
30348c2ecf20Sopenharmony_ci			qti->max_sg_elems = readw(&q_ident->max_sg_elems);
30358c2ecf20Sopenharmony_ci			qti->sg_desc_stride = readw(&q_ident->sg_desc_stride);
30368c2ecf20Sopenharmony_ci		}
30378c2ecf20Sopenharmony_ci		mutex_unlock(&ionic->dev_cmd_lock);
30388c2ecf20Sopenharmony_ci
30398c2ecf20Sopenharmony_ci		if (err == -EINVAL) {
30408c2ecf20Sopenharmony_ci			dev_err(ionic->dev, "qtype %d not supported\n", qtype);
30418c2ecf20Sopenharmony_ci			continue;
30428c2ecf20Sopenharmony_ci		} else if (err == -EIO) {
30438c2ecf20Sopenharmony_ci			dev_err(ionic->dev, "q_ident failed, not supported on older FW\n");
30448c2ecf20Sopenharmony_ci			return;
30458c2ecf20Sopenharmony_ci		} else if (err) {
30468c2ecf20Sopenharmony_ci			dev_err(ionic->dev, "q_ident failed, qtype %d: %d\n",
30478c2ecf20Sopenharmony_ci				qtype, err);
30488c2ecf20Sopenharmony_ci			return;
30498c2ecf20Sopenharmony_ci		}
30508c2ecf20Sopenharmony_ci
30518c2ecf20Sopenharmony_ci		dev_dbg(ionic->dev, " qtype[%d].version = %d\n",
30528c2ecf20Sopenharmony_ci			qtype, qti->version);
30538c2ecf20Sopenharmony_ci		dev_dbg(ionic->dev, " qtype[%d].supported = 0x%02x\n",
30548c2ecf20Sopenharmony_ci			qtype, qti->supported);
30558c2ecf20Sopenharmony_ci		dev_dbg(ionic->dev, " qtype[%d].features = 0x%04llx\n",
30568c2ecf20Sopenharmony_ci			qtype, qti->features);
30578c2ecf20Sopenharmony_ci		dev_dbg(ionic->dev, " qtype[%d].desc_sz = %d\n",
30588c2ecf20Sopenharmony_ci			qtype, qti->desc_sz);
30598c2ecf20Sopenharmony_ci		dev_dbg(ionic->dev, " qtype[%d].comp_sz = %d\n",
30608c2ecf20Sopenharmony_ci			qtype, qti->comp_sz);
30618c2ecf20Sopenharmony_ci		dev_dbg(ionic->dev, " qtype[%d].sg_desc_sz = %d\n",
30628c2ecf20Sopenharmony_ci			qtype, qti->sg_desc_sz);
30638c2ecf20Sopenharmony_ci		dev_dbg(ionic->dev, " qtype[%d].max_sg_elems = %d\n",
30648c2ecf20Sopenharmony_ci			qtype, qti->max_sg_elems);
30658c2ecf20Sopenharmony_ci		dev_dbg(ionic->dev, " qtype[%d].sg_desc_stride = %d\n",
30668c2ecf20Sopenharmony_ci			qtype, qti->sg_desc_stride);
30678c2ecf20Sopenharmony_ci	}
30688c2ecf20Sopenharmony_ci}
30698c2ecf20Sopenharmony_ci
30708c2ecf20Sopenharmony_ciint ionic_lif_identify(struct ionic *ionic, u8 lif_type,
30718c2ecf20Sopenharmony_ci		       union ionic_lif_identity *lid)
30728c2ecf20Sopenharmony_ci{
30738c2ecf20Sopenharmony_ci	struct ionic_dev *idev = &ionic->idev;
30748c2ecf20Sopenharmony_ci	size_t sz;
30758c2ecf20Sopenharmony_ci	int err;
30768c2ecf20Sopenharmony_ci
30778c2ecf20Sopenharmony_ci	sz = min(sizeof(*lid), sizeof(idev->dev_cmd_regs->data));
30788c2ecf20Sopenharmony_ci
30798c2ecf20Sopenharmony_ci	mutex_lock(&ionic->dev_cmd_lock);
30808c2ecf20Sopenharmony_ci	ionic_dev_cmd_lif_identify(idev, lif_type, IONIC_IDENTITY_VERSION_1);
30818c2ecf20Sopenharmony_ci	err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT);
30828c2ecf20Sopenharmony_ci	memcpy_fromio(lid, &idev->dev_cmd_regs->data, sz);
30838c2ecf20Sopenharmony_ci	mutex_unlock(&ionic->dev_cmd_lock);
30848c2ecf20Sopenharmony_ci	if (err)
30858c2ecf20Sopenharmony_ci		return (err);
30868c2ecf20Sopenharmony_ci
30878c2ecf20Sopenharmony_ci	dev_dbg(ionic->dev, "capabilities 0x%llx\n",
30888c2ecf20Sopenharmony_ci		le64_to_cpu(lid->capabilities));
30898c2ecf20Sopenharmony_ci
30908c2ecf20Sopenharmony_ci	dev_dbg(ionic->dev, "eth.max_ucast_filters %d\n",
30918c2ecf20Sopenharmony_ci		le32_to_cpu(lid->eth.max_ucast_filters));
30928c2ecf20Sopenharmony_ci	dev_dbg(ionic->dev, "eth.max_mcast_filters %d\n",
30938c2ecf20Sopenharmony_ci		le32_to_cpu(lid->eth.max_mcast_filters));
30948c2ecf20Sopenharmony_ci	dev_dbg(ionic->dev, "eth.features 0x%llx\n",
30958c2ecf20Sopenharmony_ci		le64_to_cpu(lid->eth.config.features));
30968c2ecf20Sopenharmony_ci	dev_dbg(ionic->dev, "eth.queue_count[IONIC_QTYPE_ADMINQ] %d\n",
30978c2ecf20Sopenharmony_ci		le32_to_cpu(lid->eth.config.queue_count[IONIC_QTYPE_ADMINQ]));
30988c2ecf20Sopenharmony_ci	dev_dbg(ionic->dev, "eth.queue_count[IONIC_QTYPE_NOTIFYQ] %d\n",
30998c2ecf20Sopenharmony_ci		le32_to_cpu(lid->eth.config.queue_count[IONIC_QTYPE_NOTIFYQ]));
31008c2ecf20Sopenharmony_ci	dev_dbg(ionic->dev, "eth.queue_count[IONIC_QTYPE_RXQ] %d\n",
31018c2ecf20Sopenharmony_ci		le32_to_cpu(lid->eth.config.queue_count[IONIC_QTYPE_RXQ]));
31028c2ecf20Sopenharmony_ci	dev_dbg(ionic->dev, "eth.queue_count[IONIC_QTYPE_TXQ] %d\n",
31038c2ecf20Sopenharmony_ci		le32_to_cpu(lid->eth.config.queue_count[IONIC_QTYPE_TXQ]));
31048c2ecf20Sopenharmony_ci	dev_dbg(ionic->dev, "eth.config.name %s\n", lid->eth.config.name);
31058c2ecf20Sopenharmony_ci	dev_dbg(ionic->dev, "eth.config.mac %pM\n", lid->eth.config.mac);
31068c2ecf20Sopenharmony_ci	dev_dbg(ionic->dev, "eth.config.mtu %d\n",
31078c2ecf20Sopenharmony_ci		le32_to_cpu(lid->eth.config.mtu));
31088c2ecf20Sopenharmony_ci
31098c2ecf20Sopenharmony_ci	return 0;
31108c2ecf20Sopenharmony_ci}
31118c2ecf20Sopenharmony_ci
31128c2ecf20Sopenharmony_ciint ionic_lif_size(struct ionic *ionic)
31138c2ecf20Sopenharmony_ci{
31148c2ecf20Sopenharmony_ci	struct ionic_identity *ident = &ionic->ident;
31158c2ecf20Sopenharmony_ci	unsigned int nintrs, dev_nintrs;
31168c2ecf20Sopenharmony_ci	union ionic_lif_config *lc;
31178c2ecf20Sopenharmony_ci	unsigned int ntxqs_per_lif;
31188c2ecf20Sopenharmony_ci	unsigned int nrxqs_per_lif;
31198c2ecf20Sopenharmony_ci	unsigned int neqs_per_lif;
31208c2ecf20Sopenharmony_ci	unsigned int nnqs_per_lif;
31218c2ecf20Sopenharmony_ci	unsigned int nxqs, neqs;
31228c2ecf20Sopenharmony_ci	unsigned int min_intrs;
31238c2ecf20Sopenharmony_ci	int err;
31248c2ecf20Sopenharmony_ci
31258c2ecf20Sopenharmony_ci	lc = &ident->lif.eth.config;
31268c2ecf20Sopenharmony_ci	dev_nintrs = le32_to_cpu(ident->dev.nintrs);
31278c2ecf20Sopenharmony_ci	neqs_per_lif = le32_to_cpu(ident->lif.rdma.eq_qtype.qid_count);
31288c2ecf20Sopenharmony_ci	nnqs_per_lif = le32_to_cpu(lc->queue_count[IONIC_QTYPE_NOTIFYQ]);
31298c2ecf20Sopenharmony_ci	ntxqs_per_lif = le32_to_cpu(lc->queue_count[IONIC_QTYPE_TXQ]);
31308c2ecf20Sopenharmony_ci	nrxqs_per_lif = le32_to_cpu(lc->queue_count[IONIC_QTYPE_RXQ]);
31318c2ecf20Sopenharmony_ci
31328c2ecf20Sopenharmony_ci	nxqs = min(ntxqs_per_lif, nrxqs_per_lif);
31338c2ecf20Sopenharmony_ci	nxqs = min(nxqs, num_online_cpus());
31348c2ecf20Sopenharmony_ci	neqs = min(neqs_per_lif, num_online_cpus());
31358c2ecf20Sopenharmony_ci
31368c2ecf20Sopenharmony_citry_again:
31378c2ecf20Sopenharmony_ci	/* interrupt usage:
31388c2ecf20Sopenharmony_ci	 *    1 for master lif adminq/notifyq
31398c2ecf20Sopenharmony_ci	 *    1 for each CPU for master lif TxRx queue pairs
31408c2ecf20Sopenharmony_ci	 *    whatever's left is for RDMA queues
31418c2ecf20Sopenharmony_ci	 */
31428c2ecf20Sopenharmony_ci	nintrs = 1 + nxqs + neqs;
31438c2ecf20Sopenharmony_ci	min_intrs = 2;  /* adminq + 1 TxRx queue pair */
31448c2ecf20Sopenharmony_ci
31458c2ecf20Sopenharmony_ci	if (nintrs > dev_nintrs)
31468c2ecf20Sopenharmony_ci		goto try_fewer;
31478c2ecf20Sopenharmony_ci
31488c2ecf20Sopenharmony_ci	err = ionic_bus_alloc_irq_vectors(ionic, nintrs);
31498c2ecf20Sopenharmony_ci	if (err < 0 && err != -ENOSPC) {
31508c2ecf20Sopenharmony_ci		dev_err(ionic->dev, "Can't get intrs from OS: %d\n", err);
31518c2ecf20Sopenharmony_ci		return err;
31528c2ecf20Sopenharmony_ci	}
31538c2ecf20Sopenharmony_ci	if (err == -ENOSPC)
31548c2ecf20Sopenharmony_ci		goto try_fewer;
31558c2ecf20Sopenharmony_ci
31568c2ecf20Sopenharmony_ci	if (err != nintrs) {
31578c2ecf20Sopenharmony_ci		ionic_bus_free_irq_vectors(ionic);
31588c2ecf20Sopenharmony_ci		goto try_fewer;
31598c2ecf20Sopenharmony_ci	}
31608c2ecf20Sopenharmony_ci
31618c2ecf20Sopenharmony_ci	ionic->nnqs_per_lif = nnqs_per_lif;
31628c2ecf20Sopenharmony_ci	ionic->neqs_per_lif = neqs;
31638c2ecf20Sopenharmony_ci	ionic->ntxqs_per_lif = nxqs;
31648c2ecf20Sopenharmony_ci	ionic->nrxqs_per_lif = nxqs;
31658c2ecf20Sopenharmony_ci	ionic->nintrs = nintrs;
31668c2ecf20Sopenharmony_ci
31678c2ecf20Sopenharmony_ci	ionic_debugfs_add_sizes(ionic);
31688c2ecf20Sopenharmony_ci
31698c2ecf20Sopenharmony_ci	return 0;
31708c2ecf20Sopenharmony_ci
31718c2ecf20Sopenharmony_citry_fewer:
31728c2ecf20Sopenharmony_ci	if (nnqs_per_lif > 1) {
31738c2ecf20Sopenharmony_ci		nnqs_per_lif >>= 1;
31748c2ecf20Sopenharmony_ci		goto try_again;
31758c2ecf20Sopenharmony_ci	}
31768c2ecf20Sopenharmony_ci	if (neqs > 1) {
31778c2ecf20Sopenharmony_ci		neqs >>= 1;
31788c2ecf20Sopenharmony_ci		goto try_again;
31798c2ecf20Sopenharmony_ci	}
31808c2ecf20Sopenharmony_ci	if (nxqs > 1) {
31818c2ecf20Sopenharmony_ci		nxqs >>= 1;
31828c2ecf20Sopenharmony_ci		goto try_again;
31838c2ecf20Sopenharmony_ci	}
31848c2ecf20Sopenharmony_ci	dev_err(ionic->dev, "Can't get minimum %d intrs from OS\n", min_intrs);
31858c2ecf20Sopenharmony_ci	return -ENOSPC;
31868c2ecf20Sopenharmony_ci}
3187