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