@@ -271,7 +271,7 @@ static struct pcisusbXHCIDevice *
271271xhciCreateDeviceCtx (struct PCIController * hc ,
272272UWORD rootPortIndex ,/* 0-based */
273273ULONG route ,/* 20-bit route string (0 for root) */
274- ULONG flags ,/* UHFF_* speed flags */
274+ ULONG flags ,/* UHFF_* speed/ hub flags */
275275UWORD mps0 )/* initial EP0 max packet size */
276276{
277277struct pcisusbXHCIDevice * devCtx ;
@@ -338,14 +338,20 @@ xhciCreateDeviceCtx(struct PCIController *hc,
338338/* ---- Fill Slot Context ---- */
339339
340340/* Root port (1-based) */
341+ islot -> ctx [1 ] &= ~(0xFFUL <<16 );
341342islot -> ctx [1 ] |= (((rootPortIndex + 1 )& 0xFF ) <<16 );
342343
343- /* Route string */
344+ /* Route string(20 bits) */
344345islot -> ctx [0 ] &= ~SLOT_CTX_ROUTE_MASK ;
345346islot -> ctx [0 ] |= (route & SLOT_CTX_ROUTE_MASK );
346347
347- /* Speed bits */
348- islot -> ctx [0 ] &= ~(0xF <<SLOTS_CTX_SPEED );
348+ /* Hub? */
349+ if (flags & UHFF_HUB )
350+ islot -> ctx [0 ] |= (1 <<26 );
351+
352+ /* Speed bits + MTT bit */
353+ islot -> ctx [0 ] &= ~(0xFUL <<SLOTS_CTX_SPEED );
354+ islot -> ctx [0 ] &= ~SLOTF_CTX_MTT ;
349355
350356if (flags & UHFF_SUPERSPEED )
351357islot -> ctx [0 ] |=SLOTF_CTX_SUPERSPEED ;
@@ -356,6 +362,21 @@ xhciCreateDeviceCtx(struct PCIController *hc,
356362else
357363islot -> ctx [0 ] |=SLOTF_CTX_FULLSPEED ;
358364
365+ /* Multi-TT hub? */
366+ if (flags & UHFF_TT_MULTI )
367+ islot -> ctx [0 ] |=SLOTF_CTX_MTT ;
368+
369+ /* simple per-device max transfer tuning based on speed. */
370+ if (flags & UHFF_SUPERSPEED ) {
371+ devCtx -> dx_TxMax = 1024 * 16 ;/* generous default for SS */
372+ }else if (flags & UHFF_HIGHSPEED ) {
373+ devCtx -> dx_TxMax = 512 * 13 ;/* HS worst-case per microframe */
374+ }else if (flags & UHFF_LOWSPEED ) {
375+ devCtx -> dx_TxMax = 8 * 1 ;/* LS: very small payloads */
376+ }else {
377+ devCtx -> dx_TxMax = 64 * 19 ;/* FS: conservative default */
378+ }
379+
359380/* ---- Enable Slot ---- */
360381slotid = xhciCmdSlotEnable (hc );
361382if (slotid < 0 ) {
@@ -674,91 +695,159 @@ void xhciFinishRequest(struct PCIController *hc, struct PCIUnit *unit, struct IO
674695unit -> hu_NakTimeoutFrame [devadrep ]= 0 ;
675696}
676697
698+ static inline void xhciIOErrfromCC (struct IOUsbHWReq * ioreq ,ULONG cc )
699+ {
700+ switch (cc ) {
701+ case TRB_CC_SUCCESS :/* Success */
702+ ioreq -> iouh_Req .io_Error = UHIOERR_NO_ERROR ;
703+ if (ioreq -> iouh_Req .io_Command == UHCMD_INTXFER ) {
704+ /*
705+ * For periodic transfers (INT/ISO), we usually care
706+ * only that something arrived.
707+ */
708+ ioreq -> iouh_Actual = ioreq -> iouh_Length ;
709+ }
710+ break ;
711+
712+ case TRB_CC_BABBLE_DETECTED_ERROR :/* Data Buffer Error / Babble */
713+ ioreq -> iouh_Req .io_Error = UHIOERR_BABBLE ;
714+ break ;
715+
716+ case TRB_CC_STALL_ERROR :/* Stall */
717+ ioreq -> iouh_Req .io_Error = UHIOERR_STALL ;
718+ break ;
719+
720+ case TRB_CC_PARAMETER_ERROR :/* Parameter Error */
721+ ioreq -> iouh_Req .io_Error = UHIOERR_BADPARAMS ;
722+ break ;
723+
724+ case TRB_CC_NO_PING_RESPONSE_ERROR :/* No Ping Response / NAK timeout equivalent */
725+ ioreq -> iouh_Req .io_Error = UHIOERR_NAKTIMEOUT ;
726+ break ;
727+
728+ default :
729+ ioreq -> iouh_Req .io_Error = UHIOERR_HOSTERROR ;
730+ break ;
731+ }
732+ }
733+
677734void xhciHandleFinishedTDs (struct PCIController * hc )
678735{
679736struct PCIUnit * unit = hc -> hc_Unit ;
680737struct IOUsbHWReq * ioreq ,* nextioreq ;
681738struct pciusbXHCIIODevPrivate * driprivate ;
682739UWORD devadrep ;
683- ULONG actual ;
684740BOOL transactiondone ;
685741
686742pciusbXHCIDebug ("xHCI" ,DEBUGFUNCCOLOR_SET "%s()" DEBUGCOLOR_RESET " \n" ,__func__ );
687743
744+ /* PERIODIC (INT/ISO) COMPLETIONS */
688745pciusbXHCIDebug ("xHCI" ,DEBUGCOLOR_SET "Checking for Periodic work done..." DEBUGCOLOR_RESET " \n" );
689- ioreq = (struct IOUsbHWReq * )hc -> hc_PeriodicTDQueue .lh_Head ;
690- while ((nextioreq = (struct IOUsbHWReq * ) ((struct Node * )ioreq )-> ln_Succ )) {
746+ ioreq = (struct IOUsbHWReq * )hc -> hc_PeriodicTDQueue .lh_Head ;
747+ while ((nextioreq = (struct IOUsbHWReq * )((struct Node * )ioreq )-> ln_Succ )) {
691748pciusbXHCIDebug ("xHCI" ,DEBUGCOLOR_SET "Examining IOReq=0x%p" DEBUGCOLOR_RESET " \n" ,ioreq );
692749
693- #if (0 )
694- if ((driprivate = (struct pciusbXHCIIODevPrivate * )ioreq -> iouh_DriverPrivate1 )!= NULL ) {
695- #endif
696- transactiondone = FALSE;
697- devadrep = (ioreq -> iouh_DevAddr <<5 )+ ioreq -> iouh_Endpoint + ((ioreq -> iouh_Dir == UHDIR_IN ) ?0x10 :0 );
750+ driprivate = (struct pciusbXHCIIODevPrivate * )ioreq -> iouh_DriverPrivate1 ;
751+ transactiondone = FALSE;
698752
699- if (unit -> hu_NakTimeoutFrame [devadrep ]&& (hc -> hc_FrameCounter > unit -> hu_NakTimeoutFrame [devadrep ])) {
700- pciusbWarn ("xHCI" ,DEBUGWARNCOLOR_SET "xHCI: Periodic NAK timeout (%u)" DEBUGCOLOR_RESET " \n" ,unit -> hu_NakTimeoutFrame [devadrep ]);
701- ioreq -> iouh_Req .io_Error = UHIOERR_NAKTIMEOUT ;
702- transactiondone = TRUE;
703- }
753+ /* DevEP index for timeouts */
754+ devadrep = (ioreq -> iouh_DevAddr <<5 )+ ioreq -> iouh_Endpoint
755+ + ((ioreq -> iouh_Dir == UHDIR_IN ) ?0x10 :0 );
704756
705- if (transactiondone ) {
706- ioreq -> iouh_Actual += actual ;
707- xhciFreePeriodicContext (hc ,unit ,ioreq );
708- ReplyMsg (& ioreq -> iouh_Req .io_Message );
757+ /*
758+ * Completion via TRB completion code (dpCC > 0).
759+ * This is what happens for hub status-change interrupts.
760+ */
761+ if (driprivate && (driprivate -> dpCC > TRB_CC_INVALID )) {
762+ pciusbXHCIDebug ("xHCI" ,
763+ DEBUGCOLOR_SET "Periodic IOReq Complete (completion code %u)!"
764+ DEBUGCOLOR_RESET " \n" ,
765+ driprivate -> dpCC );
766+ transactiondone = TRUE;
767+
768+ xhciIOErrfromCC (ioreq ,driprivate -> dpCC );
769+
770+ /* Clear the timeout slot once we have a completion */
771+ unit -> hu_NakTimeoutFrame [devadrep ]= 0 ;
772+
773+ }else if (unit -> hu_NakTimeoutFrame [devadrep ]&&
774+ (hc -> hc_FrameCounter > unit -> hu_NakTimeoutFrame [devadrep ])) {
775+ /*
776+ * Legacy NAK timeout handling for periodic transfers.
777+ * This is the only path that previously fired.
778+ */
779+ pciusbWarn ("xHCI" ,
780+ DEBUGWARNCOLOR_SET "xHCI: Periodic NAK timeout (%u)"
781+ DEBUGCOLOR_RESET " \n" ,
782+ unit -> hu_NakTimeoutFrame [devadrep ]);
783+ ioreq -> iouh_Req .io_Error = UHIOERR_NAKTIMEOUT ;
784+ transactiondone = TRUE;
785+ unit -> hu_NakTimeoutFrame [devadrep ]= 0 ;
786+ }
787+
788+ if (transactiondone ) {
789+ if (!ioreq -> iouh_Req .io_Error &&
790+ ioreq -> iouh_Req .io_Command == UHCMD_INTXFER &&
791+ ioreq -> iouh_Length > 0 &&
792+ ioreq -> iouh_Data ) {
793+ UBYTE * p = (UBYTE * )ioreq -> iouh_Data ;
794+ pciusbXHCIDebug ("xHCI" ,
795+ "Hub INT data (addr=%u, ep=%u): first byte = 0x%02x\n" ,
796+ ioreq -> iouh_DevAddr ,
797+ ioreq -> iouh_Endpoint ,
798+ p [0 ]);
709799 }
710- #if (0 )
800+ /*
801+ * Free periodic context (EP ring bookkeeping etc.) and
802+ * notify the upper layers. Hub.class will typically
803+ * resubmit the interrupt transfer if it wants continuous
804+ * status change notifications.
805+ */
806+ xhciFreePeriodicContext (hc ,unit ,ioreq );
807+ ReplyMsg (& ioreq -> iouh_Req .io_Message );
711808 }
712- #endif
809+
713810ioreq = nextioreq ;
714811 }
715812
813+ /* ASYNC (CTRL/BULK) COMPLETIONS */
716814pciusbXHCIDebug ("xHCI" ,DEBUGCOLOR_SET "Checking for Standard work done..." DEBUGCOLOR_RESET " \n" );
717- ioreq = (struct IOUsbHWReq * )hc -> hc_TDQueue .lh_Head ;
718- while ((nextioreq = (struct IOUsbHWReq * ) ((struct Node * )ioreq )-> ln_Succ )) {
815+ ioreq = (struct IOUsbHWReq * )hc -> hc_TDQueue .lh_Head ;
816+ while ((nextioreq = (struct IOUsbHWReq * )((struct Node * )ioreq )-> ln_Succ )) {
719817pciusbXHCIDebug ("xHCI" ,DEBUGCOLOR_SET "Examining IOReq=0x%p" DEBUGCOLOR_RESET " \n" ,ioreq );
720818
721- if ((driprivate = (struct pciusbXHCIIODevPrivate * )ioreq -> iouh_DriverPrivate1 )!= NULL ) {
819+ driprivate = (struct pciusbXHCIIODevPrivate * )ioreq -> iouh_DriverPrivate1 ;
820+ if (driprivate ) {
722821transactiondone = FALSE;
723- devadrep = (ioreq -> iouh_DevAddr <<5 )+ ioreq -> iouh_Endpoint + ((ioreq -> iouh_Dir == UHDIR_IN ) ?0x10 :0 );
822+ devadrep = (ioreq -> iouh_DevAddr <<5 )+ ioreq -> iouh_Endpoint
823+ + ((ioreq -> iouh_Dir == UHDIR_IN ) ?0x10 :0 );
724824
725825if (driprivate -> dpCC > 0 ) {
726- pciusbXHCIDebug ("xHCI" ,DEBUGCOLOR_SET "IOReq Complete (completion code %u)!" DEBUGCOLOR_RESET " \n" ,driprivate -> dpCC );
826+ pciusbXHCIDebug ("xHCI" ,
827+ DEBUGCOLOR_SET "IOReq Complete (completion code %u)!"
828+ DEBUGCOLOR_RESET " \n" ,
829+ driprivate -> dpCC );
727830transactiondone = TRUE;
728- switch (driprivate -> dpCC ) {
729- case 1 :
730- ioreq -> iouh_Req .io_Error = UHIOERR_NO_ERROR ;
731- break ;
732-
733- case 3 :
734- ioreq -> iouh_Req .io_Error = UHIOERR_BABBLE ;
735- break ;
736-
737- case 6 :
738- ioreq -> iouh_Req .io_Error = UHIOERR_STALL ;
739- break ;
740-
741- case 17 :
742- ioreq -> iouh_Req .io_Error = UHIOERR_BADPARAMS ;// Param Error
743- break ;
744-
745- case 20 :
746- ioreq -> iouh_Req .io_Error = UHIOERR_NAKTIMEOUT ;// No Ping Response
747- break ;
748-
749- default :
750- ioreq -> iouh_Req .io_Error = UHIOERR_HOSTERROR ;
751- break ;
752- }
753- }else if (unit -> hu_NakTimeoutFrame [devadrep ]&& (hc -> hc_FrameCounter > unit -> hu_NakTimeoutFrame [devadrep ])) {
754- pciusbWarn ("xHCI" ,DEBUGWARNCOLOR_SET "xHCI: Async NAK timeout (%u)" DEBUGCOLOR_RESET " \n" ,unit -> hu_NakTimeoutFrame [devadrep ]);
831+
832+ xhciIOErrfromCC (ioreq ,driprivate -> dpCC );
833+
834+ unit -> hu_NakTimeoutFrame [devadrep ]= 0 ;
835+
836+ }else if (unit -> hu_NakTimeoutFrame [devadrep ]&&
837+ (hc -> hc_FrameCounter > unit -> hu_NakTimeoutFrame [devadrep ])) {
838+ pciusbWarn ("xHCI" ,
839+ DEBUGWARNCOLOR_SET "xHCI: Async NAK timeout (%u)"
840+ DEBUGCOLOR_RESET " \n" ,
841+ unit -> hu_NakTimeoutFrame [devadrep ]);
755842ioreq -> iouh_Req .io_Error = UHIOERR_NAKTIMEOUT ;
756843transactiondone = TRUE;
844+ unit -> hu_NakTimeoutFrame [devadrep ]= 0 ;
757845 }
758846
759847if (transactiondone ) {
760848xhciFreeAsyncContext (hc ,unit ,ioreq );
761- if ((!ioreq -> iouh_Req .io_Error )&& (ioreq -> iouh_Req .io_Command == UHCMD_CONTROLXFER )) {
849+ if ((!ioreq -> iouh_Req .io_Error )&&
850+ (ioreq -> iouh_Req .io_Command == UHCMD_CONTROLXFER )) {
762851uhwCheckSpecialCtrlTransfers (hc ,ioreq );
763852 }
764853ReplyMsg (& ioreq -> iouh_Req .io_Message );
@@ -1109,7 +1198,6 @@ void xhciReset(struct PCIController *hc, struct PCIUnit *hu)
11091198xhciDumpIR (xhciir );
11101199}
11111200
1112-
11131201AROS_UFH0 (void ,xhciControllerTask )
11141202{
11151203AROS_USERFUNC_INIT
@@ -1118,8 +1206,8 @@ AROS_UFH0(void, xhciControllerTask)
11181206struct PCIController * hc ;
11191207struct Task * thistask ;
11201208struct pcisusbXHCIDevice * devCtx ;
1121- ULONG sigmask , portsc ;
1122- UWORD hciport ;
1209+ ULONG portsc ;
1210+ UWORD hciport ;
11231211
11241212thistask = FindTask (NULL );
11251213hc = thistask -> tc_UserData ;
@@ -1137,28 +1225,32 @@ AROS_UFH0(void, xhciControllerTask)
11371225
11381226for (;;) {
11391227ULONG xhcictsigs = Wait ((1 <<hc -> hc_DoWorkSignal ) | (1 <<hc -> hc_PortChangeSignal ));
1140- #if (1 )
1141- pciusbXHCIDebug ("xHCI" ,DEBUGCOLOR_SET "xhciControllerTask @ 0x%p, IDnest %d TDNest %d" DEBUGCOLOR_RESET " \n" ,thistask ,thistask -> tc_IDNestCnt ,thistask -> tc_TDNestCnt );
1228+ #if defined(DEBUG )&& (DEBUG > 1 )
1229+ pciusbXHCIDebug ("xHCI" ,
1230+ DEBUGCOLOR_SET "xhciControllerTask @ 0x%p, IDnest %d TDNest %d"
1231+ DEBUGCOLOR_RESET " \n" ,
1232+ thistask ,thistask -> tc_IDNestCnt ,thistask -> tc_TDNestCnt );
11421233#endif
11431234
11441235if (xhcictsigs & (1 <<hc -> hc_DoWorkSignal )) {
11451236pciusbXHCIDebug ("xHCI" ,DEBUGCOLOR_SET "Processing pending HC work" DEBUGCOLOR_RESET " \n" );
11461237xhciHandleFinishedTDs (hc );
11471238
1148- if (hc -> hc_IntXFerQueue .lh_Head -> ln_Succ ) {
1239+ if (hc -> hc_IntXFerQueue .lh_Head -> ln_Succ )
11491240xhciScheduleIntTDs (hc );
1150- }
1151- if (hc -> hc_CtrlXFerQueue .lh_Head -> ln_Succ ) {
1241+
1242+ if (hc -> hc_CtrlXFerQueue .lh_Head -> ln_Succ )
11521243xhciScheduleAsyncTDs (hc ,& hc -> hc_CtrlXFerQueue ,UHCMD_CONTROLXFER );
1153- }
1154- if (hc -> hc_BulkXFerQueue .lh_Head -> ln_Succ ) {
1244+
1245+ if (hc -> hc_BulkXFerQueue .lh_Head -> ln_Succ )
11551246xhciScheduleAsyncTDs (hc ,& hc -> hc_BulkXFerQueue ,UHCMD_BULKXFER );
1156- }
11571247 }
1248+
11581249if (xhcictsigs & (1 <<hc -> hc_PortChangeSignal )) {
11591250for (hciport = 0 ;hciport < hc -> hc_NumPorts ;hciport ++ ) {
11601251portsc = AROS_LE2LONG (xhciports [hciport ].portsc );
11611252devCtx = xhciFindPortDevice (hc ,hciport );
1253+
11621254if ((portsc & XHCIF_PR_PORTSC_PED )&& (!devCtx )) {
11631255UWORD rootPort = hciport ;/* 0-based */
11641256ULONG route = 0 ;/* root-attached */
@@ -1172,7 +1264,7 @@ AROS_UFH0(void, xhciControllerTask)
11721264flags |=UHFF_LOWSPEED ;
11731265mps0 = 8 ;/* LS EP0 = 8 bytes */
11741266 }else if (speedBits == XHCIF_PR_PORTSC_FULLSPEED ) {
1175- /*Full speed: EP0 is 8,16,32, 64 use 8 untilwe see bMaxPacketSize0 */
1267+ /*FS EP0 is 8/16/32/ 64 start with 8 untilbMaxPacketSize0 is known */
11761268mps0 = 8 ;
11771269 }else if (speedBits == XHCIF_PR_PORTSC_HIGHSPEED ) {
11781270flags |=UHFF_HIGHSPEED ;
@@ -1181,18 +1273,31 @@ AROS_UFH0(void, xhciControllerTask)
11811273flags |=UHFF_SUPERSPEED ;
11821274mps0 = 512 ;/* SS EP0 max packet size */
11831275 }else {
1184- /* Unknown/invalid speed leave defaults,let enumerationsort it out */
1276+ /* Unknown/invalid speed leave defaults, enumerationwill adjust */
11851277 }
1186- devCtx = xhciCreateDeviceCtx (hc ,rootPort ,route ,flags ,mps0 );
1187- if (devCtx )
1278+
1279+ /* Root hub device: always a hub from the HCs perspective */
1280+ devCtx = xhciCreateDeviceCtx (hc ,
1281+ rootPort ,
1282+ route ,
1283+ flags |UHFF_HUB ,
1284+ mps0 );
1285+ if (devCtx ) {
1286+ /* Root port device lives on this controller */
11881287hc -> hc_Unit -> hu_DevControllers [0 ]= hc ;
1189- }else if ((!(portsc & XHCIF_PR_PORTSC_PED ))&& (devCtx )) {
1288+ }
1289+ }else if (!(portsc & XHCIF_PR_PORTSC_PED )&& devCtx ) {
11901290if ((devCtx -> dc_SlotID > 0 )&& (devCtx -> dc_SlotID < USB_DEV_MAX ))
11911291hc -> hc_Devices [devCtx -> dc_SlotID ]= NULL ;
11921292
1193- pciusbXHCIDebug ("xHCI" ,DEBUGCOLOR_SET "Detaching HCI Device Ctx @ 0x%p" DEBUGCOLOR_RESET " \n" ,devCtx );
1293+ pciusbXHCIDebug ("xHCI" ,
1294+ DEBUGCOLOR_SET "Detaching HCI Device Ctx @ 0x%p"
1295+ DEBUGCOLOR_RESET " \n" ,
1296+ devCtx );
11941297
1195- xhciSetPointer (hc , ((volatile struct xhci_address * )hc -> hc_DCBAAp )[devCtx -> dc_SlotID ],0 );
1298+ xhciSetPointer (hc ,
1299+ ((volatile struct xhci_address * )hc -> hc_DCBAAp )[devCtx -> dc_SlotID ],
1300+ 0 );
11961301if (devCtx -> dc_SlotCtx .dmaa_Entry .me_Un .meu_Addr )
11971302FREEPCIMEM (hc ,hc -> hc_PCIDriverObject ,devCtx -> dc_SlotCtx .dmaa_Entry .me_Un .meu_Addr );
11981303if (devCtx -> dc_IN .dmaa_Entry .me_Un .meu_Addr )