brintos

brintos / linux-shallow public Read only

0
0
Text · 7.9 KiB · 9d53c14 Raw
280 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Marvell Octeon EP (EndPoint) Ethernet Driver3 *4 * Copyright (C) 2020 Marvell.5 *6 */7#include <linux/types.h>8#include <linux/errno.h>9#include <linux/string.h>10#include <linux/mutex.h>11#include <linux/jiffies.h>12#include <linux/sched.h>13#include <linux/sched/signal.h>14#include <linux/io.h>15#include <linux/pci.h>16#include <linux/etherdevice.h>17 18#include "octep_ctrl_mbox.h"19#include "octep_config.h"20#include "octep_main.h"21 22/* Timeout in msecs for message response */23#define OCTEP_CTRL_MBOX_MSG_TIMEOUT_MS			10024/* Time in msecs to wait for message response */25#define OCTEP_CTRL_MBOX_MSG_WAIT_MS			1026 27/* Size of mbox info in bytes */28#define OCTEP_CTRL_MBOX_INFO_SZ				25629/* Size of mbox host to fw queue info in bytes */30#define OCTEP_CTRL_MBOX_H2FQ_INFO_SZ			1631/* Size of mbox fw to host queue info in bytes */32#define OCTEP_CTRL_MBOX_F2HQ_INFO_SZ			1633 34#define OCTEP_CTRL_MBOX_TOTAL_INFO_SZ	(OCTEP_CTRL_MBOX_INFO_SZ + \35					 OCTEP_CTRL_MBOX_H2FQ_INFO_SZ + \36					 OCTEP_CTRL_MBOX_F2HQ_INFO_SZ)37 38#define OCTEP_CTRL_MBOX_INFO_MAGIC_NUM(m)	(m)39#define OCTEP_CTRL_MBOX_INFO_BARMEM_SZ(m)	((m) + 8)40#define OCTEP_CTRL_MBOX_INFO_HOST_VERSION(m)   ((m) + 16)41#define OCTEP_CTRL_MBOX_INFO_HOST_STATUS(m)	((m) + 24)42#define OCTEP_CTRL_MBOX_INFO_FW_VERSION(m)     ((m) + 136)43#define OCTEP_CTRL_MBOX_INFO_FW_STATUS(m)	((m) + 144)44 45#define OCTEP_CTRL_MBOX_H2FQ_INFO(m)	((m) + OCTEP_CTRL_MBOX_INFO_SZ)46#define OCTEP_CTRL_MBOX_H2FQ_PROD(m)	(OCTEP_CTRL_MBOX_H2FQ_INFO(m))47#define OCTEP_CTRL_MBOX_H2FQ_CONS(m)	((OCTEP_CTRL_MBOX_H2FQ_INFO(m)) + 4)48#define OCTEP_CTRL_MBOX_H2FQ_SZ(m)	((OCTEP_CTRL_MBOX_H2FQ_INFO(m)) + 8)49 50#define OCTEP_CTRL_MBOX_F2HQ_INFO(m)	((m) + \51					 OCTEP_CTRL_MBOX_INFO_SZ + \52					 OCTEP_CTRL_MBOX_H2FQ_INFO_SZ)53#define OCTEP_CTRL_MBOX_F2HQ_PROD(m)	(OCTEP_CTRL_MBOX_F2HQ_INFO(m))54#define OCTEP_CTRL_MBOX_F2HQ_CONS(m)	((OCTEP_CTRL_MBOX_F2HQ_INFO(m)) + 4)55#define OCTEP_CTRL_MBOX_F2HQ_SZ(m)	((OCTEP_CTRL_MBOX_F2HQ_INFO(m)) + 8)56 57static const u32 mbox_hdr_sz = sizeof(union octep_ctrl_mbox_msg_hdr);58 59static u32 octep_ctrl_mbox_circq_inc(u32 index, u32 inc, u32 sz)60{61	return (index + inc) % sz;62}63 64static u32 octep_ctrl_mbox_circq_space(u32 pi, u32 ci, u32 sz)65{66	return sz - (abs(pi - ci) % sz);67}68 69static u32 octep_ctrl_mbox_circq_depth(u32 pi, u32 ci, u32 sz)70{71	return (abs(pi - ci) % sz);72}73 74int octep_ctrl_mbox_init(struct octep_ctrl_mbox *mbox)75{76	u64 magic_num, status, fw_versions;77 78	if (!mbox)79		return -EINVAL;80 81	if (!mbox->barmem) {82		pr_info("octep_ctrl_mbox : Invalid barmem %p\n", mbox->barmem);83		return -EINVAL;84	}85 86	magic_num = readq(OCTEP_CTRL_MBOX_INFO_MAGIC_NUM(mbox->barmem));87	if (magic_num != OCTEP_CTRL_MBOX_MAGIC_NUMBER) {88		pr_info("octep_ctrl_mbox : Invalid magic number %llx\n", magic_num);89		return -EINVAL;90	}91 92	status = readq(OCTEP_CTRL_MBOX_INFO_FW_STATUS(mbox->barmem));93	if (status != OCTEP_CTRL_MBOX_STATUS_READY) {94		pr_info("octep_ctrl_mbox : Firmware is not ready.\n");95		return -EINVAL;96	}97 98	fw_versions = readq(OCTEP_CTRL_MBOX_INFO_FW_VERSION(mbox->barmem));99	mbox->min_fw_version = ((fw_versions & 0xffffffff00000000ull) >> 32);100	mbox->max_fw_version = (fw_versions & 0xffffffff);101	mbox->barmem_sz = readl(OCTEP_CTRL_MBOX_INFO_BARMEM_SZ(mbox->barmem));102 103	writeq(OCTEP_CTRL_MBOX_STATUS_INIT,104	       OCTEP_CTRL_MBOX_INFO_HOST_STATUS(mbox->barmem));105 106	mutex_init(&mbox->h2fq_lock);107	mutex_init(&mbox->f2hq_lock);108 109	mbox->h2fq.sz = readl(OCTEP_CTRL_MBOX_H2FQ_SZ(mbox->barmem));110	mbox->h2fq.hw_prod = OCTEP_CTRL_MBOX_H2FQ_PROD(mbox->barmem);111	mbox->h2fq.hw_cons = OCTEP_CTRL_MBOX_H2FQ_CONS(mbox->barmem);112	mbox->h2fq.hw_q = mbox->barmem + OCTEP_CTRL_MBOX_TOTAL_INFO_SZ;113 114	mbox->f2hq.sz = readl(OCTEP_CTRL_MBOX_F2HQ_SZ(mbox->barmem));115	mbox->f2hq.hw_prod = OCTEP_CTRL_MBOX_F2HQ_PROD(mbox->barmem);116	mbox->f2hq.hw_cons = OCTEP_CTRL_MBOX_F2HQ_CONS(mbox->barmem);117	mbox->f2hq.hw_q = mbox->barmem +118			  OCTEP_CTRL_MBOX_TOTAL_INFO_SZ +119			  mbox->h2fq.sz;120 121	writeq(mbox->version, OCTEP_CTRL_MBOX_INFO_HOST_VERSION(mbox->barmem));122	/* ensure ready state is seen after everything is initialized */123	wmb();124	writeq(OCTEP_CTRL_MBOX_STATUS_READY,125	       OCTEP_CTRL_MBOX_INFO_HOST_STATUS(mbox->barmem));126 127	pr_info("Octep ctrl mbox : Init successful.\n");128 129	return 0;130}131 132static void133octep_write_mbox_data(struct octep_ctrl_mbox_q *q, u32 *pi, u32 ci, void *buf, u32 w_sz)134{135	u8 __iomem *qbuf;136	u32 cp_sz;137 138	/* Assumption: Caller has ensured enough write space */139	qbuf = (q->hw_q + *pi);140	if (*pi < ci) {141		/* copy entire w_sz */142		memcpy_toio(qbuf, buf, w_sz);143		*pi = octep_ctrl_mbox_circq_inc(*pi, w_sz, q->sz);144	} else {145		/* copy up to end of queue */146		cp_sz = min((q->sz - *pi), w_sz);147		memcpy_toio(qbuf, buf, cp_sz);148		w_sz -= cp_sz;149		*pi = octep_ctrl_mbox_circq_inc(*pi, cp_sz, q->sz);150		if (w_sz) {151			/* roll over and copy remaining w_sz */152			buf += cp_sz;153			qbuf = (q->hw_q + *pi);154			memcpy_toio(qbuf, buf, w_sz);155			*pi = octep_ctrl_mbox_circq_inc(*pi, w_sz, q->sz);156		}157	}158}159 160int octep_ctrl_mbox_send(struct octep_ctrl_mbox *mbox, struct octep_ctrl_mbox_msg *msg)161{162	struct octep_ctrl_mbox_msg_buf *sg;163	struct octep_ctrl_mbox_q *q;164	u32 pi, ci, buf_sz, w_sz;165	int s;166 167	if (!mbox || !msg)168		return -EINVAL;169 170	if (readq(OCTEP_CTRL_MBOX_INFO_FW_STATUS(mbox->barmem)) != OCTEP_CTRL_MBOX_STATUS_READY)171		return -EIO;172 173	mutex_lock(&mbox->h2fq_lock);174	q = &mbox->h2fq;175	pi = readl(q->hw_prod);176	ci = readl(q->hw_cons);177 178	if (octep_ctrl_mbox_circq_space(pi, ci, q->sz) < (msg->hdr.s.sz + mbox_hdr_sz)) {179		mutex_unlock(&mbox->h2fq_lock);180		return -EAGAIN;181	}182 183	octep_write_mbox_data(q, &pi, ci, (void *)&msg->hdr, mbox_hdr_sz);184	buf_sz = msg->hdr.s.sz;185	for (s = 0; ((s < msg->sg_num) && (buf_sz > 0)); s++) {186		sg = &msg->sg_list[s];187		w_sz = (sg->sz <= buf_sz) ? sg->sz : buf_sz;188		octep_write_mbox_data(q, &pi, ci, sg->msg, w_sz);189		buf_sz -= w_sz;190	}191	writel(pi, q->hw_prod);192	mutex_unlock(&mbox->h2fq_lock);193 194	return 0;195}196 197static void198octep_read_mbox_data(struct octep_ctrl_mbox_q *q, u32 pi, u32 *ci, void *buf, u32 r_sz)199{200	u8 __iomem *qbuf;201	u32 cp_sz;202 203	/* Assumption: Caller has ensured enough read space */204	qbuf = (q->hw_q + *ci);205	if (*ci < pi) {206		/* copy entire r_sz */207		memcpy_fromio(buf, qbuf, r_sz);208		*ci = octep_ctrl_mbox_circq_inc(*ci, r_sz, q->sz);209	} else {210		/* copy up to end of queue */211		cp_sz = min((q->sz - *ci), r_sz);212		memcpy_fromio(buf, qbuf, cp_sz);213		r_sz -= cp_sz;214		*ci = octep_ctrl_mbox_circq_inc(*ci, cp_sz, q->sz);215		if (r_sz) {216			/* roll over and copy remaining r_sz */217			buf += cp_sz;218			qbuf = (q->hw_q + *ci);219			memcpy_fromio(buf, qbuf, r_sz);220			*ci = octep_ctrl_mbox_circq_inc(*ci, r_sz, q->sz);221		}222	}223}224 225int octep_ctrl_mbox_recv(struct octep_ctrl_mbox *mbox, struct octep_ctrl_mbox_msg *msg)226{227	struct octep_ctrl_mbox_msg_buf *sg;228	u32 pi, ci, r_sz, buf_sz, q_depth;229	struct octep_ctrl_mbox_q *q;230	int s;231 232	if (readq(OCTEP_CTRL_MBOX_INFO_FW_STATUS(mbox->barmem)) != OCTEP_CTRL_MBOX_STATUS_READY)233		return -EIO;234 235	mutex_lock(&mbox->f2hq_lock);236	q = &mbox->f2hq;237	pi = readl(q->hw_prod);238	ci = readl(q->hw_cons);239 240	q_depth = octep_ctrl_mbox_circq_depth(pi, ci, q->sz);241	if (q_depth < mbox_hdr_sz) {242		mutex_unlock(&mbox->f2hq_lock);243		return -EAGAIN;244	}245 246	octep_read_mbox_data(q, pi, &ci, (void *)&msg->hdr, mbox_hdr_sz);247	buf_sz = msg->hdr.s.sz;248	for (s = 0; ((s < msg->sg_num) && (buf_sz > 0)); s++) {249		sg = &msg->sg_list[s];250		r_sz = (sg->sz <= buf_sz) ? sg->sz : buf_sz;251		octep_read_mbox_data(q, pi, &ci, sg->msg, r_sz);252		buf_sz -= r_sz;253	}254	writel(ci, q->hw_cons);255	mutex_unlock(&mbox->f2hq_lock);256 257	return 0;258}259 260int octep_ctrl_mbox_uninit(struct octep_ctrl_mbox *mbox)261{262	if (!mbox)263		return -EINVAL;264	if (!mbox->barmem)265		return -EINVAL;266 267	writeq(0, OCTEP_CTRL_MBOX_INFO_HOST_VERSION(mbox->barmem));268	writeq(OCTEP_CTRL_MBOX_STATUS_INVALID,269	       OCTEP_CTRL_MBOX_INFO_HOST_STATUS(mbox->barmem));270	/* ensure uninit state is written before uninitialization */271	wmb();272 273	mutex_destroy(&mbox->h2fq_lock);274	mutex_destroy(&mbox->f2hq_lock);275 276	pr_info("Octep ctrl mbox : Uninit successful.\n");277 278	return 0;279}280