SAMA5 EHCI: Initial debug changes
This commit is contained in:
parent
f356586fd3
commit
eef0f392ec
@ -143,7 +143,7 @@ struct sam_qh_s
|
|||||||
/* Internal fields used by the EHCI driver */
|
/* Internal fields used by the EHCI driver */
|
||||||
|
|
||||||
struct sam_epinfo_s *epinfo; /* Endpoint used for the transfer */
|
struct sam_epinfo_s *epinfo; /* Endpoint used for the transfer */
|
||||||
uint32_t pad[12]; /* Padding to assure 32-byte alignment */
|
uint8_t pad[12]; /* Padding to assure 32-byte alignment */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Internal representation of the EHCI Queue Element Transfer Descriptor (qTD) */
|
/* Internal representation of the EHCI Queue Element Transfer Descriptor (qTD) */
|
||||||
@ -299,6 +299,18 @@ static int sam_qh_flush(struct sam_qh_s *qh);
|
|||||||
|
|
||||||
/* Endpoint Transfer Handling **************************************************/
|
/* Endpoint Transfer Handling **************************************************/
|
||||||
|
|
||||||
|
#ifdef CONFIG_SAMA5_EHCI_REGDEBUG
|
||||||
|
static int sam_qtd_dump(struct sam_qtd_s *qtd, uint32_t **bp, void *arg);
|
||||||
|
static int sam_qh_dump(struct sam_qh_s *qh, uint32_t **bp, void *arg);
|
||||||
|
#if 0 /* not used */
|
||||||
|
static int sam_qh_dumpall(void);
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
# define sam_qtd_dump(qtd, bp, arg) OK
|
||||||
|
# define sam_qh_dump(qh, bp, arg) OK
|
||||||
|
# define sam_qh_dumpall() OK
|
||||||
|
#endif
|
||||||
|
|
||||||
static int sam_ioc_setup(struct sam_rhport_s *rhport, struct sam_epinfo_s *epinfo);
|
static int sam_ioc_setup(struct sam_rhport_s *rhport, struct sam_epinfo_s *epinfo);
|
||||||
static int sam_ioc_wait(struct sam_epinfo_s *epinfo);
|
static int sam_ioc_wait(struct sam_epinfo_s *epinfo);
|
||||||
static void sam_qh_enqueue(struct sam_qh_s *qh);
|
static void sam_qh_enqueue(struct sam_qh_s *qh);
|
||||||
@ -673,7 +685,7 @@ static int ehci_wait_usbsts(uint32_t maskbits, uint32_t donebits,
|
|||||||
regval = sam_getreg(&HCOR->usbsts);
|
regval = sam_getreg(&HCOR->usbsts);
|
||||||
if ((regval & EHCI_INT_SYSERROR) != 0)
|
if ((regval & EHCI_INT_SYSERROR) != 0)
|
||||||
{
|
{
|
||||||
udbg("ERROR: System error: 0x%08X", regval);
|
udbg("ERROR: System error: %08x\n", regval);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -933,19 +945,20 @@ static int sam_qtd_foreach(struct sam_qh_s *qh, foreach_qtd_t handler, void *arg
|
|||||||
|
|
||||||
/* Handle the special case where the queue is empty */
|
/* Handle the special case where the queue is empty */
|
||||||
|
|
||||||
bp = &qh->hw.overlay.nqp;
|
bp = &qh->hw.overlay.nqp; /* Start of qTDs remaining */
|
||||||
if ((*bp & QH_NQP_T) != 0)
|
physaddr = sam_swap32(*bp); /* Physical address of first qTD in CPU order */
|
||||||
|
|
||||||
|
if ((physaddr & QH_NQP_T) != 0)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Start with the first qTD in the queue */
|
/* Start with the first qTD in the list */
|
||||||
|
|
||||||
physaddr = sam_swap32(*bp);
|
qtd = (struct sam_qtd_s *)sam_virtramaddr(physaddr);
|
||||||
qtd = (struct sam_qtd_s *)sam_virtramaddr(physaddr);
|
next = NULL;
|
||||||
next = NULL;
|
|
||||||
|
|
||||||
/* Now loop until we encounter the end of the qTD list */
|
/* And loop until we encounter the end of the qTD list */
|
||||||
|
|
||||||
while (qtd)
|
while (qtd)
|
||||||
{
|
{
|
||||||
@ -1130,8 +1143,8 @@ static int sam_qh_flush(struct sam_qh_s *qh)
|
|||||||
{
|
{
|
||||||
/* Flush the QH first */
|
/* Flush the QH first */
|
||||||
|
|
||||||
cp15_invalidate_dcache((uintptr_t)&qh->hw,
|
cp15_coherent_dcache((uintptr_t)&qh->hw,
|
||||||
(uintptr_t)&qh->hw + sizeof(struct ehci_qh_s));
|
(uintptr_t)&qh->hw + sizeof(struct ehci_qh_s));
|
||||||
|
|
||||||
/* Then flush all of the qTD entries in the queue */
|
/* Then flush all of the qTD entries in the queue */
|
||||||
|
|
||||||
@ -1143,7 +1156,73 @@ static int sam_qh_flush(struct sam_qh_s *qh)
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Name: sam_ioc_setup
|
* Name: sam_qtd_dump
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* This is a sam_qtd_foreach callout function. It dumps the context of one
|
||||||
|
* qTD
|
||||||
|
*
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#ifdef CONFIG_SAMA5_EHCI_REGDEBUG
|
||||||
|
static int sam_qtd_dump(struct sam_qtd_s *qtd, uint32_t **bp, void *arg)
|
||||||
|
{
|
||||||
|
uvdbg(" QTD[%p]:\n", qtd);
|
||||||
|
uvdbg(" hw:\n");
|
||||||
|
uvdbg(" nqp: %08x alt: %08x token: %08x\n",
|
||||||
|
qtd->hw.nqp, qtd->hw.alt, qtd->hw.token);
|
||||||
|
uvdbg(" bpl: %08x %08x %08x %08x %08x\n",
|
||||||
|
qtd->hw.bpl[0], qtd->hw.bpl[1], qtd->hw.bpl[2],
|
||||||
|
qtd->hw.bpl[3], qtd->hw.bpl[4]);
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Name: sam_qh_dump
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* This is a sam_qh_foreach callout function. It dumps a QH structure and
|
||||||
|
* all of the qTD structures linked to the QH.
|
||||||
|
*
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#ifdef CONFIG_SAMA5_EHCI_REGDEBUG
|
||||||
|
static int sam_qh_dump(struct sam_qh_s *qh, uint32_t **bp, void *arg)
|
||||||
|
{
|
||||||
|
struct sam_epinfo_s *epinfo;
|
||||||
|
struct ehci_overlay_s *overlay;
|
||||||
|
|
||||||
|
uvdbg("QH[%p]:\n", qh);
|
||||||
|
uvdbg(" hw:\n");
|
||||||
|
uvdbg(" hlp: %08x epchar: %08x epcaps: %08x cqp: %08x\n",
|
||||||
|
qh->hw.hlp, qh->hw.epchar, qh->hw.epcaps, qh->hw.cqp);
|
||||||
|
|
||||||
|
overlay = &qh->hw.overlay;
|
||||||
|
uvdbg(" overlay:\n");
|
||||||
|
uvdbg(" nqp: %08x alt: %08x token: %08x\n",
|
||||||
|
overlay->nqp, overlay->alt, overlay->token);
|
||||||
|
uvdbg(" bpl: %08x %08x %08x %08x %08x\n",
|
||||||
|
overlay->bpl[0], overlay->bpl[1], overlay->bpl[2],
|
||||||
|
overlay->bpl[3], overlay->bpl[4]);
|
||||||
|
|
||||||
|
epinfo = qh->epinfo;
|
||||||
|
uvdbg(" epinfo[%p]:\n", epinfo);
|
||||||
|
if (epinfo)
|
||||||
|
{
|
||||||
|
uvdbg(" EP%d DIR=%s FA=%08x TYPE=%d MaxPacket=%d\n",
|
||||||
|
epinfo->epno, epinfo->dirin ? "IN" : "OUT", epinfo->devaddr,
|
||||||
|
epinfo->xfrtype, epinfo->maxpacket);
|
||||||
|
uvdbg(" Toggle=%d iocwait=%d speed=%d result=%d\n",
|
||||||
|
epinfo->toggle, epinfo->iocwait, epinfo->speed, epinfo->result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sam_qtd_foreach(qh, sam_qtd_dump, NULL);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Name: sam_qh_dumpall
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* Set the request for the IOC event well BEFORE enabling the transfer (as
|
* Set the request for the IOC event well BEFORE enabling the transfer (as
|
||||||
@ -1153,12 +1232,34 @@ static int sam_qh_flush(struct sam_qh_s *qh)
|
|||||||
*
|
*
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#ifdef CONFIG_SAMA5_EHCI_REGDEBUG
|
||||||
|
#if 0 /* not used */
|
||||||
|
static int sam_qh_dumpall(void)
|
||||||
|
{
|
||||||
|
return sam_qh_forall(sam_qh_dump, NULL);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Name: sam_ioc_setup
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Set the request for the IOC event well BEFORE enabling the transfer (as
|
||||||
|
* soon as we are absolutely committed to the to avoid transfer). We do this
|
||||||
|
* to minimize race conditions. This logic would have to be expanded if we
|
||||||
|
* want to have more than one packet in flight at a time!
|
||||||
|
*
|
||||||
|
* Assumption: The caller holds tex EHCI exclsem
|
||||||
|
*
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
static int sam_ioc_setup(struct sam_rhport_s *rhport, struct sam_epinfo_s *epinfo)
|
static int sam_ioc_setup(struct sam_rhport_s *rhport, struct sam_epinfo_s *epinfo)
|
||||||
{
|
{
|
||||||
irqstate_t flags;
|
irqstate_t flags;
|
||||||
int ret = -ENODEV;
|
int ret = -ENODEV;
|
||||||
|
|
||||||
DEBUGASSERT(rhport && epinfo);
|
DEBUGASSERT(rhport && epinfo && !epinfo->iocwait);
|
||||||
|
|
||||||
/* Is the device still connected? */
|
/* Is the device still connected? */
|
||||||
|
|
||||||
@ -1186,6 +1287,9 @@ static int sam_ioc_setup(struct sam_rhport_s *rhport, struct sam_epinfo_s *epinf
|
|||||||
* Description:
|
* Description:
|
||||||
* Wait for the IOC event.
|
* Wait for the IOC event.
|
||||||
*
|
*
|
||||||
|
* Assumption: The caller does *NOT* hold the EHCI exclsem. That would cause
|
||||||
|
* a deadlock when the bottom-half, worker thread needs to take the semaphore.
|
||||||
|
*
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
static int sam_ioc_wait(struct sam_epinfo_s *epinfo)
|
static int sam_ioc_wait(struct sam_epinfo_s *epinfo)
|
||||||
@ -1311,7 +1415,10 @@ static struct sam_qh_s *sam_qh_create(struct sam_rhport_s *rhport,
|
|||||||
* next qTD is added to the queue.
|
* next qTD is added to the queue.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
qh->hw.hlp = sam_swap32(QH_HLP_T);
|
||||||
qh->hw.overlay.nqp = sam_swap32(QH_NQP_T);
|
qh->hw.overlay.nqp = sam_swap32(QH_NQP_T);
|
||||||
|
qh->hw.overlay.alt = sam_swap32(QH_AQP_T);
|
||||||
|
return qh;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
@ -1564,7 +1671,10 @@ static struct sam_qtd_s *sam_qtd_statusphase(uint32_t tokenbits)
|
|||||||
* This is a blocking function; it will not return until the control transfer
|
* This is a blocking function; it will not return until the control transfer
|
||||||
* has completed.
|
* has completed.
|
||||||
*
|
*
|
||||||
* Assumption: The caller holds the EHCI exclsem
|
* Assumption: The caller holds the EHCI exclsem. The caller must be aware
|
||||||
|
* that the EHCI exclsem will released while waiting for the transfer to
|
||||||
|
* complete, but will be re-aquired when before returning. The state of
|
||||||
|
* EHCI resources could be very different upon return.
|
||||||
*
|
*
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
@ -1638,7 +1748,7 @@ static int sam_async_transfer(struct sam_rhport_s *rhport,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
flink = &qh->hw.overlay.nqp;
|
flink = &qh->hw.overlay.nqp;
|
||||||
toggle = epinfo->toggle ? 0 : QTD_TOKEN_TOGGLE;
|
toggle = (uint32_t)epinfo->toggle << QTD_TOKEN_TOGGLE_SHIFT;
|
||||||
ret = -EIO;
|
ret = -EIO;
|
||||||
|
|
||||||
/* Is the an EP0 SETUP request? If req will be non-NULL */
|
/* Is the an EP0 SETUP request? If req will be non-NULL */
|
||||||
@ -1714,7 +1824,7 @@ static int sam_async_transfer(struct sam_rhport_s *rhport,
|
|||||||
{
|
{
|
||||||
/* Extra TOKEN bits include the data toggle and the data PID. */
|
/* Extra TOKEN bits include the data toggle and the data PID. */
|
||||||
|
|
||||||
uint32_t tokenbits = toggle | datapid ;
|
uint32_t tokenbits = toggle | datapid;
|
||||||
|
|
||||||
/* Allocate a new Queue Element Transfer Descriptor (qTD) for the status */
|
/* Allocate a new Queue Element Transfer Descriptor (qTD) for the status */
|
||||||
|
|
||||||
@ -1733,11 +1843,33 @@ static int sam_async_transfer(struct sam_rhport_s *rhport,
|
|||||||
|
|
||||||
/* Add the new QH to the head of the asynchronous queue list */
|
/* Add the new QH to the head of the asynchronous queue list */
|
||||||
|
|
||||||
|
(void)sam_qh_dump(qh, NULL, NULL);
|
||||||
sam_qh_enqueue(qh);
|
sam_qh_enqueue(qh);
|
||||||
|
|
||||||
|
/* Release the EHCI semaphore while we wait. Other threads need the
|
||||||
|
* opportunity to access the EHCI resources while we wait.
|
||||||
|
*
|
||||||
|
* REVISIT: Is this safe? NO. This is a bug and needs rethinking.
|
||||||
|
* We need to lock all of the port-resources (not EHCI common) until
|
||||||
|
* the transfer is complete. But we can't use the common ECHI exclsem
|
||||||
|
* or we will deadlock while waiting (because the working thread that
|
||||||
|
* wakes this thread up needs the exclsem).
|
||||||
|
*/
|
||||||
|
#warning REVISIT
|
||||||
|
sam_givesem(&g_ehci.exclsem);
|
||||||
|
|
||||||
/* Wait for the IOC completion event */
|
/* Wait for the IOC completion event */
|
||||||
|
|
||||||
ret = sam_ioc_wait(epinfo);
|
ret = sam_ioc_wait(epinfo);
|
||||||
|
|
||||||
|
/* Re-aquire the ECHI semaphore. The caller expects to be holding
|
||||||
|
* this upon return.
|
||||||
|
*/
|
||||||
|
|
||||||
|
sam_takesem(&g_ehci.exclsem);
|
||||||
|
|
||||||
|
/* Did sam_ioc_wait() report an error? */
|
||||||
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
udbg("ERROR: Transfer failed\n");
|
udbg("ERROR: Transfer failed\n");
|
||||||
@ -1875,7 +2007,7 @@ static int sam_qh_ioccheck(struct sam_qh_s *qh, uint32_t **bp, void *arg)
|
|||||||
{
|
{
|
||||||
/* No errors.. Save the last data toggle value */
|
/* No errors.. Save the last data toggle value */
|
||||||
|
|
||||||
epinfo->toggle = ((token & QTD_TOKEN_TOGGLE) != 0);
|
epinfo->toggle = (token >> QTD_TOKEN_TOGGLE_SHIFT) & 1;
|
||||||
|
|
||||||
/* Report success */
|
/* Report success */
|
||||||
|
|
||||||
@ -1912,6 +2044,8 @@ static int sam_qh_ioccheck(struct sam_qh_s *qh, uint32_t **bp, void *arg)
|
|||||||
|
|
||||||
*bp = &qh->hw.overlay.nqp;
|
*bp = &qh->hw.overlay.nqp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
@ -2418,7 +2552,7 @@ static int sam_enumerate(FAR struct usbhost_connection_s *conn, int rhpndx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* USB 2.0 spec says at least 50ms delay before port reset.
|
/* USB 2.0 spec says at least 50ms delay before port reset.
|
||||||
* REVISIT: I think this is wrong. It needs to hold the port in
|
* REVISIT: I think this is wrong. It needs to hold the port in
|
||||||
* reset for 50Msec, not wait 50Msec before resetting.
|
* reset for 50Msec, not wait 50Msec before resetting.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -2574,7 +2708,7 @@ static int sam_epalloc(FAR struct usbhost_driver_s *drvr,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
DEBUGASSERT(drvr && epdesc && ep);
|
DEBUGASSERT(drvr && epdesc && ep);
|
||||||
uvdbg("EP%d DIR=%s FA=%08x TYPE=%d Interval=%d Max Packet Size=%d\n",
|
uvdbg("EP%d DIR=%s FA=%08x TYPE=%d Interval=%d MaxPacket=%d\n",
|
||||||
epdesc->addr, epdesc->in ? "IN" : "OUT", epdesc->funcaddr,
|
epdesc->addr, epdesc->in ? "IN" : "OUT", epdesc->funcaddr,
|
||||||
epdesc->xfrtype, epdesc->interval, epdesc->mxpacketsize);
|
epdesc->xfrtype, epdesc->interval, epdesc->mxpacketsize);
|
||||||
|
|
||||||
@ -3062,7 +3196,7 @@ static int sam_reset(void)
|
|||||||
|
|
||||||
if ((regval & EHCI_USBSTS_HALTED) == 0)
|
if ((regval & EHCI_USBSTS_HALTED) == 0)
|
||||||
{
|
{
|
||||||
udbg("ERROR: Timed out waiting for HCHalted. USBSTS: %08X", regval);
|
udbg("ERROR: Timed out waiting for HCHalted. USBSTS: %08x", regval);
|
||||||
return -ETIMEDOUT;
|
return -ETIMEDOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3296,14 +3430,14 @@ FAR struct usbhost_connection_s *sam_ehci_initialize(int controller)
|
|||||||
/* Show the ECHI version */
|
/* Show the ECHI version */
|
||||||
|
|
||||||
regval16 = sam_swap16(HCCR->hciversion);
|
regval16 = sam_swap16(HCCR->hciversion);
|
||||||
uvdbg("HCIVERSIONI %x.%02x", regval16 >> 8, regval16 & 0xff);
|
uvdbg("HCIVERSION %x.%02x\n", regval16 >> 8, regval16 & 0xff);
|
||||||
|
|
||||||
/* Verify the the correct number of ports is reported */
|
/* Verify the the correct number of ports is reported */
|
||||||
|
|
||||||
regval = sam_getreg(&HCCR->hcsparams);
|
regval = sam_getreg(&HCCR->hcsparams);
|
||||||
nports = (regval & EHCI_HCSPARAMS_NPORTS_MASK) >> EHCI_HCSPARAMS_NPORTS_SHIFT;
|
nports = (regval & EHCI_HCSPARAMS_NPORTS_MASK) >> EHCI_HCSPARAMS_NPORTS_SHIFT;
|
||||||
|
|
||||||
uvdbg("HCSPARAMS=%08x nports=%d", regval, nports);
|
uvdbg("HCSPARAMS=%08x nports=%d\n", regval, nports);
|
||||||
DEBUGASSERT(nports == SAM_EHCI_NRHPORT);
|
DEBUGASSERT(nports == SAM_EHCI_NRHPORT);
|
||||||
|
|
||||||
/* Show the HCCPARAMS register */
|
/* Show the HCCPARAMS register */
|
||||||
|
@ -542,7 +542,8 @@
|
|||||||
#define QTD_TOKEN_IOC (1 << 15) /* Bit 15: Interrupt On Complete */
|
#define QTD_TOKEN_IOC (1 << 15) /* Bit 15: Interrupt On Complete */
|
||||||
#define QTD_TOKEN_NBYTES_SHIFT (16) /* Bits 16-30: Total Bytes to Transfer */
|
#define QTD_TOKEN_NBYTES_SHIFT (16) /* Bits 16-30: Total Bytes to Transfer */
|
||||||
#define QTD_TOKEN_NBYTES_MASK (0x7fff << QTD_TOKEN_NBYTES_SHIFT)
|
#define QTD_TOKEN_NBYTES_MASK (0x7fff << QTD_TOKEN_NBYTES_SHIFT)
|
||||||
#define QTD_TOKEN_TOGGLE (1 << 13) /* Bit 31: Data Toggle */
|
#define QTD_TOKEN_TOGGLE_SHIFT (31) /* Bit 31: Data Toggle */
|
||||||
|
#define QTD_TOKEN_TOGGLE (1 << 31) /* Bit 31: Data Toggle */
|
||||||
|
|
||||||
/* qTD Buffer Page Pointer List. Paragraph 3.5.4 */
|
/* qTD Buffer Page Pointer List. Paragraph 3.5.4 */
|
||||||
/* Page 0 */
|
/* Page 0 */
|
||||||
@ -662,7 +663,8 @@
|
|||||||
#define QH_TOKEN_IOC (1 << 15) /* Bit 15: Interrupt On Complete */
|
#define QH_TOKEN_IOC (1 << 15) /* Bit 15: Interrupt On Complete */
|
||||||
#define QH_TOKEN_NBYTES_SHIFT (16) /* Bits 16-30: Total Bytes to Transfer */
|
#define QH_TOKEN_NBYTES_SHIFT (16) /* Bits 16-30: Total Bytes to Transfer */
|
||||||
#define QH_TOKEN_NBYTES_MASK (0x7fff << QH_TOKEN_NBYTES_SHIFT)
|
#define QH_TOKEN_NBYTES_MASK (0x7fff << QH_TOKEN_NBYTES_SHIFT)
|
||||||
#define QH_TOKEN_TOGGLE (1 << 13) /* Bit 31: Data Toggle
|
#define QH_TOKEN_TOGGLE_SHIFT (31) /* Bit 31: Data Toggle */
|
||||||
|
#define QH_TOKEN_TOGGLE (1 << 31) /* Bit 31: Data Toggle */
|
||||||
|
|
||||||
/* Buffer Page Pointer List (NOTE 2)
|
/* Buffer Page Pointer List (NOTE 2)
|
||||||
/* Page 0 */
|
/* Page 0 */
|
||||||
|
Loading…
Reference in New Issue
Block a user