diff options
Diffstat (limited to 'drivers/net/igb/e1000_mbx.c')
-rw-r--r-- | drivers/net/igb/e1000_mbx.c | 446 |
1 files changed, 446 insertions, 0 deletions
diff --git a/drivers/net/igb/e1000_mbx.c b/drivers/net/igb/e1000_mbx.c new file mode 100644 index 00000000000..74f2f11ac29 --- /dev/null +++ b/drivers/net/igb/e1000_mbx.c | |||
@@ -0,0 +1,446 @@ | |||
1 | /******************************************************************************* | ||
2 | |||
3 | Intel(R) Gigabit Ethernet Linux driver | ||
4 | Copyright(c) 2007-2011 Intel Corporation. | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify it | ||
7 | under the terms and conditions of the GNU General Public License, | ||
8 | version 2, as published by the Free Software Foundation. | ||
9 | |||
10 | This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License along with | ||
16 | this program; if not, write to the Free Software Foundation, Inc., | ||
17 | 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | ||
18 | |||
19 | The full GNU General Public License is included in this distribution in | ||
20 | the file called "COPYING". | ||
21 | |||
22 | Contact Information: | ||
23 | e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> | ||
24 | Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
25 | |||
26 | *******************************************************************************/ | ||
27 | |||
28 | #include "e1000_mbx.h" | ||
29 | |||
30 | /** | ||
31 | * igb_read_mbx - Reads a message from the mailbox | ||
32 | * @hw: pointer to the HW structure | ||
33 | * @msg: The message buffer | ||
34 | * @size: Length of buffer | ||
35 | * @mbx_id: id of mailbox to read | ||
36 | * | ||
37 | * returns SUCCESS if it successfuly read message from buffer | ||
38 | **/ | ||
39 | s32 igb_read_mbx(struct e1000_hw *hw, u32 *msg, u16 size, u16 mbx_id) | ||
40 | { | ||
41 | struct e1000_mbx_info *mbx = &hw->mbx; | ||
42 | s32 ret_val = -E1000_ERR_MBX; | ||
43 | |||
44 | /* limit read to size of mailbox */ | ||
45 | if (size > mbx->size) | ||
46 | size = mbx->size; | ||
47 | |||
48 | if (mbx->ops.read) | ||
49 | ret_val = mbx->ops.read(hw, msg, size, mbx_id); | ||
50 | |||
51 | return ret_val; | ||
52 | } | ||
53 | |||
54 | /** | ||
55 | * igb_write_mbx - Write a message to the mailbox | ||
56 | * @hw: pointer to the HW structure | ||
57 | * @msg: The message buffer | ||
58 | * @size: Length of buffer | ||
59 | * @mbx_id: id of mailbox to write | ||
60 | * | ||
61 | * returns SUCCESS if it successfully copied message into the buffer | ||
62 | **/ | ||
63 | s32 igb_write_mbx(struct e1000_hw *hw, u32 *msg, u16 size, u16 mbx_id) | ||
64 | { | ||
65 | struct e1000_mbx_info *mbx = &hw->mbx; | ||
66 | s32 ret_val = 0; | ||
67 | |||
68 | if (size > mbx->size) | ||
69 | ret_val = -E1000_ERR_MBX; | ||
70 | |||
71 | else if (mbx->ops.write) | ||
72 | ret_val = mbx->ops.write(hw, msg, size, mbx_id); | ||
73 | |||
74 | return ret_val; | ||
75 | } | ||
76 | |||
77 | /** | ||
78 | * igb_check_for_msg - checks to see if someone sent us mail | ||
79 | * @hw: pointer to the HW structure | ||
80 | * @mbx_id: id of mailbox to check | ||
81 | * | ||
82 | * returns SUCCESS if the Status bit was found or else ERR_MBX | ||
83 | **/ | ||
84 | s32 igb_check_for_msg(struct e1000_hw *hw, u16 mbx_id) | ||
85 | { | ||
86 | struct e1000_mbx_info *mbx = &hw->mbx; | ||
87 | s32 ret_val = -E1000_ERR_MBX; | ||
88 | |||
89 | if (mbx->ops.check_for_msg) | ||
90 | ret_val = mbx->ops.check_for_msg(hw, mbx_id); | ||
91 | |||
92 | return ret_val; | ||
93 | } | ||
94 | |||
95 | /** | ||
96 | * igb_check_for_ack - checks to see if someone sent us ACK | ||
97 | * @hw: pointer to the HW structure | ||
98 | * @mbx_id: id of mailbox to check | ||
99 | * | ||
100 | * returns SUCCESS if the Status bit was found or else ERR_MBX | ||
101 | **/ | ||
102 | s32 igb_check_for_ack(struct e1000_hw *hw, u16 mbx_id) | ||
103 | { | ||
104 | struct e1000_mbx_info *mbx = &hw->mbx; | ||
105 | s32 ret_val = -E1000_ERR_MBX; | ||
106 | |||
107 | if (mbx->ops.check_for_ack) | ||
108 | ret_val = mbx->ops.check_for_ack(hw, mbx_id); | ||
109 | |||
110 | return ret_val; | ||
111 | } | ||
112 | |||
113 | /** | ||
114 | * igb_check_for_rst - checks to see if other side has reset | ||
115 | * @hw: pointer to the HW structure | ||
116 | * @mbx_id: id of mailbox to check | ||
117 | * | ||
118 | * returns SUCCESS if the Status bit was found or else ERR_MBX | ||
119 | **/ | ||
120 | s32 igb_check_for_rst(struct e1000_hw *hw, u16 mbx_id) | ||
121 | { | ||
122 | struct e1000_mbx_info *mbx = &hw->mbx; | ||
123 | s32 ret_val = -E1000_ERR_MBX; | ||
124 | |||
125 | if (mbx->ops.check_for_rst) | ||
126 | ret_val = mbx->ops.check_for_rst(hw, mbx_id); | ||
127 | |||
128 | return ret_val; | ||
129 | } | ||
130 | |||
131 | /** | ||
132 | * igb_poll_for_msg - Wait for message notification | ||
133 | * @hw: pointer to the HW structure | ||
134 | * @mbx_id: id of mailbox to write | ||
135 | * | ||
136 | * returns SUCCESS if it successfully received a message notification | ||
137 | **/ | ||
138 | static s32 igb_poll_for_msg(struct e1000_hw *hw, u16 mbx_id) | ||
139 | { | ||
140 | struct e1000_mbx_info *mbx = &hw->mbx; | ||
141 | int countdown = mbx->timeout; | ||
142 | |||
143 | if (!countdown || !mbx->ops.check_for_msg) | ||
144 | goto out; | ||
145 | |||
146 | while (countdown && mbx->ops.check_for_msg(hw, mbx_id)) { | ||
147 | countdown--; | ||
148 | if (!countdown) | ||
149 | break; | ||
150 | udelay(mbx->usec_delay); | ||
151 | } | ||
152 | |||
153 | /* if we failed, all future posted messages fail until reset */ | ||
154 | if (!countdown) | ||
155 | mbx->timeout = 0; | ||
156 | out: | ||
157 | return countdown ? 0 : -E1000_ERR_MBX; | ||
158 | } | ||
159 | |||
160 | /** | ||
161 | * igb_poll_for_ack - Wait for message acknowledgement | ||
162 | * @hw: pointer to the HW structure | ||
163 | * @mbx_id: id of mailbox to write | ||
164 | * | ||
165 | * returns SUCCESS if it successfully received a message acknowledgement | ||
166 | **/ | ||
167 | static s32 igb_poll_for_ack(struct e1000_hw *hw, u16 mbx_id) | ||
168 | { | ||
169 | struct e1000_mbx_info *mbx = &hw->mbx; | ||
170 | int countdown = mbx->timeout; | ||
171 | |||
172 | if (!countdown || !mbx->ops.check_for_ack) | ||
173 | goto out; | ||
174 | |||
175 | while (countdown && mbx->ops.check_for_ack(hw, mbx_id)) { | ||
176 | countdown--; | ||
177 | if (!countdown) | ||
178 | break; | ||
179 | udelay(mbx->usec_delay); | ||
180 | } | ||
181 | |||
182 | /* if we failed, all future posted messages fail until reset */ | ||
183 | if (!countdown) | ||
184 | mbx->timeout = 0; | ||
185 | out: | ||
186 | return countdown ? 0 : -E1000_ERR_MBX; | ||
187 | } | ||
188 | |||
189 | /** | ||
190 | * igb_read_posted_mbx - Wait for message notification and receive message | ||
191 | * @hw: pointer to the HW structure | ||
192 | * @msg: The message buffer | ||
193 | * @size: Length of buffer | ||
194 | * @mbx_id: id of mailbox to write | ||
195 | * | ||
196 | * returns SUCCESS if it successfully received a message notification and | ||
197 | * copied it into the receive buffer. | ||
198 | **/ | ||
199 | static s32 igb_read_posted_mbx(struct e1000_hw *hw, u32 *msg, u16 size, u16 mbx_id) | ||
200 | { | ||
201 | struct e1000_mbx_info *mbx = &hw->mbx; | ||
202 | s32 ret_val = -E1000_ERR_MBX; | ||
203 | |||
204 | if (!mbx->ops.read) | ||
205 | goto out; | ||
206 | |||
207 | ret_val = igb_poll_for_msg(hw, mbx_id); | ||
208 | |||
209 | if (!ret_val) | ||
210 | ret_val = mbx->ops.read(hw, msg, size, mbx_id); | ||
211 | out: | ||
212 | return ret_val; | ||
213 | } | ||
214 | |||
215 | /** | ||
216 | * igb_write_posted_mbx - Write a message to the mailbox, wait for ack | ||
217 | * @hw: pointer to the HW structure | ||
218 | * @msg: The message buffer | ||
219 | * @size: Length of buffer | ||
220 | * @mbx_id: id of mailbox to write | ||
221 | * | ||
222 | * returns SUCCESS if it successfully copied message into the buffer and | ||
223 | * received an ack to that message within delay * timeout period | ||
224 | **/ | ||
225 | static s32 igb_write_posted_mbx(struct e1000_hw *hw, u32 *msg, u16 size, u16 mbx_id) | ||
226 | { | ||
227 | struct e1000_mbx_info *mbx = &hw->mbx; | ||
228 | s32 ret_val = -E1000_ERR_MBX; | ||
229 | |||
230 | /* exit if either we can't write or there isn't a defined timeout */ | ||
231 | if (!mbx->ops.write || !mbx->timeout) | ||
232 | goto out; | ||
233 | |||
234 | /* send msg */ | ||
235 | ret_val = mbx->ops.write(hw, msg, size, mbx_id); | ||
236 | |||
237 | /* if msg sent wait until we receive an ack */ | ||
238 | if (!ret_val) | ||
239 | ret_val = igb_poll_for_ack(hw, mbx_id); | ||
240 | out: | ||
241 | return ret_val; | ||
242 | } | ||
243 | |||
244 | static s32 igb_check_for_bit_pf(struct e1000_hw *hw, u32 mask) | ||
245 | { | ||
246 | u32 mbvficr = rd32(E1000_MBVFICR); | ||
247 | s32 ret_val = -E1000_ERR_MBX; | ||
248 | |||
249 | if (mbvficr & mask) { | ||
250 | ret_val = 0; | ||
251 | wr32(E1000_MBVFICR, mask); | ||
252 | } | ||
253 | |||
254 | return ret_val; | ||
255 | } | ||
256 | |||
257 | /** | ||
258 | * igb_check_for_msg_pf - checks to see if the VF has sent mail | ||
259 | * @hw: pointer to the HW structure | ||
260 | * @vf_number: the VF index | ||
261 | * | ||
262 | * returns SUCCESS if the VF has set the Status bit or else ERR_MBX | ||
263 | **/ | ||
264 | static s32 igb_check_for_msg_pf(struct e1000_hw *hw, u16 vf_number) | ||
265 | { | ||
266 | s32 ret_val = -E1000_ERR_MBX; | ||
267 | |||
268 | if (!igb_check_for_bit_pf(hw, E1000_MBVFICR_VFREQ_VF1 << vf_number)) { | ||
269 | ret_val = 0; | ||
270 | hw->mbx.stats.reqs++; | ||
271 | } | ||
272 | |||
273 | return ret_val; | ||
274 | } | ||
275 | |||
276 | /** | ||
277 | * igb_check_for_ack_pf - checks to see if the VF has ACKed | ||
278 | * @hw: pointer to the HW structure | ||
279 | * @vf_number: the VF index | ||
280 | * | ||
281 | * returns SUCCESS if the VF has set the Status bit or else ERR_MBX | ||
282 | **/ | ||
283 | static s32 igb_check_for_ack_pf(struct e1000_hw *hw, u16 vf_number) | ||
284 | { | ||
285 | s32 ret_val = -E1000_ERR_MBX; | ||
286 | |||
287 | if (!igb_check_for_bit_pf(hw, E1000_MBVFICR_VFACK_VF1 << vf_number)) { | ||
288 | ret_val = 0; | ||
289 | hw->mbx.stats.acks++; | ||
290 | } | ||
291 | |||
292 | return ret_val; | ||
293 | } | ||
294 | |||
295 | /** | ||
296 | * igb_check_for_rst_pf - checks to see if the VF has reset | ||
297 | * @hw: pointer to the HW structure | ||
298 | * @vf_number: the VF index | ||
299 | * | ||
300 | * returns SUCCESS if the VF has set the Status bit or else ERR_MBX | ||
301 | **/ | ||
302 | static s32 igb_check_for_rst_pf(struct e1000_hw *hw, u16 vf_number) | ||
303 | { | ||
304 | u32 vflre = rd32(E1000_VFLRE); | ||
305 | s32 ret_val = -E1000_ERR_MBX; | ||
306 | |||
307 | if (vflre & (1 << vf_number)) { | ||
308 | ret_val = 0; | ||
309 | wr32(E1000_VFLRE, (1 << vf_number)); | ||
310 | hw->mbx.stats.rsts++; | ||
311 | } | ||
312 | |||
313 | return ret_val; | ||
314 | } | ||
315 | |||
316 | /** | ||
317 | * igb_obtain_mbx_lock_pf - obtain mailbox lock | ||
318 | * @hw: pointer to the HW structure | ||
319 | * @vf_number: the VF index | ||
320 | * | ||
321 | * return SUCCESS if we obtained the mailbox lock | ||
322 | **/ | ||
323 | static s32 igb_obtain_mbx_lock_pf(struct e1000_hw *hw, u16 vf_number) | ||
324 | { | ||
325 | s32 ret_val = -E1000_ERR_MBX; | ||
326 | u32 p2v_mailbox; | ||
327 | |||
328 | |||
329 | /* Take ownership of the buffer */ | ||
330 | wr32(E1000_P2VMAILBOX(vf_number), E1000_P2VMAILBOX_PFU); | ||
331 | |||
332 | /* reserve mailbox for vf use */ | ||
333 | p2v_mailbox = rd32(E1000_P2VMAILBOX(vf_number)); | ||
334 | if (p2v_mailbox & E1000_P2VMAILBOX_PFU) | ||
335 | ret_val = 0; | ||
336 | |||
337 | return ret_val; | ||
338 | } | ||
339 | |||
340 | /** | ||
341 | * igb_write_mbx_pf - Places a message in the mailbox | ||
342 | * @hw: pointer to the HW structure | ||
343 | * @msg: The message buffer | ||
344 | * @size: Length of buffer | ||
345 | * @vf_number: the VF index | ||
346 | * | ||
347 | * returns SUCCESS if it successfully copied message into the buffer | ||
348 | **/ | ||
349 | static s32 igb_write_mbx_pf(struct e1000_hw *hw, u32 *msg, u16 size, | ||
350 | u16 vf_number) | ||
351 | { | ||
352 | s32 ret_val; | ||
353 | u16 i; | ||
354 | |||
355 | /* lock the mailbox to prevent pf/vf race condition */ | ||
356 | ret_val = igb_obtain_mbx_lock_pf(hw, vf_number); | ||
357 | if (ret_val) | ||
358 | goto out_no_write; | ||
359 | |||
360 | /* flush msg and acks as we are overwriting the message buffer */ | ||
361 | igb_check_for_msg_pf(hw, vf_number); | ||
362 | igb_check_for_ack_pf(hw, vf_number); | ||
363 | |||
364 | /* copy the caller specified message to the mailbox memory buffer */ | ||
365 | for (i = 0; i < size; i++) | ||
366 | array_wr32(E1000_VMBMEM(vf_number), i, msg[i]); | ||
367 | |||
368 | /* Interrupt VF to tell it a message has been sent and release buffer*/ | ||
369 | wr32(E1000_P2VMAILBOX(vf_number), E1000_P2VMAILBOX_STS); | ||
370 | |||
371 | /* update stats */ | ||
372 | hw->mbx.stats.msgs_tx++; | ||
373 | |||
374 | out_no_write: | ||
375 | return ret_val; | ||
376 | |||
377 | } | ||
378 | |||
379 | /** | ||
380 | * igb_read_mbx_pf - Read a message from the mailbox | ||
381 | * @hw: pointer to the HW structure | ||
382 | * @msg: The message buffer | ||
383 | * @size: Length of buffer | ||
384 | * @vf_number: the VF index | ||
385 | * | ||
386 | * This function copies a message from the mailbox buffer to the caller's | ||
387 | * memory buffer. The presumption is that the caller knows that there was | ||
388 | * a message due to a VF request so no polling for message is needed. | ||
389 | **/ | ||
390 | static s32 igb_read_mbx_pf(struct e1000_hw *hw, u32 *msg, u16 size, | ||
391 | u16 vf_number) | ||
392 | { | ||
393 | s32 ret_val; | ||
394 | u16 i; | ||
395 | |||
396 | /* lock the mailbox to prevent pf/vf race condition */ | ||
397 | ret_val = igb_obtain_mbx_lock_pf(hw, vf_number); | ||
398 | if (ret_val) | ||
399 | goto out_no_read; | ||
400 | |||
401 | /* copy the message to the mailbox memory buffer */ | ||
402 | for (i = 0; i < size; i++) | ||
403 | msg[i] = array_rd32(E1000_VMBMEM(vf_number), i); | ||
404 | |||
405 | /* Acknowledge the message and release buffer */ | ||
406 | wr32(E1000_P2VMAILBOX(vf_number), E1000_P2VMAILBOX_ACK); | ||
407 | |||
408 | /* update stats */ | ||
409 | hw->mbx.stats.msgs_rx++; | ||
410 | |||
411 | out_no_read: | ||
412 | return ret_val; | ||
413 | } | ||
414 | |||
415 | /** | ||
416 | * e1000_init_mbx_params_pf - set initial values for pf mailbox | ||
417 | * @hw: pointer to the HW structure | ||
418 | * | ||
419 | * Initializes the hw->mbx struct to correct values for pf mailbox | ||
420 | */ | ||
421 | s32 igb_init_mbx_params_pf(struct e1000_hw *hw) | ||
422 | { | ||
423 | struct e1000_mbx_info *mbx = &hw->mbx; | ||
424 | |||
425 | mbx->timeout = 0; | ||
426 | mbx->usec_delay = 0; | ||
427 | |||
428 | mbx->size = E1000_VFMAILBOX_SIZE; | ||
429 | |||
430 | mbx->ops.read = igb_read_mbx_pf; | ||
431 | mbx->ops.write = igb_write_mbx_pf; | ||
432 | mbx->ops.read_posted = igb_read_posted_mbx; | ||
433 | mbx->ops.write_posted = igb_write_posted_mbx; | ||
434 | mbx->ops.check_for_msg = igb_check_for_msg_pf; | ||
435 | mbx->ops.check_for_ack = igb_check_for_ack_pf; | ||
436 | mbx->ops.check_for_rst = igb_check_for_rst_pf; | ||
437 | |||
438 | mbx->stats.msgs_tx = 0; | ||
439 | mbx->stats.msgs_rx = 0; | ||
440 | mbx->stats.reqs = 0; | ||
441 | mbx->stats.acks = 0; | ||
442 | mbx->stats.rsts = 0; | ||
443 | |||
444 | return 0; | ||
445 | } | ||
446 | |||