xref: /dpdk/drivers/net/ionic/ionic_dev.c (revision 01a6c311df2fa78928d46eb9bf4f2658a3cc08ee)
15ef51809SAlfredo Cardigliano /* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0)
25ef51809SAlfredo Cardigliano  * Copyright(c) 2018-2019 Pensando Systems, Inc. All rights reserved.
35ef51809SAlfredo Cardigliano  */
45ef51809SAlfredo Cardigliano 
55ef51809SAlfredo Cardigliano #include <rte_malloc.h>
65ef51809SAlfredo Cardigliano 
75ef51809SAlfredo Cardigliano #include "ionic_dev.h"
8c67719e1SAlfredo Cardigliano #include "ionic_lif.h"
95ef51809SAlfredo Cardigliano #include "ionic.h"
105ef51809SAlfredo Cardigliano 
115ef51809SAlfredo Cardigliano int
125ef51809SAlfredo Cardigliano ionic_dev_setup(struct ionic_adapter *adapter)
135ef51809SAlfredo Cardigliano {
145ef51809SAlfredo Cardigliano 	struct ionic_dev_bar *bar = adapter->bars;
155ef51809SAlfredo Cardigliano 	unsigned int num_bars = adapter->num_bars;
165ef51809SAlfredo Cardigliano 	struct ionic_dev *idev = &adapter->idev;
175ef51809SAlfredo Cardigliano 	uint32_t sig;
185ef51809SAlfredo Cardigliano 	u_char *bar0_base;
195ef51809SAlfredo Cardigliano 
205ef51809SAlfredo Cardigliano 	/* BAR0: dev_cmd and interrupts */
215ef51809SAlfredo Cardigliano 	if (num_bars < 1) {
225ef51809SAlfredo Cardigliano 		IONIC_PRINT(ERR, "No bars found, aborting");
235ef51809SAlfredo Cardigliano 		return -EFAULT;
245ef51809SAlfredo Cardigliano 	}
255ef51809SAlfredo Cardigliano 
265ef51809SAlfredo Cardigliano 	if (bar->len < IONIC_BAR0_SIZE) {
275ef51809SAlfredo Cardigliano 		IONIC_PRINT(ERR,
285ef51809SAlfredo Cardigliano 			"Resource bar size %lu too small, aborting",
295ef51809SAlfredo Cardigliano 			bar->len);
305ef51809SAlfredo Cardigliano 		return -EFAULT;
315ef51809SAlfredo Cardigliano 	}
325ef51809SAlfredo Cardigliano 
335ef51809SAlfredo Cardigliano 	bar0_base = bar->vaddr;
345ef51809SAlfredo Cardigliano 	idev->dev_info = (union ionic_dev_info_regs *)
355ef51809SAlfredo Cardigliano 		&bar0_base[IONIC_BAR0_DEV_INFO_REGS_OFFSET];
365ef51809SAlfredo Cardigliano 	idev->dev_cmd = (union ionic_dev_cmd_regs *)
375ef51809SAlfredo Cardigliano 		&bar0_base[IONIC_BAR0_DEV_CMD_REGS_OFFSET];
385ef51809SAlfredo Cardigliano 	idev->intr_status = (struct ionic_intr_status *)
395ef51809SAlfredo Cardigliano 		&bar0_base[IONIC_BAR0_INTR_STATUS_OFFSET];
405ef51809SAlfredo Cardigliano 	idev->intr_ctrl = (struct ionic_intr *)
415ef51809SAlfredo Cardigliano 		&bar0_base[IONIC_BAR0_INTR_CTRL_OFFSET];
425ef51809SAlfredo Cardigliano 
435ef51809SAlfredo Cardigliano 	sig = ioread32(&idev->dev_info->signature);
445ef51809SAlfredo Cardigliano 	if (sig != IONIC_DEV_INFO_SIGNATURE) {
455ef51809SAlfredo Cardigliano 		IONIC_PRINT(ERR, "Incompatible firmware signature %" PRIx32 "",
465ef51809SAlfredo Cardigliano 			sig);
475ef51809SAlfredo Cardigliano 		return -EFAULT;
485ef51809SAlfredo Cardigliano 	}
495ef51809SAlfredo Cardigliano 
505ef51809SAlfredo Cardigliano 	/* BAR1: doorbells */
515ef51809SAlfredo Cardigliano 	bar++;
525ef51809SAlfredo Cardigliano 	if (num_bars < 2) {
535ef51809SAlfredo Cardigliano 		IONIC_PRINT(ERR, "Doorbell bar missing, aborting");
545ef51809SAlfredo Cardigliano 		return -EFAULT;
555ef51809SAlfredo Cardigliano 	}
565ef51809SAlfredo Cardigliano 
575ef51809SAlfredo Cardigliano 	idev->db_pages = bar->vaddr;
585ef51809SAlfredo Cardigliano 	idev->phy_db_pages = bar->bus_addr;
595ef51809SAlfredo Cardigliano 
605ef51809SAlfredo Cardigliano 	return 0;
615ef51809SAlfredo Cardigliano }
625ef51809SAlfredo Cardigliano 
635ef51809SAlfredo Cardigliano /* Devcmd Interface */
645ef51809SAlfredo Cardigliano 
655ef51809SAlfredo Cardigliano uint8_t
665ef51809SAlfredo Cardigliano ionic_dev_cmd_status(struct ionic_dev *idev)
675ef51809SAlfredo Cardigliano {
685ef51809SAlfredo Cardigliano 	return ioread8(&idev->dev_cmd->comp.comp.status);
695ef51809SAlfredo Cardigliano }
705ef51809SAlfredo Cardigliano 
715ef51809SAlfredo Cardigliano bool
725ef51809SAlfredo Cardigliano ionic_dev_cmd_done(struct ionic_dev *idev)
735ef51809SAlfredo Cardigliano {
745ef51809SAlfredo Cardigliano 	return ioread32(&idev->dev_cmd->done) & IONIC_DEV_CMD_DONE;
755ef51809SAlfredo Cardigliano }
765ef51809SAlfredo Cardigliano 
775ef51809SAlfredo Cardigliano void
785ef51809SAlfredo Cardigliano ionic_dev_cmd_comp(struct ionic_dev *idev, void *mem)
795ef51809SAlfredo Cardigliano {
805ef51809SAlfredo Cardigliano 	union ionic_dev_cmd_comp *comp = mem;
815ef51809SAlfredo Cardigliano 	unsigned int i;
825ef51809SAlfredo Cardigliano 	uint32_t comp_size = sizeof(comp->words) /
835ef51809SAlfredo Cardigliano 		sizeof(comp->words[0]);
845ef51809SAlfredo Cardigliano 
855ef51809SAlfredo Cardigliano 	for (i = 0; i < comp_size; i++)
865ef51809SAlfredo Cardigliano 		comp->words[i] = ioread32(&idev->dev_cmd->comp.words[i]);
875ef51809SAlfredo Cardigliano }
885ef51809SAlfredo Cardigliano 
895ef51809SAlfredo Cardigliano void
905ef51809SAlfredo Cardigliano ionic_dev_cmd_go(struct ionic_dev *idev, union ionic_dev_cmd *cmd)
915ef51809SAlfredo Cardigliano {
925ef51809SAlfredo Cardigliano 	unsigned int i;
935ef51809SAlfredo Cardigliano 	uint32_t cmd_size = sizeof(cmd->words) /
945ef51809SAlfredo Cardigliano 		sizeof(cmd->words[0]);
955ef51809SAlfredo Cardigliano 
965ef51809SAlfredo Cardigliano 	for (i = 0; i < cmd_size; i++)
975ef51809SAlfredo Cardigliano 		iowrite32(cmd->words[i], &idev->dev_cmd->cmd.words[i]);
985ef51809SAlfredo Cardigliano 
995ef51809SAlfredo Cardigliano 	iowrite32(0, &idev->dev_cmd->done);
1005ef51809SAlfredo Cardigliano 	iowrite32(1, &idev->dev_cmd->doorbell);
1015ef51809SAlfredo Cardigliano }
1025ef51809SAlfredo Cardigliano 
1035ef51809SAlfredo Cardigliano /* Device commands */
1045ef51809SAlfredo Cardigliano 
1055ef51809SAlfredo Cardigliano void
1065ef51809SAlfredo Cardigliano ionic_dev_cmd_identify(struct ionic_dev *idev, uint8_t ver)
1075ef51809SAlfredo Cardigliano {
1085ef51809SAlfredo Cardigliano 	union ionic_dev_cmd cmd = {
1095ef51809SAlfredo Cardigliano 		.identify.opcode = IONIC_CMD_IDENTIFY,
1105ef51809SAlfredo Cardigliano 		.identify.ver = ver,
1115ef51809SAlfredo Cardigliano 	};
1125ef51809SAlfredo Cardigliano 
1135ef51809SAlfredo Cardigliano 	ionic_dev_cmd_go(idev, &cmd);
1145ef51809SAlfredo Cardigliano }
1155ef51809SAlfredo Cardigliano 
1165ef51809SAlfredo Cardigliano void
1175ef51809SAlfredo Cardigliano ionic_dev_cmd_init(struct ionic_dev *idev)
1185ef51809SAlfredo Cardigliano {
1195ef51809SAlfredo Cardigliano 	union ionic_dev_cmd cmd = {
1205ef51809SAlfredo Cardigliano 		.init.opcode = IONIC_CMD_INIT,
1215ef51809SAlfredo Cardigliano 		.init.type = 0,
1225ef51809SAlfredo Cardigliano 	};
1235ef51809SAlfredo Cardigliano 
1245ef51809SAlfredo Cardigliano 	ionic_dev_cmd_go(idev, &cmd);
1255ef51809SAlfredo Cardigliano }
1265ef51809SAlfredo Cardigliano 
1275ef51809SAlfredo Cardigliano void
1285ef51809SAlfredo Cardigliano ionic_dev_cmd_reset(struct ionic_dev *idev)
1295ef51809SAlfredo Cardigliano {
1305ef51809SAlfredo Cardigliano 	union ionic_dev_cmd cmd = {
1315ef51809SAlfredo Cardigliano 		.reset.opcode = IONIC_CMD_RESET,
1325ef51809SAlfredo Cardigliano 	};
1335ef51809SAlfredo Cardigliano 
1345ef51809SAlfredo Cardigliano 	ionic_dev_cmd_go(idev, &cmd);
1355ef51809SAlfredo Cardigliano }
13623bf4ddbSAlfredo Cardigliano 
13723bf4ddbSAlfredo Cardigliano /* Port commands */
13823bf4ddbSAlfredo Cardigliano 
13923bf4ddbSAlfredo Cardigliano void
14023bf4ddbSAlfredo Cardigliano ionic_dev_cmd_port_identify(struct ionic_dev *idev)
14123bf4ddbSAlfredo Cardigliano {
14223bf4ddbSAlfredo Cardigliano 	union ionic_dev_cmd cmd = {
14323bf4ddbSAlfredo Cardigliano 		.port_init.opcode = IONIC_CMD_PORT_IDENTIFY,
14423bf4ddbSAlfredo Cardigliano 		.port_init.index = 0,
14523bf4ddbSAlfredo Cardigliano 	};
14623bf4ddbSAlfredo Cardigliano 
14723bf4ddbSAlfredo Cardigliano 	ionic_dev_cmd_go(idev, &cmd);
14823bf4ddbSAlfredo Cardigliano }
14923bf4ddbSAlfredo Cardigliano 
15023bf4ddbSAlfredo Cardigliano void
15123bf4ddbSAlfredo Cardigliano ionic_dev_cmd_port_init(struct ionic_dev *idev)
15223bf4ddbSAlfredo Cardigliano {
15323bf4ddbSAlfredo Cardigliano 	union ionic_dev_cmd cmd = {
15423bf4ddbSAlfredo Cardigliano 		.port_init.opcode = IONIC_CMD_PORT_INIT,
15523bf4ddbSAlfredo Cardigliano 		.port_init.index = 0,
15623bf4ddbSAlfredo Cardigliano 		.port_init.info_pa = idev->port_info_pa,
15723bf4ddbSAlfredo Cardigliano 	};
15823bf4ddbSAlfredo Cardigliano 
15923bf4ddbSAlfredo Cardigliano 	ionic_dev_cmd_go(idev, &cmd);
16023bf4ddbSAlfredo Cardigliano }
16123bf4ddbSAlfredo Cardigliano 
16223bf4ddbSAlfredo Cardigliano void
16323bf4ddbSAlfredo Cardigliano ionic_dev_cmd_port_reset(struct ionic_dev *idev)
16423bf4ddbSAlfredo Cardigliano {
16523bf4ddbSAlfredo Cardigliano 	union ionic_dev_cmd cmd = {
16623bf4ddbSAlfredo Cardigliano 		.port_reset.opcode = IONIC_CMD_PORT_RESET,
16723bf4ddbSAlfredo Cardigliano 		.port_reset.index = 0,
16823bf4ddbSAlfredo Cardigliano 	};
16923bf4ddbSAlfredo Cardigliano 
17023bf4ddbSAlfredo Cardigliano 	ionic_dev_cmd_go(idev, &cmd);
17123bf4ddbSAlfredo Cardigliano }
17223bf4ddbSAlfredo Cardigliano 
17323bf4ddbSAlfredo Cardigliano void
17423bf4ddbSAlfredo Cardigliano ionic_dev_cmd_port_state(struct ionic_dev *idev, uint8_t state)
17523bf4ddbSAlfredo Cardigliano {
17623bf4ddbSAlfredo Cardigliano 	union ionic_dev_cmd cmd = {
17723bf4ddbSAlfredo Cardigliano 		.port_setattr.opcode = IONIC_CMD_PORT_SETATTR,
17823bf4ddbSAlfredo Cardigliano 		.port_setattr.index = 0,
17923bf4ddbSAlfredo Cardigliano 		.port_setattr.attr = IONIC_PORT_ATTR_STATE,
18023bf4ddbSAlfredo Cardigliano 		.port_setattr.state = state,
18123bf4ddbSAlfredo Cardigliano 	};
18223bf4ddbSAlfredo Cardigliano 
18323bf4ddbSAlfredo Cardigliano 	ionic_dev_cmd_go(idev, &cmd);
18423bf4ddbSAlfredo Cardigliano }
18523bf4ddbSAlfredo Cardigliano 
18623bf4ddbSAlfredo Cardigliano void
18723bf4ddbSAlfredo Cardigliano ionic_dev_cmd_port_speed(struct ionic_dev *idev, uint32_t speed)
18823bf4ddbSAlfredo Cardigliano {
18923bf4ddbSAlfredo Cardigliano 	union ionic_dev_cmd cmd = {
19023bf4ddbSAlfredo Cardigliano 		.port_setattr.opcode = IONIC_CMD_PORT_SETATTR,
19123bf4ddbSAlfredo Cardigliano 		.port_setattr.index = 0,
19223bf4ddbSAlfredo Cardigliano 		.port_setattr.attr = IONIC_PORT_ATTR_SPEED,
19323bf4ddbSAlfredo Cardigliano 		.port_setattr.speed = speed,
19423bf4ddbSAlfredo Cardigliano 	};
19523bf4ddbSAlfredo Cardigliano 
19623bf4ddbSAlfredo Cardigliano 	ionic_dev_cmd_go(idev, &cmd);
19723bf4ddbSAlfredo Cardigliano }
19823bf4ddbSAlfredo Cardigliano 
19923bf4ddbSAlfredo Cardigliano void
20023bf4ddbSAlfredo Cardigliano ionic_dev_cmd_port_mtu(struct ionic_dev *idev, uint32_t mtu)
20123bf4ddbSAlfredo Cardigliano {
20223bf4ddbSAlfredo Cardigliano 	union ionic_dev_cmd cmd = {
20323bf4ddbSAlfredo Cardigliano 		.port_setattr.opcode = IONIC_CMD_PORT_SETATTR,
20423bf4ddbSAlfredo Cardigliano 		.port_setattr.index = 0,
20523bf4ddbSAlfredo Cardigliano 		.port_setattr.attr = IONIC_PORT_ATTR_MTU,
20623bf4ddbSAlfredo Cardigliano 		.port_setattr.mtu = mtu,
20723bf4ddbSAlfredo Cardigliano 	};
20823bf4ddbSAlfredo Cardigliano 
20923bf4ddbSAlfredo Cardigliano 	ionic_dev_cmd_go(idev, &cmd);
21023bf4ddbSAlfredo Cardigliano }
21123bf4ddbSAlfredo Cardigliano 
21223bf4ddbSAlfredo Cardigliano void
21323bf4ddbSAlfredo Cardigliano ionic_dev_cmd_port_autoneg(struct ionic_dev *idev, uint8_t an_enable)
21423bf4ddbSAlfredo Cardigliano {
21523bf4ddbSAlfredo Cardigliano 	union ionic_dev_cmd cmd = {
21623bf4ddbSAlfredo Cardigliano 		.port_setattr.opcode = IONIC_CMD_PORT_SETATTR,
21723bf4ddbSAlfredo Cardigliano 		.port_setattr.index = 0,
21823bf4ddbSAlfredo Cardigliano 		.port_setattr.attr = IONIC_PORT_ATTR_AUTONEG,
21923bf4ddbSAlfredo Cardigliano 		.port_setattr.an_enable = an_enable,
22023bf4ddbSAlfredo Cardigliano 	};
22123bf4ddbSAlfredo Cardigliano 
22223bf4ddbSAlfredo Cardigliano 	ionic_dev_cmd_go(idev, &cmd);
22323bf4ddbSAlfredo Cardigliano }
22423bf4ddbSAlfredo Cardigliano 
22523bf4ddbSAlfredo Cardigliano void
22623bf4ddbSAlfredo Cardigliano ionic_dev_cmd_port_fec(struct ionic_dev *idev, uint8_t fec_type)
22723bf4ddbSAlfredo Cardigliano {
22823bf4ddbSAlfredo Cardigliano 	union ionic_dev_cmd cmd = {
22923bf4ddbSAlfredo Cardigliano 		.port_setattr.opcode = IONIC_CMD_PORT_SETATTR,
23023bf4ddbSAlfredo Cardigliano 		.port_setattr.index = 0,
23123bf4ddbSAlfredo Cardigliano 		.port_setattr.attr = IONIC_PORT_ATTR_FEC,
23223bf4ddbSAlfredo Cardigliano 		.port_setattr.fec_type = fec_type,
23323bf4ddbSAlfredo Cardigliano 	};
23423bf4ddbSAlfredo Cardigliano 
23523bf4ddbSAlfredo Cardigliano 	ionic_dev_cmd_go(idev, &cmd);
23623bf4ddbSAlfredo Cardigliano }
23723bf4ddbSAlfredo Cardigliano 
23823bf4ddbSAlfredo Cardigliano void
23923bf4ddbSAlfredo Cardigliano ionic_dev_cmd_port_pause(struct ionic_dev *idev, uint8_t pause_type)
24023bf4ddbSAlfredo Cardigliano {
24123bf4ddbSAlfredo Cardigliano 	union ionic_dev_cmd cmd = {
24223bf4ddbSAlfredo Cardigliano 		.port_setattr.opcode = IONIC_CMD_PORT_SETATTR,
24323bf4ddbSAlfredo Cardigliano 		.port_setattr.index = 0,
24423bf4ddbSAlfredo Cardigliano 		.port_setattr.attr = IONIC_PORT_ATTR_PAUSE,
24523bf4ddbSAlfredo Cardigliano 		.port_setattr.pause_type = pause_type,
24623bf4ddbSAlfredo Cardigliano 	};
24723bf4ddbSAlfredo Cardigliano 
24823bf4ddbSAlfredo Cardigliano 	ionic_dev_cmd_go(idev, &cmd);
24923bf4ddbSAlfredo Cardigliano }
25023bf4ddbSAlfredo Cardigliano 
25123bf4ddbSAlfredo Cardigliano void
25223bf4ddbSAlfredo Cardigliano ionic_dev_cmd_port_loopback(struct ionic_dev *idev, uint8_t loopback_mode)
25323bf4ddbSAlfredo Cardigliano {
25423bf4ddbSAlfredo Cardigliano 	union ionic_dev_cmd cmd = {
25523bf4ddbSAlfredo Cardigliano 		.port_setattr.opcode = IONIC_CMD_PORT_SETATTR,
25623bf4ddbSAlfredo Cardigliano 		.port_setattr.index = 0,
25723bf4ddbSAlfredo Cardigliano 		.port_setattr.attr = IONIC_PORT_ATTR_LOOPBACK,
25823bf4ddbSAlfredo Cardigliano 		.port_setattr.loopback_mode = loopback_mode,
25923bf4ddbSAlfredo Cardigliano 	};
26023bf4ddbSAlfredo Cardigliano 
26123bf4ddbSAlfredo Cardigliano 	ionic_dev_cmd_go(idev, &cmd);
26223bf4ddbSAlfredo Cardigliano }
263669c8de6SAlfredo Cardigliano 
264669c8de6SAlfredo Cardigliano /* LIF commands */
265669c8de6SAlfredo Cardigliano 
266669c8de6SAlfredo Cardigliano void
267669c8de6SAlfredo Cardigliano ionic_dev_cmd_lif_identify(struct ionic_dev *idev, uint8_t type, uint8_t ver)
268669c8de6SAlfredo Cardigliano {
269669c8de6SAlfredo Cardigliano 	union ionic_dev_cmd cmd = {
270669c8de6SAlfredo Cardigliano 		.lif_identify.opcode = IONIC_CMD_LIF_IDENTIFY,
271669c8de6SAlfredo Cardigliano 		.lif_identify.type = type,
272669c8de6SAlfredo Cardigliano 		.lif_identify.ver = ver,
273669c8de6SAlfredo Cardigliano 	};
274669c8de6SAlfredo Cardigliano 
275669c8de6SAlfredo Cardigliano 	ionic_dev_cmd_go(idev, &cmd);
276669c8de6SAlfredo Cardigliano }
277669c8de6SAlfredo Cardigliano 
278669c8de6SAlfredo Cardigliano void
279669c8de6SAlfredo Cardigliano ionic_dev_cmd_lif_init(struct ionic_dev *idev, uint16_t lif_index,
280669c8de6SAlfredo Cardigliano 		       rte_iova_t info_pa)
281669c8de6SAlfredo Cardigliano {
282669c8de6SAlfredo Cardigliano 	union ionic_dev_cmd cmd = {
283669c8de6SAlfredo Cardigliano 		.lif_init.opcode = IONIC_CMD_LIF_INIT,
284669c8de6SAlfredo Cardigliano 		.lif_init.index = lif_index,
285669c8de6SAlfredo Cardigliano 		.lif_init.info_pa = info_pa,
286669c8de6SAlfredo Cardigliano 	};
287669c8de6SAlfredo Cardigliano 
288669c8de6SAlfredo Cardigliano 	ionic_dev_cmd_go(idev, &cmd);
289669c8de6SAlfredo Cardigliano }
290669c8de6SAlfredo Cardigliano 
291669c8de6SAlfredo Cardigliano void
292669c8de6SAlfredo Cardigliano ionic_dev_cmd_lif_reset(struct ionic_dev *idev, uint16_t lif_index)
293669c8de6SAlfredo Cardigliano {
294669c8de6SAlfredo Cardigliano 	union ionic_dev_cmd cmd = {
295669c8de6SAlfredo Cardigliano 		.lif_init.opcode = IONIC_CMD_LIF_RESET,
296669c8de6SAlfredo Cardigliano 		.lif_init.index = lif_index,
297669c8de6SAlfredo Cardigliano 	};
298669c8de6SAlfredo Cardigliano 
299669c8de6SAlfredo Cardigliano 	ionic_dev_cmd_go(idev, &cmd);
300669c8de6SAlfredo Cardigliano }
301c67719e1SAlfredo Cardigliano 
302*01a6c311SAlfredo Cardigliano struct ionic_doorbell *
303*01a6c311SAlfredo Cardigliano ionic_db_map(struct ionic_lif *lif, struct ionic_queue *q)
304*01a6c311SAlfredo Cardigliano {
305*01a6c311SAlfredo Cardigliano 	return lif->kern_dbpage + q->hw_type;
306*01a6c311SAlfredo Cardigliano }
307*01a6c311SAlfredo Cardigliano 
308c67719e1SAlfredo Cardigliano int
309c67719e1SAlfredo Cardigliano ionic_db_page_num(struct ionic_lif *lif, int pid)
310c67719e1SAlfredo Cardigliano {
311c67719e1SAlfredo Cardigliano 	return (lif->index * 0) + pid;
312c67719e1SAlfredo Cardigliano }
313c67719e1SAlfredo Cardigliano 
314c67719e1SAlfredo Cardigliano void
315c67719e1SAlfredo Cardigliano ionic_intr_init(struct ionic_dev *idev, struct ionic_intr_info *intr,
316c67719e1SAlfredo Cardigliano 		unsigned long index)
317c67719e1SAlfredo Cardigliano {
318c67719e1SAlfredo Cardigliano 	ionic_intr_clean(idev->intr_ctrl, index);
319c67719e1SAlfredo Cardigliano 	intr->index = index;
320c67719e1SAlfredo Cardigliano }
321*01a6c311SAlfredo Cardigliano 
322*01a6c311SAlfredo Cardigliano void
323*01a6c311SAlfredo Cardigliano ionic_dev_cmd_adminq_init(struct ionic_dev *idev,
324*01a6c311SAlfredo Cardigliano 		struct ionic_qcq *qcq,
325*01a6c311SAlfredo Cardigliano 		uint16_t lif_index, uint16_t intr_index)
326*01a6c311SAlfredo Cardigliano {
327*01a6c311SAlfredo Cardigliano 	struct ionic_queue *q = &qcq->q;
328*01a6c311SAlfredo Cardigliano 	struct ionic_cq *cq = &qcq->cq;
329*01a6c311SAlfredo Cardigliano 
330*01a6c311SAlfredo Cardigliano 	union ionic_dev_cmd cmd = {
331*01a6c311SAlfredo Cardigliano 		.q_init.opcode = IONIC_CMD_Q_INIT,
332*01a6c311SAlfredo Cardigliano 		.q_init.lif_index = lif_index,
333*01a6c311SAlfredo Cardigliano 		.q_init.type = q->type,
334*01a6c311SAlfredo Cardigliano 		.q_init.index = q->index,
335*01a6c311SAlfredo Cardigliano 		.q_init.flags = IONIC_QINIT_F_ENA,
336*01a6c311SAlfredo Cardigliano 		.q_init.pid = q->pid,
337*01a6c311SAlfredo Cardigliano 		.q_init.intr_index = intr_index,
338*01a6c311SAlfredo Cardigliano 		.q_init.ring_size = rte_log2_u32(q->num_descs),
339*01a6c311SAlfredo Cardigliano 		.q_init.ring_base = q->base_pa,
340*01a6c311SAlfredo Cardigliano 		.q_init.cq_ring_base = cq->base_pa,
341*01a6c311SAlfredo Cardigliano 	};
342*01a6c311SAlfredo Cardigliano 
343*01a6c311SAlfredo Cardigliano 	ionic_dev_cmd_go(idev, &cmd);
344*01a6c311SAlfredo Cardigliano }
345*01a6c311SAlfredo Cardigliano 
346*01a6c311SAlfredo Cardigliano int
347*01a6c311SAlfredo Cardigliano ionic_cq_init(struct ionic_lif *lif, struct ionic_cq *cq,
348*01a6c311SAlfredo Cardigliano 		struct ionic_intr_info *intr,
349*01a6c311SAlfredo Cardigliano 		uint32_t num_descs, size_t desc_size)
350*01a6c311SAlfredo Cardigliano {
351*01a6c311SAlfredo Cardigliano 	if (desc_size == 0) {
352*01a6c311SAlfredo Cardigliano 		IONIC_PRINT(ERR, "Descriptor size is %zu", desc_size);
353*01a6c311SAlfredo Cardigliano 		return -EINVAL;
354*01a6c311SAlfredo Cardigliano 	}
355*01a6c311SAlfredo Cardigliano 
356*01a6c311SAlfredo Cardigliano 	if (!rte_is_power_of_2(num_descs) ||
357*01a6c311SAlfredo Cardigliano 	    num_descs < IONIC_MIN_RING_DESC ||
358*01a6c311SAlfredo Cardigliano 	    num_descs > IONIC_MAX_RING_DESC) {
359*01a6c311SAlfredo Cardigliano 		IONIC_PRINT(ERR, "%u descriptors (min: %u max: %u)",
360*01a6c311SAlfredo Cardigliano 			num_descs, IONIC_MIN_RING_DESC, IONIC_MAX_RING_DESC);
361*01a6c311SAlfredo Cardigliano 		return -EINVAL;
362*01a6c311SAlfredo Cardigliano 	}
363*01a6c311SAlfredo Cardigliano 
364*01a6c311SAlfredo Cardigliano 	cq->lif = lif;
365*01a6c311SAlfredo Cardigliano 	cq->bound_intr = intr;
366*01a6c311SAlfredo Cardigliano 	cq->num_descs = num_descs;
367*01a6c311SAlfredo Cardigliano 	cq->desc_size = desc_size;
368*01a6c311SAlfredo Cardigliano 	cq->tail_idx = 0;
369*01a6c311SAlfredo Cardigliano 	cq->done_color = 1;
370*01a6c311SAlfredo Cardigliano 
371*01a6c311SAlfredo Cardigliano 	return 0;
372*01a6c311SAlfredo Cardigliano }
373*01a6c311SAlfredo Cardigliano 
374*01a6c311SAlfredo Cardigliano void
375*01a6c311SAlfredo Cardigliano ionic_cq_map(struct ionic_cq *cq, void *base, rte_iova_t base_pa)
376*01a6c311SAlfredo Cardigliano {
377*01a6c311SAlfredo Cardigliano 	cq->base = base;
378*01a6c311SAlfredo Cardigliano 	cq->base_pa = base_pa;
379*01a6c311SAlfredo Cardigliano }
380*01a6c311SAlfredo Cardigliano 
381*01a6c311SAlfredo Cardigliano void
382*01a6c311SAlfredo Cardigliano ionic_cq_bind(struct ionic_cq *cq, struct ionic_queue *q)
383*01a6c311SAlfredo Cardigliano {
384*01a6c311SAlfredo Cardigliano 	cq->bound_q = q;
385*01a6c311SAlfredo Cardigliano 	q->bound_cq = cq;
386*01a6c311SAlfredo Cardigliano }
387*01a6c311SAlfredo Cardigliano 
388*01a6c311SAlfredo Cardigliano uint32_t
389*01a6c311SAlfredo Cardigliano ionic_cq_service(struct ionic_cq *cq, uint32_t work_to_do,
390*01a6c311SAlfredo Cardigliano 		 ionic_cq_cb cb, void *cb_arg)
391*01a6c311SAlfredo Cardigliano {
392*01a6c311SAlfredo Cardigliano 	uint32_t work_done = 0;
393*01a6c311SAlfredo Cardigliano 
394*01a6c311SAlfredo Cardigliano 	if (work_to_do == 0)
395*01a6c311SAlfredo Cardigliano 		return 0;
396*01a6c311SAlfredo Cardigliano 
397*01a6c311SAlfredo Cardigliano 	while (cb(cq, cq->tail_idx, cb_arg)) {
398*01a6c311SAlfredo Cardigliano 		cq->tail_idx = (cq->tail_idx + 1) & (cq->num_descs - 1);
399*01a6c311SAlfredo Cardigliano 		if (cq->tail_idx == 0)
400*01a6c311SAlfredo Cardigliano 			cq->done_color = !cq->done_color;
401*01a6c311SAlfredo Cardigliano 
402*01a6c311SAlfredo Cardigliano 		if (++work_done == work_to_do)
403*01a6c311SAlfredo Cardigliano 			break;
404*01a6c311SAlfredo Cardigliano 	}
405*01a6c311SAlfredo Cardigliano 
406*01a6c311SAlfredo Cardigliano 	return work_done;
407*01a6c311SAlfredo Cardigliano }
408*01a6c311SAlfredo Cardigliano 
409*01a6c311SAlfredo Cardigliano int
410*01a6c311SAlfredo Cardigliano ionic_q_init(struct ionic_lif *lif, struct ionic_dev *idev,
411*01a6c311SAlfredo Cardigliano 	     struct ionic_queue *q, uint32_t index, uint32_t num_descs,
412*01a6c311SAlfredo Cardigliano 	     size_t desc_size, size_t sg_desc_size, uint32_t pid)
413*01a6c311SAlfredo Cardigliano {
414*01a6c311SAlfredo Cardigliano 	uint32_t ring_size;
415*01a6c311SAlfredo Cardigliano 
416*01a6c311SAlfredo Cardigliano 	if (desc_size == 0 || !rte_is_power_of_2(num_descs))
417*01a6c311SAlfredo Cardigliano 		return -EINVAL;
418*01a6c311SAlfredo Cardigliano 
419*01a6c311SAlfredo Cardigliano 	ring_size = rte_log2_u32(num_descs);
420*01a6c311SAlfredo Cardigliano 
421*01a6c311SAlfredo Cardigliano 	if (ring_size < 2 || ring_size > 16)
422*01a6c311SAlfredo Cardigliano 		return -EINVAL;
423*01a6c311SAlfredo Cardigliano 
424*01a6c311SAlfredo Cardigliano 	q->lif = lif;
425*01a6c311SAlfredo Cardigliano 	q->idev = idev;
426*01a6c311SAlfredo Cardigliano 	q->index = index;
427*01a6c311SAlfredo Cardigliano 	q->num_descs = num_descs;
428*01a6c311SAlfredo Cardigliano 	q->desc_size = desc_size;
429*01a6c311SAlfredo Cardigliano 	q->sg_desc_size = sg_desc_size;
430*01a6c311SAlfredo Cardigliano 	q->head_idx = 0;
431*01a6c311SAlfredo Cardigliano 	q->tail_idx = 0;
432*01a6c311SAlfredo Cardigliano 	q->pid = pid;
433*01a6c311SAlfredo Cardigliano 
434*01a6c311SAlfredo Cardigliano 	return 0;
435*01a6c311SAlfredo Cardigliano }
436*01a6c311SAlfredo Cardigliano 
437*01a6c311SAlfredo Cardigliano void
438*01a6c311SAlfredo Cardigliano ionic_q_map(struct ionic_queue *q, void *base, rte_iova_t base_pa)
439*01a6c311SAlfredo Cardigliano {
440*01a6c311SAlfredo Cardigliano 	q->base = base;
441*01a6c311SAlfredo Cardigliano 	q->base_pa = base_pa;
442*01a6c311SAlfredo Cardigliano }
443*01a6c311SAlfredo Cardigliano 
444*01a6c311SAlfredo Cardigliano void
445*01a6c311SAlfredo Cardigliano ionic_q_sg_map(struct ionic_queue *q, void *base, rte_iova_t base_pa)
446*01a6c311SAlfredo Cardigliano {
447*01a6c311SAlfredo Cardigliano 	q->sg_base = base;
448*01a6c311SAlfredo Cardigliano 	q->sg_base_pa = base_pa;
449*01a6c311SAlfredo Cardigliano }
450*01a6c311SAlfredo Cardigliano 
451*01a6c311SAlfredo Cardigliano void
452*01a6c311SAlfredo Cardigliano ionic_q_flush(struct ionic_queue *q)
453*01a6c311SAlfredo Cardigliano {
454*01a6c311SAlfredo Cardigliano 	writeq(IONIC_DBELL_QID(q->hw_index) | q->head_idx, q->db);
455*01a6c311SAlfredo Cardigliano }
456*01a6c311SAlfredo Cardigliano 
457*01a6c311SAlfredo Cardigliano void
458*01a6c311SAlfredo Cardigliano ionic_q_post(struct ionic_queue *q, bool ring_doorbell, desc_cb cb,
459*01a6c311SAlfredo Cardigliano 	     void *cb_arg)
460*01a6c311SAlfredo Cardigliano {
461*01a6c311SAlfredo Cardigliano 	struct ionic_desc_info *head = &q->info[q->head_idx];
462*01a6c311SAlfredo Cardigliano 
463*01a6c311SAlfredo Cardigliano 	head->cb = cb;
464*01a6c311SAlfredo Cardigliano 	head->cb_arg = cb_arg;
465*01a6c311SAlfredo Cardigliano 
466*01a6c311SAlfredo Cardigliano 	q->head_idx = (q->head_idx + 1) & (q->num_descs - 1);
467*01a6c311SAlfredo Cardigliano 
468*01a6c311SAlfredo Cardigliano 	if (ring_doorbell)
469*01a6c311SAlfredo Cardigliano 		ionic_q_flush(q);
470*01a6c311SAlfredo Cardigliano }
471*01a6c311SAlfredo Cardigliano 
472*01a6c311SAlfredo Cardigliano uint32_t
473*01a6c311SAlfredo Cardigliano ionic_q_space_avail(struct ionic_queue *q)
474*01a6c311SAlfredo Cardigliano {
475*01a6c311SAlfredo Cardigliano 	uint32_t avail = q->tail_idx;
476*01a6c311SAlfredo Cardigliano 
477*01a6c311SAlfredo Cardigliano 	if (q->head_idx >= avail)
478*01a6c311SAlfredo Cardigliano 		avail += q->num_descs - q->head_idx - 1;
479*01a6c311SAlfredo Cardigliano 	else
480*01a6c311SAlfredo Cardigliano 		avail -= q->head_idx + 1;
481*01a6c311SAlfredo Cardigliano 
482*01a6c311SAlfredo Cardigliano 	return avail;
483*01a6c311SAlfredo Cardigliano }
484*01a6c311SAlfredo Cardigliano 
485*01a6c311SAlfredo Cardigliano bool
486*01a6c311SAlfredo Cardigliano ionic_q_has_space(struct ionic_queue *q, uint32_t want)
487*01a6c311SAlfredo Cardigliano {
488*01a6c311SAlfredo Cardigliano 	return ionic_q_space_avail(q) >= want;
489*01a6c311SAlfredo Cardigliano }
490*01a6c311SAlfredo Cardigliano 
491*01a6c311SAlfredo Cardigliano void
492*01a6c311SAlfredo Cardigliano ionic_q_service(struct ionic_queue *q, uint32_t cq_desc_index,
493*01a6c311SAlfredo Cardigliano 		uint32_t stop_index, void *service_cb_arg)
494*01a6c311SAlfredo Cardigliano {
495*01a6c311SAlfredo Cardigliano 	struct ionic_desc_info *desc_info;
496*01a6c311SAlfredo Cardigliano 	uint32_t curr_q_tail_idx;
497*01a6c311SAlfredo Cardigliano 
498*01a6c311SAlfredo Cardigliano 	do {
499*01a6c311SAlfredo Cardigliano 		desc_info = &q->info[q->tail_idx];
500*01a6c311SAlfredo Cardigliano 
501*01a6c311SAlfredo Cardigliano 		if (desc_info->cb)
502*01a6c311SAlfredo Cardigliano 			desc_info->cb(q, q->tail_idx, cq_desc_index,
503*01a6c311SAlfredo Cardigliano 				desc_info->cb_arg, service_cb_arg);
504*01a6c311SAlfredo Cardigliano 
505*01a6c311SAlfredo Cardigliano 		desc_info->cb = NULL;
506*01a6c311SAlfredo Cardigliano 		desc_info->cb_arg = NULL;
507*01a6c311SAlfredo Cardigliano 
508*01a6c311SAlfredo Cardigliano 		curr_q_tail_idx = q->tail_idx;
509*01a6c311SAlfredo Cardigliano 		q->tail_idx = (q->tail_idx + 1) & (q->num_descs - 1);
510*01a6c311SAlfredo Cardigliano 
511*01a6c311SAlfredo Cardigliano 	} while (curr_q_tail_idx != stop_index);
512*01a6c311SAlfredo Cardigliano }
513*01a6c311SAlfredo Cardigliano 
514*01a6c311SAlfredo Cardigliano static void
515*01a6c311SAlfredo Cardigliano ionic_adminq_cb(struct ionic_queue *q,
516*01a6c311SAlfredo Cardigliano 		uint32_t q_desc_index, uint32_t cq_desc_index,
517*01a6c311SAlfredo Cardigliano 		void *cb_arg, void *service_cb_arg __rte_unused)
518*01a6c311SAlfredo Cardigliano {
519*01a6c311SAlfredo Cardigliano 	struct ionic_admin_ctx *ctx = cb_arg;
520*01a6c311SAlfredo Cardigliano 	struct ionic_admin_comp *cq_desc_base = q->bound_cq->base;
521*01a6c311SAlfredo Cardigliano 	struct ionic_admin_comp *cq_desc = &cq_desc_base[cq_desc_index];
522*01a6c311SAlfredo Cardigliano 
523*01a6c311SAlfredo Cardigliano 	if (unlikely(cq_desc->comp_index != q_desc_index)) {
524*01a6c311SAlfredo Cardigliano 		IONIC_WARN_ON(cq_desc->comp_index != q_desc_index);
525*01a6c311SAlfredo Cardigliano 		return;
526*01a6c311SAlfredo Cardigliano 	}
527*01a6c311SAlfredo Cardigliano 
528*01a6c311SAlfredo Cardigliano 	memcpy(&ctx->comp, cq_desc, sizeof(*cq_desc));
529*01a6c311SAlfredo Cardigliano 
530*01a6c311SAlfredo Cardigliano 	ctx->pending_work = false; /* done */
531*01a6c311SAlfredo Cardigliano }
532*01a6c311SAlfredo Cardigliano 
533*01a6c311SAlfredo Cardigliano /** ionic_adminq_post - Post an admin command.
534*01a6c311SAlfredo Cardigliano  * @lif:		Handle to lif.
535*01a6c311SAlfredo Cardigliano  * @cmd_ctx:		Api admin command context.
536*01a6c311SAlfredo Cardigliano  *
537*01a6c311SAlfredo Cardigliano  * Post the command to an admin queue in the ethernet driver.  If this command
538*01a6c311SAlfredo Cardigliano  * succeeds, then the command has been posted, but that does not indicate a
539*01a6c311SAlfredo Cardigliano  * completion.  If this command returns success, then the completion callback
540*01a6c311SAlfredo Cardigliano  * will eventually be called.
541*01a6c311SAlfredo Cardigliano  *
542*01a6c311SAlfredo Cardigliano  * Return: zero or negative error status.
543*01a6c311SAlfredo Cardigliano  */
544*01a6c311SAlfredo Cardigliano int
545*01a6c311SAlfredo Cardigliano ionic_adminq_post(struct ionic_lif *lif, struct ionic_admin_ctx *ctx)
546*01a6c311SAlfredo Cardigliano {
547*01a6c311SAlfredo Cardigliano 	struct ionic_queue *adminq = &lif->adminqcq->q;
548*01a6c311SAlfredo Cardigliano 	struct ionic_admin_cmd *q_desc_base = adminq->base;
549*01a6c311SAlfredo Cardigliano 	struct ionic_admin_cmd *q_desc;
550*01a6c311SAlfredo Cardigliano 	int err = 0;
551*01a6c311SAlfredo Cardigliano 
552*01a6c311SAlfredo Cardigliano 	rte_spinlock_lock(&lif->adminq_lock);
553*01a6c311SAlfredo Cardigliano 
554*01a6c311SAlfredo Cardigliano 	if (!ionic_q_has_space(adminq, 1)) {
555*01a6c311SAlfredo Cardigliano 		err = -ENOSPC;
556*01a6c311SAlfredo Cardigliano 		goto err_out;
557*01a6c311SAlfredo Cardigliano 	}
558*01a6c311SAlfredo Cardigliano 
559*01a6c311SAlfredo Cardigliano 	q_desc = &q_desc_base[adminq->head_idx];
560*01a6c311SAlfredo Cardigliano 
561*01a6c311SAlfredo Cardigliano 	memcpy(q_desc, &ctx->cmd, sizeof(ctx->cmd));
562*01a6c311SAlfredo Cardigliano 
563*01a6c311SAlfredo Cardigliano 	ionic_q_post(adminq, true, ionic_adminq_cb, ctx);
564*01a6c311SAlfredo Cardigliano 
565*01a6c311SAlfredo Cardigliano err_out:
566*01a6c311SAlfredo Cardigliano 	rte_spinlock_unlock(&lif->adminq_lock);
567*01a6c311SAlfredo Cardigliano 
568*01a6c311SAlfredo Cardigliano 	return err;
569*01a6c311SAlfredo Cardigliano }
570