brintos

brintos / linux-shallow public Read only

0
0
Text · 20.6 KiB · 9e42d59 Raw
836 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Copyright(c) 2017 - 2019 Pensando Systems, Inc */3 4#include <linux/kernel.h>5#include <linux/types.h>6#include <linux/errno.h>7#include <linux/io.h>8#include <linux/slab.h>9#include <linux/etherdevice.h>10#include "ionic.h"11#include "ionic_dev.h"12#include "ionic_lif.h"13 14static void ionic_watchdog_cb(struct timer_list *t)15{16	struct ionic *ionic = from_timer(ionic, t, watchdog_timer);17	struct ionic_lif *lif = ionic->lif;18	struct ionic_deferred_work *work;19	int hb;20 21	mod_timer(&ionic->watchdog_timer,22		  round_jiffies(jiffies + ionic->watchdog_period));23 24	if (!lif)25		return;26 27	hb = ionic_heartbeat_check(ionic);28	dev_dbg(ionic->dev, "%s: hb %d running %d UP %d\n",29		__func__, hb, netif_running(lif->netdev),30		test_bit(IONIC_LIF_F_UP, lif->state));31 32	if (hb >= 0 &&33	    !test_bit(IONIC_LIF_F_FW_RESET, lif->state))34		ionic_link_status_check_request(lif, CAN_NOT_SLEEP);35 36	if (test_bit(IONIC_LIF_F_FILTER_SYNC_NEEDED, lif->state) &&37	    !test_bit(IONIC_LIF_F_FW_RESET, lif->state)) {38		work = kzalloc(sizeof(*work), GFP_ATOMIC);39		if (!work) {40			netdev_err(lif->netdev, "rxmode change dropped\n");41			return;42		}43 44		work->type = IONIC_DW_TYPE_RX_MODE;45		netdev_dbg(lif->netdev, "deferred: rx_mode\n");46		ionic_lif_deferred_enqueue(lif, work);47	}48}49 50static void ionic_napi_schedule_do_softirq(struct napi_struct *napi)51{52	local_bh_disable();53	napi_schedule(napi);54	local_bh_enable();55}56 57void ionic_doorbell_napi_work(struct work_struct *work)58{59	struct ionic_qcq *qcq = container_of(work, struct ionic_qcq,60					     doorbell_napi_work);61	unsigned long now, then, dif;62 63	now = READ_ONCE(jiffies);64	then = qcq->q.dbell_jiffies;65	dif = now - then;66 67	if (dif > qcq->q.dbell_deadline)68		ionic_napi_schedule_do_softirq(&qcq->napi);69}70 71static int ionic_get_preferred_cpu(struct ionic *ionic,72				   struct ionic_intr_info *intr)73{74	int cpu;75 76	cpu = cpumask_first_and(*intr->affinity_mask, cpu_online_mask);77	if (cpu >= nr_cpu_ids)78		cpu = cpumask_local_spread(0, dev_to_node(ionic->dev));79 80	return cpu;81}82 83static void ionic_queue_dbell_napi_work(struct ionic *ionic,84					struct ionic_qcq *qcq)85{86	int cpu;87 88	if (!(qcq->flags & IONIC_QCQ_F_INTR))89		return;90 91	cpu = ionic_get_preferred_cpu(ionic, &qcq->intr);92	queue_work_on(cpu, ionic->wq, &qcq->doorbell_napi_work);93}94 95static void ionic_doorbell_check_dwork(struct work_struct *work)96{97	struct ionic *ionic = container_of(work, struct ionic,98					   doorbell_check_dwork.work);99	struct ionic_lif *lif = ionic->lif;100 101	mutex_lock(&lif->queue_lock);102 103	if (test_bit(IONIC_LIF_F_FW_STOPPING, lif->state) ||104	    test_bit(IONIC_LIF_F_FW_RESET, lif->state)) {105		mutex_unlock(&lif->queue_lock);106		return;107	}108 109	ionic_napi_schedule_do_softirq(&lif->adminqcq->napi);110 111	if (test_bit(IONIC_LIF_F_UP, lif->state)) {112		int i;113 114		for (i = 0; i < lif->nxqs; i++) {115			ionic_queue_dbell_napi_work(ionic, lif->txqcqs[i]);116			ionic_queue_dbell_napi_work(ionic, lif->rxqcqs[i]);117		}118 119		if (lif->hwstamp_txq &&120		    lif->hwstamp_txq->flags & IONIC_QCQ_F_INTR)121			ionic_napi_schedule_do_softirq(&lif->hwstamp_txq->napi);122		if (lif->hwstamp_rxq &&123		    lif->hwstamp_rxq->flags & IONIC_QCQ_F_INTR)124			ionic_napi_schedule_do_softirq(&lif->hwstamp_rxq->napi);125	}126	mutex_unlock(&lif->queue_lock);127 128	ionic_queue_doorbell_check(ionic, IONIC_NAPI_DEADLINE);129}130 131bool ionic_doorbell_wa(struct ionic *ionic)132{133	u8 asic_type = ionic->idev.dev_info.asic_type;134 135	return !asic_type || asic_type == IONIC_ASIC_TYPE_ELBA;136}137 138static int ionic_watchdog_init(struct ionic *ionic)139{140	struct ionic_dev *idev = &ionic->idev;141 142	timer_setup(&ionic->watchdog_timer, ionic_watchdog_cb, 0);143	ionic->watchdog_period = IONIC_WATCHDOG_SECS * HZ;144 145	/* set times to ensure the first check will proceed */146	atomic_long_set(&idev->last_check_time, jiffies - 2 * HZ);147	idev->last_hb_time = jiffies - 2 * ionic->watchdog_period;148	/* init as ready, so no transition if the first check succeeds */149	idev->last_fw_hb = 0;150	idev->fw_hb_ready = true;151	idev->fw_status_ready = true;152	idev->fw_generation = IONIC_FW_STS_F_GENERATION &153			      ioread8(&idev->dev_info_regs->fw_status);154 155	ionic->wq = alloc_workqueue("%s-wq", WQ_UNBOUND, 0,156				    dev_name(ionic->dev));157	if (!ionic->wq) {158		dev_err(ionic->dev, "alloc_workqueue failed");159		return -ENOMEM;160	}161 162	if (ionic_doorbell_wa(ionic))163		INIT_DELAYED_WORK(&ionic->doorbell_check_dwork,164				  ionic_doorbell_check_dwork);165 166	return 0;167}168 169void ionic_queue_doorbell_check(struct ionic *ionic, int delay)170{171	int cpu;172 173	if (!ionic->lif->doorbell_wa)174		return;175 176	cpu = ionic_get_preferred_cpu(ionic, &ionic->lif->adminqcq->intr);177	queue_delayed_work_on(cpu, ionic->wq, &ionic->doorbell_check_dwork,178			      delay);179}180 181void ionic_init_devinfo(struct ionic *ionic)182{183	struct ionic_dev *idev = &ionic->idev;184 185	idev->dev_info.asic_type = ioread8(&idev->dev_info_regs->asic_type);186	idev->dev_info.asic_rev = ioread8(&idev->dev_info_regs->asic_rev);187 188	memcpy_fromio(idev->dev_info.fw_version,189		      idev->dev_info_regs->fw_version,190		      IONIC_DEVINFO_FWVERS_BUFLEN);191 192	memcpy_fromio(idev->dev_info.serial_num,193		      idev->dev_info_regs->serial_num,194		      IONIC_DEVINFO_SERIAL_BUFLEN);195 196	idev->dev_info.fw_version[IONIC_DEVINFO_FWVERS_BUFLEN] = 0;197	idev->dev_info.serial_num[IONIC_DEVINFO_SERIAL_BUFLEN] = 0;198 199	dev_dbg(ionic->dev, "fw_version %s\n", idev->dev_info.fw_version);200}201 202int ionic_dev_setup(struct ionic *ionic)203{204	struct ionic_dev_bar *bar = ionic->bars;205	unsigned int num_bars = ionic->num_bars;206	struct ionic_dev *idev = &ionic->idev;207	struct device *dev = ionic->dev;208	int size;209	u32 sig;210	int err;211 212	/* BAR0: dev_cmd and interrupts */213	if (num_bars < 1) {214		dev_err(dev, "No bars found, aborting\n");215		return -EFAULT;216	}217 218	if (bar->len < IONIC_BAR0_SIZE) {219		dev_err(dev, "Resource bar size %lu too small, aborting\n",220			bar->len);221		return -EFAULT;222	}223 224	idev->dev_info_regs = bar->vaddr + IONIC_BAR0_DEV_INFO_REGS_OFFSET;225	idev->dev_cmd_regs = bar->vaddr + IONIC_BAR0_DEV_CMD_REGS_OFFSET;226	idev->intr_status = bar->vaddr + IONIC_BAR0_INTR_STATUS_OFFSET;227	idev->intr_ctrl = bar->vaddr + IONIC_BAR0_INTR_CTRL_OFFSET;228 229	idev->hwstamp_regs = &idev->dev_info_regs->hwstamp;230 231	sig = ioread32(&idev->dev_info_regs->signature);232	if (sig != IONIC_DEV_INFO_SIGNATURE) {233		dev_err(dev, "Incompatible firmware signature %x", sig);234		return -EFAULT;235	}236 237	ionic_init_devinfo(ionic);238 239	/* BAR1: doorbells */240	bar++;241	if (num_bars < 2) {242		dev_err(dev, "Doorbell bar missing, aborting\n");243		return -EFAULT;244	}245 246	err = ionic_watchdog_init(ionic);247	if (err)248		return err;249 250	idev->db_pages = bar->vaddr;251	idev->phy_db_pages = bar->bus_addr;252 253	/* BAR2: optional controller memory mapping */254	bar++;255	mutex_init(&idev->cmb_inuse_lock);256	if (num_bars < 3 || !ionic->bars[IONIC_PCI_BAR_CMB].len) {257		idev->cmb_inuse = NULL;258		return 0;259	}260 261	idev->phy_cmb_pages = bar->bus_addr;262	idev->cmb_npages = bar->len / PAGE_SIZE;263	size = BITS_TO_LONGS(idev->cmb_npages) * sizeof(long);264	idev->cmb_inuse = kzalloc(size, GFP_KERNEL);265	if (!idev->cmb_inuse)266		dev_warn(dev, "No memory for CMB, disabling\n");267 268	return 0;269}270 271void ionic_dev_teardown(struct ionic *ionic)272{273	struct ionic_dev *idev = &ionic->idev;274 275	kfree(idev->cmb_inuse);276	idev->cmb_inuse = NULL;277	idev->phy_cmb_pages = 0;278	idev->cmb_npages = 0;279 280	destroy_workqueue(ionic->wq);281	mutex_destroy(&idev->cmb_inuse_lock);282}283 284/* Devcmd Interface */285static bool __ionic_is_fw_running(struct ionic_dev *idev, u8 *status_ptr)286{287	u8 fw_status;288 289	if (!idev->dev_info_regs) {290		if (status_ptr)291			*status_ptr = 0xff;292		return false;293	}294 295	fw_status = ioread8(&idev->dev_info_regs->fw_status);296	if (status_ptr)297		*status_ptr = fw_status;298 299	/* firmware is useful only if the running bit is set and300	 * fw_status != 0xff (bad PCI read)301	 */302	return (fw_status != 0xff) && (fw_status & IONIC_FW_STS_F_RUNNING);303}304 305bool ionic_is_fw_running(struct ionic_dev *idev)306{307	return __ionic_is_fw_running(idev, NULL);308}309 310int ionic_heartbeat_check(struct ionic *ionic)311{312	unsigned long check_time, last_check_time;313	struct ionic_dev *idev = &ionic->idev;314	struct ionic_lif *lif = ionic->lif;315	bool fw_status_ready = true;316	bool fw_hb_ready;317	u8 fw_generation;318	u8 fw_status;319	u32 fw_hb;320 321	/* wait a least one second before testing again */322	check_time = jiffies;323	last_check_time = atomic_long_read(&idev->last_check_time);324do_check_time:325	if (time_before(check_time, last_check_time + HZ))326		return 0;327	if (!atomic_long_try_cmpxchg_relaxed(&idev->last_check_time,328					     &last_check_time, check_time)) {329		/* if called concurrently, only the first should proceed. */330		dev_dbg(ionic->dev, "%s: do_check_time again\n", __func__);331		goto do_check_time;332	}333 334	/* If fw_status is not ready don't bother with the generation */335	if (!__ionic_is_fw_running(idev, &fw_status)) {336		fw_status_ready = false;337	} else {338		fw_generation = fw_status & IONIC_FW_STS_F_GENERATION;339		if (idev->fw_generation != fw_generation) {340			dev_info(ionic->dev, "FW generation 0x%02x -> 0x%02x\n",341				 idev->fw_generation, fw_generation);342 343			idev->fw_generation = fw_generation;344 345			/* If the generation changed, the fw status is not346			 * ready so we need to trigger a fw-down cycle.  After347			 * the down, the next watchdog will see the fw is up348			 * and the generation value stable, so will trigger349			 * the fw-up activity.350			 *351			 * If we had already moved to FW_RESET from a RESET event,352			 * it is possible that we never saw the fw_status go to 0,353			 * so we fake the current idev->fw_status_ready here to354			 * force the transition and get FW up again.355			 */356			if (test_bit(IONIC_LIF_F_FW_RESET, lif->state))357				idev->fw_status_ready = false;	/* go to running */358			else359				fw_status_ready = false;	/* go to down */360		}361	}362 363	dev_dbg(ionic->dev, "fw_status 0x%02x ready %d idev->ready %d last_hb 0x%x state 0x%02lx\n",364		fw_status, fw_status_ready, idev->fw_status_ready,365		idev->last_fw_hb, lif->state[0]);366 367	/* is this a transition? */368	if (fw_status_ready != idev->fw_status_ready &&369	    !test_bit(IONIC_LIF_F_FW_STOPPING, lif->state)) {370		bool trigger = false;371 372		idev->fw_status_ready = fw_status_ready;373 374		if (!fw_status_ready &&375		    !test_bit(IONIC_LIF_F_FW_RESET, lif->state) &&376		    !test_and_set_bit(IONIC_LIF_F_FW_STOPPING, lif->state)) {377			dev_info(ionic->dev, "FW stopped 0x%02x\n", fw_status);378			trigger = true;379 380		} else if (fw_status_ready &&381			   test_bit(IONIC_LIF_F_FW_RESET, lif->state)) {382			dev_info(ionic->dev, "FW running 0x%02x\n", fw_status);383			trigger = true;384		}385 386		if (trigger) {387			struct ionic_deferred_work *work;388 389			work = kzalloc(sizeof(*work), GFP_ATOMIC);390			if (work) {391				work->type = IONIC_DW_TYPE_LIF_RESET;392				work->fw_status = fw_status_ready;393				ionic_lif_deferred_enqueue(lif, work);394			}395		}396	}397 398	if (!idev->fw_status_ready)399		return -ENXIO;400 401	/* Because of some variability in the actual FW heartbeat, we402	 * wait longer than the DEVCMD_TIMEOUT before checking again.403	 */404	last_check_time = idev->last_hb_time;405	if (time_before(check_time, last_check_time + DEVCMD_TIMEOUT * 2 * HZ))406		return 0;407 408	fw_hb = ioread32(&idev->dev_info_regs->fw_heartbeat);409	fw_hb_ready = fw_hb != idev->last_fw_hb;410 411	/* early FW version had no heartbeat, so fake it */412	if (!fw_hb_ready && !fw_hb)413		fw_hb_ready = true;414 415	dev_dbg(ionic->dev, "%s: fw_hb %u last_fw_hb %u ready %u\n",416		__func__, fw_hb, idev->last_fw_hb, fw_hb_ready);417 418	idev->last_fw_hb = fw_hb;419 420	/* log a transition */421	if (fw_hb_ready != idev->fw_hb_ready) {422		idev->fw_hb_ready = fw_hb_ready;423		if (!fw_hb_ready)424			dev_info(ionic->dev, "FW heartbeat stalled at %d\n", fw_hb);425		else426			dev_info(ionic->dev, "FW heartbeat restored at %d\n", fw_hb);427	}428 429	if (!fw_hb_ready)430		return -ENXIO;431 432	idev->last_hb_time = check_time;433 434	return 0;435}436 437u8 ionic_dev_cmd_status(struct ionic_dev *idev)438{439	if (!idev->dev_cmd_regs)440		return (u8)PCI_ERROR_RESPONSE;441	return ioread8(&idev->dev_cmd_regs->comp.comp.status);442}443 444bool ionic_dev_cmd_done(struct ionic_dev *idev)445{446	if (!idev->dev_cmd_regs)447		return false;448	return ioread32(&idev->dev_cmd_regs->done) & IONIC_DEV_CMD_DONE;449}450 451void ionic_dev_cmd_comp(struct ionic_dev *idev, union ionic_dev_cmd_comp *comp)452{453	if (!idev->dev_cmd_regs)454		return;455	memcpy_fromio(comp, &idev->dev_cmd_regs->comp, sizeof(*comp));456}457 458void ionic_dev_cmd_go(struct ionic_dev *idev, union ionic_dev_cmd *cmd)459{460	idev->opcode = cmd->cmd.opcode;461 462	if (!idev->dev_cmd_regs)463		return;464 465	memcpy_toio(&idev->dev_cmd_regs->cmd, cmd, sizeof(*cmd));466	iowrite32(0, &idev->dev_cmd_regs->done);467	iowrite32(1, &idev->dev_cmd_regs->doorbell);468}469 470/* Device commands */471void ionic_dev_cmd_identify(struct ionic_dev *idev, u8 ver)472{473	union ionic_dev_cmd cmd = {474		.identify.opcode = IONIC_CMD_IDENTIFY,475		.identify.ver = ver,476	};477 478	ionic_dev_cmd_go(idev, &cmd);479}480 481void ionic_dev_cmd_init(struct ionic_dev *idev)482{483	union ionic_dev_cmd cmd = {484		.init.opcode = IONIC_CMD_INIT,485		.init.type = 0,486	};487 488	ionic_dev_cmd_go(idev, &cmd);489}490 491void ionic_dev_cmd_reset(struct ionic_dev *idev)492{493	union ionic_dev_cmd cmd = {494		.reset.opcode = IONIC_CMD_RESET,495	};496 497	ionic_dev_cmd_go(idev, &cmd);498}499 500/* Port commands */501void ionic_dev_cmd_port_identify(struct ionic_dev *idev)502{503	union ionic_dev_cmd cmd = {504		.port_init.opcode = IONIC_CMD_PORT_IDENTIFY,505		.port_init.index = 0,506	};507 508	ionic_dev_cmd_go(idev, &cmd);509}510 511void ionic_dev_cmd_port_init(struct ionic_dev *idev)512{513	union ionic_dev_cmd cmd = {514		.port_init.opcode = IONIC_CMD_PORT_INIT,515		.port_init.index = 0,516		.port_init.info_pa = cpu_to_le64(idev->port_info_pa),517	};518 519	ionic_dev_cmd_go(idev, &cmd);520}521 522void ionic_dev_cmd_port_reset(struct ionic_dev *idev)523{524	union ionic_dev_cmd cmd = {525		.port_reset.opcode = IONIC_CMD_PORT_RESET,526		.port_reset.index = 0,527	};528 529	ionic_dev_cmd_go(idev, &cmd);530}531 532void ionic_dev_cmd_port_state(struct ionic_dev *idev, u8 state)533{534	union ionic_dev_cmd cmd = {535		.port_setattr.opcode = IONIC_CMD_PORT_SETATTR,536		.port_setattr.index = 0,537		.port_setattr.attr = IONIC_PORT_ATTR_STATE,538		.port_setattr.state = state,539	};540 541	ionic_dev_cmd_go(idev, &cmd);542}543 544void ionic_dev_cmd_port_speed(struct ionic_dev *idev, u32 speed)545{546	union ionic_dev_cmd cmd = {547		.port_setattr.opcode = IONIC_CMD_PORT_SETATTR,548		.port_setattr.index = 0,549		.port_setattr.attr = IONIC_PORT_ATTR_SPEED,550		.port_setattr.speed = cpu_to_le32(speed),551	};552 553	ionic_dev_cmd_go(idev, &cmd);554}555 556void ionic_dev_cmd_port_autoneg(struct ionic_dev *idev, u8 an_enable)557{558	union ionic_dev_cmd cmd = {559		.port_setattr.opcode = IONIC_CMD_PORT_SETATTR,560		.port_setattr.index = 0,561		.port_setattr.attr = IONIC_PORT_ATTR_AUTONEG,562		.port_setattr.an_enable = an_enable,563	};564 565	ionic_dev_cmd_go(idev, &cmd);566}567 568void ionic_dev_cmd_port_fec(struct ionic_dev *idev, u8 fec_type)569{570	union ionic_dev_cmd cmd = {571		.port_setattr.opcode = IONIC_CMD_PORT_SETATTR,572		.port_setattr.index = 0,573		.port_setattr.attr = IONIC_PORT_ATTR_FEC,574		.port_setattr.fec_type = fec_type,575	};576 577	ionic_dev_cmd_go(idev, &cmd);578}579 580void ionic_dev_cmd_port_pause(struct ionic_dev *idev, u8 pause_type)581{582	union ionic_dev_cmd cmd = {583		.port_setattr.opcode = IONIC_CMD_PORT_SETATTR,584		.port_setattr.index = 0,585		.port_setattr.attr = IONIC_PORT_ATTR_PAUSE,586		.port_setattr.pause_type = pause_type,587	};588 589	ionic_dev_cmd_go(idev, &cmd);590}591 592/* VF commands */593int ionic_set_vf_config(struct ionic *ionic, int vf,594			struct ionic_vf_setattr_cmd *vfc)595{596	union ionic_dev_cmd cmd = {597		.vf_setattr.opcode = IONIC_CMD_VF_SETATTR,598		.vf_setattr.attr = vfc->attr,599		.vf_setattr.vf_index = cpu_to_le16(vf),600	};601	int err;602 603	memcpy(cmd.vf_setattr.pad, vfc->pad, sizeof(vfc->pad));604 605	mutex_lock(&ionic->dev_cmd_lock);606	ionic_dev_cmd_go(&ionic->idev, &cmd);607	err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT);608	mutex_unlock(&ionic->dev_cmd_lock);609 610	return err;611}612 613void ionic_vf_start(struct ionic *ionic)614{615	union ionic_dev_cmd cmd = {616		.vf_ctrl.opcode = IONIC_CMD_VF_CTRL,617		.vf_ctrl.ctrl_opcode = IONIC_VF_CTRL_START_ALL,618	};619 620	if (!(ionic->ident.dev.capabilities & cpu_to_le64(IONIC_DEV_CAP_VF_CTRL)))621		return;622 623	ionic_dev_cmd_go(&ionic->idev, &cmd);624	ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT);625}626 627/* LIF commands */628void ionic_dev_cmd_queue_identify(struct ionic_dev *idev,629				  u16 lif_type, u8 qtype, u8 qver)630{631	union ionic_dev_cmd cmd = {632		.q_identify.opcode = IONIC_CMD_Q_IDENTIFY,633		.q_identify.lif_type = cpu_to_le16(lif_type),634		.q_identify.type = qtype,635		.q_identify.ver = qver,636	};637 638	ionic_dev_cmd_go(idev, &cmd);639}640 641void ionic_dev_cmd_lif_identify(struct ionic_dev *idev, u8 type, u8 ver)642{643	union ionic_dev_cmd cmd = {644		.lif_identify.opcode = IONIC_CMD_LIF_IDENTIFY,645		.lif_identify.type = type,646		.lif_identify.ver = ver,647	};648 649	ionic_dev_cmd_go(idev, &cmd);650}651 652void ionic_dev_cmd_lif_init(struct ionic_dev *idev, u16 lif_index,653			    dma_addr_t info_pa)654{655	union ionic_dev_cmd cmd = {656		.lif_init.opcode = IONIC_CMD_LIF_INIT,657		.lif_init.index = cpu_to_le16(lif_index),658		.lif_init.info_pa = cpu_to_le64(info_pa),659	};660 661	ionic_dev_cmd_go(idev, &cmd);662}663 664void ionic_dev_cmd_lif_reset(struct ionic_dev *idev, u16 lif_index)665{666	union ionic_dev_cmd cmd = {667		.lif_init.opcode = IONIC_CMD_LIF_RESET,668		.lif_init.index = cpu_to_le16(lif_index),669	};670 671	ionic_dev_cmd_go(idev, &cmd);672}673 674void ionic_dev_cmd_adminq_init(struct ionic_dev *idev, struct ionic_qcq *qcq,675			       u16 lif_index, u16 intr_index)676{677	struct ionic_queue *q = &qcq->q;678	struct ionic_cq *cq = &qcq->cq;679 680	union ionic_dev_cmd cmd = {681		.q_init.opcode = IONIC_CMD_Q_INIT,682		.q_init.lif_index = cpu_to_le16(lif_index),683		.q_init.type = q->type,684		.q_init.ver = qcq->q.lif->qtype_info[q->type].version,685		.q_init.index = cpu_to_le32(q->index),686		.q_init.flags = cpu_to_le16(IONIC_QINIT_F_IRQ |687					    IONIC_QINIT_F_ENA),688		.q_init.pid = cpu_to_le16(q->pid),689		.q_init.intr_index = cpu_to_le16(intr_index),690		.q_init.ring_size = ilog2(q->num_descs),691		.q_init.ring_base = cpu_to_le64(q->base_pa),692		.q_init.cq_ring_base = cpu_to_le64(cq->base_pa),693	};694 695	ionic_dev_cmd_go(idev, &cmd);696}697 698int ionic_db_page_num(struct ionic_lif *lif, int pid)699{700	return (lif->hw_index * lif->dbid_count) + pid;701}702 703int ionic_get_cmb(struct ionic_lif *lif, u32 *pgid, phys_addr_t *pgaddr, int order)704{705	struct ionic_dev *idev = &lif->ionic->idev;706	int ret;707 708	mutex_lock(&idev->cmb_inuse_lock);709	ret = bitmap_find_free_region(idev->cmb_inuse, idev->cmb_npages, order);710	mutex_unlock(&idev->cmb_inuse_lock);711 712	if (ret < 0)713		return ret;714 715	*pgid = ret;716	*pgaddr = idev->phy_cmb_pages + ret * PAGE_SIZE;717 718	return 0;719}720 721void ionic_put_cmb(struct ionic_lif *lif, u32 pgid, int order)722{723	struct ionic_dev *idev = &lif->ionic->idev;724 725	mutex_lock(&idev->cmb_inuse_lock);726	bitmap_release_region(idev->cmb_inuse, pgid, order);727	mutex_unlock(&idev->cmb_inuse_lock);728}729 730int ionic_cq_init(struct ionic_lif *lif, struct ionic_cq *cq,731		  struct ionic_intr_info *intr,732		  unsigned int num_descs, size_t desc_size)733{734	unsigned int ring_size;735 736	if (desc_size == 0 || !is_power_of_2(num_descs))737		return -EINVAL;738 739	ring_size = ilog2(num_descs);740	if (ring_size < 2 || ring_size > 16)741		return -EINVAL;742 743	cq->lif = lif;744	cq->bound_intr = intr;745	cq->num_descs = num_descs;746	cq->desc_size = desc_size;747	cq->tail_idx = 0;748	cq->done_color = 1;749	cq->idev = &lif->ionic->idev;750 751	return 0;752}753 754unsigned int ionic_cq_service(struct ionic_cq *cq, unsigned int work_to_do,755			      ionic_cq_cb cb, ionic_cq_done_cb done_cb,756			      void *done_arg)757{758	unsigned int work_done = 0;759 760	if (work_to_do == 0)761		return 0;762 763	while (cb(cq)) {764		if (cq->tail_idx == cq->num_descs - 1)765			cq->done_color = !cq->done_color;766 767		cq->tail_idx = (cq->tail_idx + 1) & (cq->num_descs - 1);768 769		if (++work_done >= work_to_do)770			break;771	}772 773	if (work_done && done_cb)774		done_cb(done_arg);775 776	return work_done;777}778 779int ionic_q_init(struct ionic_lif *lif, struct ionic_dev *idev,780		 struct ionic_queue *q, unsigned int index, const char *name,781		 unsigned int num_descs, size_t desc_size,782		 size_t sg_desc_size, unsigned int pid)783{784	unsigned int ring_size;785 786	if (desc_size == 0 || !is_power_of_2(num_descs))787		return -EINVAL;788 789	ring_size = ilog2(num_descs);790	if (ring_size < 2 || ring_size > 16)791		return -EINVAL;792 793	q->lif = lif;794	q->index = index;795	q->num_descs = num_descs;796	q->desc_size = desc_size;797	q->sg_desc_size = sg_desc_size;798	q->tail_idx = 0;799	q->head_idx = 0;800	q->pid = pid;801 802	snprintf(q->name, sizeof(q->name), "L%d-%s%u", lif->index, name, index);803 804	return 0;805}806 807void ionic_q_post(struct ionic_queue *q, bool ring_doorbell)808{809	struct ionic_lif *lif = q->lif;810	struct device *dev = q->dev;811 812	q->head_idx = (q->head_idx + 1) & (q->num_descs - 1);813 814	dev_dbg(dev, "lif=%d qname=%s qid=%d qtype=%d p_index=%d ringdb=%d\n",815		q->lif->index, q->name, q->hw_type, q->hw_index,816		q->head_idx, ring_doorbell);817 818	if (ring_doorbell) {819		ionic_dbell_ring(lif->kern_dbpage, q->hw_type,820				 q->dbval | q->head_idx);821 822		q->dbell_jiffies = jiffies;823	}824}825 826bool ionic_q_is_posted(struct ionic_queue *q, unsigned int pos)827{828	unsigned int mask, tail, head;829 830	mask = q->num_descs - 1;831	tail = q->tail_idx;832	head = q->head_idx;833 834	return ((pos - tail) & mask) < ((head - tail) & mask);835}836