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_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
57 static const u32 mbox_hdr_sz = sizeof(union octep_ctrl_mbox_msg_hdr);
58
octep_ctrl_mbox_circq_inc(u32 index,u32 inc,u32 sz)59 static u32 octep_ctrl_mbox_circq_inc(u32 index, u32 inc, u32 sz)
60 {
61 return (index + inc) % sz;
62 }
63
octep_ctrl_mbox_circq_space(u32 pi,u32 ci,u32 sz)64 static u32 octep_ctrl_mbox_circq_space(u32 pi, u32 ci, u32 sz)
65 {
66 return sz - (abs(pi - ci) % sz);
67 }
68
octep_ctrl_mbox_circq_depth(u32 pi,u32 ci,u32 sz)69 static u32 octep_ctrl_mbox_circq_depth(u32 pi, u32 ci, u32 sz)
70 {
71 return (abs(pi - ci) % sz);
72 }
73
octep_ctrl_mbox_init(struct octep_ctrl_mbox * mbox)74 int 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
132 static void
octep_write_mbox_data(struct octep_ctrl_mbox_q * q,u32 * pi,u32 ci,void * buf,u32 w_sz)133 octep_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
octep_ctrl_mbox_send(struct octep_ctrl_mbox * mbox,struct octep_ctrl_mbox_msg * msg)160 int 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
197 static void
octep_read_mbox_data(struct octep_ctrl_mbox_q * q,u32 pi,u32 * ci,void * buf,u32 r_sz)198 octep_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
octep_ctrl_mbox_recv(struct octep_ctrl_mbox * mbox,struct octep_ctrl_mbox_msg * msg)225 int 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
octep_ctrl_mbox_uninit(struct octep_ctrl_mbox * mbox)260 int 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