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
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         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;
105
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;
112
113         /* ensure ready state is seen after everything is initialized */
114         wmb();
115         writeq(OCTEP_CTRL_MBOX_STATUS_READY,
116                OCTEP_CTRL_MBOX_INFO_HOST_STATUS(mbox->barmem));
117
118         pr_info("Octep ctrl mbox : Init successful.\n");
119
120         return 0;
121 }
122
123 static void
124 octep_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
151 int octep_ctrl_mbox_send(struct octep_ctrl_mbox *mbox, struct octep_ctrl_mbox_msg *msg)
152 {
153         struct octep_ctrl_mbox_msg_buf *sg;
154         struct octep_ctrl_mbox_q *q;
155         u32 pi, ci, buf_sz, w_sz;
156         int s;
157
158         if (!mbox || !msg)
159                 return -EINVAL;
160
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);
165         q = &mbox->h2fq;
166         pi = readl(q->hw_prod);
167         ci = readl(q->hw_cons);
168
169         if (octep_ctrl_mbox_circq_space(pi, ci, q->sz) < (msg->hdr.s.sz + mbox_hdr_sz)) {
170                 mutex_unlock(&mbox->h2fq_lock);
171                 return -EAGAIN;
172         }
173
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         }
182         writel(pi, q->hw_prod);
183         mutex_unlock(&mbox->h2fq_lock);
184
185         return 0;
186 }
187
188 static void
189 octep_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);
212                 }
213         }
214 }
215
216 int octep_ctrl_mbox_recv(struct octep_ctrl_mbox *mbox, struct octep_ctrl_mbox_msg *msg)
217 {
218         struct octep_ctrl_mbox_msg_buf *sg;
219         u32 pi, ci, r_sz, buf_sz, q_depth;
220         struct octep_ctrl_mbox_q *q;
221         int s;
222
223         if (readq(OCTEP_CTRL_MBOX_INFO_FW_STATUS(mbox->barmem)) != OCTEP_CTRL_MBOX_STATUS_READY)
224                 return -EIO;
225
226         mutex_lock(&mbox->f2hq_lock);
227         q = &mbox->f2hq;
228         pi = readl(q->hw_prod);
229         ci = readl(q->hw_cons);
230
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         }
236
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         }
245         writel(ci, q->hw_cons);
246         mutex_unlock(&mbox->f2hq_lock);
247
248         return 0;
249 }
250
251 int octep_ctrl_mbox_uninit(struct octep_ctrl_mbox *mbox)
252 {
253         if (!mbox)
254                 return -EINVAL;
255         if (!mbox->barmem)
256                 return -EINVAL;
257
258         writeq(OCTEP_CTRL_MBOX_STATUS_INVALID,
259                OCTEP_CTRL_MBOX_INFO_HOST_STATUS(mbox->barmem));
260         /* ensure uninit state is written before uninitialization */
261         wmb();
262
263         mutex_destroy(&mbox->h2fq_lock);
264         mutex_destroy(&mbox->f2hq_lock);
265
266         pr_info("Octep ctrl mbox : Uninit successful.\n");
267
268         return 0;
269 }