Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2013 - 2015 Intel Corporation
3 : : */
4 : :
5 : : #include "fm10k_common.h"
6 : :
7 : : /**
8 : : * fm10k_fifo_init - Initialize a message FIFO
9 : : * @fifo: pointer to FIFO
10 : : * @buffer: pointer to memory to be used to store FIFO
11 : : * @size: maximum message size to store in FIFO, must be 2^n - 1
12 : : **/
13 : : STATIC void fm10k_fifo_init(struct fm10k_mbx_fifo *fifo, u32 *buffer, u16 size)
14 : : {
15 : 0 : fifo->buffer = buffer;
16 : 0 : fifo->size = size;
17 : 0 : fifo->head = 0;
18 : 0 : fifo->tail = 0;
19 : : }
20 : :
21 : : /**
22 : : * fm10k_fifo_used - Retrieve used space in FIFO
23 : : * @fifo: pointer to FIFO
24 : : *
25 : : * This function returns the number of DWORDs used in the FIFO
26 : : **/
27 : : STATIC u16 fm10k_fifo_used(struct fm10k_mbx_fifo *fifo)
28 : : {
29 : 0 : return fifo->tail - fifo->head;
30 : : }
31 : :
32 : : /**
33 : : * fm10k_fifo_unused - Retrieve unused space in FIFO
34 : : * @fifo: pointer to FIFO
35 : : *
36 : : * This function returns the number of unused DWORDs in the FIFO
37 : : **/
38 : : STATIC u16 fm10k_fifo_unused(struct fm10k_mbx_fifo *fifo)
39 : : {
40 : 0 : return fifo->size + fifo->head - fifo->tail;
41 : : }
42 : :
43 : : /**
44 : : * fm10k_fifo_empty - Test to verify if FIFO is empty
45 : : * @fifo: pointer to FIFO
46 : : *
47 : : * This function returns true if the FIFO is empty, else false
48 : : **/
49 : : STATIC bool fm10k_fifo_empty(struct fm10k_mbx_fifo *fifo)
50 : : {
51 : 0 : return fifo->head == fifo->tail;
52 : : }
53 : :
54 : : /**
55 : : * fm10k_fifo_head_offset - returns indices of head with given offset
56 : : * @fifo: pointer to FIFO
57 : : * @offset: offset to add to head
58 : : *
59 : : * This function returns the indices into the FIFO based on head + offset
60 : : **/
61 : : STATIC u16 fm10k_fifo_head_offset(struct fm10k_mbx_fifo *fifo, u16 offset)
62 : : {
63 : 0 : return (fifo->head + offset) & (fifo->size - 1);
64 : : }
65 : :
66 : : /**
67 : : * fm10k_fifo_tail_offset - returns indices of tail with given offset
68 : : * @fifo: pointer to FIFO
69 : : * @offset: offset to add to tail
70 : : *
71 : : * This function returns the indices into the FIFO based on tail + offset
72 : : **/
73 : : STATIC u16 fm10k_fifo_tail_offset(struct fm10k_mbx_fifo *fifo, u16 offset)
74 : : {
75 : 0 : return (fifo->tail + offset) & (fifo->size - 1);
76 : : }
77 : :
78 : : /**
79 : : * fm10k_fifo_head_len - Retrieve length of first message in FIFO
80 : : * @fifo: pointer to FIFO
81 : : *
82 : : * This function returns the size of the first message in the FIFO
83 : : **/
84 : : STATIC u16 fm10k_fifo_head_len(struct fm10k_mbx_fifo *fifo)
85 : : {
86 : 0 : u32 *head = fifo->buffer + fm10k_fifo_head_offset(fifo, 0);
87 : :
88 : : /* verify there is at least 1 DWORD in the fifo so *head is valid */
89 [ # # # # : 0 : if (fm10k_fifo_empty(fifo))
# # # # ]
90 : : return 0;
91 : :
92 : : /* retieve the message length */
93 : 0 : return FM10K_TLV_DWORD_LEN(*head);
94 : : }
95 : :
96 : : /**
97 : : * fm10k_fifo_head_drop - Drop the first message in FIFO
98 : : * @fifo: pointer to FIFO
99 : : *
100 : : * This function returns the size of the message dropped from the FIFO
101 : : **/
102 : : STATIC u16 fm10k_fifo_head_drop(struct fm10k_mbx_fifo *fifo)
103 : : {
104 : : u16 len = fm10k_fifo_head_len(fifo);
105 : :
106 : : /* update head so it is at the start of next frame */
107 : 0 : fifo->head += len;
108 : :
109 : : return len;
110 : : }
111 : :
112 : : /**
113 : : * fm10k_fifo_drop_all - Drop all messages in FIFO
114 : : * @fifo: pointer to FIFO
115 : : *
116 : : * This function resets the head pointer to drop all messages in the FIFO and
117 : : * ensure the FIFO is empty.
118 : : **/
119 : : STATIC void fm10k_fifo_drop_all(struct fm10k_mbx_fifo *fifo)
120 : : {
121 : 0 : fifo->head = fifo->tail;
122 : : }
123 : :
124 : : /**
125 : : * fm10k_mbx_index_len - Convert a head/tail index into a length value
126 : : * @mbx: pointer to mailbox
127 : : * @head: head index
128 : : * @tail: head index
129 : : *
130 : : * This function takes the head and tail index and determines the length
131 : : * of the data indicated by this pair.
132 : : **/
133 : : STATIC u16 fm10k_mbx_index_len(struct fm10k_mbx_info *mbx, u16 head, u16 tail)
134 : : {
135 : 0 : u16 len = tail - head;
136 : :
137 : : /* we wrapped so subtract 2, one for index 0, one for all 1s index */
138 [ # # # # ]: 0 : if (len > tail)
139 : 0 : len -= 2;
140 : :
141 : 0 : return len & ((mbx->mbmem_len << 1) - 1);
142 : : }
143 : :
144 : : /**
145 : : * fm10k_mbx_tail_add - Determine new tail value with added offset
146 : : * @mbx: pointer to mailbox
147 : : * @offset: length to add to tail offset
148 : : *
149 : : * This function takes the local tail index and recomputes it for
150 : : * a given length added as an offset.
151 : : **/
152 : : STATIC u16 fm10k_mbx_tail_add(struct fm10k_mbx_info *mbx, u16 offset)
153 : : {
154 : 0 : u16 tail = (mbx->tail + offset + 1) & ((mbx->mbmem_len << 1) - 1);
155 : :
156 : : /* add/sub 1 because we cannot have offset 0 or all 1s */
157 : 0 : return (tail > mbx->tail) ? --tail : ++tail;
158 : : }
159 : :
160 : : /**
161 : : * fm10k_mbx_tail_sub - Determine new tail value with subtracted offset
162 : : * @mbx: pointer to mailbox
163 : : * @offset: length to add to tail offset
164 : : *
165 : : * This function takes the local tail index and recomputes it for
166 : : * a given length added as an offset.
167 : : **/
168 : : STATIC u16 fm10k_mbx_tail_sub(struct fm10k_mbx_info *mbx, u16 offset)
169 : : {
170 : 0 : u16 tail = (mbx->tail - offset - 1) & ((mbx->mbmem_len << 1) - 1);
171 : :
172 : : /* sub/add 1 because we cannot have offset 0 or all 1s */
173 [ # # ]: 0 : return (tail < mbx->tail) ? ++tail : --tail;
174 : : }
175 : :
176 : : /**
177 : : * fm10k_mbx_head_add - Determine new head value with added offset
178 : : * @mbx: pointer to mailbox
179 : : * @offset: length to add to head offset
180 : : *
181 : : * This function takes the local head index and recomputes it for
182 : : * a given length added as an offset.
183 : : **/
184 : : STATIC u16 fm10k_mbx_head_add(struct fm10k_mbx_info *mbx, u16 offset)
185 : : {
186 : 0 : u16 head = (mbx->head + offset + 1) & ((mbx->mbmem_len << 1) - 1);
187 : :
188 : : /* add/sub 1 because we cannot have offset 0 or all 1s */
189 : 0 : return (head > mbx->head) ? --head : ++head;
190 : : }
191 : :
192 : : /**
193 : : * fm10k_mbx_head_sub - Determine new head value with subtracted offset
194 : : * @mbx: pointer to mailbox
195 : : * @offset: length to add to head offset
196 : : *
197 : : * This function takes the local head index and recomputes it for
198 : : * a given length added as an offset.
199 : : **/
200 : : STATIC u16 fm10k_mbx_head_sub(struct fm10k_mbx_info *mbx, u16 offset)
201 : : {
202 : 0 : u16 head = (mbx->head - offset - 1) & ((mbx->mbmem_len << 1) - 1);
203 : :
204 : : /* sub/add 1 because we cannot have offset 0 or all 1s */
205 : 0 : return (head < mbx->head) ? ++head : --head;
206 : : }
207 : :
208 : : /**
209 : : * fm10k_mbx_pushed_tail_len - Retrieve the length of message being pushed
210 : : * @mbx: pointer to mailbox
211 : : *
212 : : * This function will return the length of the message currently being
213 : : * pushed onto the tail of the Rx queue.
214 : : **/
215 : : STATIC u16 fm10k_mbx_pushed_tail_len(struct fm10k_mbx_info *mbx)
216 : : {
217 : 0 : u32 *tail = mbx->rx.buffer + fm10k_fifo_tail_offset(&mbx->rx, 0);
218 : :
219 : : /* pushed tail is only valid if pushed is set */
220 : 0 : if (!mbx->pushed)
221 : : return 0;
222 : :
223 : 0 : return FM10K_TLV_DWORD_LEN(*tail);
224 : : }
225 : :
226 : : /**
227 : : * fm10k_fifo_write_copy - pulls data off of msg and places it in FIFO
228 : : * @fifo: pointer to FIFO
229 : : * @msg: message array to populate
230 : : * @tail_offset: additional offset to add to tail pointer
231 : : * @len: length of FIFO to copy into message header
232 : : *
233 : : * This function will take a message and copy it into a section of the
234 : : * FIFO. In order to get something into a location other than just
235 : : * the tail you can use tail_offset to adjust the pointer.
236 : : **/
237 : 0 : STATIC void fm10k_fifo_write_copy(struct fm10k_mbx_fifo *fifo,
238 : : const u32 *msg, u16 tail_offset, u16 len)
239 : : {
240 : : u16 end = fm10k_fifo_tail_offset(fifo, tail_offset);
241 : 0 : u32 *tail = fifo->buffer + end;
242 : :
243 : : /* track when we should cross the end of the FIFO */
244 : 0 : end = fifo->size - end;
245 : :
246 : : /* copy end of message before start of message */
247 [ # # ]: 0 : if (end < len)
248 : 0 : memcpy(fifo->buffer, msg + end, (len - end) << 2);
249 : : else
250 : : end = len;
251 : :
252 : : /* Copy remaining message into Tx FIFO */
253 : 0 : memcpy(tail, msg, end << 2);
254 : 0 : }
255 : :
256 : : /**
257 : : * fm10k_fifo_enqueue - Enqueues the message to the tail of the FIFO
258 : : * @fifo: pointer to FIFO
259 : : * @msg: message array to read
260 : : *
261 : : * This function enqueues a message up to the size specified by the length
262 : : * contained in the first DWORD of the message and will place at the tail
263 : : * of the FIFO. It will return 0 on success, or a negative value on error.
264 : : **/
265 : 0 : STATIC s32 fm10k_fifo_enqueue(struct fm10k_mbx_fifo *fifo, const u32 *msg)
266 : : {
267 : 0 : u16 len = FM10K_TLV_DWORD_LEN(*msg);
268 : :
269 : 0 : DEBUGFUNC("fm10k_fifo_enqueue");
270 : :
271 : : /* verify parameters */
272 [ # # ]: 0 : if (len > fifo->size)
273 : : return FM10K_MBX_ERR_SIZE;
274 : :
275 : : /* verify there is room for the message */
276 [ # # ]: 0 : if (len > fm10k_fifo_unused(fifo))
277 : : return FM10K_MBX_ERR_NO_SPACE;
278 : :
279 : : /* Copy message into FIFO */
280 : 0 : fm10k_fifo_write_copy(fifo, msg, 0, len);
281 : :
282 : : /* memory barrier to guarantee FIFO is written before tail update */
283 : : FM10K_WMB();
284 : :
285 : : /* Update Tx FIFO tail */
286 : 0 : fifo->tail += len;
287 : :
288 : 0 : return FM10K_SUCCESS;
289 : : }
290 : :
291 : : /**
292 : : * fm10k_mbx_validate_msg_size - Validate incoming message based on size
293 : : * @mbx: pointer to mailbox
294 : : * @len: length of data pushed onto buffer
295 : : *
296 : : * This function analyzes the frame and will return a non-zero value when
297 : : * the start of a message larger than the mailbox is detected.
298 : : **/
299 : 0 : STATIC u16 fm10k_mbx_validate_msg_size(struct fm10k_mbx_info *mbx, u16 len)
300 : : {
301 : : struct fm10k_mbx_fifo *fifo = &mbx->rx;
302 : : u16 total_len = 0, msg_len;
303 : : u32 *msg;
304 : :
305 : 0 : DEBUGFUNC("fm10k_mbx_validate_msg_size");
306 : :
307 : : /* length should include previous amounts pushed */
308 : 0 : len += mbx->pushed;
309 : :
310 : : /* offset in message is based off of current message size */
311 : : do {
312 : 0 : msg = fifo->buffer + fm10k_fifo_tail_offset(fifo, total_len);
313 : 0 : msg_len = FM10K_TLV_DWORD_LEN(*msg);
314 : 0 : total_len += msg_len;
315 [ # # ]: 0 : } while (total_len < len);
316 : :
317 : : /* message extends out of pushed section, but fits in FIFO */
318 [ # # # # ]: 0 : if ((len < total_len) && (msg_len <= mbx->max_size))
319 : : return 0;
320 : :
321 : : /* return length of invalid section */
322 [ # # ]: 0 : return (len < total_len) ? len : (len - total_len);
323 : : }
324 : :
325 : : /**
326 : : * fm10k_mbx_write_copy - pulls data off of Tx FIFO and places it in mbmem
327 : : * @hw: pointer to hardware structure
328 : : * @mbx: pointer to mailbox
329 : : *
330 : : * This function will take a section of the Tx FIFO and copy it into the
331 : : * mailbox memory. The offset in mbmem is based on the lower bits of the
332 : : * tail and len determines the length to copy.
333 : : **/
334 : 0 : STATIC void fm10k_mbx_write_copy(struct fm10k_hw *hw,
335 : : struct fm10k_mbx_info *mbx)
336 : : {
337 : : struct fm10k_mbx_fifo *fifo = &mbx->tx;
338 : 0 : u32 mbmem = mbx->mbmem_reg;
339 : 0 : u32 *head = fifo->buffer;
340 : : u16 end, len, tail, mask;
341 : :
342 : 0 : DEBUGFUNC("fm10k_mbx_write_copy");
343 : :
344 [ # # ]: 0 : if (!mbx->tail_len)
345 : : return;
346 : :
347 : : /* determine data length and mbmem tail index */
348 [ # # ]: 0 : mask = mbx->mbmem_len - 1;
349 : : len = mbx->tail_len;
350 : : tail = fm10k_mbx_tail_sub(mbx, len);
351 [ # # ]: 0 : if (tail > mask)
352 : 0 : tail++;
353 : :
354 : : /* determine offset in the ring */
355 : 0 : end = fm10k_fifo_head_offset(fifo, mbx->pulled);
356 : 0 : head += end;
357 : :
358 : : /* memory barrier to guarantee data is ready to be read */
359 : : FM10K_RMB();
360 : :
361 : : /* Copy message from Tx FIFO */
362 [ # # ]: 0 : for (end = fifo->size - end; len; head = fifo->buffer) {
363 : : do {
364 : : /* adjust tail to match offset for FIFO */
365 : 0 : tail &= mask;
366 : : if (!tail)
367 : : tail++;
368 : :
369 : 0 : mbx->tx_mbmem_pulled++;
370 : :
371 : : /* write message to hardware FIFO */
372 : 0 : FM10K_WRITE_MBX(hw, mbmem + tail++, *(head++));
373 [ # # # # ]: 0 : } while (--len && --end);
374 : : }
375 : : }
376 : :
377 : : /**
378 : : * fm10k_mbx_pull_head - Pulls data off of head of Tx FIFO
379 : : * @hw: pointer to hardware structure
380 : : * @mbx: pointer to mailbox
381 : : * @head: acknowledgement number last received
382 : : *
383 : : * This function will push the tail index forward based on the remote
384 : : * head index. It will then pull up to mbmem_len DWORDs off of the
385 : : * head of the FIFO and will place it in the MBMEM registers
386 : : * associated with the mailbox.
387 : : **/
388 : 0 : STATIC void fm10k_mbx_pull_head(struct fm10k_hw *hw,
389 : : struct fm10k_mbx_info *mbx, u16 head)
390 : : {
391 [ # # ]: 0 : u16 mbmem_len, len, ack = fm10k_mbx_index_len(mbx, head, mbx->tail);
392 : : struct fm10k_mbx_fifo *fifo = &mbx->tx;
393 : :
394 : : /* update number of bytes pulled and update bytes in transit */
395 : 0 : mbx->pulled += mbx->tail_len - ack;
396 : :
397 : : /* determine length of data to pull, reserve space for mbmem header */
398 : 0 : mbmem_len = mbx->mbmem_len - 1;
399 : 0 : len = fm10k_fifo_used(fifo) - mbx->pulled;
400 : : if (len > mbmem_len)
401 : : len = mbmem_len;
402 : :
403 : : /* update tail and record number of bytes in transit */
404 [ # # ]: 0 : mbx->tail = fm10k_mbx_tail_add(mbx, len - ack);
405 [ # # ]: 0 : mbx->tail_len = len;
406 : :
407 : : /* drop pulled messages from the FIFO */
408 : : for (len = fm10k_fifo_head_len(fifo);
409 [ # # # # ]: 0 : len && (mbx->pulled >= len);
410 : : len = fm10k_fifo_head_len(fifo)) {
411 : 0 : mbx->pulled -= fm10k_fifo_head_drop(fifo);
412 : 0 : mbx->tx_messages++;
413 [ # # ]: 0 : mbx->tx_dwords += len;
414 : : }
415 : :
416 : : /* Copy message out from the Tx FIFO */
417 : 0 : fm10k_mbx_write_copy(hw, mbx);
418 : 0 : }
419 : :
420 : : /**
421 : : * fm10k_mbx_read_copy - pulls data off of mbmem and places it in Rx FIFO
422 : : * @hw: pointer to hardware structure
423 : : * @mbx: pointer to mailbox
424 : : *
425 : : * This function will take a section of the mailbox memory and copy it
426 : : * into the Rx FIFO. The offset is based on the lower bits of the
427 : : * head and len determines the length to copy.
428 : : **/
429 : 0 : STATIC void fm10k_mbx_read_copy(struct fm10k_hw *hw,
430 : : struct fm10k_mbx_info *mbx)
431 : : {
432 : : struct fm10k_mbx_fifo *fifo = &mbx->rx;
433 : 0 : u32 mbmem = mbx->mbmem_reg ^ mbx->mbmem_len;
434 : 0 : u32 *tail = fifo->buffer;
435 : : u16 end, len, head;
436 : :
437 : 0 : DEBUGFUNC("fm10k_mbx_read_copy");
438 : :
439 : : /* determine data length and mbmem head index */
440 [ # # ]: 0 : len = mbx->head_len;
441 : : head = fm10k_mbx_head_sub(mbx, len);
442 [ # # ]: 0 : if (head >= mbx->mbmem_len)
443 : 0 : head++;
444 : :
445 : : /* determine offset in the ring */
446 : 0 : end = fm10k_fifo_tail_offset(fifo, mbx->pushed);
447 : 0 : tail += end;
448 : :
449 : : /* Copy message into Rx FIFO */
450 [ # # ]: 0 : for (end = fifo->size - end; len; tail = fifo->buffer) {
451 : : do {
452 : : /* adjust head to match offset for FIFO */
453 : 0 : head &= mbx->mbmem_len - 1;
454 : : if (!head)
455 : : head++;
456 : :
457 : 0 : mbx->rx_mbmem_pushed++;
458 : :
459 : : /* read message from hardware FIFO */
460 : 0 : *(tail++) = FM10K_READ_MBX(hw, mbmem + head++);
461 [ # # # # ]: 0 : } while (--len && --end);
462 : : }
463 : :
464 : : /* memory barrier to guarantee FIFO is written before tail update */
465 : : FM10K_WMB();
466 : 0 : }
467 : :
468 : : /**
469 : : * fm10k_mbx_push_tail - Pushes up to 15 DWORDs on to tail of FIFO
470 : : * @hw: pointer to hardware structure
471 : : * @mbx: pointer to mailbox
472 : : * @tail: tail index of message
473 : : *
474 : : * This function will first validate the tail index and size for the
475 : : * incoming message. It then updates the acknowledgment number and
476 : : * copies the data into the FIFO. It will return the number of messages
477 : : * dequeued on success and a negative value on error.
478 : : **/
479 : 0 : STATIC s32 fm10k_mbx_push_tail(struct fm10k_hw *hw,
480 : : struct fm10k_mbx_info *mbx,
481 : : u16 tail)
482 : : {
483 : : struct fm10k_mbx_fifo *fifo = &mbx->rx;
484 [ # # ]: 0 : u16 len, seq = fm10k_mbx_index_len(mbx, mbx->head, tail);
485 : :
486 : 0 : DEBUGFUNC("fm10k_mbx_push_tail");
487 : :
488 : : /* determine length of data to push */
489 : 0 : len = fm10k_fifo_unused(fifo) - mbx->pushed;
490 : : if (len > seq)
491 : : len = seq;
492 : :
493 : : /* update head and record bytes received */
494 [ # # ]: 0 : mbx->head = fm10k_mbx_head_add(mbx, len);
495 : 0 : mbx->head_len = len;
496 : :
497 : : /* nothing to do if there is no data */
498 [ # # ]: 0 : if (!len)
499 : : return FM10K_SUCCESS;
500 : :
501 : : /* Copy msg into Rx FIFO */
502 : 0 : fm10k_mbx_read_copy(hw, mbx);
503 : :
504 : : /* determine if there are any invalid lengths in message */
505 [ # # ]: 0 : if (fm10k_mbx_validate_msg_size(mbx, len))
506 : : return FM10K_MBX_ERR_SIZE;
507 : :
508 : : /* Update pushed */
509 [ # # ]: 0 : mbx->pushed += len;
510 : :
511 : : /* flush any completed messages */
512 : : for (len = fm10k_mbx_pushed_tail_len(mbx);
513 [ # # # # ]: 0 : len && (mbx->pushed >= len);
514 : : len = fm10k_mbx_pushed_tail_len(mbx)) {
515 : 0 : fifo->tail += len;
516 : 0 : mbx->pushed -= len;
517 : 0 : mbx->rx_messages++;
518 [ # # ]: 0 : mbx->rx_dwords += len;
519 : : }
520 : :
521 : : return FM10K_SUCCESS;
522 : : }
523 : :
524 : : /* pre-generated data for generating the CRC based on the poly 0xAC9A. */
525 : : static const u16 fm10k_crc_16b_table[256] = {
526 : : 0x0000, 0x7956, 0xF2AC, 0x8BFA, 0xBC6D, 0xC53B, 0x4EC1, 0x3797,
527 : : 0x21EF, 0x58B9, 0xD343, 0xAA15, 0x9D82, 0xE4D4, 0x6F2E, 0x1678,
528 : : 0x43DE, 0x3A88, 0xB172, 0xC824, 0xFFB3, 0x86E5, 0x0D1F, 0x7449,
529 : : 0x6231, 0x1B67, 0x909D, 0xE9CB, 0xDE5C, 0xA70A, 0x2CF0, 0x55A6,
530 : : 0x87BC, 0xFEEA, 0x7510, 0x0C46, 0x3BD1, 0x4287, 0xC97D, 0xB02B,
531 : : 0xA653, 0xDF05, 0x54FF, 0x2DA9, 0x1A3E, 0x6368, 0xE892, 0x91C4,
532 : : 0xC462, 0xBD34, 0x36CE, 0x4F98, 0x780F, 0x0159, 0x8AA3, 0xF3F5,
533 : : 0xE58D, 0x9CDB, 0x1721, 0x6E77, 0x59E0, 0x20B6, 0xAB4C, 0xD21A,
534 : : 0x564D, 0x2F1B, 0xA4E1, 0xDDB7, 0xEA20, 0x9376, 0x188C, 0x61DA,
535 : : 0x77A2, 0x0EF4, 0x850E, 0xFC58, 0xCBCF, 0xB299, 0x3963, 0x4035,
536 : : 0x1593, 0x6CC5, 0xE73F, 0x9E69, 0xA9FE, 0xD0A8, 0x5B52, 0x2204,
537 : : 0x347C, 0x4D2A, 0xC6D0, 0xBF86, 0x8811, 0xF147, 0x7ABD, 0x03EB,
538 : : 0xD1F1, 0xA8A7, 0x235D, 0x5A0B, 0x6D9C, 0x14CA, 0x9F30, 0xE666,
539 : : 0xF01E, 0x8948, 0x02B2, 0x7BE4, 0x4C73, 0x3525, 0xBEDF, 0xC789,
540 : : 0x922F, 0xEB79, 0x6083, 0x19D5, 0x2E42, 0x5714, 0xDCEE, 0xA5B8,
541 : : 0xB3C0, 0xCA96, 0x416C, 0x383A, 0x0FAD, 0x76FB, 0xFD01, 0x8457,
542 : : 0xAC9A, 0xD5CC, 0x5E36, 0x2760, 0x10F7, 0x69A1, 0xE25B, 0x9B0D,
543 : : 0x8D75, 0xF423, 0x7FD9, 0x068F, 0x3118, 0x484E, 0xC3B4, 0xBAE2,
544 : : 0xEF44, 0x9612, 0x1DE8, 0x64BE, 0x5329, 0x2A7F, 0xA185, 0xD8D3,
545 : : 0xCEAB, 0xB7FD, 0x3C07, 0x4551, 0x72C6, 0x0B90, 0x806A, 0xF93C,
546 : : 0x2B26, 0x5270, 0xD98A, 0xA0DC, 0x974B, 0xEE1D, 0x65E7, 0x1CB1,
547 : : 0x0AC9, 0x739F, 0xF865, 0x8133, 0xB6A4, 0xCFF2, 0x4408, 0x3D5E,
548 : : 0x68F8, 0x11AE, 0x9A54, 0xE302, 0xD495, 0xADC3, 0x2639, 0x5F6F,
549 : : 0x4917, 0x3041, 0xBBBB, 0xC2ED, 0xF57A, 0x8C2C, 0x07D6, 0x7E80,
550 : : 0xFAD7, 0x8381, 0x087B, 0x712D, 0x46BA, 0x3FEC, 0xB416, 0xCD40,
551 : : 0xDB38, 0xA26E, 0x2994, 0x50C2, 0x6755, 0x1E03, 0x95F9, 0xECAF,
552 : : 0xB909, 0xC05F, 0x4BA5, 0x32F3, 0x0564, 0x7C32, 0xF7C8, 0x8E9E,
553 : : 0x98E6, 0xE1B0, 0x6A4A, 0x131C, 0x248B, 0x5DDD, 0xD627, 0xAF71,
554 : : 0x7D6B, 0x043D, 0x8FC7, 0xF691, 0xC106, 0xB850, 0x33AA, 0x4AFC,
555 : : 0x5C84, 0x25D2, 0xAE28, 0xD77E, 0xE0E9, 0x99BF, 0x1245, 0x6B13,
556 : : 0x3EB5, 0x47E3, 0xCC19, 0xB54F, 0x82D8, 0xFB8E, 0x7074, 0x0922,
557 : : 0x1F5A, 0x660C, 0xEDF6, 0x94A0, 0xA337, 0xDA61, 0x519B, 0x28CD };
558 : :
559 : : /**
560 : : * fm10k_crc_16b - Generate a 16 bit CRC for a region of 16 bit data
561 : : * @data: pointer to data to process
562 : : * @seed: seed value for CRC
563 : : * @len: length measured in 16 bits words
564 : : *
565 : : * This function will generate a CRC based on the polynomial 0xAC9A and
566 : : * whatever value is stored in the seed variable. Note that this
567 : : * value inverts the local seed and the result in order to capture all
568 : : * leading and trailing zeros.
569 : : */
570 : 0 : STATIC u16 fm10k_crc_16b(const u32 *data, u16 seed, u16 len)
571 : : {
572 : 0 : u32 result = seed;
573 : :
574 [ # # ]: 0 : while (len--) {
575 : 0 : result ^= *(data++);
576 : 0 : result = (result >> 8) ^ fm10k_crc_16b_table[result & 0xFF];
577 : 0 : result = (result >> 8) ^ fm10k_crc_16b_table[result & 0xFF];
578 : :
579 [ # # ]: 0 : if (!(len--))
580 : : break;
581 : :
582 : 0 : result = (result >> 8) ^ fm10k_crc_16b_table[result & 0xFF];
583 : 0 : result = (result >> 8) ^ fm10k_crc_16b_table[result & 0xFF];
584 : : }
585 : :
586 : 0 : return (u16)result;
587 : : }
588 : :
589 : : /**
590 : : * fm10k_fifo_crc - generate a CRC based off of FIFO data
591 : : * @fifo: pointer to FIFO
592 : : * @offset: offset point for start of FIFO
593 : : * @len: number of DWORDS words to process
594 : : * @seed: seed value for CRC
595 : : *
596 : : * This function generates a CRC for some region of the FIFO
597 : : **/
598 : 0 : STATIC u16 fm10k_fifo_crc(struct fm10k_mbx_fifo *fifo, u16 offset,
599 : : u16 len, u16 seed)
600 : : {
601 : 0 : u32 *data = fifo->buffer + offset;
602 : :
603 : : /* track when we should cross the end of the FIFO */
604 : 0 : offset = fifo->size - offset;
605 : :
606 : : /* if we are in 2 blocks process the end of the FIFO first */
607 [ # # ]: 0 : if (offset < len) {
608 : 0 : seed = fm10k_crc_16b(data, seed, offset * 2);
609 : : data = fifo->buffer;
610 : 0 : len -= offset;
611 : : }
612 : :
613 : : /* process any remaining bits */
614 : 0 : return fm10k_crc_16b(data, seed, len * 2);
615 : : }
616 : :
617 : : /**
618 : : * fm10k_mbx_update_local_crc - Update the local CRC for outgoing data
619 : : * @mbx: pointer to mailbox
620 : : * @head: head index provided by remote mailbox
621 : : *
622 : : * This function will generate the CRC for all data from the end of the
623 : : * last head update to the current one. It uses the result of the
624 : : * previous CRC as the seed for this update. The result is stored in
625 : : * mbx->local.
626 : : **/
627 : 0 : STATIC void fm10k_mbx_update_local_crc(struct fm10k_mbx_info *mbx, u16 head)
628 : : {
629 [ # # ]: 0 : u16 len = mbx->tail_len - fm10k_mbx_index_len(mbx, head, mbx->tail);
630 : :
631 : : /* determine the offset for the start of the region to be pulled */
632 : 0 : head = fm10k_fifo_head_offset(&mbx->tx, mbx->pulled);
633 : :
634 : : /* update local CRC to include all of the pulled data */
635 : 0 : mbx->local = fm10k_fifo_crc(&mbx->tx, head, len, mbx->local);
636 : 0 : }
637 : :
638 : : /**
639 : : * fm10k_mbx_verify_remote_crc - Verify the CRC is correct for current data
640 : : * @mbx: pointer to mailbox
641 : : *
642 : : * This function will take all data that has been provided from the remote
643 : : * end and generate a CRC for it. This is stored in mbx->remote. The
644 : : * CRC for the header is then computed and if the result is non-zero this
645 : : * is an error and we signal an error dropping all data and resetting the
646 : : * connection.
647 : : */
648 : 0 : STATIC s32 fm10k_mbx_verify_remote_crc(struct fm10k_mbx_info *mbx)
649 : : {
650 : 0 : struct fm10k_mbx_fifo *fifo = &mbx->rx;
651 : 0 : u16 len = mbx->head_len;
652 : 0 : u16 offset = fm10k_fifo_tail_offset(fifo, mbx->pushed) - len;
653 : : u16 crc;
654 : :
655 : : /* update the remote CRC if new data has been received */
656 [ # # ]: 0 : if (len)
657 : 0 : mbx->remote = fm10k_fifo_crc(fifo, offset, len, mbx->remote);
658 : :
659 : : /* process the full header as we have to validate the CRC */
660 : 0 : crc = fm10k_crc_16b(&mbx->mbx_hdr, mbx->remote, 1);
661 : :
662 : : /* notify other end if we have a problem */
663 [ # # ]: 0 : return crc ? FM10K_MBX_ERR_CRC : FM10K_SUCCESS;
664 : : }
665 : :
666 : : /**
667 : : * fm10k_mbx_rx_ready - Indicates that a message is ready in the Rx FIFO
668 : : * @mbx: pointer to mailbox
669 : : *
670 : : * This function returns true if there is a message in the Rx FIFO to dequeue.
671 : : **/
672 [ # # ]: 0 : STATIC bool fm10k_mbx_rx_ready(struct fm10k_mbx_info *mbx)
673 : : {
674 : : u16 msg_size = fm10k_fifo_head_len(&mbx->rx);
675 : :
676 [ # # ]: 0 : return msg_size && (fm10k_fifo_used(&mbx->rx) >= msg_size);
677 : : }
678 : :
679 : : /**
680 : : * fm10k_mbx_tx_ready - Indicates that the mailbox is in state ready for Tx
681 : : * @mbx: pointer to mailbox
682 : : * @len: verify free space is >= this value
683 : : *
684 : : * This function returns true if the mailbox is in a state ready to transmit.
685 : : **/
686 : 0 : STATIC bool fm10k_mbx_tx_ready(struct fm10k_mbx_info *mbx, u16 len)
687 : : {
688 : : u16 fifo_unused = fm10k_fifo_unused(&mbx->tx);
689 : :
690 [ # # # # ]: 0 : return (mbx->state == FM10K_STATE_OPEN) && (fifo_unused >= len);
691 : : }
692 : :
693 : : /**
694 : : * fm10k_mbx_tx_complete - Indicates that the Tx FIFO has been emptied
695 : : * @mbx: pointer to mailbox
696 : : *
697 : : * This function returns true if the Tx FIFO is empty.
698 : : **/
699 : 0 : STATIC bool fm10k_mbx_tx_complete(struct fm10k_mbx_info *mbx)
700 : : {
701 : 0 : return fm10k_fifo_empty(&mbx->tx);
702 : : }
703 : :
704 : : /**
705 : : * fm10k_mbx_deqeueue_rx - Dequeues the message from the head in the Rx FIFO
706 : : * @hw: pointer to hardware structure
707 : : * @mbx: pointer to mailbox
708 : : *
709 : : * This function dequeues messages and hands them off to the TLV parser.
710 : : * It will return the number of messages processed when called.
711 : : **/
712 : 0 : STATIC u16 fm10k_mbx_dequeue_rx(struct fm10k_hw *hw,
713 : : struct fm10k_mbx_info *mbx)
714 : : {
715 : : struct fm10k_mbx_fifo *fifo = &mbx->rx;
716 : : s32 err;
717 : : u16 cnt;
718 : :
719 : : /* parse Rx messages out of the Rx FIFO to empty it */
720 [ # # ]: 0 : for (cnt = 0; !fm10k_fifo_empty(fifo); cnt++) {
721 : 0 : err = fm10k_tlv_msg_parse(hw, fifo->buffer + fifo->head,
722 : : mbx, mbx->msg_data);
723 [ # # ]: 0 : if (err < 0)
724 : 0 : mbx->rx_parse_err++;
725 : :
726 : : fm10k_fifo_head_drop(fifo);
727 : : }
728 : :
729 : : /* shift remaining bytes back to start of FIFO */
730 : 0 : memmove(fifo->buffer, fifo->buffer + fifo->tail, mbx->pushed << 2);
731 : :
732 : : /* shift head and tail based on the memory we moved */
733 : 0 : fifo->tail -= fifo->head;
734 : 0 : fifo->head = 0;
735 : :
736 : 0 : return cnt;
737 : : }
738 : :
739 : : /**
740 : : * fm10k_mbx_enqueue_tx - Enqueues the message to the tail of the Tx FIFO
741 : : * @hw: pointer to hardware structure
742 : : * @mbx: pointer to mailbox
743 : : * @msg: message array to read
744 : : *
745 : : * This function enqueues a message up to the size specified by the length
746 : : * contained in the first DWORD of the message and will place at the tail
747 : : * of the FIFO. It will return 0 on success, or a negative value on error.
748 : : **/
749 : 0 : STATIC s32 fm10k_mbx_enqueue_tx(struct fm10k_hw *hw,
750 : : struct fm10k_mbx_info *mbx, const u32 *msg)
751 : : {
752 : 0 : u32 countdown = mbx->timeout;
753 : : s32 err;
754 : :
755 [ # # ]: 0 : switch (mbx->state) {
756 : : case FM10K_STATE_CLOSED:
757 : : case FM10K_STATE_DISCONNECT:
758 : : return FM10K_MBX_ERR_NO_MBX;
759 : : default:
760 : : break;
761 : : }
762 : :
763 : : /* enqueue the message on the Tx FIFO */
764 : 0 : err = fm10k_fifo_enqueue(&mbx->tx, msg);
765 : :
766 : : /* if it failed give the FIFO a chance to drain */
767 [ # # ]: 0 : while (err && countdown) {
768 : 0 : countdown--;
769 : 0 : usec_delay(mbx->usec_delay);
770 : 0 : mbx->ops.process(hw, mbx);
771 : 0 : err = fm10k_fifo_enqueue(&mbx->tx, msg);
772 : : }
773 : :
774 : : /* if we failed treat the error */
775 [ # # ]: 0 : if (err) {
776 : 0 : mbx->timeout = 0;
777 : 0 : mbx->tx_busy++;
778 : : }
779 : :
780 : : /* begin processing message, ignore errors as this is just meant
781 : : * to start the mailbox flow so we are not concerned if there
782 : : * is a bad error, or the mailbox is already busy with a request
783 : : */
784 [ # # ]: 0 : if (!mbx->tail_len)
785 : 0 : mbx->ops.process(hw, mbx);
786 : :
787 : : return FM10K_SUCCESS;
788 : : }
789 : :
790 : : /**
791 : : * fm10k_mbx_read - Copies the mbmem to local message buffer
792 : : * @hw: pointer to hardware structure
793 : : * @mbx: pointer to mailbox
794 : : *
795 : : * This function copies the message from the mbmem to the message array
796 : : **/
797 : 0 : STATIC s32 fm10k_mbx_read(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx)
798 : : {
799 : 0 : DEBUGFUNC("fm10k_mbx_read");
800 : :
801 : : /* only allow one reader in here at a time */
802 [ # # ]: 0 : if (mbx->mbx_hdr)
803 : : return FM10K_MBX_ERR_BUSY;
804 : :
805 : : /* read to capture initial interrupt bits */
806 [ # # ]: 0 : if (FM10K_READ_MBX(hw, mbx->mbx_reg) & FM10K_MBX_REQ_INTERRUPT)
807 : 0 : mbx->mbx_lock = FM10K_MBX_ACK;
808 : :
809 : : /* write back interrupt bits to clear */
810 : 0 : FM10K_WRITE_MBX(hw, mbx->mbx_reg,
811 : : FM10K_MBX_REQ_INTERRUPT | FM10K_MBX_ACK_INTERRUPT);
812 : :
813 : : /* read remote header */
814 : 0 : mbx->mbx_hdr = FM10K_READ_MBX(hw, mbx->mbmem_reg ^ mbx->mbmem_len);
815 : :
816 : 0 : return FM10K_SUCCESS;
817 : : }
818 : :
819 : : /**
820 : : * fm10k_mbx_write - Copies the local message buffer to mbmem
821 : : * @hw: pointer to hardware structure
822 : : * @mbx: pointer to mailbox
823 : : *
824 : : * This function copies the message from the message array to mbmem
825 : : **/
826 : 0 : STATIC void fm10k_mbx_write(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx)
827 : : {
828 : 0 : u32 mbmem = mbx->mbmem_reg;
829 : :
830 : 0 : DEBUGFUNC("fm10k_mbx_write");
831 : :
832 : : /* write new msg header to notify recipient of change */
833 : 0 : FM10K_WRITE_MBX(hw, mbmem, mbx->mbx_hdr);
834 : :
835 : : /* write mailbox to send interrupt */
836 [ # # ]: 0 : if (mbx->mbx_lock)
837 : 0 : FM10K_WRITE_MBX(hw, mbx->mbx_reg, mbx->mbx_lock);
838 : :
839 : : /* we no longer are using the header so free it */
840 : 0 : mbx->mbx_hdr = 0;
841 : 0 : mbx->mbx_lock = 0;
842 : 0 : }
843 : :
844 : : /**
845 : : * fm10k_mbx_create_connect_hdr - Generate a connect mailbox header
846 : : * @mbx: pointer to mailbox
847 : : *
848 : : * This function returns a connection mailbox header
849 : : **/
850 : : STATIC void fm10k_mbx_create_connect_hdr(struct fm10k_mbx_info *mbx)
851 : : {
852 : 0 : mbx->mbx_lock |= FM10K_MBX_REQ;
853 : :
854 : 0 : mbx->mbx_hdr = FM10K_MSG_HDR_FIELD_SET(FM10K_MSG_CONNECT, TYPE) |
855 : 0 : FM10K_MSG_HDR_FIELD_SET(mbx->head, HEAD) |
856 : 0 : FM10K_MSG_HDR_FIELD_SET(mbx->rx.size - 1, CONNECT_SIZE);
857 : 0 : }
858 : :
859 : : /**
860 : : * fm10k_mbx_create_data_hdr - Generate a data mailbox header
861 : : * @mbx: pointer to mailbox
862 : : *
863 : : * This function returns a data mailbox header
864 : : **/
865 : 0 : STATIC void fm10k_mbx_create_data_hdr(struct fm10k_mbx_info *mbx)
866 : : {
867 : 0 : u32 hdr = FM10K_MSG_HDR_FIELD_SET(FM10K_MSG_DATA, TYPE) |
868 : 0 : FM10K_MSG_HDR_FIELD_SET(mbx->tail, TAIL) |
869 : 0 : FM10K_MSG_HDR_FIELD_SET(mbx->head, HEAD);
870 : 0 : struct fm10k_mbx_fifo *fifo = &mbx->tx;
871 : : u16 crc;
872 : :
873 [ # # ]: 0 : if (mbx->tail_len)
874 : 0 : mbx->mbx_lock |= FM10K_MBX_REQ;
875 : :
876 : : /* generate CRC for data in flight and header */
877 : 0 : crc = fm10k_fifo_crc(fifo, fm10k_fifo_head_offset(fifo, mbx->pulled),
878 : 0 : mbx->tail_len, mbx->local);
879 : 0 : crc = fm10k_crc_16b(&hdr, crc, 1);
880 : :
881 : : /* load header to memory to be written */
882 : 0 : mbx->mbx_hdr = hdr | FM10K_MSG_HDR_FIELD_SET(crc, CRC);
883 : 0 : }
884 : :
885 : : /**
886 : : * fm10k_mbx_create_disconnect_hdr - Generate a disconnect mailbox header
887 : : * @mbx: pointer to mailbox
888 : : *
889 : : * This function returns a disconnect mailbox header
890 : : **/
891 : 0 : STATIC void fm10k_mbx_create_disconnect_hdr(struct fm10k_mbx_info *mbx)
892 : : {
893 : 0 : u32 hdr = FM10K_MSG_HDR_FIELD_SET(FM10K_MSG_DISCONNECT, TYPE) |
894 : 0 : FM10K_MSG_HDR_FIELD_SET(mbx->tail, TAIL) |
895 : 0 : FM10K_MSG_HDR_FIELD_SET(mbx->head, HEAD);
896 : 0 : u16 crc = fm10k_crc_16b(&hdr, mbx->local, 1);
897 : :
898 : 0 : mbx->mbx_lock |= FM10K_MBX_ACK;
899 : :
900 : : /* load header to memory to be written */
901 : 0 : mbx->mbx_hdr = hdr | FM10K_MSG_HDR_FIELD_SET(crc, CRC);
902 : 0 : }
903 : :
904 : : /**
905 : : * fm10k_mbx_create_fake_disconnect_hdr - Generate a false disconnect mbox hdr
906 : : * @mbx: pointer to mailbox
907 : : *
908 : : * This function creates a fake disconnect header for loading into remote
909 : : * mailbox header. The primary purpose is to prevent errors on immediate
910 : : * start up after mbx->connect.
911 : : **/
912 : 0 : STATIC void fm10k_mbx_create_fake_disconnect_hdr(struct fm10k_mbx_info *mbx)
913 : : {
914 : 0 : u32 hdr = FM10K_MSG_HDR_FIELD_SET(FM10K_MSG_DISCONNECT, TYPE) |
915 : 0 : FM10K_MSG_HDR_FIELD_SET(mbx->head, TAIL) |
916 : 0 : FM10K_MSG_HDR_FIELD_SET(mbx->tail, HEAD);
917 : 0 : u16 crc = fm10k_crc_16b(&hdr, mbx->local, 1);
918 : :
919 : 0 : mbx->mbx_lock |= FM10K_MBX_ACK;
920 : :
921 : : /* load header to memory to be written */
922 : 0 : mbx->mbx_hdr = hdr | FM10K_MSG_HDR_FIELD_SET(crc, CRC);
923 : 0 : }
924 : :
925 : : /**
926 : : * fm10k_mbx_create_error_msg - Generate an error message
927 : : * @mbx: pointer to mailbox
928 : : * @err: local error encountered
929 : : *
930 : : * This function will interpret the error provided by err, and based on
931 : : * that it may shift the message by 1 DWORD and then place an error header
932 : : * at the start of the message.
933 : : **/
934 : 0 : STATIC void fm10k_mbx_create_error_msg(struct fm10k_mbx_info *mbx, s32 err)
935 : : {
936 : : /* only generate an error message for these types */
937 [ # # ]: 0 : switch (err) {
938 : : case FM10K_MBX_ERR_TAIL:
939 : : case FM10K_MBX_ERR_HEAD:
940 : : case FM10K_MBX_ERR_TYPE:
941 : : case FM10K_MBX_ERR_SIZE:
942 : : case FM10K_MBX_ERR_RSVD0:
943 : : case FM10K_MBX_ERR_CRC:
944 : : break;
945 : : default:
946 : : return;
947 : : }
948 : :
949 : 0 : mbx->mbx_lock |= FM10K_MBX_REQ;
950 : :
951 : 0 : mbx->mbx_hdr = FM10K_MSG_HDR_FIELD_SET(FM10K_MSG_ERROR, TYPE) |
952 : 0 : FM10K_MSG_HDR_FIELD_SET(err, ERR_NO) |
953 : 0 : FM10K_MSG_HDR_FIELD_SET(mbx->head, HEAD);
954 : : }
955 : :
956 : : /**
957 : : * fm10k_mbx_validate_msg_hdr - Validate common fields in the message header
958 : : * @mbx: pointer to mailbox
959 : : *
960 : : * This function will parse up the fields in the mailbox header and return
961 : : * an error if the header contains any of a number of invalid configurations
962 : : * including unrecognized type, invalid route, or a malformed message.
963 : : **/
964 : 0 : STATIC s32 fm10k_mbx_validate_msg_hdr(struct fm10k_mbx_info *mbx)
965 : : {
966 : : u16 type, rsvd0, head, tail, size;
967 : : const u32 *hdr = &mbx->mbx_hdr;
968 : :
969 : 0 : DEBUGFUNC("fm10k_mbx_validate_msg_hdr");
970 : :
971 : 0 : type = FM10K_MSG_HDR_FIELD_GET(*hdr, TYPE);
972 : 0 : rsvd0 = FM10K_MSG_HDR_FIELD_GET(*hdr, RSVD0);
973 : 0 : tail = FM10K_MSG_HDR_FIELD_GET(*hdr, TAIL);
974 : 0 : head = FM10K_MSG_HDR_FIELD_GET(*hdr, HEAD);
975 : 0 : size = FM10K_MSG_HDR_FIELD_GET(*hdr, CONNECT_SIZE);
976 : :
977 [ # # ]: 0 : if (rsvd0)
978 : : return FM10K_MBX_ERR_RSVD0;
979 : :
980 [ # # # # : 0 : switch (type) {
# ]
981 : 0 : case FM10K_MSG_DISCONNECT:
982 : : /* validate that all data has been received */
983 [ # # ]: 0 : if (tail != mbx->head)
984 : : return FM10K_MBX_ERR_TAIL;
985 : :
986 : : /* fall through */
987 : : case FM10K_MSG_DATA:
988 : : /* validate that head is moving correctly */
989 [ # # ]: 0 : if (!head || (head == FM10K_MSG_HDR_MASK(HEAD)))
990 : : return FM10K_MBX_ERR_HEAD;
991 [ # # # # ]: 0 : if (fm10k_mbx_index_len(mbx, head, mbx->tail) > mbx->tail_len)
992 : : return FM10K_MBX_ERR_HEAD;
993 : :
994 : : /* validate that tail is moving correctly */
995 [ # # ]: 0 : if (!tail || (tail == FM10K_MSG_HDR_MASK(TAIL)))
996 : : return FM10K_MBX_ERR_TAIL;
997 [ # # # # ]: 0 : if (fm10k_mbx_index_len(mbx, mbx->head, tail) < mbx->mbmem_len)
998 : : break;
999 : :
1000 : : return FM10K_MBX_ERR_TAIL;
1001 : 0 : case FM10K_MSG_CONNECT:
1002 : : /* validate size is in range and is power of 2 mask */
1003 [ # # # # ]: 0 : if ((size < FM10K_VFMBX_MSG_MTU) || (size & (size + 1)))
1004 : : return FM10K_MBX_ERR_SIZE;
1005 : :
1006 : : /* fall through */
1007 : : case FM10K_MSG_ERROR:
1008 [ # # ]: 0 : if (!head || (head == FM10K_MSG_HDR_MASK(HEAD)))
1009 : : return FM10K_MBX_ERR_HEAD;
1010 : : /* neither create nor error include a tail offset */
1011 [ # # ]: 0 : if (tail)
1012 : 0 : return FM10K_MBX_ERR_TAIL;
1013 : :
1014 : : break;
1015 : : default:
1016 : : return FM10K_MBX_ERR_TYPE;
1017 : : }
1018 : :
1019 : : return FM10K_SUCCESS;
1020 : : }
1021 : :
1022 : : /**
1023 : : * fm10k_mbx_create_reply - Generate reply based on state and remote head
1024 : : * @hw: pointer to hardware structure
1025 : : * @mbx: pointer to mailbox
1026 : : * @head: acknowledgement number
1027 : : *
1028 : : * This function will generate an outgoing message based on the current
1029 : : * mailbox state and the remote FIFO head. It will return the length
1030 : : * of the outgoing message excluding header on success, and a negative value
1031 : : * on error.
1032 : : **/
1033 : 0 : STATIC s32 fm10k_mbx_create_reply(struct fm10k_hw *hw,
1034 : : struct fm10k_mbx_info *mbx, u16 head)
1035 : : {
1036 [ # # # # ]: 0 : switch (mbx->state) {
1037 : 0 : case FM10K_STATE_OPEN:
1038 : : case FM10K_STATE_DISCONNECT:
1039 : : /* update our checksum for the outgoing data */
1040 : 0 : fm10k_mbx_update_local_crc(mbx, head);
1041 : :
1042 : : /* as long as other end recognizes us keep sending data */
1043 : 0 : fm10k_mbx_pull_head(hw, mbx, head);
1044 : :
1045 : : /* generate new header based on data */
1046 [ # # # # ]: 0 : if (mbx->tail_len || (mbx->state == FM10K_STATE_OPEN))
1047 : 0 : fm10k_mbx_create_data_hdr(mbx);
1048 : : else
1049 : 0 : fm10k_mbx_create_disconnect_hdr(mbx);
1050 : : break;
1051 : : case FM10K_STATE_CONNECT:
1052 : : /* send disconnect even if we aren't connected */
1053 : : fm10k_mbx_create_connect_hdr(mbx);
1054 : : break;
1055 : 0 : case FM10K_STATE_CLOSED:
1056 : : /* generate new header based on data */
1057 : 0 : fm10k_mbx_create_disconnect_hdr(mbx);
1058 : : default:
1059 : : break;
1060 : : }
1061 : :
1062 : 0 : return FM10K_SUCCESS;
1063 : : }
1064 : :
1065 : : /**
1066 : : * fm10k_mbx_reset_work- Reset internal pointers for any pending work
1067 : : * @mbx: pointer to mailbox
1068 : : *
1069 : : * This function will reset all internal pointers so any work in progress
1070 : : * is dropped. This call should occur every time we transition from the
1071 : : * open state to the connect state.
1072 : : **/
1073 : 0 : STATIC void fm10k_mbx_reset_work(struct fm10k_mbx_info *mbx)
1074 : : {
1075 : : u16 len, head, ack;
1076 : :
1077 : : /* reset our outgoing max size back to Rx limits */
1078 : 0 : mbx->max_size = mbx->rx.size - 1;
1079 : :
1080 : : /* update mbx->pulled to account for tail_len and ack */
1081 : 0 : head = FM10K_MSG_HDR_FIELD_GET(mbx->mbx_hdr, HEAD);
1082 [ # # ]: 0 : ack = fm10k_mbx_index_len(mbx, head, mbx->tail);
1083 : 0 : mbx->pulled += mbx->tail_len - ack;
1084 : :
1085 : : /* now drop any messages which have started or finished transmitting */
1086 [ # # ]: 0 : while (fm10k_fifo_head_len(&mbx->tx) && mbx->pulled) {
1087 : : len = fm10k_fifo_head_drop(&mbx->tx);
1088 : 0 : mbx->tx_dropped++;
1089 [ # # ]: 0 : if (mbx->pulled >= len)
1090 : 0 : mbx->pulled -= len;
1091 : : else
1092 : 0 : mbx->pulled = 0;
1093 : : }
1094 : :
1095 : : /* just do a quick resysnc to start of message */
1096 : 0 : mbx->pushed = 0;
1097 : 0 : mbx->pulled = 0;
1098 : 0 : mbx->tail_len = 0;
1099 : 0 : mbx->head_len = 0;
1100 : 0 : mbx->rx.tail = 0;
1101 : 0 : mbx->rx.head = 0;
1102 : 0 : }
1103 : :
1104 : : /**
1105 : : * fm10k_mbx_update_max_size - Update the max_size and drop any large messages
1106 : : * @mbx: pointer to mailbox
1107 : : * @size: new value for max_size
1108 : : *
1109 : : * This function updates the max_size value and drops any outgoing messages
1110 : : * at the head of the Tx FIFO if they are larger than max_size. It does not
1111 : : * drop all messages, as this is too difficult to parse and remove them from
1112 : : * the FIFO. Instead, rely on the checking to ensure that messages larger
1113 : : * than max_size aren't pushed into the memory buffer.
1114 : : **/
1115 : 0 : STATIC void fm10k_mbx_update_max_size(struct fm10k_mbx_info *mbx, u16 size)
1116 : : {
1117 : : u16 len;
1118 : :
1119 : 0 : DEBUGFUNC("fm10k_mbx_update_max_size");
1120 : :
1121 [ # # ]: 0 : mbx->max_size = size;
1122 : :
1123 : : /* flush any oversized messages from the queue */
1124 : : for (len = fm10k_fifo_head_len(&mbx->tx);
1125 [ # # ]: 0 : len > size;
1126 : : len = fm10k_fifo_head_len(&mbx->tx)) {
1127 : : fm10k_fifo_head_drop(&mbx->tx);
1128 [ # # ]: 0 : mbx->tx_dropped++;
1129 : : }
1130 : 0 : }
1131 : :
1132 : : /**
1133 : : * fm10k_mbx_connect_reset - Reset following request for reset
1134 : : * @mbx: pointer to mailbox
1135 : : *
1136 : : * This function resets the mailbox to either a disconnected state
1137 : : * or a connect state depending on the current mailbox state
1138 : : **/
1139 : : STATIC void fm10k_mbx_connect_reset(struct fm10k_mbx_info *mbx)
1140 : : {
1141 : : /* just do a quick resysnc to start of frame */
1142 : 0 : fm10k_mbx_reset_work(mbx);
1143 : :
1144 : : /* reset CRC seeds */
1145 : 0 : mbx->local = FM10K_MBX_CRC_SEED;
1146 : 0 : mbx->remote = FM10K_MBX_CRC_SEED;
1147 : :
1148 : : /* we cannot exit connect until the size is good */
1149 [ # # # # : 0 : if (mbx->state == FM10K_STATE_OPEN)
# # ]
1150 : 0 : mbx->state = FM10K_STATE_CONNECT;
1151 : : else
1152 : 0 : mbx->state = FM10K_STATE_CLOSED;
1153 : : }
1154 : :
1155 : : /**
1156 : : * fm10k_mbx_process_connect - Process connect header
1157 : : * @hw: pointer to hardware structure
1158 : : * @mbx: pointer to mailbox
1159 : : *
1160 : : * This function will read an incoming connect header and reply with the
1161 : : * appropriate message. It will return a value indicating the number of
1162 : : * data DWORDs on success, or will return a negative value on failure.
1163 : : **/
1164 : 0 : STATIC s32 fm10k_mbx_process_connect(struct fm10k_hw *hw,
1165 : : struct fm10k_mbx_info *mbx)
1166 : : {
1167 : 0 : const enum fm10k_mbx_state state = mbx->state;
1168 : : const u32 *hdr = &mbx->mbx_hdr;
1169 : : u16 size, head;
1170 : :
1171 : : /* we will need to pull all of the fields for verification */
1172 : 0 : size = FM10K_MSG_HDR_FIELD_GET(*hdr, CONNECT_SIZE);
1173 : 0 : head = FM10K_MSG_HDR_FIELD_GET(*hdr, HEAD);
1174 : :
1175 [ # # # ]: 0 : switch (state) {
1176 : : case FM10K_STATE_DISCONNECT:
1177 : : case FM10K_STATE_OPEN:
1178 : : /* reset any in-progress work */
1179 : : fm10k_mbx_connect_reset(mbx);
1180 : : break;
1181 : 0 : case FM10K_STATE_CONNECT:
1182 : : /* we cannot exit connect until the size is good */
1183 [ # # ]: 0 : if (size > mbx->rx.size) {
1184 : 0 : mbx->max_size = mbx->rx.size - 1;
1185 : : } else {
1186 : : /* record the remote system requesting connection */
1187 : 0 : mbx->state = FM10K_STATE_OPEN;
1188 : :
1189 : 0 : fm10k_mbx_update_max_size(mbx, size);
1190 : : }
1191 : : break;
1192 : : default:
1193 : : break;
1194 : : }
1195 : :
1196 : : /* align our tail index to remote head index */
1197 : 0 : mbx->tail = head;
1198 : :
1199 : 0 : return fm10k_mbx_create_reply(hw, mbx, head);
1200 : : }
1201 : :
1202 : : /**
1203 : : * fm10k_mbx_process_data - Process data header
1204 : : * @hw: pointer to hardware structure
1205 : : * @mbx: pointer to mailbox
1206 : : *
1207 : : * This function will read an incoming data header and reply with the
1208 : : * appropriate message. It will return a value indicating the number of
1209 : : * data DWORDs on success, or will return a negative value on failure.
1210 : : **/
1211 : 0 : STATIC s32 fm10k_mbx_process_data(struct fm10k_hw *hw,
1212 : : struct fm10k_mbx_info *mbx)
1213 : : {
1214 : : const u32 *hdr = &mbx->mbx_hdr;
1215 : : u16 head, tail;
1216 : : s32 err;
1217 : :
1218 : 0 : DEBUGFUNC("fm10k_mbx_process_data");
1219 : :
1220 : : /* we will need to pull all of the fields for verification */
1221 : 0 : head = FM10K_MSG_HDR_FIELD_GET(*hdr, HEAD);
1222 : 0 : tail = FM10K_MSG_HDR_FIELD_GET(*hdr, TAIL);
1223 : :
1224 : : /* if we are in connect just update our data and go */
1225 [ # # ]: 0 : if (mbx->state == FM10K_STATE_CONNECT) {
1226 : 0 : mbx->tail = head;
1227 : 0 : mbx->state = FM10K_STATE_OPEN;
1228 : : }
1229 : :
1230 : : /* abort on message size errors */
1231 : 0 : err = fm10k_mbx_push_tail(hw, mbx, tail);
1232 [ # # ]: 0 : if (err < 0)
1233 : : return err;
1234 : :
1235 : : /* verify the checksum on the incoming data */
1236 : 0 : err = fm10k_mbx_verify_remote_crc(mbx);
1237 [ # # ]: 0 : if (err)
1238 : : return err;
1239 : :
1240 : : /* process messages if we have received any */
1241 : 0 : fm10k_mbx_dequeue_rx(hw, mbx);
1242 : :
1243 : 0 : return fm10k_mbx_create_reply(hw, mbx, head);
1244 : : }
1245 : :
1246 : : /**
1247 : : * fm10k_mbx_process_disconnect - Process disconnect header
1248 : : * @hw: pointer to hardware structure
1249 : : * @mbx: pointer to mailbox
1250 : : *
1251 : : * This function will read an incoming disconnect header and reply with the
1252 : : * appropriate message. It will return a value indicating the number of
1253 : : * data DWORDs on success, or will return a negative value on failure.
1254 : : **/
1255 : 0 : STATIC s32 fm10k_mbx_process_disconnect(struct fm10k_hw *hw,
1256 : : struct fm10k_mbx_info *mbx)
1257 : : {
1258 : 0 : const enum fm10k_mbx_state state = mbx->state;
1259 : : const u32 *hdr = &mbx->mbx_hdr;
1260 : : u16 head;
1261 : : s32 err;
1262 : :
1263 : : /* we will need to pull the header field for verification */
1264 : 0 : head = FM10K_MSG_HDR_FIELD_GET(*hdr, HEAD);
1265 : :
1266 : : /* We should not be receiving disconnect if Rx is incomplete */
1267 [ # # ]: 0 : if (mbx->pushed)
1268 : : return FM10K_MBX_ERR_TAIL;
1269 : :
1270 : : /* we have already verified mbx->head == tail so we know this is 0 */
1271 : 0 : mbx->head_len = 0;
1272 : :
1273 : : /* verify the checksum on the incoming header is correct */
1274 : 0 : err = fm10k_mbx_verify_remote_crc(mbx);
1275 [ # # ]: 0 : if (err)
1276 : : return err;
1277 : :
1278 [ # # ]: 0 : switch (state) {
1279 : : case FM10K_STATE_DISCONNECT:
1280 : : case FM10K_STATE_OPEN:
1281 : : /* state doesn't change if we still have work to do */
1282 [ # # ]: 0 : if (!fm10k_mbx_tx_complete(mbx))
1283 : : break;
1284 : :
1285 : : /* verify the head indicates we completed all transmits */
1286 [ # # ]: 0 : if (head != mbx->tail)
1287 : : return FM10K_MBX_ERR_HEAD;
1288 : :
1289 : : /* reset any in-progress work */
1290 : : fm10k_mbx_connect_reset(mbx);
1291 : : break;
1292 : : default:
1293 : : break;
1294 : : }
1295 : :
1296 : 0 : return fm10k_mbx_create_reply(hw, mbx, head);
1297 : : }
1298 : :
1299 : : /**
1300 : : * fm10k_mbx_process_error - Process error header
1301 : : * @hw: pointer to hardware structure
1302 : : * @mbx: pointer to mailbox
1303 : : *
1304 : : * This function will read an incoming error header and reply with the
1305 : : * appropriate message. It will return a value indicating the number of
1306 : : * data DWORDs on success, or will return a negative value on failure.
1307 : : **/
1308 : 0 : STATIC s32 fm10k_mbx_process_error(struct fm10k_hw *hw,
1309 : : struct fm10k_mbx_info *mbx)
1310 : : {
1311 : : const u32 *hdr = &mbx->mbx_hdr;
1312 : : u16 head;
1313 : :
1314 : : /* we will need to pull all of the fields for verification */
1315 : 0 : head = FM10K_MSG_HDR_FIELD_GET(*hdr, HEAD);
1316 : :
1317 [ # # ]: 0 : switch (mbx->state) {
1318 : 0 : case FM10K_STATE_OPEN:
1319 : : case FM10K_STATE_DISCONNECT:
1320 : : /* flush any uncompleted work */
1321 : 0 : fm10k_mbx_reset_work(mbx);
1322 : :
1323 : : /* reset CRC seeds */
1324 : 0 : mbx->local = FM10K_MBX_CRC_SEED;
1325 : 0 : mbx->remote = FM10K_MBX_CRC_SEED;
1326 : :
1327 : : /* reset tail index and size to prepare for reconnect */
1328 : 0 : mbx->tail = head;
1329 : :
1330 : : /* if open then reset max_size and go back to connect */
1331 [ # # ]: 0 : if (mbx->state == FM10K_STATE_OPEN) {
1332 : 0 : mbx->state = FM10K_STATE_CONNECT;
1333 : 0 : break;
1334 : : }
1335 : :
1336 : : /* send a connect message to get data flowing again */
1337 : : fm10k_mbx_create_connect_hdr(mbx);
1338 : 0 : return FM10K_SUCCESS;
1339 : : default:
1340 : : break;
1341 : : }
1342 : :
1343 : 0 : return fm10k_mbx_create_reply(hw, mbx, mbx->tail);
1344 : : }
1345 : :
1346 : : /**
1347 : : * fm10k_mbx_process - Process mailbox interrupt
1348 : : * @hw: pointer to hardware structure
1349 : : * @mbx: pointer to mailbox
1350 : : *
1351 : : * This function will process incoming mailbox events and generate mailbox
1352 : : * replies. It will return a value indicating the number of DWORDs
1353 : : * transmitted excluding header on success or a negative value on error.
1354 : : **/
1355 : 0 : STATIC s32 fm10k_mbx_process(struct fm10k_hw *hw,
1356 : : struct fm10k_mbx_info *mbx)
1357 : : {
1358 : : s32 err;
1359 : :
1360 : 0 : DEBUGFUNC("fm10k_mbx_process");
1361 : :
1362 : : /* we do not read mailbox if closed */
1363 [ # # ]: 0 : if (mbx->state == FM10K_STATE_CLOSED)
1364 : : return FM10K_SUCCESS;
1365 : :
1366 : : /* copy data from mailbox */
1367 : 0 : err = fm10k_mbx_read(hw, mbx);
1368 [ # # ]: 0 : if (err)
1369 : : return err;
1370 : :
1371 : : /* validate type, source, and destination */
1372 : 0 : err = fm10k_mbx_validate_msg_hdr(mbx);
1373 [ # # ]: 0 : if (err < 0)
1374 : 0 : goto msg_err;
1375 : :
1376 [ # # # # : 0 : switch (FM10K_MSG_HDR_FIELD_GET(mbx->mbx_hdr, TYPE)) {
# ]
1377 : 0 : case FM10K_MSG_CONNECT:
1378 : 0 : err = fm10k_mbx_process_connect(hw, mbx);
1379 : 0 : break;
1380 : 0 : case FM10K_MSG_DATA:
1381 : 0 : err = fm10k_mbx_process_data(hw, mbx);
1382 : 0 : break;
1383 : 0 : case FM10K_MSG_DISCONNECT:
1384 : 0 : err = fm10k_mbx_process_disconnect(hw, mbx);
1385 : 0 : break;
1386 : 0 : case FM10K_MSG_ERROR:
1387 : 0 : err = fm10k_mbx_process_error(hw, mbx);
1388 : 0 : break;
1389 : : default:
1390 : : err = FM10K_MBX_ERR_TYPE;
1391 : : break;
1392 : : }
1393 : :
1394 : 0 : msg_err:
1395 : : /* notify partner of errors on our end */
1396 [ # # ]: 0 : if (err < 0)
1397 : 0 : fm10k_mbx_create_error_msg(mbx, err);
1398 : :
1399 : : /* copy data from mailbox */
1400 : 0 : fm10k_mbx_write(hw, mbx);
1401 : :
1402 : 0 : return err;
1403 : : }
1404 : :
1405 : : /**
1406 : : * fm10k_mbx_disconnect - Shutdown mailbox connection
1407 : : * @hw: pointer to hardware structure
1408 : : * @mbx: pointer to mailbox
1409 : : *
1410 : : * This function will shut down the mailbox. It places the mailbox first
1411 : : * in the disconnect state, it then allows up to a predefined timeout for
1412 : : * the mailbox to transition to close on its own. If this does not occur
1413 : : * then the mailbox will be forced into the closed state.
1414 : : *
1415 : : * Any mailbox transactions not completed before calling this function
1416 : : * are not guaranteed to complete and may be dropped.
1417 : : **/
1418 : 0 : STATIC void fm10k_mbx_disconnect(struct fm10k_hw *hw,
1419 : : struct fm10k_mbx_info *mbx)
1420 : : {
1421 [ # # ]: 0 : int timeout = mbx->timeout ? FM10K_MBX_DISCONNECT_TIMEOUT : 0;
1422 : :
1423 : 0 : DEBUGFUNC("fm10k_mbx_disconnect");
1424 : :
1425 : : /* Place mbx in ready to disconnect state */
1426 : 0 : mbx->state = FM10K_STATE_DISCONNECT;
1427 : :
1428 : : /* trigger interrupt to start shutdown process */
1429 : 0 : FM10K_WRITE_MBX(hw, mbx->mbx_reg, FM10K_MBX_REQ |
1430 : : FM10K_MBX_INTERRUPT_DISABLE);
1431 : : do {
1432 : 0 : usec_delay(FM10K_MBX_POLL_DELAY);
1433 : 0 : mbx->ops.process(hw, mbx);
1434 : 0 : timeout -= FM10K_MBX_POLL_DELAY;
1435 [ # # # # ]: 0 : } while ((timeout > 0) && (mbx->state != FM10K_STATE_CLOSED));
1436 : :
1437 : : /* in case we didn't close, just force the mailbox into shutdown and
1438 : : * drop all left over messages in the FIFO.
1439 : : */
1440 : : fm10k_mbx_connect_reset(mbx);
1441 : : fm10k_fifo_drop_all(&mbx->tx);
1442 : :
1443 : 0 : FM10K_WRITE_MBX(hw, mbx->mbmem_reg, 0);
1444 : 0 : }
1445 : :
1446 : : /**
1447 : : * fm10k_mbx_connect - Start mailbox connection
1448 : : * @hw: pointer to hardware structure
1449 : : * @mbx: pointer to mailbox
1450 : : *
1451 : : * This function will initiate a mailbox connection. It will populate the
1452 : : * mailbox with a broadcast connect message and then initialize the lock.
1453 : : * This is safe since the connect message is a single DWORD so the mailbox
1454 : : * transaction is guaranteed to be atomic.
1455 : : *
1456 : : * This function will return an error if the mailbox has not been initiated
1457 : : * or is currently in use.
1458 : : **/
1459 : 0 : STATIC s32 fm10k_mbx_connect(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx)
1460 : : {
1461 : 0 : DEBUGFUNC("fm10k_mbx_connect");
1462 : :
1463 : : /* we cannot connect an uninitialized mailbox */
1464 [ # # ]: 0 : if (!mbx->rx.buffer)
1465 : : return FM10K_MBX_ERR_NO_SPACE;
1466 : :
1467 : : /* we cannot connect an already connected mailbox */
1468 [ # # ]: 0 : if (mbx->state != FM10K_STATE_CLOSED)
1469 : : return FM10K_MBX_ERR_BUSY;
1470 : :
1471 : : /* mailbox timeout can now become active */
1472 : 0 : mbx->timeout = FM10K_MBX_INIT_TIMEOUT;
1473 : :
1474 : : /* Place mbx in ready to connect state */
1475 : 0 : mbx->state = FM10K_STATE_CONNECT;
1476 : :
1477 : 0 : fm10k_mbx_reset_work(mbx);
1478 : :
1479 : : /* initialize header of remote mailbox */
1480 : 0 : fm10k_mbx_create_fake_disconnect_hdr(mbx);
1481 : 0 : FM10K_WRITE_MBX(hw, mbx->mbmem_reg ^ mbx->mbmem_len, mbx->mbx_hdr);
1482 : :
1483 : : /* enable interrupt and notify other party of new message */
1484 : : mbx->mbx_lock = FM10K_MBX_REQ_INTERRUPT | FM10K_MBX_ACK_INTERRUPT |
1485 : : FM10K_MBX_INTERRUPT_ENABLE;
1486 : :
1487 : : /* generate and load connect header into mailbox */
1488 : : fm10k_mbx_create_connect_hdr(mbx);
1489 : 0 : fm10k_mbx_write(hw, mbx);
1490 : :
1491 : 0 : return FM10K_SUCCESS;
1492 : : }
1493 : :
1494 : : /**
1495 : : * fm10k_mbx_validate_handlers - Validate layout of message parsing data
1496 : : * @msg_data: handlers for mailbox events
1497 : : *
1498 : : * This function validates the layout of the message parsing data. This
1499 : : * should be mostly static, but it is important to catch any errors that
1500 : : * are made when constructing the parsers.
1501 : : **/
1502 : 0 : STATIC s32 fm10k_mbx_validate_handlers(const struct fm10k_msg_data *msg_data)
1503 : : {
1504 : : const struct fm10k_tlv_attr *attr;
1505 : : unsigned int id;
1506 : :
1507 : 0 : DEBUGFUNC("fm10k_mbx_validate_handlers");
1508 : :
1509 : : /* Allow NULL mailboxes that transmit but don't receive */
1510 [ # # ]: 0 : if (!msg_data)
1511 : : return FM10K_SUCCESS;
1512 : :
1513 [ # # ]: 0 : while (msg_data->id != FM10K_TLV_ERROR) {
1514 : : /* all messages should have a function handler */
1515 [ # # ]: 0 : if (!msg_data->func)
1516 : : return FM10K_ERR_PARAM;
1517 : :
1518 : : /* parser is optional */
1519 : 0 : attr = msg_data->attr;
1520 [ # # ]: 0 : if (attr) {
1521 [ # # ]: 0 : while (attr->id != FM10K_TLV_ERROR) {
1522 : : id = attr->id;
1523 : 0 : attr++;
1524 : : /* ID should always be increasing */
1525 [ # # ]: 0 : if (id >= attr->id)
1526 : : return FM10K_ERR_PARAM;
1527 : : /* ID should fit in results array */
1528 [ # # ]: 0 : if (id >= FM10K_TLV_RESULTS_MAX)
1529 : : return FM10K_ERR_PARAM;
1530 : : }
1531 : :
1532 : : /* verify terminator is in the list */
1533 : : if (attr->id != FM10K_TLV_ERROR)
1534 : : return FM10K_ERR_PARAM;
1535 : : }
1536 : :
1537 : : id = msg_data->id;
1538 : 0 : msg_data++;
1539 : : /* ID should always be increasing */
1540 [ # # ]: 0 : if (id >= msg_data->id)
1541 : : return FM10K_ERR_PARAM;
1542 : : }
1543 : :
1544 : : /* verify terminator is in the list */
1545 [ # # ]: 0 : if ((msg_data->id != FM10K_TLV_ERROR) || !msg_data->func)
1546 : 0 : return FM10K_ERR_PARAM;
1547 : :
1548 : : return FM10K_SUCCESS;
1549 : : }
1550 : :
1551 : : /**
1552 : : * fm10k_mbx_register_handlers - Register a set of handler ops for mailbox
1553 : : * @mbx: pointer to mailbox
1554 : : * @msg_data: handlers for mailbox events
1555 : : *
1556 : : * This function associates a set of message handling ops with a mailbox.
1557 : : **/
1558 : 0 : STATIC s32 fm10k_mbx_register_handlers(struct fm10k_mbx_info *mbx,
1559 : : const struct fm10k_msg_data *msg_data)
1560 : : {
1561 : 0 : DEBUGFUNC("fm10k_mbx_register_handlers");
1562 : :
1563 : : /* validate layout of handlers before assigning them */
1564 [ # # ]: 0 : if (fm10k_mbx_validate_handlers(msg_data))
1565 : : return FM10K_ERR_PARAM;
1566 : :
1567 : : /* initialize the message handlers */
1568 : 0 : mbx->msg_data = msg_data;
1569 : :
1570 : 0 : return FM10K_SUCCESS;
1571 : : }
1572 : :
1573 : : /**
1574 : : * fm10k_pfvf_mbx_init - Initialize mailbox memory for PF/VF mailbox
1575 : : * @hw: pointer to hardware structure
1576 : : * @mbx: pointer to mailbox
1577 : : * @msg_data: handlers for mailbox events
1578 : : * @id: ID reference for PF as it supports up to 64 PF/VF mailboxes
1579 : : *
1580 : : * This function initializes the mailbox for use. It will split the
1581 : : * buffer provided and use that to populate both the Tx and Rx FIFO by
1582 : : * evenly splitting it. In order to allow for easy masking of head/tail
1583 : : * the value reported in size must be a power of 2 and is reported in
1584 : : * DWORDs, not bytes. Any invalid values will cause the mailbox to return
1585 : : * error.
1586 : : **/
1587 : 0 : s32 fm10k_pfvf_mbx_init(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx,
1588 : : const struct fm10k_msg_data *msg_data, u8 id)
1589 : : {
1590 : 0 : DEBUGFUNC("fm10k_pfvf_mbx_init");
1591 : :
1592 : : /* initialize registers */
1593 [ # # # ]: 0 : switch (hw->mac.type) {
1594 : 0 : case fm10k_mac_vf:
1595 : 0 : mbx->mbx_reg = FM10K_VFMBX;
1596 : 0 : mbx->mbmem_reg = FM10K_VFMBMEM(FM10K_VFMBMEM_VF_XOR);
1597 : 0 : break;
1598 : 0 : case fm10k_mac_pf:
1599 : : /* there are only 64 VF <-> PF mailboxes */
1600 [ # # ]: 0 : if (id < 64) {
1601 : 0 : mbx->mbx_reg = FM10K_MBX(id);
1602 : 0 : mbx->mbmem_reg = FM10K_MBMEM_VF(id, 0);
1603 : 0 : break;
1604 : : }
1605 : : /* fallthough */
1606 : : default:
1607 : : return FM10K_MBX_ERR_NO_MBX;
1608 : : }
1609 : :
1610 : : /* start out in closed state */
1611 : 0 : mbx->state = FM10K_STATE_CLOSED;
1612 : :
1613 : : /* validate layout of handlers before assigning them */
1614 [ # # ]: 0 : if (fm10k_mbx_validate_handlers(msg_data))
1615 : : return FM10K_ERR_PARAM;
1616 : :
1617 : : /* initialize the message handlers */
1618 : 0 : mbx->msg_data = msg_data;
1619 : :
1620 : : /* start mailbox as timed out and let the reset_hw call
1621 : : * set the timeout value to begin communications
1622 : : */
1623 : 0 : mbx->timeout = 0;
1624 : 0 : mbx->usec_delay = FM10K_MBX_INIT_DELAY;
1625 : :
1626 : : /* initialize tail and head */
1627 : 0 : mbx->tail = 1;
1628 : 0 : mbx->head = 1;
1629 : :
1630 : : /* initialize CRC seeds */
1631 : 0 : mbx->local = FM10K_MBX_CRC_SEED;
1632 : 0 : mbx->remote = FM10K_MBX_CRC_SEED;
1633 : :
1634 : : /* Split buffer for use by Tx/Rx FIFOs */
1635 : 0 : mbx->max_size = FM10K_MBX_MSG_MAX_SIZE;
1636 : 0 : mbx->mbmem_len = FM10K_VFMBMEM_VF_XOR;
1637 : :
1638 : : /* initialize the FIFOs, sizes are in 4 byte increments */
1639 : 0 : fm10k_fifo_init(&mbx->tx, mbx->buffer, FM10K_MBX_TX_BUFFER_SIZE);
1640 : 0 : fm10k_fifo_init(&mbx->rx, &mbx->buffer[FM10K_MBX_TX_BUFFER_SIZE],
1641 : : FM10K_MBX_RX_BUFFER_SIZE);
1642 : :
1643 : : /* initialize function pointers */
1644 : 0 : mbx->ops.connect = fm10k_mbx_connect;
1645 : 0 : mbx->ops.disconnect = fm10k_mbx_disconnect;
1646 : 0 : mbx->ops.rx_ready = fm10k_mbx_rx_ready;
1647 : 0 : mbx->ops.tx_ready = fm10k_mbx_tx_ready;
1648 : 0 : mbx->ops.tx_complete = fm10k_mbx_tx_complete;
1649 : 0 : mbx->ops.enqueue_tx = fm10k_mbx_enqueue_tx;
1650 : 0 : mbx->ops.process = fm10k_mbx_process;
1651 : 0 : mbx->ops.register_handlers = fm10k_mbx_register_handlers;
1652 : :
1653 : 0 : return FM10K_SUCCESS;
1654 : : }
1655 : :
1656 : : /**
1657 : : * fm10k_sm_mbx_create_data_hdr - Generate a mailbox header for local FIFO
1658 : : * @mbx: pointer to mailbox
1659 : : *
1660 : : * This function returns a data mailbox header
1661 : : **/
1662 : : STATIC void fm10k_sm_mbx_create_data_hdr(struct fm10k_mbx_info *mbx)
1663 : : {
1664 [ # # ]: 0 : if (mbx->tail_len)
1665 : 0 : mbx->mbx_lock |= FM10K_MBX_REQ;
1666 : :
1667 : 0 : mbx->mbx_hdr = FM10K_MSG_HDR_FIELD_SET(mbx->tail, SM_TAIL) |
1668 : 0 : FM10K_MSG_HDR_FIELD_SET(mbx->remote, SM_VER) |
1669 : 0 : FM10K_MSG_HDR_FIELD_SET(mbx->head, SM_HEAD);
1670 : 0 : }
1671 : :
1672 : : /**
1673 : : * fm10k_sm_mbx_create_connect_hdr - Generate a mailbox header for local FIFO
1674 : : * @mbx: pointer to mailbox
1675 : : * @err: error flags to report if any
1676 : : *
1677 : : * This function returns a connection mailbox header
1678 : : **/
1679 : : STATIC void fm10k_sm_mbx_create_connect_hdr(struct fm10k_mbx_info *mbx, u8 err)
1680 : : {
1681 [ # # # # : 0 : if (mbx->local)
# # ]
1682 : 0 : mbx->mbx_lock |= FM10K_MBX_REQ;
1683 : :
1684 : 0 : mbx->mbx_hdr = FM10K_MSG_HDR_FIELD_SET(mbx->tail, SM_TAIL) |
1685 : 0 : FM10K_MSG_HDR_FIELD_SET(mbx->remote, SM_VER) |
1686 : 0 : FM10K_MSG_HDR_FIELD_SET(mbx->head, SM_HEAD) |
1687 : : FM10K_MSG_HDR_FIELD_SET(err, SM_ERR);
1688 : 0 : }
1689 : :
1690 : : /**
1691 : : * fm10k_sm_mbx_connect_reset - Reset following request for reset
1692 : : * @mbx: pointer to mailbox
1693 : : *
1694 : : * This function resets the mailbox to a just connected state
1695 : : **/
1696 : : STATIC void fm10k_sm_mbx_connect_reset(struct fm10k_mbx_info *mbx)
1697 : : {
1698 : : /* flush any uncompleted work */
1699 : 0 : fm10k_mbx_reset_work(mbx);
1700 : :
1701 : : /* set local version to max and remote version to 0 */
1702 : 0 : mbx->local = FM10K_SM_MBX_VERSION;
1703 : 0 : mbx->remote = 0;
1704 : :
1705 : : /* initialize tail and head */
1706 : 0 : mbx->tail = 1;
1707 : 0 : mbx->head = 1;
1708 : :
1709 : : /* reset state back to connect */
1710 : 0 : mbx->state = FM10K_STATE_CONNECT;
1711 : 0 : }
1712 : :
1713 : : /**
1714 : : * fm10k_sm_mbx_connect - Start switch manager mailbox connection
1715 : : * @hw: pointer to hardware structure
1716 : : * @mbx: pointer to mailbox
1717 : : *
1718 : : * This function will initiate a mailbox connection with the switch
1719 : : * manager. To do this it will first disconnect the mailbox, and then
1720 : : * reconnect it in order to complete a reset of the mailbox.
1721 : : *
1722 : : * This function will return an error if the mailbox has not been initiated
1723 : : * or is currently in use.
1724 : : **/
1725 : 0 : STATIC s32 fm10k_sm_mbx_connect(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx)
1726 : : {
1727 : 0 : DEBUGFUNC("fm10k_sm_mbx_connect");
1728 : :
1729 : : /* we cannot connect an uninitialized mailbox */
1730 [ # # ]: 0 : if (!mbx->rx.buffer)
1731 : : return FM10K_MBX_ERR_NO_SPACE;
1732 : :
1733 : : /* we cannot connect an already connected mailbox */
1734 [ # # ]: 0 : if (mbx->state != FM10K_STATE_CLOSED)
1735 : : return FM10K_MBX_ERR_BUSY;
1736 : :
1737 : : /* mailbox timeout can now become active */
1738 : 0 : mbx->timeout = FM10K_MBX_INIT_TIMEOUT;
1739 : :
1740 : : /* Place mbx in ready to connect state */
1741 : 0 : mbx->state = FM10K_STATE_CONNECT;
1742 : 0 : mbx->max_size = FM10K_MBX_MSG_MAX_SIZE;
1743 : :
1744 : : /* reset interface back to connect */
1745 : : fm10k_sm_mbx_connect_reset(mbx);
1746 : :
1747 : : /* enable interrupt and notify other party of new message */
1748 : : mbx->mbx_lock = FM10K_MBX_REQ_INTERRUPT | FM10K_MBX_ACK_INTERRUPT |
1749 : : FM10K_MBX_INTERRUPT_ENABLE;
1750 : :
1751 : : /* generate and load connect header into mailbox */
1752 : : fm10k_sm_mbx_create_connect_hdr(mbx, 0);
1753 : 0 : fm10k_mbx_write(hw, mbx);
1754 : :
1755 : 0 : return FM10K_SUCCESS;
1756 : : }
1757 : :
1758 : : /**
1759 : : * fm10k_sm_mbx_disconnect - Shutdown mailbox connection
1760 : : * @hw: pointer to hardware structure
1761 : : * @mbx: pointer to mailbox
1762 : : *
1763 : : * This function will shut down the mailbox. It places the mailbox first
1764 : : * in the disconnect state, it then allows up to a predefined timeout for
1765 : : * the mailbox to transition to close on its own. If this does not occur
1766 : : * then the mailbox will be forced into the closed state.
1767 : : *
1768 : : * Any mailbox transactions not completed before calling this function
1769 : : * are not guaranteed to complete and may be dropped.
1770 : : **/
1771 : 0 : STATIC void fm10k_sm_mbx_disconnect(struct fm10k_hw *hw,
1772 : : struct fm10k_mbx_info *mbx)
1773 : : {
1774 [ # # ]: 0 : int timeout = mbx->timeout ? FM10K_MBX_DISCONNECT_TIMEOUT : 0;
1775 : :
1776 : 0 : DEBUGFUNC("fm10k_sm_mbx_disconnect");
1777 : :
1778 : : /* Place mbx in ready to disconnect state */
1779 : 0 : mbx->state = FM10K_STATE_DISCONNECT;
1780 : :
1781 : : /* trigger interrupt to start shutdown process */
1782 : 0 : FM10K_WRITE_REG(hw, mbx->mbx_reg, FM10K_MBX_REQ |
1783 : : FM10K_MBX_INTERRUPT_DISABLE);
1784 : : do {
1785 : 0 : usec_delay(FM10K_MBX_POLL_DELAY);
1786 : 0 : mbx->ops.process(hw, mbx);
1787 : 0 : timeout -= FM10K_MBX_POLL_DELAY;
1788 [ # # # # ]: 0 : } while ((timeout > 0) && (mbx->state != FM10K_STATE_CLOSED));
1789 : :
1790 : : /* in case we didn't close just force the mailbox into shutdown */
1791 : 0 : mbx->state = FM10K_STATE_CLOSED;
1792 : 0 : mbx->remote = 0;
1793 : 0 : fm10k_mbx_reset_work(mbx);
1794 : : fm10k_fifo_drop_all(&mbx->tx);
1795 : :
1796 : 0 : FM10K_WRITE_REG(hw, mbx->mbmem_reg, 0);
1797 : 0 : }
1798 : :
1799 : : /**
1800 : : * fm10k_sm_mbx_validate_fifo_hdr - Validate fields in the remote FIFO header
1801 : : * @mbx: pointer to mailbox
1802 : : *
1803 : : * This function will parse up the fields in the mailbox header and return
1804 : : * an error if the header contains any of a number of invalid configurations
1805 : : * including unrecognized offsets or version numbers.
1806 : : **/
1807 : 0 : STATIC s32 fm10k_sm_mbx_validate_fifo_hdr(struct fm10k_mbx_info *mbx)
1808 : : {
1809 : : const u32 *hdr = &mbx->mbx_hdr;
1810 : : u16 tail, head, ver;
1811 : :
1812 : 0 : DEBUGFUNC("fm10k_sm_mbx_validate_fifo_hdr");
1813 : :
1814 : 0 : tail = FM10K_MSG_HDR_FIELD_GET(*hdr, SM_TAIL);
1815 : 0 : ver = FM10K_MSG_HDR_FIELD_GET(*hdr, SM_VER);
1816 : 0 : head = FM10K_MSG_HDR_FIELD_GET(*hdr, SM_HEAD);
1817 : :
1818 [ # # # ]: 0 : switch (ver) {
1819 : : case 0:
1820 : : break;
1821 : 0 : case FM10K_SM_MBX_VERSION:
1822 [ # # ]: 0 : if (!head || head > FM10K_SM_MBX_FIFO_LEN)
1823 : : return FM10K_MBX_ERR_HEAD;
1824 [ # # ]: 0 : if (!tail || tail > FM10K_SM_MBX_FIFO_LEN)
1825 : : return FM10K_MBX_ERR_TAIL;
1826 [ # # ]: 0 : if (mbx->tail < head)
1827 : 0 : head += mbx->mbmem_len - 1;
1828 [ # # ]: 0 : if (tail < mbx->head)
1829 : 0 : tail += mbx->mbmem_len - 1;
1830 [ # # ]: 0 : if (fm10k_mbx_index_len(mbx, head, mbx->tail) > mbx->tail_len)
1831 : : return FM10K_MBX_ERR_HEAD;
1832 [ # # ]: 0 : if (fm10k_mbx_index_len(mbx, mbx->head, tail) < mbx->mbmem_len)
1833 : : break;
1834 : : return FM10K_MBX_ERR_TAIL;
1835 : : default:
1836 : : return FM10K_MBX_ERR_SRC;
1837 : : }
1838 : :
1839 : : return FM10K_SUCCESS;
1840 : : }
1841 : :
1842 : : /**
1843 : : * fm10k_sm_mbx_process_error - Process header with error flag set
1844 : : * @mbx: pointer to mailbox
1845 : : *
1846 : : * This function is meant to respond to a request where the error flag
1847 : : * is set. As a result we will terminate a connection if one is present
1848 : : * and fall back into the reset state with a connection header of version
1849 : : * 0 (RESET).
1850 : : **/
1851 : 0 : STATIC void fm10k_sm_mbx_process_error(struct fm10k_mbx_info *mbx)
1852 : : {
1853 : 0 : const enum fm10k_mbx_state state = mbx->state;
1854 : :
1855 [ # # # # ]: 0 : switch (state) {
1856 : 0 : case FM10K_STATE_DISCONNECT:
1857 : : /* if there is an error just disconnect */
1858 : 0 : mbx->remote = 0;
1859 : 0 : break;
1860 : : case FM10K_STATE_OPEN:
1861 : : /* flush any uncompleted work */
1862 : : fm10k_sm_mbx_connect_reset(mbx);
1863 : : break;
1864 : 0 : case FM10K_STATE_CONNECT:
1865 : : /* try connnecting at lower version */
1866 [ # # ]: 0 : if (mbx->remote) {
1867 [ # # ]: 0 : while (mbx->local > 1)
1868 : 0 : mbx->local--;
1869 : 0 : mbx->remote = 0;
1870 : : }
1871 : : break;
1872 : : default:
1873 : : break;
1874 : : }
1875 : :
1876 : : fm10k_sm_mbx_create_connect_hdr(mbx, 0);
1877 : 0 : }
1878 : :
1879 : : /**
1880 : : * fm10k_sm_mbx_create_error_msg - Process an error in FIFO header
1881 : : * @mbx: pointer to mailbox
1882 : : * @err: local error encountered
1883 : : *
1884 : : * This function will interpret the error provided by err, and based on
1885 : : * that it may set the error bit in the local message header
1886 : : **/
1887 : 0 : STATIC void fm10k_sm_mbx_create_error_msg(struct fm10k_mbx_info *mbx, s32 err)
1888 : : {
1889 : : /* only generate an error message for these types */
1890 [ # # ]: 0 : switch (err) {
1891 : : case FM10K_MBX_ERR_TAIL:
1892 : : case FM10K_MBX_ERR_HEAD:
1893 : : case FM10K_MBX_ERR_SRC:
1894 : : case FM10K_MBX_ERR_SIZE:
1895 : : case FM10K_MBX_ERR_RSVD0:
1896 : : break;
1897 : : default:
1898 : : return;
1899 : : }
1900 : :
1901 : : /* process it as though we received an error, and send error reply */
1902 : 0 : fm10k_sm_mbx_process_error(mbx);
1903 : : fm10k_sm_mbx_create_connect_hdr(mbx, 1);
1904 : : }
1905 : :
1906 : : /**
1907 : : * fm10k_sm_mbx_receive - Take message from Rx mailbox FIFO and put it in Rx
1908 : : * @hw: pointer to hardware structure
1909 : : * @mbx: pointer to mailbox
1910 : : * @tail: tail index of message
1911 : : *
1912 : : * This function will dequeue one message from the Rx switch manager mailbox
1913 : : * FIFO and place it in the Rx mailbox FIFO for processing by software.
1914 : : **/
1915 : 0 : STATIC s32 fm10k_sm_mbx_receive(struct fm10k_hw *hw,
1916 : : struct fm10k_mbx_info *mbx,
1917 : : u16 tail)
1918 : : {
1919 : : /* reduce length by 1 to convert to a mask */
1920 : 0 : u16 mbmem_len = mbx->mbmem_len - 1;
1921 : : s32 err;
1922 : :
1923 : 0 : DEBUGFUNC("fm10k_sm_mbx_receive");
1924 : :
1925 : : /* push tail in front of head */
1926 [ # # ]: 0 : if (tail < mbx->head)
1927 : 0 : tail += mbmem_len;
1928 : :
1929 : : /* copy data to the Rx FIFO */
1930 : 0 : err = fm10k_mbx_push_tail(hw, mbx, tail);
1931 [ # # ]: 0 : if (err < 0)
1932 : : return err;
1933 : :
1934 : : /* process messages if we have received any */
1935 : 0 : fm10k_mbx_dequeue_rx(hw, mbx);
1936 : :
1937 : : /* guarantee head aligns with the end of the last message */
1938 [ # # ]: 0 : mbx->head = fm10k_mbx_head_sub(mbx, mbx->pushed);
1939 : 0 : mbx->pushed = 0;
1940 : :
1941 : : /* clear any extra bits left over since index adds 1 extra bit */
1942 [ # # ]: 0 : if (mbx->head > mbmem_len)
1943 : 0 : mbx->head -= mbmem_len;
1944 : :
1945 : : return err;
1946 : : }
1947 : :
1948 : : /**
1949 : : * fm10k_sm_mbx_transmit - Take message from Tx and put it in Tx mailbox FIFO
1950 : : * @hw: pointer to hardware structure
1951 : : * @mbx: pointer to mailbox
1952 : : * @head: head index of message
1953 : : *
1954 : : * This function will dequeue one message from the Tx mailbox FIFO and place
1955 : : * it in the Tx switch manager mailbox FIFO for processing by hardware.
1956 : : **/
1957 : 0 : STATIC void fm10k_sm_mbx_transmit(struct fm10k_hw *hw,
1958 : : struct fm10k_mbx_info *mbx, u16 head)
1959 : : {
1960 : : struct fm10k_mbx_fifo *fifo = &mbx->tx;
1961 : : /* reduce length by 1 to convert to a mask */
1962 : 0 : u16 mbmem_len = mbx->mbmem_len - 1;
1963 : : u16 tail_len, len = 0;
1964 : : u32 *msg;
1965 : :
1966 : 0 : DEBUGFUNC("fm10k_sm_mbx_transmit");
1967 : :
1968 : : /* push head behind tail */
1969 [ # # ]: 0 : if (mbx->tail < head)
1970 : 0 : head += mbmem_len;
1971 : :
1972 : 0 : fm10k_mbx_pull_head(hw, mbx, head);
1973 : :
1974 : : /* determine msg aligned offset for end of buffer */
1975 : : do {
1976 : 0 : msg = fifo->buffer + fm10k_fifo_head_offset(fifo, len);
1977 : : tail_len = len;
1978 : 0 : len += FM10K_TLV_DWORD_LEN(*msg);
1979 [ # # # # ]: 0 : } while ((len <= mbx->tail_len) && (len < mbmem_len));
1980 : :
1981 : : /* guarantee we stop on a message boundary */
1982 [ # # ]: 0 : if (mbx->tail_len > tail_len) {
1983 : 0 : mbx->tail = fm10k_mbx_tail_sub(mbx, mbx->tail_len - tail_len);
1984 : 0 : mbx->tail_len = tail_len;
1985 : : }
1986 : :
1987 : : /* clear any extra bits left over since index adds 1 extra bit */
1988 [ # # ]: 0 : if (mbx->tail > mbmem_len)
1989 : 0 : mbx->tail -= mbmem_len;
1990 : 0 : }
1991 : :
1992 : : /**
1993 : : * fm10k_sm_mbx_create_reply - Generate reply based on state and remote head
1994 : : * @hw: pointer to hardware structure
1995 : : * @mbx: pointer to mailbox
1996 : : * @head: acknowledgement number
1997 : : *
1998 : : * This function will generate an outgoing message based on the current
1999 : : * mailbox state and the remote FIFO head. It will return the length
2000 : : * of the outgoing message excluding header on success, and a negative value
2001 : : * on error.
2002 : : **/
2003 : 0 : STATIC void fm10k_sm_mbx_create_reply(struct fm10k_hw *hw,
2004 : : struct fm10k_mbx_info *mbx, u16 head)
2005 : : {
2006 [ # # # ]: 0 : switch (mbx->state) {
2007 : 0 : case FM10K_STATE_OPEN:
2008 : : case FM10K_STATE_DISCONNECT:
2009 : : /* flush out Tx data */
2010 : 0 : fm10k_sm_mbx_transmit(hw, mbx, head);
2011 : :
2012 : : /* generate new header based on data */
2013 [ # # # # ]: 0 : if (mbx->tail_len || (mbx->state == FM10K_STATE_OPEN)) {
2014 : : fm10k_sm_mbx_create_data_hdr(mbx);
2015 : : } else {
2016 [ # # ]: 0 : mbx->remote = 0;
2017 : : fm10k_sm_mbx_create_connect_hdr(mbx, 0);
2018 : : }
2019 : : break;
2020 : : case FM10K_STATE_CONNECT:
2021 : : case FM10K_STATE_CLOSED:
2022 : : fm10k_sm_mbx_create_connect_hdr(mbx, 0);
2023 : : break;
2024 : : default:
2025 : : break;
2026 : : }
2027 : 0 : }
2028 : :
2029 : : /**
2030 : : * fm10k_sm_mbx_process_reset - Process header with version == 0 (RESET)
2031 : : * @hw: pointer to hardware structure
2032 : : * @mbx: pointer to mailbox
2033 : : *
2034 : : * This function is meant to respond to a request where the version data
2035 : : * is set to 0. As such we will either terminate the connection or go
2036 : : * into the connect state in order to re-establish the connection. This
2037 : : * function can also be used to respond to an error as the connection
2038 : : * resetting would also be a means of dealing with errors.
2039 : : **/
2040 : 0 : STATIC s32 fm10k_sm_mbx_process_reset(struct fm10k_hw *hw,
2041 : : struct fm10k_mbx_info *mbx)
2042 : : {
2043 : : s32 err = FM10K_SUCCESS;
2044 : 0 : const enum fm10k_mbx_state state = mbx->state;
2045 : :
2046 [ # # # # ]: 0 : switch (state) {
2047 : 0 : case FM10K_STATE_DISCONNECT:
2048 : : /* drop remote connections and disconnect */
2049 : 0 : mbx->state = FM10K_STATE_CLOSED;
2050 : 0 : mbx->remote = 0;
2051 : 0 : mbx->local = 0;
2052 : 0 : break;
2053 : : case FM10K_STATE_OPEN:
2054 : : /* flush any incomplete work */
2055 : : fm10k_sm_mbx_connect_reset(mbx);
2056 : : err = FM10K_ERR_RESET_REQUESTED;
2057 : 0 : break;
2058 : 0 : case FM10K_STATE_CONNECT:
2059 : : /* Update remote value to match local value */
2060 : 0 : mbx->remote = mbx->local;
2061 : : default:
2062 : : break;
2063 : : }
2064 : :
2065 : 0 : fm10k_sm_mbx_create_reply(hw, mbx, mbx->tail);
2066 : :
2067 : 0 : return err;
2068 : : }
2069 : :
2070 : : /**
2071 : : * fm10k_sm_mbx_process_version_1 - Process header with version == 1
2072 : : * @hw: pointer to hardware structure
2073 : : * @mbx: pointer to mailbox
2074 : : *
2075 : : * This function is meant to process messages received when the remote
2076 : : * mailbox is active.
2077 : : **/
2078 : 0 : STATIC s32 fm10k_sm_mbx_process_version_1(struct fm10k_hw *hw,
2079 : : struct fm10k_mbx_info *mbx)
2080 : : {
2081 : : const u32 *hdr = &mbx->mbx_hdr;
2082 : : u16 head, tail;
2083 : : s32 len;
2084 : :
2085 : : /* pull all fields needed for verification */
2086 : 0 : tail = FM10K_MSG_HDR_FIELD_GET(*hdr, SM_TAIL);
2087 : 0 : head = FM10K_MSG_HDR_FIELD_GET(*hdr, SM_HEAD);
2088 : :
2089 : : /* if we are in connect and wanting version 1 then start up and go */
2090 [ # # ]: 0 : if (mbx->state == FM10K_STATE_CONNECT) {
2091 [ # # ]: 0 : if (!mbx->remote)
2092 : 0 : goto send_reply;
2093 [ # # ]: 0 : if (mbx->remote != 1)
2094 : : return FM10K_MBX_ERR_SRC;
2095 : :
2096 : 0 : mbx->state = FM10K_STATE_OPEN;
2097 : : }
2098 : :
2099 : : do {
2100 : : /* abort on message size errors */
2101 : 0 : len = fm10k_sm_mbx_receive(hw, mbx, tail);
2102 [ # # ]: 0 : if (len < 0)
2103 : 0 : return len;
2104 : :
2105 : : /* continue until we have flushed the Rx FIFO */
2106 [ # # ]: 0 : } while (len);
2107 : :
2108 : 0 : send_reply:
2109 : 0 : fm10k_sm_mbx_create_reply(hw, mbx, head);
2110 : :
2111 : 0 : return FM10K_SUCCESS;
2112 : : }
2113 : :
2114 : : /**
2115 : : * fm10k_sm_mbx_process - Process switch manager mailbox interrupt
2116 : : * @hw: pointer to hardware structure
2117 : : * @mbx: pointer to mailbox
2118 : : *
2119 : : * This function will process incoming mailbox events and generate mailbox
2120 : : * replies. It will return a value indicating the number of DWORDs
2121 : : * transmitted excluding header on success or a negative value on error.
2122 : : **/
2123 : 0 : STATIC s32 fm10k_sm_mbx_process(struct fm10k_hw *hw,
2124 : : struct fm10k_mbx_info *mbx)
2125 : : {
2126 : : s32 err;
2127 : :
2128 : 0 : DEBUGFUNC("fm10k_sm_mbx_process");
2129 : :
2130 : : /* we do not read mailbox if closed */
2131 [ # # ]: 0 : if (mbx->state == FM10K_STATE_CLOSED)
2132 : : return FM10K_SUCCESS;
2133 : :
2134 : : /* retrieve data from switch manager */
2135 : 0 : err = fm10k_mbx_read(hw, mbx);
2136 [ # # ]: 0 : if (err)
2137 : : return err;
2138 : :
2139 : 0 : err = fm10k_sm_mbx_validate_fifo_hdr(mbx);
2140 [ # # ]: 0 : if (err < 0)
2141 : 0 : goto fifo_err;
2142 : :
2143 [ # # ]: 0 : if (FM10K_MSG_HDR_FIELD_GET(mbx->mbx_hdr, SM_ERR)) {
2144 : 0 : fm10k_sm_mbx_process_error(mbx);
2145 : 0 : goto fifo_err;
2146 : : }
2147 : :
2148 [ # # # ]: 0 : switch (FM10K_MSG_HDR_FIELD_GET(mbx->mbx_hdr, SM_VER)) {
2149 : 0 : case 0:
2150 : 0 : err = fm10k_sm_mbx_process_reset(hw, mbx);
2151 : 0 : break;
2152 : 0 : case FM10K_SM_MBX_VERSION:
2153 : 0 : err = fm10k_sm_mbx_process_version_1(hw, mbx);
2154 : 0 : break;
2155 : : }
2156 : :
2157 : 0 : fifo_err:
2158 [ # # ]: 0 : if (err < 0)
2159 : 0 : fm10k_sm_mbx_create_error_msg(mbx, err);
2160 : :
2161 : : /* report data to switch manager */
2162 : 0 : fm10k_mbx_write(hw, mbx);
2163 : :
2164 : 0 : return err;
2165 : : }
2166 : :
2167 : : /**
2168 : : * fm10k_sm_mbx_init - Initialize mailbox memory for PF/SM mailbox
2169 : : * @hw: pointer to hardware structure
2170 : : * @mbx: pointer to mailbox
2171 : : * @msg_data: handlers for mailbox events
2172 : : *
2173 : : * This function initializes the PF/SM mailbox for use. It will split the
2174 : : * buffer provided and use that to populate both the Tx and Rx FIFO by
2175 : : * evenly splitting it. In order to allow for easy masking of head/tail
2176 : : * the value reported in size must be a power of 2 and is reported in
2177 : : * DWORDs, not bytes. Any invalid values will cause the mailbox to return
2178 : : * error.
2179 : : **/
2180 : 0 : s32 fm10k_sm_mbx_init(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx,
2181 : : const struct fm10k_msg_data *msg_data)
2182 : : {
2183 : 0 : DEBUGFUNC("fm10k_sm_mbx_init");
2184 : : UNREFERENCED_1PARAMETER(hw);
2185 : :
2186 : 0 : mbx->mbx_reg = FM10K_GMBX;
2187 : 0 : mbx->mbmem_reg = FM10K_MBMEM_PF(0);
2188 : :
2189 : : /* start out in closed state */
2190 : 0 : mbx->state = FM10K_STATE_CLOSED;
2191 : :
2192 : : /* validate layout of handlers before assigning them */
2193 [ # # ]: 0 : if (fm10k_mbx_validate_handlers(msg_data))
2194 : : return FM10K_ERR_PARAM;
2195 : :
2196 : : /* initialize the message handlers */
2197 : 0 : mbx->msg_data = msg_data;
2198 : :
2199 : : /* start mailbox as timed out and let the reset_hw call
2200 : : * set the timeout value to begin communications
2201 : : */
2202 : 0 : mbx->timeout = 0;
2203 : 0 : mbx->usec_delay = FM10K_MBX_INIT_DELAY;
2204 : :
2205 : : /* Split buffer for use by Tx/Rx FIFOs */
2206 : 0 : mbx->max_size = FM10K_MBX_MSG_MAX_SIZE;
2207 : 0 : mbx->mbmem_len = FM10K_MBMEM_PF_XOR;
2208 : :
2209 : : /* initialize the FIFOs, sizes are in 4 byte increments */
2210 : 0 : fm10k_fifo_init(&mbx->tx, mbx->buffer, FM10K_MBX_TX_BUFFER_SIZE);
2211 : 0 : fm10k_fifo_init(&mbx->rx, &mbx->buffer[FM10K_MBX_TX_BUFFER_SIZE],
2212 : : FM10K_MBX_RX_BUFFER_SIZE);
2213 : :
2214 : : /* initialize function pointers */
2215 : 0 : mbx->ops.connect = fm10k_sm_mbx_connect;
2216 : 0 : mbx->ops.disconnect = fm10k_sm_mbx_disconnect;
2217 : 0 : mbx->ops.rx_ready = fm10k_mbx_rx_ready;
2218 : 0 : mbx->ops.tx_ready = fm10k_mbx_tx_ready;
2219 : 0 : mbx->ops.tx_complete = fm10k_mbx_tx_complete;
2220 : 0 : mbx->ops.enqueue_tx = fm10k_mbx_enqueue_tx;
2221 : 0 : mbx->ops.process = fm10k_sm_mbx_process;
2222 : 0 : mbx->ops.register_handlers = fm10k_mbx_register_handlers;
2223 : :
2224 : 0 : return FM10K_SUCCESS;
2225 : : }
|