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