/
xhci.c
1763 lines (1563 loc) · 63.3 KB
/
xhci.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#include "xhci.h"
#include <common/kprint.h>
#include <debug/bug.h>
#include <common/spinlock.h>
#include <mm/mm.h>
#include <mm/slab.h>
#include <debug/traceback/traceback.h>
#include <common/time.h>
#include <exception/irq.h>
#include <driver/interrupt/apic/apic.h>
// 由于xhci寄存器读取需要对齐,因此禁用GCC优化选项
#pragma GCC optimize("O0")
spinlock_t xhci_controller_init_lock = {0}; // xhci控制器初始化锁(在usb_init中被初始化)
static int xhci_ctrl_count = 0; // xhci控制器计数
static struct xhci_host_controller_t xhci_hc[XHCI_MAX_HOST_CONTROLLERS] = {0};
void xhci_hc_irq_enable(uint64_t irq_num);
void xhci_hc_irq_disable(uint64_t irq_num);
uint64_t xhci_hc_irq_install(uint64_t irq_num, void *arg);
void xhci_hc_irq_uninstall(uint64_t irq_num);
static int xhci_hc_find_available_id();
static int xhci_hc_stop(int id);
static int xhci_hc_reset(int id);
static int xhci_hc_stop_legacy(int id);
static int xhci_hc_start_sched(int id);
static int xhci_hc_stop_sched(int id);
static uint32_t xhci_hc_get_protocol_offset(int id, uint32_t list_off, const int version, uint32_t *offset, uint32_t *count, uint16_t *protocol_flag);
static int xhci_hc_pair_ports(int id);
static uint64_t xhci_create_ring(int trbs);
static uint64_t xhci_create_event_ring(int trbs, uint64_t *ret_ring_addr);
void xhci_hc_irq_handler(uint64_t irq_num, uint64_t cid, struct pt_regs *regs);
static int xhci_hc_init_intr(int id);
static int xhci_hc_start_ports(int id);
static int xhci_send_command(int id, struct xhci_TRB_t *trb, const bool do_ring);
static uint64_t xhci_initialize_slot(const int id, const int slot_id, const int port, const int speed, const int max_packet);
static void xhci_initialize_ep(const int id, const uint64_t slot_vaddr, const int slot_id, const int ep_num, const int max_packet, const int type, const int direction, const int speed, const int ep_interval);
static int xhci_set_address(const int id, const uint64_t slot_vaddr, const int slot_id, const bool block);
static int xhci_control_in(const int id, void *target, const int in_size, const int slot_id, const int max_packet);
static int xhci_setup_stage(struct xhci_ep_ring_info_t *ep, const struct usb_request_packet_t *packet, const uint8_t direction);
static int xhci_data_stage(struct xhci_ep_ring_info_t *ep, uint64_t buf_vaddr, uint8_t trb_type, const uint32_t size, uint8_t direction, const int max_packet, const uint64_t status_vaddr);
static int xhci_status_stage(const int id, uint8_t direction, uint64_t status_buf_vaddr);
static int xhci_wait_for_interrupt(const int id, uint64_t status_vaddr);
static struct xhci_ep_context_t ep_ctx = {0};
struct xhci_slot_context_t slot_ctx = {0};
hardware_intr_controller xhci_hc_intr_controller =
{
.enable = xhci_hc_irq_enable,
.disable = xhci_hc_irq_disable,
.install = xhci_hc_irq_install,
.uninstall = xhci_hc_irq_uninstall,
.ack = apic_local_apic_edge_ack,
};
/*
注意!!!
尽管采用MMI/O的方式访问寄存器,但是对于指定大小的寄存器,
在发起读请求的时候,只能从寄存器的起始地址位置开始读取。
例子:不能在一个32bit的寄存器中的偏移量8的位置开始读取1个字节
这种情况下,我们必须从32bit的寄存器的0地址处开始读取32bit,然后通过移位的方式得到其中的字节。
*/
#define xhci_read_cap_reg32(id, offset) (__read4b(xhci_hc[id].vbase + (offset)))
#define xhci_get_ptr_cap_reg32(id, offset) ((uint32_t *)(xhci_hc[id].vbase + (offset)))
#define xhci_write_cap_reg32(id, offset, value) (__write4b(xhci_hc[id].vbase + (offset), (value)))
#define xhci_read_cap_reg64(id, offset) (__read8b(xhci_hc[id].vbase + (offset)))
#define xhci_get_ptr_reg64(id, offset) ((uint64_t *)(xhci_hc[id].vbase + (offset)))
#define xhci_write_cap_reg64(id, offset, value) (__write8b(xhci_hc[id].vbase + (offset), (value)))
#define xhci_read_op_reg8(id, offset) (*(uint8_t *)(xhci_hc[id].vbase_op + (offset)))
#define xhci_get_ptr_op_reg8(id, offset) ((uint8_t *)(xhci_hc[id].vbase_op + (offset)))
#define xhci_write_op_reg8(id, offset, value) (*(uint8_t *)(xhci_hc[id].vbase_op + (offset)) = (uint8_t)(value))
#define xhci_read_op_reg32(id, offset) (__read4b(xhci_hc[id].vbase_op + (offset)))
#define xhci_get_ptr_op_reg32(id, offset) ((uint32_t *)(xhci_hc[id].vbase_op + (offset)))
#define xhci_write_op_reg32(id, offset, value) (__write4b(xhci_hc[id].vbase_op + (offset), (value)))
#define xhci_read_op_reg64(id, offset) (__read8b(xhci_hc[id].vbase_op + (offset)))
#define xhci_get_ptr_op_reg64(id, offset) ((uint64_t *)(xhci_hc[id].vbase_op + (offset)))
#define xhci_write_op_reg64(id, offset, value) (__write8b(xhci_hc[id].vbase_op + (offset), (value)))
/**
* @brief 计算中断寄存器组虚拟地址
* @param id 主机控制器id
* @param num xhci中断寄存器组号
*/
#define xhci_calc_intr_vaddr(id, num) (xhci_hc[id].vbase + xhci_hc[id].rts_offset + XHCI_RT_IR0 + (num)*XHCI_IR_SIZE)
/**
* @brief 读取/写入中断寄存器
* @param id 主机控制器id
* @param num xhci中断寄存器组号
* @param intr_offset 寄存器在当前寄存器组中的偏移量
*/
#define xhci_read_intr_reg32(id, num, intr_offset) (__read4b(xhci_calc_intr_vaddr(id, num) + (intr_offset)))
#define xhci_write_intr_reg32(id, num, intr_offset, value) (__write4b(xhci_calc_intr_vaddr(id, num) + (intr_offset), (value)))
#define xhci_read_intr_reg64(id, num, intr_offset) (__read8b(xhci_calc_intr_vaddr(id, num) + (intr_offset)))
#define xhci_write_intr_reg64(id, num, intr_offset, value) (__write8b(xhci_calc_intr_vaddr(id, num) + (intr_offset), (value)))
#define xhci_is_aligned64(addr) (((addr)&0x3f) == 0) // 是否64bytes对齐
/**
* @brief 判断端口信息
* @param cid 主机控制器id
* @param pid 端口id
*/
#define XHCI_PORT_IS_USB2(cid, pid) ((xhci_hc[cid].ports[pid].flags & XHCI_PROTOCOL_INFO) == XHCI_PROTOCOL_USB2)
#define XHCI_PORT_IS_USB3(cid, pid) ((xhci_hc[cid].ports[pid].flags & XHCI_PROTOCOL_INFO) == XHCI_PROTOCOL_USB3)
#define XHCI_PORT_IS_USB2_HSO(cid, pid) ((xhci_hc[cid].ports[pid].flags & XHCI_PROTOCOL_HSO) == XHCI_PROTOCOL_HSO)
#define XHCI_PORT_HAS_PAIR(cid, pid) ((xhci_hc[cid].ports[pid].flags & XHCI_PROTOCOL_HAS_PAIR) == XHCI_PROTOCOL_HAS_PAIR)
#define XHCI_PORT_IS_ACTIVE(cid, pid) ((xhci_hc[cid].ports[pid].flags & XHCI_PROTOCOL_ACTIVE) == XHCI_PROTOCOL_ACTIVE)
/**
* @brief 设置link TRB的命令(dword3)
*
*/
#define xhci_TRB_set_link_cmd(trb_vaddr) \
do \
{ \
struct xhci_TRB_normal_t *ptr = (struct xhci_TRB_normal_t *)(trb_vaddr); \
ptr->TRB_type = TRB_TYPE_LINK; \
ptr->ioc = 0; \
ptr->chain = 0; \
ptr->ent = 0; \
ptr->cycle = 1; \
} while (0)
// 设置endpoint结构体的dequeue_cycle_state bit
#define xhci_ep_set_dequeue_cycle_state(ep_ctx_ptr, state) ((ep_ctx_ptr)->tr_dequeue_ptr |= ((state)&1))
// 获取endpoint结构体的dequeue_cycle_state bit
#define xhci_ep_get_dequeue_cycle_state(ep_ctx_ptr) (((ep_ctx_ptr)->tr_dequeue_ptr) & 1)
/**
* @brief 在controller数组之中寻找可用插槽
*
* 注意:该函数只能被获得init锁的进程所调用
* @return int 可用id(无空位时返回-1)
*/
static int xhci_hc_find_available_id()
{
if (unlikely(xhci_ctrl_count >= XHCI_MAX_HOST_CONTROLLERS))
return -1;
for (int i = 0; i < XHCI_MAX_HOST_CONTROLLERS; ++i)
{
if (xhci_hc[i].pci_dev_hdr == NULL)
return i;
}
return -1;
}
/**
* @brief 从指定地址读取trb
*
* @param trb 要存储到的trb的地址
* @param address 待读取trb的地址
*/
static __always_inline void xhci_get_trb(struct xhci_TRB_t *trb, const uint64_t address)
{
trb->param = __read8b(address);
trb->status = __read4b(address + 8);
trb->command = __read4b(address + 12);
}
/**
* @brief 将给定的trb写入指定的地址
*
* @param trb 源trb
* @param address 拷贝的目标地址
*/
static __always_inline void xhci_set_trb(struct xhci_TRB_t *trb, const uint64_t address)
{
__write8b(address, trb->param);
__write4b(address + 8, trb->status);
__write4b(address + 12, trb->command);
}
/**
* @brief 将ep结构体写入到设备上下文中的对应块内
*
* @param id 主机控制器id
* @param slot_vaddr 设备上下文虚拟地址
* @param ep_num ep结构体要写入到哪个块中(在设备上下文中的块号)
* @param ep 源数据
*/
static __always_inline void __write_ep(int id, uint64_t slot_vaddr, int ep_num, struct xhci_ep_context_t *ep)
{
memcpy((void *)(slot_vaddr + ep_num * xhci_hc[id].context_size), ep, sizeof(struct xhci_ep_context_t));
}
/**
* @brief 从设备上下文中的对应块内读取数据到ep结构体
*
* @param id 主机控制器id
* @param slot_vaddr 设备上下文虚拟地址
* @param ep_num 要从哪个块中读取(在设备上下文中的块号)
* @param ep 目标地址
*/
static __always_inline void __read_from_ep(int id, uint64_t slot_vaddr, int ep_num, struct xhci_ep_context_t *ep)
{
memcpy(ep, (void *)(slot_vaddr + ep_num * xhci_hc[id].context_size), sizeof(struct xhci_ep_context_t));
}
/**
* @brief 将slot上下文数组结构体写入插槽的上下文空间
*
* @param vaddr 目标地址
* @param slot_ctx slot上下文数组
*/
static __always_inline void __write_slot(const uint64_t vaddr, struct xhci_slot_context_t *slot_ctx)
{
memcpy((void *)vaddr, slot_ctx, sizeof(struct xhci_slot_context_t));
}
/**
* @brief 从指定地址读取slot context
*
* @param slot_ctx 目标地址
* @param slot_vaddr 源地址
* @return __always_inline
*/
static __always_inline void __read_from_slot(struct xhci_slot_context_t *slot_ctx, uint64_t slot_vaddr)
{
memcpy(slot_ctx, (void *)slot_vaddr, sizeof(struct xhci_slot_context_t));
}
/**
* @brief 写入doorbell寄存器
*
* @param id 主机控制器id
* @param slot_id usb控制器插槽id(0用作命令门铃,其他的用于具体的设备的门铃)
* @param value endpoint
*/
static __always_inline void __xhci_write_doorbell(const int id, const uint16_t slot_id, const uint32_t value)
{
// 确保写入门铃寄存器之前,所有的写操作均已完成
io_mfence();
xhci_write_cap_reg32(id, xhci_hc[id].db_offset + slot_id * sizeof(uint32_t), value);
io_mfence();
}
/**
* @brief 将trb写入指定的ring中,并更新下一个要写入的地址的值
*
* @param ep_info 端点信息结构体
* @param trb 待写入的trb
*/
static __always_inline void __xhci_write_trb(struct xhci_ep_ring_info_t *ep_info, struct xhci_TRB_t *trb)
{
memcpy((void *)ep_info->current_ep_ring_vaddr, trb, sizeof(struct xhci_TRB_t));
ep_info->current_ep_ring_vaddr += sizeof(struct xhci_TRB_t);
struct xhci_TRB_normal_t *ptr = (struct xhci_TRB_normal_t *)(ep_info->current_ep_ring_vaddr);
// ring到头了,转换cycle,然后回到第一个trb
if (unlikely(ptr->TRB_type == TRB_TYPE_LINK))
{
ptr->cycle = ep_info->current_ep_ring_cycle;
ep_info->current_ep_ring_vaddr = ep_info->ep_ring_vbase;
ep_info->current_ep_ring_cycle ^= 1;
}
}
/**
* @brief 停止xhci主机控制器
*
* @param id 主机控制器id
* @return int
*/
static int xhci_hc_stop(int id)
{
// 判断是否已经停止
if (unlikely((xhci_read_op_reg32(id, XHCI_OPS_USBSTS) & (1 << 0)) == 1))
return 0;
io_mfence();
xhci_write_op_reg32(id, XHCI_OPS_USBCMD, 0x00000000);
io_mfence();
char timeout = 17;
while ((xhci_read_op_reg32(id, XHCI_OPS_USBSTS) & (1 << 0)) == 0)
{
io_mfence();
usleep(1000);
if (--timeout == 0)
return -ETIMEDOUT;
}
return 0;
}
/**
* @brief reset xHCI主机控制器
*
* @param id 主机控制器id
* @return int
*/
static int xhci_hc_reset(int id)
{
int retval = 0;
io_mfence();
// 判断HCHalted是否置位
if ((xhci_read_op_reg32(id, XHCI_OPS_USBSTS) & (1 << 0)) == 0)
{
io_mfence();
kdebug("stopping usb hc...");
// 未置位,需要先尝试停止usb主机控制器
retval = xhci_hc_stop(id);
if (unlikely(retval))
return retval;
}
int timeout = 500; // wait 500ms
// reset
uint32_t cmd = xhci_read_op_reg32(id, XHCI_OPS_USBCMD);
io_mfence();
cmd |= (1 << 1);
xhci_write_op_reg32(id, XHCI_OPS_USBCMD, cmd);
io_mfence();
io_mfence();
while (xhci_read_op_reg32(id, XHCI_OPS_USBCMD) & (1 << 1))
{
io_mfence();
usleep(1000);
if (--timeout == 0)
return -ETIMEDOUT;
}
return retval;
}
/**
* @brief 停止指定xhci控制器的legacy support
*
* @param id 控制器id
* @return int
*/
static int xhci_hc_stop_legacy(int id)
{
uint64_t current_offset = xhci_hc[id].ext_caps_off;
do
{
// 判断当前entry是否为legacy support entry
if ((xhci_read_cap_reg32(id, current_offset) & 0xff) == XHCI_XECP_ID_LEGACY)
{
io_mfence();
// 接管控制权
xhci_write_cap_reg32(id, current_offset, xhci_read_cap_reg32(id, current_offset) | XHCI_XECP_LEGACY_OS_OWNED);
io_mfence();
// 等待响应完成
int timeout = XHCI_XECP_LEGACY_TIMEOUT;
while ((xhci_read_cap_reg32(id, current_offset) & XHCI_XECP_LEGACY_OWNING_MASK) != XHCI_XECP_LEGACY_OS_OWNED)
{
io_mfence();
usleep(1000);
if (--timeout == 0)
{
kerror("The BIOS doesn't stop legacy support.");
return -ETIMEDOUT;
}
}
// 处理完成
return 0;
}
io_mfence();
// 读取下一个entry的偏移增加量
int next_off = ((xhci_read_cap_reg32(id, current_offset) & 0xff00) >> 8) << 2;
io_mfence();
// 将指针跳转到下一个entry
current_offset = next_off ? (current_offset + next_off) : 0;
} while (current_offset);
// 当前controller不存在legacy支持,也问题不大,不影响
return 0;
}
/**
* @brief 启用指定xhci控制器的调度
*
* @param id 控制器id
* @return int
*/
static int xhci_hc_start_sched(int id)
{
io_mfence();
xhci_write_op_reg32(id, XHCI_OPS_USBCMD, (1 << 0) | (1 << 2) | (1 << 3));
io_mfence();
usleep(100 * 1000);
}
/**
* @brief 停止指定xhci控制器的调度
*
* @param id 控制器id
* @return int
*/
static int xhci_hc_stop_sched(int id)
{
io_mfence();
xhci_write_op_reg32(id, XHCI_OPS_USBCMD, 0x00);
io_mfence();
}
/**
* @brief 在Ex capability list中寻找符合指定的协议号的寄存器offset、count、flag信息
*
* @param id 主机控制器id
* @param list_off 列表项位置距离控制器虚拟基地址的偏移量
* @param version 要寻找的端口版本号(2或3)
* @param offset 返回的 Compatible Port Offset
* @param count 返回的 Compatible Port Count
* @param protocol_flag 返回的与协议相关的flag
* @return uint32_t 下一个列表项的偏移量
*/
static uint32_t xhci_hc_get_protocol_offset(int id, uint32_t list_off, const int version, uint32_t *offset, uint32_t *count, uint16_t *protocol_flag)
{
if (count)
*count = 0;
do
{
uint32_t dw0 = xhci_read_cap_reg32(id, list_off);
io_mfence();
uint32_t next_list_off = (dw0 >> 8) & 0xff;
next_list_off = next_list_off ? (list_off + (next_list_off << 2)) : 0;
if ((dw0 & 0xff) == XHCI_XECP_ID_PROTOCOL && ((dw0 & 0xff000000) >> 24) == version)
{
uint32_t dw2 = xhci_read_cap_reg32(id, list_off + 8);
io_mfence();
if (offset != NULL)
*offset = (uint32_t)(dw2 & 0xff) - 1; // 使其转换为zero based
if (count != NULL)
*count = (uint32_t)((dw2 & 0xff00) >> 8);
if (protocol_flag != NULL && version == 2)
*protocol_flag = (uint16_t)((dw2 >> 16) & 0x0fff);
return next_list_off;
}
list_off = next_list_off;
} while (list_off);
return 0;
}
/**
* @brief 配对xhci主机控制器的usb2、usb3端口
*
* @param id 主机控制器id
* @return int 返回码
*/
static int xhci_hc_pair_ports(int id)
{
struct xhci_caps_HCSPARAMS1_reg_t hcs1;
io_mfence();
memcpy(&hcs1, xhci_get_ptr_cap_reg32(id, XHCI_CAPS_HCSPARAMS1), sizeof(struct xhci_caps_HCSPARAMS1_reg_t));
io_mfence();
// 从hcs1获取端口数量
xhci_hc[id].port_num = hcs1.max_ports;
// 找到所有的端口并标记其端口信息
xhci_hc[id].port_num_u2 = 0;
xhci_hc[id].port_num_u3 = 0;
uint32_t next_off = xhci_hc[id].ext_caps_off;
uint32_t offset, cnt;
uint16_t protocol_flags = 0;
// 寻找所有的usb2端口
while (next_off)
{
io_mfence();
next_off = xhci_hc_get_protocol_offset(id, next_off, 2, &offset, &cnt, &protocol_flags);
io_mfence();
if (cnt)
{
for (int i = 0; i < cnt; ++i)
{
io_mfence();
xhci_hc[id].ports[offset + i].offset = xhci_hc[id].port_num_u2++;
xhci_hc[id].ports[offset + i].flags = XHCI_PROTOCOL_USB2;
io_mfence();
// usb2 high speed only
if (protocol_flags & 2)
xhci_hc[id].ports[offset + i].flags |= XHCI_PROTOCOL_HSO;
}
}
}
// 寻找所有的usb3端口
next_off = xhci_hc[id].ext_caps_off;
while (next_off)
{
io_mfence();
next_off = xhci_hc_get_protocol_offset(id, next_off, 3, &offset, &cnt, &protocol_flags);
io_mfence();
if (cnt)
{
for (int i = 0; i < cnt; ++i)
{
io_mfence();
xhci_hc[id].ports[offset + i].offset = xhci_hc[id].port_num_u3++;
xhci_hc[id].ports[offset + i].flags = XHCI_PROTOCOL_USB3;
}
}
}
// 将对应的USB2端口和USB3端口进行配对
for (int i = 0; i < xhci_hc[id].port_num; ++i)
{
for (int j = 0; j < xhci_hc[id].port_num; ++j)
{
if (unlikely(i == j))
continue;
io_mfence();
if ((xhci_hc[id].ports[i].offset == xhci_hc[id].ports[j].offset) &&
((xhci_hc[id].ports[i].flags & XHCI_PROTOCOL_INFO) != (xhci_hc[id].ports[j].flags & XHCI_PROTOCOL_INFO)))
{
xhci_hc[id].ports[i].paired_port_num = j;
xhci_hc[id].ports[i].flags |= XHCI_PROTOCOL_HAS_PAIR;
io_mfence();
xhci_hc[id].ports[j].paired_port_num = i;
xhci_hc[id].ports[j].flags |= XHCI_PROTOCOL_HAS_PAIR;
}
}
}
// 标记所有的usb3、单独的usb2端口为激活状态
for (int i = 0; i < xhci_hc[id].port_num; ++i)
{
io_mfence();
if (XHCI_PORT_IS_USB3(id, i) ||
(XHCI_PORT_IS_USB2(id, i) && (!XHCI_PORT_HAS_PAIR(id, i))))
xhci_hc[id].ports[i].flags |= XHCI_PROTOCOL_ACTIVE;
}
kinfo("Found %d ports on root hub, usb2 ports:%d, usb3 ports:%d", xhci_hc[id].port_num, xhci_hc[id].port_num_u2, xhci_hc[id].port_num_u3);
/*
// 打印配对结果
for (int i = 1; i <= xhci_hc[id].port_num; ++i)
{
if (XHCI_PORT_IS_USB3(id, i))
{
kdebug("USB3 port %d, offset=%d, pair with usb2 port %d, current port is %s", i, xhci_hc[id].ports[i].offset,
xhci_hc[id].ports[i].paired_port_num, XHCI_PORT_IS_ACTIVE(id, i) ? "active" : "inactive");
}
else if (XHCI_PORT_IS_USB2(id, i) && (!XHCI_PORT_HAS_PAIR(id, i))) // 单独的2.0接口
{
kdebug("Stand alone USB2 port %d, offset=%d, current port is %s", i, xhci_hc[id].ports[i].offset,
XHCI_PORT_IS_ACTIVE(id, i) ? "active" : "inactive");
}
else if (XHCI_PORT_IS_USB2(id, i))
{
kdebug("USB2 port %d, offset=%d, current port is %s, has pair=%s", i, xhci_hc[id].ports[i].offset,
XHCI_PORT_IS_ACTIVE(id, i) ? "active" : "inactive", XHCI_PORT_HAS_PAIR(id, i) ? "true" : "false");
}
}
*/
return 0;
}
/**
* @brief 创建ring,并将最后一个trb指向头一个trb
*
* @param trbs 要创建的trb数量
* @return uint64_t trb数组的起始虚拟地址
*/
static uint64_t xhci_create_ring(int trbs)
{
int total_size = trbs * sizeof(struct xhci_TRB_t);
const uint64_t vaddr = (uint64_t)kmalloc(total_size, 0);
io_mfence();
memset((void *)vaddr, 0, total_size);
io_mfence();
// 设置最后一个trb为link trb
xhci_TRB_set_link_cmd(vaddr + total_size - sizeof(struct xhci_TRB_t));
io_mfence();
return vaddr;
}
/**
* @brief 创建新的event ring table和对应的ring segment
*
* @param trbs 包含的trb的数量
* @param ret_ring_addr 返回的第一个event ring segment的基地址(虚拟)
* @return uint64_t trb table的虚拟地址
*/
static uint64_t xhci_create_event_ring(int trbs, uint64_t *ret_ring_addr)
{
const uint64_t table_vaddr = (const uint64_t)kmalloc(64, 0); // table支持8个segment
io_mfence();
if (unlikely(table_vaddr == NULL))
return -ENOMEM;
memset((void *)table_vaddr, 0, 64);
// 暂时只创建1个segment
const uint64_t seg_vaddr = (const uint64_t)kmalloc(trbs * sizeof(struct xhci_TRB_t), 0);
io_mfence();
if (unlikely(seg_vaddr == NULL))
return -ENOMEM;
memset((void *)seg_vaddr, 0, trbs * sizeof(struct xhci_TRB_t));
io_mfence();
// 将segment地址和大小写入table
*(uint64_t *)(table_vaddr) = virt_2_phys(seg_vaddr);
*(uint64_t *)(table_vaddr + 8) = trbs;
*ret_ring_addr = seg_vaddr;
return table_vaddr;
}
void xhci_hc_irq_enable(uint64_t irq_num)
{
int cid = xhci_find_hcid_by_irq_num(irq_num);
io_mfence();
if (WARN_ON(cid == -1))
return;
io_mfence();
pci_start_msi(xhci_hc[cid].pci_dev_hdr);
io_mfence();
xhci_hc_start_sched(cid);
io_mfence();
xhci_hc_start_ports(cid);
}
void xhci_hc_irq_disable(uint64_t irq_num)
{
int cid = xhci_find_hcid_by_irq_num(irq_num);
io_mfence();
if (WARN_ON(cid == -1))
return;
xhci_hc_stop_sched(cid);
io_mfence();
pci_disable_msi(xhci_hc[cid].pci_dev_hdr);
io_mfence();
}
/**
* @brief xhci中断的安装函数
*
* @param irq_num 要安装的中断向量号
* @param arg 参数
* @return uint64_t 错误码
*/
uint64_t xhci_hc_irq_install(uint64_t irq_num, void *arg)
{
int cid = xhci_find_hcid_by_irq_num(irq_num);
io_mfence();
if (WARN_ON(cid == -1))
return -EINVAL;
struct xhci_hc_irq_install_info_t *info = (struct xhci_hc_irq_install_info_t *)arg;
struct msi_desc_t msi_desc;
memset(&msi_desc, 0, sizeof(struct msi_desc_t));
io_mfence();
msi_desc.irq_num = irq_num;
msi_desc.msi_index = 0;
msi_desc.pci_dev = (struct pci_device_structure_header_t *)xhci_hc[cid].pci_dev_hdr;
msi_desc.assert = info->assert;
msi_desc.edge_trigger = info->edge_trigger;
msi_desc.processor = info->processor;
msi_desc.pci.msi_attribute.is_64 = 1;
msi_desc.pci.msi_attribute.is_msix = 1;
io_mfence();
int retval = pci_enable_msi(&msi_desc);
return 0;
}
void xhci_hc_irq_uninstall(uint64_t irq_num)
{
// todo
int cid = xhci_find_hcid_by_irq_num(irq_num);
io_mfence();
if (WARN_ON(cid == -1))
return;
xhci_hc_stop(cid);
io_mfence();
}
/**
* @brief xhci主机控制器的中断处理函数
*
* @param irq_num 中断向量号
* @param cid 控制器号
* @param regs 寄存器值
*/
void xhci_hc_irq_handler(uint64_t irq_num, uint64_t cid, struct pt_regs *regs)
{
// kdebug("USB irq received.");
/*
写入usb status寄存器,以表明当前收到了中断,清除usb status寄存器中的EINT位
需要先清除这个位,再清除interrupter中的pending bit)
*/
xhci_write_op_reg32(cid, XHCI_OPS_USBSTS, xhci_read_op_reg32(cid, XHCI_OPS_USBSTS));
// 读取第0个usb interrupter的intr management寄存器
const uint32_t iman0 = xhci_read_intr_reg32(cid, 0, XHCI_IR_MAN);
uint64_t dequeue_reg = xhci_read_intr_reg64(cid, 0, XHCI_IR_DEQUEUE);
if (((iman0 & 3) == 3) || (dequeue_reg & 8)) // 中断被启用,且pending不为0
{
// 写入1以清除该interrupter的pending bit
xhci_write_intr_reg32(cid, 0, XHCI_IR_MAN, iman0 | 3);
io_mfence();
struct xhci_TRB_t event_trb, origin_trb; // event ring trb以及其对应的command trb
uint64_t origin_vaddr;
// 暂存当前trb的起始地址
uint64_t last_event_ring_vaddr = xhci_hc[cid].current_event_ring_vaddr;
xhci_get_trb(&event_trb, xhci_hc[cid].current_event_ring_vaddr);
while ((event_trb.command & 1) == xhci_hc[cid].current_event_ring_cycle) // 循环处理处于当前周期的所有event ring
{
struct xhci_TRB_cmd_complete_t *event_trb_ptr = (struct xhci_TRB_cmd_complete_t *)&event_trb;
if ((event_trb.command & (1 << 2)) == 0) // 当前event trb不是由于short packet产生的
{
switch (event_trb_ptr->code) // 判断它的完成码
{
case TRB_COMP_TRB_SUCCESS: // trb执行成功,则将结果返回到对应的command ring的trb里面
switch (event_trb_ptr->TRB_type) // 根据event trb类型的不同,采取不同的措施
{
case TRB_TYPE_COMMAND_COMPLETION: // 命令已经完成
origin_vaddr = (uint64_t)phys_2_virt(event_trb.param);
// 获取对应的command trb
xhci_get_trb(&origin_trb, origin_vaddr);
switch (((struct xhci_TRB_normal_t *)&origin_trb)->TRB_type)
{
case TRB_TYPE_ENABLE_SLOT: // 源命令为enable slot
// 将slot id返回到命令TRB的command字段中
origin_trb.command &= 0x00ffffff;
origin_trb.command |= (event_trb.command & 0xff000000);
origin_trb.status = event_trb.status;
break;
default:
origin_trb.status = event_trb.status;
break;
}
// 标记该命令已经执行完成
origin_trb.status |= XHCI_IRQ_DONE;
// 将command trb写入到表中
xhci_set_trb(&origin_trb, origin_vaddr);
// kdebug("set origin:%#018lx", origin_vaddr);
break;
}
break;
default:
break;
}
}
else // 当前TRB是由short packet产生的
{
switch (event_trb_ptr->TRB_type)
{
case TRB_TYPE_TRANS_EVENT: // 当前 event trb是 transfer event TRB
// If SPD was encountered in this TD, comp_code will be SPD, else it should be SUCCESS (specs 4.10.1.1)
__write4b((uint64_t)phys_2_virt(event_trb.param), (event_trb.status | XHCI_IRQ_DONE)); // return code + bytes *not* transferred
break;
default:
break;
}
}
// 获取下一个event ring TRB
last_event_ring_vaddr = xhci_hc[cid].current_event_ring_vaddr;
xhci_hc[cid].current_event_ring_vaddr += sizeof(struct xhci_TRB_t);
xhci_get_trb(&event_trb, xhci_hc[cid].current_event_ring_vaddr);
if (((struct xhci_TRB_normal_t *)&event_trb)->TRB_type == TRB_TYPE_LINK)
{
xhci_hc[cid].current_event_ring_vaddr = xhci_hc[cid].event_ring_vaddr;
xhci_get_trb(&event_trb, xhci_hc[cid].current_event_ring_vaddr);
}
}
// 当前event ring cycle的TRB处理结束
// 更新dequeue指针, 并清除event handler busy标志位
xhci_write_intr_reg64(cid, 0, XHCI_IR_DEQUEUE, virt_2_phys(last_event_ring_vaddr) | (1 << 3));
io_mfence();
}
}
/**
* @brief 重置端口
*
* @param id 控制器id
* @param port 端口id
* @return int
*/
static int xhci_reset_port(const int id, const int port)
{
int retval = 0;
// 相对于op寄存器基地址的偏移量
uint64_t port_status_offset = XHCI_OPS_PRS + port * 16;
// kdebug("to reset %d, portsc=%#010lx", port, (xhci_read_op_reg32(id, port_status_offset + XHCI_PORT_PORTSC)));
// kdebug("to reset %d, usbcmd=%#010lx", port, xhci_read_op_reg32(id, XHCI_OPS_USBCMD));
// kdebug("to reset %d, usbsts=%#010lx", port, xhci_read_op_reg32(id, XHCI_OPS_USBSTS));
io_mfence();
// 检查端口电源状态
if ((xhci_read_op_reg32(id, port_status_offset + XHCI_PORT_PORTSC) & (1 << 9)) == 0)
{
kdebug("port is power off, starting...");
io_mfence();
xhci_write_cap_reg32(id, port_status_offset + XHCI_PORT_PORTSC, (1 << 9));
io_mfence();
usleep(2000);
// 检测端口是否被启用, 若未启用,则报错
if ((xhci_read_op_reg32(id, port_status_offset + XHCI_PORT_PORTSC) & (1 << 9)) == 0)
{
kdebug("cannot power on %d", port);
return -EAGAIN;
}
}
// kdebug("port:%d, power check ok", port);
io_mfence();
// 确保端口的status被清0
xhci_write_op_reg32(id, port_status_offset + XHCI_PORT_PORTSC, (1 << 9) | XHCI_PORTUSB_CHANGE_BITS);
// kdebug("to reset timeout;");
io_mfence();
// 重置当前端口
if (XHCI_PORT_IS_USB3(id, port))
xhci_write_op_reg32(id, port_status_offset + XHCI_PORT_PORTSC, (1 << 9) | (1 << 31));
else
xhci_write_op_reg32(id, port_status_offset + XHCI_PORT_PORTSC, (1 << 9) | (1 << 4));
retval = -ETIMEDOUT;
// kdebug("to wait reset timeout;");
// 等待portsc的port reset change位被置位,说明reset完成
int timeout = 200;
while (timeout)
{
io_mfence();
uint32_t val = xhci_read_op_reg32(id, port_status_offset + XHCI_PORT_PORTSC);
// kdebug("val=%#010lx", val);
io_mfence();
if (XHCI_PORT_IS_USB3(id, port) && (val & (1 << 31)) == 0)
break;
else if (XHCI_PORT_IS_USB2(id, port) && (val & (1 << 4)) == 0)
break;
else if (val & (1 << 21))
break;
--timeout;
usleep(500);
}
// kdebug("timeout= %d", timeout);
if (timeout > 0)
{
// 等待恢复
usleep(USB_TIME_RST_REC * 100);
// kdebug("to check if reset ok");
uint32_t val = xhci_read_op_reg32(id, port_status_offset + XHCI_PORT_PORTSC);
io_mfence();
// 如果reset之后,enable bit仍然是1,那么说明reset成功
if (val & (1 << 1))
{
// kdebug("reset ok");
retval = 0;
io_mfence();
// 清除status change bit
xhci_write_op_reg32(id, port_status_offset + XHCI_PORT_PORTSC, (1 << 9) | XHCI_PORTUSB_CHANGE_BITS);
io_mfence();
}
else
retval = -1;
}
// kdebug("reset ok!");
// 如果usb2端口成功reset,则处理该端口的active状态
if (retval == 0 && XHCI_PORT_IS_USB2(id, port))
{
xhci_hc[id].ports[port].flags |= XHCI_PROTOCOL_ACTIVE;
if (XHCI_PORT_HAS_PAIR(id, port)) // 如果有对应的usb3端口,则将usb3端口设置为未激活
xhci_hc[id].ports[xhci_hc[id].ports[port].paired_port_num].flags &= ~(XHCI_PROTOCOL_ACTIVE);
}
// 如果usb3端口reset失败,则启用与之配对的usb2端口
if (retval != 0 && XHCI_PORT_IS_USB3(id, port))
{
xhci_hc[id].ports[port].flags &= ~XHCI_PROTOCOL_ACTIVE;
xhci_hc[id].ports[xhci_hc[id].ports[port].paired_port_num].flags |= XHCI_PROTOCOL_ACTIVE;
}
return retval;
}
/**
* @brief 初始化设备slot的上下文,并将其写入dcbaap中的上下文index数组
* - at this time, we don't know if the device is a hub or not, so we don't
* set the slot->hub, ->mtt, ->ttt, ->etc, items.
*
* @param id 控制器id
* @param slot_id enable_slot命令分配的插槽id
* @param port 端口号
* @param speed 端口速度
* @param max_packet 最大数据包大小
* @return uint64_t 初始化好的设备上下文空间的虚拟地址
*/
static uint64_t xhci_initialize_slot(const int id, const int slot_id, const int port, const int speed, const int max_packet)
{
// 暂时只初始化slot和control EP0
// 申请上下文数据结构所占用的内存空间
uint64_t device_context_vaddr = (uint64_t)kzalloc(xhci_hc[id].context_size * 2, 0);
// kdebug("slot id=%d, device_context_vaddr=%#018lx, port=%d", slot_id, device_context_vaddr, port);
// 写到数组中
__write8b(xhci_hc[id].dcbaap_vaddr + (slot_id * sizeof(uint64_t)), virt_2_phys(device_context_vaddr));
slot_ctx.entries = 1;
slot_ctx.speed = speed;
slot_ctx.route_string = 0;
slot_ctx.rh_port_num = port + 1; // 由于xhci控制器是1-base的,因此把驱动程序中存储的端口号加1,才是真实的端口号
slot_ctx.max_exit_latency = 0; // 稍后会计算这个值
slot_ctx.int_target = 0; // 当前全部使用第0个interrupter
slot_ctx.slot_state = XHCI_SLOT_STATE_DISABLED_OR_ENABLED;
slot_ctx.device_address = 0;
// 将slot信息写入上下文空间
__write_slot(device_context_vaddr, &slot_ctx);
xhci_initialize_ep(id, device_context_vaddr, slot_id, XHCI_EP_CONTROL, max_packet, USB_EP_CONTROL, 0, speed, 0);
return device_context_vaddr;
}
/**
* @brief 初始化endpoint
*
* @param id 控制器id
* @param slot_vaddr slot上下文的虚拟地址
* @param slot_id 插槽id
* @param ep_num 端点上下文在slot上下文区域内的编号
* @param max_packet 最大数据包大小
* @param type 端点类型
* @param direction 传输方向
* @param speed 传输速度
* @param ep_interval 端点的连续请求间隔
*/
static void xhci_initialize_ep(const int id, const uint64_t slot_vaddr, const int slot_id, const int ep_num, const int max_packet, const int type, const int direction, const int speed, const int ep_interval)
{
// 由于目前只实现获取设备的描述符,因此暂时只支持control ep
if (type != USB_EP_CONTROL)
return;
memset(&ep_ctx, 0, sizeof(struct xhci_ep_context_t));
xhci_hc[id].control_ep_info.ep_ring_vbase = xhci_create_ring(XHCI_TRBS_PER_RING);
// 申请ep的 transfer ring
ep_ctx.tr_dequeue_ptr = virt_2_phys(xhci_hc[id].control_ep_info.ep_ring_vbase);
xhci_ep_set_dequeue_cycle_state(&ep_ctx, XHCI_TRB_CYCLE_ON);
xhci_hc[id].control_ep_info.current_ep_ring_vaddr = xhci_hc[id].control_ep_info.ep_ring_vbase;
xhci_hc[id].control_ep_info.current_ep_ring_cycle = xhci_ep_get_dequeue_cycle_state(&ep_ctx);
// kdebug("ep_ctx.tr_dequeue_ptr = %#018lx", ep_ctx.tr_dequeue_ptr);
// kdebug("xhci_hc[id].control_ep_info.current_ep_ring_cycle = %d", xhci_hc[id].control_ep_info.current_ep_ring_cycle);
// 设置初始值
ep_ctx.max_packet_size = max_packet;
ep_ctx.linear_stream_array = 0;
ep_ctx.max_primary_streams = 0;
ep_ctx.mult = 0;
ep_ctx.ep_state = XHCI_EP_STATE_DISABLED;
ep_ctx.hid = 0;
ep_ctx.ep_type = 4;
ep_ctx.average_trb_len = 8; // 所有的control ep的该值均为8
ep_ctx.err_cnt = 3;
ep_ctx.max_burst_size = 0;
ep_ctx.interval = ep_interval;
// 将ep的信息写入到slot上下文中对应的ep的块中
__write_ep(id, slot_vaddr, ep_num, &ep_ctx);
}
/**
* @brief 向usb控制器发送 address_device命令
*
* @param id 主机控制器id
* @param slot_vaddr 插槽上下文的虚拟基地址
* @param slot_id 插槽id