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