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