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