1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Copyright(c) 1999 - 2018 Intel Corporation. */ |
3 | |
4 | #include "mbx.h" |
5 | #include "ixgbevf.h" |
6 | |
7 | /** |
8 | * ixgbevf_poll_for_msg - Wait for message notification |
9 | * @hw: pointer to the HW structure |
10 | * |
11 | * returns 0 if it successfully received a message notification |
12 | **/ |
13 | static s32 ixgbevf_poll_for_msg(struct ixgbe_hw *hw) |
14 | { |
15 | struct ixgbe_mbx_info *mbx = &hw->mbx; |
16 | int countdown = mbx->timeout; |
17 | |
18 | if (!countdown || !mbx->ops.check_for_msg) |
19 | return IXGBE_ERR_CONFIG; |
20 | |
21 | while (countdown && mbx->ops.check_for_msg(hw)) { |
22 | countdown--; |
23 | udelay(mbx->udelay); |
24 | } |
25 | |
26 | return countdown ? 0 : IXGBE_ERR_TIMEOUT; |
27 | } |
28 | |
29 | /** |
30 | * ixgbevf_poll_for_ack - Wait for message acknowledgment |
31 | * @hw: pointer to the HW structure |
32 | * |
33 | * returns 0 if it successfully received a message acknowledgment |
34 | **/ |
35 | static s32 ixgbevf_poll_for_ack(struct ixgbe_hw *hw) |
36 | { |
37 | struct ixgbe_mbx_info *mbx = &hw->mbx; |
38 | int countdown = mbx->timeout; |
39 | |
40 | if (!countdown || !mbx->ops.check_for_ack) |
41 | return IXGBE_ERR_CONFIG; |
42 | |
43 | while (countdown && mbx->ops.check_for_ack(hw)) { |
44 | countdown--; |
45 | udelay(mbx->udelay); |
46 | } |
47 | |
48 | return countdown ? 0 : IXGBE_ERR_TIMEOUT; |
49 | } |
50 | |
51 | /** |
52 | * ixgbevf_read_mailbox_vf - read VF's mailbox register |
53 | * @hw: pointer to the HW structure |
54 | * |
55 | * This function is used to read the mailbox register dedicated for VF without |
56 | * losing the read to clear status bits. |
57 | **/ |
58 | static u32 ixgbevf_read_mailbox_vf(struct ixgbe_hw *hw) |
59 | { |
60 | u32 vf_mailbox = IXGBE_READ_REG(hw, IXGBE_VFMAILBOX); |
61 | |
62 | vf_mailbox |= hw->mbx.vf_mailbox; |
63 | hw->mbx.vf_mailbox |= vf_mailbox & IXGBE_VFMAILBOX_R2C_BITS; |
64 | |
65 | return vf_mailbox; |
66 | } |
67 | |
68 | /** |
69 | * ixgbevf_clear_msg_vf - clear PF status bit |
70 | * @hw: pointer to the HW structure |
71 | * |
72 | * This function is used to clear PFSTS bit in the VFMAILBOX register |
73 | **/ |
74 | static void ixgbevf_clear_msg_vf(struct ixgbe_hw *hw) |
75 | { |
76 | u32 vf_mailbox = ixgbevf_read_mailbox_vf(hw); |
77 | |
78 | if (vf_mailbox & IXGBE_VFMAILBOX_PFSTS) { |
79 | hw->mbx.stats.reqs++; |
80 | hw->mbx.vf_mailbox &= ~IXGBE_VFMAILBOX_PFSTS; |
81 | } |
82 | } |
83 | |
84 | /** |
85 | * ixgbevf_clear_ack_vf - clear PF ACK bit |
86 | * @hw: pointer to the HW structure |
87 | * |
88 | * This function is used to clear PFACK bit in the VFMAILBOX register |
89 | **/ |
90 | static void ixgbevf_clear_ack_vf(struct ixgbe_hw *hw) |
91 | { |
92 | u32 vf_mailbox = ixgbevf_read_mailbox_vf(hw); |
93 | |
94 | if (vf_mailbox & IXGBE_VFMAILBOX_PFACK) { |
95 | hw->mbx.stats.acks++; |
96 | hw->mbx.vf_mailbox &= ~IXGBE_VFMAILBOX_PFACK; |
97 | } |
98 | } |
99 | |
100 | /** |
101 | * ixgbevf_clear_rst_vf - clear PF reset bit |
102 | * @hw: pointer to the HW structure |
103 | * |
104 | * This function is used to clear reset indication and reset done bit in |
105 | * VFMAILBOX register after reset the shared resources and the reset sequence. |
106 | **/ |
107 | static void ixgbevf_clear_rst_vf(struct ixgbe_hw *hw) |
108 | { |
109 | u32 vf_mailbox = ixgbevf_read_mailbox_vf(hw); |
110 | |
111 | if (vf_mailbox & (IXGBE_VFMAILBOX_RSTI | IXGBE_VFMAILBOX_RSTD)) { |
112 | hw->mbx.stats.rsts++; |
113 | hw->mbx.vf_mailbox &= ~(IXGBE_VFMAILBOX_RSTI | |
114 | IXGBE_VFMAILBOX_RSTD); |
115 | } |
116 | } |
117 | |
118 | /** |
119 | * ixgbevf_check_for_bit_vf - Determine if a status bit was set |
120 | * @hw: pointer to the HW structure |
121 | * @mask: bitmask for bits to be tested and cleared |
122 | * |
123 | * This function is used to check for the read to clear bits within |
124 | * the V2P mailbox. |
125 | **/ |
126 | static s32 ixgbevf_check_for_bit_vf(struct ixgbe_hw *hw, u32 mask) |
127 | { |
128 | u32 vf_mailbox = ixgbevf_read_mailbox_vf(hw); |
129 | s32 ret_val = IXGBE_ERR_MBX; |
130 | |
131 | if (vf_mailbox & mask) |
132 | ret_val = 0; |
133 | |
134 | return ret_val; |
135 | } |
136 | |
137 | /** |
138 | * ixgbevf_check_for_msg_vf - checks to see if the PF has sent mail |
139 | * @hw: pointer to the HW structure |
140 | * |
141 | * returns 0 if the PF has set the Status bit or else ERR_MBX |
142 | **/ |
143 | static s32 ixgbevf_check_for_msg_vf(struct ixgbe_hw *hw) |
144 | { |
145 | s32 ret_val = IXGBE_ERR_MBX; |
146 | |
147 | if (!ixgbevf_check_for_bit_vf(hw, IXGBE_VFMAILBOX_PFSTS)) { |
148 | ret_val = 0; |
149 | hw->mbx.stats.reqs++; |
150 | } |
151 | |
152 | return ret_val; |
153 | } |
154 | |
155 | /** |
156 | * ixgbevf_check_for_ack_vf - checks to see if the PF has ACK'd |
157 | * @hw: pointer to the HW structure |
158 | * |
159 | * returns 0 if the PF has set the ACK bit or else ERR_MBX |
160 | **/ |
161 | static s32 ixgbevf_check_for_ack_vf(struct ixgbe_hw *hw) |
162 | { |
163 | s32 ret_val = IXGBE_ERR_MBX; |
164 | |
165 | if (!ixgbevf_check_for_bit_vf(hw, IXGBE_VFMAILBOX_PFACK)) { |
166 | ret_val = 0; |
167 | ixgbevf_clear_ack_vf(hw); |
168 | hw->mbx.stats.acks++; |
169 | } |
170 | |
171 | return ret_val; |
172 | } |
173 | |
174 | /** |
175 | * ixgbevf_check_for_rst_vf - checks to see if the PF has reset |
176 | * @hw: pointer to the HW structure |
177 | * |
178 | * returns true if the PF has set the reset done bit or else false |
179 | **/ |
180 | static s32 ixgbevf_check_for_rst_vf(struct ixgbe_hw *hw) |
181 | { |
182 | s32 ret_val = IXGBE_ERR_MBX; |
183 | |
184 | if (!ixgbevf_check_for_bit_vf(hw, mask: (IXGBE_VFMAILBOX_RSTD | |
185 | IXGBE_VFMAILBOX_RSTI))) { |
186 | ret_val = 0; |
187 | ixgbevf_clear_rst_vf(hw); |
188 | hw->mbx.stats.rsts++; |
189 | } |
190 | |
191 | return ret_val; |
192 | } |
193 | |
194 | /** |
195 | * ixgbevf_obtain_mbx_lock_vf - obtain mailbox lock |
196 | * @hw: pointer to the HW structure |
197 | * |
198 | * return 0 if we obtained the mailbox lock |
199 | **/ |
200 | static s32 ixgbevf_obtain_mbx_lock_vf(struct ixgbe_hw *hw) |
201 | { |
202 | struct ixgbe_mbx_info *mbx = &hw->mbx; |
203 | s32 ret_val = IXGBE_ERR_CONFIG; |
204 | int countdown = mbx->timeout; |
205 | u32 vf_mailbox; |
206 | |
207 | if (!mbx->timeout) |
208 | return ret_val; |
209 | |
210 | while (countdown--) { |
211 | /* Reserve mailbox for VF use */ |
212 | vf_mailbox = ixgbevf_read_mailbox_vf(hw); |
213 | vf_mailbox |= IXGBE_VFMAILBOX_VFU; |
214 | IXGBE_WRITE_REG(hw, IXGBE_VFMAILBOX, vf_mailbox); |
215 | |
216 | /* Verify that VF is the owner of the lock */ |
217 | if (ixgbevf_read_mailbox_vf(hw) & IXGBE_VFMAILBOX_VFU) { |
218 | ret_val = 0; |
219 | break; |
220 | } |
221 | |
222 | /* Wait a bit before trying again */ |
223 | udelay(mbx->udelay); |
224 | } |
225 | |
226 | if (ret_val) |
227 | ret_val = IXGBE_ERR_TIMEOUT; |
228 | |
229 | return ret_val; |
230 | } |
231 | |
232 | /** |
233 | * ixgbevf_release_mbx_lock_vf - release mailbox lock |
234 | * @hw: pointer to the HW structure |
235 | **/ |
236 | static void ixgbevf_release_mbx_lock_vf(struct ixgbe_hw *hw) |
237 | { |
238 | u32 vf_mailbox; |
239 | |
240 | /* Return ownership of the buffer */ |
241 | vf_mailbox = ixgbevf_read_mailbox_vf(hw); |
242 | vf_mailbox &= ~IXGBE_VFMAILBOX_VFU; |
243 | IXGBE_WRITE_REG(hw, IXGBE_VFMAILBOX, vf_mailbox); |
244 | } |
245 | |
246 | /** |
247 | * ixgbevf_release_mbx_lock_vf_legacy - release mailbox lock |
248 | * @hw: pointer to the HW structure |
249 | **/ |
250 | static void ixgbevf_release_mbx_lock_vf_legacy(struct ixgbe_hw *__always_unused hw) |
251 | { |
252 | } |
253 | |
254 | /** |
255 | * ixgbevf_write_mbx_vf - Write a message to the mailbox |
256 | * @hw: pointer to the HW structure |
257 | * @msg: The message buffer |
258 | * @size: Length of buffer |
259 | * |
260 | * returns 0 if it successfully copied message into the buffer |
261 | **/ |
262 | static s32 ixgbevf_write_mbx_vf(struct ixgbe_hw *hw, u32 *msg, u16 size) |
263 | { |
264 | u32 vf_mailbox; |
265 | s32 ret_val; |
266 | u16 i; |
267 | |
268 | /* lock the mailbox to prevent PF/VF race condition */ |
269 | ret_val = ixgbevf_obtain_mbx_lock_vf(hw); |
270 | if (ret_val) |
271 | goto out_no_write; |
272 | |
273 | /* flush msg and acks as we are overwriting the message buffer */ |
274 | ixgbevf_clear_msg_vf(hw); |
275 | ixgbevf_clear_ack_vf(hw); |
276 | |
277 | /* copy the caller specified message to the mailbox memory buffer */ |
278 | for (i = 0; i < size; i++) |
279 | IXGBE_WRITE_REG_ARRAY(hw, IXGBE_VFMBMEM, i, msg[i]); |
280 | |
281 | /* update stats */ |
282 | hw->mbx.stats.msgs_tx++; |
283 | |
284 | /* interrupt the PF to tell it a message has been sent */ |
285 | vf_mailbox = ixgbevf_read_mailbox_vf(hw); |
286 | vf_mailbox |= IXGBE_VFMAILBOX_REQ; |
287 | IXGBE_WRITE_REG(hw, IXGBE_VFMAILBOX, vf_mailbox); |
288 | |
289 | /* if msg sent wait until we receive an ack */ |
290 | ret_val = ixgbevf_poll_for_ack(hw); |
291 | |
292 | out_no_write: |
293 | hw->mbx.ops.release(hw); |
294 | |
295 | return ret_val; |
296 | } |
297 | |
298 | /** |
299 | * ixgbevf_write_mbx_vf_legacy - Write a message to the mailbox |
300 | * @hw: pointer to the HW structure |
301 | * @msg: The message buffer |
302 | * @size: Length of buffer |
303 | * |
304 | * returns 0 if it successfully copied message into the buffer |
305 | **/ |
306 | static s32 ixgbevf_write_mbx_vf_legacy(struct ixgbe_hw *hw, u32 *msg, u16 size) |
307 | { |
308 | s32 ret_val; |
309 | u16 i; |
310 | |
311 | /* lock the mailbox to prevent PF/VF race condition */ |
312 | ret_val = ixgbevf_obtain_mbx_lock_vf(hw); |
313 | if (ret_val) |
314 | goto out_no_write; |
315 | |
316 | /* flush msg and acks as we are overwriting the message buffer */ |
317 | ixgbevf_check_for_msg_vf(hw); |
318 | ixgbevf_clear_msg_vf(hw); |
319 | ixgbevf_check_for_ack_vf(hw); |
320 | ixgbevf_clear_ack_vf(hw); |
321 | |
322 | /* copy the caller specified message to the mailbox memory buffer */ |
323 | for (i = 0; i < size; i++) |
324 | IXGBE_WRITE_REG_ARRAY(hw, IXGBE_VFMBMEM, i, msg[i]); |
325 | |
326 | /* update stats */ |
327 | hw->mbx.stats.msgs_tx++; |
328 | |
329 | /* Drop VFU and interrupt the PF to tell it a message has been sent */ |
330 | IXGBE_WRITE_REG(hw, IXGBE_VFMAILBOX, IXGBE_VFMAILBOX_REQ); |
331 | |
332 | out_no_write: |
333 | return ret_val; |
334 | } |
335 | |
336 | /** |
337 | * ixgbevf_read_mbx_vf - Reads a message from the inbox intended for VF |
338 | * @hw: pointer to the HW structure |
339 | * @msg: The message buffer |
340 | * @size: Length of buffer |
341 | * |
342 | * returns 0 if it successfully read message from buffer |
343 | **/ |
344 | static s32 ixgbevf_read_mbx_vf(struct ixgbe_hw *hw, u32 *msg, u16 size) |
345 | { |
346 | u32 vf_mailbox; |
347 | s32 ret_val; |
348 | u16 i; |
349 | |
350 | /* check if there is a message from PF */ |
351 | ret_val = ixgbevf_check_for_msg_vf(hw); |
352 | if (ret_val) |
353 | return ret_val; |
354 | |
355 | ixgbevf_clear_msg_vf(hw); |
356 | |
357 | /* copy the message from the mailbox memory buffer */ |
358 | for (i = 0; i < size; i++) |
359 | msg[i] = IXGBE_READ_REG_ARRAY(hw, IXGBE_VFMBMEM, i); |
360 | |
361 | /* Acknowledge receipt */ |
362 | vf_mailbox = ixgbevf_read_mailbox_vf(hw); |
363 | vf_mailbox |= IXGBE_VFMAILBOX_ACK; |
364 | IXGBE_WRITE_REG(hw, IXGBE_VFMAILBOX, vf_mailbox); |
365 | |
366 | /* update stats */ |
367 | hw->mbx.stats.msgs_rx++; |
368 | |
369 | return ret_val; |
370 | } |
371 | |
372 | /** |
373 | * ixgbevf_read_mbx_vf_legacy - Reads a message from the inbox intended for VF |
374 | * @hw: pointer to the HW structure |
375 | * @msg: The message buffer |
376 | * @size: Length of buffer |
377 | * |
378 | * returns 0 if it successfully read message from buffer |
379 | **/ |
380 | static s32 ixgbevf_read_mbx_vf_legacy(struct ixgbe_hw *hw, u32 *msg, u16 size) |
381 | { |
382 | s32 ret_val = 0; |
383 | u16 i; |
384 | |
385 | /* lock the mailbox to prevent PF/VF race condition */ |
386 | ret_val = ixgbevf_obtain_mbx_lock_vf(hw); |
387 | if (ret_val) |
388 | goto out_no_read; |
389 | |
390 | /* copy the message from the mailbox memory buffer */ |
391 | for (i = 0; i < size; i++) |
392 | msg[i] = IXGBE_READ_REG_ARRAY(hw, IXGBE_VFMBMEM, i); |
393 | |
394 | /* Acknowledge receipt and release mailbox, then we're done */ |
395 | IXGBE_WRITE_REG(hw, IXGBE_VFMAILBOX, IXGBE_VFMAILBOX_ACK); |
396 | |
397 | /* update stats */ |
398 | hw->mbx.stats.msgs_rx++; |
399 | |
400 | out_no_read: |
401 | return ret_val; |
402 | } |
403 | |
404 | /** |
405 | * ixgbevf_init_mbx_params_vf - set initial values for VF mailbox |
406 | * @hw: pointer to the HW structure |
407 | * |
408 | * Initializes the hw->mbx struct to correct values for VF mailbox |
409 | */ |
410 | static s32 ixgbevf_init_mbx_params_vf(struct ixgbe_hw *hw) |
411 | { |
412 | struct ixgbe_mbx_info *mbx = &hw->mbx; |
413 | |
414 | /* start mailbox as timed out and let the reset_hw call set the timeout |
415 | * value to begin communications |
416 | */ |
417 | mbx->timeout = IXGBE_VF_MBX_INIT_TIMEOUT; |
418 | mbx->udelay = IXGBE_VF_MBX_INIT_DELAY; |
419 | |
420 | mbx->size = IXGBE_VFMAILBOX_SIZE; |
421 | |
422 | mbx->stats.msgs_tx = 0; |
423 | mbx->stats.msgs_rx = 0; |
424 | mbx->stats.reqs = 0; |
425 | mbx->stats.acks = 0; |
426 | mbx->stats.rsts = 0; |
427 | |
428 | return 0; |
429 | } |
430 | |
431 | /** |
432 | * ixgbevf_poll_mbx - Wait for message and read it from the mailbox |
433 | * @hw: pointer to the HW structure |
434 | * @msg: The message buffer |
435 | * @size: Length of buffer |
436 | * |
437 | * returns 0 if it successfully read message from buffer |
438 | **/ |
439 | s32 ixgbevf_poll_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size) |
440 | { |
441 | struct ixgbe_mbx_info *mbx = &hw->mbx; |
442 | s32 ret_val = IXGBE_ERR_CONFIG; |
443 | |
444 | if (!mbx->ops.read || !mbx->ops.check_for_msg || !mbx->timeout) |
445 | return ret_val; |
446 | |
447 | /* limit read to size of mailbox */ |
448 | if (size > mbx->size) |
449 | size = mbx->size; |
450 | |
451 | ret_val = ixgbevf_poll_for_msg(hw); |
452 | /* if ack received read message, otherwise we timed out */ |
453 | if (!ret_val) |
454 | ret_val = mbx->ops.read(hw, msg, size); |
455 | |
456 | return ret_val; |
457 | } |
458 | |
459 | /** |
460 | * ixgbevf_write_mbx - Write a message to the mailbox and wait for ACK |
461 | * @hw: pointer to the HW structure |
462 | * @msg: The message buffer |
463 | * @size: Length of buffer |
464 | * |
465 | * returns 0 if it successfully copied message into the buffer and |
466 | * received an ACK to that message within specified period |
467 | **/ |
468 | s32 ixgbevf_write_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size) |
469 | { |
470 | struct ixgbe_mbx_info *mbx = &hw->mbx; |
471 | s32 ret_val = IXGBE_ERR_CONFIG; |
472 | |
473 | /** |
474 | * exit if either we can't write, release |
475 | * or there is no timeout defined |
476 | */ |
477 | if (!mbx->ops.write || !mbx->ops.check_for_ack || !mbx->ops.release || |
478 | !mbx->timeout) |
479 | return ret_val; |
480 | |
481 | if (size > mbx->size) |
482 | ret_val = IXGBE_ERR_PARAM; |
483 | else |
484 | ret_val = mbx->ops.write(hw, msg, size); |
485 | |
486 | return ret_val; |
487 | } |
488 | |
489 | const struct ixgbe_mbx_operations ixgbevf_mbx_ops = { |
490 | .init_params = ixgbevf_init_mbx_params_vf, |
491 | .release = ixgbevf_release_mbx_lock_vf, |
492 | .read = ixgbevf_read_mbx_vf, |
493 | .write = ixgbevf_write_mbx_vf, |
494 | .check_for_msg = ixgbevf_check_for_msg_vf, |
495 | .check_for_ack = ixgbevf_check_for_ack_vf, |
496 | .check_for_rst = ixgbevf_check_for_rst_vf, |
497 | }; |
498 | |
499 | const struct ixgbe_mbx_operations ixgbevf_mbx_ops_legacy = { |
500 | .init_params = ixgbevf_init_mbx_params_vf, |
501 | .release = ixgbevf_release_mbx_lock_vf_legacy, |
502 | .read = ixgbevf_read_mbx_vf_legacy, |
503 | .write = ixgbevf_write_mbx_vf_legacy, |
504 | .check_for_msg = ixgbevf_check_for_msg_vf, |
505 | .check_for_ack = ixgbevf_check_for_ack_vf, |
506 | .check_for_rst = ixgbevf_check_for_rst_vf, |
507 | }; |
508 | |
509 | /* Mailbox operations when running on Hyper-V. |
510 | * On Hyper-V, PF/VF communication is not through the |
511 | * hardware mailbox; this communication is through |
512 | * a software mediated path. |
513 | * Most mail box operations are noop while running on |
514 | * Hyper-V. |
515 | */ |
516 | const struct ixgbe_mbx_operations ixgbevf_hv_mbx_ops = { |
517 | .init_params = ixgbevf_init_mbx_params_vf, |
518 | .check_for_rst = ixgbevf_check_for_rst_vf, |
519 | }; |
520 | |