brintos

brintos / linux-shallow public Read only

0
0
Text · 24.4 KiB · 35857dc Raw
982 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.02/* Copyright (c) 2019-2020 Marvell International Ltd. All rights reserved */3 4#include <linux/bitfield.h>5#include <linux/circ_buf.h>6#include <linux/device.h>7#include <linux/firmware.h>8#include <linux/iopoll.h>9#include <linux/kernel.h>10#include <linux/module.h>11#include <linux/pci.h>12 13#include "prestera.h"14 15#define PRESTERA_MSG_MAX_SIZE 150016 17#define PRESTERA_SUPP_FW_MAJ_VER	418#define PRESTERA_SUPP_FW_MIN_VER	119 20#define PRESTERA_PREV_FW_MAJ_VER	421#define PRESTERA_PREV_FW_MIN_VER	022 23#define PRESTERA_FW_PATH_FMT	"mrvl/prestera/mvsw_prestera_fw-v%u.%u.img"24#define PRESTERA_FW_ARM64_PATH_FMT "mrvl/prestera/mvsw_prestera_fw_arm64-v%u.%u.img"25 26#define PRESTERA_FW_HDR_MAGIC		0x351D9D0627#define PRESTERA_FW_DL_TIMEOUT_MS	5000028#define PRESTERA_FW_BLK_SZ		102429 30#define PRESTERA_FW_VER_MAJ_MUL 100000031#define PRESTERA_FW_VER_MIN_MUL 100032 33#define PRESTERA_FW_VER_MAJ(v)	((v) / PRESTERA_FW_VER_MAJ_MUL)34 35#define PRESTERA_FW_VER_MIN(v) \36	(((v) - (PRESTERA_FW_VER_MAJ(v) * PRESTERA_FW_VER_MAJ_MUL)) / \37			PRESTERA_FW_VER_MIN_MUL)38 39#define PRESTERA_FW_VER_PATCH(v) \40	((v) - (PRESTERA_FW_VER_MAJ(v) * PRESTERA_FW_VER_MAJ_MUL) - \41			(PRESTERA_FW_VER_MIN(v) * PRESTERA_FW_VER_MIN_MUL))42 43enum prestera_pci_bar_t {44	PRESTERA_PCI_BAR_FW = 2,45	PRESTERA_PCI_BAR_PP = 4,46};47 48struct prestera_fw_header {49	__be32 magic_number;50	__be32 version_value;51	u8 reserved[8];52};53 54struct prestera_ldr_regs {55	u32 ldr_ready;56	u32 pad1;57 58	u32 ldr_img_size;59	u32 ldr_ctl_flags;60 61	u32 ldr_buf_offs;62	u32 ldr_buf_size;63 64	u32 ldr_buf_rd;65	u32 pad2;66	u32 ldr_buf_wr;67 68	u32 ldr_status;69};70 71#define PRESTERA_LDR_REG_OFFSET(f)	offsetof(struct prestera_ldr_regs, f)72 73#define PRESTERA_LDR_READY_MAGIC	0xf00dfeed74 75#define PRESTERA_LDR_STATUS_IMG_DL	BIT(0)76#define PRESTERA_LDR_STATUS_START_FW	BIT(1)77#define PRESTERA_LDR_STATUS_INVALID_IMG	BIT(2)78#define PRESTERA_LDR_STATUS_NOMEM	BIT(3)79 80#define PRESTERA_LDR_REG_BASE(fw)	((fw)->ldr_regs)81#define PRESTERA_LDR_REG_ADDR(fw, reg)	(PRESTERA_LDR_REG_BASE(fw) + (reg))82 83/* fw loader registers */84#define PRESTERA_LDR_READY_REG		PRESTERA_LDR_REG_OFFSET(ldr_ready)85#define PRESTERA_LDR_IMG_SIZE_REG	PRESTERA_LDR_REG_OFFSET(ldr_img_size)86#define PRESTERA_LDR_CTL_REG		PRESTERA_LDR_REG_OFFSET(ldr_ctl_flags)87#define PRESTERA_LDR_BUF_SIZE_REG	PRESTERA_LDR_REG_OFFSET(ldr_buf_size)88#define PRESTERA_LDR_BUF_OFFS_REG	PRESTERA_LDR_REG_OFFSET(ldr_buf_offs)89#define PRESTERA_LDR_BUF_RD_REG		PRESTERA_LDR_REG_OFFSET(ldr_buf_rd)90#define PRESTERA_LDR_BUF_WR_REG		PRESTERA_LDR_REG_OFFSET(ldr_buf_wr)91#define PRESTERA_LDR_STATUS_REG		PRESTERA_LDR_REG_OFFSET(ldr_status)92 93#define PRESTERA_LDR_CTL_DL_START	BIT(0)94 95#define PRESTERA_EVT_QNUM_MAX	496 97struct prestera_fw_evtq_regs {98	u32 rd_idx;99	u32 pad1;100	u32 wr_idx;101	u32 pad2;102	u32 offs;103	u32 len;104};105 106#define PRESTERA_CMD_QNUM_MAX	4107 108struct prestera_fw_cmdq_regs {109	u32 req_ctl;110	u32 req_len;111	u32 rcv_ctl;112	u32 rcv_len;113	u32 offs;114	u32 len;115};116 117struct prestera_fw_regs {118	u32 fw_ready;119	u32 cmd_offs;120	u32 cmd_len;121	u32 cmd_qnum;122	u32 evt_offs;123	u32 evt_qnum;124 125	u32 fw_status;126	u32 rx_status;127 128	struct prestera_fw_cmdq_regs cmdq_list[PRESTERA_EVT_QNUM_MAX];129	struct prestera_fw_evtq_regs evtq_list[PRESTERA_CMD_QNUM_MAX];130};131 132#define PRESTERA_FW_REG_OFFSET(f)	offsetof(struct prestera_fw_regs, f)133 134#define PRESTERA_FW_READY_MAGIC		0xcafebabe135 136/* fw registers */137#define PRESTERA_FW_READY_REG		PRESTERA_FW_REG_OFFSET(fw_ready)138 139#define PRESTERA_CMD_BUF_OFFS_REG	PRESTERA_FW_REG_OFFSET(cmd_offs)140#define PRESTERA_CMD_BUF_LEN_REG	PRESTERA_FW_REG_OFFSET(cmd_len)141#define PRESTERA_CMD_QNUM_REG		PRESTERA_FW_REG_OFFSET(cmd_qnum)142#define PRESTERA_EVT_BUF_OFFS_REG	PRESTERA_FW_REG_OFFSET(evt_offs)143#define PRESTERA_EVT_QNUM_REG		PRESTERA_FW_REG_OFFSET(evt_qnum)144 145#define PRESTERA_CMDQ_REG_OFFSET(q, f)			\146	(PRESTERA_FW_REG_OFFSET(cmdq_list) +		\147	 (q) * sizeof(struct prestera_fw_cmdq_regs) +	\148	 offsetof(struct prestera_fw_cmdq_regs, f))149 150#define PRESTERA_CMDQ_REQ_CTL_REG(q)	PRESTERA_CMDQ_REG_OFFSET(q, req_ctl)151#define PRESTERA_CMDQ_REQ_LEN_REG(q)	PRESTERA_CMDQ_REG_OFFSET(q, req_len)152#define PRESTERA_CMDQ_RCV_CTL_REG(q)	PRESTERA_CMDQ_REG_OFFSET(q, rcv_ctl)153#define PRESTERA_CMDQ_RCV_LEN_REG(q)	PRESTERA_CMDQ_REG_OFFSET(q, rcv_len)154#define PRESTERA_CMDQ_OFFS_REG(q)	PRESTERA_CMDQ_REG_OFFSET(q, offs)155#define PRESTERA_CMDQ_LEN_REG(q)	PRESTERA_CMDQ_REG_OFFSET(q, len)156 157#define PRESTERA_FW_STATUS_REG		PRESTERA_FW_REG_OFFSET(fw_status)158#define PRESTERA_RX_STATUS_REG		PRESTERA_FW_REG_OFFSET(rx_status)159 160/* PRESTERA_CMD_REQ_CTL_REG flags */161#define PRESTERA_CMD_F_REQ_SENT		BIT(0)162#define PRESTERA_CMD_F_REPL_RCVD	BIT(1)163 164/* PRESTERA_CMD_RCV_CTL_REG flags */165#define PRESTERA_CMD_F_REPL_SENT	BIT(0)166 167#define PRESTERA_FW_EVT_CTL_STATUS_MASK	GENMASK(1, 0)168 169#define PRESTERA_FW_EVT_CTL_STATUS_ON	0170#define PRESTERA_FW_EVT_CTL_STATUS_OFF	1171 172#define PRESTERA_EVTQ_REG_OFFSET(q, f)			\173	(PRESTERA_FW_REG_OFFSET(evtq_list) +		\174	 (q) * sizeof(struct prestera_fw_evtq_regs) +	\175	 offsetof(struct prestera_fw_evtq_regs, f))176 177#define PRESTERA_EVTQ_RD_IDX_REG(q)	PRESTERA_EVTQ_REG_OFFSET(q, rd_idx)178#define PRESTERA_EVTQ_WR_IDX_REG(q)	PRESTERA_EVTQ_REG_OFFSET(q, wr_idx)179#define PRESTERA_EVTQ_OFFS_REG(q)	PRESTERA_EVTQ_REG_OFFSET(q, offs)180#define PRESTERA_EVTQ_LEN_REG(q)	PRESTERA_EVTQ_REG_OFFSET(q, len)181 182#define PRESTERA_FW_REG_BASE(fw)	((fw)->dev.ctl_regs)183#define PRESTERA_FW_REG_ADDR(fw, reg)	PRESTERA_FW_REG_BASE((fw)) + (reg)184 185#define PRESTERA_FW_CMD_DEFAULT_WAIT_MS	30000186#define PRESTERA_FW_READY_WAIT_MS	20000187 188#define PRESTERA_DEV_ID_AC3X_98DX_55	0xC804189#define PRESTERA_DEV_ID_AC3X_98DX_65	0xC80C190#define PRESTERA_DEV_ID_ALDRIN2		0xCC1E191#define PRESTERA_DEV_ID_98DX7312M	0x981F192#define PRESTERA_DEV_ID_98DX3500	0x9820193#define PRESTERA_DEV_ID_98DX3501	0x9826194#define PRESTERA_DEV_ID_98DX3510	0x9821195#define PRESTERA_DEV_ID_98DX3520	0x9822196 197struct prestera_fw_evtq {198	u8 __iomem *addr;199	size_t len;200};201 202struct prestera_fw_cmdq {203	/* serialize access to dev->send_req */204	struct mutex cmd_mtx;205	u8 __iomem *addr;206	size_t len;207};208 209struct prestera_fw {210	struct prestera_fw_rev rev_supp;211	const struct firmware *bin;212	struct workqueue_struct *wq;213	struct prestera_device dev;214	struct pci_dev *pci_dev;215	u8 __iomem *ldr_regs;216	u8 __iomem *ldr_ring_buf;217	u32 ldr_buf_len;218	u32 ldr_wr_idx;219	size_t cmd_mbox_len;220	u8 __iomem *cmd_mbox;221	struct prestera_fw_cmdq cmd_queue[PRESTERA_CMD_QNUM_MAX];222	u8 cmd_qnum;223	struct prestera_fw_evtq evt_queue[PRESTERA_EVT_QNUM_MAX];224	u8 evt_qnum;225	struct work_struct evt_work;226	u8 __iomem *evt_buf;227	u8 *evt_msg;228};229 230static int prestera_fw_load(struct prestera_fw *fw);231 232static void prestera_fw_write(struct prestera_fw *fw, u32 reg, u32 val)233{234	writel(val, PRESTERA_FW_REG_ADDR(fw, reg));235}236 237static u32 prestera_fw_read(struct prestera_fw *fw, u32 reg)238{239	return readl(PRESTERA_FW_REG_ADDR(fw, reg));240}241 242static u32 prestera_fw_evtq_len(struct prestera_fw *fw, u8 qid)243{244	return fw->evt_queue[qid].len;245}246 247static u32 prestera_fw_evtq_avail(struct prestera_fw *fw, u8 qid)248{249	u32 wr_idx = prestera_fw_read(fw, PRESTERA_EVTQ_WR_IDX_REG(qid));250	u32 rd_idx = prestera_fw_read(fw, PRESTERA_EVTQ_RD_IDX_REG(qid));251 252	return CIRC_CNT(wr_idx, rd_idx, prestera_fw_evtq_len(fw, qid));253}254 255static void prestera_fw_evtq_rd_set(struct prestera_fw *fw,256				    u8 qid, u32 idx)257{258	u32 rd_idx = idx & (prestera_fw_evtq_len(fw, qid) - 1);259 260	prestera_fw_write(fw, PRESTERA_EVTQ_RD_IDX_REG(qid), rd_idx);261}262 263static u8 __iomem *prestera_fw_evtq_buf(struct prestera_fw *fw, u8 qid)264{265	return fw->evt_queue[qid].addr;266}267 268static u32 prestera_fw_evtq_read32(struct prestera_fw *fw, u8 qid)269{270	u32 rd_idx = prestera_fw_read(fw, PRESTERA_EVTQ_RD_IDX_REG(qid));271	u32 val;272 273	val = readl(prestera_fw_evtq_buf(fw, qid) + rd_idx);274	prestera_fw_evtq_rd_set(fw, qid, rd_idx + 4);275	return val;276}277 278static ssize_t prestera_fw_evtq_read_buf(struct prestera_fw *fw,279					 u8 qid, void *buf, size_t len)280{281	u32 idx = prestera_fw_read(fw, PRESTERA_EVTQ_RD_IDX_REG(qid));282	u8 __iomem *evtq_addr = prestera_fw_evtq_buf(fw, qid);283	u32 *buf32 = buf;284	int i;285 286	for (i = 0; i < len / 4; buf32++, i++) {287		*buf32 = readl_relaxed(evtq_addr + idx);288		idx = (idx + 4) & (prestera_fw_evtq_len(fw, qid) - 1);289	}290 291	prestera_fw_evtq_rd_set(fw, qid, idx);292 293	return i;294}295 296static u8 prestera_fw_evtq_pick(struct prestera_fw *fw)297{298	int qid;299 300	for (qid = 0; qid < fw->evt_qnum; qid++) {301		if (prestera_fw_evtq_avail(fw, qid) >= 4)302			return qid;303	}304 305	return PRESTERA_EVT_QNUM_MAX;306}307 308static void prestera_fw_evt_ctl_status_set(struct prestera_fw *fw, u32 val)309{310	u32 status = prestera_fw_read(fw, PRESTERA_FW_STATUS_REG);311 312	u32p_replace_bits(&status, val, PRESTERA_FW_EVT_CTL_STATUS_MASK);313 314	prestera_fw_write(fw, PRESTERA_FW_STATUS_REG, status);315}316 317static void prestera_fw_evt_work_fn(struct work_struct *work)318{319	struct prestera_fw *fw;320	void *msg;321	u8 qid;322 323	fw = container_of(work, struct prestera_fw, evt_work);324	msg = fw->evt_msg;325 326	prestera_fw_evt_ctl_status_set(fw, PRESTERA_FW_EVT_CTL_STATUS_OFF);327 328	while ((qid = prestera_fw_evtq_pick(fw)) < PRESTERA_EVT_QNUM_MAX) {329		u32 idx;330		u32 len;331 332		len = prestera_fw_evtq_read32(fw, qid);333		idx = prestera_fw_read(fw, PRESTERA_EVTQ_RD_IDX_REG(qid));334 335		WARN_ON(prestera_fw_evtq_avail(fw, qid) < len);336 337		if (WARN_ON(len > PRESTERA_MSG_MAX_SIZE)) {338			prestera_fw_evtq_rd_set(fw, qid, idx + len);339			continue;340		}341 342		prestera_fw_evtq_read_buf(fw, qid, msg, len);343 344		if (fw->dev.recv_msg)345			fw->dev.recv_msg(&fw->dev, msg, len);346	}347 348	prestera_fw_evt_ctl_status_set(fw, PRESTERA_FW_EVT_CTL_STATUS_ON);349}350 351static int prestera_fw_wait_reg32(struct prestera_fw *fw, u32 reg, u32 cmp,352				  unsigned int waitms)353{354	u8 __iomem *addr = PRESTERA_FW_REG_ADDR(fw, reg);355	u32 val;356 357	return readl_poll_timeout(addr, val, cmp == val,358				  1 * USEC_PER_MSEC, waitms * USEC_PER_MSEC);359}360 361static void prestera_fw_cmdq_lock(struct prestera_fw *fw, u8 qid)362{363	mutex_lock(&fw->cmd_queue[qid].cmd_mtx);364}365 366static void prestera_fw_cmdq_unlock(struct prestera_fw *fw, u8 qid)367{368	mutex_unlock(&fw->cmd_queue[qid].cmd_mtx);369}370 371static u32 prestera_fw_cmdq_len(struct prestera_fw *fw, u8 qid)372{373	return fw->cmd_queue[qid].len;374}375 376static u8 __iomem *prestera_fw_cmdq_buf(struct prestera_fw *fw, u8 qid)377{378	return fw->cmd_queue[qid].addr;379}380 381static int prestera_fw_cmd_send(struct prestera_fw *fw, int qid,382				void *in_msg, size_t in_size,383				void *out_msg, size_t out_size,384				unsigned int waitms)385{386	u32 ret_size;387	int err;388 389	if (!waitms)390		waitms = PRESTERA_FW_CMD_DEFAULT_WAIT_MS;391 392	if (ALIGN(in_size, 4) > prestera_fw_cmdq_len(fw, qid))393		return -EMSGSIZE;394 395	/* wait for finish previous reply from FW */396	err = prestera_fw_wait_reg32(fw, PRESTERA_CMDQ_RCV_CTL_REG(qid), 0, 30);397	if (err) {398		dev_err(fw->dev.dev, "finish reply from FW is timed out\n");399		return err;400	}401 402	prestera_fw_write(fw, PRESTERA_CMDQ_REQ_LEN_REG(qid), in_size);403 404	memcpy_toio(prestera_fw_cmdq_buf(fw, qid), in_msg, in_size);405 406	prestera_fw_write(fw, PRESTERA_CMDQ_REQ_CTL_REG(qid),407			  PRESTERA_CMD_F_REQ_SENT);408 409	/* wait for reply from FW */410	err = prestera_fw_wait_reg32(fw, PRESTERA_CMDQ_RCV_CTL_REG(qid),411				     PRESTERA_CMD_F_REPL_SENT, waitms);412	if (err) {413		dev_err(fw->dev.dev, "reply from FW is timed out\n");414		goto cmd_exit;415	}416 417	ret_size = prestera_fw_read(fw, PRESTERA_CMDQ_RCV_LEN_REG(qid));418	if (ret_size > out_size) {419		dev_err(fw->dev.dev, "ret_size (%u) > out_len(%zu)\n",420			ret_size, out_size);421		err = -EMSGSIZE;422		goto cmd_exit;423	}424 425	memcpy_fromio(out_msg,426		      prestera_fw_cmdq_buf(fw, qid) + in_size, ret_size);427 428cmd_exit:429	prestera_fw_write(fw, PRESTERA_CMDQ_REQ_CTL_REG(qid),430			  PRESTERA_CMD_F_REPL_RCVD);431	return err;432}433 434static int prestera_fw_send_req(struct prestera_device *dev, int qid,435				void *in_msg, size_t in_size, void *out_msg,436				size_t out_size, unsigned int waitms)437{438	struct prestera_fw *fw;439	ssize_t ret;440 441	fw = container_of(dev, struct prestera_fw, dev);442 443	prestera_fw_cmdq_lock(fw, qid);444	ret = prestera_fw_cmd_send(fw, qid, in_msg, in_size, out_msg, out_size,445				   waitms);446	prestera_fw_cmdq_unlock(fw, qid);447 448	return ret;449}450 451static int prestera_fw_init(struct prestera_fw *fw)452{453	u8 __iomem *base;454	int err;455	u8 qid;456 457	fw->dev.send_req = prestera_fw_send_req;458	fw->ldr_regs = fw->dev.ctl_regs;459 460	err = prestera_fw_load(fw);461	if (err)462		return err;463 464	err = prestera_fw_wait_reg32(fw, PRESTERA_FW_READY_REG,465				     PRESTERA_FW_READY_MAGIC,466				     PRESTERA_FW_READY_WAIT_MS);467	if (err) {468		dev_err(fw->dev.dev, "FW failed to start\n");469		return err;470	}471 472	base = fw->dev.ctl_regs;473 474	fw->cmd_mbox = base + prestera_fw_read(fw, PRESTERA_CMD_BUF_OFFS_REG);475	fw->cmd_mbox_len = prestera_fw_read(fw, PRESTERA_CMD_BUF_LEN_REG);476	fw->cmd_qnum = prestera_fw_read(fw, PRESTERA_CMD_QNUM_REG);477 478	for (qid = 0; qid < fw->cmd_qnum; qid++) {479		u32 offs = prestera_fw_read(fw, PRESTERA_CMDQ_OFFS_REG(qid));480		struct prestera_fw_cmdq *cmdq = &fw->cmd_queue[qid];481 482		cmdq->len = prestera_fw_read(fw, PRESTERA_CMDQ_LEN_REG(qid));483		cmdq->addr = fw->cmd_mbox + offs;484		mutex_init(&cmdq->cmd_mtx);485	}486 487	fw->evt_buf = base + prestera_fw_read(fw, PRESTERA_EVT_BUF_OFFS_REG);488	fw->evt_qnum = prestera_fw_read(fw, PRESTERA_EVT_QNUM_REG);489	fw->evt_msg = kmalloc(PRESTERA_MSG_MAX_SIZE, GFP_KERNEL);490	if (!fw->evt_msg)491		return -ENOMEM;492 493	for (qid = 0; qid < fw->evt_qnum; qid++) {494		u32 offs = prestera_fw_read(fw, PRESTERA_EVTQ_OFFS_REG(qid));495		struct prestera_fw_evtq *evtq = &fw->evt_queue[qid];496 497		evtq->len = prestera_fw_read(fw, PRESTERA_EVTQ_LEN_REG(qid));498		evtq->addr = fw->evt_buf + offs;499	}500 501	return 0;502}503 504static void prestera_fw_uninit(struct prestera_fw *fw)505{506	kfree(fw->evt_msg);507}508 509static irqreturn_t prestera_pci_irq_handler(int irq, void *dev_id)510{511	struct prestera_fw *fw = dev_id;512 513	if (prestera_fw_read(fw, PRESTERA_RX_STATUS_REG)) {514		prestera_fw_write(fw, PRESTERA_RX_STATUS_REG, 0);515 516		if (fw->dev.recv_pkt)517			fw->dev.recv_pkt(&fw->dev);518	}519 520	queue_work(fw->wq, &fw->evt_work);521 522	return IRQ_HANDLED;523}524 525static void prestera_ldr_write(struct prestera_fw *fw, u32 reg, u32 val)526{527	writel(val, PRESTERA_LDR_REG_ADDR(fw, reg));528}529 530static u32 prestera_ldr_read(struct prestera_fw *fw, u32 reg)531{532	return readl(PRESTERA_LDR_REG_ADDR(fw, reg));533}534 535static int prestera_ldr_wait_reg32(struct prestera_fw *fw,536				   u32 reg, u32 cmp, unsigned int waitms)537{538	u8 __iomem *addr = PRESTERA_LDR_REG_ADDR(fw, reg);539	u32 val;540 541	return readl_poll_timeout(addr, val, cmp == val,542				  10 * USEC_PER_MSEC, waitms * USEC_PER_MSEC);543}544 545static u32 prestera_ldr_wait_buf(struct prestera_fw *fw, size_t len)546{547	u8 __iomem *addr = PRESTERA_LDR_REG_ADDR(fw, PRESTERA_LDR_BUF_RD_REG);548	u32 buf_len = fw->ldr_buf_len;549	u32 wr_idx = fw->ldr_wr_idx;550	u32 rd_idx;551 552	return readl_poll_timeout(addr, rd_idx,553				 CIRC_SPACE(wr_idx, rd_idx, buf_len) >= len,554				 1 * USEC_PER_MSEC, 100 * USEC_PER_MSEC);555}556 557static int prestera_ldr_wait_dl_finish(struct prestera_fw *fw)558{559	u8 __iomem *addr = PRESTERA_LDR_REG_ADDR(fw, PRESTERA_LDR_STATUS_REG);560	unsigned long mask = ~(PRESTERA_LDR_STATUS_IMG_DL);561	u32 val;562	int err;563 564	err = readl_poll_timeout(addr, val, val & mask, 10 * USEC_PER_MSEC,565				 PRESTERA_FW_DL_TIMEOUT_MS * USEC_PER_MSEC);566	if (err) {567		dev_err(fw->dev.dev, "Timeout to load FW img [state=%d]",568			prestera_ldr_read(fw, PRESTERA_LDR_STATUS_REG));569		return err;570	}571 572	return 0;573}574 575static void prestera_ldr_wr_idx_move(struct prestera_fw *fw, unsigned int n)576{577	fw->ldr_wr_idx = (fw->ldr_wr_idx + (n)) & (fw->ldr_buf_len - 1);578}579 580static void prestera_ldr_wr_idx_commit(struct prestera_fw *fw)581{582	prestera_ldr_write(fw, PRESTERA_LDR_BUF_WR_REG, fw->ldr_wr_idx);583}584 585static u8 __iomem *prestera_ldr_wr_ptr(struct prestera_fw *fw)586{587	return fw->ldr_ring_buf + fw->ldr_wr_idx;588}589 590static int prestera_ldr_send(struct prestera_fw *fw, const u8 *buf, size_t len)591{592	int err;593	int i;594 595	err = prestera_ldr_wait_buf(fw, len);596	if (err) {597		dev_err(fw->dev.dev, "failed wait for sending firmware\n");598		return err;599	}600 601	for (i = 0; i < len; i += 4) {602		writel_relaxed(*(u32 *)(buf + i), prestera_ldr_wr_ptr(fw));603		prestera_ldr_wr_idx_move(fw, 4);604	}605 606	prestera_ldr_wr_idx_commit(fw);607	return 0;608}609 610static int prestera_ldr_fw_send(struct prestera_fw *fw,611				const char *img, u32 fw_size)612{613	u32 status;614	u32 pos;615	int err;616 617	err = prestera_ldr_wait_reg32(fw, PRESTERA_LDR_STATUS_REG,618				      PRESTERA_LDR_STATUS_IMG_DL,619				      5 * MSEC_PER_SEC);620	if (err) {621		dev_err(fw->dev.dev, "Loader is not ready to load image\n");622		return err;623	}624 625	for (pos = 0; pos < fw_size; pos += PRESTERA_FW_BLK_SZ) {626		if (pos + PRESTERA_FW_BLK_SZ > fw_size)627			break;628 629		err = prestera_ldr_send(fw, img + pos, PRESTERA_FW_BLK_SZ);630		if (err)631			return err;632	}633 634	if (pos < fw_size) {635		err = prestera_ldr_send(fw, img + pos, fw_size - pos);636		if (err)637			return err;638	}639 640	err = prestera_ldr_wait_dl_finish(fw);641	if (err)642		return err;643 644	status = prestera_ldr_read(fw, PRESTERA_LDR_STATUS_REG);645 646	switch (status) {647	case PRESTERA_LDR_STATUS_INVALID_IMG:648		dev_err(fw->dev.dev, "FW img has bad CRC\n");649		return -EINVAL;650	case PRESTERA_LDR_STATUS_NOMEM:651		dev_err(fw->dev.dev, "Loader has no enough mem\n");652		return -ENOMEM;653	}654 655	return 0;656}657 658static void prestera_fw_rev_parse(const struct prestera_fw_header *hdr,659				  struct prestera_fw_rev *rev)660{661	u32 version = be32_to_cpu(hdr->version_value);662 663	rev->maj = PRESTERA_FW_VER_MAJ(version);664	rev->min = PRESTERA_FW_VER_MIN(version);665	rev->sub = PRESTERA_FW_VER_PATCH(version);666}667 668static int prestera_fw_rev_check(struct prestera_fw *fw)669{670	struct prestera_fw_rev *rev = &fw->dev.fw_rev;671 672	if (rev->maj == fw->rev_supp.maj && rev->min >= fw->rev_supp.min)673		return 0;674 675	dev_err(fw->dev.dev, "Driver supports FW version only '%u.%u.x'",676		fw->rev_supp.maj, fw->rev_supp.min);677 678	return -EINVAL;679}680 681static int prestera_fw_hdr_parse(struct prestera_fw *fw)682{683	struct prestera_fw_rev *rev = &fw->dev.fw_rev;684	struct prestera_fw_header *hdr;685	u32 magic;686 687	hdr = (struct prestera_fw_header *)fw->bin->data;688 689	magic = be32_to_cpu(hdr->magic_number);690	if (magic != PRESTERA_FW_HDR_MAGIC) {691		dev_err(fw->dev.dev, "FW img hdr magic is invalid");692		return -EINVAL;693	}694 695	prestera_fw_rev_parse(hdr, rev);696 697	dev_info(fw->dev.dev, "FW version '%u.%u.%u'\n",698		 rev->maj, rev->min, rev->sub);699 700	return prestera_fw_rev_check(fw);701}702 703static const char *prestera_fw_path_fmt_get(struct prestera_fw *fw)704{705	switch (fw->pci_dev->device) {706	case PRESTERA_DEV_ID_98DX3500:707	case PRESTERA_DEV_ID_98DX3501:708	case PRESTERA_DEV_ID_98DX3510:709	case PRESTERA_DEV_ID_98DX3520:710		return PRESTERA_FW_ARM64_PATH_FMT;711 712	default:713		return PRESTERA_FW_PATH_FMT;714	}715}716 717static int prestera_fw_get(struct prestera_fw *fw)718{719	int ver_maj = PRESTERA_SUPP_FW_MAJ_VER;720	int ver_min = PRESTERA_SUPP_FW_MIN_VER;721	char fw_path[128];722	int err;723 724pick_fw_ver:725	snprintf(fw_path, sizeof(fw_path), prestera_fw_path_fmt_get(fw),726		 ver_maj, ver_min);727 728	err = request_firmware_direct(&fw->bin, fw_path, fw->dev.dev);729	if (err) {730		if (ver_maj != PRESTERA_PREV_FW_MAJ_VER ||731		    ver_min != PRESTERA_PREV_FW_MIN_VER) {732			ver_maj = PRESTERA_PREV_FW_MAJ_VER;733			ver_min = PRESTERA_PREV_FW_MIN_VER;734 735			dev_warn(fw->dev.dev,736				 "missing latest %s firmware, fall-back to previous %u.%u version\n",737				 fw_path, ver_maj, ver_min);738 739			goto pick_fw_ver;740		} else {741			dev_err(fw->dev.dev, "failed to request previous firmware: %s\n",742				fw_path);743			return err;744		}745	}746 747	dev_info(fw->dev.dev, "Loading %s ...", fw_path);748 749	fw->rev_supp.maj = ver_maj;750	fw->rev_supp.min = ver_min;751	fw->rev_supp.sub = 0;752 753	return 0;754}755 756static void prestera_fw_put(struct prestera_fw *fw)757{758	release_firmware(fw->bin);759}760 761static int prestera_fw_load(struct prestera_fw *fw)762{763	size_t hlen = sizeof(struct prestera_fw_header);764	int err;765 766	err = prestera_ldr_wait_reg32(fw, PRESTERA_LDR_READY_REG,767				      PRESTERA_LDR_READY_MAGIC,768				      5 * MSEC_PER_SEC);769	if (err) {770		dev_err(fw->dev.dev, "waiting for FW loader is timed out");771		return err;772	}773 774	fw->ldr_ring_buf = fw->ldr_regs +775		prestera_ldr_read(fw, PRESTERA_LDR_BUF_OFFS_REG);776 777	fw->ldr_buf_len =778		prestera_ldr_read(fw, PRESTERA_LDR_BUF_SIZE_REG);779 780	fw->ldr_wr_idx = 0;781 782	err = prestera_fw_get(fw);783	if (err)784		return err;785 786	err = prestera_fw_hdr_parse(fw);787	if (err) {788		dev_err(fw->dev.dev, "FW image header is invalid\n");789		goto out_release;790	}791 792	prestera_ldr_write(fw, PRESTERA_LDR_IMG_SIZE_REG, fw->bin->size - hlen);793	prestera_ldr_write(fw, PRESTERA_LDR_CTL_REG, PRESTERA_LDR_CTL_DL_START);794 795	err = prestera_ldr_fw_send(fw, fw->bin->data + hlen,796				   fw->bin->size - hlen);797 798out_release:799	prestera_fw_put(fw);800	return err;801}802 803static bool prestera_pci_pp_use_bar2(struct pci_dev *pdev)804{805	switch (pdev->device) {806	case PRESTERA_DEV_ID_98DX7312M:807	case PRESTERA_DEV_ID_98DX3500:808	case PRESTERA_DEV_ID_98DX3501:809	case PRESTERA_DEV_ID_98DX3510:810	case PRESTERA_DEV_ID_98DX3520:811		return true;812 813	default:814		return false;815	}816}817 818static u32 prestera_pci_pp_bar2_offs(struct pci_dev *pdev)819{820	if (pci_resource_len(pdev, 2) == 0x1000000)821		return 0x0;822	else823		return (pci_resource_len(pdev, 2) / 2);824}825 826static u32 prestera_pci_fw_bar2_offs(struct pci_dev *pdev)827{828	if (pci_resource_len(pdev, 2) == 0x1000000)829		return 0x400000;830	else831		return 0x0;832}833 834static int prestera_pci_probe(struct pci_dev *pdev,835			      const struct pci_device_id *id)836{837	const char *driver_name = dev_driver_string(&pdev->dev);838	u8 __iomem *mem_addr, *pp_addr = NULL;839	struct prestera_fw *fw;840	int err;841 842	err = pcim_enable_device(pdev);843	if (err) {844		dev_err(&pdev->dev, "pci_enable_device failed\n");845		goto err_pci_enable_device;846	}847 848	err = pci_request_regions(pdev, driver_name);849	if (err) {850		dev_err(&pdev->dev, "pci_request_regions failed\n");851		goto err_pci_request_regions;852	}853 854	err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(30));855	if (err) {856		dev_err(&pdev->dev, "fail to set DMA mask\n");857		goto err_dma_mask;858	}859 860	mem_addr = pcim_iomap(pdev, 2, 0);861	if (!mem_addr) {862		dev_err(&pdev->dev, "pci mem ioremap failed\n");863		err = -EIO;864		goto err_mem_ioremap;865	}866 867	/* AC5X devices use second half of BAR2 */868	if (prestera_pci_pp_use_bar2(pdev)) {869		pp_addr = mem_addr + prestera_pci_pp_bar2_offs(pdev);870		mem_addr = mem_addr + prestera_pci_fw_bar2_offs(pdev);871	} else {872		pp_addr = pcim_iomap(pdev, 4, 0);873		if (!pp_addr) {874			dev_err(&pdev->dev, "pp regs ioremap failed\n");875			err = -EIO;876			goto err_pp_ioremap;877		}878	}879 880	pci_set_master(pdev);881 882	fw = devm_kzalloc(&pdev->dev, sizeof(*fw), GFP_KERNEL);883	if (!fw) {884		err = -ENOMEM;885		goto err_pci_dev_alloc;886	}887 888	fw->pci_dev = pdev;889	fw->dev.ctl_regs = mem_addr;890	fw->dev.pp_regs = pp_addr;891	fw->dev.dev = &pdev->dev;892 893	pci_set_drvdata(pdev, fw);894 895	err = prestera_fw_init(fw);896	if (err)897		goto err_prestera_fw_init;898 899	dev_info(fw->dev.dev, "Prestera FW is ready\n");900 901	fw->wq = alloc_workqueue("prestera_fw_wq", WQ_HIGHPRI, 1);902	if (!fw->wq) {903		err = -ENOMEM;904		goto err_wq_alloc;905	}906 907	INIT_WORK(&fw->evt_work, prestera_fw_evt_work_fn);908 909	err = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI);910	if (err < 0) {911		dev_err(&pdev->dev, "MSI IRQ init failed\n");912		goto err_irq_alloc;913	}914 915	err = request_irq(pci_irq_vector(pdev, 0), prestera_pci_irq_handler,916			  0, driver_name, fw);917	if (err) {918		dev_err(&pdev->dev, "fail to request IRQ\n");919		goto err_request_irq;920	}921 922	err = prestera_device_register(&fw->dev);923	if (err)924		goto err_prestera_dev_register;925 926	return 0;927 928err_prestera_dev_register:929	free_irq(pci_irq_vector(pdev, 0), fw);930err_request_irq:931	pci_free_irq_vectors(pdev);932err_irq_alloc:933	destroy_workqueue(fw->wq);934err_wq_alloc:935	prestera_fw_uninit(fw);936err_prestera_fw_init:937err_pci_dev_alloc:938err_pp_ioremap:939err_mem_ioremap:940err_dma_mask:941	pci_release_regions(pdev);942err_pci_request_regions:943err_pci_enable_device:944	return err;945}946 947static void prestera_pci_remove(struct pci_dev *pdev)948{949	struct prestera_fw *fw = pci_get_drvdata(pdev);950 951	prestera_device_unregister(&fw->dev);952	free_irq(pci_irq_vector(pdev, 0), fw);953	pci_free_irq_vectors(pdev);954	destroy_workqueue(fw->wq);955	prestera_fw_uninit(fw);956	pci_release_regions(pdev);957}958 959static const struct pci_device_id prestera_pci_devices[] = {960	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, PRESTERA_DEV_ID_AC3X_98DX_55) },961	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, PRESTERA_DEV_ID_AC3X_98DX_65) },962	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, PRESTERA_DEV_ID_ALDRIN2) },963	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, PRESTERA_DEV_ID_98DX7312M) },964	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, PRESTERA_DEV_ID_98DX3500) },965	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, PRESTERA_DEV_ID_98DX3501) },966	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, PRESTERA_DEV_ID_98DX3510) },967	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, PRESTERA_DEV_ID_98DX3520) },968	{ }969};970MODULE_DEVICE_TABLE(pci, prestera_pci_devices);971 972static struct pci_driver prestera_pci_driver = {973	.name     = "Prestera DX",974	.id_table = prestera_pci_devices,975	.probe    = prestera_pci_probe,976	.remove   = prestera_pci_remove,977};978module_pci_driver(prestera_pci_driver);979 980MODULE_LICENSE("Dual BSD/GPL");981MODULE_DESCRIPTION("Marvell Prestera switch PCI interface");982