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