diff --git a/drivers/usbdev/usbmsc.c b/drivers/usbdev/usbmsc.c index 64478f86869..ccadac99e1e 100644 --- a/drivers/usbdev/usbmsc.c +++ b/drivers/usbdev/usbmsc.c @@ -321,9 +321,9 @@ static int usbmsc_bind(FAR struct usbdevclass_driver_s *driver, reqcontainer->req->priv = reqcontainer; reqcontainer->req->callback = usbmsc_wrcomplete; - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->spinlock); sq_addlast((FAR sq_entry_t *)reqcontainer, &priv->wrreqlist); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->spinlock, flags); } /* Report if we are selfpowered (unless we are part of a composite @@ -441,18 +441,23 @@ static void usbmsc_unbind(FAR struct usbdevclass_driver_s *driver, * of them */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->spinlock); while (!sq_empty(&priv->wrreqlist)) { reqcontainer = (struct usbmsc_req_s *) sq_remfirst(&priv->wrreqlist); + spin_unlock_irqrestore(&priv->spinlock, flags); if (reqcontainer->req != NULL) { usbdev_freereq(priv->epbulkin, reqcontainer->req); } + + flags = spin_lock_irqsave(&priv->spinlock); } + spin_unlock_irqrestore(&priv->spinlock, flags); + /* Free the bulk IN endpoint */ if (priv->epbulkin) @@ -460,8 +465,6 @@ static void usbmsc_unbind(FAR struct usbdevclass_driver_s *driver, DEV_FREEEP(dev, priv->epbulkin); priv->epbulkin = NULL; } - - leave_critical_section(flags); } } @@ -726,8 +729,8 @@ static int usbmsc_setup(FAR struct usbdevclass_driver_s *driver, * state. */ - priv->theventset |= USBMSC_EVENT_RESET; - usbmsc_scsi_signal(priv); + priv->theventset |= USBMSC_EVENT_RESET; + usbmsc_scsi_signal(priv); /* Return here... the response will be provided later by * the worker thread. @@ -844,14 +847,14 @@ static void usbmsc_disconnect(FAR struct usbdevclass_driver_s *driver, /* Reset the configuration */ - flags = enter_critical_section(); + flags = spin_lock_irqsave_nopreempt(&priv->spinlock); usbmsc_resetconfig(priv); /* Signal the worker thread */ priv->theventset |= USBMSC_EVENT_DISCONNECT; usbmsc_scsi_signal(priv); - leave_critical_section(flags); + spin_unlock_irqrestore_nopreempt(&priv->spinlock, flags); /* Perform the soft connect function so that we will we can be * re-enumerated (unless we are part of a composite device) @@ -1050,9 +1053,9 @@ void usbmsc_wrcomplete(FAR struct usbdev_ep_s *ep, /* Return the write request to the free list */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->spinlock); sq_addlast((FAR sq_entry_t *)privreq, &priv->wrreqlist); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->spinlock, flags); /* Process the received data unless this is some unusual condition */ @@ -1074,8 +1077,10 @@ void usbmsc_wrcomplete(FAR struct usbdev_ep_s *ep, /* Inform the worker thread that a write request has been returned */ + flags = spin_lock_irqsave_nopreempt(&priv->spinlock); priv->theventset |= USBMSC_EVENT_WRCOMPLETE; usbmsc_scsi_signal(priv); + spin_unlock_irqrestore_nopreempt(&priv->spinlock, flags); } /**************************************************************************** @@ -1120,9 +1125,8 @@ void usbmsc_rdcomplete(FAR struct usbdev_ep_s *ep, /* Add the filled read request from the rdreqlist */ - flags = enter_critical_section(); + flags = spin_lock_irqsave_nopreempt(&priv->spinlock); sq_addlast((FAR sq_entry_t *)privreq, &priv->rdreqlist); - leave_critical_section(flags); /* Signal the worker thread that there is received data to be * processed. @@ -1130,6 +1134,7 @@ void usbmsc_rdcomplete(FAR struct usbdev_ep_s *ep, priv->theventset |= USBMSC_EVENT_RDCOMPLETE; usbmsc_scsi_signal(priv); + spin_unlock_irqrestore_nopreempt(&priv->spinlock, flags); } break; @@ -1300,6 +1305,7 @@ int usbmsc_configure(unsigned int nluns, FAR void **handle) nxsem_init(&priv->thsynch, 0, 0); nxmutex_init(&priv->thlock); nxsem_init(&priv->thwaitsem, 0, 0); + spin_lock_init(&priv->spinlock); sq_init(&priv->wrreqlist); priv->nluns = nluns; @@ -1698,10 +1704,10 @@ int usbmsc_exportluns(FAR void *handle) /* Signal to start the thread */ uinfo("Signalling for the SCSI worker thread\n"); - flags = enter_critical_section(); + flags = spin_lock_irqsave_nopreempt(&priv->spinlock); priv->theventset |= USBMSC_EVENT_READY; usbmsc_scsi_signal(priv); - leave_critical_section(flags); + spin_unlock_irqrestore_nopreempt(&priv->spinlock, flags); errout_with_lock: nxmutex_unlock(&priv->thlock); @@ -1810,10 +1816,10 @@ void usbmsc_uninitialize(FAR void *handle) { /* Yes.. Ask the thread to stop */ - flags = enter_critical_section(); + flags = spin_lock_irqsave_nopreempt(&priv->spinlock); priv->theventset |= USBMSC_EVENT_TERMINATEREQUEST; usbmsc_scsi_signal(priv); - leave_critical_section(flags); + spin_unlock_irqrestore_nopreempt(&priv->spinlock, flags); } nxmutex_unlock(&priv->thlock); diff --git a/drivers/usbdev/usbmsc.h b/drivers/usbdev/usbmsc.h index 81afd81a507..4afb0dda7b4 100644 --- a/drivers/usbdev/usbmsc.h +++ b/drivers/usbdev/usbmsc.h @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -380,6 +381,7 @@ struct usbmsc_dev_s pid_t thpid; /* The worker thread task ID */ sem_t thsynch; /* Used to synchronizer terminal events */ + spinlock_t spinlock; /* Used to protect the critical section */ mutex_t thlock; /* Used to get exclusive access to the state data */ sem_t thwaitsem; /* Used to signal worker thread */ volatile bool thwaiting; /* True: worker thread is waiting for an event */ diff --git a/drivers/usbdev/usbmsc_scsi.c b/drivers/usbdev/usbmsc_scsi.c index 83b60cccae9..2a736950fd4 100644 --- a/drivers/usbdev/usbmsc_scsi.c +++ b/drivers/usbdev/usbmsc_scsi.c @@ -360,9 +360,10 @@ static void usbmsc_putle32(FAR uint8_t *buf, uint32_t val) * ****************************************************************************/ -static int usbmsc_scsi_wait(FAR struct usbmsc_dev_s *priv) +static int usbmsc_scsi_wait(FAR struct usbmsc_dev_s *priv, + FAR irqstate_t *flags) { - irqstate_t flags; + bool waiting; int ret; int ret2; @@ -377,8 +378,8 @@ static int usbmsc_scsi_wait(FAR struct usbmsc_dev_s *priv) * enabled while we wait for the event. */ - flags = enter_critical_section(); priv->thwaiting = true; + spin_unlock_irqrestore(&priv->spinlock, *flags); /* Relinquish our lock on the SCSI state data */ @@ -389,13 +390,16 @@ static int usbmsc_scsi_wait(FAR struct usbmsc_dev_s *priv) do { ret = nxsem_wait_uninterruptible(&priv->thwaitsem); + *flags = spin_lock_irqsave(&priv->spinlock); + waiting = priv->thwaiting; + spin_unlock_irqrestore(&priv->spinlock, *flags); } - while (priv->thwaiting && ret >= 0); + while (waiting && ret >= 0); /* Re-acquire our lock on the SCSI state data */ ret2 = nxmutex_lock(&priv->thlock); - leave_critical_section(flags); + *flags = spin_lock_irqsave(&priv->spinlock); return ret >= 0 ? ret2 : ret; } @@ -1751,9 +1755,9 @@ static int usbmsc_idlestate(FAR struct usbmsc_dev_s *priv) /* Take a request from the rdreqlist */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->spinlock); privreq = (FAR struct usbmsc_req_s *)sq_remfirst(&priv->rdreqlist); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->spinlock, flags); /* Has anything been received? If not, just return an error. * This will cause us to remain in the IDLE state. When a USB request is @@ -2329,9 +2333,9 @@ static int usbmsc_cmdreadstate(FAR struct usbmsc_dev_s *priv) * already checked that is it not NULL */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->spinlock); privreq = (FAR struct usbmsc_req_s *)sq_remfirst(&priv->wrreqlist); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->spinlock, flags); /* And submit the request to the bulk IN endpoint */ @@ -2417,9 +2421,9 @@ static int usbmsc_cmdwritestate(FAR struct usbmsc_dev_s *priv) * data to be written. */ - irqstate_t flags = enter_critical_section(); + irqstate_t flags = spin_lock_irqsave(&priv->spinlock); privreq = (FAR struct usbmsc_req_s *)sq_remfirst(&priv->rdreqlist); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->spinlock, flags); /* If there no request data available, then just return an error. * This will cause us to remain in the CMDWRITE state. When a filled @@ -2622,10 +2626,10 @@ static int usbmsc_cmdfinishstate(FAR struct usbmsc_dev_s *priv) * that is it not NULL) */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->spinlock); privreq = (FAR struct usbmsc_req_s *) sq_remfirst(&priv->wrreqlist); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->spinlock, flags); /* Send the write request */ @@ -2680,7 +2684,6 @@ static int usbmsc_cmdfinishstate(FAR struct usbmsc_dev_s *priv) { /* Did the host stop sending unexpectedly early? */ - flags = enter_critical_section(); if (priv->shortpacket) { usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_CMDFINISHSHORTPKT), @@ -2696,8 +2699,9 @@ static int usbmsc_cmdfinishstate(FAR struct usbmsc_dev_s *priv) EP_STALL(priv->epbulkout); } - priv->theventset |= USBMSC_EVENT_ABORTBULKOUT; - leave_critical_section(flags); + flags = spin_lock_irqsave(&priv->spinlock); + priv->theventset |= USBMSC_EVENT_ABORTBULKOUT; + spin_unlock_irqrestore(&priv->spinlock, flags); } break; @@ -2743,9 +2747,9 @@ static int usbmsc_cmdstatusstate(FAR struct usbmsc_dev_s *priv) /* Take a request from the wrreqlist */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->spinlock); privreq = (FAR struct usbmsc_req_s *)sq_remfirst(&priv->wrreqlist); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->spinlock, flags); /* If there no request structures available, then just return an error. * This will cause us to remain in the CMDSTATUS status. When a request @@ -2809,9 +2813,9 @@ static int usbmsc_cmdstatusstate(FAR struct usbmsc_dev_s *priv) { usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_SNDSTATUSSUBMIT), (uint16_t)-ret); - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->spinlock); sq_addlast((FAR sq_entry_t *)privreq, &priv->wrreqlist); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->spinlock, flags); } /* Return to the IDLE state */ @@ -2866,29 +2870,32 @@ int usbmsc_scsi_main(int argc, FAR char *argv[]) uinfo("Waiting to be signaled\n"); + flags = spin_lock_irqsave(&priv->spinlock); priv->thstate = USBMSC_STATE_STARTED; while ((priv->theventset & USBMSC_EVENT_READY) == 0 && (priv->theventset & USBMSC_EVENT_TERMINATEREQUEST) == 0) { - ret = usbmsc_scsi_wait(priv); + ret = usbmsc_scsi_wait(priv, &flags); if (ret < 0) { /* The thread has been canceled */ + spin_unlock_irqrestore(&priv->spinlock, flags); nxmutex_unlock(&priv->thlock); return EXIT_FAILURE; } } - uinfo("Running\n"); - /* Transition to the INITIALIZED/IDLE state */ priv->thstate = USBMSC_STATE_IDLE; eventset = priv->theventset; priv->theventset = USBMSC_EVENT_NOEVENTS; + spin_unlock_irqrestore(&priv->spinlock, flags); nxmutex_unlock(&priv->thlock); + uinfo("Running\n"); + /* Then loop until we are asked to terminate */ while ((eventset & USBMSC_EVENT_TERMINATEREQUEST) == 0) @@ -2905,15 +2912,15 @@ int usbmsc_scsi_main(int argc, FAR char *argv[]) return EXIT_FAILURE; } - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->spinlock); if (priv->theventset == USBMSC_EVENT_NOEVENTS) { - ret = usbmsc_scsi_wait(priv); + ret = usbmsc_scsi_wait(priv, &flags); if (ret < 0) { /* The thread has been canceled */ - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->spinlock, flags); nxmutex_unlock(&priv->thlock); return EXIT_FAILURE; } @@ -2926,6 +2933,7 @@ int usbmsc_scsi_main(int argc, FAR char *argv[]) eventset = priv->theventset; priv->theventset = USBMSC_EVENT_NOEVENTS; + spin_unlock_irqrestore(&priv->spinlock, flags); nxmutex_unlock(&priv->thlock); /* Were we awakened by some event that requires immediate action? @@ -2980,8 +2988,6 @@ int usbmsc_scsi_main(int argc, FAR char *argv[]) priv->thstate = USBMSC_STATE_IDLE; } - leave_critical_section(flags); - /* Loop processing each SCSI command state. Each state handling * function will do the following: * @@ -3054,20 +3060,15 @@ int usbmsc_scsi_main(int argc, FAR char *argv[]) void usbmsc_scsi_signal(FAR struct usbmsc_dev_s *priv) { - irqstate_t flags; - /* A flag is used to prevent driving up the semaphore count. This function * is called (primarily) from interrupt level logic so we must disable - * interrupts momentarily to assure that test of the flag and the increment - * of the semaphore count are atomic. + * interrupts momentarily before call this function to assure that test of + * the flag and the increment of the semaphore count are atomic. */ - flags = enter_critical_section(); if (priv->thwaiting) { priv->thwaiting = false; nxsem_post(&priv->thwaitsem); } - - leave_critical_section(flags); }