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
|
/*
* This file and its contents are supplied under the terms of the
* Common Development and Distribution License ("CDDL"), version 1.0.
* You may only use this file in accordance with the terms of version
* 1.0 of the CDDL.
*
* A full copy of the text of the CDDL should have accompanied this
* source. A copy of the CDDL is also available via the Internet at
* http://www.illumos.org/license/CDDL.
*/
/*
* Copyright (c) 2018, Joyent, Inc.
* Copyright (c) 2019 by Western Digital Corporation
* Copyright 2022 Oxide Computer Company
*/
#ifndef _SYS_USB_XHCI_XHCI_H
#define _SYS_USB_XHCI_XHCI_H
/*
* Extensible Host Controller Interface (xHCI) USB Driver
*/
#include <sys/conf.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/taskq_impl.h>
#include <sys/sysmacros.h>
#include <sys/usb/hcd/xhci/xhcireg.h>
#include <sys/usb/usba.h>
#include <sys/usb/usba/hcdi.h>
#include <sys/usb/hubd/hub.h>
#include <sys/usb/usba/hubdi.h>
#include <sys/usb/hubd/hubdvar.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* The base segment for DMA attributes was determined to be 4k based on xHCI 1.1
* / table 54: Data Structure Max Size, Boundary, and Alignment Requirement
* Summary. This indicates that the required alignment for most things is
* PAGESIZE, which in our current implementation is required to be 4K. We
* provide the ring segment value below for the things which need 64K alignment
*
* Similarly, in the same table, the maximum required alignment is 64 bytes,
* hence we use that for everything.
*
* Next is the scatter/gather lengths. For most of the data structures, we only
* want to have a single SGL entry, e.g. just a simple flat mapping. For many of
* our transfers, we use the same logic to simplify the implementation of the
* driver. However, for bulk transfers, which are the largest by far, we want to
* be able to leverage SGLs to give us more DMA flexibility.
*
* We can transfer up to 64K in one transfer request block (TRB) which
* corresponds to a single SGL entry. Each ring we create is a single page in
* size and will support at most 256 TRBs. To try and give the operating system
* flexibility when allocating DMA transfers, we've opted to allow up to 63
* SGLs. Because there isn't a good way to support DMA windows with the xHCI
* controller design, if this number is too small then DMA allocations and
* binding might fail. If the DMA binding fails, the transfer will fail.
*
* The reason that we use 63 SGLs and not the expected 64 is that we always need
* to allocate an additional TRB for the event data. This leaves us with a
* nicely divisible number of entries.
*
* The final piece of this is the maximum sized transfer that the driver
* advertises to the broader framework. This is currently sized at 512 KiB. For
* reference the ehci driver sized this value at 640 KiB. It's important to
* understand that this isn't reflected in the DMA attribute limitation, because
* it's not an attribute of the hardware. Experimentally, this has proven to be
* sufficient for most of the drivers that we support today. When considering
* increasing this number, please note the impact that might have on the
* required number of DMA SGL entries required to satisfy the allocation.
*
* The value of 512 KiB was originally based on the number of SGLs we supported
* multiplied by the maximum transfer size. The original number of
* XHCI_TRANSFER_DMA_SGL was 8. The 512 KiB value was based upon taking the
* number of SGLs and assuming that each TRB used its maximum transfer size of
* 64 KiB.
*/
#define XHCI_TRB_MAX_TRANSFER 65536 /* 64 KiB */
#define XHCI_DMA_ALIGN 64
#define XHCI_DEF_DMA_SGL 1
#define XHCI_TRANSFER_DMA_SGL 63
#define XHCI_MAX_TRANSFER 524288 /* 512 KiB */
/*
* Properties and values for rerouting ehci ports to xhci.
*/
#define XHCI_PROP_REROUTE_DISABLE 0
#define XHCI_PROP_REROUTE_DEFAULT 1
/*
* This number is a bit made up. Truthfully, the API here isn't the most useful
* for what we need to define as it should really be based on the endpoint that
* we're interested in rather than the device as a whole.
*
* We're basically being asked how many TRBs we're willing to schedule in one
* go. There's no great way to come up with this number, so we basically are
* making up something such that we use up a good portion of a ring, but not too
* much of it.
*/
#define XHCI_ISOC_MAX_TRB 64
#ifdef DEBUG
#define XHCI_DMA_SYNC(dma, flag) VERIFY0(ddi_dma_sync( \
(dma).xdb_dma_handle, 0, 0, \
(flag)))
#else
#define XHCI_DMA_SYNC(dma, flag) ((void) ddi_dma_sync( \
(dma).xdb_dma_handle, 0, 0, \
(flag)))
#endif
/*
* TRBs need to indicate the number of remaining USB packets in the overall
* transfer. This is a 5-bit value, which means that the maximum value we can
* store in that TRD field is 31.
*/
#define XHCI_MAX_TDSIZE 31
/*
* This defines a time in 2-ms ticks that is required to wait for the controller
* to be ready to go. Section 5.4.8 of the XHCI specification in the description
* of the PORTSC register indicates that the upper bound is 20 ms. Therefore the
* number of ticks is 10.
*/
#define XHCI_POWER_GOOD 10
/*
* Definitions to determine the default number of interrupts. Note that we only
* bother with a single interrupt at this time, though we've arranged the driver
* to make it possible to request more if, for some unlikely reason, it becomes
* necessary.
*/
#define XHCI_NINTR 1
/*
* Default interrupt modulation value. This enables us to have 4000 interrupts /
* second. This is supposed to be the default value of the controller. See xHCI
* 1.1 / 4.17.2 for more information.
*/
#define XHCI_IMOD_DEFAULT 0x000003F8U
/*
* Definitions that surround the default values used in various contexts. These
* come from various parts of the xHCI specification. In general, see xHCI 1.1 /
* 4.8.2. Note that the MPS_MASK is used for ISOCH and INTR endpoints which have
* different sizes.
*
* The burst member is a bit more complicated. By default for USB 2 devices, it
* only matters for ISOCH and INTR endpoints and so we use the macros below to
* pull it out of the endpoint description's max packet field. For USB 3, it
* matters for non-control endpoints. However, it comes out of a companion
* description.
*
* By default the mult member is zero for all cases except for super speed
* ISOCH endpoints, where it comes from the companion descriptor.
*/
#define XHCI_CONTEXT_DEF_CERR 3
#define XHCI_CONTEXT_ISOCH_CERR 0
#define XHCI_CONTEXT_MPS_MASK 0x07ff
#define XHCI_CONTEXT_BURST_MASK 0x1800
#define XHCI_CONTEXT_BURST_SHIFT 11
#define XHCI_CONTEXT_DEF_MULT 0
#define XHCI_CONTEXT_DEF_MAX_ESIT 0
#define XHCI_CONTEXT_DEF_CTRL_ATL 8
/*
* This number represents the number of transfers that we'll set up for a given
* interrupt transfer. Note that the idea here is that we'll want to allocate a
* certain number of transfers to basically ensure that we'll always be able to
* have a transfer available, even if the system is a bit caught up in trying to
* process it and for some reason we can't fire the interrupt. As such, we
* basically want to have enough available that at the fastest interval (125 us)
* that we have enough. So in this case we choose 8, with the assumption that we
* should be able to process at least one in a given millisecond. Note that this
* is not based in fact and is really just as much a guess and a hope.
*
* While we could then use less resources for other interrupt transfers that are
* slower, starting with uniform resource usage will make things a bit easier.
*/
#define XHCI_INTR_IN_NTRANSFERS 8
/*
* This number represents the number of xhci_transfer_t structures that we'll
* set up for a given isochronous transfer polling request. A given isochronous
* transfer may actually have multiple units of time associated with it. As
* such, we basically want to treat this like a case of classic double
* buffering. We have one ready to go while the other is being filled up. This
* will compensate for additional latency in the system. This is smaller than
* the Interrupt IN transfer case above as many callers may ask for multiple
* intervals in a single request.
*/
#define XHCI_ISOC_IN_NTRANSFERS 2
#define XHCI_PERIODIC_IN_NTRANSFERS \
MAX(XHCI_ISOC_IN_NTRANSFERS, XHCI_INTR_IN_NTRANSFERS)
/*
* Mask for a route string which is a 20-bit value.
*/
#define XHCI_ROUTE_MASK(x) ((x) & 0xfffff)
/*
* This is the default tick that we use for timeouts while endpoints have
* outstanding, active, non-periodic transfers. We choose one second as the USBA
* specifies timeouts in units of seconds. Note that this is in microseconds, so
* it can be fed into drv_usectohz().
*/
#define XHCI_TICK_TIMEOUT_US (MICROSEC)
/*
* Set of bits that we need one of to indicate that this port has something
* interesting on it.
*/
#define XHCI_HUB_INTR_CHANGE_MASK (XHCI_PS_CSC | XHCI_PS_PEC | \
XHCI_PS_WRC | XHCI_PS_OCC | XHCI_PS_PRC | XHCI_PS_PLC | XHCI_PS_CEC)
/*
* These represent known issues with various xHCI controllers.
*
* XHCI_QUIRK_NO_MSI MSI support on this controller is known to be
* broken.
*
* XHCI_QUIRK_32_ONLY Only use 32-bit DMA addreses with this
* controller.
*
* XHCI_QUIRK_INTC_EHCI This is an Intel platform which supports
* rerouting ports between EHCI and xHCI
* controllers on the platform.
*/
typedef enum xhci_quirk {
XHCI_QUIRK_NO_MSI = 0x01,
XHCI_QUIRK_32_ONLY = 0x02,
XHCI_QUIRK_INTC_EHCI = 0x04
} xhci_quirk_t;
/*
* xHCI capability parameter flags. These are documented in xHCI 1.1 / 5.3.6.
*/
typedef enum xhci_cap_flags {
XCAP_AC64 = 0x001,
XCAP_BNC = 0x002,
XCAP_CSZ = 0x004,
XCAP_PPC = 0x008,
XCAP_PIND = 0x010,
XCAP_LHRC = 0x020,
XCAP_LTC = 0x040,
XCAP_NSS = 0x080,
XCAP_PAE = 0x100,
XCAP_SPC = 0x200,
XCAP_SEC = 0x400,
XCAP_CFC = 0x800
} xchi_cap_flags_t;
/*
* Second set of capabilities, these are documented in xHCI 1.1 / 5.3.9.
*/
typedef enum xhci_cap2_flags {
XCAP2_U3C = 0x01,
XCAP2_CMC = 0x02,
XCAP2_FMC = 0x04,
XCAP2_CTC = 0x08,
XCAP2_LEC = 0x10,
XCAP2_CIC = 0x20
} xhci_cap2_flags_t;
/*
* These represent and store the various capability registers that we'll need to
* use. In addition, we stash a few other versioning related bits here. Note
* that we cache more information than we might need so that we have it for
* debugging purposes.
*/
typedef struct xhci_capability {
uint8_t xcap_usb_vers;
uint16_t xcap_hci_vers;
uint32_t xcap_pagesize;
uint8_t xcap_max_slots;
uint16_t xcap_max_intrs;
uint8_t xcap_max_ports;
boolean_t xcap_ist_micro;
uint8_t xcap_ist;
uint16_t xcap_max_esrt;
boolean_t xcap_scratch_restore;
uint16_t xcap_max_scratch;
uint8_t xcap_u1_lat;
uint16_t xcap_u2_lat;
xchi_cap_flags_t xcap_flags;
uint8_t xcap_max_psa;
uint16_t xcap_xecp_off;
xhci_cap2_flags_t xcap_flags2;
int xcap_intr_types;
} xhci_capability_t;
/*
* This represents a single logical DMA allocation. For the vast majority of
* non-transfer cases, it only represents a single DMA buffer and not a
* scatter-gather list.
*/
typedef struct xhci_dma_buffer {
caddr_t xdb_va; /* Buffer VA */
size_t xdb_len; /* Buffer logical len */
ddi_acc_handle_t xdb_acc_handle; /* Access handle */
ddi_dma_handle_t xdb_dma_handle; /* DMA handle */
int xdb_ncookies; /* Number of actual cookies */
ddi_dma_cookie_t xdb_cookies[XHCI_TRANSFER_DMA_SGL];
} xhci_dma_buffer_t;
/*
* This is a single transfer descriptor. It's packed to match the hardware
* layout.
*/
#pragma pack(1)
typedef struct xhci_trb {
uint64_t trb_addr;
uint32_t trb_status;
uint32_t trb_flags;
} xhci_trb_t;
#pragma pack()
/*
* This represents a single transfer that we want to allocate and perform.
*/
typedef struct xhci_transfer {
list_node_t xt_link;
hrtime_t xt_sched_time;
xhci_dma_buffer_t xt_buffer;
uint_t xt_ntrbs;
uint_t xt_short;
uint_t xt_timeout;
usb_cr_t xt_cr;
boolean_t xt_data_tohost;
xhci_trb_t *xt_trbs;
uint64_t *xt_trbs_pa;
usb_isoc_pkt_descr_t *xt_isoc;
usb_opaque_t xt_usba_req;
} xhci_transfer_t;
/*
* This represents a ring in xHCI, upon which event, transfer, and command TRBs
* are scheduled.
*/
typedef struct xhci_ring {
xhci_dma_buffer_t xr_dma;
uint_t xr_ntrb;
xhci_trb_t *xr_trb;
uint_t xr_head;
uint_t xr_tail;
uint8_t xr_cycle;
} xhci_ring_t;
/*
* This structure is used to represent the xHCI Device Context Base Address
* Array. It's defined in section 6.1 of the specification and is required for
* the controller to start.
*
* The maximum number of slots supported is always 256, therefore we size this
* structure at its maximum.
*/
#define XHCI_MAX_SLOTS 256
#define XHCI_DCBAA_SCRATCHPAD_INDEX 0
typedef struct xhci_dcbaa {
uint64_t *xdc_base_addrs;
xhci_dma_buffer_t xdc_dma;
} xhci_dcbaa_t;
typedef struct xhci_scratchpad {
uint64_t *xsp_addrs;
xhci_dma_buffer_t xsp_addr_dma;
xhci_dma_buffer_t *xsp_scratch_dma;
} xhci_scratchpad_t;
/*
* Contexts. These structures are inserted into the DCBAA above and are used for
* describing the state of the system. Note, that while many of these are
* 32-bytes in size, the xHCI specification defines that they'll be extended to
* 64-bytes with all the extra bytes as zeros if the CSZ flag is set in the
* HCCPARAMS1 register, e.g. we have the flag XCAP_CSZ set.
*
* The device context covers the slot context and 31 endpoints.
*/
#define XHCI_DEVICE_CONTEXT_32 1024
#define XHCI_DEVICE_CONTEXT_64 2048
#define XHCI_NUM_ENDPOINTS 31
#define XHCI_DEFAULT_ENDPOINT 0
#pragma pack(1)
typedef struct xhci_slot_context {
uint32_t xsc_info;
uint32_t xsc_info2;
uint32_t xsc_tt;
uint32_t xsc_state;
uint32_t xsc_reserved[4];
} xhci_slot_context_t;
typedef struct xhci_endpoint_context {
uint32_t xec_info;
uint32_t xec_info2;
uint64_t xec_dequeue;
uint32_t xec_txinfo;
uint32_t xec_reserved[3];
} xhci_endpoint_context_t;
typedef struct xhci_input_context {
uint32_t xic_drop_flags;
uint32_t xic_add_flags;
uint32_t xic_reserved[6];
} xhci_input_context_t;
#pragma pack()
/*
* Definitions and structures for maintaining the event ring.
*/
#define XHCI_EVENT_NSEGS 1
#pragma pack(1)
typedef struct xhci_event_segment {
uint64_t xes_addr;
uint16_t xes_size;
uint16_t xes_rsvd0;
uint32_t xes_rsvd1;
} xhci_event_segment_t;
#pragma pack()
typedef struct xhci_event_ring {
xhci_event_segment_t *xev_segs;
xhci_dma_buffer_t xev_dma;
xhci_ring_t xev_ring;
} xhci_event_ring_t;
typedef enum xhci_command_ring_state {
XHCI_COMMAND_RING_IDLE = 0x00,
XHCI_COMMAND_RING_RUNNING = 0x01,
XHCI_COMMAND_RING_ABORTING = 0x02,
XHCI_COMMAND_RING_ABORT_DONE = 0x03
} xhci_command_ring_state_t;
typedef struct xhci_command_ring {
xhci_ring_t xcr_ring;
kmutex_t xcr_lock;
kcondvar_t xcr_cv;
list_t xcr_commands;
timeout_id_t xcr_timeout;
xhci_command_ring_state_t xcr_state;
} xhci_command_ring_t;
/*
* Individual command states.
*
* XHCI_COMMAND_S_INIT The command has yet to be inserted into the
* command ring.
*
* XHCI_COMMAND_S_QUEUED The command is queued in the command ring.
*
* XHCI_COMMAND_S_RECEIVED A command completion for this was received.
*
* XHCI_COMMAND_S_DONE The command has been executed. Note that it may
* have been aborted.
*
* XHCI_COMMAND_S_RESET The ring is being reset due to a fatal error and
* this command has been removed from the ring.
* This means it has been aborted, but it was not
* the cause of the abort.
*
* Note, when adding states, anything after XHCI_COMMAND_S_DONE implies that
* upon reaching this state, it is no longer in the ring.
*/
typedef enum xhci_command_state {
XHCI_COMMAND_S_INIT = 0x00,
XHCI_COMMAND_S_QUEUED = 0x01,
XHCI_COMMAND_S_RECEIVED = 0x02,
XHCI_COMMAND_S_DONE = 0x03,
XHCI_COMMAND_S_RESET = 0x04
} xhci_command_state_t;
/*
* The TRB contents here are always kept in host byte order and are transformed
* to little endian when actually scheduled on the ring.
*/
typedef struct xhci_command {
list_node_t xco_link;
kcondvar_t xco_cv;
xhci_trb_t xco_req;
xhci_trb_t xco_res;
xhci_command_state_t xco_state;
} xhci_command_t;
typedef enum xhci_endpoint_state {
XHCI_ENDPOINT_PERIODIC = 0x01,
XHCI_ENDPOINT_HALTED = 0x02,
XHCI_ENDPOINT_QUIESCE = 0x04,
XHCI_ENDPOINT_TIMED_OUT = 0x08,
/*
* This enpdoint is being torn down and should make sure it de-schedules
* itself.
*/
XHCI_ENDPOINT_TEARDOWN = 0x10,
/*
* This endpoint is currently used in polled I/O mode by the
* kernel debugger.
*/
XHCI_ENDPOINT_POLLED = 0x20,
/*
* This endpoint is open and in use by a pipe.
*/
XHCI_ENDPOINT_OPEN = 0x40,
} xhci_endpoint_state_t;
/*
* This is a composite of states that we need to watch for. We don't
* want to allow ourselves to set one of these flags while one of them
* is currently active.
*/
#define XHCI_ENDPOINT_SERIALIZE (XHCI_ENDPOINT_QUIESCE | \
XHCI_ENDPOINT_TIMED_OUT)
/*
* This is a composite of states that we need to make sure that if set, we do
* not schedule activity on the ring.
*/
#define XHCI_ENDPOINT_DONT_SCHEDULE (XHCI_ENDPOINT_HALTED | \
XHCI_ENDPOINT_QUIESCE | \
XHCI_ENDPOINT_TIMED_OUT)
/*
* Forwards required for the endpoint
*/
struct xhci_device;
struct xhci;
typedef struct xhci_endpoint_params {
boolean_t xepp_configured;
uint_t xepp_eptype;
uint_t xepp_burst;
uint_t xepp_ival;
uint_t xepp_max_esit;
uint_t xepp_avgtrb;
uint_t xepp_mps;
uint_t xepp_mult;
uint_t xepp_cerr;
} xhci_endpoint_params_t;
typedef struct xhci_endpoint {
struct xhci *xep_xhci;
struct xhci_device *xep_xd;
uint_t xep_num;
uint_t xep_type;
xhci_endpoint_state_t xep_state;
kcondvar_t xep_state_cv;
timeout_id_t xep_timeout;
list_t xep_transfers;
usba_pipe_handle_data_t *xep_pipe;
xhci_ring_t xep_ring;
xhci_endpoint_params_t xep_params;
} xhci_endpoint_t;
typedef struct xhci_device {
list_node_t xd_link;
usb_port_t xd_port;
uint8_t xd_slot;
boolean_t xd_addressed;
usba_device_t *xd_usbdev;
xhci_dma_buffer_t xd_ictx;
kmutex_t xd_imtx; /* Protects input contexts */
xhci_input_context_t *xd_input;
xhci_slot_context_t *xd_slotin;
xhci_endpoint_context_t *xd_endin[XHCI_NUM_ENDPOINTS];
xhci_dma_buffer_t xd_octx;
xhci_slot_context_t *xd_slotout;
xhci_endpoint_context_t *xd_endout[XHCI_NUM_ENDPOINTS];
xhci_endpoint_t *xd_endpoints[XHCI_NUM_ENDPOINTS];
} xhci_device_t;
typedef enum xhci_periodic_state {
XHCI_PERIODIC_POLL_IDLE = 0x0,
XHCI_PERIODIC_POLL_ACTIVE,
XHCI_PERIODIC_POLL_NOMEM,
XHCI_PERIODIC_POLL_STOPPING
} xhci_periodic_state_t;
typedef struct xhci_periodic_pipe {
xhci_periodic_state_t xpp_poll_state;
usb_opaque_t xpp_usb_req;
size_t xpp_tsize;
uint_t xpp_ntransfers;
xhci_transfer_t *xpp_transfers[XHCI_PERIODIC_IN_NTRANSFERS];
} xhci_periodic_pipe_t;
typedef struct xhci_pipe {
list_node_t xp_link;
hrtime_t xp_opentime;
usba_pipe_handle_data_t *xp_pipe;
xhci_endpoint_t *xp_ep;
xhci_periodic_pipe_t xp_periodic;
} xhci_pipe_t;
typedef struct xhci_usba {
usba_hcdi_ops_t *xa_ops;
ddi_dma_attr_t xa_dma_attr;
usb_dev_descr_t xa_dev_descr;
usb_ss_hub_descr_t xa_hub_descr;
usba_pipe_handle_data_t *xa_intr_cb_ph;
usb_intr_req_t *xa_intr_cb_req;
list_t xa_devices;
list_t xa_pipes;
} xhci_usba_t;
typedef enum xhci_attach_seq {
XHCI_ATTACH_FM = 0x1 << 0,
XHCI_ATTACH_PCI_CONFIG = 0x1 << 1,
XHCI_ATTACH_REGS_MAP = 0x1 << 2,
XHCI_ATTACH_INTR_ALLOC = 0x1 << 3,
XHCI_ATTACH_INTR_ADD = 0x1 << 4,
XHCI_ATTACH_SYNCH = 0x1 << 5,
XHCI_ATTACH_INTR_ENABLE = 0x1 << 6,
XHCI_ATTACH_STARTED = 0x1 << 7,
XHCI_ATTACH_USBA = 0x1 << 8,
XHCI_ATTACH_ROOT_HUB = 0x1 << 9
} xhci_attach_seq_t;
typedef enum xhci_state_flags {
XHCI_S_ERROR = 0x1 << 0
} xhci_state_flags_t;
typedef struct xhci {
dev_info_t *xhci_dip;
xhci_attach_seq_t xhci_seq;
int xhci_fm_caps;
ddi_acc_handle_t xhci_cfg_handle;
uint16_t xhci_vendor_id;
uint16_t xhci_device_id;
caddr_t xhci_regs_base;
ddi_acc_handle_t xhci_regs_handle;
uint_t xhci_regs_capoff;
uint_t xhci_regs_operoff;
uint_t xhci_regs_runoff;
uint_t xhci_regs_dooroff;
xhci_capability_t xhci_caps;
xhci_quirk_t xhci_quirks;
ddi_intr_handle_t xhci_intr_hdl;
int xhci_intr_num;
int xhci_intr_type;
uint_t xhci_intr_pri;
int xhci_intr_caps;
xhci_dcbaa_t xhci_dcbaa;
xhci_scratchpad_t xhci_scratchpad;
xhci_command_ring_t xhci_command;
xhci_event_ring_t xhci_event;
taskq_ent_t xhci_tqe;
kmutex_t xhci_lock;
kcondvar_t xhci_statecv;
xhci_state_flags_t xhci_state;
xhci_usba_t xhci_usba;
} xhci_t;
/*
* The xHCI memory mapped registers come in four different categories. The
* offset to them is variable. These represent the given register set that we're
* after.
*/
typedef enum xhci_reg_type {
XHCI_R_CAP,
XHCI_R_OPER,
XHCI_R_RUN,
XHCI_R_DOOR
} xhci_reg_type_t;
/*
* Polled I/O data structure
*/
typedef struct xhci_polled {
/*
* Pointer to the xhcip structure for the device that is to be
* used as input in polled mode.
*/
xhci_t *xhci_polled_xhci;
/*
* Pipe handle for the pipe that is to be used as input device
* in POLLED mode.
*/
usba_pipe_handle_data_t *xhci_polled_input_pipe_handle;
/* Endpoint for the above */
xhci_endpoint_t *xhci_polled_endpoint;
/*
* The buffer that the USB HDI scan codes are copied into.
* A USB keyboard will report up to 8 bytes consisting of the
* modifier status, a reserved byte and up to 6 key presses.
* This buffer is sized to be large enough for one such report.
*/
uchar_t xhci_polled_buf[8];
/*
* Track how many times xhci_polled_input_enter() and
* xhci_polled_input_exit() have been called so that the host
* controller isn't switched back to OS mode prematurely.
*/
uint_t xhci_polled_entry;
/*
* Remember persistent errors that will prevent us from reading
* further input to avoid repeatedly polling to no avail
*/
int xhci_polled_persistent_error;
} xhci_polled_t;
/*
* Helper functions
*/
extern xhci_t *xhci_hcdi_get_xhcip_from_dev(usba_device_t *);
extern xhci_device_t *xhci_device_lookup_by_slot(xhci_t *, int);
/*
* Quirks related functions
*/
extern void xhci_quirks_populate(xhci_t *);
extern void xhci_reroute_intel(xhci_t *);
/*
* Interrupt related functions
*/
extern uint_t xhci_intr(caddr_t, caddr_t);
extern boolean_t xhci_ddi_intr_disable(xhci_t *);
extern boolean_t xhci_ddi_intr_enable(xhci_t *);
extern int xhci_intr_conf(xhci_t *);
/*
* DMA related functions
*/
extern int xhci_check_dma_handle(xhci_t *, xhci_dma_buffer_t *);
extern void xhci_dma_acc_attr(xhci_t *, ddi_device_acc_attr_t *);
extern void xhci_dma_dma_attr(xhci_t *, ddi_dma_attr_t *);
extern void xhci_dma_scratchpad_attr(xhci_t *, ddi_dma_attr_t *);
extern void xhci_dma_transfer_attr(xhci_t *, ddi_dma_attr_t *, uint_t);
extern void xhci_dma_free(xhci_dma_buffer_t *);
extern boolean_t xhci_dma_alloc(xhci_t *, xhci_dma_buffer_t *, ddi_dma_attr_t *,
ddi_device_acc_attr_t *, boolean_t, size_t, boolean_t);
extern uint64_t xhci_dma_pa(xhci_dma_buffer_t *);
/*
* DMA Transfer Ring functions
*/
extern xhci_transfer_t *xhci_transfer_alloc(xhci_t *, xhci_endpoint_t *, size_t,
uint_t, int);
extern void xhci_transfer_free(xhci_t *, xhci_transfer_t *);
extern void xhci_transfer_copy(xhci_transfer_t *, void *, size_t, boolean_t);
extern int xhci_transfer_sync(xhci_t *, xhci_transfer_t *, uint_t);
extern void xhci_transfer_trb_fill_data(xhci_endpoint_t *, xhci_transfer_t *,
int, boolean_t);
extern void xhci_transfer_calculate_isoc(xhci_device_t *, xhci_endpoint_t *,
uint_t, uint_t *, uint_t *);
/*
* Context (DCBAA, Scratchpad, Slot) functions
*/
extern int xhci_context_init(xhci_t *);
extern void xhci_context_fini(xhci_t *);
extern boolean_t xhci_context_slot_output_init(xhci_t *, xhci_device_t *);
extern void xhci_context_slot_output_fini(xhci_t *, xhci_device_t *);
/*
* Command Ring Functions
*/
extern int xhci_command_ring_init(xhci_t *);
extern void xhci_command_ring_fini(xhci_t *);
extern boolean_t xhci_command_event_callback(xhci_t *, xhci_trb_t *trb);
extern void xhci_command_init(xhci_command_t *);
extern void xhci_command_fini(xhci_command_t *);
extern int xhci_command_enable_slot(xhci_t *, uint8_t *);
extern int xhci_command_disable_slot(xhci_t *, uint8_t);
extern int xhci_command_set_address(xhci_t *, xhci_device_t *, boolean_t);
extern int xhci_command_configure_endpoint(xhci_t *, xhci_device_t *);
extern int xhci_command_evaluate_context(xhci_t *, xhci_device_t *);
extern int xhci_command_reset_endpoint(xhci_t *, xhci_device_t *,
xhci_endpoint_t *);
extern int xhci_command_set_tr_dequeue(xhci_t *, xhci_device_t *,
xhci_endpoint_t *);
extern int xhci_command_stop_endpoint(xhci_t *, xhci_device_t *,
xhci_endpoint_t *);
/*
* Event Ring Functions
*/
extern int xhci_event_init(xhci_t *);
extern void xhci_event_fini(xhci_t *);
extern boolean_t xhci_event_process_trb(xhci_t *, xhci_trb_t *);
extern boolean_t xhci_event_process(xhci_t *);
/*
* General Ring functions
*/
extern void xhci_ring_free(xhci_ring_t *);
extern int xhci_ring_reset(xhci_t *, xhci_ring_t *);
extern int xhci_ring_alloc(xhci_t *, xhci_ring_t *);
/*
* Event Ring (Consumer) oriented functions.
*/
extern xhci_trb_t *xhci_ring_event_advance(xhci_ring_t *);
/*
* Command and Transfer Ring (Producer) oriented functions.
*/
extern boolean_t xhci_ring_trb_tail_valid(xhci_ring_t *, uint64_t);
extern int xhci_ring_trb_valid_range(xhci_ring_t *, uint64_t, uint_t);
extern boolean_t xhci_ring_trb_space(xhci_ring_t *, uint_t);
extern void xhci_ring_trb_fill(xhci_ring_t *, uint_t, xhci_trb_t *, uint64_t *,
boolean_t);
extern void xhci_ring_trb_produce(xhci_ring_t *, uint_t);
extern boolean_t xhci_ring_trb_consumed(xhci_ring_t *, uint64_t);
extern void xhci_ring_trb_put(xhci_ring_t *, xhci_trb_t *);
extern void xhci_ring_skip(xhci_ring_t *);
extern void xhci_ring_skip_transfer(xhci_ring_t *, xhci_transfer_t *);
/*
* MMIO related functions. Note callers are responsible for checking with FM
* after accessing registers.
*/
extern int xhci_check_regs_acc(xhci_t *);
extern uint8_t xhci_get8(xhci_t *, xhci_reg_type_t, uintptr_t);
extern uint16_t xhci_get16(xhci_t *, xhci_reg_type_t, uintptr_t);
extern uint32_t xhci_get32(xhci_t *, xhci_reg_type_t, uintptr_t);
extern uint64_t xhci_get64(xhci_t *, xhci_reg_type_t, uintptr_t);
extern void xhci_put8(xhci_t *, xhci_reg_type_t, uintptr_t, uint8_t);
extern void xhci_put16(xhci_t *, xhci_reg_type_t, uintptr_t, uint16_t);
extern void xhci_put32(xhci_t *, xhci_reg_type_t, uintptr_t, uint32_t);
extern void xhci_put64(xhci_t *, xhci_reg_type_t, uintptr_t, uint64_t);
/*
* Runtime FM related functions
*/
extern void xhci_fm_runtime_reset(xhci_t *);
/*
* Endpoint related functions
*/
extern int xhci_endpoint_init(xhci_t *, xhci_device_t *,
usba_pipe_handle_data_t *);
extern int xhci_endpoint_reinit(xhci_t *, xhci_device_t *,
xhci_endpoint_t *, usba_pipe_handle_data_t *);
extern void xhci_endpoint_release(xhci_t *, xhci_endpoint_t *);
extern void xhci_endpoint_fini(xhci_device_t *, int);
extern int xhci_endpoint_update_default(xhci_t *, xhci_device_t *,
xhci_endpoint_t *);
extern void xhci_endpoint_timeout_cancel(xhci_t *, xhci_endpoint_t *);
extern int xhci_endpoint_setup_default_context(xhci_t *, xhci_device_t *,
xhci_endpoint_t *);
extern uint_t xhci_endpoint_pipe_to_epid(usba_pipe_handle_data_t *);
extern boolean_t xhci_endpoint_is_periodic_in(xhci_endpoint_t *);
extern void xhci_endpoint_serialize(xhci_t *, xhci_endpoint_t *);
extern int xhci_endpoint_quiesce(xhci_t *, xhci_device_t *, xhci_endpoint_t *);
extern int xhci_endpoint_schedule(xhci_t *, xhci_device_t *, xhci_endpoint_t *,
xhci_transfer_t *, boolean_t);
extern int xhci_endpoint_ring(xhci_t *, xhci_device_t *, xhci_endpoint_t *);
extern boolean_t xhci_endpoint_transfer_callback(xhci_t *, xhci_trb_t *);
extern xhci_transfer_t *xhci_endpoint_determine_transfer(xhci_t *,
xhci_endpoint_t *, xhci_trb_t *, uint_t *);
/*
* USB Framework related functions
*/
extern int xhci_hcd_init(xhci_t *);
extern void xhci_hcd_fini(xhci_t *);
/*
* Root hub related functions
*/
extern int xhci_root_hub_init(xhci_t *);
extern int xhci_root_hub_fini(xhci_t *);
extern int xhci_root_hub_ctrl_req(xhci_t *, usba_pipe_handle_data_t *,
usb_ctrl_req_t *);
extern void xhci_root_hub_psc_callback(xhci_t *);
extern int xhci_root_hub_intr_root_enable(xhci_t *, usba_pipe_handle_data_t *,
usb_intr_req_t *);
extern void xhci_root_hub_intr_root_disable(xhci_t *);
/*
* Polled I/O functions
*/
extern int xhci_hcdi_console_input_init(usba_pipe_handle_data_t *, uchar_t **,
usb_console_info_impl_t *);
extern int xhci_hcdi_console_input_fini(usb_console_info_impl_t *);
extern int xhci_hcdi_console_input_enter(usb_console_info_impl_t *);
extern int xhci_hcdi_console_read(usb_console_info_impl_t *, uint_t *);
extern int xhci_hcdi_console_input_exit(usb_console_info_impl_t *);
extern int xhci_hcdi_console_output_init(usba_pipe_handle_data_t *,
usb_console_info_impl_t *);
extern int xhci_hcdi_console_output_fini(usb_console_info_impl_t *);
extern int xhci_hcdi_console_output_enter(usb_console_info_impl_t *);
extern int xhci_hcdi_console_write(usb_console_info_impl_t *, uchar_t *,
uint_t, uint_t *);
extern int xhci_hcdi_console_output_exit(usb_console_info_impl_t *);
/*
* Logging functions
*/
extern void xhci_log(xhci_t *xhcip, const char *fmt, ...) __KPRINTFLIKE(2);
extern void xhci_error(xhci_t *xhcip, const char *fmt, ...) __KPRINTFLIKE(2);
/*
* Misc. data
*/
extern void *xhci_soft_state;
#ifdef __cplusplus
}
#endif
#endif /* _SYS_USB_XHCI_XHCI_H */
|