Use small lock to protect usbdev and endpoint in arch ARM.

Signed-off-by: wangzhi16 <wangzhi16@xiaomi.com>
This commit is contained in:
wangzhi16
2025-01-20 11:47:19 +08:00
committed by Xiang Xiao
parent 4857ea211f
commit e177ff9c0c
14 changed files with 969 additions and 419 deletions
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+44 -20
View File
@@ -48,6 +48,7 @@
#include <assert.h>
#include <errno.h>
#include <debug.h>
#include <sched.h>
#include <nuttx/arch.h>
#include <nuttx/wdog.h>
@@ -57,6 +58,7 @@
#include <nuttx/usb/usbdev_trace.h>
#include <nuttx/irq.h>
#include <nuttx/spinlock.h>
#include "arm_internal.h"
#include "kinetis.h"
@@ -502,6 +504,10 @@ struct khci_usbdev_s
/* The endpoint list */
struct khci_ep_s eplist[KHCI_NENDPOINTS];
/* Spinlock */
spinlock_t lock;
};
/****************************************************************************
@@ -892,9 +898,9 @@ static void khci_reqcomplete(struct khci_ep_s *privep, int16_t result)
* request list.
*/
flags = enter_critical_section();
flags = spin_lock_irqsave(&privep->dev->lock);
privreq = khci_remfirst(&privep->active);
leave_critical_section(flags);
spin_unlock_irqrestore(&privep->dev->lock, flags);
if (privreq)
{
@@ -3202,7 +3208,8 @@ static void khci_resume(struct khci_usbdev_s *priv)
irqstate_t flags;
uint32_t regval;
flags = enter_critical_section();
flags = spin_lock_irqsave(&priv->lock);
sched_lock();
/* This function is called when the USB resume interrupt occurs.
* If using clock switching, this is the place to call out to
@@ -3243,7 +3250,8 @@ static void khci_resume(struct khci_usbdev_s *priv)
CLASS_RESUME(priv->driver, &priv->usbdev);
}
leave_critical_section(flags);
spin_unlock_irqrestore(&priv->lock, flags);
sched_unlock();
}
/****************************************************************************
@@ -3261,7 +3269,7 @@ khci_epreserve(struct khci_usbdev_s *priv, uint8_t epset)
irqstate_t flags;
int epndx = 0;
flags = enter_critical_section();
flags = spin_lock_irqsave(&priv->lock);
epset &= priv->epavail;
if (epset)
{
@@ -3286,7 +3294,7 @@ khci_epreserve(struct khci_usbdev_s *priv, uint8_t epset)
}
}
leave_critical_section(flags);
spin_unlock_irqrestore(&priv->lock, flags);
return privep;
}
@@ -3297,9 +3305,9 @@ khci_epreserve(struct khci_usbdev_s *priv, uint8_t epset)
static inline void
khci_epunreserve(struct khci_usbdev_s *priv, struct khci_ep_s *privep)
{
irqstate_t flags = enter_critical_section();
irqstate_t flags = spin_lock_irqsave(&priv->lock);
priv->epavail |= KHCI_ENDP_BIT(USB_EPNO(privep->ep.eplog));
leave_critical_section(flags);
spin_unlock_irqrestore(&priv->lock, flags);
}
/****************************************************************************
@@ -3528,7 +3536,8 @@ static int khci_epdisable(struct usbdev_ep_s *ep)
/* Cancel any ongoing activity */
flags = enter_critical_section();
flags = spin_lock_irqsave(&privep->dev->lock);
sched_lock();
khci_cancelrequests(privep, -ESHUTDOWN);
/* Disable the endpoint */
@@ -3545,7 +3554,8 @@ static int khci_epdisable(struct usbdev_ep_s *ep)
*ptr++ = 0;
}
leave_critical_section(flags);
spin_unlock_irqrestore(&privep->dev->lock, flags);
sched_unlock();
return OK;
}
@@ -3644,7 +3654,8 @@ static int khci_epsubmit(struct usbdev_ep_s *ep, struct usbdev_req_s *req)
#ifndef CONFIG_USBDEV_NOWRITEAHEAD
privreq->inflight[1] = 0;
#endif
flags = enter_critical_section();
flags = spin_lock_irqsave(&priv->lock);
sched_lock();
/* Add the new request to the request queue for the OUT endpoint */
@@ -3688,7 +3699,8 @@ static int khci_epsubmit(struct usbdev_ep_s *ep, struct usbdev_req_s *req)
}
}
leave_critical_section(flags);
spin_unlock_irqrestore(&priv->lock, flags);
sched_unlock();
return ret;
}
@@ -3711,9 +3723,11 @@ static int khci_epcancel(struct usbdev_ep_s *ep, struct usbdev_req_s *req)
usbtrace(TRACE_EPCANCEL, USB_EPNO(ep->eplog));
flags = enter_critical_section();
flags = spin_lock_irqsave(&privep->dev->lock);
sched_lock();
khci_cancelrequests(privep, -EAGAIN);
leave_critical_section(flags);
spin_unlock_irqrestore(&privep->dev->lock, flags);
sched_unlock();
return OK;
}
@@ -3920,7 +3934,8 @@ static int khci_epstall(struct usbdev_ep_s *ep, bool resume)
/* STALL or RESUME the endpoint */
flags = enter_critical_section();
flags = spin_lock_irqsave(&privep->dev->lock);
sched_lock();
/* Special case EP0. When we stall EP0 we have to stall both the IN and
* OUT BDTs.
@@ -3949,7 +3964,8 @@ static int khci_epstall(struct usbdev_ep_s *ep, bool resume)
ret = khci_epbdtstall(ep, resume, USB_ISEPIN(ep->eplog));
}
leave_critical_section(flags);
spin_unlock_irqrestore(&privep->dev->lock, flags);
sched_unlock();
return ret;
}
@@ -4516,6 +4532,10 @@ void arm_usbinitialize(void)
usbtrace(TRACE_DEVINIT, 0);
/* Initialize driver lock */
spin_lock_init(&priv->lock);
/* Initialize the driver state structure */
khci_swinitialize(priv);
@@ -4594,7 +4614,8 @@ void arm_usbuninitialize(void)
/* Disconnect the device */
flags = enter_critical_section();
flags = spin_lock_irqsave(&priv->lock);
sched_lock();
khci_swreset(priv);
@@ -4618,7 +4639,8 @@ void arm_usbuninitialize(void)
regval &= ~SIM_SCGC4_USBOTG;
putreg32(regval, KINETIS_SIM_SCGC4);
leave_critical_section(flags);
spin_unlock_irqrestore(&priv->lock, flags);
sched_unlock();
}
/****************************************************************************
@@ -4719,7 +4741,8 @@ int usbdev_unregister(struct usbdevclass_driver_s *driver)
* the hardware back into its initial, unconnected state.
*/
flags = enter_critical_section();
flags = spin_lock_irqsave(&priv->lock);
sched_lock();
khci_swreset(priv);
kinetis_usbpullup(&priv->usbdev, false);
khci_hwreset(priv);
@@ -4740,7 +4763,8 @@ int usbdev_unregister(struct usbdevclass_driver_s *driver)
khci_hwshutdown(priv);
khci_swinitialize(priv);
leave_critical_section(flags);
spin_unlock_irqrestore(&priv->lock, flags);
sched_unlock();
return OK;
}
#endif /* CONFIG_USBDEV */
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+43 -14
View File
@@ -34,6 +34,7 @@
#include <errno.h>
#include <assert.h>
#include <debug.h>
#include <sched.h>
#include <nuttx/arch.h>
#include <nuttx/spinlock.h>
@@ -584,17 +585,15 @@ static void rp2040_abortrequest(struct rp2040_ep_s *privep,
*
****************************************************************************/
static void rp2040_reqcomplete(struct rp2040_ep_s *privep, int16_t result)
static void rp2040_reqcomplete_nolock(struct rp2040_ep_s *privep,
int16_t result)
{
struct rp2040_req_s *privreq;
int stalled = privep->stalled;
irqstate_t flags;
/* Remove the completed request at the head of the endpoint request list */
flags = enter_critical_section();
privreq = rp2040_rqdequeue(privep);
leave_critical_section(flags);
if (privreq)
{
@@ -622,6 +621,15 @@ static void rp2040_reqcomplete(struct rp2040_ep_s *privep, int16_t result)
}
}
static void rp2040_reqcomplete(struct rp2040_ep_s *privep, int16_t result)
{
irqstate_t flags = spin_lock_irqsave(&privep->dev->lock);
rp2040_reqcomplete_nolock(privep, result);
spin_unlock_irqrestore(&privep->dev->lock, flags);
}
/****************************************************************************
* Name: rp2040_txcomplete
*
@@ -856,16 +864,25 @@ static void rp2040_handle_zlp(struct rp2040_usbdev_s *priv)
*
****************************************************************************/
static void rp2040_cancelrequests(struct rp2040_ep_s *privep)
static void rp2040_cancelrequests_nolock(struct rp2040_ep_s *privep)
{
while (!rp2040_rqempty(privep))
{
usbtrace(TRACE_COMPLETE(privep->epphy),
(rp2040_rqpeek(privep))->req.xfrd);
rp2040_reqcomplete(privep, -ESHUTDOWN);
rp2040_reqcomplete_nolock(privep, -ESHUTDOWN);
}
}
static void rp2040_cancelrequests(struct rp2040_ep_s *privep)
{
irqstate_t flags = spin_lock_irqsave(&privep->dev->lock);
sched_lock();
rp2040_cancelrequests_nolock(privep);
spin_unlock_irqrestore(&privep->dev->lock, flags);
sched_unlock();
}
/****************************************************************************
* Name: rp2040_epfindbyaddr
*
@@ -1518,7 +1535,8 @@ static int rp2040_epdisable(struct usbdev_ep_s *ep)
usbtrace(TRACE_EPDISABLE, privep->epphy);
uinfo("EP%d\n", privep->epphy);
flags = enter_critical_section();
flags = spin_lock_irqsave(&privep->dev->lock);
sched_lock();
privep->ep.maxpacket = 64;
privep->stalled = false;
@@ -1527,9 +1545,10 @@ static int rp2040_epdisable(struct usbdev_ep_s *ep)
/* Cancel all queued requests */
rp2040_cancelrequests(privep);
rp2040_cancelrequests_nolock(privep);
leave_critical_section(flags);
spin_unlock_irqrestore(&privep->dev->lock, flags);
sched_unlock();
return OK;
}
@@ -1622,7 +1641,8 @@ static int rp2040_epsubmit(struct usbdev_ep_s *ep,
req->result = -EINPROGRESS;
req->xfrd = 0;
flags = enter_critical_section();
flags = spin_lock_irqsave(&privep->dev->lock);
sched_lock();
if (privep->stalled && privep->in)
{
@@ -1667,7 +1687,8 @@ static int rp2040_epsubmit(struct usbdev_ep_s *ep,
}
}
leave_critical_section(flags);
spin_unlock_irqrestore(&privep->dev->lock, flags);
sched_unlock();
return ret;
}
@@ -1697,9 +1718,11 @@ static int rp2040_epcancel(struct usbdev_ep_s *ep,
/* Remove request from req_queue */
flags = enter_critical_section();
rp2040_cancelrequests(privep);
leave_critical_section(flags);
flags = spin_lock_irqsave(&privep->dev->lock);
sched_lock();
rp2040_cancelrequests_nolock(privep);
spin_unlock_irqrestore(&privep->dev->lock, flags);
sched_unlock();
return OK;
}
@@ -1742,8 +1765,10 @@ static int rp2040_epstall_exec(struct usbdev_ep_s *ep)
int ret;
flags = spin_lock_irqsave(&priv->lock);
sched_lock();
ret = rp2040_epstall_exec_nolock(ep);
spin_unlock_irqrestore(&priv->lock, flags);
sched_unlock();
return ret;
}
@@ -1762,6 +1787,7 @@ static int rp2040_epstall(struct usbdev_ep_s *ep, bool resume)
irqstate_t flags;
flags = spin_lock_irqsave(&priv->lock);
sched_lock();
if (resume)
{
@@ -1803,6 +1829,7 @@ static int rp2040_epstall(struct usbdev_ep_s *ep, bool resume)
}
spin_unlock_irqrestore(&priv->lock, flags);
sched_unlock();
return OK;
}
@@ -2153,6 +2180,7 @@ int usbdev_unregister(struct usbdevclass_driver_s *driver)
usbtrace(TRACE_DEVUNREGISTER, 0);
flags = spin_lock_irqsave(&priv->lock);
sched_lock();
/* Unbind the class driver */
@@ -2171,6 +2199,7 @@ int usbdev_unregister(struct usbdevclass_driver_s *driver)
priv->driver = NULL;
spin_unlock_irqrestore(&priv->lock, flags);
sched_unlock();
return OK;
}
+51 -24
View File
@@ -34,6 +34,7 @@
#include <errno.h>
#include <assert.h>
#include <debug.h>
#include <sched.h>
#include <nuttx/arch.h>
#include <nuttx/spinlock.h>
@@ -514,9 +515,9 @@ static int rp23xx_epwrite(struct rp23xx_ep_s *privep, uint8_t *buf,
/* Start the transfer */
flags = spin_lock_irqsave(&g_usbdev.lock);
flags = spin_lock_irqsave(&privep->dev->lock);
rp23xx_update_buffer_control(privep, 0, val);
spin_unlock_irqrestore(&g_usbdev.lock, flags);
spin_unlock_irqrestore(&privep->dev->lock, flags);
return nbytes;
}
@@ -543,9 +544,9 @@ static int rp23xx_epread(struct rp23xx_ep_s *privep, uint16_t nbytes)
/* Start the transfer */
flags = spin_lock_irqsave(&g_usbdev.lock);
flags = spin_lock_irqsave(&privep->dev->lock);
rp23xx_update_buffer_control(privep, 0, val);
spin_unlock_irqrestore(&g_usbdev.lock, flags);
spin_unlock_irqrestore(&privep->dev->lock, flags);
return OK;
}
@@ -582,17 +583,15 @@ static void rp23xx_abortrequest(struct rp23xx_ep_s *privep,
*
****************************************************************************/
static void rp23xx_reqcomplete(struct rp23xx_ep_s *privep, int16_t result)
static void rp23xx_reqcomplete_nolock(struct rp23xx_ep_s *privep,
int16_t result)
{
struct rp23xx_req_s *privreq;
int stalled = privep->stalled;
irqstate_t flags;
/* Remove the completed request at the head of the endpoint request list */
flags = enter_critical_section();
privreq = rp23xx_rqdequeue(privep);
leave_critical_section(flags);
if (privreq)
{
@@ -620,6 +619,13 @@ static void rp23xx_reqcomplete(struct rp23xx_ep_s *privep, int16_t result)
}
}
static void rp23xx_reqcomplete(struct rp23xx_ep_s *privep, int16_t result)
{
irqstate_t flags = spin_lock_irqsave(&privep->dev->lock);
rp23xx_reqcomplete_nolock(privep, result);
spin_unlock_irqrestore(&privep->dev->lock, flags);
}
/****************************************************************************
* Name: rp23xx_txcomplete
*
@@ -854,16 +860,25 @@ static void rp23xx_handle_zlp(struct rp23xx_usbdev_s *priv)
*
****************************************************************************/
static void rp23xx_cancelrequests(struct rp23xx_ep_s *privep)
static void rp23xx_cancelrequests_nolock(struct rp23xx_ep_s *privep)
{
while (!rp23xx_rqempty(privep))
{
usbtrace(TRACE_COMPLETE(privep->epphy),
(rp23xx_rqpeek(privep))->req.xfrd);
rp23xx_reqcomplete(privep, -ESHUTDOWN);
rp23xx_reqcomplete_nolock(privep, -ESHUTDOWN);
}
}
static void rp23xx_cancelrequests(struct rp23xx_ep_s *privep)
{
irqstate_t flags = spin_lock_irqsave(&privep->dev->lock);
sched_lock();
rp23xx_cancelrequests_nolock(privep);
spin_unlock_irqrestore(&privep->dev->lock, flags);
sched_unlock();
}
/****************************************************************************
* Name: rp23xx_epfindbyaddr
*
@@ -1330,9 +1345,11 @@ static bool rp23xx_usbintr_buffstat(struct rp23xx_usbdev_s *priv)
}
else if (privep->pending_stall)
{
flags = spin_lock_irqsave(&g_usbdev.lock);
flags = spin_lock_irqsave(&priv->lock);
sched_lock();
rp23xx_epstall_exec(&privep->ep);
spin_unlock_irqrestore(&g_usbdev.lock, flags);
spin_unlock_irqrestore(&priv->lock, flags);
sched_unlock();
}
}
else
@@ -1519,7 +1536,8 @@ static int rp23xx_epdisable(struct usbdev_ep_s *ep)
usbtrace(TRACE_EPDISABLE, privep->epphy);
uinfo("EP%d\n", privep->epphy);
flags = enter_critical_section();
flags = spin_lock_irqsave(&privep->dev->lock);
sched_lock();
privep->ep.maxpacket = 64;
privep->stalled = false;
@@ -1528,9 +1546,10 @@ static int rp23xx_epdisable(struct usbdev_ep_s *ep)
/* Cancel all queued requests */
rp23xx_cancelrequests(privep);
rp23xx_cancelrequests_nolock(privep);
leave_critical_section(flags);
spin_unlock_irqrestore(&privep->dev->lock, flags);
sched_unlock();
return OK;
}
@@ -1623,7 +1642,8 @@ static int rp23xx_epsubmit(struct usbdev_ep_s *ep,
req->result = -EINPROGRESS;
req->xfrd = 0;
flags = enter_critical_section();
flags = spin_lock_irqsave(&privep->dev->lock);
sched_lock();
if (privep->stalled && privep->in)
{
@@ -1668,7 +1688,8 @@ static int rp23xx_epsubmit(struct usbdev_ep_s *ep,
}
}
leave_critical_section(flags);
spin_unlock_irqrestore(&privep->dev->lock, flags);
sched_unlock();
return ret;
}
@@ -1698,9 +1719,11 @@ static int rp23xx_epcancel(struct usbdev_ep_s *ep,
/* Remove request from req_queue */
flags = enter_critical_section();
rp23xx_cancelrequests(privep);
leave_critical_section(flags);
flags = spin_lock_irqsave(&privep->dev->lock);
sched_lock();
rp23xx_cancelrequests_nolock(privep);
spin_unlock_irqrestore(&privep->dev->lock, flags);
sched_unlock();
return OK;
}
@@ -1749,7 +1772,8 @@ static int rp23xx_epstall(struct usbdev_ep_s *ep, bool resume)
struct rp23xx_usbdev_s *priv = privep->dev;
irqstate_t flags;
flags = spin_lock_irqsave(&g_usbdev.lock);
flags = spin_lock_irqsave(&priv->lock);
sched_lock();
if (resume)
{
@@ -1790,7 +1814,8 @@ static int rp23xx_epstall(struct usbdev_ep_s *ep, bool resume)
priv->zlp_stat = RP23XX_ZLP_NONE;
}
spin_unlock_irqrestore(&g_usbdev.lock, flags);
spin_unlock_irqrestore(&priv->lock, flags);
sched_unlock();
return OK;
}
@@ -2140,7 +2165,8 @@ int usbdev_unregister(struct usbdevclass_driver_s *driver)
usbtrace(TRACE_DEVUNREGISTER, 0);
flags = spin_lock_irqsave(&g_usbdev.lock);
flags = spin_lock_irqsave(&priv->lock);
sched_lock();
/* Unbind the class driver */
@@ -2158,7 +2184,8 @@ int usbdev_unregister(struct usbdevclass_driver_s *driver)
priv->driver = NULL;
spin_unlock_irqrestore(&g_usbdev.lock, flags);
spin_unlock_irqrestore(&priv->lock, flags);
sched_unlock();
return OK;
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff