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:
yangsong8
2025-06-21 22:22:59 +08:00
committed by Xiang Xiao
parent 4d319c6816
commit 35a89be950
3 changed files with 61 additions and 52 deletions
+23 -17
View File
@@ -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);
+2
View File
@@ -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 */
+36 -35
View File
@@ -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);
}