mirror of
https://github.com/apache/nuttx.git
synced 2026-05-19 20:06:24 +08:00
drivers/usbdev: Use small lock to protect usbdev msc
Use spin lock to replace enter_critical_section Signed-off-by: yangsong8 <yangsong8@xiaomi.com>
This commit is contained in:
+23
-17
@@ -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);
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include <nuttx/fs/fs.h>
|
||||
#include <nuttx/queue.h>
|
||||
#include <nuttx/mutex.h>
|
||||
#include <nuttx/spinlock.h>
|
||||
#include <nuttx/semaphore.h>
|
||||
#include <nuttx/usb/storage.h>
|
||||
#include <nuttx/usb/usbdev.h>
|
||||
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user