1 // SPDX-License-Identifier: GPL-2.0
2 /* Marvell Octeon EP (EndPoint) Ethernet Driver
4 * Copyright (C) 2020 Marvell.
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>
15 #include <linux/pci.h>
16 #include <linux/etherdevice.h>
18 #include "octep_ctrl_mbox.h"
19 #include "octep_config.h"
20 #include "octep_main.h"
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
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
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)
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)
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)
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)
55 static const u32 mbox_hdr_sz = sizeof(union octep_ctrl_mbox_msg_hdr);
57 static u32 octep_ctrl_mbox_circq_inc(u32 index, u32 inc, u32 sz)
59 return (index + inc) % sz;
62 static u32 octep_ctrl_mbox_circq_space(u32 pi, u32 ci, u32 sz)
64 return sz - (abs(pi - ci) % sz);
67 static u32 octep_ctrl_mbox_circq_depth(u32 pi, u32 ci, u32 sz)
69 return (abs(pi - ci) % sz);
72 int octep_ctrl_mbox_init(struct octep_ctrl_mbox *mbox)
74 u64 magic_num, status;
80 pr_info("octep_ctrl_mbox : Invalid barmem %p\n", mbox->barmem);
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);
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");
96 mbox->barmem_sz = readl(OCTEP_CTRL_MBOX_INFO_BARMEM_SZ(mbox->barmem));
98 writeq(OCTEP_CTRL_MBOX_STATUS_INIT,
99 OCTEP_CTRL_MBOX_INFO_HOST_STATUS(mbox->barmem));
101 mutex_init(&mbox->h2fq_lock);
102 mutex_init(&mbox->f2hq_lock);
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;
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 +
116 /* ensure ready state is seen after everything is initialized */
118 writeq(OCTEP_CTRL_MBOX_STATUS_READY,
119 OCTEP_CTRL_MBOX_INFO_HOST_STATUS(mbox->barmem));
121 pr_info("Octep ctrl mbox : Init successful.\n");
127 octep_write_mbox_data(struct octep_ctrl_mbox_q *q, u32 *pi, u32 ci, void *buf, u32 w_sz)
132 /* Assumption: Caller has ensured enough write space */
133 qbuf = (q->hw_q + *pi);
135 /* copy entire w_sz */
136 memcpy_toio(qbuf, buf, w_sz);
137 *pi = octep_ctrl_mbox_circq_inc(*pi, w_sz, q->sz);
139 /* copy up to end of queue */
140 cp_sz = min((q->sz - *pi), w_sz);
141 memcpy_toio(qbuf, buf, cp_sz);
143 *pi = octep_ctrl_mbox_circq_inc(*pi, cp_sz, q->sz);
145 /* roll over and copy remaining w_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);
154 int octep_ctrl_mbox_send(struct octep_ctrl_mbox *mbox, struct octep_ctrl_mbox_msg *msg)
156 struct octep_ctrl_mbox_msg_buf *sg;
157 struct octep_ctrl_mbox_q *q;
158 u32 pi, ci, buf_sz, w_sz;
164 if (readq(OCTEP_CTRL_MBOX_INFO_FW_STATUS(mbox->barmem)) != OCTEP_CTRL_MBOX_STATUS_READY)
167 mutex_lock(&mbox->h2fq_lock);
169 pi = readl(q->hw_prod);
170 ci = readl(q->hw_cons);
172 if (octep_ctrl_mbox_circq_space(pi, ci, q->sz) < (msg->hdr.s.sz + mbox_hdr_sz)) {
173 mutex_unlock(&mbox->h2fq_lock);
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);
185 writel(pi, q->hw_prod);
186 mutex_unlock(&mbox->h2fq_lock);
192 octep_read_mbox_data(struct octep_ctrl_mbox_q *q, u32 pi, u32 *ci, void *buf, u32 r_sz)
197 /* Assumption: Caller has ensured enough read space */
198 qbuf = (q->hw_q + *ci);
200 /* copy entire r_sz */
201 memcpy_fromio(buf, qbuf, r_sz);
202 *ci = octep_ctrl_mbox_circq_inc(*ci, r_sz, q->sz);
204 /* copy up to end of queue */
205 cp_sz = min((q->sz - *ci), r_sz);
206 memcpy_fromio(buf, qbuf, cp_sz);
208 *ci = octep_ctrl_mbox_circq_inc(*ci, cp_sz, q->sz);
210 /* roll over and copy remaining r_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);
219 int octep_ctrl_mbox_recv(struct octep_ctrl_mbox *mbox, struct octep_ctrl_mbox_msg *msg)
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;
226 if (readq(OCTEP_CTRL_MBOX_INFO_FW_STATUS(mbox->barmem)) != OCTEP_CTRL_MBOX_STATUS_READY)
229 mutex_lock(&mbox->f2hq_lock);
231 pi = readl(q->hw_prod);
232 ci = readl(q->hw_cons);
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);
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);
248 writel(ci, q->hw_cons);
249 mutex_unlock(&mbox->f2hq_lock);
254 int octep_ctrl_mbox_uninit(struct octep_ctrl_mbox *mbox)
261 writeq(OCTEP_CTRL_MBOX_STATUS_INVALID,
262 OCTEP_CTRL_MBOX_INFO_HOST_STATUS(mbox->barmem));
263 /* ensure uninit state is written before uninitialization */
266 mutex_destroy(&mbox->h2fq_lock);
267 mutex_destroy(&mbox->f2hq_lock);
269 pr_info("Octep ctrl mbox : Uninit successful.\n");