1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Copyright(c) 1999 - 2018 Intel Corporation. */ |
3 | |
4 | #include <linux/pci.h> |
5 | #include <linux/delay.h> |
6 | #include "ixgbe.h" |
7 | #include "ixgbe_mbx.h" |
8 | |
9 | /** |
10 | * ixgbe_read_mbx - Reads a message from the mailbox |
11 | * @hw: pointer to the HW structure |
12 | * @msg: The message buffer |
13 | * @size: Length of buffer |
14 | * @mbx_id: id of mailbox to read |
15 | * |
16 | * returns SUCCESS if it successfully read message from buffer |
17 | **/ |
18 | int ixgbe_read_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size, u16 mbx_id) |
19 | { |
20 | struct ixgbe_mbx_info *mbx = &hw->mbx; |
21 | |
22 | /* limit read to size of mailbox */ |
23 | if (size > mbx->size) |
24 | size = mbx->size; |
25 | |
26 | if (!mbx->ops) |
27 | return -EIO; |
28 | |
29 | return mbx->ops->read(hw, msg, size, mbx_id); |
30 | } |
31 | |
32 | /** |
33 | * ixgbe_write_mbx - Write a message to the mailbox |
34 | * @hw: pointer to the HW structure |
35 | * @msg: The message buffer |
36 | * @size: Length of buffer |
37 | * @mbx_id: id of mailbox to write |
38 | * |
39 | * returns SUCCESS if it successfully copied message into the buffer |
40 | **/ |
41 | int ixgbe_write_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size, u16 mbx_id) |
42 | { |
43 | struct ixgbe_mbx_info *mbx = &hw->mbx; |
44 | |
45 | if (size > mbx->size) |
46 | return -EINVAL; |
47 | |
48 | if (!mbx->ops) |
49 | return -EIO; |
50 | |
51 | return mbx->ops->write(hw, msg, size, mbx_id); |
52 | } |
53 | |
54 | /** |
55 | * ixgbe_check_for_msg - checks to see if someone sent us mail |
56 | * @hw: pointer to the HW structure |
57 | * @mbx_id: id of mailbox to check |
58 | * |
59 | * returns SUCCESS if the Status bit was found or else ERR_MBX |
60 | **/ |
61 | int ixgbe_check_for_msg(struct ixgbe_hw *hw, u16 mbx_id) |
62 | { |
63 | struct ixgbe_mbx_info *mbx = &hw->mbx; |
64 | |
65 | if (!mbx->ops) |
66 | return -EIO; |
67 | |
68 | return mbx->ops->check_for_msg(hw, mbx_id); |
69 | } |
70 | |
71 | /** |
72 | * ixgbe_check_for_ack - checks to see if someone sent us ACK |
73 | * @hw: pointer to the HW structure |
74 | * @mbx_id: id of mailbox to check |
75 | * |
76 | * returns SUCCESS if the Status bit was found or else ERR_MBX |
77 | **/ |
78 | int ixgbe_check_for_ack(struct ixgbe_hw *hw, u16 mbx_id) |
79 | { |
80 | struct ixgbe_mbx_info *mbx = &hw->mbx; |
81 | |
82 | if (!mbx->ops) |
83 | return -EIO; |
84 | |
85 | return mbx->ops->check_for_ack(hw, mbx_id); |
86 | } |
87 | |
88 | /** |
89 | * ixgbe_check_for_rst - checks to see if other side has reset |
90 | * @hw: pointer to the HW structure |
91 | * @mbx_id: id of mailbox to check |
92 | * |
93 | * returns SUCCESS if the Status bit was found or else ERR_MBX |
94 | **/ |
95 | int ixgbe_check_for_rst(struct ixgbe_hw *hw, u16 mbx_id) |
96 | { |
97 | struct ixgbe_mbx_info *mbx = &hw->mbx; |
98 | |
99 | if (!mbx->ops) |
100 | return -EIO; |
101 | |
102 | return mbx->ops->check_for_rst(hw, mbx_id); |
103 | } |
104 | |
105 | /** |
106 | * ixgbe_poll_for_msg - Wait for message notification |
107 | * @hw: pointer to the HW structure |
108 | * @mbx_id: id of mailbox to write |
109 | * |
110 | * returns SUCCESS if it successfully received a message notification |
111 | **/ |
112 | static int ixgbe_poll_for_msg(struct ixgbe_hw *hw, u16 mbx_id) |
113 | { |
114 | struct ixgbe_mbx_info *mbx = &hw->mbx; |
115 | int countdown = mbx->timeout; |
116 | |
117 | if (!countdown || !mbx->ops) |
118 | return -EIO; |
119 | |
120 | while (mbx->ops->check_for_msg(hw, mbx_id)) { |
121 | countdown--; |
122 | if (!countdown) |
123 | return -EIO; |
124 | udelay(mbx->usec_delay); |
125 | } |
126 | |
127 | return 0; |
128 | } |
129 | |
130 | /** |
131 | * ixgbe_poll_for_ack - Wait for message acknowledgement |
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 acknowledgement |
136 | **/ |
137 | static int ixgbe_poll_for_ack(struct ixgbe_hw *hw, u16 mbx_id) |
138 | { |
139 | struct ixgbe_mbx_info *mbx = &hw->mbx; |
140 | int countdown = mbx->timeout; |
141 | |
142 | if (!countdown || !mbx->ops) |
143 | return -EIO; |
144 | |
145 | while (mbx->ops->check_for_ack(hw, mbx_id)) { |
146 | countdown--; |
147 | if (!countdown) |
148 | return -EIO; |
149 | udelay(mbx->usec_delay); |
150 | } |
151 | |
152 | return 0; |
153 | } |
154 | |
155 | /** |
156 | * ixgbe_read_posted_mbx - Wait for message notification and receive message |
157 | * @hw: pointer to the HW structure |
158 | * @msg: The message buffer |
159 | * @size: Length of buffer |
160 | * @mbx_id: id of mailbox to write |
161 | * |
162 | * returns SUCCESS if it successfully received a message notification and |
163 | * copied it into the receive buffer. |
164 | **/ |
165 | static int ixgbe_read_posted_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size, |
166 | u16 mbx_id) |
167 | { |
168 | struct ixgbe_mbx_info *mbx = &hw->mbx; |
169 | int ret_val; |
170 | |
171 | if (!mbx->ops) |
172 | return -EIO; |
173 | |
174 | ret_val = ixgbe_poll_for_msg(hw, mbx_id); |
175 | if (ret_val) |
176 | return ret_val; |
177 | |
178 | /* if ack received read message */ |
179 | return mbx->ops->read(hw, msg, size, mbx_id); |
180 | } |
181 | |
182 | /** |
183 | * ixgbe_write_posted_mbx - Write a message to the mailbox, wait for ack |
184 | * @hw: pointer to the HW structure |
185 | * @msg: The message buffer |
186 | * @size: Length of buffer |
187 | * @mbx_id: id of mailbox to write |
188 | * |
189 | * returns SUCCESS if it successfully copied message into the buffer and |
190 | * received an ack to that message within delay * timeout period |
191 | **/ |
192 | static int ixgbe_write_posted_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size, |
193 | u16 mbx_id) |
194 | { |
195 | struct ixgbe_mbx_info *mbx = &hw->mbx; |
196 | int ret_val; |
197 | |
198 | /* exit if either we can't write or there isn't a defined timeout */ |
199 | if (!mbx->ops || !mbx->timeout) |
200 | return -EIO; |
201 | |
202 | /* send msg */ |
203 | ret_val = mbx->ops->write(hw, msg, size, mbx_id); |
204 | if (ret_val) |
205 | return ret_val; |
206 | |
207 | /* if msg sent wait until we receive an ack */ |
208 | return ixgbe_poll_for_ack(hw, mbx_id); |
209 | } |
210 | |
211 | static int ixgbe_check_for_bit_pf(struct ixgbe_hw *hw, u32 mask, s32 index) |
212 | { |
213 | u32 mbvficr = IXGBE_READ_REG(hw, IXGBE_MBVFICR(index)); |
214 | |
215 | if (mbvficr & mask) { |
216 | IXGBE_WRITE_REG(hw, IXGBE_MBVFICR(index), mask); |
217 | return 0; |
218 | } |
219 | |
220 | return -EIO; |
221 | } |
222 | |
223 | /** |
224 | * ixgbe_check_for_msg_pf - checks to see if the VF has sent mail |
225 | * @hw: pointer to the HW structure |
226 | * @vf_number: the VF index |
227 | * |
228 | * returns SUCCESS if the VF has set the Status bit or else ERR_MBX |
229 | **/ |
230 | static int ixgbe_check_for_msg_pf(struct ixgbe_hw *hw, u16 vf_number) |
231 | { |
232 | int index = IXGBE_MBVFICR_INDEX(vf_number); |
233 | u32 vf_bit = vf_number % 16; |
234 | |
235 | if (!ixgbe_check_for_bit_pf(hw, IXGBE_MBVFICR_VFREQ_VF1 << vf_bit, |
236 | index)) { |
237 | hw->mbx.stats.reqs++; |
238 | return 0; |
239 | } |
240 | |
241 | return -EIO; |
242 | } |
243 | |
244 | /** |
245 | * ixgbe_check_for_ack_pf - checks to see if the VF has ACKed |
246 | * @hw: pointer to the HW structure |
247 | * @vf_number: the VF index |
248 | * |
249 | * returns SUCCESS if the VF has set the Status bit or else ERR_MBX |
250 | **/ |
251 | static int ixgbe_check_for_ack_pf(struct ixgbe_hw *hw, u16 vf_number) |
252 | { |
253 | int index = IXGBE_MBVFICR_INDEX(vf_number); |
254 | u32 vf_bit = vf_number % 16; |
255 | |
256 | if (!ixgbe_check_for_bit_pf(hw, IXGBE_MBVFICR_VFACK_VF1 << vf_bit, |
257 | index)) { |
258 | hw->mbx.stats.acks++; |
259 | return 0; |
260 | } |
261 | |
262 | return -EIO; |
263 | } |
264 | |
265 | /** |
266 | * ixgbe_check_for_rst_pf - checks to see if the VF has reset |
267 | * @hw: pointer to the HW structure |
268 | * @vf_number: the VF index |
269 | * |
270 | * returns SUCCESS if the VF has set the Status bit or else ERR_MBX |
271 | **/ |
272 | static int ixgbe_check_for_rst_pf(struct ixgbe_hw *hw, u16 vf_number) |
273 | { |
274 | u32 reg_offset = (vf_number < 32) ? 0 : 1; |
275 | u32 vf_shift = vf_number % 32; |
276 | u32 vflre = 0; |
277 | |
278 | switch (hw->mac.type) { |
279 | case ixgbe_mac_82599EB: |
280 | vflre = IXGBE_READ_REG(hw, IXGBE_VFLRE(reg_offset)); |
281 | break; |
282 | case ixgbe_mac_X540: |
283 | case ixgbe_mac_X550: |
284 | case ixgbe_mac_X550EM_x: |
285 | case ixgbe_mac_x550em_a: |
286 | vflre = IXGBE_READ_REG(hw, IXGBE_VFLREC(reg_offset)); |
287 | break; |
288 | default: |
289 | break; |
290 | } |
291 | |
292 | if (vflre & BIT(vf_shift)) { |
293 | IXGBE_WRITE_REG(hw, IXGBE_VFLREC(reg_offset), BIT(vf_shift)); |
294 | hw->mbx.stats.rsts++; |
295 | return 0; |
296 | } |
297 | |
298 | return -EIO; |
299 | } |
300 | |
301 | /** |
302 | * ixgbe_obtain_mbx_lock_pf - obtain mailbox lock |
303 | * @hw: pointer to the HW structure |
304 | * @vf_number: the VF index |
305 | * |
306 | * return SUCCESS if we obtained the mailbox lock |
307 | **/ |
308 | static int ixgbe_obtain_mbx_lock_pf(struct ixgbe_hw *hw, u16 vf_number) |
309 | { |
310 | u32 p2v_mailbox; |
311 | |
312 | /* Take ownership of the buffer */ |
313 | IXGBE_WRITE_REG(hw, IXGBE_PFMAILBOX(vf_number), IXGBE_PFMAILBOX_PFU); |
314 | |
315 | /* reserve mailbox for vf use */ |
316 | p2v_mailbox = IXGBE_READ_REG(hw, IXGBE_PFMAILBOX(vf_number)); |
317 | if (p2v_mailbox & IXGBE_PFMAILBOX_PFU) |
318 | return 0; |
319 | |
320 | return -EIO; |
321 | } |
322 | |
323 | /** |
324 | * ixgbe_write_mbx_pf - Places a message in the mailbox |
325 | * @hw: pointer to the HW structure |
326 | * @msg: The message buffer |
327 | * @size: Length of buffer |
328 | * @vf_number: the VF index |
329 | * |
330 | * returns SUCCESS if it successfully copied message into the buffer |
331 | **/ |
332 | static int ixgbe_write_mbx_pf(struct ixgbe_hw *hw, u32 *msg, u16 size, |
333 | u16 vf_number) |
334 | { |
335 | int ret_val; |
336 | u16 i; |
337 | |
338 | /* lock the mailbox to prevent pf/vf race condition */ |
339 | ret_val = ixgbe_obtain_mbx_lock_pf(hw, vf_number); |
340 | if (ret_val) |
341 | return ret_val; |
342 | |
343 | /* flush msg and acks as we are overwriting the message buffer */ |
344 | ixgbe_check_for_msg_pf(hw, vf_number); |
345 | ixgbe_check_for_ack_pf(hw, vf_number); |
346 | |
347 | /* copy the caller specified message to the mailbox memory buffer */ |
348 | for (i = 0; i < size; i++) |
349 | IXGBE_WRITE_REG_ARRAY(hw, IXGBE_PFMBMEM(vf_number), i, msg[i]); |
350 | |
351 | /* Interrupt VF to tell it a message has been sent and release buffer*/ |
352 | IXGBE_WRITE_REG(hw, IXGBE_PFMAILBOX(vf_number), IXGBE_PFMAILBOX_STS); |
353 | |
354 | /* update stats */ |
355 | hw->mbx.stats.msgs_tx++; |
356 | |
357 | return 0; |
358 | } |
359 | |
360 | /** |
361 | * ixgbe_read_mbx_pf - Read a message from the mailbox |
362 | * @hw: pointer to the HW structure |
363 | * @msg: The message buffer |
364 | * @size: Length of buffer |
365 | * @vf_number: the VF index |
366 | * |
367 | * This function copies a message from the mailbox buffer to the caller's |
368 | * memory buffer. The presumption is that the caller knows that there was |
369 | * a message due to a VF request so no polling for message is needed. |
370 | **/ |
371 | static int ixgbe_read_mbx_pf(struct ixgbe_hw *hw, u32 *msg, u16 size, |
372 | u16 vf_number) |
373 | { |
374 | int ret_val; |
375 | u16 i; |
376 | |
377 | /* lock the mailbox to prevent pf/vf race condition */ |
378 | ret_val = ixgbe_obtain_mbx_lock_pf(hw, vf_number); |
379 | if (ret_val) |
380 | return ret_val; |
381 | |
382 | /* copy the message to the mailbox memory buffer */ |
383 | for (i = 0; i < size; i++) |
384 | msg[i] = IXGBE_READ_REG_ARRAY(hw, IXGBE_PFMBMEM(vf_number), i); |
385 | |
386 | /* Acknowledge the message and release buffer */ |
387 | IXGBE_WRITE_REG(hw, IXGBE_PFMAILBOX(vf_number), IXGBE_PFMAILBOX_ACK); |
388 | |
389 | /* update stats */ |
390 | hw->mbx.stats.msgs_rx++; |
391 | |
392 | return 0; |
393 | } |
394 | |
395 | #ifdef CONFIG_PCI_IOV |
396 | /** |
397 | * ixgbe_init_mbx_params_pf - set initial values for pf mailbox |
398 | * @hw: pointer to the HW structure |
399 | * |
400 | * Initializes the hw->mbx struct to correct values for pf mailbox |
401 | */ |
402 | void ixgbe_init_mbx_params_pf(struct ixgbe_hw *hw) |
403 | { |
404 | struct ixgbe_mbx_info *mbx = &hw->mbx; |
405 | |
406 | if (hw->mac.type != ixgbe_mac_82599EB && |
407 | hw->mac.type != ixgbe_mac_X550 && |
408 | hw->mac.type != ixgbe_mac_X550EM_x && |
409 | hw->mac.type != ixgbe_mac_x550em_a && |
410 | hw->mac.type != ixgbe_mac_X540) |
411 | return; |
412 | |
413 | mbx->timeout = 0; |
414 | mbx->usec_delay = 0; |
415 | |
416 | mbx->stats.msgs_tx = 0; |
417 | mbx->stats.msgs_rx = 0; |
418 | mbx->stats.reqs = 0; |
419 | mbx->stats.acks = 0; |
420 | mbx->stats.rsts = 0; |
421 | |
422 | mbx->size = IXGBE_VFMAILBOX_SIZE; |
423 | } |
424 | #endif /* CONFIG_PCI_IOV */ |
425 | |
426 | const struct ixgbe_mbx_operations mbx_ops_generic = { |
427 | .read = ixgbe_read_mbx_pf, |
428 | .write = ixgbe_write_mbx_pf, |
429 | .read_posted = ixgbe_read_posted_mbx, |
430 | .write_posted = ixgbe_write_posted_mbx, |
431 | .check_for_msg = ixgbe_check_for_msg_pf, |
432 | .check_for_ack = ixgbe_check_for_ack_pf, |
433 | .check_for_rst = ixgbe_check_for_rst_pf, |
434 | }; |
435 | |
436 | |