Commit | Line | Data |
---|---|---|
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 | ||
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) | |
4ca2fbdd | 58 | { |
577f0d1b | 59 | return (index + inc) % sz; |
4ca2fbdd VB |
60 | } |
61 | ||
577f0d1b | 62 | static 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 | 67 | static 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 |
72 | int 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 |
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 | ||
4ca2fbdd VB |
151 | int 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 | ||
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); | |
4ca2fbdd VB |
212 | } |
213 | } | |
862cd659 VB |
214 | } |
215 | ||
216 | int 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 | ||
251 | int 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 | } |