Merge branch 'drm-next' of git://anongit.freedesktop.org/drm/drm into msm-next-lumag...
[linux-block.git] / drivers / net / ethernet / marvell / octeon_ep / octep_ctrl_mbox.c
CommitLineData
862cd659
VB
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
577f0d1b
VB
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
55static const u32 mbox_hdr_sz = sizeof(union octep_ctrl_mbox_msg_hdr);
56
57static u32 octep_ctrl_mbox_circq_inc(u32 index, u32 inc, u32 sz)
4ca2fbdd 58{
577f0d1b 59 return (index + inc) % sz;
4ca2fbdd
VB
60}
61
577f0d1b 62static u32 octep_ctrl_mbox_circq_space(u32 pi, u32 ci, u32 sz)
4ca2fbdd 63{
577f0d1b 64 return sz - (abs(pi - ci) % sz);
4ca2fbdd
VB
65}
66
577f0d1b 67static u32 octep_ctrl_mbox_circq_depth(u32 pi, u32 ci, u32 sz)
4ca2fbdd 68{
577f0d1b 69 return (abs(pi - ci) % sz);
4ca2fbdd
VB
70}
71
862cd659
VB
72int octep_ctrl_mbox_init(struct octep_ctrl_mbox *mbox)
73{
31248b5a 74 u64 magic_num, status;
4ca2fbdd
VB
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
577f0d1b 84 magic_num = readq(OCTEP_CTRL_MBOX_INFO_MAGIC_NUM(mbox->barmem));
4ca2fbdd
VB
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
577f0d1b 90 status = readq(OCTEP_CTRL_MBOX_INFO_FW_STATUS(mbox->barmem));
4ca2fbdd
VB
91 if (status != OCTEP_CTRL_MBOX_STATUS_READY) {
92 pr_info("octep_ctrl_mbox : Firmware is not ready.\n");
93 return -EINVAL;
94 }
95
577f0d1b 96 mbox->barmem_sz = readl(OCTEP_CTRL_MBOX_INFO_BARMEM_SZ(mbox->barmem));
4ca2fbdd 97
577f0d1b
VB
98 writeq(OCTEP_CTRL_MBOX_STATUS_INIT,
99 OCTEP_CTRL_MBOX_INFO_HOST_STATUS(mbox->barmem));
4ca2fbdd 100
577f0d1b
VB
101 mbox->h2fq.sz = readl(OCTEP_CTRL_MBOX_H2FQ_SZ(mbox->barmem));
102 mbox->h2fq.hw_prod = OCTEP_CTRL_MBOX_H2FQ_PROD(mbox->barmem);
103 mbox->h2fq.hw_cons = OCTEP_CTRL_MBOX_H2FQ_CONS(mbox->barmem);
104 mbox->h2fq.hw_q = mbox->barmem + OCTEP_CTRL_MBOX_TOTAL_INFO_SZ;
4ca2fbdd 105
577f0d1b
VB
106 mbox->f2hq.sz = readl(OCTEP_CTRL_MBOX_F2HQ_SZ(mbox->barmem));
107 mbox->f2hq.hw_prod = OCTEP_CTRL_MBOX_F2HQ_PROD(mbox->barmem);
108 mbox->f2hq.hw_cons = OCTEP_CTRL_MBOX_F2HQ_CONS(mbox->barmem);
109 mbox->f2hq.hw_q = mbox->barmem +
110 OCTEP_CTRL_MBOX_TOTAL_INFO_SZ +
111 mbox->h2fq.sz;
4ca2fbdd
VB
112
113 /* ensure ready state is seen after everything is initialized */
114 wmb();
577f0d1b
VB
115 writeq(OCTEP_CTRL_MBOX_STATUS_READY,
116 OCTEP_CTRL_MBOX_INFO_HOST_STATUS(mbox->barmem));
4ca2fbdd
VB
117
118 pr_info("Octep ctrl mbox : Init successful.\n");
119
120 return 0;
121}
122
577f0d1b
VB
123static void
124octep_write_mbox_data(struct octep_ctrl_mbox_q *q, u32 *pi, u32 ci, void *buf, u32 w_sz)
125{
126 u8 __iomem *qbuf;
127 u32 cp_sz;
128
129 /* Assumption: Caller has ensured enough write space */
130 qbuf = (q->hw_q + *pi);
131 if (*pi < ci) {
132 /* copy entire w_sz */
133 memcpy_toio(qbuf, buf, w_sz);
134 *pi = octep_ctrl_mbox_circq_inc(*pi, w_sz, q->sz);
135 } else {
136 /* copy up to end of queue */
137 cp_sz = min((q->sz - *pi), w_sz);
138 memcpy_toio(qbuf, buf, cp_sz);
139 w_sz -= cp_sz;
140 *pi = octep_ctrl_mbox_circq_inc(*pi, cp_sz, q->sz);
141 if (w_sz) {
142 /* roll over and copy remaining w_sz */
143 buf += cp_sz;
144 qbuf = (q->hw_q + *pi);
145 memcpy_toio(qbuf, buf, w_sz);
146 *pi = octep_ctrl_mbox_circq_inc(*pi, w_sz, q->sz);
147 }
148 }
149}
150
4ca2fbdd
VB
151int octep_ctrl_mbox_send(struct octep_ctrl_mbox *mbox, struct octep_ctrl_mbox_msg *msg)
152{
577f0d1b 153 struct octep_ctrl_mbox_msg_buf *sg;
4ca2fbdd 154 struct octep_ctrl_mbox_q *q;
577f0d1b
VB
155 u32 pi, ci, buf_sz, w_sz;
156 int s;
4ca2fbdd
VB
157
158 if (!mbox || !msg)
159 return -EINVAL;
160
577f0d1b
VB
161 if (readq(OCTEP_CTRL_MBOX_INFO_FW_STATUS(mbox->barmem)) != OCTEP_CTRL_MBOX_STATUS_READY)
162 return -EIO;
163
164 mutex_lock(&mbox->h2fq_lock);
4ca2fbdd
VB
165 q = &mbox->h2fq;
166 pi = readl(q->hw_prod);
167 ci = readl(q->hw_cons);
168
577f0d1b 169 if (octep_ctrl_mbox_circq_space(pi, ci, q->sz) < (msg->hdr.s.sz + mbox_hdr_sz)) {
765f3604 170 mutex_unlock(&mbox->h2fq_lock);
577f0d1b
VB
171 return -EAGAIN;
172 }
4ca2fbdd 173
577f0d1b
VB
174 octep_write_mbox_data(q, &pi, ci, (void *)&msg->hdr, mbox_hdr_sz);
175 buf_sz = msg->hdr.s.sz;
176 for (s = 0; ((s < msg->sg_num) && (buf_sz > 0)); s++) {
177 sg = &msg->sg_list[s];
178 w_sz = (sg->sz <= buf_sz) ? sg->sz : buf_sz;
179 octep_write_mbox_data(q, &pi, ci, sg->msg, w_sz);
180 buf_sz -= w_sz;
181 }
4ca2fbdd
VB
182 writel(pi, q->hw_prod);
183 mutex_unlock(&mbox->h2fq_lock);
184
577f0d1b
VB
185 return 0;
186}
187
188static void
189octep_read_mbox_data(struct octep_ctrl_mbox_q *q, u32 pi, u32 *ci, void *buf, u32 r_sz)
190{
191 u8 __iomem *qbuf;
192 u32 cp_sz;
193
194 /* Assumption: Caller has ensured enough read space */
195 qbuf = (q->hw_q + *ci);
196 if (*ci < pi) {
197 /* copy entire r_sz */
198 memcpy_fromio(buf, qbuf, r_sz);
199 *ci = octep_ctrl_mbox_circq_inc(*ci, r_sz, q->sz);
200 } else {
201 /* copy up to end of queue */
202 cp_sz = min((q->sz - *ci), r_sz);
203 memcpy_fromio(buf, qbuf, cp_sz);
204 r_sz -= cp_sz;
205 *ci = octep_ctrl_mbox_circq_inc(*ci, cp_sz, q->sz);
206 if (r_sz) {
207 /* roll over and copy remaining r_sz */
208 buf += cp_sz;
209 qbuf = (q->hw_q + *ci);
210 memcpy_fromio(buf, qbuf, r_sz);
211 *ci = octep_ctrl_mbox_circq_inc(*ci, r_sz, q->sz);
4ca2fbdd
VB
212 }
213 }
862cd659
VB
214}
215
216int octep_ctrl_mbox_recv(struct octep_ctrl_mbox *mbox, struct octep_ctrl_mbox_msg *msg)
217{
577f0d1b
VB
218 struct octep_ctrl_mbox_msg_buf *sg;
219 u32 pi, ci, r_sz, buf_sz, q_depth;
4ca2fbdd 220 struct octep_ctrl_mbox_q *q;
577f0d1b 221 int s;
4ca2fbdd 222
577f0d1b
VB
223 if (readq(OCTEP_CTRL_MBOX_INFO_FW_STATUS(mbox->barmem)) != OCTEP_CTRL_MBOX_STATUS_READY)
224 return -EIO;
4ca2fbdd 225
577f0d1b 226 mutex_lock(&mbox->f2hq_lock);
4ca2fbdd
VB
227 q = &mbox->f2hq;
228 pi = readl(q->hw_prod);
229 ci = readl(q->hw_cons);
4ca2fbdd 230
577f0d1b
VB
231 q_depth = octep_ctrl_mbox_circq_depth(pi, ci, q->sz);
232 if (q_depth < mbox_hdr_sz) {
233 mutex_unlock(&mbox->f2hq_lock);
234 return -EAGAIN;
235 }
4ca2fbdd 236
577f0d1b
VB
237 octep_read_mbox_data(q, pi, &ci, (void *)&msg->hdr, mbox_hdr_sz);
238 buf_sz = msg->hdr.s.sz;
239 for (s = 0; ((s < msg->sg_num) && (buf_sz > 0)); s++) {
240 sg = &msg->sg_list[s];
241 r_sz = (sg->sz <= buf_sz) ? sg->sz : buf_sz;
242 octep_read_mbox_data(q, pi, &ci, sg->msg, r_sz);
243 buf_sz -= r_sz;
244 }
4ca2fbdd 245 writel(ci, q->hw_cons);
4ca2fbdd
VB
246 mutex_unlock(&mbox->f2hq_lock);
247
4ca2fbdd 248 return 0;
862cd659
VB
249}
250
251int octep_ctrl_mbox_uninit(struct octep_ctrl_mbox *mbox)
252{
4ca2fbdd
VB
253 if (!mbox)
254 return -EINVAL;
577f0d1b
VB
255 if (!mbox->barmem)
256 return -EINVAL;
4ca2fbdd 257
577f0d1b
VB
258 writeq(OCTEP_CTRL_MBOX_STATUS_INVALID,
259 OCTEP_CTRL_MBOX_INFO_HOST_STATUS(mbox->barmem));
4ca2fbdd
VB
260 /* ensure uninit state is written before uninitialization */
261 wmb();
262
263 mutex_destroy(&mbox->h2fq_lock);
264 mutex_destroy(&mbox->f2hq_lock);
265
4ca2fbdd
VB
266 pr_info("Octep ctrl mbox : Uninit successful.\n");
267
268 return 0;
862cd659 269}