xref: /openbmc/linux/drivers/net/ethernet/pensando/ionic/ionic_lif.c (revision 55e43d6abd078ed6d219902ce8cb4d68e3c993ba)
11a58e196SShannon Nelson // SPDX-License-Identifier: GPL-2.0
21a58e196SShannon Nelson /* Copyright(c) 2017 - 2019 Pensando Systems, Inc */
31a58e196SShannon Nelson 
4cc69837fSJakub Kicinski #include <linux/ethtool.h>
5011c7289SArnd Bergmann #include <linux/printk.h>
6011c7289SArnd Bergmann #include <linux/dynamic_debug.h>
71a58e196SShannon Nelson #include <linux/netdevice.h>
81a58e196SShannon Nelson #include <linux/etherdevice.h>
94b03b273SShannon Nelson #include <linux/if_vlan.h>
108c15440bSShannon Nelson #include <linux/rtnetlink.h>
111a58e196SShannon Nelson #include <linux/interrupt.h>
121a58e196SShannon Nelson #include <linux/pci.h>
131a58e196SShannon Nelson #include <linux/cpumask.h>
14c0b03e83SShannon Nelson #include <linux/crash_dump.h>
15922ea87fSShannon Nelson #include <linux/vmalloc.h>
161a58e196SShannon Nelson 
171a58e196SShannon Nelson #include "ionic.h"
181a58e196SShannon Nelson #include "ionic_bus.h"
19b69585bfSAllen Hubbe #include "ionic_dev.h"
201a58e196SShannon Nelson #include "ionic_lif.h"
210f3154e6SShannon Nelson #include "ionic_txrx.h"
224d03e00aSShannon Nelson #include "ionic_ethtool.h"
231a58e196SShannon Nelson #include "ionic_debugfs.h"
241a58e196SShannon Nelson 
255b3f3f2aSShannon Nelson /* queuetype support level */
265b3f3f2aSShannon Nelson static const u8 ionic_qtype_versions[IONIC_QTYPE_MAX] = {
275b3f3f2aSShannon Nelson 	[IONIC_QTYPE_ADMINQ]  = 0,   /* 0 = Base version with CQ support */
285b3f3f2aSShannon Nelson 	[IONIC_QTYPE_NOTIFYQ] = 0,   /* 0 = Base version */
2940bc471dSShannon Nelson 	[IONIC_QTYPE_RXQ]     = 2,   /* 0 = Base version with CQ+SG support
3040bc471dSShannon Nelson 				      * 2 =       ... with CMB rings
3140bc471dSShannon Nelson 				      */
3240bc471dSShannon Nelson 	[IONIC_QTYPE_TXQ]     = 3,   /* 0 = Base version with CQ+SG support
335b3f3f2aSShannon Nelson 				      * 1 =       ... with Tx SG version 1
3440bc471dSShannon Nelson 				      * 3 =       ... with CMB rings
355b3f3f2aSShannon Nelson 				      */
365b3f3f2aSShannon Nelson };
375b3f3f2aSShannon Nelson 
388d61aad4SShannon Nelson static void ionic_link_status_check(struct ionic_lif *lif);
39c672412fSShannon Nelson static void ionic_lif_handle_fw_down(struct ionic_lif *lif);
40c672412fSShannon Nelson static void ionic_lif_handle_fw_up(struct ionic_lif *lif);
41c672412fSShannon Nelson static void ionic_lif_set_netdev_info(struct ionic_lif *lif);
422a654540SShannon Nelson 
43f053e1f8SShannon Nelson static void ionic_txrx_deinit(struct ionic_lif *lif);
44f053e1f8SShannon Nelson static int ionic_txrx_init(struct ionic_lif *lif);
4549d3b493SShannon Nelson static int ionic_start_queues(struct ionic_lif *lif);
4649d3b493SShannon Nelson static void ionic_stop_queues(struct ionic_lif *lif);
475b3f3f2aSShannon Nelson static void ionic_lif_queue_identify(struct ionic_lif *lif);
4849d3b493SShannon Nelson 
ionic_dim_work(struct work_struct * work)4904a83459SShannon Nelson static void ionic_dim_work(struct work_struct *work)
5004a83459SShannon Nelson {
5104a83459SShannon Nelson 	struct dim *dim = container_of(work, struct dim, work);
5277c02d10SBrett Creeley 	struct ionic_intr_info *intr;
5304a83459SShannon Nelson 	struct dim_cq_moder cur_moder;
5404a83459SShannon Nelson 	struct ionic_qcq *qcq;
5577c02d10SBrett Creeley 	struct ionic_lif *lif;
5604a83459SShannon Nelson 	u32 new_coal;
5704a83459SShannon Nelson 
5804a83459SShannon Nelson 	cur_moder = net_dim_get_rx_moderation(dim->mode, dim->profile_ix);
5904a83459SShannon Nelson 	qcq = container_of(dim, struct ionic_qcq, dim);
6077c02d10SBrett Creeley 	lif = qcq->q.lif;
6177c02d10SBrett Creeley 	new_coal = ionic_coal_usec_to_hw(lif->ionic, cur_moder.usec);
62a6ff85e0SShannon Nelson 	new_coal = new_coal ? new_coal : 1;
63a6ff85e0SShannon Nelson 
6477c02d10SBrett Creeley 	intr = &qcq->intr;
6577c02d10SBrett Creeley 	if (intr->dim_coal_hw != new_coal) {
6677c02d10SBrett Creeley 		intr->dim_coal_hw = new_coal;
67a6ff85e0SShannon Nelson 
68a6ff85e0SShannon Nelson 		ionic_intr_coal_init(lif->ionic->idev.intr_ctrl,
6977c02d10SBrett Creeley 				     intr->index, intr->dim_coal_hw);
70a6ff85e0SShannon Nelson 	}
71a6ff85e0SShannon Nelson 
7204a83459SShannon Nelson 	dim->state = DIM_START_MEASURE;
7304a83459SShannon Nelson }
7404a83459SShannon Nelson 
ionic_lif_deferred_work(struct work_struct * work)752a654540SShannon Nelson static void ionic_lif_deferred_work(struct work_struct *work)
762a654540SShannon Nelson {
772a654540SShannon Nelson 	struct ionic_lif *lif = container_of(work, struct ionic_lif, deferred.work);
782a654540SShannon Nelson 	struct ionic_deferred *def = &lif->deferred;
792a654540SShannon Nelson 	struct ionic_deferred_work *w = NULL;
802a654540SShannon Nelson 
8152733cffSShannon Nelson 	do {
822a654540SShannon Nelson 		spin_lock_bh(&def->lock);
832a654540SShannon Nelson 		if (!list_empty(&def->list)) {
842a654540SShannon Nelson 			w = list_first_entry(&def->list,
852a654540SShannon Nelson 					     struct ionic_deferred_work, list);
862a654540SShannon Nelson 			list_del(&w->list);
872a654540SShannon Nelson 		}
882a654540SShannon Nelson 		spin_unlock_bh(&def->lock);
892a654540SShannon Nelson 
9052733cffSShannon Nelson 		if (!w)
9152733cffSShannon Nelson 			break;
9252733cffSShannon Nelson 
932a654540SShannon Nelson 		switch (w->type) {
942a654540SShannon Nelson 		case IONIC_DW_TYPE_RX_MODE:
956840e17bSShannon Nelson 			ionic_lif_rx_mode(lif);
962a654540SShannon Nelson 			break;
978d61aad4SShannon Nelson 		case IONIC_DW_TYPE_LINK_STATUS:
988d61aad4SShannon Nelson 			ionic_link_status_check(lif);
998d61aad4SShannon Nelson 			break;
100c672412fSShannon Nelson 		case IONIC_DW_TYPE_LIF_RESET:
101d3e2dcdbSShannon Nelson 			if (w->fw_status) {
102c672412fSShannon Nelson 				ionic_lif_handle_fw_up(lif);
103d3e2dcdbSShannon Nelson 			} else {
104c672412fSShannon Nelson 				ionic_lif_handle_fw_down(lif);
105d3e2dcdbSShannon Nelson 
106d3e2dcdbSShannon Nelson 				/* Fire off another watchdog to see
107d3e2dcdbSShannon Nelson 				 * if the FW is already back rather than
108d3e2dcdbSShannon Nelson 				 * waiting another whole cycle
109d3e2dcdbSShannon Nelson 				 */
110d3e2dcdbSShannon Nelson 				mod_timer(&lif->ionic->watchdog_timer, jiffies + 1);
111d3e2dcdbSShannon Nelson 			}
112c672412fSShannon Nelson 			break;
1132a654540SShannon Nelson 		default:
1142a654540SShannon Nelson 			break;
1152a654540SShannon Nelson 		}
1162a654540SShannon Nelson 		kfree(w);
11752733cffSShannon Nelson 		w = NULL;
11852733cffSShannon Nelson 	} while (true);
1192a654540SShannon Nelson }
1202a654540SShannon Nelson 
ionic_lif_deferred_enqueue(struct ionic_deferred * def,struct ionic_deferred_work * work)121c672412fSShannon Nelson void ionic_lif_deferred_enqueue(struct ionic_deferred *def,
1222a654540SShannon Nelson 				struct ionic_deferred_work *work)
1232a654540SShannon Nelson {
1242a654540SShannon Nelson 	spin_lock_bh(&def->lock);
1252a654540SShannon Nelson 	list_add_tail(&work->list, &def->list);
1262a654540SShannon Nelson 	spin_unlock_bh(&def->lock);
1272a654540SShannon Nelson 	schedule_work(&def->work);
1282a654540SShannon Nelson }
1292a654540SShannon Nelson 
ionic_link_status_check(struct ionic_lif * lif)1308d61aad4SShannon Nelson static void ionic_link_status_check(struct ionic_lif *lif)
1318d61aad4SShannon Nelson {
1328d61aad4SShannon Nelson 	struct net_device *netdev = lif->netdev;
1338d61aad4SShannon Nelson 	u16 link_status;
1348d61aad4SShannon Nelson 	bool link_up;
1358d61aad4SShannon Nelson 
1360925e9dbSShannon Nelson 	if (!test_bit(IONIC_LIF_F_LINK_CHECK_REQUESTED, lif->state))
13749d3b493SShannon Nelson 		return;
13849d3b493SShannon Nelson 
1399e8eaf84SShannon Nelson 	/* Don't put carrier back up if we're in a broken state */
1409e8eaf84SShannon Nelson 	if (test_bit(IONIC_LIF_F_BROKEN, lif->state)) {
1419e8eaf84SShannon Nelson 		clear_bit(IONIC_LIF_F_LINK_CHECK_REQUESTED, lif->state);
1429e8eaf84SShannon Nelson 		return;
1439e8eaf84SShannon Nelson 	}
1449e8eaf84SShannon Nelson 
1458d61aad4SShannon Nelson 	link_status = le16_to_cpu(lif->info->status.link_status);
1468d61aad4SShannon Nelson 	link_up = link_status == IONIC_PORT_OPER_STATUS_UP;
1478d61aad4SShannon Nelson 
1488d61aad4SShannon Nelson 	if (link_up) {
1499e8eaf84SShannon Nelson 		int err = 0;
1509e8eaf84SShannon Nelson 
15125cc5a5fSShannon Nelson 		if (netdev->flags & IFF_UP && netif_running(netdev)) {
1528f56bc4dSShannon Nelson 			mutex_lock(&lif->queue_lock);
1539e8eaf84SShannon Nelson 			err = ionic_start_queues(lif);
15499b5bea0SShannon Nelson 			if (err && err != -EBUSY) {
1557bb99009SShannon Nelson 				netdev_err(netdev,
1569e8eaf84SShannon Nelson 					   "Failed to start queues: %d\n", err);
1579e8eaf84SShannon Nelson 				set_bit(IONIC_LIF_F_BROKEN, lif->state);
1589e8eaf84SShannon Nelson 				netif_carrier_off(lif->netdev);
1599e8eaf84SShannon Nelson 			}
1608f56bc4dSShannon Nelson 			mutex_unlock(&lif->queue_lock);
1618f56bc4dSShannon Nelson 		}
1628f56bc4dSShannon Nelson 
1639e8eaf84SShannon Nelson 		if (!err && !netif_carrier_ok(netdev)) {
164aa47b540SShannon Nelson 			ionic_port_identify(lif->ionic);
165aa47b540SShannon Nelson 			netdev_info(netdev, "Link up - %d Gbps\n",
16625cc5a5fSShannon Nelson 				    le32_to_cpu(lif->info->status.link_speed) / 1000);
1670f3154e6SShannon Nelson 			netif_carrier_on(netdev);
1680f3154e6SShannon Nelson 		}
169aa47b540SShannon Nelson 	} else {
170aa47b540SShannon Nelson 		if (netif_carrier_ok(netdev)) {
171132b4ebfSNitya Sunkad 			lif->link_down_count++;
172aa47b540SShannon Nelson 			netdev_info(netdev, "Link down\n");
1738d61aad4SShannon Nelson 			netif_carrier_off(netdev);
174aa47b540SShannon Nelson 		}
175aa47b540SShannon Nelson 
17625cc5a5fSShannon Nelson 		if (netdev->flags & IFF_UP && netif_running(netdev)) {
1770925e9dbSShannon Nelson 			mutex_lock(&lif->queue_lock);
17849d3b493SShannon Nelson 			ionic_stop_queues(lif);
1790925e9dbSShannon Nelson 			mutex_unlock(&lif->queue_lock);
1800925e9dbSShannon Nelson 		}
1818d61aad4SShannon Nelson 	}
1828d61aad4SShannon Nelson 
183c6d3d73aSShannon Nelson 	clear_bit(IONIC_LIF_F_LINK_CHECK_REQUESTED, lif->state);
1848d61aad4SShannon Nelson }
1858d61aad4SShannon Nelson 
ionic_link_status_check_request(struct ionic_lif * lif,bool can_sleep)1861800eee1SSebastian Andrzej Siewior void ionic_link_status_check_request(struct ionic_lif *lif, bool can_sleep)
1878d61aad4SShannon Nelson {
1888d61aad4SShannon Nelson 	struct ionic_deferred_work *work;
1898d61aad4SShannon Nelson 
1908d61aad4SShannon Nelson 	/* we only need one request outstanding at a time */
191c6d3d73aSShannon Nelson 	if (test_and_set_bit(IONIC_LIF_F_LINK_CHECK_REQUESTED, lif->state))
1928d61aad4SShannon Nelson 		return;
1938d61aad4SShannon Nelson 
1941800eee1SSebastian Andrzej Siewior 	if (!can_sleep) {
1958d61aad4SShannon Nelson 		work = kzalloc(sizeof(*work), GFP_ATOMIC);
1962c580d77SShannon Nelson 		if (!work) {
1972c580d77SShannon Nelson 			clear_bit(IONIC_LIF_F_LINK_CHECK_REQUESTED, lif->state);
1988d61aad4SShannon Nelson 			return;
1992c580d77SShannon Nelson 		}
2008d61aad4SShannon Nelson 
2018d61aad4SShannon Nelson 		work->type = IONIC_DW_TYPE_LINK_STATUS;
2028d61aad4SShannon Nelson 		ionic_lif_deferred_enqueue(&lif->deferred, work);
2038d61aad4SShannon Nelson 	} else {
2048d61aad4SShannon Nelson 		ionic_link_status_check(lif);
2058d61aad4SShannon Nelson 	}
2068d61aad4SShannon Nelson }
2078d61aad4SShannon Nelson 
ionic_napi_deadline(struct timer_list * timer)208b69585bfSAllen Hubbe static void ionic_napi_deadline(struct timer_list *timer)
209b69585bfSAllen Hubbe {
210b69585bfSAllen Hubbe 	struct ionic_qcq *qcq = container_of(timer, struct ionic_qcq, napi_deadline);
211b69585bfSAllen Hubbe 
212b69585bfSAllen Hubbe 	napi_schedule(&qcq->napi);
213b69585bfSAllen Hubbe }
214b69585bfSAllen Hubbe 
ionic_isr(int irq,void * data)2151d062b7bSShannon Nelson static irqreturn_t ionic_isr(int irq, void *data)
2161d062b7bSShannon Nelson {
2171d062b7bSShannon Nelson 	struct napi_struct *napi = data;
2181d062b7bSShannon Nelson 
2191d062b7bSShannon Nelson 	napi_schedule_irqoff(napi);
2201d062b7bSShannon Nelson 
2211d062b7bSShannon Nelson 	return IRQ_HANDLED;
2221d062b7bSShannon Nelson }
2231d062b7bSShannon Nelson 
ionic_request_irq(struct ionic_lif * lif,struct ionic_qcq * qcq)2241d062b7bSShannon Nelson static int ionic_request_irq(struct ionic_lif *lif, struct ionic_qcq *qcq)
2251d062b7bSShannon Nelson {
2261d062b7bSShannon Nelson 	struct ionic_intr_info *intr = &qcq->intr;
2271d062b7bSShannon Nelson 	struct device *dev = lif->ionic->dev;
2281d062b7bSShannon Nelson 	struct ionic_queue *q = &qcq->q;
2291d062b7bSShannon Nelson 	const char *name;
2301d062b7bSShannon Nelson 
2311d062b7bSShannon Nelson 	if (lif->registered)
2321d062b7bSShannon Nelson 		name = lif->netdev->name;
2331d062b7bSShannon Nelson 	else
2341d062b7bSShannon Nelson 		name = dev_name(dev);
2351d062b7bSShannon Nelson 
2361d062b7bSShannon Nelson 	snprintf(intr->name, sizeof(intr->name),
23704e787f8SShannon Nelson 		 "%.5s-%.16s-%.8s", IONIC_DRV_NAME, name, q->name);
2381d062b7bSShannon Nelson 
2391d062b7bSShannon Nelson 	return devm_request_irq(dev, intr->vector, ionic_isr,
2401d062b7bSShannon Nelson 				0, intr->name, &qcq->napi);
2411d062b7bSShannon Nelson }
2421d062b7bSShannon Nelson 
ionic_intr_alloc(struct ionic_lif * lif,struct ionic_intr_info * intr)2431d062b7bSShannon Nelson static int ionic_intr_alloc(struct ionic_lif *lif, struct ionic_intr_info *intr)
2441d062b7bSShannon Nelson {
2451d062b7bSShannon Nelson 	struct ionic *ionic = lif->ionic;
2461d062b7bSShannon Nelson 	int index;
2471d062b7bSShannon Nelson 
2481d062b7bSShannon Nelson 	index = find_first_zero_bit(ionic->intrs, ionic->nintrs);
2491d062b7bSShannon Nelson 	if (index == ionic->nintrs) {
2501d062b7bSShannon Nelson 		netdev_warn(lif->netdev, "%s: no intr, index=%d nintrs=%d\n",
2511d062b7bSShannon Nelson 			    __func__, index, ionic->nintrs);
2521d062b7bSShannon Nelson 		return -ENOSPC;
2531d062b7bSShannon Nelson 	}
2541d062b7bSShannon Nelson 
2551d062b7bSShannon Nelson 	set_bit(index, ionic->intrs);
2561d062b7bSShannon Nelson 	ionic_intr_init(&ionic->idev, intr, index);
2571d062b7bSShannon Nelson 
2581d062b7bSShannon Nelson 	return 0;
2591d062b7bSShannon Nelson }
2601d062b7bSShannon Nelson 
ionic_intr_free(struct ionic * ionic,int index)26136ac2c50SShannon Nelson static void ionic_intr_free(struct ionic *ionic, int index)
2621d062b7bSShannon Nelson {
263c06107caSShannon Nelson 	if (index != IONIC_INTR_INDEX_NOT_ASSIGNED && index < ionic->nintrs)
26436ac2c50SShannon Nelson 		clear_bit(index, ionic->intrs);
2651d062b7bSShannon Nelson }
2661d062b7bSShannon Nelson 
ionic_qcq_enable(struct ionic_qcq * qcq)2670f3154e6SShannon Nelson static int ionic_qcq_enable(struct ionic_qcq *qcq)
2680f3154e6SShannon Nelson {
2690f3154e6SShannon Nelson 	struct ionic_queue *q = &qcq->q;
2700f3154e6SShannon Nelson 	struct ionic_lif *lif = q->lif;
2710f3154e6SShannon Nelson 	struct ionic_dev *idev;
2720f3154e6SShannon Nelson 	struct device *dev;
2730f3154e6SShannon Nelson 
2740f3154e6SShannon Nelson 	struct ionic_admin_ctx ctx = {
2750f3154e6SShannon Nelson 		.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
2760f3154e6SShannon Nelson 		.cmd.q_control = {
2770f3154e6SShannon Nelson 			.opcode = IONIC_CMD_Q_CONTROL,
2780f3154e6SShannon Nelson 			.lif_index = cpu_to_le16(lif->index),
2790f3154e6SShannon Nelson 			.type = q->type,
2800f3154e6SShannon Nelson 			.index = cpu_to_le32(q->index),
2810f3154e6SShannon Nelson 			.oper = IONIC_Q_ENABLE,
2820f3154e6SShannon Nelson 		},
2830f3154e6SShannon Nelson 	};
284e8797a05SNeel Patel 	int ret;
2850f3154e6SShannon Nelson 
2860f3154e6SShannon Nelson 	idev = &lif->ionic->idev;
2870f3154e6SShannon Nelson 	dev = lif->ionic->dev;
2880f3154e6SShannon Nelson 
2890f3154e6SShannon Nelson 	dev_dbg(dev, "q_enable.index %d q_enable.qtype %d\n",
2900f3154e6SShannon Nelson 		ctx.cmd.q_control.index, ctx.cmd.q_control.type);
2910f3154e6SShannon Nelson 
292e8797a05SNeel Patel 	if (qcq->flags & IONIC_QCQ_F_INTR)
293e8797a05SNeel Patel 		ionic_intr_clean(idev->intr_ctrl, qcq->intr.index);
294e8797a05SNeel Patel 
295e8797a05SNeel Patel 	ret = ionic_adminq_post_wait(lif, &ctx);
296e8797a05SNeel Patel 	if (ret)
297e8797a05SNeel Patel 		return ret;
298e8797a05SNeel Patel 
2990f3154e6SShannon Nelson 	if (qcq->flags & IONIC_QCQ_F_INTR) {
300183ebc16STaehee Yoo 		napi_enable(&qcq->napi);
3010f3154e6SShannon Nelson 		irq_set_affinity_hint(qcq->intr.vector,
3020f3154e6SShannon Nelson 				      &qcq->intr.affinity_mask);
3030f3154e6SShannon Nelson 		ionic_intr_mask(idev->intr_ctrl, qcq->intr.index,
3040f3154e6SShannon Nelson 				IONIC_INTR_MASK_CLEAR);
3050f3154e6SShannon Nelson 	}
3060f3154e6SShannon Nelson 
307e8797a05SNeel Patel 	return 0;
3080f3154e6SShannon Nelson }
3090f3154e6SShannon Nelson 
ionic_qcq_disable(struct ionic_lif * lif,struct ionic_qcq * qcq,int fw_err)3107dd22a86SShannon Nelson static int ionic_qcq_disable(struct ionic_lif *lif, struct ionic_qcq *qcq, int fw_err)
3110f3154e6SShannon Nelson {
3127c737fc4SShannon Nelson 	struct ionic_queue *q;
3130f3154e6SShannon Nelson 
3140f3154e6SShannon Nelson 	struct ionic_admin_ctx ctx = {
3150f3154e6SShannon Nelson 		.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
3160f3154e6SShannon Nelson 		.cmd.q_control = {
3170f3154e6SShannon Nelson 			.opcode = IONIC_CMD_Q_CONTROL,
3180f3154e6SShannon Nelson 			.oper = IONIC_Q_DISABLE,
3190f3154e6SShannon Nelson 		},
3200f3154e6SShannon Nelson 	};
3210f3154e6SShannon Nelson 
3227dd22a86SShannon Nelson 	if (!qcq) {
3237dd22a86SShannon Nelson 		netdev_err(lif->netdev, "%s: bad qcq\n", __func__);
3247c737fc4SShannon Nelson 		return -ENXIO;
3257dd22a86SShannon Nelson 	}
3260f3154e6SShannon Nelson 
3277c737fc4SShannon Nelson 	q = &qcq->q;
3280f3154e6SShannon Nelson 
3290f3154e6SShannon Nelson 	if (qcq->flags & IONIC_QCQ_F_INTR) {
3307c737fc4SShannon Nelson 		struct ionic_dev *idev = &lif->ionic->idev;
3317c737fc4SShannon Nelson 
33204a83459SShannon Nelson 		cancel_work_sync(&qcq->dim.work);
3330f3154e6SShannon Nelson 		ionic_intr_mask(idev->intr_ctrl, qcq->intr.index,
3340f3154e6SShannon Nelson 				IONIC_INTR_MASK_SET);
3350f3154e6SShannon Nelson 		synchronize_irq(qcq->intr.vector);
3360f3154e6SShannon Nelson 		irq_set_affinity_hint(qcq->intr.vector, NULL);
3370f3154e6SShannon Nelson 		napi_disable(&qcq->napi);
338b69585bfSAllen Hubbe 		del_timer_sync(&qcq->napi_deadline);
3390f3154e6SShannon Nelson 	}
3400f3154e6SShannon Nelson 
3413a5e0fafSShannon Nelson 	/* If there was a previous fw communcation error, don't bother with
3423a5e0fafSShannon Nelson 	 * sending the adminq command and just return the same error value.
3433a5e0fafSShannon Nelson 	 */
3443a5e0fafSShannon Nelson 	if (fw_err == -ETIMEDOUT || fw_err == -ENXIO)
3453a5e0fafSShannon Nelson 		return fw_err;
3463a5e0fafSShannon Nelson 
3477c737fc4SShannon Nelson 	ctx.cmd.q_control.lif_index = cpu_to_le16(lif->index);
3487c737fc4SShannon Nelson 	ctx.cmd.q_control.type = q->type;
3497c737fc4SShannon Nelson 	ctx.cmd.q_control.index = cpu_to_le32(q->index);
3507c737fc4SShannon Nelson 	dev_dbg(lif->ionic->dev, "q_disable.index %d q_disable.qtype %d\n",
3517c737fc4SShannon Nelson 		ctx.cmd.q_control.index, ctx.cmd.q_control.type);
3527c737fc4SShannon Nelson 
3533a5e0fafSShannon Nelson 	return ionic_adminq_post_wait(lif, &ctx);
3540f3154e6SShannon Nelson }
3550f3154e6SShannon Nelson 
ionic_lif_qcq_deinit(struct ionic_lif * lif,struct ionic_qcq * qcq)3561d062b7bSShannon Nelson static void ionic_lif_qcq_deinit(struct ionic_lif *lif, struct ionic_qcq *qcq)
3571d062b7bSShannon Nelson {
3581d062b7bSShannon Nelson 	struct ionic_dev *idev = &lif->ionic->idev;
3591d062b7bSShannon Nelson 
3601d062b7bSShannon Nelson 	if (!qcq)
3611d062b7bSShannon Nelson 		return;
3621d062b7bSShannon Nelson 
3631d062b7bSShannon Nelson 	if (!(qcq->flags & IONIC_QCQ_F_INITED))
3641d062b7bSShannon Nelson 		return;
3651d062b7bSShannon Nelson 
3661d062b7bSShannon Nelson 	if (qcq->flags & IONIC_QCQ_F_INTR) {
3671d062b7bSShannon Nelson 		ionic_intr_mask(idev->intr_ctrl, qcq->intr.index,
3681d062b7bSShannon Nelson 				IONIC_INTR_MASK_SET);
3691d062b7bSShannon Nelson 		netif_napi_del(&qcq->napi);
3701d062b7bSShannon Nelson 	}
3711d062b7bSShannon Nelson 
3721d062b7bSShannon Nelson 	qcq->flags &= ~IONIC_QCQ_F_INITED;
3731d062b7bSShannon Nelson }
3741d062b7bSShannon Nelson 
ionic_qcq_intr_free(struct ionic_lif * lif,struct ionic_qcq * qcq)375101b40a0SShannon Nelson static void ionic_qcq_intr_free(struct ionic_lif *lif, struct ionic_qcq *qcq)
376101b40a0SShannon Nelson {
377101b40a0SShannon Nelson 	if (!(qcq->flags & IONIC_QCQ_F_INTR) || qcq->intr.vector == 0)
378101b40a0SShannon Nelson 		return;
379101b40a0SShannon Nelson 
380101b40a0SShannon Nelson 	irq_set_affinity_hint(qcq->intr.vector, NULL);
381101b40a0SShannon Nelson 	devm_free_irq(lif->ionic->dev, qcq->intr.vector, &qcq->napi);
382101b40a0SShannon Nelson 	qcq->intr.vector = 0;
383101b40a0SShannon Nelson 	ionic_intr_free(lif->ionic, qcq->intr.index);
384101b40a0SShannon Nelson 	qcq->intr.index = IONIC_INTR_INDEX_NOT_ASSIGNED;
385101b40a0SShannon Nelson }
386101b40a0SShannon Nelson 
ionic_qcq_free(struct ionic_lif * lif,struct ionic_qcq * qcq)3871d062b7bSShannon Nelson static void ionic_qcq_free(struct ionic_lif *lif, struct ionic_qcq *qcq)
3881d062b7bSShannon Nelson {
3891d062b7bSShannon Nelson 	struct device *dev = lif->ionic->dev;
3901d062b7bSShannon Nelson 
3911d062b7bSShannon Nelson 	if (!qcq)
3921d062b7bSShannon Nelson 		return;
3931d062b7bSShannon Nelson 
3942a8c2c1aSShannon Nelson 	ionic_debugfs_del_qcq(qcq);
3952a8c2c1aSShannon Nelson 
396ea5a8b09SShannon Nelson 	if (qcq->q_base) {
397ea5a8b09SShannon Nelson 		dma_free_coherent(dev, qcq->q_size, qcq->q_base, qcq->q_base_pa);
398ea5a8b09SShannon Nelson 		qcq->q_base = NULL;
399ea5a8b09SShannon Nelson 		qcq->q_base_pa = 0;
400ea5a8b09SShannon Nelson 	}
401ea5a8b09SShannon Nelson 
40240bc471dSShannon Nelson 	if (qcq->cmb_q_base) {
40340bc471dSShannon Nelson 		iounmap(qcq->cmb_q_base);
40440bc471dSShannon Nelson 		ionic_put_cmb(lif, qcq->cmb_pgid, qcq->cmb_order);
40540bc471dSShannon Nelson 		qcq->cmb_pgid = 0;
40640bc471dSShannon Nelson 		qcq->cmb_order = 0;
40740bc471dSShannon Nelson 		qcq->cmb_q_base = NULL;
40840bc471dSShannon Nelson 		qcq->cmb_q_base_pa = 0;
40940bc471dSShannon Nelson 	}
41040bc471dSShannon Nelson 
411ea5a8b09SShannon Nelson 	if (qcq->cq_base) {
412ea5a8b09SShannon Nelson 		dma_free_coherent(dev, qcq->cq_size, qcq->cq_base, qcq->cq_base_pa);
413ea5a8b09SShannon Nelson 		qcq->cq_base = NULL;
414ea5a8b09SShannon Nelson 		qcq->cq_base_pa = 0;
415ea5a8b09SShannon Nelson 	}
416ea5a8b09SShannon Nelson 
417ea5a8b09SShannon Nelson 	if (qcq->sg_base) {
418ea5a8b09SShannon Nelson 		dma_free_coherent(dev, qcq->sg_size, qcq->sg_base, qcq->sg_base_pa);
419ea5a8b09SShannon Nelson 		qcq->sg_base = NULL;
420ea5a8b09SShannon Nelson 		qcq->sg_base_pa = 0;
421ea5a8b09SShannon Nelson 	}
4221d062b7bSShannon Nelson 
423101b40a0SShannon Nelson 	ionic_qcq_intr_free(lif, qcq);
4241d062b7bSShannon Nelson 
425a34e25abSShannon Nelson 	if (qcq->cq.info) {
426116dce0fSBrett Creeley 		vfree(qcq->cq.info);
4271d062b7bSShannon Nelson 		qcq->cq.info = NULL;
428a34e25abSShannon Nelson 	}
429a34e25abSShannon Nelson 	if (qcq->q.info) {
430116dce0fSBrett Creeley 		vfree(qcq->q.info);
4311d062b7bSShannon Nelson 		qcq->q.info = NULL;
432a34e25abSShannon Nelson 	}
4331d062b7bSShannon Nelson }
4341d062b7bSShannon Nelson 
ionic_qcqs_free(struct ionic_lif * lif)435a79b559eSShannon Nelson void ionic_qcqs_free(struct ionic_lif *lif)
4361d062b7bSShannon Nelson {
4370f3154e6SShannon Nelson 	struct device *dev = lif->ionic->dev;
438e768929dSShannon Nelson 	struct ionic_qcq *adminqcq;
439e768929dSShannon Nelson 	unsigned long irqflags;
4400f3154e6SShannon Nelson 
44177ceb68eSShannon Nelson 	if (lif->notifyqcq) {
44277ceb68eSShannon Nelson 		ionic_qcq_free(lif, lif->notifyqcq);
443101b40a0SShannon Nelson 		devm_kfree(dev, lif->notifyqcq);
44477ceb68eSShannon Nelson 		lif->notifyqcq = NULL;
44577ceb68eSShannon Nelson 	}
44677ceb68eSShannon Nelson 
4471d062b7bSShannon Nelson 	if (lif->adminqcq) {
448e768929dSShannon Nelson 		spin_lock_irqsave(&lif->adminq_lock, irqflags);
449e768929dSShannon Nelson 		adminqcq = READ_ONCE(lif->adminqcq);
4501d062b7bSShannon Nelson 		lif->adminqcq = NULL;
451e768929dSShannon Nelson 		spin_unlock_irqrestore(&lif->adminq_lock, irqflags);
452e768929dSShannon Nelson 		if (adminqcq) {
453e768929dSShannon Nelson 			ionic_qcq_free(lif, adminqcq);
454e768929dSShannon Nelson 			devm_kfree(dev, adminqcq);
455e768929dSShannon Nelson 		}
4561d062b7bSShannon Nelson 	}
4570f3154e6SShannon Nelson 
458a4674f34SShannon Nelson 	if (lif->rxqcqs) {
45934dec947SShannon Nelson 		devm_kfree(dev, lif->rxqstats);
46034dec947SShannon Nelson 		lif->rxqstats = NULL;
4610f3154e6SShannon Nelson 		devm_kfree(dev, lif->rxqcqs);
4620f3154e6SShannon Nelson 		lif->rxqcqs = NULL;
463a4674f34SShannon Nelson 	}
4640f3154e6SShannon Nelson 
465a4674f34SShannon Nelson 	if (lif->txqcqs) {
46634dec947SShannon Nelson 		devm_kfree(dev, lif->txqstats);
46734dec947SShannon Nelson 		lif->txqstats = NULL;
4680f3154e6SShannon Nelson 		devm_kfree(dev, lif->txqcqs);
4690f3154e6SShannon Nelson 		lif->txqcqs = NULL;
4701d062b7bSShannon Nelson 	}
471a4674f34SShannon Nelson }
4721d062b7bSShannon Nelson 
ionic_link_qcq_interrupts(struct ionic_qcq * src_qcq,struct ionic_qcq * n_qcq)47377ceb68eSShannon Nelson static void ionic_link_qcq_interrupts(struct ionic_qcq *src_qcq,
47477ceb68eSShannon Nelson 				      struct ionic_qcq *n_qcq)
47577ceb68eSShannon Nelson {
47677ceb68eSShannon Nelson 	n_qcq->intr.vector = src_qcq->intr.vector;
47777ceb68eSShannon Nelson 	n_qcq->intr.index = src_qcq->intr.index;
478b69585bfSAllen Hubbe 	n_qcq->napi_qcq = src_qcq->napi_qcq;
47977ceb68eSShannon Nelson }
48077ceb68eSShannon Nelson 
ionic_alloc_qcq_interrupt(struct ionic_lif * lif,struct ionic_qcq * qcq)481101b40a0SShannon Nelson static int ionic_alloc_qcq_interrupt(struct ionic_lif *lif, struct ionic_qcq *qcq)
482101b40a0SShannon Nelson {
483101b40a0SShannon Nelson 	int err;
484101b40a0SShannon Nelson 
485101b40a0SShannon Nelson 	if (!(qcq->flags & IONIC_QCQ_F_INTR)) {
486101b40a0SShannon Nelson 		qcq->intr.index = IONIC_INTR_INDEX_NOT_ASSIGNED;
487101b40a0SShannon Nelson 		return 0;
488101b40a0SShannon Nelson 	}
489101b40a0SShannon Nelson 
490101b40a0SShannon Nelson 	err = ionic_intr_alloc(lif, &qcq->intr);
491101b40a0SShannon Nelson 	if (err) {
492101b40a0SShannon Nelson 		netdev_warn(lif->netdev, "no intr for %s: %d\n",
493101b40a0SShannon Nelson 			    qcq->q.name, err);
494101b40a0SShannon Nelson 		goto err_out;
495101b40a0SShannon Nelson 	}
496101b40a0SShannon Nelson 
497101b40a0SShannon Nelson 	err = ionic_bus_get_irq(lif->ionic, qcq->intr.index);
498101b40a0SShannon Nelson 	if (err < 0) {
499101b40a0SShannon Nelson 		netdev_warn(lif->netdev, "no vector for %s: %d\n",
500101b40a0SShannon Nelson 			    qcq->q.name, err);
501101b40a0SShannon Nelson 		goto err_out_free_intr;
502101b40a0SShannon Nelson 	}
503101b40a0SShannon Nelson 	qcq->intr.vector = err;
504101b40a0SShannon Nelson 	ionic_intr_mask_assert(lif->ionic->idev.intr_ctrl, qcq->intr.index,
505101b40a0SShannon Nelson 			       IONIC_INTR_MASK_SET);
506101b40a0SShannon Nelson 
507101b40a0SShannon Nelson 	err = ionic_request_irq(lif, qcq);
508101b40a0SShannon Nelson 	if (err) {
509101b40a0SShannon Nelson 		netdev_warn(lif->netdev, "irq request failed %d\n", err);
510101b40a0SShannon Nelson 		goto err_out_free_intr;
511101b40a0SShannon Nelson 	}
512101b40a0SShannon Nelson 
513101b40a0SShannon Nelson 	/* try to get the irq on the local numa node first */
514101b40a0SShannon Nelson 	qcq->intr.cpu = cpumask_local_spread(qcq->intr.index,
515101b40a0SShannon Nelson 					     dev_to_node(lif->ionic->dev));
516101b40a0SShannon Nelson 	if (qcq->intr.cpu != -1)
517101b40a0SShannon Nelson 		cpumask_set_cpu(qcq->intr.cpu, &qcq->intr.affinity_mask);
518101b40a0SShannon Nelson 
519101b40a0SShannon Nelson 	netdev_dbg(lif->netdev, "%s: Interrupt index %d\n", qcq->q.name, qcq->intr.index);
520101b40a0SShannon Nelson 	return 0;
521101b40a0SShannon Nelson 
522101b40a0SShannon Nelson err_out_free_intr:
523101b40a0SShannon Nelson 	ionic_intr_free(lif->ionic, qcq->intr.index);
524101b40a0SShannon Nelson err_out:
525101b40a0SShannon Nelson 	return err;
526101b40a0SShannon Nelson }
527101b40a0SShannon Nelson 
ionic_qcq_alloc(struct ionic_lif * lif,unsigned int type,unsigned int index,const char * name,unsigned int flags,unsigned int num_descs,unsigned int desc_size,unsigned int cq_desc_size,unsigned int sg_desc_size,unsigned int pid,struct ionic_qcq ** qcq)5281d062b7bSShannon Nelson static int ionic_qcq_alloc(struct ionic_lif *lif, unsigned int type,
5291d062b7bSShannon Nelson 			   unsigned int index,
5301d062b7bSShannon Nelson 			   const char *name, unsigned int flags,
5311d062b7bSShannon Nelson 			   unsigned int num_descs, unsigned int desc_size,
5321d062b7bSShannon Nelson 			   unsigned int cq_desc_size,
5331d062b7bSShannon Nelson 			   unsigned int sg_desc_size,
5341d062b7bSShannon Nelson 			   unsigned int pid, struct ionic_qcq **qcq)
5351d062b7bSShannon Nelson {
5361d062b7bSShannon Nelson 	struct ionic_dev *idev = &lif->ionic->idev;
5371d062b7bSShannon Nelson 	struct device *dev = lif->ionic->dev;
5381d062b7bSShannon Nelson 	void *q_base, *cq_base, *sg_base;
5391d062b7bSShannon Nelson 	dma_addr_t cq_base_pa = 0;
5401d062b7bSShannon Nelson 	dma_addr_t sg_base_pa = 0;
5411d062b7bSShannon Nelson 	dma_addr_t q_base_pa = 0;
5421d062b7bSShannon Nelson 	struct ionic_qcq *new;
5431d062b7bSShannon Nelson 	int err;
5441d062b7bSShannon Nelson 
5451d062b7bSShannon Nelson 	*qcq = NULL;
5461d062b7bSShannon Nelson 
5471d062b7bSShannon Nelson 	new = devm_kzalloc(dev, sizeof(*new), GFP_KERNEL);
5481d062b7bSShannon Nelson 	if (!new) {
5491d062b7bSShannon Nelson 		netdev_err(lif->netdev, "Cannot allocate queue structure\n");
5501d062b7bSShannon Nelson 		err = -ENOMEM;
5511d062b7bSShannon Nelson 		goto err_out;
5521d062b7bSShannon Nelson 	}
5531d062b7bSShannon Nelson 
554f37bc346SShannon Nelson 	new->q.dev = dev;
5551d062b7bSShannon Nelson 	new->flags = flags;
5561d062b7bSShannon Nelson 
557f712c829SJulia Lawall 	new->q.info = vcalloc(num_descs, sizeof(*new->q.info));
5581d062b7bSShannon Nelson 	if (!new->q.info) {
5591d062b7bSShannon Nelson 		netdev_err(lif->netdev, "Cannot allocate queue info\n");
5601d062b7bSShannon Nelson 		err = -ENOMEM;
561ea5a8b09SShannon Nelson 		goto err_out_free_qcq;
5621d062b7bSShannon Nelson 	}
5631d062b7bSShannon Nelson 
5641d062b7bSShannon Nelson 	new->q.type = type;
565f37bc346SShannon Nelson 	new->q.max_sg_elems = lif->qtype_info[type].max_sg_elems;
5661d062b7bSShannon Nelson 
5671d062b7bSShannon Nelson 	err = ionic_q_init(lif, idev, &new->q, index, name, num_descs,
5681d062b7bSShannon Nelson 			   desc_size, sg_desc_size, pid);
5691d062b7bSShannon Nelson 	if (err) {
5701d062b7bSShannon Nelson 		netdev_err(lif->netdev, "Cannot initialize queue\n");
571ea5a8b09SShannon Nelson 		goto err_out_free_q_info;
5721d062b7bSShannon Nelson 	}
5731d062b7bSShannon Nelson 
574101b40a0SShannon Nelson 	err = ionic_alloc_qcq_interrupt(lif, new);
575101b40a0SShannon Nelson 	if (err)
5761d062b7bSShannon Nelson 		goto err_out;
5771d062b7bSShannon Nelson 
578f712c829SJulia Lawall 	new->cq.info = vcalloc(num_descs, sizeof(*new->cq.info));
5791d062b7bSShannon Nelson 	if (!new->cq.info) {
5801d062b7bSShannon Nelson 		netdev_err(lif->netdev, "Cannot allocate completion queue info\n");
5811d062b7bSShannon Nelson 		err = -ENOMEM;
5820b064100SShannon Nelson 		goto err_out_free_irq;
5831d062b7bSShannon Nelson 	}
5841d062b7bSShannon Nelson 
5851d062b7bSShannon Nelson 	err = ionic_cq_init(lif, &new->cq, &new->intr, num_descs, cq_desc_size);
5861d062b7bSShannon Nelson 	if (err) {
5871d062b7bSShannon Nelson 		netdev_err(lif->netdev, "Cannot initialize completion queue\n");
588ea5a8b09SShannon Nelson 		goto err_out_free_cq_info;
5891d062b7bSShannon Nelson 	}
5901d062b7bSShannon Nelson 
5919576a36cSShannon Nelson 	if (flags & IONIC_QCQ_F_NOTIFYQ) {
5921fffb025SShannon Nelson 		int q_size;
5939576a36cSShannon Nelson 
5941fffb025SShannon Nelson 		/* q & cq need to be contiguous in NotifyQ, so alloc it all in q
5951fffb025SShannon Nelson 		 * and don't alloc qc.  We leave new->qc_size and new->qc_base
5961fffb025SShannon Nelson 		 * as 0 to be sure we don't try to free it later.
5971fffb025SShannon Nelson 		 */
5989576a36cSShannon Nelson 		q_size = ALIGN(num_descs * desc_size, PAGE_SIZE);
5991fffb025SShannon Nelson 		new->q_size = PAGE_SIZE + q_size +
6001fffb025SShannon Nelson 			      ALIGN(num_descs * cq_desc_size, PAGE_SIZE);
6019576a36cSShannon Nelson 		new->q_base = dma_alloc_coherent(dev, new->q_size,
6029576a36cSShannon Nelson 						 &new->q_base_pa, GFP_KERNEL);
6039576a36cSShannon Nelson 		if (!new->q_base) {
6049576a36cSShannon Nelson 			netdev_err(lif->netdev, "Cannot allocate qcq DMA memory\n");
6059576a36cSShannon Nelson 			err = -ENOMEM;
6069576a36cSShannon Nelson 			goto err_out_free_cq_info;
6079576a36cSShannon Nelson 		}
6089576a36cSShannon Nelson 		q_base = PTR_ALIGN(new->q_base, PAGE_SIZE);
6099576a36cSShannon Nelson 		q_base_pa = ALIGN(new->q_base_pa, PAGE_SIZE);
6109576a36cSShannon Nelson 		ionic_q_map(&new->q, q_base, q_base_pa);
6119576a36cSShannon Nelson 
6129576a36cSShannon Nelson 		cq_base = PTR_ALIGN(q_base + q_size, PAGE_SIZE);
6139576a36cSShannon Nelson 		cq_base_pa = ALIGN(new->q_base_pa + q_size, PAGE_SIZE);
6149576a36cSShannon Nelson 		ionic_cq_map(&new->cq, cq_base, cq_base_pa);
6159576a36cSShannon Nelson 		ionic_cq_bind(&new->cq, &new->q);
6169576a36cSShannon Nelson 	} else {
61740bc471dSShannon Nelson 		/* regular DMA q descriptors */
618ea5a8b09SShannon Nelson 		new->q_size = PAGE_SIZE + (num_descs * desc_size);
619ea5a8b09SShannon Nelson 		new->q_base = dma_alloc_coherent(dev, new->q_size, &new->q_base_pa,
6201d062b7bSShannon Nelson 						 GFP_KERNEL);
621ea5a8b09SShannon Nelson 		if (!new->q_base) {
6221d062b7bSShannon Nelson 			netdev_err(lif->netdev, "Cannot allocate queue DMA memory\n");
6231d062b7bSShannon Nelson 			err = -ENOMEM;
624ea5a8b09SShannon Nelson 			goto err_out_free_cq_info;
6251d062b7bSShannon Nelson 		}
626ea5a8b09SShannon Nelson 		q_base = PTR_ALIGN(new->q_base, PAGE_SIZE);
627ea5a8b09SShannon Nelson 		q_base_pa = ALIGN(new->q_base_pa, PAGE_SIZE);
6281d062b7bSShannon Nelson 		ionic_q_map(&new->q, q_base, q_base_pa);
629ea5a8b09SShannon Nelson 
63040bc471dSShannon Nelson 		if (flags & IONIC_QCQ_F_CMB_RINGS) {
63140bc471dSShannon Nelson 			/* on-chip CMB q descriptors */
63240bc471dSShannon Nelson 			new->cmb_q_size = num_descs * desc_size;
63340bc471dSShannon Nelson 			new->cmb_order = order_base_2(new->cmb_q_size / PAGE_SIZE);
63440bc471dSShannon Nelson 
63540bc471dSShannon Nelson 			err = ionic_get_cmb(lif, &new->cmb_pgid, &new->cmb_q_base_pa,
63640bc471dSShannon Nelson 					    new->cmb_order);
63740bc471dSShannon Nelson 			if (err) {
63840bc471dSShannon Nelson 				netdev_err(lif->netdev,
63940bc471dSShannon Nelson 					   "Cannot allocate queue order %d from cmb: err %d\n",
64040bc471dSShannon Nelson 					   new->cmb_order, err);
64140bc471dSShannon Nelson 				goto err_out_free_q;
64240bc471dSShannon Nelson 			}
64340bc471dSShannon Nelson 
64440bc471dSShannon Nelson 			new->cmb_q_base = ioremap_wc(new->cmb_q_base_pa, new->cmb_q_size);
64540bc471dSShannon Nelson 			if (!new->cmb_q_base) {
64640bc471dSShannon Nelson 				netdev_err(lif->netdev, "Cannot map queue from cmb\n");
64740bc471dSShannon Nelson 				ionic_put_cmb(lif, new->cmb_pgid, new->cmb_order);
64840bc471dSShannon Nelson 				err = -ENOMEM;
64940bc471dSShannon Nelson 				goto err_out_free_q;
65040bc471dSShannon Nelson 			}
65140bc471dSShannon Nelson 
65240bc471dSShannon Nelson 			new->cmb_q_base_pa -= idev->phy_cmb_pages;
65340bc471dSShannon Nelson 			ionic_q_cmb_map(&new->q, new->cmb_q_base, new->cmb_q_base_pa);
65440bc471dSShannon Nelson 		}
65540bc471dSShannon Nelson 
65640bc471dSShannon Nelson 		/* cq DMA descriptors */
657ea5a8b09SShannon Nelson 		new->cq_size = PAGE_SIZE + (num_descs * cq_desc_size);
658ea5a8b09SShannon Nelson 		new->cq_base = dma_alloc_coherent(dev, new->cq_size, &new->cq_base_pa,
659ea5a8b09SShannon Nelson 						  GFP_KERNEL);
660ea5a8b09SShannon Nelson 		if (!new->cq_base) {
661ea5a8b09SShannon Nelson 			netdev_err(lif->netdev, "Cannot allocate cq DMA memory\n");
662ea5a8b09SShannon Nelson 			err = -ENOMEM;
663ea5a8b09SShannon Nelson 			goto err_out_free_q;
664ea5a8b09SShannon Nelson 		}
665ea5a8b09SShannon Nelson 		cq_base = PTR_ALIGN(new->cq_base, PAGE_SIZE);
666ea5a8b09SShannon Nelson 		cq_base_pa = ALIGN(new->cq_base_pa, PAGE_SIZE);
6671d062b7bSShannon Nelson 		ionic_cq_map(&new->cq, cq_base, cq_base_pa);
6681d062b7bSShannon Nelson 		ionic_cq_bind(&new->cq, &new->q);
6699576a36cSShannon Nelson 	}
6701d062b7bSShannon Nelson 
671ea5a8b09SShannon Nelson 	if (flags & IONIC_QCQ_F_SG) {
672ea5a8b09SShannon Nelson 		new->sg_size = PAGE_SIZE + (num_descs * sg_desc_size);
673ea5a8b09SShannon Nelson 		new->sg_base = dma_alloc_coherent(dev, new->sg_size, &new->sg_base_pa,
674ea5a8b09SShannon Nelson 						  GFP_KERNEL);
675ea5a8b09SShannon Nelson 		if (!new->sg_base) {
676ea5a8b09SShannon Nelson 			netdev_err(lif->netdev, "Cannot allocate sg DMA memory\n");
677ea5a8b09SShannon Nelson 			err = -ENOMEM;
678ea5a8b09SShannon Nelson 			goto err_out_free_cq;
679ea5a8b09SShannon Nelson 		}
680ea5a8b09SShannon Nelson 		sg_base = PTR_ALIGN(new->sg_base, PAGE_SIZE);
681ea5a8b09SShannon Nelson 		sg_base_pa = ALIGN(new->sg_base_pa, PAGE_SIZE);
682ea5a8b09SShannon Nelson 		ionic_q_sg_map(&new->q, sg_base, sg_base_pa);
683ea5a8b09SShannon Nelson 	}
684ea5a8b09SShannon Nelson 
68504a83459SShannon Nelson 	INIT_WORK(&new->dim.work, ionic_dim_work);
68604a83459SShannon Nelson 	new->dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE;
68704a83459SShannon Nelson 
6881d062b7bSShannon Nelson 	*qcq = new;
6891d062b7bSShannon Nelson 
6901d062b7bSShannon Nelson 	return 0;
6911d062b7bSShannon Nelson 
692ea5a8b09SShannon Nelson err_out_free_cq:
693ea5a8b09SShannon Nelson 	dma_free_coherent(dev, new->cq_size, new->cq_base, new->cq_base_pa);
694ea5a8b09SShannon Nelson err_out_free_q:
69540bc471dSShannon Nelson 	if (new->cmb_q_base) {
69640bc471dSShannon Nelson 		iounmap(new->cmb_q_base);
69740bc471dSShannon Nelson 		ionic_put_cmb(lif, new->cmb_pgid, new->cmb_order);
69840bc471dSShannon Nelson 	}
699ea5a8b09SShannon Nelson 	dma_free_coherent(dev, new->q_size, new->q_base, new->q_base_pa);
700ea5a8b09SShannon Nelson err_out_free_cq_info:
701116dce0fSBrett Creeley 	vfree(new->cq.info);
7020b064100SShannon Nelson err_out_free_irq:
703101b40a0SShannon Nelson 	if (flags & IONIC_QCQ_F_INTR) {
7040b064100SShannon Nelson 		devm_free_irq(dev, new->intr.vector, &new->napi);
70536ac2c50SShannon Nelson 		ionic_intr_free(lif->ionic, new->intr.index);
706101b40a0SShannon Nelson 	}
707ea5a8b09SShannon Nelson err_out_free_q_info:
708116dce0fSBrett Creeley 	vfree(new->q.info);
709ea5a8b09SShannon Nelson err_out_free_qcq:
710ea5a8b09SShannon Nelson 	devm_kfree(dev, new);
7111d062b7bSShannon Nelson err_out:
7121d062b7bSShannon Nelson 	dev_err(dev, "qcq alloc of %s%d failed %d\n", name, index, err);
7131d062b7bSShannon Nelson 	return err;
7141d062b7bSShannon Nelson }
7151d062b7bSShannon Nelson 
ionic_qcqs_alloc(struct ionic_lif * lif)7161d062b7bSShannon Nelson static int ionic_qcqs_alloc(struct ionic_lif *lif)
7171d062b7bSShannon Nelson {
7180f3154e6SShannon Nelson 	struct device *dev = lif->ionic->dev;
7191d062b7bSShannon Nelson 	unsigned int flags;
7201d062b7bSShannon Nelson 	int err;
7211d062b7bSShannon Nelson 
7221d062b7bSShannon Nelson 	flags = IONIC_QCQ_F_INTR;
7231d062b7bSShannon Nelson 	err = ionic_qcq_alloc(lif, IONIC_QTYPE_ADMINQ, 0, "admin", flags,
7241d062b7bSShannon Nelson 			      IONIC_ADMINQ_LENGTH,
7251d062b7bSShannon Nelson 			      sizeof(struct ionic_admin_cmd),
7261d062b7bSShannon Nelson 			      sizeof(struct ionic_admin_comp),
7271d062b7bSShannon Nelson 			      0, lif->kern_pid, &lif->adminqcq);
7281d062b7bSShannon Nelson 	if (err)
7291d062b7bSShannon Nelson 		return err;
7302a8c2c1aSShannon Nelson 	ionic_debugfs_add_qcq(lif, lif->adminqcq);
7311d062b7bSShannon Nelson 
73277ceb68eSShannon Nelson 	if (lif->ionic->nnqs_per_lif) {
73377ceb68eSShannon Nelson 		flags = IONIC_QCQ_F_NOTIFYQ;
73477ceb68eSShannon Nelson 		err = ionic_qcq_alloc(lif, IONIC_QTYPE_NOTIFYQ, 0, "notifyq",
73577ceb68eSShannon Nelson 				      flags, IONIC_NOTIFYQ_LENGTH,
73677ceb68eSShannon Nelson 				      sizeof(struct ionic_notifyq_cmd),
73777ceb68eSShannon Nelson 				      sizeof(union ionic_notifyq_comp),
73877ceb68eSShannon Nelson 				      0, lif->kern_pid, &lif->notifyqcq);
73977ceb68eSShannon Nelson 		if (err)
74034dec947SShannon Nelson 			goto err_out;
7412a8c2c1aSShannon Nelson 		ionic_debugfs_add_qcq(lif, lif->notifyqcq);
74277ceb68eSShannon Nelson 
74377ceb68eSShannon Nelson 		/* Let the notifyq ride on the adminq interrupt */
74477ceb68eSShannon Nelson 		ionic_link_qcq_interrupts(lif->adminqcq, lif->notifyqcq);
74577ceb68eSShannon Nelson 	}
74677ceb68eSShannon Nelson 
7470f3154e6SShannon Nelson 	err = -ENOMEM;
748ee205626SShannon Nelson 	lif->txqcqs = devm_kcalloc(dev, lif->ionic->ntxqs_per_lif,
749230efff4SShannon Nelson 				   sizeof(*lif->txqcqs), GFP_KERNEL);
7500f3154e6SShannon Nelson 	if (!lif->txqcqs)
75134dec947SShannon Nelson 		goto err_out;
752ee205626SShannon Nelson 	lif->rxqcqs = devm_kcalloc(dev, lif->ionic->nrxqs_per_lif,
753230efff4SShannon Nelson 				   sizeof(*lif->rxqcqs), GFP_KERNEL);
7540f3154e6SShannon Nelson 	if (!lif->rxqcqs)
75534dec947SShannon Nelson 		goto err_out;
75634dec947SShannon Nelson 
757f0790bcdSShannon Nelson 	lif->txqstats = devm_kcalloc(dev, lif->ionic->ntxqs_per_lif + 1,
758230efff4SShannon Nelson 				     sizeof(*lif->txqstats), GFP_KERNEL);
75934dec947SShannon Nelson 	if (!lif->txqstats)
76034dec947SShannon Nelson 		goto err_out;
761f0790bcdSShannon Nelson 	lif->rxqstats = devm_kcalloc(dev, lif->ionic->nrxqs_per_lif + 1,
762230efff4SShannon Nelson 				     sizeof(*lif->rxqstats), GFP_KERNEL);
76334dec947SShannon Nelson 	if (!lif->rxqstats)
76434dec947SShannon Nelson 		goto err_out;
7650f3154e6SShannon Nelson 
7661d062b7bSShannon Nelson 	return 0;
76777ceb68eSShannon Nelson 
76834dec947SShannon Nelson err_out:
76934dec947SShannon Nelson 	ionic_qcqs_free(lif);
77077ceb68eSShannon Nelson 	return err;
77177ceb68eSShannon Nelson }
77277ceb68eSShannon Nelson 
ionic_qcq_sanitize(struct ionic_qcq * qcq)773f053e1f8SShannon Nelson static void ionic_qcq_sanitize(struct ionic_qcq *qcq)
774f053e1f8SShannon Nelson {
775f053e1f8SShannon Nelson 	qcq->q.tail_idx = 0;
776f053e1f8SShannon Nelson 	qcq->q.head_idx = 0;
777f053e1f8SShannon Nelson 	qcq->cq.tail_idx = 0;
778f053e1f8SShannon Nelson 	qcq->cq.done_color = 1;
779f053e1f8SShannon Nelson 	memset(qcq->q_base, 0, qcq->q_size);
78040bc471dSShannon Nelson 	if (qcq->cmb_q_base)
78140bc471dSShannon Nelson 		memset_io(qcq->cmb_q_base, 0, qcq->cmb_q_size);
782f053e1f8SShannon Nelson 	memset(qcq->cq_base, 0, qcq->cq_size);
783f053e1f8SShannon Nelson 	memset(qcq->sg_base, 0, qcq->sg_size);
784f053e1f8SShannon Nelson }
785f053e1f8SShannon Nelson 
ionic_lif_txq_init(struct ionic_lif * lif,struct ionic_qcq * qcq)7860f3154e6SShannon Nelson static int ionic_lif_txq_init(struct ionic_lif *lif, struct ionic_qcq *qcq)
7870f3154e6SShannon Nelson {
7880f3154e6SShannon Nelson 	struct device *dev = lif->ionic->dev;
7890f3154e6SShannon Nelson 	struct ionic_queue *q = &qcq->q;
7900f3154e6SShannon Nelson 	struct ionic_cq *cq = &qcq->cq;
7910f3154e6SShannon Nelson 	struct ionic_admin_ctx ctx = {
7920f3154e6SShannon Nelson 		.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
7930f3154e6SShannon Nelson 		.cmd.q_init = {
7940f3154e6SShannon Nelson 			.opcode = IONIC_CMD_Q_INIT,
7950f3154e6SShannon Nelson 			.lif_index = cpu_to_le16(lif->index),
7960f3154e6SShannon Nelson 			.type = q->type,
7975b3f3f2aSShannon Nelson 			.ver = lif->qtype_info[q->type].version,
7980f3154e6SShannon Nelson 			.index = cpu_to_le32(q->index),
7990f3154e6SShannon Nelson 			.flags = cpu_to_le16(IONIC_QINIT_F_IRQ |
8000f3154e6SShannon Nelson 					     IONIC_QINIT_F_SG),
80140bc471dSShannon Nelson 			.intr_index = cpu_to_le16(qcq->intr.index),
8020f3154e6SShannon Nelson 			.pid = cpu_to_le16(q->pid),
8030f3154e6SShannon Nelson 			.ring_size = ilog2(q->num_descs),
8040f3154e6SShannon Nelson 			.ring_base = cpu_to_le64(q->base_pa),
8050f3154e6SShannon Nelson 			.cq_ring_base = cpu_to_le64(cq->base_pa),
8060f3154e6SShannon Nelson 			.sg_ring_base = cpu_to_le64(q->sg_base_pa),
80757a3a98dSShannon Nelson 			.features = cpu_to_le64(q->features),
8080f3154e6SShannon Nelson 		},
8090f3154e6SShannon Nelson 	};
8100f3154e6SShannon Nelson 	int err;
8110f3154e6SShannon Nelson 
81240bc471dSShannon Nelson 	if (qcq->flags & IONIC_QCQ_F_CMB_RINGS) {
81340bc471dSShannon Nelson 		ctx.cmd.q_init.flags |= cpu_to_le16(IONIC_QINIT_F_CMB);
81440bc471dSShannon Nelson 		ctx.cmd.q_init.ring_base = cpu_to_le64(qcq->cmb_q_base_pa);
81540bc471dSShannon Nelson 	}
816fe8c30b5SShannon Nelson 
8170f3154e6SShannon Nelson 	dev_dbg(dev, "txq_init.pid %d\n", ctx.cmd.q_init.pid);
8180f3154e6SShannon Nelson 	dev_dbg(dev, "txq_init.index %d\n", ctx.cmd.q_init.index);
8190f3154e6SShannon Nelson 	dev_dbg(dev, "txq_init.ring_base 0x%llx\n", ctx.cmd.q_init.ring_base);
8200f3154e6SShannon Nelson 	dev_dbg(dev, "txq_init.ring_size %d\n", ctx.cmd.q_init.ring_size);
82140bc471dSShannon Nelson 	dev_dbg(dev, "txq_init.cq_ring_base 0x%llx\n", ctx.cmd.q_init.cq_ring_base);
82240bc471dSShannon Nelson 	dev_dbg(dev, "txq_init.sg_ring_base 0x%llx\n", ctx.cmd.q_init.sg_ring_base);
8235b3f3f2aSShannon Nelson 	dev_dbg(dev, "txq_init.flags 0x%x\n", ctx.cmd.q_init.flags);
8245b3f3f2aSShannon Nelson 	dev_dbg(dev, "txq_init.ver %d\n", ctx.cmd.q_init.ver);
825fe8c30b5SShannon Nelson 	dev_dbg(dev, "txq_init.intr_index %d\n", ctx.cmd.q_init.intr_index);
8260f3154e6SShannon Nelson 
827f053e1f8SShannon Nelson 	ionic_qcq_sanitize(qcq);
82849d3b493SShannon Nelson 
8290f3154e6SShannon Nelson 	err = ionic_adminq_post_wait(lif, &ctx);
8300f3154e6SShannon Nelson 	if (err)
8310f3154e6SShannon Nelson 		return err;
8320f3154e6SShannon Nelson 
8330f3154e6SShannon Nelson 	q->hw_type = ctx.comp.q_init.hw_type;
8340f3154e6SShannon Nelson 	q->hw_index = le32_to_cpu(ctx.comp.q_init.hw_index);
8350f3154e6SShannon Nelson 	q->dbval = IONIC_DBELL_QID(q->hw_index);
8360f3154e6SShannon Nelson 
8370f3154e6SShannon Nelson 	dev_dbg(dev, "txq->hw_type %d\n", q->hw_type);
8380f3154e6SShannon Nelson 	dev_dbg(dev, "txq->hw_index %d\n", q->hw_index);
8390f3154e6SShannon Nelson 
840b69585bfSAllen Hubbe 	q->dbell_deadline = IONIC_TX_DOORBELL_DEADLINE;
841b69585bfSAllen Hubbe 	q->dbell_jiffies = jiffies;
842b69585bfSAllen Hubbe 
843b69585bfSAllen Hubbe 	if (test_bit(IONIC_LIF_F_SPLIT_INTR, lif->state)) {
844b48b89f9SJakub Kicinski 		netif_napi_add(lif->netdev, &qcq->napi, ionic_tx_napi);
845b69585bfSAllen Hubbe 		qcq->napi_qcq = qcq;
846b69585bfSAllen Hubbe 		timer_setup(&qcq->napi_deadline, ionic_napi_deadline, 0);
847b69585bfSAllen Hubbe 	}
848fe8c30b5SShannon Nelson 
8490f3154e6SShannon Nelson 	qcq->flags |= IONIC_QCQ_F_INITED;
8500f3154e6SShannon Nelson 
8510f3154e6SShannon Nelson 	return 0;
8520f3154e6SShannon Nelson }
8530f3154e6SShannon Nelson 
ionic_lif_rxq_init(struct ionic_lif * lif,struct ionic_qcq * qcq)8540f3154e6SShannon Nelson static int ionic_lif_rxq_init(struct ionic_lif *lif, struct ionic_qcq *qcq)
8550f3154e6SShannon Nelson {
8560f3154e6SShannon Nelson 	struct device *dev = lif->ionic->dev;
8570f3154e6SShannon Nelson 	struct ionic_queue *q = &qcq->q;
8580f3154e6SShannon Nelson 	struct ionic_cq *cq = &qcq->cq;
8590f3154e6SShannon Nelson 	struct ionic_admin_ctx ctx = {
8600f3154e6SShannon Nelson 		.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
8610f3154e6SShannon Nelson 		.cmd.q_init = {
8620f3154e6SShannon Nelson 			.opcode = IONIC_CMD_Q_INIT,
8630f3154e6SShannon Nelson 			.lif_index = cpu_to_le16(lif->index),
8640f3154e6SShannon Nelson 			.type = q->type,
8655b3f3f2aSShannon Nelson 			.ver = lif->qtype_info[q->type].version,
8660f3154e6SShannon Nelson 			.index = cpu_to_le32(q->index),
86708f2e4b2SShannon Nelson 			.flags = cpu_to_le16(IONIC_QINIT_F_IRQ |
86808f2e4b2SShannon Nelson 					     IONIC_QINIT_F_SG),
8690f3154e6SShannon Nelson 			.intr_index = cpu_to_le16(cq->bound_intr->index),
8700f3154e6SShannon Nelson 			.pid = cpu_to_le16(q->pid),
8710f3154e6SShannon Nelson 			.ring_size = ilog2(q->num_descs),
8720f3154e6SShannon Nelson 			.ring_base = cpu_to_le64(q->base_pa),
8730f3154e6SShannon Nelson 			.cq_ring_base = cpu_to_le64(cq->base_pa),
87408f2e4b2SShannon Nelson 			.sg_ring_base = cpu_to_le64(q->sg_base_pa),
87557a3a98dSShannon Nelson 			.features = cpu_to_le64(q->features),
8760f3154e6SShannon Nelson 		},
8770f3154e6SShannon Nelson 	};
8780f3154e6SShannon Nelson 	int err;
8790f3154e6SShannon Nelson 
88040bc471dSShannon Nelson 	if (qcq->flags & IONIC_QCQ_F_CMB_RINGS) {
88140bc471dSShannon Nelson 		ctx.cmd.q_init.flags |= cpu_to_le16(IONIC_QINIT_F_CMB);
88240bc471dSShannon Nelson 		ctx.cmd.q_init.ring_base = cpu_to_le64(qcq->cmb_q_base_pa);
88340bc471dSShannon Nelson 	}
88440bc471dSShannon Nelson 
8850f3154e6SShannon Nelson 	dev_dbg(dev, "rxq_init.pid %d\n", ctx.cmd.q_init.pid);
8860f3154e6SShannon Nelson 	dev_dbg(dev, "rxq_init.index %d\n", ctx.cmd.q_init.index);
8870f3154e6SShannon Nelson 	dev_dbg(dev, "rxq_init.ring_base 0x%llx\n", ctx.cmd.q_init.ring_base);
8880f3154e6SShannon Nelson 	dev_dbg(dev, "rxq_init.ring_size %d\n", ctx.cmd.q_init.ring_size);
8895b3f3f2aSShannon Nelson 	dev_dbg(dev, "rxq_init.flags 0x%x\n", ctx.cmd.q_init.flags);
8905b3f3f2aSShannon Nelson 	dev_dbg(dev, "rxq_init.ver %d\n", ctx.cmd.q_init.ver);
891fe8c30b5SShannon Nelson 	dev_dbg(dev, "rxq_init.intr_index %d\n", ctx.cmd.q_init.intr_index);
8920f3154e6SShannon Nelson 
893f053e1f8SShannon Nelson 	ionic_qcq_sanitize(qcq);
89449d3b493SShannon Nelson 
8950f3154e6SShannon Nelson 	err = ionic_adminq_post_wait(lif, &ctx);
8960f3154e6SShannon Nelson 	if (err)
8970f3154e6SShannon Nelson 		return err;
8980f3154e6SShannon Nelson 
8990f3154e6SShannon Nelson 	q->hw_type = ctx.comp.q_init.hw_type;
9000f3154e6SShannon Nelson 	q->hw_index = le32_to_cpu(ctx.comp.q_init.hw_index);
9010f3154e6SShannon Nelson 	q->dbval = IONIC_DBELL_QID(q->hw_index);
9020f3154e6SShannon Nelson 
9030f3154e6SShannon Nelson 	dev_dbg(dev, "rxq->hw_type %d\n", q->hw_type);
9040f3154e6SShannon Nelson 	dev_dbg(dev, "rxq->hw_index %d\n", q->hw_index);
9050f3154e6SShannon Nelson 
906b69585bfSAllen Hubbe 	q->dbell_deadline = IONIC_RX_MIN_DOORBELL_DEADLINE;
907b69585bfSAllen Hubbe 	q->dbell_jiffies = jiffies;
908b69585bfSAllen Hubbe 
909fe8c30b5SShannon Nelson 	if (test_bit(IONIC_LIF_F_SPLIT_INTR, lif->state))
910b48b89f9SJakub Kicinski 		netif_napi_add(lif->netdev, &qcq->napi, ionic_rx_napi);
911fe8c30b5SShannon Nelson 	else
912b48b89f9SJakub Kicinski 		netif_napi_add(lif->netdev, &qcq->napi, ionic_txrx_napi);
9130f3154e6SShannon Nelson 
914b69585bfSAllen Hubbe 	qcq->napi_qcq = qcq;
915b69585bfSAllen Hubbe 	timer_setup(&qcq->napi_deadline, ionic_napi_deadline, 0);
916b69585bfSAllen Hubbe 
9170f3154e6SShannon Nelson 	qcq->flags |= IONIC_QCQ_F_INITED;
9180f3154e6SShannon Nelson 
9190f3154e6SShannon Nelson 	return 0;
9200f3154e6SShannon Nelson }
9210f3154e6SShannon Nelson 
ionic_lif_create_hwstamp_txq(struct ionic_lif * lif)92261db421dSShannon Nelson int ionic_lif_create_hwstamp_txq(struct ionic_lif *lif)
92361db421dSShannon Nelson {
924f0790bcdSShannon Nelson 	unsigned int num_desc, desc_sz, comp_sz, sg_desc_sz;
925f0790bcdSShannon Nelson 	unsigned int txq_i, flags;
926f0790bcdSShannon Nelson 	struct ionic_qcq *txq;
927f0790bcdSShannon Nelson 	u64 features;
928f0790bcdSShannon Nelson 	int err;
929f0790bcdSShannon Nelson 
930f0790bcdSShannon Nelson 	if (lif->hwstamp_txq)
9317ee99fc5SShannon Nelson 		return 0;
932f0790bcdSShannon Nelson 
933f0790bcdSShannon Nelson 	features = IONIC_Q_F_2X_CQ_DESC | IONIC_TXQ_F_HWSTAMP;
934f0790bcdSShannon Nelson 
935f0790bcdSShannon Nelson 	num_desc = IONIC_MIN_TXRX_DESC;
936f0790bcdSShannon Nelson 	desc_sz = sizeof(struct ionic_txq_desc);
937f0790bcdSShannon Nelson 	comp_sz = 2 * sizeof(struct ionic_txq_comp);
938f0790bcdSShannon Nelson 
939f0790bcdSShannon Nelson 	if (lif->qtype_info[IONIC_QTYPE_TXQ].version >= 1 &&
940f0790bcdSShannon Nelson 	    lif->qtype_info[IONIC_QTYPE_TXQ].sg_desc_sz == sizeof(struct ionic_txq_sg_desc_v1))
941f0790bcdSShannon Nelson 		sg_desc_sz = sizeof(struct ionic_txq_sg_desc_v1);
942f0790bcdSShannon Nelson 	else
943f0790bcdSShannon Nelson 		sg_desc_sz = sizeof(struct ionic_txq_sg_desc);
944f0790bcdSShannon Nelson 
945f0790bcdSShannon Nelson 	txq_i = lif->ionic->ntxqs_per_lif;
946f0790bcdSShannon Nelson 	flags = IONIC_QCQ_F_TX_STATS | IONIC_QCQ_F_SG;
947f0790bcdSShannon Nelson 
948f0790bcdSShannon Nelson 	err = ionic_qcq_alloc(lif, IONIC_QTYPE_TXQ, txq_i, "hwstamp_tx", flags,
949f0790bcdSShannon Nelson 			      num_desc, desc_sz, comp_sz, sg_desc_sz,
950f0790bcdSShannon Nelson 			      lif->kern_pid, &txq);
951f0790bcdSShannon Nelson 	if (err)
952f0790bcdSShannon Nelson 		goto err_qcq_alloc;
953f0790bcdSShannon Nelson 
954f0790bcdSShannon Nelson 	txq->q.features = features;
955f0790bcdSShannon Nelson 
956f0790bcdSShannon Nelson 	ionic_link_qcq_interrupts(lif->adminqcq, txq);
957f0790bcdSShannon Nelson 	ionic_debugfs_add_qcq(lif, txq);
958f0790bcdSShannon Nelson 
959f0790bcdSShannon Nelson 	lif->hwstamp_txq = txq;
960f0790bcdSShannon Nelson 
961f0790bcdSShannon Nelson 	if (netif_running(lif->netdev)) {
962f0790bcdSShannon Nelson 		err = ionic_lif_txq_init(lif, txq);
963f0790bcdSShannon Nelson 		if (err)
964f0790bcdSShannon Nelson 			goto err_qcq_init;
965f0790bcdSShannon Nelson 
966f0790bcdSShannon Nelson 		if (test_bit(IONIC_LIF_F_UP, lif->state)) {
967f0790bcdSShannon Nelson 			err = ionic_qcq_enable(txq);
968f0790bcdSShannon Nelson 			if (err)
969f0790bcdSShannon Nelson 				goto err_qcq_enable;
970f0790bcdSShannon Nelson 		}
971f0790bcdSShannon Nelson 	}
972f0790bcdSShannon Nelson 
97361db421dSShannon Nelson 	return 0;
974f0790bcdSShannon Nelson 
975f0790bcdSShannon Nelson err_qcq_enable:
976f0790bcdSShannon Nelson 	ionic_lif_qcq_deinit(lif, txq);
977f0790bcdSShannon Nelson err_qcq_init:
978f0790bcdSShannon Nelson 	lif->hwstamp_txq = NULL;
979f0790bcdSShannon Nelson 	ionic_debugfs_del_qcq(txq);
980f0790bcdSShannon Nelson 	ionic_qcq_free(lif, txq);
981f0790bcdSShannon Nelson 	devm_kfree(lif->ionic->dev, txq);
982f0790bcdSShannon Nelson err_qcq_alloc:
983f0790bcdSShannon Nelson 	return err;
98461db421dSShannon Nelson }
98561db421dSShannon Nelson 
ionic_lif_create_hwstamp_rxq(struct ionic_lif * lif)98661db421dSShannon Nelson int ionic_lif_create_hwstamp_rxq(struct ionic_lif *lif)
98761db421dSShannon Nelson {
988f0790bcdSShannon Nelson 	unsigned int num_desc, desc_sz, comp_sz, sg_desc_sz;
989f0790bcdSShannon Nelson 	unsigned int rxq_i, flags;
990f0790bcdSShannon Nelson 	struct ionic_qcq *rxq;
991f0790bcdSShannon Nelson 	u64 features;
992f0790bcdSShannon Nelson 	int err;
993f0790bcdSShannon Nelson 
994f0790bcdSShannon Nelson 	if (lif->hwstamp_rxq)
9957ee99fc5SShannon Nelson 		return 0;
996f0790bcdSShannon Nelson 
997f0790bcdSShannon Nelson 	features = IONIC_Q_F_2X_CQ_DESC | IONIC_RXQ_F_HWSTAMP;
998f0790bcdSShannon Nelson 
999f0790bcdSShannon Nelson 	num_desc = IONIC_MIN_TXRX_DESC;
1000f0790bcdSShannon Nelson 	desc_sz = sizeof(struct ionic_rxq_desc);
1001f0790bcdSShannon Nelson 	comp_sz = 2 * sizeof(struct ionic_rxq_comp);
1002f0790bcdSShannon Nelson 	sg_desc_sz = sizeof(struct ionic_rxq_sg_desc);
1003f0790bcdSShannon Nelson 
1004f0790bcdSShannon Nelson 	rxq_i = lif->ionic->nrxqs_per_lif;
1005f0790bcdSShannon Nelson 	flags = IONIC_QCQ_F_RX_STATS | IONIC_QCQ_F_SG;
1006f0790bcdSShannon Nelson 
1007f0790bcdSShannon Nelson 	err = ionic_qcq_alloc(lif, IONIC_QTYPE_RXQ, rxq_i, "hwstamp_rx", flags,
1008f0790bcdSShannon Nelson 			      num_desc, desc_sz, comp_sz, sg_desc_sz,
1009f0790bcdSShannon Nelson 			      lif->kern_pid, &rxq);
1010f0790bcdSShannon Nelson 	if (err)
1011f0790bcdSShannon Nelson 		goto err_qcq_alloc;
1012f0790bcdSShannon Nelson 
1013f0790bcdSShannon Nelson 	rxq->q.features = features;
1014f0790bcdSShannon Nelson 
1015f0790bcdSShannon Nelson 	ionic_link_qcq_interrupts(lif->adminqcq, rxq);
1016f0790bcdSShannon Nelson 	ionic_debugfs_add_qcq(lif, rxq);
1017f0790bcdSShannon Nelson 
1018f0790bcdSShannon Nelson 	lif->hwstamp_rxq = rxq;
1019f0790bcdSShannon Nelson 
1020f0790bcdSShannon Nelson 	if (netif_running(lif->netdev)) {
1021f0790bcdSShannon Nelson 		err = ionic_lif_rxq_init(lif, rxq);
1022f0790bcdSShannon Nelson 		if (err)
1023f0790bcdSShannon Nelson 			goto err_qcq_init;
1024f0790bcdSShannon Nelson 
1025f0790bcdSShannon Nelson 		if (test_bit(IONIC_LIF_F_UP, lif->state)) {
1026f0790bcdSShannon Nelson 			ionic_rx_fill(&rxq->q);
1027f0790bcdSShannon Nelson 			err = ionic_qcq_enable(rxq);
1028f0790bcdSShannon Nelson 			if (err)
1029f0790bcdSShannon Nelson 				goto err_qcq_enable;
1030f0790bcdSShannon Nelson 		}
1031f0790bcdSShannon Nelson 	}
1032f0790bcdSShannon Nelson 
103361db421dSShannon Nelson 	return 0;
1034f0790bcdSShannon Nelson 
1035f0790bcdSShannon Nelson err_qcq_enable:
1036f0790bcdSShannon Nelson 	ionic_lif_qcq_deinit(lif, rxq);
1037f0790bcdSShannon Nelson err_qcq_init:
1038f0790bcdSShannon Nelson 	lif->hwstamp_rxq = NULL;
1039f0790bcdSShannon Nelson 	ionic_debugfs_del_qcq(rxq);
1040f0790bcdSShannon Nelson 	ionic_qcq_free(lif, rxq);
1041f0790bcdSShannon Nelson 	devm_kfree(lif->ionic->dev, rxq);
1042f0790bcdSShannon Nelson err_qcq_alloc:
1043f0790bcdSShannon Nelson 	return err;
104461db421dSShannon Nelson }
104561db421dSShannon Nelson 
ionic_lif_config_hwstamp_rxq_all(struct ionic_lif * lif,bool rx_all)104661db421dSShannon Nelson int ionic_lif_config_hwstamp_rxq_all(struct ionic_lif *lif, bool rx_all)
104761db421dSShannon Nelson {
1048f0790bcdSShannon Nelson 	struct ionic_queue_params qparam;
1049f0790bcdSShannon Nelson 
1050f0790bcdSShannon Nelson 	ionic_init_queue_params(lif, &qparam);
1051f0790bcdSShannon Nelson 
1052f0790bcdSShannon Nelson 	if (rx_all)
1053f0790bcdSShannon Nelson 		qparam.rxq_features = IONIC_Q_F_2X_CQ_DESC | IONIC_RXQ_F_HWSTAMP;
1054f0790bcdSShannon Nelson 	else
1055f0790bcdSShannon Nelson 		qparam.rxq_features = 0;
1056f0790bcdSShannon Nelson 
1057f0790bcdSShannon Nelson 	/* if we're not running, just set the values and return */
1058f0790bcdSShannon Nelson 	if (!netif_running(lif->netdev)) {
1059f0790bcdSShannon Nelson 		lif->rxq_features = qparam.rxq_features;
106061db421dSShannon Nelson 		return 0;
106161db421dSShannon Nelson 	}
106261db421dSShannon Nelson 
1063f0790bcdSShannon Nelson 	return ionic_reconfigure_queues(lif, &qparam);
1064f0790bcdSShannon Nelson }
1065f0790bcdSShannon Nelson 
ionic_lif_set_hwstamp_txmode(struct ionic_lif * lif,u16 txstamp_mode)106661db421dSShannon Nelson int ionic_lif_set_hwstamp_txmode(struct ionic_lif *lif, u16 txstamp_mode)
106761db421dSShannon Nelson {
1068f0790bcdSShannon Nelson 	struct ionic_admin_ctx ctx = {
1069f0790bcdSShannon Nelson 		.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
1070f0790bcdSShannon Nelson 		.cmd.lif_setattr = {
1071f0790bcdSShannon Nelson 			.opcode = IONIC_CMD_LIF_SETATTR,
1072f0790bcdSShannon Nelson 			.index = cpu_to_le16(lif->index),
1073f0790bcdSShannon Nelson 			.attr = IONIC_LIF_ATTR_TXSTAMP,
1074f0790bcdSShannon Nelson 			.txstamp_mode = cpu_to_le16(txstamp_mode),
1075f0790bcdSShannon Nelson 		},
1076f0790bcdSShannon Nelson 	};
1077f0790bcdSShannon Nelson 
1078f0790bcdSShannon Nelson 	return ionic_adminq_post_wait(lif, &ctx);
1079f0790bcdSShannon Nelson }
1080f0790bcdSShannon Nelson 
ionic_lif_del_hwstamp_rxfilt(struct ionic_lif * lif)1081f0790bcdSShannon Nelson static void ionic_lif_del_hwstamp_rxfilt(struct ionic_lif *lif)
1082f0790bcdSShannon Nelson {
1083f0790bcdSShannon Nelson 	struct ionic_admin_ctx ctx = {
1084f0790bcdSShannon Nelson 		.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
1085f0790bcdSShannon Nelson 		.cmd.rx_filter_del = {
1086f0790bcdSShannon Nelson 			.opcode = IONIC_CMD_RX_FILTER_DEL,
1087f0790bcdSShannon Nelson 			.lif_index = cpu_to_le16(lif->index),
1088f0790bcdSShannon Nelson 		},
1089f0790bcdSShannon Nelson 	};
1090f0790bcdSShannon Nelson 	struct ionic_rx_filter *f;
1091f0790bcdSShannon Nelson 	u32 filter_id;
1092f0790bcdSShannon Nelson 	int err;
1093f0790bcdSShannon Nelson 
1094f0790bcdSShannon Nelson 	spin_lock_bh(&lif->rx_filters.lock);
1095f0790bcdSShannon Nelson 
1096f0790bcdSShannon Nelson 	f = ionic_rx_filter_rxsteer(lif);
1097f0790bcdSShannon Nelson 	if (!f) {
1098f0790bcdSShannon Nelson 		spin_unlock_bh(&lif->rx_filters.lock);
1099f0790bcdSShannon Nelson 		return;
1100f0790bcdSShannon Nelson 	}
1101f0790bcdSShannon Nelson 
1102f0790bcdSShannon Nelson 	filter_id = f->filter_id;
1103f0790bcdSShannon Nelson 	ionic_rx_filter_free(lif, f);
1104f0790bcdSShannon Nelson 
1105f0790bcdSShannon Nelson 	spin_unlock_bh(&lif->rx_filters.lock);
1106f0790bcdSShannon Nelson 
1107f0790bcdSShannon Nelson 	netdev_dbg(lif->netdev, "rx_filter del RXSTEER (id %d)\n", filter_id);
1108f0790bcdSShannon Nelson 
1109f0790bcdSShannon Nelson 	ctx.cmd.rx_filter_del.filter_id = cpu_to_le32(filter_id);
1110f0790bcdSShannon Nelson 
1111f0790bcdSShannon Nelson 	err = ionic_adminq_post_wait(lif, &ctx);
1112f0790bcdSShannon Nelson 	if (err && err != -EEXIST)
1113f0790bcdSShannon Nelson 		netdev_dbg(lif->netdev, "failed to delete rx_filter RXSTEER (id %d)\n", filter_id);
1114f0790bcdSShannon Nelson }
1115f0790bcdSShannon Nelson 
ionic_lif_add_hwstamp_rxfilt(struct ionic_lif * lif,u64 pkt_class)1116f0790bcdSShannon Nelson static int ionic_lif_add_hwstamp_rxfilt(struct ionic_lif *lif, u64 pkt_class)
1117f0790bcdSShannon Nelson {
1118f0790bcdSShannon Nelson 	struct ionic_admin_ctx ctx = {
1119f0790bcdSShannon Nelson 		.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
1120f0790bcdSShannon Nelson 		.cmd.rx_filter_add = {
1121f0790bcdSShannon Nelson 			.opcode = IONIC_CMD_RX_FILTER_ADD,
1122f0790bcdSShannon Nelson 			.lif_index = cpu_to_le16(lif->index),
1123f0790bcdSShannon Nelson 			.match = cpu_to_le16(IONIC_RX_FILTER_STEER_PKTCLASS),
1124f0790bcdSShannon Nelson 			.pkt_class = cpu_to_le64(pkt_class),
1125f0790bcdSShannon Nelson 		},
1126f0790bcdSShannon Nelson 	};
1127f0790bcdSShannon Nelson 	u8 qtype;
1128f0790bcdSShannon Nelson 	u32 qid;
1129f0790bcdSShannon Nelson 	int err;
1130f0790bcdSShannon Nelson 
1131f0790bcdSShannon Nelson 	if (!lif->hwstamp_rxq)
1132f0790bcdSShannon Nelson 		return -EINVAL;
1133f0790bcdSShannon Nelson 
1134f0790bcdSShannon Nelson 	qtype = lif->hwstamp_rxq->q.type;
1135f0790bcdSShannon Nelson 	ctx.cmd.rx_filter_add.qtype = qtype;
1136f0790bcdSShannon Nelson 
1137f0790bcdSShannon Nelson 	qid = lif->hwstamp_rxq->q.index;
1138f0790bcdSShannon Nelson 	ctx.cmd.rx_filter_add.qid = cpu_to_le32(qid);
1139f0790bcdSShannon Nelson 
1140f0790bcdSShannon Nelson 	netdev_dbg(lif->netdev, "rx_filter add RXSTEER\n");
1141f0790bcdSShannon Nelson 	err = ionic_adminq_post_wait(lif, &ctx);
1142f0790bcdSShannon Nelson 	if (err && err != -EEXIST)
1143f0790bcdSShannon Nelson 		return err;
1144f0790bcdSShannon Nelson 
1145969f8439SShannon Nelson 	spin_lock_bh(&lif->rx_filters.lock);
1146969f8439SShannon Nelson 	err = ionic_rx_filter_save(lif, 0, qid, 0, &ctx, IONIC_FILTER_STATE_SYNCED);
1147969f8439SShannon Nelson 	spin_unlock_bh(&lif->rx_filters.lock);
1148969f8439SShannon Nelson 
1149969f8439SShannon Nelson 	return err;
115061db421dSShannon Nelson }
115161db421dSShannon Nelson 
ionic_lif_set_hwstamp_rxfilt(struct ionic_lif * lif,u64 pkt_class)115261db421dSShannon Nelson int ionic_lif_set_hwstamp_rxfilt(struct ionic_lif *lif, u64 pkt_class)
115361db421dSShannon Nelson {
1154f0790bcdSShannon Nelson 	ionic_lif_del_hwstamp_rxfilt(lif);
1155f0790bcdSShannon Nelson 
1156f0790bcdSShannon Nelson 	if (!pkt_class)
115761db421dSShannon Nelson 		return 0;
1158f0790bcdSShannon Nelson 
1159f0790bcdSShannon Nelson 	return ionic_lif_add_hwstamp_rxfilt(lif, pkt_class);
116061db421dSShannon Nelson }
116161db421dSShannon Nelson 
ionic_notifyq_service(struct ionic_cq * cq,struct ionic_cq_info * cq_info)116277ceb68eSShannon Nelson static bool ionic_notifyq_service(struct ionic_cq *cq,
116377ceb68eSShannon Nelson 				  struct ionic_cq_info *cq_info)
116477ceb68eSShannon Nelson {
116577ceb68eSShannon Nelson 	union ionic_notifyq_comp *comp = cq_info->cq_desc;
1166c672412fSShannon Nelson 	struct ionic_deferred_work *work;
116777ceb68eSShannon Nelson 	struct net_device *netdev;
116877ceb68eSShannon Nelson 	struct ionic_queue *q;
116977ceb68eSShannon Nelson 	struct ionic_lif *lif;
117077ceb68eSShannon Nelson 	u64 eid;
117177ceb68eSShannon Nelson 
117277ceb68eSShannon Nelson 	q = cq->bound_q;
117377ceb68eSShannon Nelson 	lif = q->info[0].cb_arg;
117477ceb68eSShannon Nelson 	netdev = lif->netdev;
117577ceb68eSShannon Nelson 	eid = le64_to_cpu(comp->event.eid);
117677ceb68eSShannon Nelson 
117777ceb68eSShannon Nelson 	/* Have we run out of new completions to process? */
11783fbc9bb6SShannon Nelson 	if ((s64)(eid - lif->last_eid) <= 0)
117977ceb68eSShannon Nelson 		return false;
118077ceb68eSShannon Nelson 
118177ceb68eSShannon Nelson 	lif->last_eid = eid;
118277ceb68eSShannon Nelson 
118377ceb68eSShannon Nelson 	dev_dbg(lif->ionic->dev, "notifyq event:\n");
118477ceb68eSShannon Nelson 	dynamic_hex_dump("event ", DUMP_PREFIX_OFFSET, 16, 1,
118577ceb68eSShannon Nelson 			 comp, sizeof(*comp), true);
118677ceb68eSShannon Nelson 
118777ceb68eSShannon Nelson 	switch (le16_to_cpu(comp->event.ecode)) {
118877ceb68eSShannon Nelson 	case IONIC_EVENT_LINK_CHANGE:
118925cc5a5fSShannon Nelson 		ionic_link_status_check_request(lif, CAN_NOT_SLEEP);
119077ceb68eSShannon Nelson 		break;
119177ceb68eSShannon Nelson 	case IONIC_EVENT_RESET:
1192abd75d14SShannon Nelson 		if (lif->ionic->idev.fw_status_ready &&
1193abd75d14SShannon Nelson 		    !test_bit(IONIC_LIF_F_FW_RESET, lif->state) &&
1194abd75d14SShannon Nelson 		    !test_and_set_bit(IONIC_LIF_F_FW_STOPPING, lif->state)) {
1195c672412fSShannon Nelson 			work = kzalloc(sizeof(*work), GFP_ATOMIC);
1196c672412fSShannon Nelson 			if (!work) {
1197c0c682eeSShannon Nelson 				netdev_err(lif->netdev, "Reset event dropped\n");
1198abd75d14SShannon Nelson 				clear_bit(IONIC_LIF_F_FW_STOPPING, lif->state);
1199c672412fSShannon Nelson 			} else {
1200c672412fSShannon Nelson 				work->type = IONIC_DW_TYPE_LIF_RESET;
1201c672412fSShannon Nelson 				ionic_lif_deferred_enqueue(&lif->deferred, work);
1202c672412fSShannon Nelson 			}
1203abd75d14SShannon Nelson 		}
120477ceb68eSShannon Nelson 		break;
120577ceb68eSShannon Nelson 	default:
12065b3f3f2aSShannon Nelson 		netdev_warn(netdev, "Notifyq event ecode=%d eid=%lld\n",
120777ceb68eSShannon Nelson 			    comp->event.ecode, eid);
120877ceb68eSShannon Nelson 		break;
120977ceb68eSShannon Nelson 	}
121077ceb68eSShannon Nelson 
121177ceb68eSShannon Nelson 	return true;
121277ceb68eSShannon Nelson }
121377ceb68eSShannon Nelson 
ionic_adminq_service(struct ionic_cq * cq,struct ionic_cq_info * cq_info)12141d062b7bSShannon Nelson static bool ionic_adminq_service(struct ionic_cq *cq,
12151d062b7bSShannon Nelson 				 struct ionic_cq_info *cq_info)
12161d062b7bSShannon Nelson {
12171d062b7bSShannon Nelson 	struct ionic_admin_comp *comp = cq_info->cq_desc;
12181d062b7bSShannon Nelson 
12191d062b7bSShannon Nelson 	if (!color_match(comp->color, cq->done_color))
12201d062b7bSShannon Nelson 		return false;
12211d062b7bSShannon Nelson 
12221d062b7bSShannon Nelson 	ionic_q_service(cq->bound_q, cq_info, le16_to_cpu(comp->comp_index));
12231d062b7bSShannon Nelson 
12241d062b7bSShannon Nelson 	return true;
12251d062b7bSShannon Nelson }
12261d062b7bSShannon Nelson 
ionic_adminq_napi(struct napi_struct * napi,int budget)12271d062b7bSShannon Nelson static int ionic_adminq_napi(struct napi_struct *napi, int budget)
12281d062b7bSShannon Nelson {
1229b4280948SShannon Nelson 	struct ionic_intr_info *intr = napi_to_cq(napi)->bound_intr;
123077ceb68eSShannon Nelson 	struct ionic_lif *lif = napi_to_cq(napi)->lif;
1231b4280948SShannon Nelson 	struct ionic_dev *idev = &lif->ionic->idev;
1232e768929dSShannon Nelson 	unsigned long irqflags;
1233b4280948SShannon Nelson 	unsigned int flags = 0;
1234b69585bfSAllen Hubbe 	bool resched = false;
1235a8771bfeSShannon Nelson 	int rx_work = 0;
1236a8771bfeSShannon Nelson 	int tx_work = 0;
123777ceb68eSShannon Nelson 	int n_work = 0;
123877ceb68eSShannon Nelson 	int a_work = 0;
1239b4280948SShannon Nelson 	int work_done;
1240a8771bfeSShannon Nelson 	int credits;
124177ceb68eSShannon Nelson 
1242b4280948SShannon Nelson 	if (lif->notifyqcq && lif->notifyqcq->flags & IONIC_QCQ_F_INITED)
1243b4280948SShannon Nelson 		n_work = ionic_cq_service(&lif->notifyqcq->cq, budget,
1244b4280948SShannon Nelson 					  ionic_notifyq_service, NULL, NULL);
124577ceb68eSShannon Nelson 
1246e768929dSShannon Nelson 	spin_lock_irqsave(&lif->adminq_lock, irqflags);
1247b4280948SShannon Nelson 	if (lif->adminqcq && lif->adminqcq->flags & IONIC_QCQ_F_INITED)
1248b4280948SShannon Nelson 		a_work = ionic_cq_service(&lif->adminqcq->cq, budget,
1249b4280948SShannon Nelson 					  ionic_adminq_service, NULL, NULL);
1250e768929dSShannon Nelson 	spin_unlock_irqrestore(&lif->adminq_lock, irqflags);
1251b4280948SShannon Nelson 
1252a8771bfeSShannon Nelson 	if (lif->hwstamp_rxq)
1253a8771bfeSShannon Nelson 		rx_work = ionic_cq_service(&lif->hwstamp_rxq->cq, budget,
1254a8771bfeSShannon Nelson 					   ionic_rx_service, NULL, NULL);
1255a8771bfeSShannon Nelson 
1256a8771bfeSShannon Nelson 	if (lif->hwstamp_txq)
1257a8771bfeSShannon Nelson 		tx_work = ionic_cq_service(&lif->hwstamp_txq->cq, budget,
1258a8771bfeSShannon Nelson 					   ionic_tx_service, NULL, NULL);
1259a8771bfeSShannon Nelson 
1260a8771bfeSShannon Nelson 	work_done = max(max(n_work, a_work), max(rx_work, tx_work));
1261b4280948SShannon Nelson 	if (work_done < budget && napi_complete_done(napi, work_done)) {
1262b4280948SShannon Nelson 		flags |= IONIC_INTR_CRED_UNMASK;
12639b761574SShannon Nelson 		intr->rearm_count++;
1264b4280948SShannon Nelson 	}
1265b4280948SShannon Nelson 
1266b4280948SShannon Nelson 	if (work_done || flags) {
1267b4280948SShannon Nelson 		flags |= IONIC_INTR_CRED_RESET_COALESCE;
1268a8771bfeSShannon Nelson 		credits = n_work + a_work + rx_work + tx_work;
1269a8771bfeSShannon Nelson 		ionic_intr_credits(idev->intr_ctrl, intr->index, credits, flags);
1270b4280948SShannon Nelson 	}
1271b4280948SShannon Nelson 
1272b69585bfSAllen Hubbe 	if (!a_work && ionic_adminq_poke_doorbell(&lif->adminqcq->q))
1273b69585bfSAllen Hubbe 		resched = true;
1274b69585bfSAllen Hubbe 	if (lif->hwstamp_rxq && !rx_work && ionic_rxq_poke_doorbell(&lif->hwstamp_rxq->q))
1275b69585bfSAllen Hubbe 		resched = true;
1276b69585bfSAllen Hubbe 	if (lif->hwstamp_txq && !tx_work && ionic_txq_poke_doorbell(&lif->hwstamp_txq->q))
1277b69585bfSAllen Hubbe 		resched = true;
1278b69585bfSAllen Hubbe 	if (resched)
1279b69585bfSAllen Hubbe 		mod_timer(&lif->adminqcq->napi_deadline,
1280b69585bfSAllen Hubbe 			  jiffies + IONIC_NAPI_DEADLINE);
1281b69585bfSAllen Hubbe 
1282b4280948SShannon Nelson 	return work_done;
12831d062b7bSShannon Nelson }
12841d062b7bSShannon Nelson 
ionic_get_stats64(struct net_device * netdev,struct rtnl_link_stats64 * ns)1285f64e0c56SShannon Nelson void ionic_get_stats64(struct net_device *netdev,
12868d61aad4SShannon Nelson 		       struct rtnl_link_stats64 *ns)
12878d61aad4SShannon Nelson {
12888d61aad4SShannon Nelson 	struct ionic_lif *lif = netdev_priv(netdev);
12898d61aad4SShannon Nelson 	struct ionic_lif_stats *ls;
12908d61aad4SShannon Nelson 
12918d61aad4SShannon Nelson 	memset(ns, 0, sizeof(*ns));
12928d61aad4SShannon Nelson 	ls = &lif->info->stats;
12938d61aad4SShannon Nelson 
12948d61aad4SShannon Nelson 	ns->rx_packets = le64_to_cpu(ls->rx_ucast_packets) +
12958d61aad4SShannon Nelson 			 le64_to_cpu(ls->rx_mcast_packets) +
12968d61aad4SShannon Nelson 			 le64_to_cpu(ls->rx_bcast_packets);
12978d61aad4SShannon Nelson 
12988d61aad4SShannon Nelson 	ns->tx_packets = le64_to_cpu(ls->tx_ucast_packets) +
12998d61aad4SShannon Nelson 			 le64_to_cpu(ls->tx_mcast_packets) +
13008d61aad4SShannon Nelson 			 le64_to_cpu(ls->tx_bcast_packets);
13018d61aad4SShannon Nelson 
13028d61aad4SShannon Nelson 	ns->rx_bytes = le64_to_cpu(ls->rx_ucast_bytes) +
13038d61aad4SShannon Nelson 		       le64_to_cpu(ls->rx_mcast_bytes) +
13048d61aad4SShannon Nelson 		       le64_to_cpu(ls->rx_bcast_bytes);
13058d61aad4SShannon Nelson 
13068d61aad4SShannon Nelson 	ns->tx_bytes = le64_to_cpu(ls->tx_ucast_bytes) +
13078d61aad4SShannon Nelson 		       le64_to_cpu(ls->tx_mcast_bytes) +
13088d61aad4SShannon Nelson 		       le64_to_cpu(ls->tx_bcast_bytes);
13098d61aad4SShannon Nelson 
13108d61aad4SShannon Nelson 	ns->rx_dropped = le64_to_cpu(ls->rx_ucast_drop_packets) +
13118d61aad4SShannon Nelson 			 le64_to_cpu(ls->rx_mcast_drop_packets) +
13128d61aad4SShannon Nelson 			 le64_to_cpu(ls->rx_bcast_drop_packets);
13138d61aad4SShannon Nelson 
13148d61aad4SShannon Nelson 	ns->tx_dropped = le64_to_cpu(ls->tx_ucast_drop_packets) +
13158d61aad4SShannon Nelson 			 le64_to_cpu(ls->tx_mcast_drop_packets) +
13168d61aad4SShannon Nelson 			 le64_to_cpu(ls->tx_bcast_drop_packets);
13178d61aad4SShannon Nelson 
13188d61aad4SShannon Nelson 	ns->multicast = le64_to_cpu(ls->rx_mcast_packets);
13198d61aad4SShannon Nelson 
13208d61aad4SShannon Nelson 	ns->rx_over_errors = le64_to_cpu(ls->rx_queue_empty);
13218d61aad4SShannon Nelson 
13228d61aad4SShannon Nelson 	ns->rx_missed_errors = le64_to_cpu(ls->rx_dma_error) +
13238d61aad4SShannon Nelson 			       le64_to_cpu(ls->rx_queue_disabled) +
13248d61aad4SShannon Nelson 			       le64_to_cpu(ls->rx_desc_fetch_error) +
13258d61aad4SShannon Nelson 			       le64_to_cpu(ls->rx_desc_data_error);
13268d61aad4SShannon Nelson 
13278d61aad4SShannon Nelson 	ns->tx_aborted_errors = le64_to_cpu(ls->tx_dma_error) +
13288d61aad4SShannon Nelson 				le64_to_cpu(ls->tx_queue_disabled) +
13298d61aad4SShannon Nelson 				le64_to_cpu(ls->tx_desc_fetch_error) +
13308d61aad4SShannon Nelson 				le64_to_cpu(ls->tx_desc_data_error);
13318d61aad4SShannon Nelson 
13328d61aad4SShannon Nelson 	ns->rx_errors = ns->rx_over_errors +
13338d61aad4SShannon Nelson 			ns->rx_missed_errors;
13348d61aad4SShannon Nelson 
13358d61aad4SShannon Nelson 	ns->tx_errors = ns->tx_aborted_errors;
13368d61aad4SShannon Nelson }
13378d61aad4SShannon Nelson 
ionic_addr_add(struct net_device * netdev,const u8 * addr)13382a654540SShannon Nelson static int ionic_addr_add(struct net_device *netdev, const u8 *addr)
13392a654540SShannon Nelson {
1340969f8439SShannon Nelson 	return ionic_lif_list_addr(netdev_priv(netdev), addr, ADD_ADDR);
13412a654540SShannon Nelson }
13422a654540SShannon Nelson 
ionic_addr_del(struct net_device * netdev,const u8 * addr)13432a654540SShannon Nelson static int ionic_addr_del(struct net_device *netdev, const u8 *addr)
13442a654540SShannon Nelson {
13455c976a56SShannon Nelson 	/* Don't delete our own address from the uc list */
13465c976a56SShannon Nelson 	if (ether_addr_equal(addr, netdev->dev_addr))
13475c976a56SShannon Nelson 		return 0;
13485c976a56SShannon Nelson 
1349969f8439SShannon Nelson 	return ionic_lif_list_addr(netdev_priv(netdev), addr, DEL_ADDR);
13501800eee1SSebastian Andrzej Siewior }
13511800eee1SSebastian Andrzej Siewior 
ionic_lif_rx_mode(struct ionic_lif * lif)1352969f8439SShannon Nelson void ionic_lif_rx_mode(struct ionic_lif *lif)
13531800eee1SSebastian Andrzej Siewior {
13546840e17bSShannon Nelson 	struct net_device *netdev = lif->netdev;
13556840e17bSShannon Nelson 	unsigned int nfilters;
13566840e17bSShannon Nelson 	unsigned int nd_flags;
13572a654540SShannon Nelson 	char buf[128];
13586840e17bSShannon Nelson 	u16 rx_mode;
13592a654540SShannon Nelson 	int i;
13602a654540SShannon Nelson #define REMAIN(__x) (sizeof(buf) - (__x))
13612a654540SShannon Nelson 
13626840e17bSShannon Nelson 	mutex_lock(&lif->config_lock);
13636840e17bSShannon Nelson 
13646840e17bSShannon Nelson 	/* grab the flags once for local use */
13656840e17bSShannon Nelson 	nd_flags = netdev->flags;
13666840e17bSShannon Nelson 
13676840e17bSShannon Nelson 	rx_mode = IONIC_RX_MODE_F_UNICAST;
13686840e17bSShannon Nelson 	rx_mode |= (nd_flags & IFF_MULTICAST) ? IONIC_RX_MODE_F_MULTICAST : 0;
13696840e17bSShannon Nelson 	rx_mode |= (nd_flags & IFF_BROADCAST) ? IONIC_RX_MODE_F_BROADCAST : 0;
13706840e17bSShannon Nelson 	rx_mode |= (nd_flags & IFF_PROMISC) ? IONIC_RX_MODE_F_PROMISC : 0;
13716840e17bSShannon Nelson 	rx_mode |= (nd_flags & IFF_ALLMULTI) ? IONIC_RX_MODE_F_ALLMULTI : 0;
13726840e17bSShannon Nelson 
13739b0b6ba6SShannon Nelson 	/* sync the filters */
1374969f8439SShannon Nelson 	ionic_rx_filter_sync(lif);
1375969f8439SShannon Nelson 
1376969f8439SShannon Nelson 	/* check for overflow state
13776840e17bSShannon Nelson 	 *    if so, we track that we overflowed and enable NIC PROMISC
13786840e17bSShannon Nelson 	 *    else if the overflow is set and not needed
13796840e17bSShannon Nelson 	 *       we remove our overflow flag and check the netdev flags
13806840e17bSShannon Nelson 	 *       to see if we can disable NIC PROMISC
13816840e17bSShannon Nelson 	 */
13826840e17bSShannon Nelson 	nfilters = le32_to_cpu(lif->identity->eth.max_ucast_filters);
13834ed642ccSShannon Nelson 
13849b0b6ba6SShannon Nelson 	if (((lif->nucast + lif->nmcast) >= nfilters) ||
13859b0b6ba6SShannon Nelson 	    (lif->max_vlans && lif->nvlans >= lif->max_vlans)) {
13866840e17bSShannon Nelson 		rx_mode |= IONIC_RX_MODE_F_PROMISC;
1387a0c007b3SShannon Nelson 		rx_mode |= IONIC_RX_MODE_F_ALLMULTI;
13884ed642ccSShannon Nelson 	} else {
13896840e17bSShannon Nelson 		if (!(nd_flags & IFF_PROMISC))
13906840e17bSShannon Nelson 			rx_mode &= ~IONIC_RX_MODE_F_PROMISC;
13916840e17bSShannon Nelson 		if (!(nd_flags & IFF_ALLMULTI))
13926840e17bSShannon Nelson 			rx_mode &= ~IONIC_RX_MODE_F_ALLMULTI;
13936840e17bSShannon Nelson 	}
13946840e17bSShannon Nelson 
139538e0f746STakashi Iwai 	i = scnprintf(buf, sizeof(buf), "rx_mode 0x%04x -> 0x%04x:",
13962a654540SShannon Nelson 		      lif->rx_mode, rx_mode);
13972a654540SShannon Nelson 	if (rx_mode & IONIC_RX_MODE_F_UNICAST)
139838e0f746STakashi Iwai 		i += scnprintf(&buf[i], REMAIN(i), " RX_MODE_F_UNICAST");
13992a654540SShannon Nelson 	if (rx_mode & IONIC_RX_MODE_F_MULTICAST)
140038e0f746STakashi Iwai 		i += scnprintf(&buf[i], REMAIN(i), " RX_MODE_F_MULTICAST");
14012a654540SShannon Nelson 	if (rx_mode & IONIC_RX_MODE_F_BROADCAST)
140238e0f746STakashi Iwai 		i += scnprintf(&buf[i], REMAIN(i), " RX_MODE_F_BROADCAST");
14032a654540SShannon Nelson 	if (rx_mode & IONIC_RX_MODE_F_PROMISC)
140438e0f746STakashi Iwai 		i += scnprintf(&buf[i], REMAIN(i), " RX_MODE_F_PROMISC");
14052a654540SShannon Nelson 	if (rx_mode & IONIC_RX_MODE_F_ALLMULTI)
140638e0f746STakashi Iwai 		i += scnprintf(&buf[i], REMAIN(i), " RX_MODE_F_ALLMULTI");
14076840e17bSShannon Nelson 	if (rx_mode & IONIC_RX_MODE_F_RDMA_SNIFFER)
14086840e17bSShannon Nelson 		i += scnprintf(&buf[i], REMAIN(i), " RX_MODE_F_RDMA_SNIFFER");
14096840e17bSShannon Nelson 	netdev_dbg(netdev, "lif%d %s\n", lif->index, buf);
14102a654540SShannon Nelson 
14116840e17bSShannon Nelson 	if (lif->rx_mode != rx_mode) {
14126840e17bSShannon Nelson 		struct ionic_admin_ctx ctx = {
14136840e17bSShannon Nelson 			.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
14146840e17bSShannon Nelson 			.cmd.rx_mode_set = {
14156840e17bSShannon Nelson 				.opcode = IONIC_CMD_RX_MODE_SET,
14166840e17bSShannon Nelson 				.lif_index = cpu_to_le16(lif->index),
14176840e17bSShannon Nelson 			},
14186840e17bSShannon Nelson 		};
14196840e17bSShannon Nelson 		int err;
14206840e17bSShannon Nelson 
14216840e17bSShannon Nelson 		ctx.cmd.rx_mode_set.rx_mode = cpu_to_le16(rx_mode);
14222a654540SShannon Nelson 		err = ionic_adminq_post_wait(lif, &ctx);
14232a654540SShannon Nelson 		if (err)
14246840e17bSShannon Nelson 			netdev_warn(netdev, "set rx_mode 0x%04x failed: %d\n",
14252a654540SShannon Nelson 				    rx_mode, err);
14262a654540SShannon Nelson 		else
14272a654540SShannon Nelson 			lif->rx_mode = rx_mode;
14282a654540SShannon Nelson 	}
14292a654540SShannon Nelson 
14306840e17bSShannon Nelson 	mutex_unlock(&lif->config_lock);
14316840e17bSShannon Nelson }
14326840e17bSShannon Nelson 
ionic_ndo_set_rx_mode(struct net_device * netdev)1433b941ea05SShannon Nelson static void ionic_ndo_set_rx_mode(struct net_device *netdev)
14342a654540SShannon Nelson {
14352a654540SShannon Nelson 	struct ionic_lif *lif = netdev_priv(netdev);
1436e94f76bbSShannon Nelson 	struct ionic_deferred_work *work;
14372a654540SShannon Nelson 
1438969f8439SShannon Nelson 	/* Sync the kernel filter list with the driver filter list */
1439969f8439SShannon Nelson 	__dev_uc_sync(netdev, ionic_addr_add, ionic_addr_del);
1440969f8439SShannon Nelson 	__dev_mc_sync(netdev, ionic_addr_add, ionic_addr_del);
1441969f8439SShannon Nelson 
1442969f8439SShannon Nelson 	/* Shove off the rest of the rxmode work to the work task
1443969f8439SShannon Nelson 	 * which will include syncing the filters to the firmware.
1444969f8439SShannon Nelson 	 */
1445e94f76bbSShannon Nelson 	work = kzalloc(sizeof(*work), GFP_ATOMIC);
1446e94f76bbSShannon Nelson 	if (!work) {
1447c0c682eeSShannon Nelson 		netdev_err(lif->netdev, "rxmode change dropped\n");
1448e94f76bbSShannon Nelson 		return;
1449e94f76bbSShannon Nelson 	}
1450e94f76bbSShannon Nelson 	work->type = IONIC_DW_TYPE_RX_MODE;
1451e94f76bbSShannon Nelson 	netdev_dbg(lif->netdev, "deferred: rx_mode\n");
1452e94f76bbSShannon Nelson 	ionic_lif_deferred_enqueue(&lif->deferred, work);
14532a654540SShannon Nelson }
14542a654540SShannon Nelson 
ionic_netdev_features_to_nic(netdev_features_t features)1455beead698SShannon Nelson static __le64 ionic_netdev_features_to_nic(netdev_features_t features)
1456beead698SShannon Nelson {
1457beead698SShannon Nelson 	u64 wanted = 0;
1458beead698SShannon Nelson 
1459beead698SShannon Nelson 	if (features & NETIF_F_HW_VLAN_CTAG_TX)
1460beead698SShannon Nelson 		wanted |= IONIC_ETH_HW_VLAN_TX_TAG;
1461beead698SShannon Nelson 	if (features & NETIF_F_HW_VLAN_CTAG_RX)
1462beead698SShannon Nelson 		wanted |= IONIC_ETH_HW_VLAN_RX_STRIP;
1463beead698SShannon Nelson 	if (features & NETIF_F_HW_VLAN_CTAG_FILTER)
1464beead698SShannon Nelson 		wanted |= IONIC_ETH_HW_VLAN_RX_FILTER;
1465beead698SShannon Nelson 	if (features & NETIF_F_RXHASH)
1466beead698SShannon Nelson 		wanted |= IONIC_ETH_HW_RX_HASH;
1467beead698SShannon Nelson 	if (features & NETIF_F_RXCSUM)
1468beead698SShannon Nelson 		wanted |= IONIC_ETH_HW_RX_CSUM;
1469beead698SShannon Nelson 	if (features & NETIF_F_SG)
1470beead698SShannon Nelson 		wanted |= IONIC_ETH_HW_TX_SG;
1471beead698SShannon Nelson 	if (features & NETIF_F_HW_CSUM)
1472beead698SShannon Nelson 		wanted |= IONIC_ETH_HW_TX_CSUM;
1473beead698SShannon Nelson 	if (features & NETIF_F_TSO)
1474beead698SShannon Nelson 		wanted |= IONIC_ETH_HW_TSO;
1475beead698SShannon Nelson 	if (features & NETIF_F_TSO6)
1476beead698SShannon Nelson 		wanted |= IONIC_ETH_HW_TSO_IPV6;
1477beead698SShannon Nelson 	if (features & NETIF_F_TSO_ECN)
1478beead698SShannon Nelson 		wanted |= IONIC_ETH_HW_TSO_ECN;
1479beead698SShannon Nelson 	if (features & NETIF_F_GSO_GRE)
1480beead698SShannon Nelson 		wanted |= IONIC_ETH_HW_TSO_GRE;
1481beead698SShannon Nelson 	if (features & NETIF_F_GSO_GRE_CSUM)
1482beead698SShannon Nelson 		wanted |= IONIC_ETH_HW_TSO_GRE_CSUM;
1483beead698SShannon Nelson 	if (features & NETIF_F_GSO_IPXIP4)
1484beead698SShannon Nelson 		wanted |= IONIC_ETH_HW_TSO_IPXIP4;
1485beead698SShannon Nelson 	if (features & NETIF_F_GSO_IPXIP6)
1486beead698SShannon Nelson 		wanted |= IONIC_ETH_HW_TSO_IPXIP6;
1487beead698SShannon Nelson 	if (features & NETIF_F_GSO_UDP_TUNNEL)
1488beead698SShannon Nelson 		wanted |= IONIC_ETH_HW_TSO_UDP;
1489beead698SShannon Nelson 	if (features & NETIF_F_GSO_UDP_TUNNEL_CSUM)
1490beead698SShannon Nelson 		wanted |= IONIC_ETH_HW_TSO_UDP_CSUM;
1491beead698SShannon Nelson 
1492beead698SShannon Nelson 	return cpu_to_le64(wanted);
1493beead698SShannon Nelson }
1494beead698SShannon Nelson 
ionic_set_nic_features(struct ionic_lif * lif,netdev_features_t features)1495beead698SShannon Nelson static int ionic_set_nic_features(struct ionic_lif *lif,
1496beead698SShannon Nelson 				  netdev_features_t features)
1497beead698SShannon Nelson {
1498beead698SShannon Nelson 	struct device *dev = lif->ionic->dev;
1499beead698SShannon Nelson 	struct ionic_admin_ctx ctx = {
1500beead698SShannon Nelson 		.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
1501beead698SShannon Nelson 		.cmd.lif_setattr = {
1502beead698SShannon Nelson 			.opcode = IONIC_CMD_LIF_SETATTR,
1503beead698SShannon Nelson 			.index = cpu_to_le16(lif->index),
1504beead698SShannon Nelson 			.attr = IONIC_LIF_ATTR_FEATURES,
1505beead698SShannon Nelson 		},
1506beead698SShannon Nelson 	};
1507beead698SShannon Nelson 	u64 vlan_flags = IONIC_ETH_HW_VLAN_TX_TAG |
1508beead698SShannon Nelson 			 IONIC_ETH_HW_VLAN_RX_STRIP |
1509beead698SShannon Nelson 			 IONIC_ETH_HW_VLAN_RX_FILTER;
151075fcb75bSShannon Nelson 	u64 old_hw_features;
1511beead698SShannon Nelson 	int err;
1512beead698SShannon Nelson 
1513beead698SShannon Nelson 	ctx.cmd.lif_setattr.features = ionic_netdev_features_to_nic(features);
1514a8771bfeSShannon Nelson 
1515afeefec6SShannon Nelson 	if (lif->phc)
1516afeefec6SShannon Nelson 		ctx.cmd.lif_setattr.features |= cpu_to_le64(IONIC_ETH_HW_TIMESTAMP);
1517afeefec6SShannon Nelson 
1518beead698SShannon Nelson 	err = ionic_adminq_post_wait(lif, &ctx);
1519beead698SShannon Nelson 	if (err)
1520beead698SShannon Nelson 		return err;
1521beead698SShannon Nelson 
152275fcb75bSShannon Nelson 	old_hw_features = lif->hw_features;
1523beead698SShannon Nelson 	lif->hw_features = le64_to_cpu(ctx.cmd.lif_setattr.features &
1524beead698SShannon Nelson 				       ctx.comp.lif_setattr.features);
1525beead698SShannon Nelson 
152675fcb75bSShannon Nelson 	if ((old_hw_features ^ lif->hw_features) & IONIC_ETH_HW_RX_HASH)
152775fcb75bSShannon Nelson 		ionic_lif_rss_config(lif, lif->rss_types, NULL, NULL);
152875fcb75bSShannon Nelson 
1529a86e86dbSJian Shen 	if ((vlan_flags & le64_to_cpu(ctx.cmd.lif_setattr.features)) &&
1530beead698SShannon Nelson 	    !(vlan_flags & le64_to_cpu(ctx.comp.lif_setattr.features)))
1531beead698SShannon Nelson 		dev_info_once(lif->ionic->dev, "NIC is not supporting vlan offload, likely in SmartNIC mode\n");
1532beead698SShannon Nelson 
1533beead698SShannon Nelson 	if (lif->hw_features & IONIC_ETH_HW_VLAN_TX_TAG)
1534beead698SShannon Nelson 		dev_dbg(dev, "feature ETH_HW_VLAN_TX_TAG\n");
1535beead698SShannon Nelson 	if (lif->hw_features & IONIC_ETH_HW_VLAN_RX_STRIP)
1536beead698SShannon Nelson 		dev_dbg(dev, "feature ETH_HW_VLAN_RX_STRIP\n");
1537beead698SShannon Nelson 	if (lif->hw_features & IONIC_ETH_HW_VLAN_RX_FILTER)
1538beead698SShannon Nelson 		dev_dbg(dev, "feature ETH_HW_VLAN_RX_FILTER\n");
1539beead698SShannon Nelson 	if (lif->hw_features & IONIC_ETH_HW_RX_HASH)
1540beead698SShannon Nelson 		dev_dbg(dev, "feature ETH_HW_RX_HASH\n");
1541beead698SShannon Nelson 	if (lif->hw_features & IONIC_ETH_HW_TX_SG)
1542beead698SShannon Nelson 		dev_dbg(dev, "feature ETH_HW_TX_SG\n");
1543beead698SShannon Nelson 	if (lif->hw_features & IONIC_ETH_HW_TX_CSUM)
1544beead698SShannon Nelson 		dev_dbg(dev, "feature ETH_HW_TX_CSUM\n");
1545beead698SShannon Nelson 	if (lif->hw_features & IONIC_ETH_HW_RX_CSUM)
1546beead698SShannon Nelson 		dev_dbg(dev, "feature ETH_HW_RX_CSUM\n");
1547beead698SShannon Nelson 	if (lif->hw_features & IONIC_ETH_HW_TSO)
1548beead698SShannon Nelson 		dev_dbg(dev, "feature ETH_HW_TSO\n");
1549beead698SShannon Nelson 	if (lif->hw_features & IONIC_ETH_HW_TSO_IPV6)
1550beead698SShannon Nelson 		dev_dbg(dev, "feature ETH_HW_TSO_IPV6\n");
1551beead698SShannon Nelson 	if (lif->hw_features & IONIC_ETH_HW_TSO_ECN)
1552beead698SShannon Nelson 		dev_dbg(dev, "feature ETH_HW_TSO_ECN\n");
1553beead698SShannon Nelson 	if (lif->hw_features & IONIC_ETH_HW_TSO_GRE)
1554beead698SShannon Nelson 		dev_dbg(dev, "feature ETH_HW_TSO_GRE\n");
1555beead698SShannon Nelson 	if (lif->hw_features & IONIC_ETH_HW_TSO_GRE_CSUM)
1556beead698SShannon Nelson 		dev_dbg(dev, "feature ETH_HW_TSO_GRE_CSUM\n");
1557beead698SShannon Nelson 	if (lif->hw_features & IONIC_ETH_HW_TSO_IPXIP4)
1558beead698SShannon Nelson 		dev_dbg(dev, "feature ETH_HW_TSO_IPXIP4\n");
1559beead698SShannon Nelson 	if (lif->hw_features & IONIC_ETH_HW_TSO_IPXIP6)
1560beead698SShannon Nelson 		dev_dbg(dev, "feature ETH_HW_TSO_IPXIP6\n");
1561beead698SShannon Nelson 	if (lif->hw_features & IONIC_ETH_HW_TSO_UDP)
1562beead698SShannon Nelson 		dev_dbg(dev, "feature ETH_HW_TSO_UDP\n");
1563beead698SShannon Nelson 	if (lif->hw_features & IONIC_ETH_HW_TSO_UDP_CSUM)
1564beead698SShannon Nelson 		dev_dbg(dev, "feature ETH_HW_TSO_UDP_CSUM\n");
1565afeefec6SShannon Nelson 	if (lif->hw_features & IONIC_ETH_HW_TIMESTAMP)
1566afeefec6SShannon Nelson 		dev_dbg(dev, "feature ETH_HW_TIMESTAMP\n");
1567beead698SShannon Nelson 
1568beead698SShannon Nelson 	return 0;
1569beead698SShannon Nelson }
1570beead698SShannon Nelson 
ionic_init_nic_features(struct ionic_lif * lif)1571beead698SShannon Nelson static int ionic_init_nic_features(struct ionic_lif *lif)
1572beead698SShannon Nelson {
1573beead698SShannon Nelson 	struct net_device *netdev = lif->netdev;
1574beead698SShannon Nelson 	netdev_features_t features;
1575beead698SShannon Nelson 	int err;
1576beead698SShannon Nelson 
1577beead698SShannon Nelson 	/* set up what we expect to support by default */
1578beead698SShannon Nelson 	features = NETIF_F_HW_VLAN_CTAG_TX |
1579beead698SShannon Nelson 		   NETIF_F_HW_VLAN_CTAG_RX |
1580beead698SShannon Nelson 		   NETIF_F_HW_VLAN_CTAG_FILTER |
1581beead698SShannon Nelson 		   NETIF_F_SG |
1582beead698SShannon Nelson 		   NETIF_F_HW_CSUM |
1583beead698SShannon Nelson 		   NETIF_F_RXCSUM |
1584beead698SShannon Nelson 		   NETIF_F_TSO |
1585beead698SShannon Nelson 		   NETIF_F_TSO6 |
1586cad478c7SNeel Patel 		   NETIF_F_TSO_ECN |
1587cad478c7SNeel Patel 		   NETIF_F_GSO_GRE |
1588cad478c7SNeel Patel 		   NETIF_F_GSO_GRE_CSUM |
1589cad478c7SNeel Patel 		   NETIF_F_GSO_IPXIP4 |
1590cad478c7SNeel Patel 		   NETIF_F_GSO_IPXIP6 |
1591cad478c7SNeel Patel 		   NETIF_F_GSO_UDP_TUNNEL |
1592cad478c7SNeel Patel 		   NETIF_F_GSO_UDP_TUNNEL_CSUM;
1593beead698SShannon Nelson 
15946edddeadSShannon Nelson 	if (lif->nxqs > 1)
15956edddeadSShannon Nelson 		features |= NETIF_F_RXHASH;
15966edddeadSShannon Nelson 
1597beead698SShannon Nelson 	err = ionic_set_nic_features(lif, features);
1598beead698SShannon Nelson 	if (err)
1599beead698SShannon Nelson 		return err;
1600beead698SShannon Nelson 
1601beead698SShannon Nelson 	/* tell the netdev what we actually can support */
1602beead698SShannon Nelson 	netdev->features |= NETIF_F_HIGHDMA;
1603beead698SShannon Nelson 
1604beead698SShannon Nelson 	if (lif->hw_features & IONIC_ETH_HW_VLAN_TX_TAG)
1605beead698SShannon Nelson 		netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_TX;
1606beead698SShannon Nelson 	if (lif->hw_features & IONIC_ETH_HW_VLAN_RX_STRIP)
1607beead698SShannon Nelson 		netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_RX;
1608beead698SShannon Nelson 	if (lif->hw_features & IONIC_ETH_HW_VLAN_RX_FILTER)
1609beead698SShannon Nelson 		netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER;
1610beead698SShannon Nelson 	if (lif->hw_features & IONIC_ETH_HW_RX_HASH)
1611beead698SShannon Nelson 		netdev->hw_features |= NETIF_F_RXHASH;
1612beead698SShannon Nelson 	if (lif->hw_features & IONIC_ETH_HW_TX_SG)
1613beead698SShannon Nelson 		netdev->hw_features |= NETIF_F_SG;
1614beead698SShannon Nelson 
1615beead698SShannon Nelson 	if (lif->hw_features & IONIC_ETH_HW_TX_CSUM)
1616beead698SShannon Nelson 		netdev->hw_enc_features |= NETIF_F_HW_CSUM;
1617beead698SShannon Nelson 	if (lif->hw_features & IONIC_ETH_HW_RX_CSUM)
1618beead698SShannon Nelson 		netdev->hw_enc_features |= NETIF_F_RXCSUM;
1619beead698SShannon Nelson 	if (lif->hw_features & IONIC_ETH_HW_TSO)
1620beead698SShannon Nelson 		netdev->hw_enc_features |= NETIF_F_TSO;
1621beead698SShannon Nelson 	if (lif->hw_features & IONIC_ETH_HW_TSO_IPV6)
1622beead698SShannon Nelson 		netdev->hw_enc_features |= NETIF_F_TSO6;
1623beead698SShannon Nelson 	if (lif->hw_features & IONIC_ETH_HW_TSO_ECN)
1624beead698SShannon Nelson 		netdev->hw_enc_features |= NETIF_F_TSO_ECN;
1625beead698SShannon Nelson 	if (lif->hw_features & IONIC_ETH_HW_TSO_GRE)
1626beead698SShannon Nelson 		netdev->hw_enc_features |= NETIF_F_GSO_GRE;
1627beead698SShannon Nelson 	if (lif->hw_features & IONIC_ETH_HW_TSO_GRE_CSUM)
1628beead698SShannon Nelson 		netdev->hw_enc_features |= NETIF_F_GSO_GRE_CSUM;
1629beead698SShannon Nelson 	if (lif->hw_features & IONIC_ETH_HW_TSO_IPXIP4)
1630beead698SShannon Nelson 		netdev->hw_enc_features |= NETIF_F_GSO_IPXIP4;
1631beead698SShannon Nelson 	if (lif->hw_features & IONIC_ETH_HW_TSO_IPXIP6)
1632beead698SShannon Nelson 		netdev->hw_enc_features |= NETIF_F_GSO_IPXIP6;
1633beead698SShannon Nelson 	if (lif->hw_features & IONIC_ETH_HW_TSO_UDP)
1634beead698SShannon Nelson 		netdev->hw_enc_features |= NETIF_F_GSO_UDP_TUNNEL;
1635beead698SShannon Nelson 	if (lif->hw_features & IONIC_ETH_HW_TSO_UDP_CSUM)
1636beead698SShannon Nelson 		netdev->hw_enc_features |= NETIF_F_GSO_UDP_TUNNEL_CSUM;
1637beead698SShannon Nelson 
1638beead698SShannon Nelson 	netdev->hw_features |= netdev->hw_enc_features;
1639beead698SShannon Nelson 	netdev->features |= netdev->hw_features;
1640ef7232daSShannon Nelson 	netdev->vlan_features |= netdev->features & ~NETIF_F_VLAN_FEATURES;
1641beead698SShannon Nelson 
1642c672412fSShannon Nelson 	netdev->priv_flags |= IFF_UNICAST_FLT |
1643c672412fSShannon Nelson 			      IFF_LIVE_ADDR_CHANGE;
1644beead698SShannon Nelson 
1645beead698SShannon Nelson 	return 0;
1646beead698SShannon Nelson }
1647beead698SShannon Nelson 
ionic_set_features(struct net_device * netdev,netdev_features_t features)1648beead698SShannon Nelson static int ionic_set_features(struct net_device *netdev,
1649beead698SShannon Nelson 			      netdev_features_t features)
1650beead698SShannon Nelson {
1651beead698SShannon Nelson 	struct ionic_lif *lif = netdev_priv(netdev);
1652beead698SShannon Nelson 	int err;
1653beead698SShannon Nelson 
1654beead698SShannon Nelson 	netdev_dbg(netdev, "%s: lif->features=0x%08llx new_features=0x%08llx\n",
1655beead698SShannon Nelson 		   __func__, (u64)lif->netdev->features, (u64)features);
1656beead698SShannon Nelson 
1657beead698SShannon Nelson 	err = ionic_set_nic_features(lif, features);
1658beead698SShannon Nelson 
1659beead698SShannon Nelson 	return err;
1660beead698SShannon Nelson }
1661beead698SShannon Nelson 
ionic_set_attr_mac(struct ionic_lif * lif,u8 * mac)166219058be7SR Mohamed Shah static int ionic_set_attr_mac(struct ionic_lif *lif, u8 *mac)
166319058be7SR Mohamed Shah {
166419058be7SR Mohamed Shah 	struct ionic_admin_ctx ctx = {
166519058be7SR Mohamed Shah 		.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
166619058be7SR Mohamed Shah 		.cmd.lif_setattr = {
166719058be7SR Mohamed Shah 			.opcode = IONIC_CMD_LIF_SETATTR,
166819058be7SR Mohamed Shah 			.index = cpu_to_le16(lif->index),
166919058be7SR Mohamed Shah 			.attr = IONIC_LIF_ATTR_MAC,
167019058be7SR Mohamed Shah 		},
167119058be7SR Mohamed Shah 	};
167219058be7SR Mohamed Shah 
167319058be7SR Mohamed Shah 	ether_addr_copy(ctx.cmd.lif_setattr.mac, mac);
167419058be7SR Mohamed Shah 	return ionic_adminq_post_wait(lif, &ctx);
167519058be7SR Mohamed Shah }
167619058be7SR Mohamed Shah 
ionic_get_attr_mac(struct ionic_lif * lif,u8 * mac_addr)167719058be7SR Mohamed Shah static int ionic_get_attr_mac(struct ionic_lif *lif, u8 *mac_addr)
167819058be7SR Mohamed Shah {
167919058be7SR Mohamed Shah 	struct ionic_admin_ctx ctx = {
168019058be7SR Mohamed Shah 		.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
168119058be7SR Mohamed Shah 		.cmd.lif_getattr = {
168219058be7SR Mohamed Shah 			.opcode = IONIC_CMD_LIF_GETATTR,
168319058be7SR Mohamed Shah 			.index = cpu_to_le16(lif->index),
168419058be7SR Mohamed Shah 			.attr = IONIC_LIF_ATTR_MAC,
168519058be7SR Mohamed Shah 		},
168619058be7SR Mohamed Shah 	};
168719058be7SR Mohamed Shah 	int err;
168819058be7SR Mohamed Shah 
168919058be7SR Mohamed Shah 	err = ionic_adminq_post_wait(lif, &ctx);
169019058be7SR Mohamed Shah 	if (err)
169119058be7SR Mohamed Shah 		return err;
169219058be7SR Mohamed Shah 
169319058be7SR Mohamed Shah 	ether_addr_copy(mac_addr, ctx.comp.lif_getattr.mac);
169419058be7SR Mohamed Shah 	return 0;
169519058be7SR Mohamed Shah }
169619058be7SR Mohamed Shah 
ionic_program_mac(struct ionic_lif * lif,u8 * mac)169719058be7SR Mohamed Shah static int ionic_program_mac(struct ionic_lif *lif, u8 *mac)
169819058be7SR Mohamed Shah {
169919058be7SR Mohamed Shah 	u8  get_mac[ETH_ALEN];
170019058be7SR Mohamed Shah 	int err;
170119058be7SR Mohamed Shah 
170219058be7SR Mohamed Shah 	err = ionic_set_attr_mac(lif, mac);
170319058be7SR Mohamed Shah 	if (err)
170419058be7SR Mohamed Shah 		return err;
170519058be7SR Mohamed Shah 
170619058be7SR Mohamed Shah 	err = ionic_get_attr_mac(lif, get_mac);
170719058be7SR Mohamed Shah 	if (err)
170819058be7SR Mohamed Shah 		return err;
170919058be7SR Mohamed Shah 
171019058be7SR Mohamed Shah 	/* To deal with older firmware that silently ignores the set attr mac:
171119058be7SR Mohamed Shah 	 * doesn't actually change the mac and doesn't return an error, so we
171219058be7SR Mohamed Shah 	 * do the get attr to verify whether or not the set actually happened
171319058be7SR Mohamed Shah 	 */
171419058be7SR Mohamed Shah 	if (!ether_addr_equal(get_mac, mac))
171519058be7SR Mohamed Shah 		return 1;
171619058be7SR Mohamed Shah 
171719058be7SR Mohamed Shah 	return 0;
171819058be7SR Mohamed Shah }
171919058be7SR Mohamed Shah 
ionic_set_mac_address(struct net_device * netdev,void * sa)1720beead698SShannon Nelson static int ionic_set_mac_address(struct net_device *netdev, void *sa)
1721beead698SShannon Nelson {
172219058be7SR Mohamed Shah 	struct ionic_lif *lif = netdev_priv(netdev);
17232a654540SShannon Nelson 	struct sockaddr *addr = sa;
17242a654540SShannon Nelson 	u8 *mac;
17252a654540SShannon Nelson 	int err;
17262a654540SShannon Nelson 
17272a654540SShannon Nelson 	mac = (u8 *)addr->sa_data;
17282a654540SShannon Nelson 	if (ether_addr_equal(netdev->dev_addr, mac))
1729beead698SShannon Nelson 		return 0;
17302a654540SShannon Nelson 
173119058be7SR Mohamed Shah 	err = ionic_program_mac(lif, mac);
173219058be7SR Mohamed Shah 	if (err < 0)
173319058be7SR Mohamed Shah 		return err;
173419058be7SR Mohamed Shah 
173519058be7SR Mohamed Shah 	if (err > 0)
173619058be7SR Mohamed Shah 		netdev_dbg(netdev, "%s: SET and GET ATTR Mac are not equal-due to old FW running\n",
173719058be7SR Mohamed Shah 			   __func__);
173819058be7SR Mohamed Shah 
17392a654540SShannon Nelson 	err = eth_prepare_mac_addr_change(netdev, addr);
17402a654540SShannon Nelson 	if (err)
17412a654540SShannon Nelson 		return err;
17422a654540SShannon Nelson 
17432a654540SShannon Nelson 	if (!is_zero_ether_addr(netdev->dev_addr)) {
17442a654540SShannon Nelson 		netdev_info(netdev, "deleting mac addr %pM\n",
17452a654540SShannon Nelson 			    netdev->dev_addr);
1746969f8439SShannon Nelson 		ionic_lif_addr_del(netdev_priv(netdev), netdev->dev_addr);
17472a654540SShannon Nelson 	}
17482a654540SShannon Nelson 
17492a654540SShannon Nelson 	eth_commit_mac_addr_change(netdev, addr);
17502a654540SShannon Nelson 	netdev_info(netdev, "updating mac addr %pM\n", mac);
17512a654540SShannon Nelson 
1752969f8439SShannon Nelson 	return ionic_lif_addr_add(netdev_priv(netdev), mac);
1753beead698SShannon Nelson }
1754beead698SShannon Nelson 
ionic_stop_queues_reconfig(struct ionic_lif * lif)1755a79b559eSShannon Nelson void ionic_stop_queues_reconfig(struct ionic_lif *lif)
1756f053e1f8SShannon Nelson {
1757f053e1f8SShannon Nelson 	/* Stop and clean the queues before reconfiguration */
1758f053e1f8SShannon Nelson 	netif_device_detach(lif->netdev);
1759f053e1f8SShannon Nelson 	ionic_stop_queues(lif);
1760f053e1f8SShannon Nelson 	ionic_txrx_deinit(lif);
1761f053e1f8SShannon Nelson }
1762f053e1f8SShannon Nelson 
ionic_start_queues_reconfig(struct ionic_lif * lif)1763f053e1f8SShannon Nelson static int ionic_start_queues_reconfig(struct ionic_lif *lif)
1764f053e1f8SShannon Nelson {
1765f053e1f8SShannon Nelson 	int err;
1766f053e1f8SShannon Nelson 
1767f053e1f8SShannon Nelson 	/* Re-init the queues after reconfiguration */
1768f053e1f8SShannon Nelson 
1769f053e1f8SShannon Nelson 	/* The only way txrx_init can fail here is if communication
1770f053e1f8SShannon Nelson 	 * with FW is suddenly broken.  There's not much we can do
1771f053e1f8SShannon Nelson 	 * at this point - error messages have already been printed,
1772f053e1f8SShannon Nelson 	 * so we can continue on and the user can eventually do a
1773f053e1f8SShannon Nelson 	 * DOWN and UP to try to reset and clear the issue.
1774f053e1f8SShannon Nelson 	 */
1775f053e1f8SShannon Nelson 	err = ionic_txrx_init(lif);
177679a58c06SShannon Nelson 	ionic_link_status_check_request(lif, CAN_NOT_SLEEP);
1777f053e1f8SShannon Nelson 	netif_device_attach(lif->netdev);
1778f053e1f8SShannon Nelson 
1779f053e1f8SShannon Nelson 	return err;
1780f053e1f8SShannon Nelson }
1781f053e1f8SShannon Nelson 
ionic_change_mtu(struct net_device * netdev,int new_mtu)1782beead698SShannon Nelson static int ionic_change_mtu(struct net_device *netdev, int new_mtu)
1783beead698SShannon Nelson {
1784beead698SShannon Nelson 	struct ionic_lif *lif = netdev_priv(netdev);
1785beead698SShannon Nelson 	struct ionic_admin_ctx ctx = {
1786beead698SShannon Nelson 		.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
1787beead698SShannon Nelson 		.cmd.lif_setattr = {
1788beead698SShannon Nelson 			.opcode = IONIC_CMD_LIF_SETATTR,
1789beead698SShannon Nelson 			.index = cpu_to_le16(lif->index),
1790beead698SShannon Nelson 			.attr = IONIC_LIF_ATTR_MTU,
1791beead698SShannon Nelson 			.mtu = cpu_to_le32(new_mtu),
1792beead698SShannon Nelson 		},
1793beead698SShannon Nelson 	};
1794beead698SShannon Nelson 	int err;
1795beead698SShannon Nelson 
1796beead698SShannon Nelson 	err = ionic_adminq_post_wait(lif, &ctx);
1797beead698SShannon Nelson 	if (err)
1798beead698SShannon Nelson 		return err;
1799beead698SShannon Nelson 
1800f053e1f8SShannon Nelson 	/* if we're not running, nothing more to do */
180179ba55a3SShannon Nelson 	if (!netif_running(netdev)) {
180279ba55a3SShannon Nelson 		netdev->mtu = new_mtu;
1803f053e1f8SShannon Nelson 		return 0;
180479ba55a3SShannon Nelson 	}
1805beead698SShannon Nelson 
180679a58c06SShannon Nelson 	mutex_lock(&lif->queue_lock);
1807f053e1f8SShannon Nelson 	ionic_stop_queues_reconfig(lif);
180879ba55a3SShannon Nelson 	netdev->mtu = new_mtu;
180979a58c06SShannon Nelson 	err = ionic_start_queues_reconfig(lif);
181079a58c06SShannon Nelson 	mutex_unlock(&lif->queue_lock);
181179a58c06SShannon Nelson 
181279a58c06SShannon Nelson 	return err;
1813beead698SShannon Nelson }
1814beead698SShannon Nelson 
ionic_tx_timeout_work(struct work_struct * ws)18158c15440bSShannon Nelson static void ionic_tx_timeout_work(struct work_struct *ws)
18168c15440bSShannon Nelson {
18178c15440bSShannon Nelson 	struct ionic_lif *lif = container_of(ws, struct ionic_lif, tx_timeout_work);
181852417a95SNitya Sunkad 	int err;
18198c15440bSShannon Nelson 
18208c775344SShannon Nelson 	if (test_bit(IONIC_LIF_F_FW_RESET, lif->state))
18218c775344SShannon Nelson 		return;
18228c15440bSShannon Nelson 
18236f7d6f0fSShannon Nelson 	/* if we were stopped before this scheduled job was launched,
18246f7d6f0fSShannon Nelson 	 * don't bother the queues as they are already stopped.
18256f7d6f0fSShannon Nelson 	 */
18266f7d6f0fSShannon Nelson 	if (!netif_running(lif->netdev))
18276f7d6f0fSShannon Nelson 		return;
18286f7d6f0fSShannon Nelson 
182979a58c06SShannon Nelson 	mutex_lock(&lif->queue_lock);
18306f7d6f0fSShannon Nelson 	ionic_stop_queues_reconfig(lif);
183152417a95SNitya Sunkad 	err = ionic_start_queues_reconfig(lif);
183279a58c06SShannon Nelson 	mutex_unlock(&lif->queue_lock);
183352417a95SNitya Sunkad 
183452417a95SNitya Sunkad 	if (err)
183552417a95SNitya Sunkad 		dev_err(lif->ionic->dev, "%s: Restarting queues failed\n", __func__);
18368c15440bSShannon Nelson }
18378c15440bSShannon Nelson 
ionic_tx_timeout(struct net_device * netdev,unsigned int txqueue)18380290bd29SMichael S. Tsirkin static void ionic_tx_timeout(struct net_device *netdev, unsigned int txqueue)
1839beead698SShannon Nelson {
18408c15440bSShannon Nelson 	struct ionic_lif *lif = netdev_priv(netdev);
18418c15440bSShannon Nelson 
18428c775344SShannon Nelson 	netdev_info(lif->netdev, "Tx Timeout triggered - txq %d\n", txqueue);
18438c15440bSShannon Nelson 	schedule_work(&lif->tx_timeout_work);
1844beead698SShannon Nelson }
1845beead698SShannon Nelson 
ionic_vlan_rx_add_vid(struct net_device * netdev,__be16 proto,u16 vid)1846beead698SShannon Nelson static int ionic_vlan_rx_add_vid(struct net_device *netdev, __be16 proto,
1847beead698SShannon Nelson 				 u16 vid)
1848beead698SShannon Nelson {
18492a654540SShannon Nelson 	struct ionic_lif *lif = netdev_priv(netdev);
18502a654540SShannon Nelson 	int err;
18512a654540SShannon Nelson 
18529b0b6ba6SShannon Nelson 	err = ionic_lif_vlan_add(lif, vid);
18532a654540SShannon Nelson 	if (err)
18542a654540SShannon Nelson 		return err;
18552a654540SShannon Nelson 
18569b0b6ba6SShannon Nelson 	ionic_lif_rx_mode(lif);
1857969f8439SShannon Nelson 
18589b0b6ba6SShannon Nelson 	return 0;
1859beead698SShannon Nelson }
1860beead698SShannon Nelson 
ionic_vlan_rx_kill_vid(struct net_device * netdev,__be16 proto,u16 vid)1861beead698SShannon Nelson static int ionic_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto,
1862beead698SShannon Nelson 				  u16 vid)
1863beead698SShannon Nelson {
18642a654540SShannon Nelson 	struct ionic_lif *lif = netdev_priv(netdev);
18659b0b6ba6SShannon Nelson 	int err;
18662a654540SShannon Nelson 
18679b0b6ba6SShannon Nelson 	err = ionic_lif_vlan_del(lif, vid);
18689b0b6ba6SShannon Nelson 	if (err)
18699b0b6ba6SShannon Nelson 		return err;
18702a654540SShannon Nelson 
18719b0b6ba6SShannon Nelson 	ionic_lif_rx_mode(lif);
18722a654540SShannon Nelson 
18739b0b6ba6SShannon Nelson 	return 0;
1874beead698SShannon Nelson }
1875beead698SShannon Nelson 
ionic_lif_rss_config(struct ionic_lif * lif,const u16 types,const u8 * key,const u32 * indir)1876aa319881SShannon Nelson int ionic_lif_rss_config(struct ionic_lif *lif, const u16 types,
1877aa319881SShannon Nelson 			 const u8 *key, const u32 *indir)
1878aa319881SShannon Nelson {
1879aa319881SShannon Nelson 	struct ionic_admin_ctx ctx = {
1880aa319881SShannon Nelson 		.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
1881aa319881SShannon Nelson 		.cmd.lif_setattr = {
1882aa319881SShannon Nelson 			.opcode = IONIC_CMD_LIF_SETATTR,
1883aa319881SShannon Nelson 			.attr = IONIC_LIF_ATTR_RSS,
1884aa319881SShannon Nelson 			.rss.addr = cpu_to_le64(lif->rss_ind_tbl_pa),
1885aa319881SShannon Nelson 		},
1886aa319881SShannon Nelson 	};
1887aa319881SShannon Nelson 	unsigned int i, tbl_sz;
1888aa319881SShannon Nelson 
188975fcb75bSShannon Nelson 	if (lif->hw_features & IONIC_ETH_HW_RX_HASH) {
1890aa319881SShannon Nelson 		lif->rss_types = types;
189175fcb75bSShannon Nelson 		ctx.cmd.lif_setattr.rss.types = cpu_to_le16(types);
189275fcb75bSShannon Nelson 	}
1893aa319881SShannon Nelson 
1894aa319881SShannon Nelson 	if (key)
1895aa319881SShannon Nelson 		memcpy(lif->rss_hash_key, key, IONIC_RSS_HASH_KEY_SIZE);
1896aa319881SShannon Nelson 
1897aa319881SShannon Nelson 	if (indir) {
1898aa319881SShannon Nelson 		tbl_sz = le16_to_cpu(lif->ionic->ident.lif.eth.rss_ind_tbl_sz);
1899aa319881SShannon Nelson 		for (i = 0; i < tbl_sz; i++)
1900aa319881SShannon Nelson 			lif->rss_ind_tbl[i] = indir[i];
1901aa319881SShannon Nelson 	}
1902aa319881SShannon Nelson 
1903aa319881SShannon Nelson 	memcpy(ctx.cmd.lif_setattr.rss.key, lif->rss_hash_key,
1904aa319881SShannon Nelson 	       IONIC_RSS_HASH_KEY_SIZE);
1905aa319881SShannon Nelson 
1906aa319881SShannon Nelson 	return ionic_adminq_post_wait(lif, &ctx);
1907aa319881SShannon Nelson }
1908aa319881SShannon Nelson 
ionic_lif_rss_init(struct ionic_lif * lif)1909aa319881SShannon Nelson static int ionic_lif_rss_init(struct ionic_lif *lif)
1910aa319881SShannon Nelson {
1911aa319881SShannon Nelson 	unsigned int tbl_sz;
1912aa319881SShannon Nelson 	unsigned int i;
1913aa319881SShannon Nelson 
1914aa319881SShannon Nelson 	lif->rss_types = IONIC_RSS_TYPE_IPV4     |
1915aa319881SShannon Nelson 			 IONIC_RSS_TYPE_IPV4_TCP |
1916aa319881SShannon Nelson 			 IONIC_RSS_TYPE_IPV4_UDP |
1917aa319881SShannon Nelson 			 IONIC_RSS_TYPE_IPV6     |
1918aa319881SShannon Nelson 			 IONIC_RSS_TYPE_IPV6_TCP |
1919aa319881SShannon Nelson 			 IONIC_RSS_TYPE_IPV6_UDP;
1920aa319881SShannon Nelson 
1921aa319881SShannon Nelson 	/* Fill indirection table with 'default' values */
1922aa319881SShannon Nelson 	tbl_sz = le16_to_cpu(lif->ionic->ident.lif.eth.rss_ind_tbl_sz);
1923aa319881SShannon Nelson 	for (i = 0; i < tbl_sz; i++)
1924aa319881SShannon Nelson 		lif->rss_ind_tbl[i] = ethtool_rxfh_indir_default(i, lif->nxqs);
1925aa319881SShannon Nelson 
1926ffac2027SShannon Nelson 	return ionic_lif_rss_config(lif, lif->rss_types, NULL, NULL);
1927aa319881SShannon Nelson }
1928aa319881SShannon Nelson 
ionic_lif_rss_deinit(struct ionic_lif * lif)1929ffac2027SShannon Nelson static void ionic_lif_rss_deinit(struct ionic_lif *lif)
1930aa319881SShannon Nelson {
1931ffac2027SShannon Nelson 	int tbl_sz;
1932ffac2027SShannon Nelson 
1933ffac2027SShannon Nelson 	tbl_sz = le16_to_cpu(lif->ionic->ident.lif.eth.rss_ind_tbl_sz);
1934ffac2027SShannon Nelson 	memset(lif->rss_ind_tbl, 0, tbl_sz);
1935ffac2027SShannon Nelson 	memset(lif->rss_hash_key, 0, IONIC_RSS_HASH_KEY_SIZE);
1936ffac2027SShannon Nelson 
1937ffac2027SShannon Nelson 	ionic_lif_rss_config(lif, 0x0, NULL, NULL);
1938aa319881SShannon Nelson }
1939aa319881SShannon Nelson 
ionic_lif_quiesce(struct ionic_lif * lif)1940e7e8e087SShannon Nelson static void ionic_lif_quiesce(struct ionic_lif *lif)
1941e7e8e087SShannon Nelson {
1942e7e8e087SShannon Nelson 	struct ionic_admin_ctx ctx = {
1943e7e8e087SShannon Nelson 		.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
1944e7e8e087SShannon Nelson 		.cmd.lif_setattr = {
1945e7e8e087SShannon Nelson 			.opcode = IONIC_CMD_LIF_SETATTR,
1946e7e8e087SShannon Nelson 			.index = cpu_to_le16(lif->index),
1947e7e8e087SShannon Nelson 			.attr = IONIC_LIF_ATTR_STATE,
1948e7e8e087SShannon Nelson 			.state = IONIC_LIF_QUIESCE,
1949e7e8e087SShannon Nelson 		},
1950e7e8e087SShannon Nelson 	};
1951e7e8e087SShannon Nelson 	int err;
1952e7e8e087SShannon Nelson 
1953e7e8e087SShannon Nelson 	err = ionic_adminq_post_wait(lif, &ctx);
1954e7e8e087SShannon Nelson 	if (err)
1955ec8ee714SShannon Nelson 		netdev_dbg(lif->netdev, "lif quiesce failed %d\n", err);
1956e7e8e087SShannon Nelson }
1957e7e8e087SShannon Nelson 
ionic_txrx_disable(struct ionic_lif * lif)19580f3154e6SShannon Nelson static void ionic_txrx_disable(struct ionic_lif *lif)
19590f3154e6SShannon Nelson {
19600f3154e6SShannon Nelson 	unsigned int i;
1961ba6ab8acSShannon Nelson 	int err = 0;
19620f3154e6SShannon Nelson 
1963d5eddde5SShannon Nelson 	if (lif->txqcqs) {
1964ba6ab8acSShannon Nelson 		for (i = 0; i < lif->nxqs; i++)
19657dd22a86SShannon Nelson 			err = ionic_qcq_disable(lif, lif->txqcqs[i], err);
1966d5eddde5SShannon Nelson 	}
1967d5eddde5SShannon Nelson 
1968f0790bcdSShannon Nelson 	if (lif->hwstamp_txq)
19697dd22a86SShannon Nelson 		err = ionic_qcq_disable(lif, lif->hwstamp_txq, err);
1970f0790bcdSShannon Nelson 
1971d5eddde5SShannon Nelson 	if (lif->rxqcqs) {
1972ba6ab8acSShannon Nelson 		for (i = 0; i < lif->nxqs; i++)
19737dd22a86SShannon Nelson 			err = ionic_qcq_disable(lif, lif->rxqcqs[i], err);
19740f3154e6SShannon Nelson 	}
1975e7e8e087SShannon Nelson 
1976f0790bcdSShannon Nelson 	if (lif->hwstamp_rxq)
19777dd22a86SShannon Nelson 		err = ionic_qcq_disable(lif, lif->hwstamp_rxq, err);
1978f0790bcdSShannon Nelson 
1979e7e8e087SShannon Nelson 	ionic_lif_quiesce(lif);
1980d5eddde5SShannon Nelson }
19810f3154e6SShannon Nelson 
ionic_txrx_deinit(struct ionic_lif * lif)19820f3154e6SShannon Nelson static void ionic_txrx_deinit(struct ionic_lif *lif)
19830f3154e6SShannon Nelson {
19840f3154e6SShannon Nelson 	unsigned int i;
19850f3154e6SShannon Nelson 
1986d5eddde5SShannon Nelson 	if (lif->txqcqs) {
1987101b40a0SShannon Nelson 		for (i = 0; i < lif->nxqs && lif->txqcqs[i]; i++) {
198834dec947SShannon Nelson 			ionic_lif_qcq_deinit(lif, lif->txqcqs[i]);
198934dec947SShannon Nelson 			ionic_tx_flush(&lif->txqcqs[i]->cq);
199034dec947SShannon Nelson 			ionic_tx_empty(&lif->txqcqs[i]->q);
1991d5eddde5SShannon Nelson 		}
1992d5eddde5SShannon Nelson 	}
19930f3154e6SShannon Nelson 
1994d5eddde5SShannon Nelson 	if (lif->rxqcqs) {
1995101b40a0SShannon Nelson 		for (i = 0; i < lif->nxqs && lif->rxqcqs[i]; i++) {
199634dec947SShannon Nelson 			ionic_lif_qcq_deinit(lif, lif->rxqcqs[i]);
199734dec947SShannon Nelson 			ionic_rx_empty(&lif->rxqcqs[i]->q);
19980f3154e6SShannon Nelson 		}
19990f3154e6SShannon Nelson 	}
200049d3b493SShannon Nelson 	lif->rx_mode = 0;
2001a8771bfeSShannon Nelson 
2002a8771bfeSShannon Nelson 	if (lif->hwstamp_txq) {
2003a8771bfeSShannon Nelson 		ionic_lif_qcq_deinit(lif, lif->hwstamp_txq);
2004a8771bfeSShannon Nelson 		ionic_tx_flush(&lif->hwstamp_txq->cq);
2005a8771bfeSShannon Nelson 		ionic_tx_empty(&lif->hwstamp_txq->q);
2006a8771bfeSShannon Nelson 	}
2007a8771bfeSShannon Nelson 
2008a8771bfeSShannon Nelson 	if (lif->hwstamp_rxq) {
2009a8771bfeSShannon Nelson 		ionic_lif_qcq_deinit(lif, lif->hwstamp_rxq);
2010a8771bfeSShannon Nelson 		ionic_rx_empty(&lif->hwstamp_rxq->q);
2011a8771bfeSShannon Nelson 	}
2012d5eddde5SShannon Nelson }
20130f3154e6SShannon Nelson 
ionic_txrx_free(struct ionic_lif * lif)2014a79b559eSShannon Nelson void ionic_txrx_free(struct ionic_lif *lif)
20150f3154e6SShannon Nelson {
20160f3154e6SShannon Nelson 	unsigned int i;
20170f3154e6SShannon Nelson 
2018d5eddde5SShannon Nelson 	if (lif->txqcqs) {
2019101b40a0SShannon Nelson 		for (i = 0; i < lif->ionic->ntxqs_per_lif && lif->txqcqs[i]; i++) {
202034dec947SShannon Nelson 			ionic_qcq_free(lif, lif->txqcqs[i]);
2021101b40a0SShannon Nelson 			devm_kfree(lif->ionic->dev, lif->txqcqs[i]);
202234dec947SShannon Nelson 			lif->txqcqs[i] = NULL;
2023d5eddde5SShannon Nelson 		}
2024d5eddde5SShannon Nelson 	}
20250f3154e6SShannon Nelson 
2026d5eddde5SShannon Nelson 	if (lif->rxqcqs) {
2027101b40a0SShannon Nelson 		for (i = 0; i < lif->ionic->nrxqs_per_lif && lif->rxqcqs[i]; i++) {
202834dec947SShannon Nelson 			ionic_qcq_free(lif, lif->rxqcqs[i]);
2029101b40a0SShannon Nelson 			devm_kfree(lif->ionic->dev, lif->rxqcqs[i]);
203034dec947SShannon Nelson 			lif->rxqcqs[i] = NULL;
20310f3154e6SShannon Nelson 		}
20320f3154e6SShannon Nelson 	}
2033f0790bcdSShannon Nelson 
2034f0790bcdSShannon Nelson 	if (lif->hwstamp_txq) {
2035f0790bcdSShannon Nelson 		ionic_qcq_free(lif, lif->hwstamp_txq);
2036f0790bcdSShannon Nelson 		devm_kfree(lif->ionic->dev, lif->hwstamp_txq);
2037f0790bcdSShannon Nelson 		lif->hwstamp_txq = NULL;
2038f0790bcdSShannon Nelson 	}
2039f0790bcdSShannon Nelson 
2040f0790bcdSShannon Nelson 	if (lif->hwstamp_rxq) {
2041f0790bcdSShannon Nelson 		ionic_qcq_free(lif, lif->hwstamp_rxq);
2042f0790bcdSShannon Nelson 		devm_kfree(lif->ionic->dev, lif->hwstamp_rxq);
2043f0790bcdSShannon Nelson 		lif->hwstamp_rxq = NULL;
2044f0790bcdSShannon Nelson 	}
2045d5eddde5SShannon Nelson }
20460f3154e6SShannon Nelson 
ionic_txrx_alloc(struct ionic_lif * lif)20470f3154e6SShannon Nelson static int ionic_txrx_alloc(struct ionic_lif *lif)
20480f3154e6SShannon Nelson {
204933c252e1SShannon Nelson 	unsigned int comp_sz, desc_sz, num_desc, sg_desc_sz;
205033c252e1SShannon Nelson 	unsigned int flags, i;
20510f3154e6SShannon Nelson 	int err = 0;
20520f3154e6SShannon Nelson 
20530ec9f666SShannon Nelson 	num_desc = lif->ntxq_descs;
20540ec9f666SShannon Nelson 	desc_sz = sizeof(struct ionic_txq_desc);
20550ec9f666SShannon Nelson 	comp_sz = sizeof(struct ionic_txq_comp);
20560ec9f666SShannon Nelson 
20575b3f3f2aSShannon Nelson 	if (lif->qtype_info[IONIC_QTYPE_TXQ].version >= 1 &&
20585b3f3f2aSShannon Nelson 	    lif->qtype_info[IONIC_QTYPE_TXQ].sg_desc_sz ==
20595b3f3f2aSShannon Nelson 					  sizeof(struct ionic_txq_sg_desc_v1))
20605b3f3f2aSShannon Nelson 		sg_desc_sz = sizeof(struct ionic_txq_sg_desc_v1);
20615b3f3f2aSShannon Nelson 	else
20625b3f3f2aSShannon Nelson 		sg_desc_sz = sizeof(struct ionic_txq_sg_desc);
20635b3f3f2aSShannon Nelson 
20640f3154e6SShannon Nelson 	flags = IONIC_QCQ_F_TX_STATS | IONIC_QCQ_F_SG;
206540bc471dSShannon Nelson 
206640bc471dSShannon Nelson 	if (test_bit(IONIC_LIF_F_CMB_TX_RINGS, lif->state))
206740bc471dSShannon Nelson 		flags |= IONIC_QCQ_F_CMB_RINGS;
206840bc471dSShannon Nelson 
2069fe8c30b5SShannon Nelson 	if (test_bit(IONIC_LIF_F_SPLIT_INTR, lif->state))
2070fe8c30b5SShannon Nelson 		flags |= IONIC_QCQ_F_INTR;
207140bc471dSShannon Nelson 
20720f3154e6SShannon Nelson 	for (i = 0; i < lif->nxqs; i++) {
20730f3154e6SShannon Nelson 		err = ionic_qcq_alloc(lif, IONIC_QTYPE_TXQ, i, "tx", flags,
20740ec9f666SShannon Nelson 				      num_desc, desc_sz, comp_sz, sg_desc_sz,
207534dec947SShannon Nelson 				      lif->kern_pid, &lif->txqcqs[i]);
20760f3154e6SShannon Nelson 		if (err)
20770f3154e6SShannon Nelson 			goto err_out;
20780f3154e6SShannon Nelson 
207904a83459SShannon Nelson 		if (flags & IONIC_QCQ_F_INTR) {
2080fe8c30b5SShannon Nelson 			ionic_intr_coal_init(lif->ionic->idev.intr_ctrl,
208134dec947SShannon Nelson 					     lif->txqcqs[i]->intr.index,
2082fe8c30b5SShannon Nelson 					     lif->tx_coalesce_hw);
208304a83459SShannon Nelson 			if (test_bit(IONIC_LIF_F_TX_DIM_INTR, lif->state))
208404a83459SShannon Nelson 				lif->txqcqs[i]->intr.dim_coal_hw = lif->tx_coalesce_hw;
208504a83459SShannon Nelson 		}
2086fe8c30b5SShannon Nelson 
208734dec947SShannon Nelson 		ionic_debugfs_add_qcq(lif, lif->txqcqs[i]);
20880f3154e6SShannon Nelson 	}
20890f3154e6SShannon Nelson 
209008f2e4b2SShannon Nelson 	flags = IONIC_QCQ_F_RX_STATS | IONIC_QCQ_F_SG | IONIC_QCQ_F_INTR;
20910ec9f666SShannon Nelson 
209240bc471dSShannon Nelson 	if (test_bit(IONIC_LIF_F_CMB_RX_RINGS, lif->state))
209340bc471dSShannon Nelson 		flags |= IONIC_QCQ_F_CMB_RINGS;
209440bc471dSShannon Nelson 
20950ec9f666SShannon Nelson 	num_desc = lif->nrxq_descs;
20960ec9f666SShannon Nelson 	desc_sz = sizeof(struct ionic_rxq_desc);
20970ec9f666SShannon Nelson 	comp_sz = sizeof(struct ionic_rxq_comp);
20980ec9f666SShannon Nelson 	sg_desc_sz = sizeof(struct ionic_rxq_sg_desc);
20990ec9f666SShannon Nelson 
21000ec9f666SShannon Nelson 	if (lif->rxq_features & IONIC_Q_F_2X_CQ_DESC)
21010ec9f666SShannon Nelson 		comp_sz *= 2;
21020ec9f666SShannon Nelson 
21030f3154e6SShannon Nelson 	for (i = 0; i < lif->nxqs; i++) {
21040f3154e6SShannon Nelson 		err = ionic_qcq_alloc(lif, IONIC_QTYPE_RXQ, i, "rx", flags,
21050ec9f666SShannon Nelson 				      num_desc, desc_sz, comp_sz, sg_desc_sz,
210634dec947SShannon Nelson 				      lif->kern_pid, &lif->rxqcqs[i]);
21070f3154e6SShannon Nelson 		if (err)
21080f3154e6SShannon Nelson 			goto err_out;
21090f3154e6SShannon Nelson 
21100ec9f666SShannon Nelson 		lif->rxqcqs[i]->q.features = lif->rxq_features;
21110ec9f666SShannon Nelson 
21128c15440bSShannon Nelson 		ionic_intr_coal_init(lif->ionic->idev.intr_ctrl,
211334dec947SShannon Nelson 				     lif->rxqcqs[i]->intr.index,
2114780eded3SShannon Nelson 				     lif->rx_coalesce_hw);
211504a83459SShannon Nelson 		if (test_bit(IONIC_LIF_F_RX_DIM_INTR, lif->state))
211604a83459SShannon Nelson 			lif->rxqcqs[i]->intr.dim_coal_hw = lif->rx_coalesce_hw;
2117fe8c30b5SShannon Nelson 
2118fe8c30b5SShannon Nelson 		if (!test_bit(IONIC_LIF_F_SPLIT_INTR, lif->state))
211934dec947SShannon Nelson 			ionic_link_qcq_interrupts(lif->rxqcqs[i],
212034dec947SShannon Nelson 						  lif->txqcqs[i]);
2121fe8c30b5SShannon Nelson 
212234dec947SShannon Nelson 		ionic_debugfs_add_qcq(lif, lif->rxqcqs[i]);
21230f3154e6SShannon Nelson 	}
21240f3154e6SShannon Nelson 
21250f3154e6SShannon Nelson 	return 0;
21260f3154e6SShannon Nelson 
21270f3154e6SShannon Nelson err_out:
21280f3154e6SShannon Nelson 	ionic_txrx_free(lif);
21290f3154e6SShannon Nelson 
21300f3154e6SShannon Nelson 	return err;
21310f3154e6SShannon Nelson }
21320f3154e6SShannon Nelson 
ionic_txrx_init(struct ionic_lif * lif)21330f3154e6SShannon Nelson static int ionic_txrx_init(struct ionic_lif *lif)
21340f3154e6SShannon Nelson {
21350f3154e6SShannon Nelson 	unsigned int i;
21360f3154e6SShannon Nelson 	int err;
21370f3154e6SShannon Nelson 
21380f3154e6SShannon Nelson 	for (i = 0; i < lif->nxqs; i++) {
213934dec947SShannon Nelson 		err = ionic_lif_txq_init(lif, lif->txqcqs[i]);
21400f3154e6SShannon Nelson 		if (err)
21410f3154e6SShannon Nelson 			goto err_out;
21420f3154e6SShannon Nelson 
214334dec947SShannon Nelson 		err = ionic_lif_rxq_init(lif, lif->rxqcqs[i]);
21440f3154e6SShannon Nelson 		if (err) {
214534dec947SShannon Nelson 			ionic_lif_qcq_deinit(lif, lif->txqcqs[i]);
21460f3154e6SShannon Nelson 			goto err_out;
21470f3154e6SShannon Nelson 		}
21480f3154e6SShannon Nelson 	}
21490f3154e6SShannon Nelson 
2150aa319881SShannon Nelson 	if (lif->netdev->features & NETIF_F_RXHASH)
2151aa319881SShannon Nelson 		ionic_lif_rss_init(lif);
2152aa319881SShannon Nelson 
2153b941ea05SShannon Nelson 	ionic_lif_rx_mode(lif);
21540f3154e6SShannon Nelson 
21550f3154e6SShannon Nelson 	return 0;
21560f3154e6SShannon Nelson 
21570f3154e6SShannon Nelson err_out:
21580f3154e6SShannon Nelson 	while (i--) {
215934dec947SShannon Nelson 		ionic_lif_qcq_deinit(lif, lif->txqcqs[i]);
216034dec947SShannon Nelson 		ionic_lif_qcq_deinit(lif, lif->rxqcqs[i]);
21610f3154e6SShannon Nelson 	}
21620f3154e6SShannon Nelson 
21630f3154e6SShannon Nelson 	return err;
21640f3154e6SShannon Nelson }
21650f3154e6SShannon Nelson 
ionic_txrx_enable(struct ionic_lif * lif)21660f3154e6SShannon Nelson static int ionic_txrx_enable(struct ionic_lif *lif)
21670f3154e6SShannon Nelson {
2168ba6ab8acSShannon Nelson 	int derr = 0;
21690f3154e6SShannon Nelson 	int i, err;
21700f3154e6SShannon Nelson 
21710f3154e6SShannon Nelson 	for (i = 0; i < lif->nxqs; i++) {
21727c737fc4SShannon Nelson 		if (!(lif->rxqcqs[i] && lif->txqcqs[i])) {
21737c737fc4SShannon Nelson 			dev_err(lif->ionic->dev, "%s: bad qcq %d\n", __func__, i);
21747c737fc4SShannon Nelson 			err = -ENXIO;
21757c737fc4SShannon Nelson 			goto err_out;
21767c737fc4SShannon Nelson 		}
21777c737fc4SShannon Nelson 
217834dec947SShannon Nelson 		ionic_rx_fill(&lif->rxqcqs[i]->q);
217934dec947SShannon Nelson 		err = ionic_qcq_enable(lif->rxqcqs[i]);
21800f3154e6SShannon Nelson 		if (err)
21810f3154e6SShannon Nelson 			goto err_out;
21820f3154e6SShannon Nelson 
218334dec947SShannon Nelson 		err = ionic_qcq_enable(lif->txqcqs[i]);
21840f3154e6SShannon Nelson 		if (err) {
21857dd22a86SShannon Nelson 			derr = ionic_qcq_disable(lif, lif->rxqcqs[i], err);
21860f3154e6SShannon Nelson 			goto err_out;
21870f3154e6SShannon Nelson 		}
21880f3154e6SShannon Nelson 	}
21890f3154e6SShannon Nelson 
2190a8771bfeSShannon Nelson 	if (lif->hwstamp_rxq) {
2191a8771bfeSShannon Nelson 		ionic_rx_fill(&lif->hwstamp_rxq->q);
2192a8771bfeSShannon Nelson 		err = ionic_qcq_enable(lif->hwstamp_rxq);
2193a8771bfeSShannon Nelson 		if (err)
2194a8771bfeSShannon Nelson 			goto err_out_hwstamp_rx;
2195a8771bfeSShannon Nelson 	}
2196a8771bfeSShannon Nelson 
2197a8771bfeSShannon Nelson 	if (lif->hwstamp_txq) {
2198a8771bfeSShannon Nelson 		err = ionic_qcq_enable(lif->hwstamp_txq);
2199a8771bfeSShannon Nelson 		if (err)
2200a8771bfeSShannon Nelson 			goto err_out_hwstamp_tx;
2201a8771bfeSShannon Nelson 	}
2202a8771bfeSShannon Nelson 
22030f3154e6SShannon Nelson 	return 0;
22040f3154e6SShannon Nelson 
2205a8771bfeSShannon Nelson err_out_hwstamp_tx:
2206a8771bfeSShannon Nelson 	if (lif->hwstamp_rxq)
22077dd22a86SShannon Nelson 		derr = ionic_qcq_disable(lif, lif->hwstamp_rxq, derr);
2208a8771bfeSShannon Nelson err_out_hwstamp_rx:
2209a8771bfeSShannon Nelson 	i = lif->nxqs;
22100f3154e6SShannon Nelson err_out:
22110f3154e6SShannon Nelson 	while (i--) {
22127dd22a86SShannon Nelson 		derr = ionic_qcq_disable(lif, lif->txqcqs[i], derr);
22137dd22a86SShannon Nelson 		derr = ionic_qcq_disable(lif, lif->rxqcqs[i], derr);
22140f3154e6SShannon Nelson 	}
22150f3154e6SShannon Nelson 
22160f3154e6SShannon Nelson 	return err;
22170f3154e6SShannon Nelson }
22180f3154e6SShannon Nelson 
ionic_start_queues(struct ionic_lif * lif)221949d3b493SShannon Nelson static int ionic_start_queues(struct ionic_lif *lif)
222049d3b493SShannon Nelson {
222149d3b493SShannon Nelson 	int err;
222249d3b493SShannon Nelson 
22239e8eaf84SShannon Nelson 	if (test_bit(IONIC_LIF_F_BROKEN, lif->state))
22249e8eaf84SShannon Nelson 		return -EIO;
22259e8eaf84SShannon Nelson 
22268c775344SShannon Nelson 	if (test_bit(IONIC_LIF_F_FW_RESET, lif->state))
22278c775344SShannon Nelson 		return -EBUSY;
22288c775344SShannon Nelson 
222949d3b493SShannon Nelson 	if (test_and_set_bit(IONIC_LIF_F_UP, lif->state))
223049d3b493SShannon Nelson 		return 0;
223149d3b493SShannon Nelson 
223249d3b493SShannon Nelson 	err = ionic_txrx_enable(lif);
223349d3b493SShannon Nelson 	if (err) {
223449d3b493SShannon Nelson 		clear_bit(IONIC_LIF_F_UP, lif->state);
223549d3b493SShannon Nelson 		return err;
223649d3b493SShannon Nelson 	}
223749d3b493SShannon Nelson 	netif_tx_wake_all_queues(lif->netdev);
223849d3b493SShannon Nelson 
223949d3b493SShannon Nelson 	return 0;
224049d3b493SShannon Nelson }
224149d3b493SShannon Nelson 
ionic_open(struct net_device * netdev)2242d4881430SShannon Nelson static int ionic_open(struct net_device *netdev)
2243beead698SShannon Nelson {
2244beead698SShannon Nelson 	struct ionic_lif *lif = netdev_priv(netdev);
22450f3154e6SShannon Nelson 	int err;
2246beead698SShannon Nelson 
22479e8eaf84SShannon Nelson 	/* If recovering from a broken state, clear the bit and we'll try again */
22489e8eaf84SShannon Nelson 	if (test_and_clear_bit(IONIC_LIF_F_BROKEN, lif->state))
22499e8eaf84SShannon Nelson 		netdev_info(netdev, "clearing broken state\n");
22509e8eaf84SShannon Nelson 
2251af3d2ae1SShannon Nelson 	mutex_lock(&lif->queue_lock);
2252af3d2ae1SShannon Nelson 
22530f3154e6SShannon Nelson 	err = ionic_txrx_alloc(lif);
22540f3154e6SShannon Nelson 	if (err)
2255af3d2ae1SShannon Nelson 		goto err_unlock;
22560f3154e6SShannon Nelson 
22570f3154e6SShannon Nelson 	err = ionic_txrx_init(lif);
22580f3154e6SShannon Nelson 	if (err)
225925cc5a5fSShannon Nelson 		goto err_txrx_free;
22600f3154e6SShannon Nelson 
2261fa48494cSShannon Nelson 	err = netif_set_real_num_tx_queues(netdev, lif->nxqs);
2262fa48494cSShannon Nelson 	if (err)
2263fa48494cSShannon Nelson 		goto err_txrx_deinit;
2264fa48494cSShannon Nelson 
2265fa48494cSShannon Nelson 	err = netif_set_real_num_rx_queues(netdev, lif->nxqs);
2266fa48494cSShannon Nelson 	if (err)
2267fa48494cSShannon Nelson 		goto err_txrx_deinit;
2268fa48494cSShannon Nelson 
226949d3b493SShannon Nelson 	/* don't start the queues until we have link */
227049d3b493SShannon Nelson 	if (netif_carrier_ok(netdev)) {
227149d3b493SShannon Nelson 		err = ionic_start_queues(lif);
22720f3154e6SShannon Nelson 		if (err)
22730f3154e6SShannon Nelson 			goto err_txrx_deinit;
227449d3b493SShannon Nelson 	}
22758d61aad4SShannon Nelson 
2276ccbbd002SShannon Nelson 	/* If hardware timestamping is enabled, but the queues were freed by
2277ccbbd002SShannon Nelson 	 * ionic_stop, those need to be reallocated and initialized, too.
2278ccbbd002SShannon Nelson 	 */
2279ccbbd002SShannon Nelson 	ionic_lif_hwstamp_recreate_queues(lif);
2280ccbbd002SShannon Nelson 
2281af3d2ae1SShannon Nelson 	mutex_unlock(&lif->queue_lock);
2282ccbbd002SShannon Nelson 
2283beead698SShannon Nelson 	return 0;
22840f3154e6SShannon Nelson 
22850f3154e6SShannon Nelson err_txrx_deinit:
22860f3154e6SShannon Nelson 	ionic_txrx_deinit(lif);
228725cc5a5fSShannon Nelson err_txrx_free:
22880f3154e6SShannon Nelson 	ionic_txrx_free(lif);
2289af3d2ae1SShannon Nelson err_unlock:
2290af3d2ae1SShannon Nelson 	mutex_unlock(&lif->queue_lock);
22910f3154e6SShannon Nelson 	return err;
2292beead698SShannon Nelson }
2293beead698SShannon Nelson 
ionic_stop_queues(struct ionic_lif * lif)229449d3b493SShannon Nelson static void ionic_stop_queues(struct ionic_lif *lif)
229549d3b493SShannon Nelson {
229649d3b493SShannon Nelson 	if (!test_and_clear_bit(IONIC_LIF_F_UP, lif->state))
229749d3b493SShannon Nelson 		return;
229849d3b493SShannon Nelson 
229949d3b493SShannon Nelson 	netif_tx_disable(lif->netdev);
2300b59eabd2SShannon Nelson 	ionic_txrx_disable(lif);
230149d3b493SShannon Nelson }
230249d3b493SShannon Nelson 
ionic_stop(struct net_device * netdev)2303d4881430SShannon Nelson static int ionic_stop(struct net_device *netdev)
2304beead698SShannon Nelson {
2305beead698SShannon Nelson 	struct ionic_lif *lif = netdev_priv(netdev);
2306beead698SShannon Nelson 
2307b59eabd2SShannon Nelson 	if (test_bit(IONIC_LIF_F_FW_RESET, lif->state))
2308c672412fSShannon Nelson 		return 0;
2309c672412fSShannon Nelson 
2310af3d2ae1SShannon Nelson 	mutex_lock(&lif->queue_lock);
231149d3b493SShannon Nelson 	ionic_stop_queues(lif);
23120f3154e6SShannon Nelson 	ionic_txrx_deinit(lif);
23130f3154e6SShannon Nelson 	ionic_txrx_free(lif);
2314af3d2ae1SShannon Nelson 	mutex_unlock(&lif->queue_lock);
2315beead698SShannon Nelson 
231649d3b493SShannon Nelson 	return 0;
2317beead698SShannon Nelson }
2318beead698SShannon Nelson 
ionic_eth_ioctl(struct net_device * netdev,struct ifreq * ifr,int cmd)2319a7605370SArnd Bergmann static int ionic_eth_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
2320afeefec6SShannon Nelson {
2321afeefec6SShannon Nelson 	struct ionic_lif *lif = netdev_priv(netdev);
2322afeefec6SShannon Nelson 
2323afeefec6SShannon Nelson 	switch (cmd) {
2324afeefec6SShannon Nelson 	case SIOCSHWTSTAMP:
2325afeefec6SShannon Nelson 		return ionic_lif_hwstamp_set(lif, ifr);
2326afeefec6SShannon Nelson 	case SIOCGHWTSTAMP:
2327afeefec6SShannon Nelson 		return ionic_lif_hwstamp_get(lif, ifr);
2328afeefec6SShannon Nelson 	default:
2329afeefec6SShannon Nelson 		return -EOPNOTSUPP;
2330afeefec6SShannon Nelson 	}
2331afeefec6SShannon Nelson }
2332afeefec6SShannon Nelson 
ionic_get_fw_vf_config(struct ionic * ionic,int vf,struct ionic_vf * vfdata)233323e884a2SShannon Nelson static int ionic_get_fw_vf_config(struct ionic *ionic, int vf, struct ionic_vf *vfdata)
2334f16f5be3SBrett Creeley {
2335f16f5be3SBrett Creeley 	struct ionic_vf_getattr_comp comp = { 0 };
2336f16f5be3SBrett Creeley 	int err;
2337f16f5be3SBrett Creeley 	u8 attr;
2338f16f5be3SBrett Creeley 
2339f16f5be3SBrett Creeley 	attr = IONIC_VF_ATTR_VLAN;
2340f16f5be3SBrett Creeley 	err = ionic_dev_cmd_vf_getattr(ionic, vf, attr, &comp);
2341f16f5be3SBrett Creeley 	if (err && comp.status != IONIC_RC_ENOSUPP)
2342f16f5be3SBrett Creeley 		goto err_out;
2343f16f5be3SBrett Creeley 	if (!err)
234423e884a2SShannon Nelson 		vfdata->vlanid = comp.vlanid;
2345f16f5be3SBrett Creeley 
2346f16f5be3SBrett Creeley 	attr = IONIC_VF_ATTR_SPOOFCHK;
2347f16f5be3SBrett Creeley 	err = ionic_dev_cmd_vf_getattr(ionic, vf, attr, &comp);
2348f16f5be3SBrett Creeley 	if (err && comp.status != IONIC_RC_ENOSUPP)
2349f16f5be3SBrett Creeley 		goto err_out;
2350f16f5be3SBrett Creeley 	if (!err)
235123e884a2SShannon Nelson 		vfdata->spoofchk = comp.spoofchk;
2352f16f5be3SBrett Creeley 
2353f16f5be3SBrett Creeley 	attr = IONIC_VF_ATTR_LINKSTATE;
2354f16f5be3SBrett Creeley 	err = ionic_dev_cmd_vf_getattr(ionic, vf, attr, &comp);
2355f16f5be3SBrett Creeley 	if (err && comp.status != IONIC_RC_ENOSUPP)
2356f16f5be3SBrett Creeley 		goto err_out;
2357f16f5be3SBrett Creeley 	if (!err) {
2358f16f5be3SBrett Creeley 		switch (comp.linkstate) {
2359f16f5be3SBrett Creeley 		case IONIC_VF_LINK_STATUS_UP:
236023e884a2SShannon Nelson 			vfdata->linkstate = IFLA_VF_LINK_STATE_ENABLE;
2361f16f5be3SBrett Creeley 			break;
2362f16f5be3SBrett Creeley 		case IONIC_VF_LINK_STATUS_DOWN:
236323e884a2SShannon Nelson 			vfdata->linkstate = IFLA_VF_LINK_STATE_DISABLE;
2364f16f5be3SBrett Creeley 			break;
2365f16f5be3SBrett Creeley 		case IONIC_VF_LINK_STATUS_AUTO:
236623e884a2SShannon Nelson 			vfdata->linkstate = IFLA_VF_LINK_STATE_AUTO;
2367f16f5be3SBrett Creeley 			break;
2368f16f5be3SBrett Creeley 		default:
2369f16f5be3SBrett Creeley 			dev_warn(ionic->dev, "Unexpected link state %u\n", comp.linkstate);
2370f16f5be3SBrett Creeley 			break;
2371f16f5be3SBrett Creeley 		}
2372f16f5be3SBrett Creeley 	}
2373f16f5be3SBrett Creeley 
2374f16f5be3SBrett Creeley 	attr = IONIC_VF_ATTR_RATE;
2375f16f5be3SBrett Creeley 	err = ionic_dev_cmd_vf_getattr(ionic, vf, attr, &comp);
2376f16f5be3SBrett Creeley 	if (err && comp.status != IONIC_RC_ENOSUPP)
2377f16f5be3SBrett Creeley 		goto err_out;
2378f16f5be3SBrett Creeley 	if (!err)
237923e884a2SShannon Nelson 		vfdata->maxrate = comp.maxrate;
2380f16f5be3SBrett Creeley 
2381f16f5be3SBrett Creeley 	attr = IONIC_VF_ATTR_TRUST;
2382f16f5be3SBrett Creeley 	err = ionic_dev_cmd_vf_getattr(ionic, vf, attr, &comp);
2383f16f5be3SBrett Creeley 	if (err && comp.status != IONIC_RC_ENOSUPP)
2384f16f5be3SBrett Creeley 		goto err_out;
2385f16f5be3SBrett Creeley 	if (!err)
238623e884a2SShannon Nelson 		vfdata->trusted = comp.trust;
2387f16f5be3SBrett Creeley 
2388f16f5be3SBrett Creeley 	attr = IONIC_VF_ATTR_MAC;
2389f16f5be3SBrett Creeley 	err = ionic_dev_cmd_vf_getattr(ionic, vf, attr, &comp);
2390f16f5be3SBrett Creeley 	if (err && comp.status != IONIC_RC_ENOSUPP)
2391f16f5be3SBrett Creeley 		goto err_out;
2392f16f5be3SBrett Creeley 	if (!err)
239323e884a2SShannon Nelson 		ether_addr_copy(vfdata->macaddr, comp.macaddr);
2394f16f5be3SBrett Creeley 
2395f16f5be3SBrett Creeley err_out:
2396f16f5be3SBrett Creeley 	if (err)
2397f16f5be3SBrett Creeley 		dev_err(ionic->dev, "Failed to get %s for VF %d\n",
2398f16f5be3SBrett Creeley 			ionic_vf_attr_to_str(attr), vf);
2399f16f5be3SBrett Creeley 
2400f16f5be3SBrett Creeley 	return err;
2401f16f5be3SBrett Creeley }
2402f16f5be3SBrett Creeley 
ionic_get_vf_config(struct net_device * netdev,int vf,struct ifla_vf_info * ivf)2403fbb39807SShannon Nelson static int ionic_get_vf_config(struct net_device *netdev,
2404fbb39807SShannon Nelson 			       int vf, struct ifla_vf_info *ivf)
2405fbb39807SShannon Nelson {
2406fbb39807SShannon Nelson 	struct ionic_lif *lif = netdev_priv(netdev);
2407fbb39807SShannon Nelson 	struct ionic *ionic = lif->ionic;
240823e884a2SShannon Nelson 	struct ionic_vf vfdata = { 0 };
2409fbb39807SShannon Nelson 	int ret = 0;
2410fbb39807SShannon Nelson 
2411a836c352SShannon Nelson 	if (!netif_device_present(netdev))
2412a836c352SShannon Nelson 		return -EBUSY;
2413a836c352SShannon Nelson 
2414fbb39807SShannon Nelson 	down_read(&ionic->vf_op_lock);
2415fbb39807SShannon Nelson 
2416fbb39807SShannon Nelson 	if (vf >= pci_num_vf(ionic->pdev) || !ionic->vfs) {
2417fbb39807SShannon Nelson 		ret = -EINVAL;
2418fbb39807SShannon Nelson 	} else {
2419fbb39807SShannon Nelson 		ivf->vf = vf;
2420fbb39807SShannon Nelson 		ivf->qos = 0;
2421f16f5be3SBrett Creeley 
242223e884a2SShannon Nelson 		ret = ionic_get_fw_vf_config(ionic, vf, &vfdata);
2423f16f5be3SBrett Creeley 		if (!ret) {
242423e884a2SShannon Nelson 			ivf->vlan         = le16_to_cpu(vfdata.vlanid);
242523e884a2SShannon Nelson 			ivf->spoofchk     = vfdata.spoofchk;
242623e884a2SShannon Nelson 			ivf->linkstate    = vfdata.linkstate;
242723e884a2SShannon Nelson 			ivf->max_tx_rate  = le32_to_cpu(vfdata.maxrate);
242823e884a2SShannon Nelson 			ivf->trusted      = vfdata.trusted;
242923e884a2SShannon Nelson 			ether_addr_copy(ivf->mac, vfdata.macaddr);
2430fbb39807SShannon Nelson 		}
2431f16f5be3SBrett Creeley 	}
2432fbb39807SShannon Nelson 
2433fbb39807SShannon Nelson 	up_read(&ionic->vf_op_lock);
2434fbb39807SShannon Nelson 	return ret;
2435fbb39807SShannon Nelson }
2436fbb39807SShannon Nelson 
ionic_get_vf_stats(struct net_device * netdev,int vf,struct ifla_vf_stats * vf_stats)2437fbb39807SShannon Nelson static int ionic_get_vf_stats(struct net_device *netdev, int vf,
2438fbb39807SShannon Nelson 			      struct ifla_vf_stats *vf_stats)
2439fbb39807SShannon Nelson {
2440fbb39807SShannon Nelson 	struct ionic_lif *lif = netdev_priv(netdev);
2441fbb39807SShannon Nelson 	struct ionic *ionic = lif->ionic;
2442fbb39807SShannon Nelson 	struct ionic_lif_stats *vs;
2443fbb39807SShannon Nelson 	int ret = 0;
2444fbb39807SShannon Nelson 
2445a836c352SShannon Nelson 	if (!netif_device_present(netdev))
2446a836c352SShannon Nelson 		return -EBUSY;
2447a836c352SShannon Nelson 
2448fbb39807SShannon Nelson 	down_read(&ionic->vf_op_lock);
2449fbb39807SShannon Nelson 
2450fbb39807SShannon Nelson 	if (vf >= pci_num_vf(ionic->pdev) || !ionic->vfs) {
2451fbb39807SShannon Nelson 		ret = -EINVAL;
2452fbb39807SShannon Nelson 	} else {
2453fbb39807SShannon Nelson 		memset(vf_stats, 0, sizeof(*vf_stats));
2454fbb39807SShannon Nelson 		vs = &ionic->vfs[vf].stats;
2455fbb39807SShannon Nelson 
2456fbb39807SShannon Nelson 		vf_stats->rx_packets = le64_to_cpu(vs->rx_ucast_packets);
2457fbb39807SShannon Nelson 		vf_stats->tx_packets = le64_to_cpu(vs->tx_ucast_packets);
2458fbb39807SShannon Nelson 		vf_stats->rx_bytes   = le64_to_cpu(vs->rx_ucast_bytes);
2459fbb39807SShannon Nelson 		vf_stats->tx_bytes   = le64_to_cpu(vs->tx_ucast_bytes);
2460fbb39807SShannon Nelson 		vf_stats->broadcast  = le64_to_cpu(vs->rx_bcast_packets);
2461fbb39807SShannon Nelson 		vf_stats->multicast  = le64_to_cpu(vs->rx_mcast_packets);
2462fbb39807SShannon Nelson 		vf_stats->rx_dropped = le64_to_cpu(vs->rx_ucast_drop_packets) +
2463fbb39807SShannon Nelson 				       le64_to_cpu(vs->rx_mcast_drop_packets) +
2464fbb39807SShannon Nelson 				       le64_to_cpu(vs->rx_bcast_drop_packets);
2465fbb39807SShannon Nelson 		vf_stats->tx_dropped = le64_to_cpu(vs->tx_ucast_drop_packets) +
2466fbb39807SShannon Nelson 				       le64_to_cpu(vs->tx_mcast_drop_packets) +
2467fbb39807SShannon Nelson 				       le64_to_cpu(vs->tx_bcast_drop_packets);
2468fbb39807SShannon Nelson 	}
2469fbb39807SShannon Nelson 
2470fbb39807SShannon Nelson 	up_read(&ionic->vf_op_lock);
2471fbb39807SShannon Nelson 	return ret;
2472fbb39807SShannon Nelson }
2473fbb39807SShannon Nelson 
ionic_set_vf_mac(struct net_device * netdev,int vf,u8 * mac)2474fbb39807SShannon Nelson static int ionic_set_vf_mac(struct net_device *netdev, int vf, u8 *mac)
2475fbb39807SShannon Nelson {
247636197d82SShannon Nelson 	struct ionic_vf_setattr_cmd vfc = { .attr = IONIC_VF_ATTR_MAC };
2477fbb39807SShannon Nelson 	struct ionic_lif *lif = netdev_priv(netdev);
2478fbb39807SShannon Nelson 	struct ionic *ionic = lif->ionic;
2479fbb39807SShannon Nelson 	int ret;
2480fbb39807SShannon Nelson 
2481fbb39807SShannon Nelson 	if (!(is_zero_ether_addr(mac) || is_valid_ether_addr(mac)))
2482fbb39807SShannon Nelson 		return -EINVAL;
2483fbb39807SShannon Nelson 
2484a836c352SShannon Nelson 	if (!netif_device_present(netdev))
2485a836c352SShannon Nelson 		return -EBUSY;
2486a836c352SShannon Nelson 
2487e396ce5fSShannon Nelson 	down_write(&ionic->vf_op_lock);
2488fbb39807SShannon Nelson 
2489fbb39807SShannon Nelson 	if (vf >= pci_num_vf(ionic->pdev) || !ionic->vfs) {
2490fbb39807SShannon Nelson 		ret = -EINVAL;
2491fbb39807SShannon Nelson 	} else {
249236197d82SShannon Nelson 		ether_addr_copy(vfc.macaddr, mac);
249336197d82SShannon Nelson 		dev_dbg(ionic->dev, "%s: vf %d macaddr %pM\n",
249436197d82SShannon Nelson 			__func__, vf, vfc.macaddr);
249536197d82SShannon Nelson 
249636197d82SShannon Nelson 		ret = ionic_set_vf_config(ionic, vf, &vfc);
2497fbb39807SShannon Nelson 		if (!ret)
2498fbb39807SShannon Nelson 			ether_addr_copy(ionic->vfs[vf].macaddr, mac);
2499fbb39807SShannon Nelson 	}
2500fbb39807SShannon Nelson 
2501e396ce5fSShannon Nelson 	up_write(&ionic->vf_op_lock);
2502fbb39807SShannon Nelson 	return ret;
2503fbb39807SShannon Nelson }
2504fbb39807SShannon Nelson 
ionic_set_vf_vlan(struct net_device * netdev,int vf,u16 vlan,u8 qos,__be16 proto)2505fbb39807SShannon Nelson static int ionic_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan,
2506fbb39807SShannon Nelson 			     u8 qos, __be16 proto)
2507fbb39807SShannon Nelson {
250836197d82SShannon Nelson 	struct ionic_vf_setattr_cmd vfc = { .attr = IONIC_VF_ATTR_VLAN };
2509fbb39807SShannon Nelson 	struct ionic_lif *lif = netdev_priv(netdev);
2510fbb39807SShannon Nelson 	struct ionic *ionic = lif->ionic;
2511fbb39807SShannon Nelson 	int ret;
2512fbb39807SShannon Nelson 
2513fbb39807SShannon Nelson 	/* until someday when we support qos */
2514fbb39807SShannon Nelson 	if (qos)
2515fbb39807SShannon Nelson 		return -EINVAL;
2516fbb39807SShannon Nelson 
2517fbb39807SShannon Nelson 	if (vlan > 4095)
2518fbb39807SShannon Nelson 		return -EINVAL;
2519fbb39807SShannon Nelson 
2520fbb39807SShannon Nelson 	if (proto != htons(ETH_P_8021Q))
2521fbb39807SShannon Nelson 		return -EPROTONOSUPPORT;
2522fbb39807SShannon Nelson 
2523a836c352SShannon Nelson 	if (!netif_device_present(netdev))
2524a836c352SShannon Nelson 		return -EBUSY;
2525a836c352SShannon Nelson 
2526e396ce5fSShannon Nelson 	down_write(&ionic->vf_op_lock);
2527fbb39807SShannon Nelson 
2528fbb39807SShannon Nelson 	if (vf >= pci_num_vf(ionic->pdev) || !ionic->vfs) {
2529fbb39807SShannon Nelson 		ret = -EINVAL;
2530fbb39807SShannon Nelson 	} else {
253136197d82SShannon Nelson 		vfc.vlanid = cpu_to_le16(vlan);
253236197d82SShannon Nelson 		dev_dbg(ionic->dev, "%s: vf %d vlan %d\n",
253336197d82SShannon Nelson 			__func__, vf, le16_to_cpu(vfc.vlanid));
253436197d82SShannon Nelson 
253536197d82SShannon Nelson 		ret = ionic_set_vf_config(ionic, vf, &vfc);
2536fbb39807SShannon Nelson 		if (!ret)
2537d701ec32SShannon Nelson 			ionic->vfs[vf].vlanid = cpu_to_le16(vlan);
2538fbb39807SShannon Nelson 	}
2539fbb39807SShannon Nelson 
2540e396ce5fSShannon Nelson 	up_write(&ionic->vf_op_lock);
2541fbb39807SShannon Nelson 	return ret;
2542fbb39807SShannon Nelson }
2543fbb39807SShannon Nelson 
ionic_set_vf_rate(struct net_device * netdev,int vf,int tx_min,int tx_max)2544fbb39807SShannon Nelson static int ionic_set_vf_rate(struct net_device *netdev, int vf,
2545fbb39807SShannon Nelson 			     int tx_min, int tx_max)
2546fbb39807SShannon Nelson {
254736197d82SShannon Nelson 	struct ionic_vf_setattr_cmd vfc = { .attr = IONIC_VF_ATTR_RATE };
2548fbb39807SShannon Nelson 	struct ionic_lif *lif = netdev_priv(netdev);
2549fbb39807SShannon Nelson 	struct ionic *ionic = lif->ionic;
2550fbb39807SShannon Nelson 	int ret;
2551fbb39807SShannon Nelson 
2552fbb39807SShannon Nelson 	/* setting the min just seems silly */
2553fbb39807SShannon Nelson 	if (tx_min)
2554fbb39807SShannon Nelson 		return -EINVAL;
2555fbb39807SShannon Nelson 
2556a836c352SShannon Nelson 	if (!netif_device_present(netdev))
2557a836c352SShannon Nelson 		return -EBUSY;
2558a836c352SShannon Nelson 
2559fbb39807SShannon Nelson 	down_write(&ionic->vf_op_lock);
2560fbb39807SShannon Nelson 
2561fbb39807SShannon Nelson 	if (vf >= pci_num_vf(ionic->pdev) || !ionic->vfs) {
2562fbb39807SShannon Nelson 		ret = -EINVAL;
2563fbb39807SShannon Nelson 	} else {
256436197d82SShannon Nelson 		vfc.maxrate = cpu_to_le32(tx_max);
256536197d82SShannon Nelson 		dev_dbg(ionic->dev, "%s: vf %d maxrate %d\n",
256636197d82SShannon Nelson 			__func__, vf, le32_to_cpu(vfc.maxrate));
256736197d82SShannon Nelson 
256836197d82SShannon Nelson 		ret = ionic_set_vf_config(ionic, vf, &vfc);
2569fbb39807SShannon Nelson 		if (!ret)
25707bb99009SShannon Nelson 			ionic->vfs[vf].maxrate = cpu_to_le32(tx_max);
2571fbb39807SShannon Nelson 	}
2572fbb39807SShannon Nelson 
2573fbb39807SShannon Nelson 	up_write(&ionic->vf_op_lock);
2574fbb39807SShannon Nelson 	return ret;
2575fbb39807SShannon Nelson }
2576fbb39807SShannon Nelson 
ionic_set_vf_spoofchk(struct net_device * netdev,int vf,bool set)2577fbb39807SShannon Nelson static int ionic_set_vf_spoofchk(struct net_device *netdev, int vf, bool set)
2578fbb39807SShannon Nelson {
257936197d82SShannon Nelson 	struct ionic_vf_setattr_cmd vfc = { .attr = IONIC_VF_ATTR_SPOOFCHK };
2580fbb39807SShannon Nelson 	struct ionic_lif *lif = netdev_priv(netdev);
2581fbb39807SShannon Nelson 	struct ionic *ionic = lif->ionic;
2582fbb39807SShannon Nelson 	int ret;
2583fbb39807SShannon Nelson 
2584a836c352SShannon Nelson 	if (!netif_device_present(netdev))
2585a836c352SShannon Nelson 		return -EBUSY;
2586a836c352SShannon Nelson 
2587fbb39807SShannon Nelson 	down_write(&ionic->vf_op_lock);
2588fbb39807SShannon Nelson 
2589fbb39807SShannon Nelson 	if (vf >= pci_num_vf(ionic->pdev) || !ionic->vfs) {
2590fbb39807SShannon Nelson 		ret = -EINVAL;
2591fbb39807SShannon Nelson 	} else {
259236197d82SShannon Nelson 		vfc.spoofchk = set;
259336197d82SShannon Nelson 		dev_dbg(ionic->dev, "%s: vf %d spoof %d\n",
259436197d82SShannon Nelson 			__func__, vf, vfc.spoofchk);
259536197d82SShannon Nelson 
259636197d82SShannon Nelson 		ret = ionic_set_vf_config(ionic, vf, &vfc);
2597fbb39807SShannon Nelson 		if (!ret)
259836197d82SShannon Nelson 			ionic->vfs[vf].spoofchk = set;
2599fbb39807SShannon Nelson 	}
2600fbb39807SShannon Nelson 
2601fbb39807SShannon Nelson 	up_write(&ionic->vf_op_lock);
2602fbb39807SShannon Nelson 	return ret;
2603fbb39807SShannon Nelson }
2604fbb39807SShannon Nelson 
ionic_set_vf_trust(struct net_device * netdev,int vf,bool set)2605fbb39807SShannon Nelson static int ionic_set_vf_trust(struct net_device *netdev, int vf, bool set)
2606fbb39807SShannon Nelson {
260736197d82SShannon Nelson 	struct ionic_vf_setattr_cmd vfc = { .attr = IONIC_VF_ATTR_TRUST };
2608fbb39807SShannon Nelson 	struct ionic_lif *lif = netdev_priv(netdev);
2609fbb39807SShannon Nelson 	struct ionic *ionic = lif->ionic;
2610fbb39807SShannon Nelson 	int ret;
2611fbb39807SShannon Nelson 
2612a836c352SShannon Nelson 	if (!netif_device_present(netdev))
2613a836c352SShannon Nelson 		return -EBUSY;
2614a836c352SShannon Nelson 
2615fbb39807SShannon Nelson 	down_write(&ionic->vf_op_lock);
2616fbb39807SShannon Nelson 
2617fbb39807SShannon Nelson 	if (vf >= pci_num_vf(ionic->pdev) || !ionic->vfs) {
2618fbb39807SShannon Nelson 		ret = -EINVAL;
2619fbb39807SShannon Nelson 	} else {
262036197d82SShannon Nelson 		vfc.trust = set;
262136197d82SShannon Nelson 		dev_dbg(ionic->dev, "%s: vf %d trust %d\n",
262236197d82SShannon Nelson 			__func__, vf, vfc.trust);
262336197d82SShannon Nelson 
262436197d82SShannon Nelson 		ret = ionic_set_vf_config(ionic, vf, &vfc);
2625fbb39807SShannon Nelson 		if (!ret)
262636197d82SShannon Nelson 			ionic->vfs[vf].trusted = set;
2627fbb39807SShannon Nelson 	}
2628fbb39807SShannon Nelson 
2629fbb39807SShannon Nelson 	up_write(&ionic->vf_op_lock);
2630fbb39807SShannon Nelson 	return ret;
2631fbb39807SShannon Nelson }
2632fbb39807SShannon Nelson 
ionic_set_vf_link_state(struct net_device * netdev,int vf,int set)2633fbb39807SShannon Nelson static int ionic_set_vf_link_state(struct net_device *netdev, int vf, int set)
2634fbb39807SShannon Nelson {
263536197d82SShannon Nelson 	struct ionic_vf_setattr_cmd vfc = { .attr = IONIC_VF_ATTR_LINKSTATE };
2636fbb39807SShannon Nelson 	struct ionic_lif *lif = netdev_priv(netdev);
2637fbb39807SShannon Nelson 	struct ionic *ionic = lif->ionic;
263836197d82SShannon Nelson 	u8 vfls;
2639fbb39807SShannon Nelson 	int ret;
2640fbb39807SShannon Nelson 
2641fbb39807SShannon Nelson 	switch (set) {
2642fbb39807SShannon Nelson 	case IFLA_VF_LINK_STATE_ENABLE:
264336197d82SShannon Nelson 		vfls = IONIC_VF_LINK_STATUS_UP;
2644fbb39807SShannon Nelson 		break;
2645fbb39807SShannon Nelson 	case IFLA_VF_LINK_STATE_DISABLE:
264636197d82SShannon Nelson 		vfls = IONIC_VF_LINK_STATUS_DOWN;
2647fbb39807SShannon Nelson 		break;
2648fbb39807SShannon Nelson 	case IFLA_VF_LINK_STATE_AUTO:
264936197d82SShannon Nelson 		vfls = IONIC_VF_LINK_STATUS_AUTO;
2650fbb39807SShannon Nelson 		break;
2651fbb39807SShannon Nelson 	default:
2652fbb39807SShannon Nelson 		return -EINVAL;
2653fbb39807SShannon Nelson 	}
2654fbb39807SShannon Nelson 
2655a836c352SShannon Nelson 	if (!netif_device_present(netdev))
2656a836c352SShannon Nelson 		return -EBUSY;
2657a836c352SShannon Nelson 
2658fbb39807SShannon Nelson 	down_write(&ionic->vf_op_lock);
2659fbb39807SShannon Nelson 
2660fbb39807SShannon Nelson 	if (vf >= pci_num_vf(ionic->pdev) || !ionic->vfs) {
2661fbb39807SShannon Nelson 		ret = -EINVAL;
2662fbb39807SShannon Nelson 	} else {
266336197d82SShannon Nelson 		vfc.linkstate = vfls;
266436197d82SShannon Nelson 		dev_dbg(ionic->dev, "%s: vf %d linkstate %d\n",
266536197d82SShannon Nelson 			__func__, vf, vfc.linkstate);
266636197d82SShannon Nelson 
266736197d82SShannon Nelson 		ret = ionic_set_vf_config(ionic, vf, &vfc);
2668fbb39807SShannon Nelson 		if (!ret)
2669fbb39807SShannon Nelson 			ionic->vfs[vf].linkstate = set;
2670fbb39807SShannon Nelson 	}
2671fbb39807SShannon Nelson 
2672fbb39807SShannon Nelson 	up_write(&ionic->vf_op_lock);
2673fbb39807SShannon Nelson 	return ret;
2674fbb39807SShannon Nelson }
2675fbb39807SShannon Nelson 
ionic_vf_attr_replay(struct ionic_lif * lif)2676db28adf9SShannon Nelson static void ionic_vf_attr_replay(struct ionic_lif *lif)
2677db28adf9SShannon Nelson {
2678db28adf9SShannon Nelson 	struct ionic_vf_setattr_cmd vfc = { };
2679db28adf9SShannon Nelson 	struct ionic *ionic = lif->ionic;
2680db28adf9SShannon Nelson 	struct ionic_vf *v;
2681db28adf9SShannon Nelson 	int i;
2682db28adf9SShannon Nelson 
2683db28adf9SShannon Nelson 	if (!ionic->vfs)
2684db28adf9SShannon Nelson 		return;
2685db28adf9SShannon Nelson 
2686db28adf9SShannon Nelson 	down_read(&ionic->vf_op_lock);
2687db28adf9SShannon Nelson 
2688db28adf9SShannon Nelson 	for (i = 0; i < ionic->num_vfs; i++) {
2689db28adf9SShannon Nelson 		v = &ionic->vfs[i];
2690db28adf9SShannon Nelson 
2691db28adf9SShannon Nelson 		if (v->stats_pa) {
2692db28adf9SShannon Nelson 			vfc.attr = IONIC_VF_ATTR_STATSADDR;
2693db28adf9SShannon Nelson 			vfc.stats_pa = cpu_to_le64(v->stats_pa);
2694db28adf9SShannon Nelson 			ionic_set_vf_config(ionic, i, &vfc);
2695db28adf9SShannon Nelson 			vfc.stats_pa = 0;
2696db28adf9SShannon Nelson 		}
2697db28adf9SShannon Nelson 
2698db28adf9SShannon Nelson 		if (!is_zero_ether_addr(v->macaddr)) {
2699db28adf9SShannon Nelson 			vfc.attr = IONIC_VF_ATTR_MAC;
2700db28adf9SShannon Nelson 			ether_addr_copy(vfc.macaddr, v->macaddr);
2701db28adf9SShannon Nelson 			ionic_set_vf_config(ionic, i, &vfc);
2702db28adf9SShannon Nelson 			eth_zero_addr(vfc.macaddr);
2703db28adf9SShannon Nelson 		}
2704db28adf9SShannon Nelson 
2705db28adf9SShannon Nelson 		if (v->vlanid) {
2706db28adf9SShannon Nelson 			vfc.attr = IONIC_VF_ATTR_VLAN;
2707db28adf9SShannon Nelson 			vfc.vlanid = v->vlanid;
2708db28adf9SShannon Nelson 			ionic_set_vf_config(ionic, i, &vfc);
2709db28adf9SShannon Nelson 			vfc.vlanid = 0;
2710db28adf9SShannon Nelson 		}
2711db28adf9SShannon Nelson 
2712db28adf9SShannon Nelson 		if (v->maxrate) {
2713db28adf9SShannon Nelson 			vfc.attr = IONIC_VF_ATTR_RATE;
2714db28adf9SShannon Nelson 			vfc.maxrate = v->maxrate;
2715db28adf9SShannon Nelson 			ionic_set_vf_config(ionic, i, &vfc);
2716db28adf9SShannon Nelson 			vfc.maxrate = 0;
2717db28adf9SShannon Nelson 		}
2718db28adf9SShannon Nelson 
2719db28adf9SShannon Nelson 		if (v->spoofchk) {
2720db28adf9SShannon Nelson 			vfc.attr = IONIC_VF_ATTR_SPOOFCHK;
2721db28adf9SShannon Nelson 			vfc.spoofchk = v->spoofchk;
2722db28adf9SShannon Nelson 			ionic_set_vf_config(ionic, i, &vfc);
2723db28adf9SShannon Nelson 			vfc.spoofchk = 0;
2724db28adf9SShannon Nelson 		}
2725db28adf9SShannon Nelson 
2726db28adf9SShannon Nelson 		if (v->trusted) {
2727db28adf9SShannon Nelson 			vfc.attr = IONIC_VF_ATTR_TRUST;
2728db28adf9SShannon Nelson 			vfc.trust = v->trusted;
2729db28adf9SShannon Nelson 			ionic_set_vf_config(ionic, i, &vfc);
2730db28adf9SShannon Nelson 			vfc.trust = 0;
2731db28adf9SShannon Nelson 		}
2732db28adf9SShannon Nelson 
2733db28adf9SShannon Nelson 		if (v->linkstate) {
2734db28adf9SShannon Nelson 			vfc.attr = IONIC_VF_ATTR_LINKSTATE;
2735db28adf9SShannon Nelson 			vfc.linkstate = v->linkstate;
2736db28adf9SShannon Nelson 			ionic_set_vf_config(ionic, i, &vfc);
2737db28adf9SShannon Nelson 			vfc.linkstate = 0;
2738db28adf9SShannon Nelson 		}
2739db28adf9SShannon Nelson 	}
2740db28adf9SShannon Nelson 
2741db28adf9SShannon Nelson 	up_read(&ionic->vf_op_lock);
2742f43a96d9SShannon Nelson 
2743f43a96d9SShannon Nelson 	ionic_vf_start(ionic);
2744db28adf9SShannon Nelson }
2745db28adf9SShannon Nelson 
2746beead698SShannon Nelson static const struct net_device_ops ionic_netdev_ops = {
2747beead698SShannon Nelson 	.ndo_open               = ionic_open,
2748beead698SShannon Nelson 	.ndo_stop               = ionic_stop,
2749a7605370SArnd Bergmann 	.ndo_eth_ioctl		= ionic_eth_ioctl,
27500f3154e6SShannon Nelson 	.ndo_start_xmit		= ionic_start_xmit,
27518d61aad4SShannon Nelson 	.ndo_get_stats64	= ionic_get_stats64,
27521800eee1SSebastian Andrzej Siewior 	.ndo_set_rx_mode	= ionic_ndo_set_rx_mode,
2753beead698SShannon Nelson 	.ndo_set_features	= ionic_set_features,
2754beead698SShannon Nelson 	.ndo_set_mac_address	= ionic_set_mac_address,
2755beead698SShannon Nelson 	.ndo_validate_addr	= eth_validate_addr,
2756beead698SShannon Nelson 	.ndo_tx_timeout         = ionic_tx_timeout,
2757beead698SShannon Nelson 	.ndo_change_mtu         = ionic_change_mtu,
2758beead698SShannon Nelson 	.ndo_vlan_rx_add_vid    = ionic_vlan_rx_add_vid,
2759beead698SShannon Nelson 	.ndo_vlan_rx_kill_vid   = ionic_vlan_rx_kill_vid,
2760fbb39807SShannon Nelson 	.ndo_set_vf_vlan	= ionic_set_vf_vlan,
2761fbb39807SShannon Nelson 	.ndo_set_vf_trust	= ionic_set_vf_trust,
2762fbb39807SShannon Nelson 	.ndo_set_vf_mac		= ionic_set_vf_mac,
2763fbb39807SShannon Nelson 	.ndo_set_vf_rate	= ionic_set_vf_rate,
2764fbb39807SShannon Nelson 	.ndo_set_vf_spoofchk	= ionic_set_vf_spoofchk,
2765fbb39807SShannon Nelson 	.ndo_get_vf_config	= ionic_get_vf_config,
2766fbb39807SShannon Nelson 	.ndo_set_vf_link_state	= ionic_set_vf_link_state,
2767fbb39807SShannon Nelson 	.ndo_get_vf_stats       = ionic_get_vf_stats,
2768beead698SShannon Nelson };
2769beead698SShannon Nelson 
ionic_cmb_reconfig(struct ionic_lif * lif,struct ionic_queue_params * qparam)277040bc471dSShannon Nelson static int ionic_cmb_reconfig(struct ionic_lif *lif,
277140bc471dSShannon Nelson 			      struct ionic_queue_params *qparam)
277240bc471dSShannon Nelson {
277340bc471dSShannon Nelson 	struct ionic_queue_params start_qparams;
277440bc471dSShannon Nelson 	int err = 0;
277540bc471dSShannon Nelson 
277640bc471dSShannon Nelson 	/* When changing CMB queue parameters, we're using limited
277740bc471dSShannon Nelson 	 * on-device memory and don't have extra memory to use for
277840bc471dSShannon Nelson 	 * duplicate allocations, so we free it all first then
277940bc471dSShannon Nelson 	 * re-allocate with the new parameters.
278040bc471dSShannon Nelson 	 */
278140bc471dSShannon Nelson 
278240bc471dSShannon Nelson 	/* Checkpoint for possible unwind */
278340bc471dSShannon Nelson 	ionic_init_queue_params(lif, &start_qparams);
278440bc471dSShannon Nelson 
278540bc471dSShannon Nelson 	/* Stop and free the queues */
278640bc471dSShannon Nelson 	ionic_stop_queues_reconfig(lif);
278740bc471dSShannon Nelson 	ionic_txrx_free(lif);
278840bc471dSShannon Nelson 
278940bc471dSShannon Nelson 	/* Set up new qparams */
279040bc471dSShannon Nelson 	ionic_set_queue_params(lif, qparam);
279140bc471dSShannon Nelson 
279240bc471dSShannon Nelson 	if (netif_running(lif->netdev)) {
279340bc471dSShannon Nelson 		/* Alloc and start the new configuration */
279440bc471dSShannon Nelson 		err = ionic_txrx_alloc(lif);
279540bc471dSShannon Nelson 		if (err) {
279640bc471dSShannon Nelson 			dev_warn(lif->ionic->dev,
279740bc471dSShannon Nelson 				 "CMB reconfig failed, restoring values: %d\n", err);
279840bc471dSShannon Nelson 
279940bc471dSShannon Nelson 			/* Back out the changes */
280040bc471dSShannon Nelson 			ionic_set_queue_params(lif, &start_qparams);
280140bc471dSShannon Nelson 			err = ionic_txrx_alloc(lif);
280240bc471dSShannon Nelson 			if (err) {
280340bc471dSShannon Nelson 				dev_err(lif->ionic->dev,
280440bc471dSShannon Nelson 					"CMB restore failed: %d\n", err);
280552417a95SNitya Sunkad 				goto err_out;
280640bc471dSShannon Nelson 			}
280740bc471dSShannon Nelson 		}
280840bc471dSShannon Nelson 
280952417a95SNitya Sunkad 		err = ionic_start_queues_reconfig(lif);
281052417a95SNitya Sunkad 		if (err) {
281152417a95SNitya Sunkad 			dev_err(lif->ionic->dev,
281252417a95SNitya Sunkad 				"CMB reconfig failed: %d\n", err);
281352417a95SNitya Sunkad 			goto err_out;
281452417a95SNitya Sunkad 		}
281552417a95SNitya Sunkad 	}
281652417a95SNitya Sunkad 
281752417a95SNitya Sunkad err_out:
281840bc471dSShannon Nelson 	/* This was detached in ionic_stop_queues_reconfig() */
281940bc471dSShannon Nelson 	netif_device_attach(lif->netdev);
282040bc471dSShannon Nelson 
282140bc471dSShannon Nelson 	return err;
282240bc471dSShannon Nelson }
282340bc471dSShannon Nelson 
ionic_swap_queues(struct ionic_qcq * a,struct ionic_qcq * b)2824a34e25abSShannon Nelson static void ionic_swap_queues(struct ionic_qcq *a, struct ionic_qcq *b)
2825a34e25abSShannon Nelson {
2826a34e25abSShannon Nelson 	/* only swapping the queues, not the napi, flags, or other stuff */
282757a3a98dSShannon Nelson 	swap(a->q.features,   b->q.features);
2828a34e25abSShannon Nelson 	swap(a->q.num_descs,  b->q.num_descs);
28290ec9f666SShannon Nelson 	swap(a->q.desc_size,  b->q.desc_size);
2830a34e25abSShannon Nelson 	swap(a->q.base,       b->q.base);
2831a34e25abSShannon Nelson 	swap(a->q.base_pa,    b->q.base_pa);
2832a34e25abSShannon Nelson 	swap(a->q.info,       b->q.info);
2833a34e25abSShannon Nelson 	swap(a->q_base,       b->q_base);
2834a34e25abSShannon Nelson 	swap(a->q_base_pa,    b->q_base_pa);
2835a34e25abSShannon Nelson 	swap(a->q_size,       b->q_size);
2836a34e25abSShannon Nelson 
28370ec9f666SShannon Nelson 	swap(a->q.sg_desc_size, b->q.sg_desc_size);
2838a34e25abSShannon Nelson 	swap(a->q.sg_base,    b->q.sg_base);
2839a34e25abSShannon Nelson 	swap(a->q.sg_base_pa, b->q.sg_base_pa);
2840a34e25abSShannon Nelson 	swap(a->sg_base,      b->sg_base);
2841a34e25abSShannon Nelson 	swap(a->sg_base_pa,   b->sg_base_pa);
2842a34e25abSShannon Nelson 	swap(a->sg_size,      b->sg_size);
2843a34e25abSShannon Nelson 
2844a34e25abSShannon Nelson 	swap(a->cq.num_descs, b->cq.num_descs);
28450ec9f666SShannon Nelson 	swap(a->cq.desc_size, b->cq.desc_size);
2846a34e25abSShannon Nelson 	swap(a->cq.base,      b->cq.base);
2847a34e25abSShannon Nelson 	swap(a->cq.base_pa,   b->cq.base_pa);
2848a34e25abSShannon Nelson 	swap(a->cq.info,      b->cq.info);
2849a34e25abSShannon Nelson 	swap(a->cq_base,      b->cq_base);
2850a34e25abSShannon Nelson 	swap(a->cq_base_pa,   b->cq_base_pa);
2851a34e25abSShannon Nelson 	swap(a->cq_size,      b->cq_size);
285255eda6bbSShannon Nelson 
285355eda6bbSShannon Nelson 	ionic_debugfs_del_qcq(a);
285455eda6bbSShannon Nelson 	ionic_debugfs_add_qcq(a->q.lif, a);
2855a34e25abSShannon Nelson }
2856a34e25abSShannon Nelson 
ionic_reconfigure_queues(struct ionic_lif * lif,struct ionic_queue_params * qparam)2857a34e25abSShannon Nelson int ionic_reconfigure_queues(struct ionic_lif *lif,
2858a34e25abSShannon Nelson 			     struct ionic_queue_params *qparam)
2859a34e25abSShannon Nelson {
286033c252e1SShannon Nelson 	unsigned int comp_sz, desc_sz, num_desc, sg_desc_sz;
2861a34e25abSShannon Nelson 	struct ionic_qcq **tx_qcqs = NULL;
2862a34e25abSShannon Nelson 	struct ionic_qcq **rx_qcqs = NULL;
286333c252e1SShannon Nelson 	unsigned int flags, i;
2864e7f52aa4SShannon Nelson 	int err = 0;
2865a34e25abSShannon Nelson 
286640bc471dSShannon Nelson 	/* Are we changing q params while CMB is on */
286740bc471dSShannon Nelson 	if ((test_bit(IONIC_LIF_F_CMB_TX_RINGS, lif->state) && qparam->cmb_tx) ||
286840bc471dSShannon Nelson 	    (test_bit(IONIC_LIF_F_CMB_RX_RINGS, lif->state) && qparam->cmb_rx))
286940bc471dSShannon Nelson 		return ionic_cmb_reconfig(lif, qparam);
287040bc471dSShannon Nelson 
2871a34e25abSShannon Nelson 	/* allocate temporary qcq arrays to hold new queue structs */
2872101b40a0SShannon Nelson 	if (qparam->nxqs != lif->nxqs || qparam->ntxq_descs != lif->ntxq_descs) {
2873101b40a0SShannon Nelson 		tx_qcqs = devm_kcalloc(lif->ionic->dev, lif->ionic->ntxqs_per_lif,
2874a34e25abSShannon Nelson 				       sizeof(struct ionic_qcq *), GFP_KERNEL);
2875e7f52aa4SShannon Nelson 		if (!tx_qcqs) {
2876e7f52aa4SShannon Nelson 			err = -ENOMEM;
2877a34e25abSShannon Nelson 			goto err_out;
2878a34e25abSShannon Nelson 		}
2879e7f52aa4SShannon Nelson 	}
28800ec9f666SShannon Nelson 	if (qparam->nxqs != lif->nxqs ||
28810ec9f666SShannon Nelson 	    qparam->nrxq_descs != lif->nrxq_descs ||
28820ec9f666SShannon Nelson 	    qparam->rxq_features != lif->rxq_features) {
2883101b40a0SShannon Nelson 		rx_qcqs = devm_kcalloc(lif->ionic->dev, lif->ionic->nrxqs_per_lif,
2884a34e25abSShannon Nelson 				       sizeof(struct ionic_qcq *), GFP_KERNEL);
2885e7f52aa4SShannon Nelson 		if (!rx_qcqs) {
2886e7f52aa4SShannon Nelson 			err = -ENOMEM;
2887a34e25abSShannon Nelson 			goto err_out;
2888a34e25abSShannon Nelson 		}
2889e7f52aa4SShannon Nelson 	}
2890a34e25abSShannon Nelson 
2891101b40a0SShannon Nelson 	/* allocate new desc_info and rings, but leave the interrupt setup
2892101b40a0SShannon Nelson 	 * until later so as to not mess with the still-running queues
2893101b40a0SShannon Nelson 	 */
28940ec9f666SShannon Nelson 	if (tx_qcqs) {
28950ec9f666SShannon Nelson 		num_desc = qparam->ntxq_descs;
28960ec9f666SShannon Nelson 		desc_sz = sizeof(struct ionic_txq_desc);
28970ec9f666SShannon Nelson 		comp_sz = sizeof(struct ionic_txq_comp);
28980ec9f666SShannon Nelson 
2899a34e25abSShannon Nelson 		if (lif->qtype_info[IONIC_QTYPE_TXQ].version >= 1 &&
2900a34e25abSShannon Nelson 		    lif->qtype_info[IONIC_QTYPE_TXQ].sg_desc_sz ==
2901a34e25abSShannon Nelson 		    sizeof(struct ionic_txq_sg_desc_v1))
2902a34e25abSShannon Nelson 			sg_desc_sz = sizeof(struct ionic_txq_sg_desc_v1);
2903a34e25abSShannon Nelson 		else
2904a34e25abSShannon Nelson 			sg_desc_sz = sizeof(struct ionic_txq_sg_desc);
2905a34e25abSShannon Nelson 
2906101b40a0SShannon Nelson 		for (i = 0; i < qparam->nxqs; i++) {
290740bc471dSShannon Nelson 			/* If missing, short placeholder qcq needed for swap */
290840bc471dSShannon Nelson 			if (!lif->txqcqs[i]) {
290940bc471dSShannon Nelson 				flags = IONIC_QCQ_F_TX_STATS | IONIC_QCQ_F_SG;
291040bc471dSShannon Nelson 				err = ionic_qcq_alloc(lif, IONIC_QTYPE_TXQ, i, "tx", flags,
291140bc471dSShannon Nelson 						      4, desc_sz, comp_sz, sg_desc_sz,
291240bc471dSShannon Nelson 						      lif->kern_pid, &lif->txqcqs[i]);
291340bc471dSShannon Nelson 				if (err)
291440bc471dSShannon Nelson 					goto err_out;
291540bc471dSShannon Nelson 			}
291640bc471dSShannon Nelson 
2917a34e25abSShannon Nelson 			flags = lif->txqcqs[i]->flags & ~IONIC_QCQ_F_INTR;
2918a34e25abSShannon Nelson 			err = ionic_qcq_alloc(lif, IONIC_QTYPE_TXQ, i, "tx", flags,
29190ec9f666SShannon Nelson 					      num_desc, desc_sz, comp_sz, sg_desc_sz,
2920a34e25abSShannon Nelson 					      lif->kern_pid, &tx_qcqs[i]);
2921a34e25abSShannon Nelson 			if (err)
2922a34e25abSShannon Nelson 				goto err_out;
2923a34e25abSShannon Nelson 		}
2924a34e25abSShannon Nelson 	}
2925a34e25abSShannon Nelson 
2926a34e25abSShannon Nelson 	if (rx_qcqs) {
29270ec9f666SShannon Nelson 		num_desc = qparam->nrxq_descs;
29280ec9f666SShannon Nelson 		desc_sz = sizeof(struct ionic_rxq_desc);
29290ec9f666SShannon Nelson 		comp_sz = sizeof(struct ionic_rxq_comp);
29300ec9f666SShannon Nelson 		sg_desc_sz = sizeof(struct ionic_rxq_sg_desc);
29310ec9f666SShannon Nelson 
29320ec9f666SShannon Nelson 		if (qparam->rxq_features & IONIC_Q_F_2X_CQ_DESC)
29330ec9f666SShannon Nelson 			comp_sz *= 2;
29340ec9f666SShannon Nelson 
2935101b40a0SShannon Nelson 		for (i = 0; i < qparam->nxqs; i++) {
293640bc471dSShannon Nelson 			/* If missing, short placeholder qcq needed for swap */
293740bc471dSShannon Nelson 			if (!lif->rxqcqs[i]) {
293840bc471dSShannon Nelson 				flags = IONIC_QCQ_F_RX_STATS | IONIC_QCQ_F_SG;
293940bc471dSShannon Nelson 				err = ionic_qcq_alloc(lif, IONIC_QTYPE_RXQ, i, "rx", flags,
294040bc471dSShannon Nelson 						      4, desc_sz, comp_sz, sg_desc_sz,
294140bc471dSShannon Nelson 						      lif->kern_pid, &lif->rxqcqs[i]);
294240bc471dSShannon Nelson 				if (err)
294340bc471dSShannon Nelson 					goto err_out;
294440bc471dSShannon Nelson 			}
294540bc471dSShannon Nelson 
2946a34e25abSShannon Nelson 			flags = lif->rxqcqs[i]->flags & ~IONIC_QCQ_F_INTR;
2947a34e25abSShannon Nelson 			err = ionic_qcq_alloc(lif, IONIC_QTYPE_RXQ, i, "rx", flags,
29480ec9f666SShannon Nelson 					      num_desc, desc_sz, comp_sz, sg_desc_sz,
2949a34e25abSShannon Nelson 					      lif->kern_pid, &rx_qcqs[i]);
2950a34e25abSShannon Nelson 			if (err)
2951a34e25abSShannon Nelson 				goto err_out;
29520ec9f666SShannon Nelson 
29530ec9f666SShannon Nelson 			rx_qcqs[i]->q.features = qparam->rxq_features;
2954a34e25abSShannon Nelson 		}
2955a34e25abSShannon Nelson 	}
2956a34e25abSShannon Nelson 
2957a34e25abSShannon Nelson 	/* stop and clean the queues */
2958a34e25abSShannon Nelson 	ionic_stop_queues_reconfig(lif);
2959a34e25abSShannon Nelson 
2960101b40a0SShannon Nelson 	if (qparam->nxqs != lif->nxqs) {
2961101b40a0SShannon Nelson 		err = netif_set_real_num_tx_queues(lif->netdev, qparam->nxqs);
2962101b40a0SShannon Nelson 		if (err)
2963101b40a0SShannon Nelson 			goto err_out_reinit_unlock;
2964101b40a0SShannon Nelson 		err = netif_set_real_num_rx_queues(lif->netdev, qparam->nxqs);
2965101b40a0SShannon Nelson 		if (err) {
2966101b40a0SShannon Nelson 			netif_set_real_num_tx_queues(lif->netdev, lif->nxqs);
2967101b40a0SShannon Nelson 			goto err_out_reinit_unlock;
2968101b40a0SShannon Nelson 		}
2969101b40a0SShannon Nelson 	}
2970101b40a0SShannon Nelson 
2971a34e25abSShannon Nelson 	/* swap new desc_info and rings, keeping existing interrupt config */
2972a34e25abSShannon Nelson 	if (tx_qcqs) {
2973a34e25abSShannon Nelson 		lif->ntxq_descs = qparam->ntxq_descs;
2974101b40a0SShannon Nelson 		for (i = 0; i < qparam->nxqs; i++)
2975a34e25abSShannon Nelson 			ionic_swap_queues(lif->txqcqs[i], tx_qcqs[i]);
2976a34e25abSShannon Nelson 	}
2977a34e25abSShannon Nelson 
2978a34e25abSShannon Nelson 	if (rx_qcqs) {
2979a34e25abSShannon Nelson 		lif->nrxq_descs = qparam->nrxq_descs;
2980101b40a0SShannon Nelson 		for (i = 0; i < qparam->nxqs; i++)
2981a34e25abSShannon Nelson 			ionic_swap_queues(lif->rxqcqs[i], rx_qcqs[i]);
2982a34e25abSShannon Nelson 	}
2983a34e25abSShannon Nelson 
2984101b40a0SShannon Nelson 	/* if we need to change the interrupt layout, this is the time */
2985101b40a0SShannon Nelson 	if (qparam->intr_split != test_bit(IONIC_LIF_F_SPLIT_INTR, lif->state) ||
2986101b40a0SShannon Nelson 	    qparam->nxqs != lif->nxqs) {
2987101b40a0SShannon Nelson 		if (qparam->intr_split) {
2988101b40a0SShannon Nelson 			set_bit(IONIC_LIF_F_SPLIT_INTR, lif->state);
2989101b40a0SShannon Nelson 		} else {
2990101b40a0SShannon Nelson 			clear_bit(IONIC_LIF_F_SPLIT_INTR, lif->state);
2991101b40a0SShannon Nelson 			lif->tx_coalesce_usecs = lif->rx_coalesce_usecs;
2992101b40a0SShannon Nelson 			lif->tx_coalesce_hw = lif->rx_coalesce_hw;
2993101b40a0SShannon Nelson 		}
2994101b40a0SShannon Nelson 
299540bc471dSShannon Nelson 		/* Clear existing interrupt assignments.  We check for NULL here
299640bc471dSShannon Nelson 		 * because we're checking the whole array for potential qcqs, not
299740bc471dSShannon Nelson 		 * just those qcqs that have just been set up.
299840bc471dSShannon Nelson 		 */
2999101b40a0SShannon Nelson 		for (i = 0; i < lif->ionic->ntxqs_per_lif; i++) {
300040bc471dSShannon Nelson 			if (lif->txqcqs[i])
3001101b40a0SShannon Nelson 				ionic_qcq_intr_free(lif, lif->txqcqs[i]);
300240bc471dSShannon Nelson 			if (lif->rxqcqs[i])
3003101b40a0SShannon Nelson 				ionic_qcq_intr_free(lif, lif->rxqcqs[i]);
3004101b40a0SShannon Nelson 		}
3005101b40a0SShannon Nelson 
3006101b40a0SShannon Nelson 		/* re-assign the interrupts */
3007101b40a0SShannon Nelson 		for (i = 0; i < qparam->nxqs; i++) {
3008101b40a0SShannon Nelson 			lif->rxqcqs[i]->flags |= IONIC_QCQ_F_INTR;
3009101b40a0SShannon Nelson 			err = ionic_alloc_qcq_interrupt(lif, lif->rxqcqs[i]);
3010101b40a0SShannon Nelson 			ionic_intr_coal_init(lif->ionic->idev.intr_ctrl,
3011101b40a0SShannon Nelson 					     lif->rxqcqs[i]->intr.index,
3012101b40a0SShannon Nelson 					     lif->rx_coalesce_hw);
3013101b40a0SShannon Nelson 
3014101b40a0SShannon Nelson 			if (qparam->intr_split) {
3015101b40a0SShannon Nelson 				lif->txqcqs[i]->flags |= IONIC_QCQ_F_INTR;
3016101b40a0SShannon Nelson 				err = ionic_alloc_qcq_interrupt(lif, lif->txqcqs[i]);
3017101b40a0SShannon Nelson 				ionic_intr_coal_init(lif->ionic->idev.intr_ctrl,
3018101b40a0SShannon Nelson 						     lif->txqcqs[i]->intr.index,
3019101b40a0SShannon Nelson 						     lif->tx_coalesce_hw);
302004a83459SShannon Nelson 				if (test_bit(IONIC_LIF_F_TX_DIM_INTR, lif->state))
302104a83459SShannon Nelson 					lif->txqcqs[i]->intr.dim_coal_hw = lif->tx_coalesce_hw;
3022101b40a0SShannon Nelson 			} else {
3023101b40a0SShannon Nelson 				lif->txqcqs[i]->flags &= ~IONIC_QCQ_F_INTR;
3024101b40a0SShannon Nelson 				ionic_link_qcq_interrupts(lif->rxqcqs[i], lif->txqcqs[i]);
3025101b40a0SShannon Nelson 			}
3026101b40a0SShannon Nelson 		}
3027101b40a0SShannon Nelson 	}
3028101b40a0SShannon Nelson 
3029ed6d9b02SShannon Nelson 	/* now we can rework the debugfs mappings */
3030ed6d9b02SShannon Nelson 	if (tx_qcqs) {
3031ed6d9b02SShannon Nelson 		for (i = 0; i < qparam->nxqs; i++) {
3032ed6d9b02SShannon Nelson 			ionic_debugfs_del_qcq(lif->txqcqs[i]);
3033ed6d9b02SShannon Nelson 			ionic_debugfs_add_qcq(lif, lif->txqcqs[i]);
3034ed6d9b02SShannon Nelson 		}
3035ed6d9b02SShannon Nelson 	}
3036ed6d9b02SShannon Nelson 
3037ed6d9b02SShannon Nelson 	if (rx_qcqs) {
3038ed6d9b02SShannon Nelson 		for (i = 0; i < qparam->nxqs; i++) {
3039ed6d9b02SShannon Nelson 			ionic_debugfs_del_qcq(lif->rxqcqs[i]);
3040ed6d9b02SShannon Nelson 			ionic_debugfs_add_qcq(lif, lif->rxqcqs[i]);
3041ed6d9b02SShannon Nelson 		}
3042ed6d9b02SShannon Nelson 	}
3043ed6d9b02SShannon Nelson 
3044101b40a0SShannon Nelson 	swap(lif->nxqs, qparam->nxqs);
30450ec9f666SShannon Nelson 	swap(lif->rxq_features, qparam->rxq_features);
3046101b40a0SShannon Nelson 
3047101b40a0SShannon Nelson err_out_reinit_unlock:
304825cc5a5fSShannon Nelson 	/* re-init the queues, but don't lose an error code */
3049101b40a0SShannon Nelson 	if (err)
3050101b40a0SShannon Nelson 		ionic_start_queues_reconfig(lif);
3051101b40a0SShannon Nelson 	else
3052a34e25abSShannon Nelson 		err = ionic_start_queues_reconfig(lif);
3053a34e25abSShannon Nelson 
3054a34e25abSShannon Nelson err_out:
3055a34e25abSShannon Nelson 	/* free old allocs without cleaning intr */
3056101b40a0SShannon Nelson 	for (i = 0; i < qparam->nxqs; i++) {
3057a34e25abSShannon Nelson 		if (tx_qcqs && tx_qcqs[i]) {
3058a34e25abSShannon Nelson 			tx_qcqs[i]->flags &= ~IONIC_QCQ_F_INTR;
3059a34e25abSShannon Nelson 			ionic_qcq_free(lif, tx_qcqs[i]);
3060101b40a0SShannon Nelson 			devm_kfree(lif->ionic->dev, tx_qcqs[i]);
3061a34e25abSShannon Nelson 			tx_qcqs[i] = NULL;
3062a34e25abSShannon Nelson 		}
3063a34e25abSShannon Nelson 		if (rx_qcqs && rx_qcqs[i]) {
3064a34e25abSShannon Nelson 			rx_qcqs[i]->flags &= ~IONIC_QCQ_F_INTR;
3065a34e25abSShannon Nelson 			ionic_qcq_free(lif, rx_qcqs[i]);
3066101b40a0SShannon Nelson 			devm_kfree(lif->ionic->dev, rx_qcqs[i]);
3067a34e25abSShannon Nelson 			rx_qcqs[i] = NULL;
3068a34e25abSShannon Nelson 		}
3069a34e25abSShannon Nelson 	}
3070a34e25abSShannon Nelson 
3071a34e25abSShannon Nelson 	/* free q array */
3072a34e25abSShannon Nelson 	if (rx_qcqs) {
3073a34e25abSShannon Nelson 		devm_kfree(lif->ionic->dev, rx_qcqs);
3074a34e25abSShannon Nelson 		rx_qcqs = NULL;
3075a34e25abSShannon Nelson 	}
3076a34e25abSShannon Nelson 	if (tx_qcqs) {
3077a34e25abSShannon Nelson 		devm_kfree(lif->ionic->dev, tx_qcqs);
3078a34e25abSShannon Nelson 		tx_qcqs = NULL;
3079a34e25abSShannon Nelson 	}
3080a34e25abSShannon Nelson 
3081101b40a0SShannon Nelson 	/* clean the unused dma and info allocations when new set is smaller
3082101b40a0SShannon Nelson 	 * than the full array, but leave the qcq shells in place
3083101b40a0SShannon Nelson 	 */
3084101b40a0SShannon Nelson 	for (i = lif->nxqs; i < lif->ionic->ntxqs_per_lif; i++) {
3085aa1d7e12SBrett Creeley 		if (lif->txqcqs && lif->txqcqs[i]) {
3086101b40a0SShannon Nelson 			lif->txqcqs[i]->flags &= ~IONIC_QCQ_F_INTR;
3087101b40a0SShannon Nelson 			ionic_qcq_free(lif, lif->txqcqs[i]);
3088aa1d7e12SBrett Creeley 		}
3089101b40a0SShannon Nelson 
3090aa1d7e12SBrett Creeley 		if (lif->rxqcqs && lif->rxqcqs[i]) {
3091101b40a0SShannon Nelson 			lif->rxqcqs[i]->flags &= ~IONIC_QCQ_F_INTR;
3092101b40a0SShannon Nelson 			ionic_qcq_free(lif, lif->rxqcqs[i]);
3093101b40a0SShannon Nelson 		}
3094aa1d7e12SBrett Creeley 	}
3095101b40a0SShannon Nelson 
3096e7f52aa4SShannon Nelson 	if (err)
3097e7f52aa4SShannon Nelson 		netdev_info(lif->netdev, "%s: failed %d\n", __func__, err);
3098e7f52aa4SShannon Nelson 
3099a34e25abSShannon Nelson 	return err;
3100a34e25abSShannon Nelson }
3101a34e25abSShannon Nelson 
ionic_lif_alloc(struct ionic * ionic)310230b87ab4SShannon Nelson int ionic_lif_alloc(struct ionic *ionic)
31031a58e196SShannon Nelson {
31041a58e196SShannon Nelson 	struct device *dev = ionic->dev;
31054b03b273SShannon Nelson 	union ionic_lif_identity *lid;
31061a58e196SShannon Nelson 	struct net_device *netdev;
31071a58e196SShannon Nelson 	struct ionic_lif *lif;
3108aa319881SShannon Nelson 	int tbl_sz;
31091a58e196SShannon Nelson 	int err;
31101a58e196SShannon Nelson 
31114b03b273SShannon Nelson 	lid = kzalloc(sizeof(*lid), GFP_KERNEL);
31124b03b273SShannon Nelson 	if (!lid)
311330b87ab4SShannon Nelson 		return -ENOMEM;
31144b03b273SShannon Nelson 
31151a58e196SShannon Nelson 	netdev = alloc_etherdev_mqs(sizeof(*lif),
31161a58e196SShannon Nelson 				    ionic->ntxqs_per_lif, ionic->ntxqs_per_lif);
31171a58e196SShannon Nelson 	if (!netdev) {
31181a58e196SShannon Nelson 		dev_err(dev, "Cannot allocate netdev, aborting\n");
31194b1debbeSColin Ian King 		err = -ENOMEM;
31204b1debbeSColin Ian King 		goto err_out_free_lid;
31211a58e196SShannon Nelson 	}
31221a58e196SShannon Nelson 
31231a58e196SShannon Nelson 	SET_NETDEV_DEV(netdev, dev);
31241a58e196SShannon Nelson 
31251a58e196SShannon Nelson 	lif = netdev_priv(netdev);
31261a58e196SShannon Nelson 	lif->netdev = netdev;
312730b87ab4SShannon Nelson 	ionic->lif = lif;
3128beead698SShannon Nelson 	netdev->netdev_ops = &ionic_netdev_ops;
31294d03e00aSShannon Nelson 	ionic_ethtool_set_ops(netdev);
3130beead698SShannon Nelson 
3131beead698SShannon Nelson 	netdev->watchdog_timeo = 2 * HZ;
3132aa47b540SShannon Nelson 	netif_carrier_off(netdev);
3133aa47b540SShannon Nelson 
31344b03b273SShannon Nelson 	lif->identity = lid;
31354b03b273SShannon Nelson 	lif->lif_type = IONIC_LIF_TYPE_CLASSIC;
3136bb9f80f3SShannon Nelson 	err = ionic_lif_identify(ionic, lif->lif_type, lif->identity);
3137bb9f80f3SShannon Nelson 	if (err) {
3138bb9f80f3SShannon Nelson 		dev_err(ionic->dev, "Cannot identify type %d: %d\n",
3139bb9f80f3SShannon Nelson 			lif->lif_type, err);
3140bb9f80f3SShannon Nelson 		goto err_out_free_netdev;
3141bb9f80f3SShannon Nelson 	}
3142eba87609SShannon Nelson 	lif->netdev->min_mtu = max_t(unsigned int, ETH_MIN_MTU,
3143eba87609SShannon Nelson 				     le32_to_cpu(lif->identity->eth.min_frame_size));
31444b03b273SShannon Nelson 	lif->netdev->max_mtu =
31454b03b273SShannon Nelson 		le32_to_cpu(lif->identity->eth.max_frame_size) - ETH_HLEN - VLAN_HLEN;
31461a58e196SShannon Nelson 
31471a58e196SShannon Nelson 	lif->neqs = ionic->neqs_per_lif;
31481a58e196SShannon Nelson 	lif->nxqs = ionic->ntxqs_per_lif;
31491a58e196SShannon Nelson 
31501a58e196SShannon Nelson 	lif->ionic = ionic;
315130b87ab4SShannon Nelson 	lif->index = 0;
3152c0b03e83SShannon Nelson 
3153c0b03e83SShannon Nelson 	if (is_kdump_kernel()) {
3154c0b03e83SShannon Nelson 		lif->ntxq_descs = IONIC_MIN_TXRX_DESC;
3155c0b03e83SShannon Nelson 		lif->nrxq_descs = IONIC_MIN_TXRX_DESC;
3156c0b03e83SShannon Nelson 	} else {
31570f3154e6SShannon Nelson 		lif->ntxq_descs = IONIC_DEF_TXRX_DESC;
31580f3154e6SShannon Nelson 		lif->nrxq_descs = IONIC_DEF_TXRX_DESC;
3159c0b03e83SShannon Nelson 	}
31601a58e196SShannon Nelson 
31618c15440bSShannon Nelson 	/* Convert the default coalesce value to actual hw resolution */
3162780eded3SShannon Nelson 	lif->rx_coalesce_usecs = IONIC_ITR_COAL_USEC_DEFAULT;
3163ff7ebed9SShannon Nelson 	lif->rx_coalesce_hw = ionic_coal_usec_to_hw(lif->ionic,
3164780eded3SShannon Nelson 						    lif->rx_coalesce_usecs);
3165fe8c30b5SShannon Nelson 	lif->tx_coalesce_usecs = lif->rx_coalesce_usecs;
3166fe8c30b5SShannon Nelson 	lif->tx_coalesce_hw = lif->rx_coalesce_hw;
316704a83459SShannon Nelson 	set_bit(IONIC_LIF_F_RX_DIM_INTR, lif->state);
316804a83459SShannon Nelson 	set_bit(IONIC_LIF_F_TX_DIM_INTR, lif->state);
31698c15440bSShannon Nelson 
317030b87ab4SShannon Nelson 	snprintf(lif->name, sizeof(lif->name), "lif%u", lif->index);
31711a58e196SShannon Nelson 
317226671ff9SShannon Nelson 	mutex_init(&lif->queue_lock);
317326671ff9SShannon Nelson 	mutex_init(&lif->config_lock);
317426671ff9SShannon Nelson 
31751d062b7bSShannon Nelson 	spin_lock_init(&lif->adminq_lock);
31761d062b7bSShannon Nelson 
31772a654540SShannon Nelson 	spin_lock_init(&lif->deferred.lock);
31782a654540SShannon Nelson 	INIT_LIST_HEAD(&lif->deferred.list);
31792a654540SShannon Nelson 	INIT_WORK(&lif->deferred.work, ionic_lif_deferred_work);
31802a654540SShannon Nelson 
31811a58e196SShannon Nelson 	/* allocate lif info */
31821a58e196SShannon Nelson 	lif->info_sz = ALIGN(sizeof(*lif->info), PAGE_SIZE);
31831a58e196SShannon Nelson 	lif->info = dma_alloc_coherent(dev, lif->info_sz,
31841a58e196SShannon Nelson 				       &lif->info_pa, GFP_KERNEL);
31851a58e196SShannon Nelson 	if (!lif->info) {
31861a58e196SShannon Nelson 		dev_err(dev, "Failed to allocate lif info, aborting\n");
31871a58e196SShannon Nelson 		err = -ENOMEM;
318826671ff9SShannon Nelson 		goto err_out_free_mutex;
31891a58e196SShannon Nelson 	}
31901a58e196SShannon Nelson 
31912a8c2c1aSShannon Nelson 	ionic_debugfs_add_lif(lif);
31922a8c2c1aSShannon Nelson 
319330b87ab4SShannon Nelson 	/* allocate control queues and txrx queue arrays */
319430b87ab4SShannon Nelson 	ionic_lif_queue_identify(lif);
31951d062b7bSShannon Nelson 	err = ionic_qcqs_alloc(lif);
31961d062b7bSShannon Nelson 	if (err)
31971d062b7bSShannon Nelson 		goto err_out_free_lif_info;
31981d062b7bSShannon Nelson 
3199aa319881SShannon Nelson 	/* allocate rss indirection table */
3200aa319881SShannon Nelson 	tbl_sz = le16_to_cpu(lif->ionic->ident.lif.eth.rss_ind_tbl_sz);
3201aa319881SShannon Nelson 	lif->rss_ind_tbl_sz = sizeof(*lif->rss_ind_tbl) * tbl_sz;
3202aa319881SShannon Nelson 	lif->rss_ind_tbl = dma_alloc_coherent(dev, lif->rss_ind_tbl_sz,
3203aa319881SShannon Nelson 					      &lif->rss_ind_tbl_pa,
3204aa319881SShannon Nelson 					      GFP_KERNEL);
3205aa319881SShannon Nelson 
3206aa319881SShannon Nelson 	if (!lif->rss_ind_tbl) {
320773a63ee9SDan Carpenter 		err = -ENOMEM;
3208aa319881SShannon Nelson 		dev_err(dev, "Failed to allocate rss indirection table, aborting\n");
3209aa319881SShannon Nelson 		goto err_out_free_qcqs;
3210aa319881SShannon Nelson 	}
3211ffac2027SShannon Nelson 	netdev_rss_key_fill(lif->rss_hash_key, IONIC_RSS_HASH_KEY_SIZE);
3212aa319881SShannon Nelson 
3213f0790bcdSShannon Nelson 	ionic_lif_alloc_phc(lif);
3214f0790bcdSShannon Nelson 
321530b87ab4SShannon Nelson 	return 0;
32161a58e196SShannon Nelson 
3217aa319881SShannon Nelson err_out_free_qcqs:
3218aa319881SShannon Nelson 	ionic_qcqs_free(lif);
32191d062b7bSShannon Nelson err_out_free_lif_info:
32201d062b7bSShannon Nelson 	dma_free_coherent(dev, lif->info_sz, lif->info, lif->info_pa);
32211d062b7bSShannon Nelson 	lif->info = NULL;
32221d062b7bSShannon Nelson 	lif->info_pa = 0;
322326671ff9SShannon Nelson err_out_free_mutex:
322426671ff9SShannon Nelson 	mutex_destroy(&lif->config_lock);
322526671ff9SShannon Nelson 	mutex_destroy(&lif->queue_lock);
32261a58e196SShannon Nelson err_out_free_netdev:
32271a58e196SShannon Nelson 	free_netdev(lif->netdev);
32281a58e196SShannon Nelson 	lif = NULL;
32294b1debbeSColin Ian King err_out_free_lid:
32304b03b273SShannon Nelson 	kfree(lid);
32311a58e196SShannon Nelson 
323230b87ab4SShannon Nelson 	return err;
32331a58e196SShannon Nelson }
32341a58e196SShannon Nelson 
ionic_lif_reset(struct ionic_lif * lif)32351a58e196SShannon Nelson static void ionic_lif_reset(struct ionic_lif *lif)
32361a58e196SShannon Nelson {
32371a58e196SShannon Nelson 	struct ionic_dev *idev = &lif->ionic->idev;
32381a58e196SShannon Nelson 
32395e7213caSShannon Nelson 	if (!ionic_is_fw_running(idev))
32405e7213caSShannon Nelson 		return;
32415e7213caSShannon Nelson 
32421a58e196SShannon Nelson 	mutex_lock(&lif->ionic->dev_cmd_lock);
32431a58e196SShannon Nelson 	ionic_dev_cmd_lif_reset(idev, lif->index);
32441a58e196SShannon Nelson 	ionic_dev_cmd_wait(lif->ionic, DEVCMD_TIMEOUT);
32451a58e196SShannon Nelson 	mutex_unlock(&lif->ionic->dev_cmd_lock);
32461a58e196SShannon Nelson }
32471a58e196SShannon Nelson 
ionic_lif_handle_fw_down(struct ionic_lif * lif)3248c672412fSShannon Nelson static void ionic_lif_handle_fw_down(struct ionic_lif *lif)
3249c672412fSShannon Nelson {
3250c672412fSShannon Nelson 	struct ionic *ionic = lif->ionic;
3251c672412fSShannon Nelson 
3252c672412fSShannon Nelson 	if (test_and_set_bit(IONIC_LIF_F_FW_RESET, lif->state))
3253c672412fSShannon Nelson 		return;
3254c672412fSShannon Nelson 
3255c672412fSShannon Nelson 	dev_info(ionic->dev, "FW Down: Stopping LIFs\n");
3256c672412fSShannon Nelson 
3257c672412fSShannon Nelson 	netif_device_detach(lif->netdev);
3258c672412fSShannon Nelson 
32592624d959SShannon Nelson 	mutex_lock(&lif->queue_lock);
3260c672412fSShannon Nelson 	if (test_bit(IONIC_LIF_F_UP, lif->state)) {
3261c672412fSShannon Nelson 		dev_info(ionic->dev, "Surprise FW stop, stopping queues\n");
3262c672412fSShannon Nelson 		ionic_stop_queues(lif);
3263c672412fSShannon Nelson 	}
3264c672412fSShannon Nelson 
3265c672412fSShannon Nelson 	if (netif_running(lif->netdev)) {
3266c672412fSShannon Nelson 		ionic_txrx_deinit(lif);
3267c672412fSShannon Nelson 		ionic_txrx_free(lif);
3268c672412fSShannon Nelson 	}
326930b87ab4SShannon Nelson 	ionic_lif_deinit(lif);
32706bc977faSShannon Nelson 	ionic_reset(ionic);
3271c672412fSShannon Nelson 	ionic_qcqs_free(lif);
3272c672412fSShannon Nelson 
32732624d959SShannon Nelson 	mutex_unlock(&lif->queue_lock);
32742624d959SShannon Nelson 
3275398d1e37SShannon Nelson 	clear_bit(IONIC_LIF_F_FW_STOPPING, lif->state);
3276c672412fSShannon Nelson 	dev_info(ionic->dev, "FW Down: LIFs stopped\n");
3277c672412fSShannon Nelson }
3278c672412fSShannon Nelson 
ionic_restart_lif(struct ionic_lif * lif)3279a79b559eSShannon Nelson int ionic_restart_lif(struct ionic_lif *lif)
3280c672412fSShannon Nelson {
3281c672412fSShannon Nelson 	struct ionic *ionic = lif->ionic;
3282c672412fSShannon Nelson 	int err;
3283c672412fSShannon Nelson 
32842624d959SShannon Nelson 	mutex_lock(&lif->queue_lock);
32852624d959SShannon Nelson 
32869cb9dadbSShannon Nelson 	if (test_and_clear_bit(IONIC_LIF_F_BROKEN, lif->state))
32879cb9dadbSShannon Nelson 		dev_info(ionic->dev, "FW Up: clearing broken state\n");
32889cb9dadbSShannon Nelson 
3289c672412fSShannon Nelson 	err = ionic_qcqs_alloc(lif);
3290c672412fSShannon Nelson 	if (err)
32912624d959SShannon Nelson 		goto err_unlock;
3292c672412fSShannon Nelson 
329330b87ab4SShannon Nelson 	err = ionic_lif_init(lif);
3294c672412fSShannon Nelson 	if (err)
3295c672412fSShannon Nelson 		goto err_qcqs_free;
3296c672412fSShannon Nelson 
3297db28adf9SShannon Nelson 	ionic_vf_attr_replay(lif);
3298db28adf9SShannon Nelson 
3299c672412fSShannon Nelson 	if (lif->registered)
3300c672412fSShannon Nelson 		ionic_lif_set_netdev_info(lif);
3301c672412fSShannon Nelson 
33027e4d4759SShannon Nelson 	ionic_rx_filter_replay(lif);
33037e4d4759SShannon Nelson 
3304c672412fSShannon Nelson 	if (netif_running(lif->netdev)) {
3305c672412fSShannon Nelson 		err = ionic_txrx_alloc(lif);
3306c672412fSShannon Nelson 		if (err)
3307c672412fSShannon Nelson 			goto err_lifs_deinit;
3308c672412fSShannon Nelson 
3309c672412fSShannon Nelson 		err = ionic_txrx_init(lif);
3310c672412fSShannon Nelson 		if (err)
3311c672412fSShannon Nelson 			goto err_txrx_free;
3312c672412fSShannon Nelson 	}
3313c672412fSShannon Nelson 
33142624d959SShannon Nelson 	mutex_unlock(&lif->queue_lock);
33152624d959SShannon Nelson 
3316c672412fSShannon Nelson 	clear_bit(IONIC_LIF_F_FW_RESET, lif->state);
331725cc5a5fSShannon Nelson 	ionic_link_status_check_request(lif, CAN_SLEEP);
3318c672412fSShannon Nelson 	netif_device_attach(lif->netdev);
3319c672412fSShannon Nelson 
332030d2e073SShannon Nelson 	return 0;
3321c672412fSShannon Nelson 
3322c672412fSShannon Nelson err_txrx_free:
3323c672412fSShannon Nelson 	ionic_txrx_free(lif);
3324c672412fSShannon Nelson err_lifs_deinit:
332530b87ab4SShannon Nelson 	ionic_lif_deinit(lif);
3326c672412fSShannon Nelson err_qcqs_free:
3327c672412fSShannon Nelson 	ionic_qcqs_free(lif);
33282624d959SShannon Nelson err_unlock:
33292624d959SShannon Nelson 	mutex_unlock(&lif->queue_lock);
333030d2e073SShannon Nelson 
333130d2e073SShannon Nelson 	return err;
333230d2e073SShannon Nelson }
333330d2e073SShannon Nelson 
ionic_lif_handle_fw_up(struct ionic_lif * lif)333430d2e073SShannon Nelson static void ionic_lif_handle_fw_up(struct ionic_lif *lif)
333530d2e073SShannon Nelson {
333630d2e073SShannon Nelson 	struct ionic *ionic = lif->ionic;
333730d2e073SShannon Nelson 	int err;
333830d2e073SShannon Nelson 
333930d2e073SShannon Nelson 	if (!test_bit(IONIC_LIF_F_FW_RESET, lif->state))
334030d2e073SShannon Nelson 		return;
334130d2e073SShannon Nelson 
334230d2e073SShannon Nelson 	dev_info(ionic->dev, "FW Up: restarting LIFs\n");
334330d2e073SShannon Nelson 
334430d2e073SShannon Nelson 	/* This is a little different from what happens at
334530d2e073SShannon Nelson 	 * probe time because the LIF already exists so we
334630d2e073SShannon Nelson 	 * just need to reanimate it.
334730d2e073SShannon Nelson 	 */
334830d2e073SShannon Nelson 	ionic_init_devinfo(ionic);
334930d2e073SShannon Nelson 	err = ionic_identify(ionic);
335030d2e073SShannon Nelson 	if (err)
335130d2e073SShannon Nelson 		goto err_out;
335230d2e073SShannon Nelson 	err = ionic_port_identify(ionic);
335330d2e073SShannon Nelson 	if (err)
335430d2e073SShannon Nelson 		goto err_out;
335530d2e073SShannon Nelson 	err = ionic_port_init(ionic);
335630d2e073SShannon Nelson 	if (err)
335730d2e073SShannon Nelson 		goto err_out;
335830d2e073SShannon Nelson 
335930d2e073SShannon Nelson 	err = ionic_restart_lif(lif);
336030d2e073SShannon Nelson 	if (err)
336130d2e073SShannon Nelson 		goto err_out;
336230d2e073SShannon Nelson 
336330d2e073SShannon Nelson 	dev_info(ionic->dev, "FW Up: LIFs restarted\n");
336430d2e073SShannon Nelson 
336530d2e073SShannon Nelson 	/* restore the hardware timestamping queues */
336630d2e073SShannon Nelson 	ionic_lif_hwstamp_replay(lif);
336730d2e073SShannon Nelson 
336830d2e073SShannon Nelson 	return;
336930d2e073SShannon Nelson 
3370c672412fSShannon Nelson err_out:
3371c672412fSShannon Nelson 	dev_err(ionic->dev, "FW Up: LIFs restart failed - err %d\n", err);
3372c672412fSShannon Nelson }
3373c672412fSShannon Nelson 
ionic_lif_free(struct ionic_lif * lif)337430b87ab4SShannon Nelson void ionic_lif_free(struct ionic_lif *lif)
33751a58e196SShannon Nelson {
33761a58e196SShannon Nelson 	struct device *dev = lif->ionic->dev;
33771a58e196SShannon Nelson 
3378f0790bcdSShannon Nelson 	ionic_lif_free_phc(lif);
3379f0790bcdSShannon Nelson 
3380aa319881SShannon Nelson 	/* free rss indirection table */
3381aa319881SShannon Nelson 	dma_free_coherent(dev, lif->rss_ind_tbl_sz, lif->rss_ind_tbl,
3382aa319881SShannon Nelson 			  lif->rss_ind_tbl_pa);
3383aa319881SShannon Nelson 	lif->rss_ind_tbl = NULL;
3384aa319881SShannon Nelson 	lif->rss_ind_tbl_pa = 0;
3385aa319881SShannon Nelson 
33861d062b7bSShannon Nelson 	/* free queues */
33871d062b7bSShannon Nelson 	ionic_qcqs_free(lif);
3388c672412fSShannon Nelson 	if (!test_bit(IONIC_LIF_F_FW_RESET, lif->state))
33891a58e196SShannon Nelson 		ionic_lif_reset(lif);
33901a58e196SShannon Nelson 
33911a58e196SShannon Nelson 	/* free lif info */
33924b03b273SShannon Nelson 	kfree(lif->identity);
33931a58e196SShannon Nelson 	dma_free_coherent(dev, lif->info_sz, lif->info, lif->info_pa);
33941a58e196SShannon Nelson 	lif->info = NULL;
33951a58e196SShannon Nelson 	lif->info_pa = 0;
33961a58e196SShannon Nelson 
33976461b446SShannon Nelson 	/* unmap doorbell page */
33986461b446SShannon Nelson 	ionic_bus_unmap_dbpage(lif->ionic, lif->kern_dbpage);
33996461b446SShannon Nelson 	lif->kern_dbpage = NULL;
34006461b446SShannon Nelson 
340126671ff9SShannon Nelson 	mutex_destroy(&lif->config_lock);
340226671ff9SShannon Nelson 	mutex_destroy(&lif->queue_lock);
340326671ff9SShannon Nelson 
34041a58e196SShannon Nelson 	/* free netdev & lif */
34051a58e196SShannon Nelson 	ionic_debugfs_del_lif(lif);
34061a58e196SShannon Nelson 	free_netdev(lif->netdev);
34071a58e196SShannon Nelson }
34081a58e196SShannon Nelson 
ionic_lif_deinit(struct ionic_lif * lif)340930b87ab4SShannon Nelson void ionic_lif_deinit(struct ionic_lif *lif)
34101a58e196SShannon Nelson {
3411c672412fSShannon Nelson 	if (!test_and_clear_bit(IONIC_LIF_F_INITED, lif->state))
34121a58e196SShannon Nelson 		return;
34131a58e196SShannon Nelson 
3414c672412fSShannon Nelson 	if (!test_bit(IONIC_LIF_F_FW_RESET, lif->state)) {
3415c672412fSShannon Nelson 		cancel_work_sync(&lif->deferred.work);
3416c672412fSShannon Nelson 		cancel_work_sync(&lif->tx_timeout_work);
34177e4d4759SShannon Nelson 		ionic_rx_filters_deinit(lif);
3418ad6fd4d3SShannon Nelson 		if (lif->netdev->features & NETIF_F_RXHASH)
3419aa319881SShannon Nelson 			ionic_lif_rss_deinit(lif);
3420bdff4666SShannon Nelson 	}
3421c1e329ebSShannon Nelson 
34221d062b7bSShannon Nelson 	napi_disable(&lif->adminqcq->napi);
342377ceb68eSShannon Nelson 	ionic_lif_qcq_deinit(lif, lif->notifyqcq);
34241d062b7bSShannon Nelson 	ionic_lif_qcq_deinit(lif, lif->adminqcq);
34251d062b7bSShannon Nelson 
34261a58e196SShannon Nelson 	ionic_lif_reset(lif);
34271a58e196SShannon Nelson }
34281a58e196SShannon Nelson 
ionic_lif_adminq_init(struct ionic_lif * lif)34291d062b7bSShannon Nelson static int ionic_lif_adminq_init(struct ionic_lif *lif)
34301d062b7bSShannon Nelson {
34311d062b7bSShannon Nelson 	struct device *dev = lif->ionic->dev;
34321d062b7bSShannon Nelson 	struct ionic_q_init_comp comp;
34331d062b7bSShannon Nelson 	struct ionic_dev *idev;
34341d062b7bSShannon Nelson 	struct ionic_qcq *qcq;
34351d062b7bSShannon Nelson 	struct ionic_queue *q;
34361d062b7bSShannon Nelson 	int err;
34371d062b7bSShannon Nelson 
34381d062b7bSShannon Nelson 	idev = &lif->ionic->idev;
34391d062b7bSShannon Nelson 	qcq = lif->adminqcq;
34401d062b7bSShannon Nelson 	q = &qcq->q;
34411d062b7bSShannon Nelson 
34421d062b7bSShannon Nelson 	mutex_lock(&lif->ionic->dev_cmd_lock);
34431d062b7bSShannon Nelson 	ionic_dev_cmd_adminq_init(idev, qcq, lif->index, qcq->intr.index);
34441d062b7bSShannon Nelson 	err = ionic_dev_cmd_wait(lif->ionic, DEVCMD_TIMEOUT);
34451d062b7bSShannon Nelson 	ionic_dev_cmd_comp(idev, (union ionic_dev_cmd_comp *)&comp);
34461d062b7bSShannon Nelson 	mutex_unlock(&lif->ionic->dev_cmd_lock);
34471d062b7bSShannon Nelson 	if (err) {
34481d062b7bSShannon Nelson 		netdev_err(lif->netdev, "adminq init failed %d\n", err);
34491d062b7bSShannon Nelson 		return err;
34501d062b7bSShannon Nelson 	}
34511d062b7bSShannon Nelson 
34521d062b7bSShannon Nelson 	q->hw_type = comp.hw_type;
34531d062b7bSShannon Nelson 	q->hw_index = le32_to_cpu(comp.hw_index);
34541d062b7bSShannon Nelson 	q->dbval = IONIC_DBELL_QID(q->hw_index);
34551d062b7bSShannon Nelson 
34561d062b7bSShannon Nelson 	dev_dbg(dev, "adminq->hw_type %d\n", q->hw_type);
34571d062b7bSShannon Nelson 	dev_dbg(dev, "adminq->hw_index %d\n", q->hw_index);
34581d062b7bSShannon Nelson 
3459b69585bfSAllen Hubbe 	q->dbell_deadline = IONIC_ADMIN_DOORBELL_DEADLINE;
3460b69585bfSAllen Hubbe 	q->dbell_jiffies = jiffies;
3461b69585bfSAllen Hubbe 
3462b48b89f9SJakub Kicinski 	netif_napi_add(lif->netdev, &qcq->napi, ionic_adminq_napi);
34631d062b7bSShannon Nelson 
3464b69585bfSAllen Hubbe 	qcq->napi_qcq = qcq;
3465b69585bfSAllen Hubbe 	timer_setup(&qcq->napi_deadline, ionic_napi_deadline, 0);
3466b69585bfSAllen Hubbe 
34671d062b7bSShannon Nelson 	napi_enable(&qcq->napi);
34681d062b7bSShannon Nelson 
3469b8dccb25SShannon Nelson 	if (qcq->flags & IONIC_QCQ_F_INTR) {
3470b8dccb25SShannon Nelson 		irq_set_affinity_hint(qcq->intr.vector,
3471b8dccb25SShannon Nelson 				      &qcq->intr.affinity_mask);
34721d062b7bSShannon Nelson 		ionic_intr_mask(idev->intr_ctrl, qcq->intr.index,
34731d062b7bSShannon Nelson 				IONIC_INTR_MASK_CLEAR);
3474b8dccb25SShannon Nelson 	}
34751d062b7bSShannon Nelson 
34761d062b7bSShannon Nelson 	qcq->flags |= IONIC_QCQ_F_INITED;
34771d062b7bSShannon Nelson 
34781d062b7bSShannon Nelson 	return 0;
34791d062b7bSShannon Nelson }
34801d062b7bSShannon Nelson 
ionic_lif_notifyq_init(struct ionic_lif * lif)348177ceb68eSShannon Nelson static int ionic_lif_notifyq_init(struct ionic_lif *lif)
348277ceb68eSShannon Nelson {
348377ceb68eSShannon Nelson 	struct ionic_qcq *qcq = lif->notifyqcq;
348477ceb68eSShannon Nelson 	struct device *dev = lif->ionic->dev;
348577ceb68eSShannon Nelson 	struct ionic_queue *q = &qcq->q;
348677ceb68eSShannon Nelson 	int err;
348777ceb68eSShannon Nelson 
348877ceb68eSShannon Nelson 	struct ionic_admin_ctx ctx = {
348977ceb68eSShannon Nelson 		.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
349077ceb68eSShannon Nelson 		.cmd.q_init = {
349177ceb68eSShannon Nelson 			.opcode = IONIC_CMD_Q_INIT,
349277ceb68eSShannon Nelson 			.lif_index = cpu_to_le16(lif->index),
349377ceb68eSShannon Nelson 			.type = q->type,
34945b3f3f2aSShannon Nelson 			.ver = lif->qtype_info[q->type].version,
349577ceb68eSShannon Nelson 			.index = cpu_to_le32(q->index),
349677ceb68eSShannon Nelson 			.flags = cpu_to_le16(IONIC_QINIT_F_IRQ |
349777ceb68eSShannon Nelson 					     IONIC_QINIT_F_ENA),
349877ceb68eSShannon Nelson 			.intr_index = cpu_to_le16(lif->adminqcq->intr.index),
349977ceb68eSShannon Nelson 			.pid = cpu_to_le16(q->pid),
350077ceb68eSShannon Nelson 			.ring_size = ilog2(q->num_descs),
350177ceb68eSShannon Nelson 			.ring_base = cpu_to_le64(q->base_pa),
350277ceb68eSShannon Nelson 		}
350377ceb68eSShannon Nelson 	};
350477ceb68eSShannon Nelson 
350577ceb68eSShannon Nelson 	dev_dbg(dev, "notifyq_init.pid %d\n", ctx.cmd.q_init.pid);
350677ceb68eSShannon Nelson 	dev_dbg(dev, "notifyq_init.index %d\n", ctx.cmd.q_init.index);
350777ceb68eSShannon Nelson 	dev_dbg(dev, "notifyq_init.ring_base 0x%llx\n", ctx.cmd.q_init.ring_base);
350877ceb68eSShannon Nelson 	dev_dbg(dev, "notifyq_init.ring_size %d\n", ctx.cmd.q_init.ring_size);
350977ceb68eSShannon Nelson 
351077ceb68eSShannon Nelson 	err = ionic_adminq_post_wait(lif, &ctx);
351177ceb68eSShannon Nelson 	if (err)
351277ceb68eSShannon Nelson 		return err;
351377ceb68eSShannon Nelson 
3514c672412fSShannon Nelson 	lif->last_eid = 0;
351577ceb68eSShannon Nelson 	q->hw_type = ctx.comp.q_init.hw_type;
351677ceb68eSShannon Nelson 	q->hw_index = le32_to_cpu(ctx.comp.q_init.hw_index);
351777ceb68eSShannon Nelson 	q->dbval = IONIC_DBELL_QID(q->hw_index);
351877ceb68eSShannon Nelson 
351977ceb68eSShannon Nelson 	dev_dbg(dev, "notifyq->hw_type %d\n", q->hw_type);
352077ceb68eSShannon Nelson 	dev_dbg(dev, "notifyq->hw_index %d\n", q->hw_index);
352177ceb68eSShannon Nelson 
352277ceb68eSShannon Nelson 	/* preset the callback info */
352377ceb68eSShannon Nelson 	q->info[0].cb_arg = lif;
352477ceb68eSShannon Nelson 
352577ceb68eSShannon Nelson 	qcq->flags |= IONIC_QCQ_F_INITED;
352677ceb68eSShannon Nelson 
352777ceb68eSShannon Nelson 	return 0;
352877ceb68eSShannon Nelson }
352977ceb68eSShannon Nelson 
ionic_station_set(struct ionic_lif * lif)35302a654540SShannon Nelson static int ionic_station_set(struct ionic_lif *lif)
35312a654540SShannon Nelson {
35322a654540SShannon Nelson 	struct net_device *netdev = lif->netdev;
35332a654540SShannon Nelson 	struct ionic_admin_ctx ctx = {
35342a654540SShannon Nelson 		.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
35352a654540SShannon Nelson 		.cmd.lif_getattr = {
35362a654540SShannon Nelson 			.opcode = IONIC_CMD_LIF_GETATTR,
35372a654540SShannon Nelson 			.index = cpu_to_le16(lif->index),
35382a654540SShannon Nelson 			.attr = IONIC_LIF_ATTR_MAC,
35392a654540SShannon Nelson 		},
35402a654540SShannon Nelson 	};
354119058be7SR Mohamed Shah 	u8 mac_address[ETH_ALEN];
35422a654540SShannon Nelson 	struct sockaddr addr;
35432a654540SShannon Nelson 	int err;
35442a654540SShannon Nelson 
35452a654540SShannon Nelson 	err = ionic_adminq_post_wait(lif, &ctx);
35462a654540SShannon Nelson 	if (err)
35472a654540SShannon Nelson 		return err;
3548216902aeSShannon Nelson 	netdev_dbg(lif->netdev, "found initial MAC addr %pM\n",
3549216902aeSShannon Nelson 		   ctx.comp.lif_getattr.mac);
355019058be7SR Mohamed Shah 	ether_addr_copy(mac_address, ctx.comp.lif_getattr.mac);
355119058be7SR Mohamed Shah 
355219058be7SR Mohamed Shah 	if (is_zero_ether_addr(mac_address)) {
355319058be7SR Mohamed Shah 		eth_hw_addr_random(netdev);
355419058be7SR Mohamed Shah 		netdev_dbg(netdev, "Random Mac generated: %pM\n", netdev->dev_addr);
355519058be7SR Mohamed Shah 		ether_addr_copy(mac_address, netdev->dev_addr);
355619058be7SR Mohamed Shah 
355719058be7SR Mohamed Shah 		err = ionic_program_mac(lif, mac_address);
355819058be7SR Mohamed Shah 		if (err < 0)
355919058be7SR Mohamed Shah 			return err;
356019058be7SR Mohamed Shah 
356119058be7SR Mohamed Shah 		if (err > 0) {
356219058be7SR Mohamed Shah 			netdev_dbg(netdev, "%s:SET/GET ATTR Mac are not same-due to old FW running\n",
356319058be7SR Mohamed Shah 				   __func__);
3564fbb39807SShannon Nelson 			return 0;
356519058be7SR Mohamed Shah 		}
356619058be7SR Mohamed Shah 	}
3567fbb39807SShannon Nelson 
3568f20a4d40SShannon Nelson 	if (!is_zero_ether_addr(netdev->dev_addr)) {
3569f20a4d40SShannon Nelson 		/* If the netdev mac is non-zero and doesn't match the default
3570f20a4d40SShannon Nelson 		 * device address, it was set by something earlier and we're
3571f20a4d40SShannon Nelson 		 * likely here again after a fw-upgrade reset.  We need to be
3572f20a4d40SShannon Nelson 		 * sure the netdev mac is in our filter list.
3573f20a4d40SShannon Nelson 		 */
357419058be7SR Mohamed Shah 		if (!ether_addr_equal(mac_address, netdev->dev_addr))
35758b415173SShannon Nelson 			ionic_lif_addr_add(lif, netdev->dev_addr);
3576f20a4d40SShannon Nelson 	} else {
3577f20a4d40SShannon Nelson 		/* Update the netdev mac with the device's mac */
357819058be7SR Mohamed Shah 		ether_addr_copy(addr.sa_data, mac_address);
35792a654540SShannon Nelson 		addr.sa_family = AF_INET;
35802a654540SShannon Nelson 		err = eth_prepare_mac_addr_change(netdev, &addr);
3581fbb39807SShannon Nelson 		if (err) {
3582c672412fSShannon Nelson 			netdev_warn(lif->netdev, "ignoring bad MAC addr from NIC %pM - err %d\n",
3583c672412fSShannon Nelson 				    addr.sa_data, err);
3584fbb39807SShannon Nelson 			return 0;
3585fbb39807SShannon Nelson 		}
35862a654540SShannon Nelson 
35872a654540SShannon Nelson 		eth_commit_mac_addr_change(netdev, &addr);
3588216902aeSShannon Nelson 	}
3589216902aeSShannon Nelson 
35902a654540SShannon Nelson 	netdev_dbg(lif->netdev, "adding station MAC addr %pM\n",
35912a654540SShannon Nelson 		   netdev->dev_addr);
35928b415173SShannon Nelson 	ionic_lif_addr_add(lif, netdev->dev_addr);
35932a654540SShannon Nelson 
35942a654540SShannon Nelson 	return 0;
35952a654540SShannon Nelson }
35962a654540SShannon Nelson 
ionic_lif_init(struct ionic_lif * lif)359730b87ab4SShannon Nelson int ionic_lif_init(struct ionic_lif *lif)
35981a58e196SShannon Nelson {
35991a58e196SShannon Nelson 	struct ionic_dev *idev = &lif->ionic->idev;
36006461b446SShannon Nelson 	struct device *dev = lif->ionic->dev;
36011a58e196SShannon Nelson 	struct ionic_lif_init_comp comp;
36026461b446SShannon Nelson 	int dbpage_num;
36031a58e196SShannon Nelson 	int err;
36041a58e196SShannon Nelson 
36051a58e196SShannon Nelson 	mutex_lock(&lif->ionic->dev_cmd_lock);
36061a58e196SShannon Nelson 	ionic_dev_cmd_lif_init(idev, lif->index, lif->info_pa);
36071a58e196SShannon Nelson 	err = ionic_dev_cmd_wait(lif->ionic, DEVCMD_TIMEOUT);
36081a58e196SShannon Nelson 	ionic_dev_cmd_comp(idev, (union ionic_dev_cmd_comp *)&comp);
36091a58e196SShannon Nelson 	mutex_unlock(&lif->ionic->dev_cmd_lock);
36101a58e196SShannon Nelson 	if (err)
36111a58e196SShannon Nelson 		return err;
36121a58e196SShannon Nelson 
36131a58e196SShannon Nelson 	lif->hw_index = le16_to_cpu(comp.hw_index);
36141a58e196SShannon Nelson 
36156461b446SShannon Nelson 	/* now that we have the hw_index we can figure out our doorbell page */
36166461b446SShannon Nelson 	lif->dbid_count = le32_to_cpu(lif->ionic->ident.dev.ndbpgs_per_lif);
36176461b446SShannon Nelson 	if (!lif->dbid_count) {
36186461b446SShannon Nelson 		dev_err(dev, "No doorbell pages, aborting\n");
36196461b446SShannon Nelson 		return -EINVAL;
36206461b446SShannon Nelson 	}
36216461b446SShannon Nelson 
36226461b446SShannon Nelson 	lif->kern_pid = 0;
36236461b446SShannon Nelson 	dbpage_num = ionic_db_page_num(lif, lif->kern_pid);
36246461b446SShannon Nelson 	lif->kern_dbpage = ionic_bus_map_dbpage(lif->ionic, dbpage_num);
36256461b446SShannon Nelson 	if (!lif->kern_dbpage) {
36266461b446SShannon Nelson 		dev_err(dev, "Cannot map dbpage, aborting\n");
3627b1552a4cSShannon Nelson 		return -ENOMEM;
36286461b446SShannon Nelson 	}
36296461b446SShannon Nelson 
36301d062b7bSShannon Nelson 	err = ionic_lif_adminq_init(lif);
36311d062b7bSShannon Nelson 	if (err)
36321d062b7bSShannon Nelson 		goto err_out_adminq_deinit;
36331d062b7bSShannon Nelson 
363477ceb68eSShannon Nelson 	if (lif->ionic->nnqs_per_lif) {
363577ceb68eSShannon Nelson 		err = ionic_lif_notifyq_init(lif);
363677ceb68eSShannon Nelson 		if (err)
363777ceb68eSShannon Nelson 			goto err_out_notifyq_deinit;
363877ceb68eSShannon Nelson 	}
363977ceb68eSShannon Nelson 
3640beead698SShannon Nelson 	err = ionic_init_nic_features(lif);
3641beead698SShannon Nelson 	if (err)
3642beead698SShannon Nelson 		goto err_out_notifyq_deinit;
3643beead698SShannon Nelson 
36447e4d4759SShannon Nelson 	if (!test_bit(IONIC_LIF_F_FW_RESET, lif->state)) {
3645c1e329ebSShannon Nelson 		err = ionic_rx_filters_init(lif);
3646c1e329ebSShannon Nelson 		if (err)
3647c1e329ebSShannon Nelson 			goto err_out_notifyq_deinit;
36487e4d4759SShannon Nelson 	}
3649c1e329ebSShannon Nelson 
36502a654540SShannon Nelson 	err = ionic_station_set(lif);
36512a654540SShannon Nelson 	if (err)
36522a654540SShannon Nelson 		goto err_out_notifyq_deinit;
36532a654540SShannon Nelson 
36540f3154e6SShannon Nelson 	lif->rx_copybreak = IONIC_RX_COPYBREAK_DEFAULT;
36550f3154e6SShannon Nelson 
3656c6d3d73aSShannon Nelson 	set_bit(IONIC_LIF_F_INITED, lif->state);
36571a58e196SShannon Nelson 
36588c15440bSShannon Nelson 	INIT_WORK(&lif->tx_timeout_work, ionic_tx_timeout_work);
36598c15440bSShannon Nelson 
36601a58e196SShannon Nelson 	return 0;
36616461b446SShannon Nelson 
366277ceb68eSShannon Nelson err_out_notifyq_deinit:
366343cfed71SBrett Creeley 	napi_disable(&lif->adminqcq->napi);
366477ceb68eSShannon Nelson 	ionic_lif_qcq_deinit(lif, lif->notifyqcq);
36651d062b7bSShannon Nelson err_out_adminq_deinit:
36661d062b7bSShannon Nelson 	ionic_lif_qcq_deinit(lif, lif->adminqcq);
36671d062b7bSShannon Nelson 	ionic_lif_reset(lif);
36681d062b7bSShannon Nelson 	ionic_bus_unmap_dbpage(lif->ionic, lif->kern_dbpage);
36691d062b7bSShannon Nelson 	lif->kern_dbpage = NULL;
36706461b446SShannon Nelson 
36716461b446SShannon Nelson 	return err;
36721a58e196SShannon Nelson }
36731a58e196SShannon Nelson 
ionic_lif_notify_work(struct work_struct * ws)36741a371ea1SShannon Nelson static void ionic_lif_notify_work(struct work_struct *ws)
36751a371ea1SShannon Nelson {
36761a371ea1SShannon Nelson }
36771a371ea1SShannon Nelson 
ionic_lif_set_netdev_info(struct ionic_lif * lif)36781a371ea1SShannon Nelson static void ionic_lif_set_netdev_info(struct ionic_lif *lif)
36791a371ea1SShannon Nelson {
36801a371ea1SShannon Nelson 	struct ionic_admin_ctx ctx = {
36811a371ea1SShannon Nelson 		.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
36821a371ea1SShannon Nelson 		.cmd.lif_setattr = {
36831a371ea1SShannon Nelson 			.opcode = IONIC_CMD_LIF_SETATTR,
36841a371ea1SShannon Nelson 			.index = cpu_to_le16(lif->index),
36851a371ea1SShannon Nelson 			.attr = IONIC_LIF_ATTR_NAME,
36861a371ea1SShannon Nelson 		},
36871a371ea1SShannon Nelson 	};
36881a371ea1SShannon Nelson 
3689799c230eSShannon Nelson 	strscpy(ctx.cmd.lif_setattr.name, lif->netdev->name,
36901a371ea1SShannon Nelson 		sizeof(ctx.cmd.lif_setattr.name));
36911a371ea1SShannon Nelson 
36921a371ea1SShannon Nelson 	ionic_adminq_post_wait(lif, &ctx);
36931a371ea1SShannon Nelson }
36941a371ea1SShannon Nelson 
ionic_netdev_lif(struct net_device * netdev)36951a371ea1SShannon Nelson static struct ionic_lif *ionic_netdev_lif(struct net_device *netdev)
36961a371ea1SShannon Nelson {
36971a371ea1SShannon Nelson 	if (!netdev || netdev->netdev_ops->ndo_start_xmit != ionic_start_xmit)
36981a371ea1SShannon Nelson 		return NULL;
36991a371ea1SShannon Nelson 
37001a371ea1SShannon Nelson 	return netdev_priv(netdev);
37011a371ea1SShannon Nelson }
37021a371ea1SShannon Nelson 
ionic_lif_notify(struct notifier_block * nb,unsigned long event,void * info)37031a371ea1SShannon Nelson static int ionic_lif_notify(struct notifier_block *nb,
37041a371ea1SShannon Nelson 			    unsigned long event, void *info)
37051a371ea1SShannon Nelson {
37061a371ea1SShannon Nelson 	struct net_device *ndev = netdev_notifier_info_to_dev(info);
37071a371ea1SShannon Nelson 	struct ionic *ionic = container_of(nb, struct ionic, nb);
37081a371ea1SShannon Nelson 	struct ionic_lif *lif = ionic_netdev_lif(ndev);
37091a371ea1SShannon Nelson 
37101a371ea1SShannon Nelson 	if (!lif || lif->ionic != ionic)
37111a371ea1SShannon Nelson 		return NOTIFY_DONE;
37121a371ea1SShannon Nelson 
37131a371ea1SShannon Nelson 	switch (event) {
37141a371ea1SShannon Nelson 	case NETDEV_CHANGENAME:
37151a371ea1SShannon Nelson 		ionic_lif_set_netdev_info(lif);
37161a371ea1SShannon Nelson 		break;
37171a371ea1SShannon Nelson 	}
37181a371ea1SShannon Nelson 
37191a371ea1SShannon Nelson 	return NOTIFY_DONE;
37201a371ea1SShannon Nelson }
37211a371ea1SShannon Nelson 
ionic_lif_register(struct ionic_lif * lif)372230b87ab4SShannon Nelson int ionic_lif_register(struct ionic_lif *lif)
3723beead698SShannon Nelson {
3724beead698SShannon Nelson 	int err;
3725beead698SShannon Nelson 
3726afeefec6SShannon Nelson 	ionic_lif_register_phc(lif);
3727afeefec6SShannon Nelson 
372830b87ab4SShannon Nelson 	INIT_WORK(&lif->ionic->nb_work, ionic_lif_notify_work);
37291a371ea1SShannon Nelson 
373030b87ab4SShannon Nelson 	lif->ionic->nb.notifier_call = ionic_lif_notify;
37311a371ea1SShannon Nelson 
373230b87ab4SShannon Nelson 	err = register_netdevice_notifier(&lif->ionic->nb);
37331a371ea1SShannon Nelson 	if (err)
373430b87ab4SShannon Nelson 		lif->ionic->nb.notifier_call = NULL;
37351a371ea1SShannon Nelson 
3736beead698SShannon Nelson 	/* only register LIF0 for now */
373730b87ab4SShannon Nelson 	err = register_netdev(lif->netdev);
3738beead698SShannon Nelson 	if (err) {
3739*da5736f5SBrett Creeley 		dev_err(lif->ionic->dev, "Cannot register net device: %d, aborting\n", err);
3740*da5736f5SBrett Creeley 		ionic_lif_unregister(lif);
3741beead698SShannon Nelson 		return err;
3742beead698SShannon Nelson 	}
3743f6e428b2SShannon Nelson 
374425cc5a5fSShannon Nelson 	ionic_link_status_check_request(lif, CAN_SLEEP);
374530b87ab4SShannon Nelson 	lif->registered = true;
374630b87ab4SShannon Nelson 	ionic_lif_set_netdev_info(lif);
3747beead698SShannon Nelson 
3748beead698SShannon Nelson 	return 0;
3749beead698SShannon Nelson }
3750beead698SShannon Nelson 
ionic_lif_unregister(struct ionic_lif * lif)375130b87ab4SShannon Nelson void ionic_lif_unregister(struct ionic_lif *lif)
3752beead698SShannon Nelson {
375330b87ab4SShannon Nelson 	if (lif->ionic->nb.notifier_call) {
375430b87ab4SShannon Nelson 		unregister_netdevice_notifier(&lif->ionic->nb);
375530b87ab4SShannon Nelson 		cancel_work_sync(&lif->ionic->nb_work);
375630b87ab4SShannon Nelson 		lif->ionic->nb.notifier_call = NULL;
37571a371ea1SShannon Nelson 	}
37581a371ea1SShannon Nelson 
375930b87ab4SShannon Nelson 	if (lif->netdev->reg_state == NETREG_REGISTERED)
376030b87ab4SShannon Nelson 		unregister_netdev(lif->netdev);
3761f0790bcdSShannon Nelson 
3762afeefec6SShannon Nelson 	ionic_lif_unregister_phc(lif);
3763afeefec6SShannon Nelson 
376430b87ab4SShannon Nelson 	lif->registered = false;
3765beead698SShannon Nelson }
3766beead698SShannon Nelson 
ionic_lif_queue_identify(struct ionic_lif * lif)37675b3f3f2aSShannon Nelson static void ionic_lif_queue_identify(struct ionic_lif *lif)
37685b3f3f2aSShannon Nelson {
3769d701ec32SShannon Nelson 	union ionic_q_identity __iomem *q_ident;
37705b3f3f2aSShannon Nelson 	struct ionic *ionic = lif->ionic;
37715b3f3f2aSShannon Nelson 	struct ionic_dev *idev;
37725b3f3f2aSShannon Nelson 	int qtype;
37735b3f3f2aSShannon Nelson 	int err;
37745b3f3f2aSShannon Nelson 
37755b3f3f2aSShannon Nelson 	idev = &lif->ionic->idev;
3776d701ec32SShannon Nelson 	q_ident = (union ionic_q_identity __iomem *)&idev->dev_cmd_regs->data;
37775b3f3f2aSShannon Nelson 
37785b3f3f2aSShannon Nelson 	for (qtype = 0; qtype < ARRAY_SIZE(ionic_qtype_versions); qtype++) {
37795b3f3f2aSShannon Nelson 		struct ionic_qtype_info *qti = &lif->qtype_info[qtype];
37805b3f3f2aSShannon Nelson 
37815b3f3f2aSShannon Nelson 		/* filter out the ones we know about */
37825b3f3f2aSShannon Nelson 		switch (qtype) {
37835b3f3f2aSShannon Nelson 		case IONIC_QTYPE_ADMINQ:
37845b3f3f2aSShannon Nelson 		case IONIC_QTYPE_NOTIFYQ:
37855b3f3f2aSShannon Nelson 		case IONIC_QTYPE_RXQ:
37865b3f3f2aSShannon Nelson 		case IONIC_QTYPE_TXQ:
37875b3f3f2aSShannon Nelson 			break;
37885b3f3f2aSShannon Nelson 		default:
37895b3f3f2aSShannon Nelson 			continue;
37905b3f3f2aSShannon Nelson 		}
37915b3f3f2aSShannon Nelson 
37925b3f3f2aSShannon Nelson 		memset(qti, 0, sizeof(*qti));
37935b3f3f2aSShannon Nelson 
37945b3f3f2aSShannon Nelson 		mutex_lock(&ionic->dev_cmd_lock);
37955b3f3f2aSShannon Nelson 		ionic_dev_cmd_queue_identify(idev, lif->lif_type, qtype,
37965b3f3f2aSShannon Nelson 					     ionic_qtype_versions[qtype]);
37975b3f3f2aSShannon Nelson 		err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT);
37985b3f3f2aSShannon Nelson 		if (!err) {
3799d701ec32SShannon Nelson 			qti->version   = readb(&q_ident->version);
3800d701ec32SShannon Nelson 			qti->supported = readb(&q_ident->supported);
3801d701ec32SShannon Nelson 			qti->features  = readq(&q_ident->features);
3802d701ec32SShannon Nelson 			qti->desc_sz   = readw(&q_ident->desc_sz);
3803d701ec32SShannon Nelson 			qti->comp_sz   = readw(&q_ident->comp_sz);
3804d701ec32SShannon Nelson 			qti->sg_desc_sz   = readw(&q_ident->sg_desc_sz);
3805d701ec32SShannon Nelson 			qti->max_sg_elems = readw(&q_ident->max_sg_elems);
3806d701ec32SShannon Nelson 			qti->sg_desc_stride = readw(&q_ident->sg_desc_stride);
38075b3f3f2aSShannon Nelson 		}
38085b3f3f2aSShannon Nelson 		mutex_unlock(&ionic->dev_cmd_lock);
38095b3f3f2aSShannon Nelson 
38105b3f3f2aSShannon Nelson 		if (err == -EINVAL) {
38115b3f3f2aSShannon Nelson 			dev_err(ionic->dev, "qtype %d not supported\n", qtype);
38125b3f3f2aSShannon Nelson 			continue;
38135b3f3f2aSShannon Nelson 		} else if (err == -EIO) {
38145b3f3f2aSShannon Nelson 			dev_err(ionic->dev, "q_ident failed, not supported on older FW\n");
38155b3f3f2aSShannon Nelson 			return;
38165b3f3f2aSShannon Nelson 		} else if (err) {
38175b3f3f2aSShannon Nelson 			dev_err(ionic->dev, "q_ident failed, qtype %d: %d\n",
38185b3f3f2aSShannon Nelson 				qtype, err);
38195b3f3f2aSShannon Nelson 			return;
38205b3f3f2aSShannon Nelson 		}
38215b3f3f2aSShannon Nelson 
38225b3f3f2aSShannon Nelson 		dev_dbg(ionic->dev, " qtype[%d].version = %d\n",
38235b3f3f2aSShannon Nelson 			qtype, qti->version);
38245b3f3f2aSShannon Nelson 		dev_dbg(ionic->dev, " qtype[%d].supported = 0x%02x\n",
38255b3f3f2aSShannon Nelson 			qtype, qti->supported);
38265b3f3f2aSShannon Nelson 		dev_dbg(ionic->dev, " qtype[%d].features = 0x%04llx\n",
38275b3f3f2aSShannon Nelson 			qtype, qti->features);
38285b3f3f2aSShannon Nelson 		dev_dbg(ionic->dev, " qtype[%d].desc_sz = %d\n",
38295b3f3f2aSShannon Nelson 			qtype, qti->desc_sz);
38305b3f3f2aSShannon Nelson 		dev_dbg(ionic->dev, " qtype[%d].comp_sz = %d\n",
38315b3f3f2aSShannon Nelson 			qtype, qti->comp_sz);
38325b3f3f2aSShannon Nelson 		dev_dbg(ionic->dev, " qtype[%d].sg_desc_sz = %d\n",
38335b3f3f2aSShannon Nelson 			qtype, qti->sg_desc_sz);
38345b3f3f2aSShannon Nelson 		dev_dbg(ionic->dev, " qtype[%d].max_sg_elems = %d\n",
38355b3f3f2aSShannon Nelson 			qtype, qti->max_sg_elems);
38365b3f3f2aSShannon Nelson 		dev_dbg(ionic->dev, " qtype[%d].sg_desc_stride = %d\n",
38375b3f3f2aSShannon Nelson 			qtype, qti->sg_desc_stride);
38385b3f3f2aSShannon Nelson 	}
38395b3f3f2aSShannon Nelson }
38405b3f3f2aSShannon Nelson 
ionic_lif_identify(struct ionic * ionic,u8 lif_type,union ionic_lif_identity * lid)38411a58e196SShannon Nelson int ionic_lif_identify(struct ionic *ionic, u8 lif_type,
38421a58e196SShannon Nelson 		       union ionic_lif_identity *lid)
38431a58e196SShannon Nelson {
38441a58e196SShannon Nelson 	struct ionic_dev *idev = &ionic->idev;
38451a58e196SShannon Nelson 	size_t sz;
38461a58e196SShannon Nelson 	int err;
38471a58e196SShannon Nelson 
38481a58e196SShannon Nelson 	sz = min(sizeof(*lid), sizeof(idev->dev_cmd_regs->data));
38491a58e196SShannon Nelson 
38501a58e196SShannon Nelson 	mutex_lock(&ionic->dev_cmd_lock);
38511a58e196SShannon Nelson 	ionic_dev_cmd_lif_identify(idev, lif_type, IONIC_IDENTITY_VERSION_1);
38521a58e196SShannon Nelson 	err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT);
38531a58e196SShannon Nelson 	memcpy_fromio(lid, &idev->dev_cmd_regs->data, sz);
38541a58e196SShannon Nelson 	mutex_unlock(&ionic->dev_cmd_lock);
38551a58e196SShannon Nelson 	if (err)
38561a58e196SShannon Nelson 		return (err);
38571a58e196SShannon Nelson 
38581a58e196SShannon Nelson 	dev_dbg(ionic->dev, "capabilities 0x%llx\n",
38591a58e196SShannon Nelson 		le64_to_cpu(lid->capabilities));
38601a58e196SShannon Nelson 
38611a58e196SShannon Nelson 	dev_dbg(ionic->dev, "eth.max_ucast_filters %d\n",
38621a58e196SShannon Nelson 		le32_to_cpu(lid->eth.max_ucast_filters));
38631a58e196SShannon Nelson 	dev_dbg(ionic->dev, "eth.max_mcast_filters %d\n",
38641a58e196SShannon Nelson 		le32_to_cpu(lid->eth.max_mcast_filters));
38651a58e196SShannon Nelson 	dev_dbg(ionic->dev, "eth.features 0x%llx\n",
38661a58e196SShannon Nelson 		le64_to_cpu(lid->eth.config.features));
38671a58e196SShannon Nelson 	dev_dbg(ionic->dev, "eth.queue_count[IONIC_QTYPE_ADMINQ] %d\n",
38681a58e196SShannon Nelson 		le32_to_cpu(lid->eth.config.queue_count[IONIC_QTYPE_ADMINQ]));
38691a58e196SShannon Nelson 	dev_dbg(ionic->dev, "eth.queue_count[IONIC_QTYPE_NOTIFYQ] %d\n",
38701a58e196SShannon Nelson 		le32_to_cpu(lid->eth.config.queue_count[IONIC_QTYPE_NOTIFYQ]));
38711a58e196SShannon Nelson 	dev_dbg(ionic->dev, "eth.queue_count[IONIC_QTYPE_RXQ] %d\n",
38721a58e196SShannon Nelson 		le32_to_cpu(lid->eth.config.queue_count[IONIC_QTYPE_RXQ]));
38731a58e196SShannon Nelson 	dev_dbg(ionic->dev, "eth.queue_count[IONIC_QTYPE_TXQ] %d\n",
38741a58e196SShannon Nelson 		le32_to_cpu(lid->eth.config.queue_count[IONIC_QTYPE_TXQ]));
38751a58e196SShannon Nelson 	dev_dbg(ionic->dev, "eth.config.name %s\n", lid->eth.config.name);
38761a58e196SShannon Nelson 	dev_dbg(ionic->dev, "eth.config.mac %pM\n", lid->eth.config.mac);
38771a58e196SShannon Nelson 	dev_dbg(ionic->dev, "eth.config.mtu %d\n",
38781a58e196SShannon Nelson 		le32_to_cpu(lid->eth.config.mtu));
38791a58e196SShannon Nelson 
38801a58e196SShannon Nelson 	return 0;
38811a58e196SShannon Nelson }
38821a58e196SShannon Nelson 
ionic_lif_size(struct ionic * ionic)388330b87ab4SShannon Nelson int ionic_lif_size(struct ionic *ionic)
38841a58e196SShannon Nelson {
38851a58e196SShannon Nelson 	struct ionic_identity *ident = &ionic->ident;
38861a58e196SShannon Nelson 	unsigned int nintrs, dev_nintrs;
38871a58e196SShannon Nelson 	union ionic_lif_config *lc;
38881a58e196SShannon Nelson 	unsigned int ntxqs_per_lif;
38891a58e196SShannon Nelson 	unsigned int nrxqs_per_lif;
38901a58e196SShannon Nelson 	unsigned int neqs_per_lif;
38911a58e196SShannon Nelson 	unsigned int nnqs_per_lif;
38921a58e196SShannon Nelson 	unsigned int nxqs, neqs;
38931a58e196SShannon Nelson 	unsigned int min_intrs;
38941a58e196SShannon Nelson 	int err;
38951a58e196SShannon Nelson 
3896c0b03e83SShannon Nelson 	/* retrieve basic values from FW */
38971a58e196SShannon Nelson 	lc = &ident->lif.eth.config;
38981a58e196SShannon Nelson 	dev_nintrs = le32_to_cpu(ident->dev.nintrs);
38991a58e196SShannon Nelson 	neqs_per_lif = le32_to_cpu(ident->lif.rdma.eq_qtype.qid_count);
39001a58e196SShannon Nelson 	nnqs_per_lif = le32_to_cpu(lc->queue_count[IONIC_QTYPE_NOTIFYQ]);
39011a58e196SShannon Nelson 	ntxqs_per_lif = le32_to_cpu(lc->queue_count[IONIC_QTYPE_TXQ]);
39021a58e196SShannon Nelson 	nrxqs_per_lif = le32_to_cpu(lc->queue_count[IONIC_QTYPE_RXQ]);
39031a58e196SShannon Nelson 
3904c0b03e83SShannon Nelson 	/* limit values to play nice with kdump */
3905c0b03e83SShannon Nelson 	if (is_kdump_kernel()) {
3906c0b03e83SShannon Nelson 		dev_nintrs = 2;
3907c0b03e83SShannon Nelson 		neqs_per_lif = 0;
3908c0b03e83SShannon Nelson 		nnqs_per_lif = 0;
3909c0b03e83SShannon Nelson 		ntxqs_per_lif = 1;
3910c0b03e83SShannon Nelson 		nrxqs_per_lif = 1;
3911c0b03e83SShannon Nelson 	}
3912c0b03e83SShannon Nelson 
3913f0790bcdSShannon Nelson 	/* reserve last queue id for hardware timestamping */
3914f0790bcdSShannon Nelson 	if (lc->features & cpu_to_le64(IONIC_ETH_HW_TIMESTAMP)) {
3915f0790bcdSShannon Nelson 		if (ntxqs_per_lif <= 1 || nrxqs_per_lif <= 1) {
3916f0790bcdSShannon Nelson 			lc->features &= cpu_to_le64(~IONIC_ETH_HW_TIMESTAMP);
3917f0790bcdSShannon Nelson 		} else {
3918f0790bcdSShannon Nelson 			ntxqs_per_lif -= 1;
3919f0790bcdSShannon Nelson 			nrxqs_per_lif -= 1;
3920f0790bcdSShannon Nelson 		}
3921f0790bcdSShannon Nelson 	}
3922f0790bcdSShannon Nelson 
39231a58e196SShannon Nelson 	nxqs = min(ntxqs_per_lif, nrxqs_per_lif);
39241a58e196SShannon Nelson 	nxqs = min(nxqs, num_online_cpus());
39251a58e196SShannon Nelson 	neqs = min(neqs_per_lif, num_online_cpus());
39261a58e196SShannon Nelson 
39271a58e196SShannon Nelson try_again:
39281a58e196SShannon Nelson 	/* interrupt usage:
39291a58e196SShannon Nelson 	 *    1 for master lif adminq/notifyq
39301a58e196SShannon Nelson 	 *    1 for each CPU for master lif TxRx queue pairs
39311a58e196SShannon Nelson 	 *    whatever's left is for RDMA queues
39321a58e196SShannon Nelson 	 */
39331a58e196SShannon Nelson 	nintrs = 1 + nxqs + neqs;
39341a58e196SShannon Nelson 	min_intrs = 2;  /* adminq + 1 TxRx queue pair */
39351a58e196SShannon Nelson 
39361a58e196SShannon Nelson 	if (nintrs > dev_nintrs)
39371a58e196SShannon Nelson 		goto try_fewer;
39381a58e196SShannon Nelson 
39391a58e196SShannon Nelson 	err = ionic_bus_alloc_irq_vectors(ionic, nintrs);
39401a58e196SShannon Nelson 	if (err < 0 && err != -ENOSPC) {
39411a58e196SShannon Nelson 		dev_err(ionic->dev, "Can't get intrs from OS: %d\n", err);
39421a58e196SShannon Nelson 		return err;
39431a58e196SShannon Nelson 	}
39441a58e196SShannon Nelson 	if (err == -ENOSPC)
39451a58e196SShannon Nelson 		goto try_fewer;
39461a58e196SShannon Nelson 
39471a58e196SShannon Nelson 	if (err != nintrs) {
39481a58e196SShannon Nelson 		ionic_bus_free_irq_vectors(ionic);
39491a58e196SShannon Nelson 		goto try_fewer;
39501a58e196SShannon Nelson 	}
39511a58e196SShannon Nelson 
39521a58e196SShannon Nelson 	ionic->nnqs_per_lif = nnqs_per_lif;
39531a58e196SShannon Nelson 	ionic->neqs_per_lif = neqs;
39541a58e196SShannon Nelson 	ionic->ntxqs_per_lif = nxqs;
39551a58e196SShannon Nelson 	ionic->nrxqs_per_lif = nxqs;
39561a58e196SShannon Nelson 	ionic->nintrs = nintrs;
39571a58e196SShannon Nelson 
39581a58e196SShannon Nelson 	ionic_debugfs_add_sizes(ionic);
39591a58e196SShannon Nelson 
39601a58e196SShannon Nelson 	return 0;
39611a58e196SShannon Nelson 
39621a58e196SShannon Nelson try_fewer:
39631a58e196SShannon Nelson 	if (nnqs_per_lif > 1) {
39641a58e196SShannon Nelson 		nnqs_per_lif >>= 1;
39651a58e196SShannon Nelson 		goto try_again;
39661a58e196SShannon Nelson 	}
39671a58e196SShannon Nelson 	if (neqs > 1) {
39681a58e196SShannon Nelson 		neqs >>= 1;
39691a58e196SShannon Nelson 		goto try_again;
39701a58e196SShannon Nelson 	}
39711a58e196SShannon Nelson 	if (nxqs > 1) {
39721a58e196SShannon Nelson 		nxqs >>= 1;
39731a58e196SShannon Nelson 		goto try_again;
39741a58e196SShannon Nelson 	}
39751a58e196SShannon Nelson 	dev_err(ionic->dev, "Can't get minimum %d intrs from OS\n", min_intrs);
39761a58e196SShannon Nelson 	return -ENOSPC;
39771a58e196SShannon Nelson }
3978