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