55
66static struct xhci_hc * g_xhci ; /* single controller */
77
8- /* ring_init with debug */
8+ /* ring_init with debug — set Toggle Cycle (TC) like libpayload */
99static void ring_init (struct xhci_ring * r , size_t bytes , uint64_t phys , void * virt ) {
1010 dprintf ("xhci.dbg: ring_init bytes=%u phys=%llx virt=%llx\n" ,
1111 (unsigned )bytes , (unsigned long long )phys , (unsigned long long )(uintptr_t )virt );
@@ -17,12 +17,12 @@ static void ring_init(struct xhci_ring *r, size_t bytes, uint64_t phys, void *vi
1717 r -> cycle = 1 ;
1818 memset (r -> base , 0 , bytes );
1919
20- /* terminal link TRB */
20+ /* terminal link TRB: point to start, set TC=1, set C=1 (producer PCS) */
2121 struct trb * link = & r -> base [r -> num_trbs - 1 ];
2222 link -> lo = (uint32_t ) (r -> phys & 0xFFFFFFFFu );
2323 link -> hi = (uint32_t ) (r -> phys >> 32 );
2424 link -> sts = 0 ;
25- link -> ctrl = TRB_SET_TYPE (TRB_LINK ) | TRB_CYCLE ;
25+ link -> ctrl = TRB_SET_TYPE (TRB_LINK ) | TRB_TOGGLE | TRB_CYCLE ;
2626
2727 dprintf ("xhci.dbg: TRBs=%u link_trb@%u lo=%08x hi=%08x ctrl=%08x\n" ,
2828 r -> num_trbs , r -> num_trbs - 1 , link -> lo , link -> hi , link -> ctrl );
@@ -765,7 +765,7 @@ static void xhci_isr(uint8_t isr, uint64_t error, uint64_t irq, void *opaque)
765765 volatile uint8_t * ir0 = hc -> rt + XHCI_RT_IR0 ;
766766 dprintf ("xhci int\n" );
767767
768- /* Service all posted events. DO NOT set EHB here; keep it clear on exit. */
768+ /* Service all posted events. Keep EHB clear on exit. */
769769 uint64_t erdp_cur = mmio_read64 (ir0 + IR_ERDP ) & ~0x7ull ;
770770
771771 for (uint32_t i = 0 ; i < hc -> evt .num_trbs ; i ++ ) {
@@ -777,19 +777,29 @@ static void xhci_isr(uint8_t isr, uint64_t error, uint64_t irq, void *opaque)
777777 i , type , e -> lo , e -> hi , e -> sts );
778778
779779 if (type == TRB_TRANSFER_EVENT ) {
780- /* Asynchronous: INT-IN only in this driver */
781- if (hc -> dev .int_cb && hc -> dev .int_buf && hc -> dev .int_pkt_len ) {
780+ /* Identify our EP1-IN transfer by TRB pointer range (robust & simple) */
781+ uint64_t trb_ptr = ((uint64_t )e -> hi << 32 ) | e -> lo ;
782+ uint64_t ring_lo = hc -> dev .int_in_tr .phys ;
783+ uint64_t ring_hi = ring_lo + 4096 ; /* one 4K segment */
784+
785+ if (hc -> dev .int_buf && hc -> dev .int_pkt_len &&
786+ trb_ptr >= ring_lo && trb_ptr < ring_hi ) {
787+
788+ /* Length actually transferred is in EVTL (DW2[23:0]) */
789+ uint32_t evtl = (e -> sts & 0x00FFFFFFu );
790+
782791 struct usb_dev ud = {0 };
783792 ud .hc = hc ;
784793 ud .slot_id = hc -> dev .slot_id ;
785- hc -> dev .int_cb (& ud , hc -> dev .int_buf , hc -> dev .int_pkt_len );
786794
787- /* Re-arm EP1 IN (IOC|ISP) */
795+ hc -> dev .int_cb (& ud , hc -> dev .int_buf , (uint16_t )evtl );
796+
797+ /* Re-arm exactly one INT-IN TRB (IOC|ISP) */
788798 struct trb * n = ring_push (& hc -> dev .int_in_tr );
789- n -> lo = (uint32_t )(hc -> dev .int_buf_phys & 0xFFFFFFFFu );
790- n -> hi = (uint32_t )(hc -> dev .int_buf_phys >> 32 );
791- n -> sts = hc -> dev .int_pkt_len ;
792- n -> ctrl = TRB_SET_TYPE (TRB_NORMAL ) | TRB_IOC | TRB_ISP |
799+ n -> lo = (uint32_t )(hc -> dev .int_buf_phys & 0xFFFFFFFFu );
800+ n -> hi = (uint32_t )(hc -> dev .int_buf_phys >> 32 );
801+ n -> sts = hc -> dev .int_pkt_len ;
802+ n -> ctrl = TRB_SET_TYPE (TRB_NORMAL ) | TRB_ISP | TRB_IOC |
793803 (hc -> dev .int_in_tr .cycle ? TRB_CYCLE : 0 );
794804
795805 mmio_write32 (hc -> db + 4u * hc -> dev .slot_id , EPID_EP1_IN );
@@ -823,13 +833,13 @@ int xhci_arm_int_in(struct usb_dev *ud, uint16_t pkt_len, xhci_int_in_cb cb) {
823833 struct xhci_hc * hc = (struct xhci_hc * ) ud -> hc ;
824834
825835 /* Use discovered INT-IN from config (fallbacks retained). */
826- uint8_t ep_num = hc -> dev .int_ep_num ? hc -> dev .int_ep_num : 1 ;
827- uint16_t ep_mps = hc -> dev .int_ep_mps ? hc -> dev .int_ep_mps : 8 ;
828- uint8_t ep_bInterval = hc -> dev .int_ep_interval ? hc -> dev .int_ep_interval : 1 ;
836+ uint8_t ep_num = hc -> dev .int_ep_num ? hc -> dev .int_ep_num : 1 ;
837+ uint16_t ep_mps = hc -> dev .int_ep_mps ? hc -> dev .int_ep_mps : 8 ;
838+ uint8_t ep_bInterval = hc -> dev .int_ep_interval ? hc -> dev .int_ep_interval : 1 ;
829839
830- /* We currently only carry an input context slot for EP1 IN. Bail if not EP1 IN . */
840+ /* Only EP1 IN is supported in this driver (EPID==3) . */
831841 if (ep_num != 1 ) {
832- uint8_t epid = (uint8_t )(2u * ep_num + 1u ); /* IN => odd EPID */
842+ uint8_t epid = (uint8_t )(2u * ep_num + 1u );
833843 dprintf ("xhci.dbg: WARNING: device INT-IN at EP%u (EPID=%u), driver only supports EP1 IN; not arming.\n" ,
834844 ep_num , epid );
835845 return 0 ;
@@ -838,12 +848,12 @@ int xhci_arm_int_in(struct usb_dev *ud, uint16_t pkt_len, xhci_int_in_cb cb) {
838848 /* Ensure TR for EP1 IN */
839849 if (!hc -> dev .int_in_tr .base ) {
840850 void * v = kmalloc_aligned (4096 , 4096 );
841- uint64_t p = (uint64_t )(uintptr_t ) v ;
842- dprintf ("xhci.dbg: INT-IN TR alloc v=%p phys=%lx\n" , v , p );
843851 if (!v ) {
844852 dprintf ("xhci.dbg: INT-IN TR alloc fail\n" );
845853 return 0 ;
846854 }
855+ uint64_t p = (uint64_t )(uintptr_t )v ;
856+ dprintf ("xhci.dbg: INT-IN TR alloc v=%p phys=%lx\n" , v , p );
847857 ring_init (& hc -> dev .int_in_tr , 4096 , p , v );
848858 dprintf ("xhci.dbg: INT-IN TR init base=%p phys=%lx cycle=%u\n" ,
849859 hc -> dev .int_in_tr .base , hc -> dev .int_in_tr .phys ,
@@ -880,70 +890,75 @@ int xhci_arm_int_in(struct usb_dev *ud, uint16_t pkt_len, xhci_int_in_cb cb) {
880890 /* Copy current Device Slot Context -> Input Slot Context; set CE=3. */
881891 {
882892 uint64_t dphys = hc -> dcbaa [ud -> slot_id ];
883- volatile uint32_t * dcs = (volatile uint32_t * )(uintptr_t )dphys ; /* device slot ctx (8 dwords) */
884- volatile uint32_t * isc = (volatile uint32_t * )& hc -> dev .ic -> slot ; /* input slot ctx (8 dwords) */
885- for (int k = 0 ; k < 8 ; k ++ ) {
886- isc [k ] = dcs [k ];
887- }
893+ volatile uint32_t * dcs = (volatile uint32_t * )(uintptr_t )dphys ; /* device slot ctx (8 dwords) */
894+ volatile uint32_t * isc = (volatile uint32_t * )& hc -> dev .ic -> slot ; /* input slot ctx (8 dwords) */
895+ for (int k = 0 ; k < 8 ; k ++ ) isc [k ] = dcs [k ];
888896 /* CE = highest context ID present (3 => EP1 IN included) */
889897 isc [0 ] = (isc [0 ] & ~(0x1Fu << 27 )) | (3u << 27 );
890898 dprintf ("xhci.dbg: slot.dword0(copy+CE)=%08x (CE=%u)\n" ,
891899 isc [0 ], (unsigned )((isc [0 ] >> 27 ) & 0x1F ));
892900 }
893901
894- /* -------- Interval encoding per xHCI --------
895- * For SS and HS Interrupt endpoints, the Endpoint Context 'Interval' is (bInterval - 1 )
896- * in 125us units (exponent encoding). For FS/LS Interrupt endpoints, 'Interval' is
897- * the bInterval in frames (no -1) .
902+ /* -------- Interval encoding per xHCI (libpayload semantics) --------
903+ * HS/SS: INTVAL = bInterval - 1 (units: 125 µs exponent )
904+ * FS/LS: INTVAL = bInterval (units: frames)
905+ * Bound the value like libpayload for FS/LS interrupt endpoints .
898906 */
899- uint32_t interval_field = 1 ;
907+ uint32_t intval = 1 ;
900908 {
901- /* speed was recorded in Slot Context dword2[3:0] by your enumerate path */
902- uint32_t s0 = hc -> dev .ic -> slot .dword2 & 0xF ;
903- /* 1: Full, 2: Low, 3: High, 4: SuperSpeed (values vary by impl; you logged 'speed=3' earlier for SS) */
904- uint8_t speed_code = (uint8_t )s0 ;
909+ /* speed code was captured in Slot Context dword2[3:0] during enumerate */
910+ uint8_t speed_code = (uint8_t )(hc -> dev .ic -> slot .dword2 & 0xF );
905911
906912 if (speed_code >= 3 ) {
907- /* HS/SS: exponent encoding. Guard against bInterval==0. */
908- uint8_t bI = ( ep_bInterval ? ep_bInterval : 1 ) ;
909- interval_field = (bI > 0 ? (uint32_t )(bI - 1 ) : 0u ) ;
913+ /* High/Super speed */
914+ uint8_t bI = ep_bInterval ? ep_bInterval : 1 ;
915+ intval = (bI > 0 ) ? (uint32_t )(bI - 1 ) : 0u ;
910916 } else {
911- /* FS/LS: frames; program as-is (minimum 1). */
912- interval_field = (ep_bInterval ? ep_bInterval : 1 );
917+ /* Full/Low speed */
918+ intval = ep_bInterval ? ep_bInterval : 1 ;
919+ if (intval < 3 ) intval = 3 ;
920+ else if (intval > 11 ) intval = 11 ;
913921 }
922+ if (intval > 15 ) intval = 15 ;
914923 }
915924
916- /* Program EP1 IN context */
925+ /* Program EP1 IN context — field placement matches libpayload:
926+ * DW0: CErr=3
927+ * DW1: [31:16] MaxPacketSize, [15:8] Interval, [5:3] EPType (=7 Interrupt IN)
928+ * TR Dequeue: ring phys | DCS
929+ * DW4: AvgTRB Length (31:16), Max ESIT Payload (15:0)
930+ */
917931 memset (& hc -> dev .ic -> ep1_in , 0 , sizeof (hc -> dev .ic -> ep1_in ));
918-
919- /* dword0: EP State=0 (Disabled), CErr=3 */
920932 hc -> dev .ic -> ep1_in .dword0 = (3u << 1 );
921933
922- /* dword1: Max Packet Size (31:16) | EP Type (10:8 = 7 Interrupt IN) | Interval (7:0) */
923- hc -> dev .ic -> ep1_in .dword1 = ((uint32_t )ep_mps << 16 ) | (7u << 8 ) | (interval_field & 0xFFu );
934+ hc -> dev .ic -> ep1_in .dword1 =
935+ ((uint32_t )ep_mps << 16 ) |
936+ ((intval & 0xFFu ) << 8 ) |
937+ (7u << 3 ); /* EPType = 7 (Interrupt IN) in bits [5:3] */
924938
925- /* TR Dequeue (DCS=1) */
926- hc -> dev .ic -> ep1_in .deq = (hc -> dev .int_in_tr .phys | 1u );
939+ hc -> dev .ic -> ep1_in .deq = (hc -> dev .int_in_tr .phys | 1u );
927940
928- /* dword4: Avg TRB Len (31:16) | Max ESIT Payload (15:0) — use pkt_len as both (8 for boot kbd) */
929- hc -> dev .ic -> ep1_in .dword4 = ((uint32_t )pkt_len << 16 ) | (uint32_t )pkt_len ;
941+ {
942+ uint32_t avg_trb_len = 1024 ; /* libpayload uses 1024 for INT */
943+ uint32_t max_esit = ep_mps ; /* MPS * MBS (MBS defaults to 1 for HID) */
944+ hc -> dev .ic -> ep1_in .dword4 = (avg_trb_len << 16 ) | max_esit ;
945+ }
930946
931947 {
932948 const uint32_t * epd = (const uint32_t * )& hc -> dev .ic -> ep1_in ;
933- dprintf ("xhci.dbg: EP1 IN ctx dwords: %08x %08x %08x %08x | %08x %08x %08x %08x (mps=%u bInterval=%u -> interval =%u)\n" ,
949+ dprintf ("xhci.dbg: EP1 IN ctx dwords: %08x %08x %08x %08x | %08x %08x %08x %08x (mps=%u bInterval=%u -> intval =%u)\n" ,
934950 epd [0 ], epd [1 ], epd [2 ], epd [3 ], epd [4 ], epd [5 ], epd [6 ], epd [7 ],
935- ep_mps , ep_bInterval , (unsigned )interval_field );
951+ ep_mps , ep_bInterval , (unsigned )intval );
936952 }
937953
938954 dprintf ("xhci.dbg: CONFIGURE_EP add_flags=%08x slot.dword0=%08x (CE=%u)\n" ,
939- hc -> dev .ic -> add_flags ,
940- hc -> dev .ic -> slot .dword0 ,
955+ hc -> dev .ic -> add_flags , hc -> dev .ic -> slot .dword0 ,
941956 (hc -> dev .ic -> slot .dword0 >> 27 ) & 0x1F );
942957
943958 /* Issue Configure Endpoint (add EP1 IN) */
944959 struct trb * ce = xhci_cmd_begin (hc );
945- ce -> lo = (uint32_t )(hc -> dev .ic_phys & 0xFFFFFFFFu );
946- ce -> hi = (uint32_t )(hc -> dev .ic_phys >> 32 );
960+ ce -> lo = (uint32_t )(hc -> dev .ic_phys & 0xFFFFFFFFu );
961+ ce -> hi = (uint32_t )(hc -> dev .ic_phys >> 32 );
947962 ce -> ctrl |= TRB_SET_TYPE (TRB_CONFIGURE_EP ) | ((uint32_t )ud -> slot_id << 24 );
948963 dprintf ("xhci.dbg: ring_push for CONFIGURE_EP trb=%08x ic_phys_lo=%08x ic_phys_hi=%08x ctrl=%08x slot=%u\n" ,
949964 (uint32_t )(uintptr_t )ce ,
@@ -957,99 +972,41 @@ int xhci_arm_int_in(struct usb_dev *ud, uint16_t pkt_len, xhci_int_in_cb cb) {
957972 }
958973 dprintf ("xhci.dbg: CONFIGURE_EP success\n" );
959974
960- /* Post first INT-IN Normal TRB and doorbell EP1 IN.
961- Use TRB_ISP so short reports complete reliably. */
962- struct trb * n = ring_push (& hc -> dev .int_in_tr );
963- n -> lo = (uint32_t )(hc -> dev .int_buf_phys & 0xFFFFFFFFu );
964- n -> hi = (uint32_t )(hc -> dev .int_buf_phys >> 32 );
965- n -> sts = hc -> dev .int_pkt_len ;
966- n -> ctrl = TRB_SET_TYPE (TRB_NORMAL ) | TRB_IOC | TRB_ISP |
967- (hc -> dev .int_in_tr .cycle ? TRB_CYCLE : 0 );
968- dprintf ("xhci.dbg: INT-IN normal TRB @%08x lo=%08x hi=%08x len=%u ctrl=%08x cycle=%u\n" ,
969- (uint32_t )(uintptr_t )n , n -> lo , n -> hi , n -> sts , n -> ctrl ,
970- (unsigned )hc -> dev .int_in_tr .cycle );
971-
972- mmio_write32 (hc -> db + 4u * ud -> slot_id , EPID_EP1_IN );
973- dprintf ("xhci.dbg: doorbell EP1 IN (slot=%u) tr.phys=%lx buf.phys=%lx\n" ,
974- ud -> slot_id , hc -> dev .int_in_tr .phys , hc -> dev .int_buf_phys );
975-
976- {
977- uint64_t dphys = hc -> dcbaa [ud -> slot_id ];
978- volatile uint32_t * dc = (volatile uint32_t * )(uintptr_t )dphys ;
979-
980- /* 32-byte contexts => 8 dwords per context */
981- const size_t stride = 8 ;
982-
983- volatile uint32_t * d_slot = dc + 0 * stride ; /* Slot Context */
984- volatile uint32_t * d_ep1in = dc + 3 * stride ; /* EP1 IN (ID 3) */
985-
986- uint32_t ep_state = d_ep1in [0 ] & 0x7 ; /* Endpoint State */
987- uint32_t ep_type = (d_ep1in [1 ] >> 3 ) & 0x7 ; /* 7 = Intr IN */
988- uint32_t ep_mps = (d_ep1in [1 ] >> 16 ) & 0xFFFF ; /* Max Packet Size */
989- uint32_t ep_intvl = d_ep1in [1 ] & 0xFF ; /* Interval (xHCI-encoded) */
990- uint32_t avg_len = (d_ep1in [4 ] >> 16 ) & 0xFFFF ;
991- uint32_t max_esit = d_ep1in [4 ] & 0xFFFF ;
992-
993- dprintf ("xhci.dbg: DEV CTX @%lx\n" , (unsigned long )dphys );
994- dprintf ("xhci.dbg: D-SLOT ctx: %08x %08x %08x %08x | %08x %08x %08x %08x\n" ,
995- d_slot [0 ], d_slot [1 ], d_slot [2 ], d_slot [3 ], d_slot [4 ], d_slot [5 ], d_slot [6 ], d_slot [7 ]);
996- dprintf ("xhci.dbg: D-EP1IN ctx: %08x %08x %08x %08x | %08x %08x %08x %08x\n" ,
997- d_ep1in [0 ], d_ep1in [1 ], d_ep1in [2 ], d_ep1in [3 ],
998- d_ep1in [4 ], d_ep1in [5 ], d_ep1in [6 ], d_ep1in [7 ]);
999- dprintf ("xhci.dbg: EP1-IN decoded: state=%u (0=Disabled,1=Running,2=Halted,3=Stopped,4=Error) "
1000- "type=%u mps=%u interval=%u TRDP=%08x%08x avg=%u max_esit=%u\n" ,
1001- ep_state , ep_type , ep_mps , ep_intvl , d_ep1in [3 ], (d_ep1in [2 ] & ~1u ), avg_len , max_esit );
1002- }
1003-
1004- /* after ringing EP1 IN doorbell */
1005- {
1006- /* read the EP1-IN dequeue pointer back */
1007- uint64_t dphys = hc -> dcbaa [ud -> slot_id ];
1008- volatile uint32_t * dc = (volatile uint32_t * )(uintptr_t )dphys ;
1009- volatile uint32_t * d_ep1in = dc + 3 * 8 ; /* 32B contexts -> 8 dwords stride */
1010-
1011- dprintf ("xhci.dbg: EP1-IN TRDP now=%08x%08x (expect ~%08x%08x while first TD outstanding)\n" ,
1012- d_ep1in [3 ], (d_ep1in [2 ] & ~1u ),
1013- (uint32_t )((hc -> dev .int_in_tr .phys + 0 ) >> 32 ),
1014- (uint32_t )(hc -> dev .int_in_tr .phys & ~1u ));
975+ /* Pre-post two INT-IN TRBs (IOC|ISP) and ring once (libpayload style) */
976+ for (int k = 0 ; k < 2 ; ++ k ) {
977+ struct trb * n = ring_push (& hc -> dev .int_in_tr );
978+ n -> lo = (uint32_t )(hc -> dev .int_buf_phys & 0xFFFFFFFFu );
979+ n -> hi = (uint32_t )(hc -> dev .int_buf_phys >> 32 );
980+ n -> sts = hc -> dev .int_pkt_len ;
981+ n -> ctrl = TRB_SET_TYPE (TRB_NORMAL ) | TRB_ISP | TRB_IOC |
982+ (hc -> dev .int_in_tr .cycle ? TRB_CYCLE : 0 );
1015983 }
1016-
1017984 mmio_write32 (hc -> db + 4u * ud -> slot_id , EPID_EP1_IN );
1018- dprintf ("xhci.dbg: doorbell EP1 IN (slot=%u) tr.phys=%lx buf.phys=%lx\n" ,
985+ dprintf ("xhci.dbg: doorbell EP1 IN (slot=%u) tr.phys=%lx buf.phys=%lx (prepost=2) \n" ,
1019986 ud -> slot_id , hc -> dev .int_in_tr .phys , hc -> dev .int_buf_phys );
1020987
988+ /* Steady-state: moderation 0, clear EHB & IP, enable IE and INTE */
1021989 {
1022990 volatile uint8_t * ir0 = hc -> rt + XHCI_RT_IR0 ;
1023991
1024- /* 1) Make moderation a non-issue (fire immediately) */
1025992 mmio_write32 (ir0 + IR_IMOD , 0 );
1026993
1027- /* 2) Clear any stale summary bit and IP, then (re)enable IE */
1028994 uint32_t sts = mmio_read32 (hc -> op + XHCI_USBSTS );
1029995 if (sts & USBSTS_EINT ) mmio_write32 (hc -> op + XHCI_USBSTS , USBSTS_EINT );
1030996
1031997 uint32_t iman = mmio_read32 (ir0 + IR_IMAN );
1032998 if (iman & IR_IMAN_IP ) mmio_write32 (ir0 + IR_IMAN , IR_IMAN_IP ); /* W1C IP */
1033999 mmio_write32 (ir0 + IR_IMAN , (mmio_read32 (ir0 + IR_IMAN ) | IR_IMAN_IE ));
10341000
1035- /* 3) Ensure EHB is CLEAR in steady state */
10361001 uint64_t erdp = mmio_read64 (ir0 + IR_ERDP ) & ~0x7ull ;
1037- mmio_write64 (ir0 + IR_ERDP , erdp ); /* bit3=0 => EHB clear */
1002+ mmio_write64 (ir0 + IR_ERDP , erdp ); /* EHB clear */
10381003
1039- /* 4) Also ensure global INTE is on */
10401004 uint32_t cmd = mmio_read32 (hc -> op + XHCI_USBCMD ) | USBCMD_INTE ;
10411005 mmio_write32 (hc -> op + XHCI_USBCMD , cmd );
10421006
10431007 xhci_irq_sanity_dump (hc , "post-arm" );
10441008 }
10451009
1046- /*
1047- mmio_write32(hc->db + 4u * ud->slot_id, EPID_EP1_IN);
1048- dprintf("xhci.dbg: doorbell EP1 IN (slot=%u) tr.phys=%lx buf.phys=%lx\n",
1049- ud->slot_id, hc->dev.int_in_tr.phys, hc->dev.int_buf_phys);
1050- xhci_wait_for_any_transfer_event(hc, 60000, "ep1-in verify");
1051- */
1052-
10531010 return 1 ;
10541011}
10551012
0 commit comments