Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(C) 2023 Mucse IC Design Ltd.
3 : : */
4 : :
5 : : #include <string.h>
6 : :
7 : : #include "rnp_hw.h"
8 : : #include "rnp_mbx.h"
9 : : #include "../rnp.h"
10 : :
11 : : /****************************PF MBX OPS************************************/
12 : : static inline u16
13 : : rnp_mbx_get_req(struct rnp_hw *hw, enum RNP_MBX_ID mbx_id)
14 : : {
15 : : u32 reg = 0;
16 : :
17 [ # # ]: 0 : if (mbx_id == RNP_MBX_FW)
18 : : reg = RNP_FW2PF_SYNC;
19 : : else
20 : 0 : reg = RNP_VF2PF_SYNC(mbx_id);
21 : : mb();
22 : :
23 : 0 : return RNP_E_REG_RD(hw, reg) & RNP_MBX_SYNC_REQ_MASK;
24 : : }
25 : :
26 : : static inline u16
27 : : rnp_mbx_get_ack(struct rnp_hw *hw, enum RNP_MBX_ID mbx_id)
28 : : {
29 : : u32 reg = 0;
30 : : u32 v = 0;
31 : :
32 [ # # ]: 0 : if (mbx_id == RNP_MBX_FW)
33 : : reg = RNP_FW2PF_SYNC;
34 : : else
35 : 0 : reg = RNP_VF2PF_SYNC(mbx_id);
36 : : mb();
37 : 0 : v = RNP_E_REG_RD(hw, reg);
38 : :
39 : 0 : return (v & RNP_MBX_SYNC_ACK_MASK) >> RNP_MBX_SYNC_ACK_S;
40 : : }
41 : :
42 : : /*
43 : : * rnp_mbx_inc_pf_ack - increase ack num of mailbox sync info
44 : : * @hw pointer to the HW structure
45 : : * @sync_base: addr of sync
46 : : */
47 : : static inline void
48 : : rnp_mbx_inc_pf_req(struct rnp_hw *hw, enum RNP_MBX_ID mbx_id)
49 : : {
50 : : u32 sync_base;
51 : : u32 req;
52 : : u32 v;
53 : :
54 : 0 : if (mbx_id == RNP_MBX_FW)
55 : : sync_base = RNP_PF2FW_SYNC;
56 : : else
57 : 0 : sync_base = RNP_PF2VF_SYNC(mbx_id);
58 : 0 : v = RNP_E_REG_RD(hw, sync_base);
59 : 0 : req = (v & RNP_MBX_SYNC_REQ_MASK);
60 : 0 : req++;
61 : : /* clear sync req value */
62 : 0 : v &= ~(RNP_MBX_SYNC_REQ_MASK);
63 : 0 : v |= req;
64 : :
65 : : mb();
66 : 0 : RNP_E_REG_WR(hw, sync_base, v);
67 : : }
68 : :
69 : : /*
70 : : * rnp_mbx_inc_pf_ack - increase ack num of maixbox sync info
71 : : * @hw pointer to the HW structure
72 : : * @sync_base: addr of sync
73 : : */
74 : : static inline void
75 : : rnp_mbx_inc_pf_ack(struct rnp_hw *hw, enum RNP_MBX_ID mbx_id)
76 : : {
77 : : u32 ack;
78 : : u32 reg;
79 : : u32 v;
80 : :
81 : 0 : if (mbx_id == RNP_MBX_FW)
82 : : reg = RNP_PF2FW_SYNC;
83 : : else
84 : 0 : reg = RNP_PF2VF_SYNC(mbx_id);
85 : 0 : v = RNP_E_REG_RD(hw, reg);
86 : 0 : ack = (v & RNP_MBX_SYNC_ACK_MASK) >> RNP_MBX_SYNC_ACK_S;
87 : 0 : ack++;
88 : : /* clear old sync ack */
89 : 0 : v &= ~RNP_MBX_SYNC_ACK_MASK;
90 : 0 : v |= (ack << RNP_MBX_SYNC_ACK_S);
91 : : mb();
92 : 0 : RNP_E_REG_WR(hw, reg, v);
93 : : }
94 : :
95 : : static void
96 : : rnp_mbx_write_msg(struct rnp_hw *hw,
97 : : u32 *msg, u16 size,
98 : : enum RNP_MBX_ID mbx_id)
99 : : {
100 : : u32 msg_base;
101 : : u16 i = 0;
102 : :
103 [ # # ]: 0 : if (mbx_id == RNP_MBX_FW)
104 : : msg_base = RNP_FW2PF_MSG_DATA;
105 : : else
106 : 0 : msg_base = RNP_PF2VF_MSG_DATA(mbx_id);
107 [ # # ]: 0 : for (i = 0; i < size; i++)
108 : 0 : RNP_E_REG_WR(hw, msg_base + i * 4, msg[i]);
109 : : }
110 : :
111 : : static void
112 : 0 : rnp_mbx_read_msg(struct rnp_hw *hw,
113 : : u32 *msg, u16 size,
114 : : enum RNP_MBX_ID mbx_id)
115 : : {
116 : : u32 msg_base;
117 : : u16 i = 0;
118 : :
119 [ # # ]: 0 : if (mbx_id == RNP_MBX_FW)
120 : : msg_base = RNP_FW2PF_MSG_DATA;
121 : : else
122 : 0 : msg_base = RNP_PF2VF_MSG_DATA(mbx_id);
123 [ # # ]: 0 : for (i = 0; i < size; i++)
124 : 0 : msg[i] = RNP_E_REG_RD(hw, msg_base + 4 * i);
125 : : mb();
126 : : /* clear msg cmd */
127 : 0 : RNP_E_REG_WR(hw, msg_base, 0);
128 : 0 : }
129 : :
130 : : /*
131 : : * rnp_poll_for_msg - Wait for message notification
132 : : * @hw: pointer to the HW structure
133 : : * @mbx_id: id of mailbox to write
134 : : *
135 : : * returns SUCCESS if it successfully received a message notification
136 : : */
137 : : static int
138 : 0 : rnp_poll_for_msg(struct rnp_hw *hw, enum RNP_MBX_ID mbx_id)
139 : : {
140 : : struct rnp_mbx_info *mbx = &hw->mbx;
141 : 0 : u32 countdown = mbx->timeout;
142 : :
143 [ # # # # ]: 0 : if (!countdown || !mbx->ops->check_for_msg)
144 : 0 : goto out;
145 : :
146 [ # # ]: 0 : while (countdown && mbx->ops->check_for_msg(hw, mbx_id)) {
147 : 0 : countdown--;
148 [ # # ]: 0 : if (!countdown)
149 : : break;
150 : 0 : udelay(mbx->usec_delay);
151 : : }
152 : 0 : out:
153 [ # # ]: 0 : return countdown ? 0 : -ETIMEDOUT;
154 : : }
155 : :
156 : : /*
157 : : * rnp_poll_for_ack - Wait for message acknowledgment
158 : : * @hw: pointer to the HW structure
159 : : * @mbx_id: id of mailbox to write
160 : : *
161 : : * returns SUCCESS if it successfully received a message acknowledgment
162 : : */
163 : : static int
164 : 0 : rnp_poll_for_ack(struct rnp_hw *hw, enum RNP_MBX_ID mbx_id)
165 : : {
166 : : struct rnp_mbx_info *mbx = &hw->mbx;
167 : 0 : u32 countdown = mbx->timeout;
168 : :
169 [ # # # # ]: 0 : if (!countdown || !mbx->ops->check_for_ack)
170 : 0 : goto out;
171 : :
172 [ # # ]: 0 : while (countdown && mbx->ops->check_for_ack(hw, mbx_id)) {
173 : 0 : countdown--;
174 [ # # ]: 0 : if (!countdown)
175 : : break;
176 : 0 : udelay(mbx->usec_delay);
177 : : }
178 : :
179 : 0 : out:
180 [ # # ]: 0 : return countdown ? 0 : -ETIMEDOUT;
181 : : }
182 : :
183 : : static int
184 : : rnp_read_mbx_msg(struct rnp_hw *hw, u32 *msg, u16 size,
185 : : enum RNP_MBX_ID mbx_id)
186 : : {
187 : : struct rnp_mbx_info *mbx = &hw->mbx;
188 : : int ret = RNP_ERR_MBX;
189 : :
190 : 0 : if (size > mbx->size)
191 : : return -EINVAL;
192 [ # # ]: 0 : if (mbx->ops->read)
193 : 0 : return mbx->ops->read(hw, msg, size, mbx_id);
194 : : return ret;
195 : : }
196 : :
197 : : static int
198 : : rnp_write_mbx_msg(struct rnp_hw *hw, u32 *msg, u16 size,
199 : : enum RNP_MBX_ID mbx_id)
200 : : {
201 : : struct rnp_mbx_info *mbx = &hw->mbx;
202 : : int ret = RNP_ERR_MBX;
203 : :
204 : : /* exit if either we can't write or there isn't a defined timeout */
205 : 0 : if (size > mbx->size)
206 : : return -EINVAL;
207 [ # # ]: 0 : if (mbx->ops->write)
208 : 0 : return mbx->ops->write(hw, msg, size, mbx_id);
209 : : return ret;
210 : : }
211 : :
212 : : /*
213 : : * rnp_obtain_mbx_lock_pf - obtain mailbox lock
214 : : * @hw: pointer to the HW structure
215 : : * @ctrl_base: ctrl mbx addr
216 : : *
217 : : * return SUCCESS if we obtained the mailbox lock
218 : : */
219 : 0 : static int rnp_obtain_mbx_lock_pf(struct rnp_hw *hw, enum RNP_MBX_ID mbx_id)
220 : : {
221 : : int ret_val = -ETIMEDOUT;
222 : : u32 try_cnt = 5000; /* 500ms */
223 : : u32 ctrl_base;
224 : :
225 [ # # ]: 0 : if (mbx_id == RNP_MBX_FW)
226 : : ctrl_base = RNP_PF2FW_MBX_CTRL;
227 : : else
228 : 0 : ctrl_base = RNP_PF2VF_MBX_CTRL(mbx_id);
229 [ # # ]: 0 : while (try_cnt-- > 0) {
230 : : /* take ownership of the buffer */
231 : 0 : RNP_E_REG_WR(hw, ctrl_base, RNP_MBX_CTRL_PF_HOLD);
232 : : wmb();
233 : : /* reserve mailbox for pf used */
234 [ # # ]: 0 : if (RNP_E_REG_RD(hw, ctrl_base) & RNP_MBX_CTRL_PF_HOLD)
235 : : return 0;
236 : 0 : udelay(100);
237 : : }
238 : :
239 : 0 : RNP_PMD_LOG(WARNING, "%s: failed to get:lock",
240 : : __func__);
241 : 0 : return ret_val;
242 : : }
243 : :
244 : : static void
245 : : rnp_obtain_mbx_unlock_pf(struct rnp_hw *hw, enum RNP_MBX_ID mbx_id)
246 : : {
247 : : u32 ctrl_base;
248 : :
249 [ # # ]: 0 : if (mbx_id == RNP_MBX_FW)
250 : : ctrl_base = RNP_PF2FW_MBX_CTRL;
251 : : else
252 : 0 : ctrl_base = RNP_PF2VF_MBX_CTRL(mbx_id);
253 : 0 : RNP_E_REG_WR(hw, ctrl_base, 0);
254 : 0 : }
255 : :
256 : : static void
257 : : rnp_mbx_send_irq_pf(struct rnp_hw *hw, enum RNP_MBX_ID mbx_id)
258 : : {
259 : : u32 ctrl_base;
260 : :
261 [ # # ]: 0 : if (mbx_id == RNP_MBX_FW)
262 : : ctrl_base = RNP_PF2FW_MBX_CTRL;
263 : : else
264 : 0 : ctrl_base = RNP_PF2VF_MBX_CTRL(mbx_id);
265 : :
266 : 0 : RNP_E_REG_WR(hw, ctrl_base, RNP_MBX_CTRL_REQ);
267 : 0 : }
268 : : /*
269 : : * rnp_read_mbx_pf - Read a message from the mailbox
270 : : * @hw: pointer to the HW structure
271 : : * @msg: The message buffer
272 : : * @size: Length of buffer
273 : : * @mbx_id: id of request mbx target
274 : : *
275 : : * This function copies a message from the mailbox buffer to the caller's
276 : : * memory buffer. The presumption is that the caller knows that there was
277 : : * a message due to a VF/FW request so no polling for message is needed.
278 : : */
279 : 0 : static int rnp_read_mbx_pf(struct rnp_hw *hw, u32 *msg,
280 : : u16 size, enum RNP_MBX_ID mbx_id)
281 : : {
282 : : struct rnp_mbx_sync *sync = &hw->mbx.syncs[mbx_id];
283 : : struct rnp_mbx_info *mbx = &hw->mbx;
284 : : int ret_val = -EBUSY;
285 : :
286 [ # # ]: 0 : if (size > mbx->size) {
287 : 0 : RNP_PMD_LOG(ERR, "%s: mbx msg block size:%d should <%d",
288 : : __func__, size, mbx->size);
289 : 0 : return -EINVAL;
290 : : }
291 : 0 : memset(msg, 0, sizeof(*msg) * size);
292 : : /* lock the mailbox to prevent pf/vf race condition */
293 : 0 : ret_val = rnp_obtain_mbx_lock_pf(hw, mbx_id);
294 [ # # ]: 0 : if (ret_val)
295 : 0 : goto out_no_read;
296 : : /* copy the message from the mailbox memory buffer */
297 : 0 : rnp_mbx_read_msg(hw, msg, size, mbx_id);
298 : : /* update req. sync with fw or vf */
299 [ # # ]: 0 : sync->req = rnp_mbx_get_req(hw, mbx_id);
300 : : /* Acknowledge receipt and release mailbox, then we're done */
301 : : rnp_mbx_inc_pf_ack(hw, mbx_id);
302 : : mb();
303 : : /* free ownership of the buffer */
304 : : rnp_obtain_mbx_unlock_pf(hw, mbx_id);
305 : :
306 : : out_no_read:
307 : :
308 : : return ret_val;
309 : : }
310 : :
311 : : /*
312 : : * rnp_write_mbx_pf - Places a message in the mailbox
313 : : * @hw: pointer to the HW structure
314 : : * @msg: The message buffer
315 : : * @size: Length of buffer
316 : : * @mbx_id: id of request mbx target
317 : : *
318 : : * returns SUCCESS if it successfully copied message into the buffer
319 : : */
320 : 0 : static int rnp_write_mbx_pf(struct rnp_hw *hw, u32 *msg, u16 size,
321 : : enum RNP_MBX_ID mbx_id)
322 : : {
323 : : struct rnp_mbx_sync *sync = &hw->mbx.syncs[mbx_id];
324 : : struct rnp_mbx_info *mbx = &hw->mbx;
325 : : int ret_val = 0;
326 : :
327 [ # # ]: 0 : if (size > mbx->size) {
328 : 0 : RNP_PMD_LOG(ERR, "%s: size:%d should <%d", __func__, size,
329 : : mbx->size);
330 : 0 : return -EINVAL;
331 : : }
332 : : /* lock the mailbox to prevent pf/vf/cpu race condition */
333 : 0 : ret_val = rnp_obtain_mbx_lock_pf(hw, mbx_id);
334 [ # # ]: 0 : if (ret_val) {
335 : 0 : RNP_PMD_LOG(ERR, "%s: get mbx:%d wlock failed. "
336 : : "msg:0x%08x-0x%08x", __func__, mbx_id,
337 : : msg[0], msg[1]);
338 : 0 : goto out_no_write;
339 : : }
340 : : /* copy the caller specified message to the mailbox memory buffer */
341 : : rnp_mbx_write_msg(hw, msg, size, mbx_id);
342 : : /* flush msg and acks as we are overwriting the message buffer */
343 [ # # ]: 0 : sync->ack = rnp_mbx_get_ack(hw, mbx_id);
344 : : rnp_mbx_inc_pf_req(hw, mbx_id);
345 : 0 : udelay(300);
346 : : mb();
347 : : /* interrupt VF/FW to tell it a message has been sent and release buf */
348 : : rnp_mbx_send_irq_pf(hw, mbx_id);
349 : :
350 : : out_no_write:
351 : :
352 : : return ret_val;
353 : : }
354 : :
355 : : /*
356 : : * rnp_read_posted_mbx - Wait for message notification and receive message
357 : : * @hw: pointer to the HW structure
358 : : * @msg: The message buffer
359 : : * @size: Length of buffer
360 : : * @mbx_id: id of mailbox to write
361 : : *
362 : : * returns SUCCESS if it successfully received a message notification and
363 : : * copied it into the receive buffer.
364 : : */
365 : : static int32_t
366 : 0 : rnp_read_posted_mbx(struct rnp_hw *hw,
367 : : u32 *msg, u16 size, enum RNP_MBX_ID mbx_id)
368 : : {
369 : : int ret_val = -EINVAL;
370 : :
371 : 0 : ret_val = rnp_poll_for_msg(hw, mbx_id);
372 : : /* if ack received read message, otherwise we timed out */
373 [ # # ]: 0 : if (!ret_val)
374 [ # # ]: 0 : return rnp_read_mbx_msg(hw, msg, size, mbx_id);
375 : : return ret_val;
376 : : }
377 : :
378 : : /*
379 : : * rnp_write_posted_mbx - Write a message to the mailbox, wait for ack
380 : : * @hw: pointer to the HW structure
381 : : * @msg: The message buffer
382 : : * @size: Length of buffer
383 : : * @mbx_id: id of mailbox to write
384 : : *
385 : : * returns SUCCESS if it successfully copied message into the buffer and
386 : : * received an ack to that message within delay * timeout period
387 : : */
388 : 0 : static int rnp_write_posted_mbx(struct rnp_hw *hw,
389 : : u32 *msg, u16 size,
390 : : enum RNP_MBX_ID mbx_id)
391 : : {
392 : : int ret_val = RNP_ERR_MBX;
393 : :
394 [ # # ]: 0 : ret_val = rnp_write_mbx_msg(hw, msg, size, mbx_id);
395 [ # # ]: 0 : if (ret_val < 0)
396 : 0 : return ret_val;
397 : : /* if msg sent wait until we receive an ack */
398 : 0 : return rnp_poll_for_ack(hw, mbx_id);
399 : : }
400 : :
401 : : /*
402 : : * rnp_check_for_msg_pf - checks to see if the VF/FW has sent mail
403 : : * @hw: pointer to the HW structure
404 : : * @mbx_id: id of mailbox to write
405 : : *
406 : : * returns SUCCESS if the VF has set the Status bit or else ERR_MBX
407 : : */
408 [ # # ]: 0 : static int rnp_check_for_msg_pf(struct rnp_hw *hw, enum RNP_MBX_ID mbx_id)
409 : : {
410 : : struct rnp_mbx_sync *sync = &hw->mbx.syncs[mbx_id];
411 : : int ret_val = RNP_ERR_MBX;
412 : :
413 [ # # ]: 0 : if (rnp_mbx_get_req(hw, mbx_id) != sync->req)
414 : : ret_val = 0;
415 : :
416 : 0 : return ret_val;
417 : : }
418 : :
419 : : /*
420 : : * rnp_check_for_ack_pf - checks to see if the VF/FW has ACKed
421 : : * @hw: pointer to the HW structure
422 : : * @mbx_id: id of mailbox to write
423 : : *
424 : : * returns SUCCESS if the VF has set the Status bit or else ERR_MBX
425 : : */
426 [ # # ]: 0 : static int rnp_check_for_ack_pf(struct rnp_hw *hw, enum RNP_MBX_ID mbx_id)
427 : : {
428 : : struct rnp_mbx_sync *sync = &hw->mbx.syncs[mbx_id];
429 : : int ret_val = RNP_ERR_MBX;
430 : :
431 [ # # ]: 0 : if (rnp_mbx_get_ack(hw, mbx_id) != sync->ack)
432 : : ret_val = 0;
433 : :
434 : 0 : return ret_val;
435 : : }
436 : :
437 : : const struct rnp_mbx_ops rnp_mbx_ops_pf = {
438 : : .read = rnp_read_mbx_pf,
439 : : .write = rnp_write_mbx_pf,
440 : : .read_posted = rnp_read_posted_mbx,
441 : : .write_posted = rnp_write_posted_mbx,
442 : : .check_for_msg = rnp_check_for_msg_pf,
443 : : .check_for_ack = rnp_check_for_ack_pf,
444 : : };
445 : :
446 : : static u32 rnp_get_pfvfnum(struct rnp_hw *hw)
447 : : {
448 : : u32 val = 0;
449 : :
450 : 0 : val = RNP_C_REG_RD(hw, RNP_SRIOV_INFO);
451 : :
452 : 0 : return val >> RNP_PFVF_SHIFT;
453 : : }
454 : :
455 : 0 : static void rnp_mbx_reset(struct rnp_hw *hw)
456 : : {
457 : 0 : struct rnp_mbx_sync *sync = hw->mbx.syncs;
458 : : int idx = 0;
459 : : u32 v = 0;
460 : :
461 [ # # ]: 0 : for (idx = 0; idx < hw->mbx.en_vfs; idx++) {
462 : 0 : v = RNP_E_REG_RD(hw, RNP_VF2PF_SYNC(idx));
463 : 0 : sync[idx].ack = (v & RNP_MBX_SYNC_ACK_MASK) >> RNP_MBX_SYNC_ACK_S;
464 : 0 : sync[idx].req = v & RNP_MBX_SYNC_REQ_MASK;
465 : : /* release pf<->vf pf used buffer lock */
466 : 0 : RNP_E_REG_WR(hw, RNP_PF2VF_MBX_CTRL(idx), 0);
467 : : }
468 : : /* reset pf->fw status */
469 : 0 : v = RNP_E_REG_RD(hw, RNP_FW2PF_SYNC);
470 : 0 : sync[RNP_MBX_FW].ack = (v & RNP_MBX_SYNC_ACK_MASK) >> RNP_MBX_SYNC_ACK_S;
471 : 0 : sync[RNP_MBX_FW].req = v & RNP_MBX_SYNC_REQ_MASK;
472 : :
473 : 0 : RNP_PMD_LOG(INFO, "now fw_req %d fw_ack %d",
474 : : hw->mbx.syncs[idx].req, hw->mbx.syncs[idx].ack);
475 : : /* release pf->fw buffer lock */
476 : 0 : RNP_E_REG_WR(hw, RNP_PF2FW_MBX_CTRL, 0);
477 : : /* setup mailbox vec id */
478 : 0 : RNP_E_REG_WR(hw, RNP_FW2PF_MBOX_VEC, RNP_MISC_VEC_ID);
479 : : /* enable 0-31 vf interrupt */
480 : 0 : RNP_E_REG_WR(hw, RNP_PF2VF_INTR_MASK(0), 0);
481 : : /* enable 32-63 vf interrupt */
482 : 0 : RNP_E_REG_WR(hw, RNP_PF2VF_INTR_MASK(33), 0);
483 : : /* enable firmware interrupt */
484 : 0 : RNP_E_REG_WR(hw, RNP_FW2PF_INTR_MASK, 0);
485 : 0 : RNP_C_REG_WR(hw, RNP_SRIOV_ADDR_CTRL, RNP_SRIOV_ADDR_EN);
486 : 0 : }
487 : :
488 : 0 : int rnp_init_mbx_pf(struct rnp_hw *hw)
489 : : {
490 : 0 : struct rnp_proc_priv *proc_priv = RNP_DEV_TO_PROC_PRIV(hw->back->eth_dev);
491 : : struct rnp_mbx_info *mbx = &hw->mbx;
492 : : u32 pf_vf_num;
493 : :
494 : : pf_vf_num = rnp_get_pfvfnum(hw);
495 : 0 : mbx->usec_delay = RNP_MBX_DELAY_US;
496 : 0 : mbx->timeout = RNP_MBX_MAX_TM_SEC / mbx->usec_delay;
497 : 0 : mbx->size = RNP_MBX_MSG_BLOCK_SIZE;
498 : 0 : mbx->pf_num = (pf_vf_num & RNP_PF_BIT_MASK) ? 1 : 0;
499 : 0 : mbx->vf_num = UINT16_MAX;
500 : 0 : mbx->ops = &rnp_mbx_ops_pf;
501 : 0 : proc_priv->mbx_ops = &rnp_mbx_ops_pf;
502 : 0 : hw->pf_vf_num = pf_vf_num;
503 : 0 : mbx->is_pf = 1;
504 : 0 : rnp_mbx_reset(hw);
505 : :
506 : 0 : return 0;
507 : : }
|