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