SAMV7 USBHS Device: Reorder some interrupt handling logic to avoid losing an interrupt and to avoid a race condition

This commit is contained in:
Gregory Nutt 2016-03-02 14:58:17 -06:00
parent 52d499ba33
commit c75e594350

View File

@ -2498,7 +2498,14 @@ static void sam_dma_interrupt(struct sam_usbdev_s *priv, int epno)
*/ */
DEBUGASSERT(USB_ISEPIN(privep->ep.eplog)); DEBUGASSERT(USB_ISEPIN(privep->ep.eplog));
sam_putreg(USBHS_DEVEPTINT_TXINI, SAM_USBHS_DEVEPTICR(epno));
/* Assume that will wait for the TXIN interrupt. Enable it
* now. We do this PRIOR to sampling the BYCT and BUSBK
* fields to avoid the race condition that would occur if
* the interrupt were enabled afterward.
*/
sam_putreg(USBHS_DEVEPTINT_TXINI, SAM_USBHS_DEVEPTIER(epno));
/* Have all of the bytes in the FIFO been transmitted to the /* Have all of the bytes in the FIFO been transmitted to the
* host? * host?
@ -2521,23 +2528,21 @@ static void sam_dma_interrupt(struct sam_usbdev_s *priv, int epno)
if (byct > 0 || nbusybk > 0) if (byct > 0 || nbusybk > 0)
{ {
/* Not all of the data has been sent to the host. A TXIN /* Not all of the data has been sent to the host. A TXIN
* interrupt will be generated later. Enable the TXIN * interrupt will be generated later. We have already enabled
* interrupt now and wait for the transfer to complete. * the TXIN interrupt. Now wait for the transfer to complete.
*/ */
sam_putreg(USBHS_DEVEPTINT_TXINI, SAM_USBHS_DEVEPTIER(epno));
} }
else else
{ {
/* All bytes have been sent to the host. We must call /* All bytes have been sent to the host. We must call
* sam_req_write() now in the IDLE state with the number of * sam_req_write() now in the IDLE state with the number of
* bytes transferred in 'inflight' * bytes transferred in 'inflight'. First disable and
* * clear the TXIN interrupt.
* REVISIT: Isn't there a race condition here? Could TXIN
* have fired just before calculating byct? Could TXIN be
* pending here?
*/ */
sam_putreg(USBHS_DEVEPTINT_TXINI, SAM_USBHS_DEVEPTIDR(epno));
sam_putreg(USBHS_DEVEPTINT_TXINI, SAM_USBHS_DEVEPTICR(epno));
privep->epstate = USBHS_EPSTATE_IDLE; privep->epstate = USBHS_EPSTATE_IDLE;
(void)sam_req_write(priv, privep); (void)sam_req_write(priv, privep);
} }