Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 1 commit into from
Jan 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 69 additions & 27 deletions arch/arm/src/cxd56xx/cxd56_usbdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#include <debug.h>
#include <fcntl.h>
#include <stdio.h>
#include <sched.h>

#include <nuttx/arch.h>
#include <nuttx/kmalloc.h>
Expand All @@ -49,6 +50,7 @@
#include <nuttx/fs/procfs.h>

#include <nuttx/irq.h>
#include <nuttx/spinlock.h>
#include <nuttx/signal.h>
#include <arch/chip/usbdev.h>
#include <arch/chip/pm.h>
Expand Down Expand Up @@ -383,6 +385,10 @@ struct cxd56_usbdev_s

int signo;
pid_t pid;

/* spinlock */

spinlock_t lock;
};

/* For maintaining tables of endpoint info */
Expand Down Expand Up @@ -784,17 +790,15 @@ static inline void cxd56_abortrequest(struct cxd56_ep_s *privep,
*
****************************************************************************/

static void cxd56_reqcomplete(struct cxd56_ep_s *privep, int16_t result)
static void cxd56_reqcomplete_nolock(struct cxd56_ep_s *privep,
int16_t result)
{
struct cxd56_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 = cxd56_rqdequeue(privep);
leave_critical_section(flags);

if (privreq)
{
Expand Down Expand Up @@ -822,6 +826,17 @@ static void cxd56_reqcomplete(struct cxd56_ep_s *privep, int16_t result)
}
}

static void cxd56_reqcomplete(struct cxd56_ep_s *privep, int16_t result)
{
irqstate_t flags = spin_lock_irqsave(&privep->dev->lock);

/* Remove the completed request at the head of the endpoint request list */

cxd56_reqcomplete_nolock(privep, result);

spin_unlock_irqrestore(&privep->dev->lock, flags);
}

/****************************************************************************
* Name: cxd56_txdmacomplete
*
Expand Down Expand Up @@ -1085,7 +1100,7 @@ static void cxd56_stopoutep(struct cxd56_ep_s *privep)
*
****************************************************************************/

static void cxd56_cancelrequests(struct cxd56_ep_s *privep)
static void cxd56_cancelrequests_nolock(struct cxd56_ep_s *privep)
{
if (privep->epphy > 0)
{
Expand All @@ -1103,7 +1118,7 @@ static void cxd56_cancelrequests(struct cxd56_ep_s *privep)
{
usbtrace(TRACE_COMPLETE(privep->epphy),
(cxd56_rqpeek(privep))->req.xfrd);
cxd56_reqcomplete(privep, -ESHUTDOWN);
cxd56_reqcomplete_nolock(privep, -ESHUTDOWN);
}

if (privep->epphy > 0)
Expand All @@ -1119,6 +1134,17 @@ static void cxd56_cancelrequests(struct cxd56_ep_s *privep)
}
}

static void cxd56_cancelrequests(struct cxd56_ep_s *privep)
{
irqstate_t flags = spin_lock_irqsave(&privep->dev->lock);
sched_lock();

cxd56_cancelrequests_nolock(privep);

spin_unlock_irqrestore(&privep->dev->lock, flags);
sched_unlock();
}

/****************************************************************************
* Name: cxd56_epfindbyaddr
*
Expand Down Expand Up @@ -2269,10 +2295,12 @@ static int cxd56_epdisable(struct usbdev_ep_s *ep)

/* Cancel any ongoing activity and reset the endpoint */

flags = enter_critical_section();
flags = spin_lock_irqsave(&privep->dev->lock);
sched_lock();
cxd56_epstall(&privep->ep, false);
xiaoxiang781216 marked this conversation as resolved.
Show resolved Hide resolved
cxd56_cancelrequests(privep);
leave_critical_section(flags);
cxd56_cancelrequests_nolock(privep);
spin_unlock_irqrestore(&privep->dev->lock, flags);
sched_unlock();
return OK;
}

Expand Down Expand Up @@ -2411,7 +2439,8 @@ static int cxd56_epsubmit(struct usbdev_ep_s *ep,

req->result = -EINPROGRESS;
req->xfrd = 0;
flags = enter_critical_section();
flags = spin_lock_irqsave(&priv->lock);
sched_lock();

/* If we are stalled, then drop all requests on the floor, except OUT */

Expand Down Expand Up @@ -2442,7 +2471,7 @@ static int cxd56_epsubmit(struct usbdev_ep_s *ep,
*/

usbtrace(TRACE_COMPLETE(privep->epphy), privreq->req.xfrd);
cxd56_reqcomplete(privep, OK);
cxd56_reqcomplete_nolock(privep, OK);
}

if (priv->ctrl.req == USB_REQ_SETCONFIGURATION)
Expand Down Expand Up @@ -2515,7 +2544,8 @@ static int cxd56_epsubmit(struct usbdev_ep_s *ep,
ret = cxd56_rdrequest(privep);
}

leave_critical_section(flags);
spin_unlock_irqrestore(&priv->lock, flags);
sched_unlock();
return ret;
}

Expand Down Expand Up @@ -2543,9 +2573,11 @@ static int cxd56_epcancel(struct usbdev_ep_s *ep,

usbtrace(TRACE_EPCANCEL, privep->epphy);

flags = enter_critical_section();
cxd56_cancelrequests(privep);
leave_critical_section(flags);
flags = spin_lock_irqsave(&privep->dev->lock);
sched_lock();
cxd56_cancelrequests_nolock(privep);
spin_unlock_irqrestore(&privep->dev->lock, flags);
sched_unlock();
return OK;
}

Expand Down Expand Up @@ -2725,12 +2757,12 @@ static struct usbdev_ep_s *cxd56_allocep(struct usbdev_s *dev,
continue;
}

flags = enter_critical_section();
flags = spin_lock_irqsave(&priv->lock);
priv->avail &= ~(1 << ndx);
mask = getreg32(CXD56_USB_DEV_EP_INTR_MASK);
mask &= ~(1 << ndx << (in ? 0 : 16));
putreg32(mask, CXD56_USB_DEV_EP_INTR_MASK);
leave_critical_section(flags);
spin_unlock_irqrestore(&priv->lock, flags);
return &priv->eplist[ndx].ep;
}
}
Expand Down Expand Up @@ -2758,9 +2790,9 @@ static void cxd56_freeep(struct usbdev_s *dev,

cxd56_freeepbuffer(privep);

flags = enter_critical_section();
flags = spin_lock_irqsave(&privep->dev->lock);
pdev->avail |= 1 << privep->epphy;
leave_critical_section(flags);
spin_unlock_irqrestore(&privep->dev->lock, flags);
}

/****************************************************************************
Expand All @@ -2773,6 +2805,7 @@ static void cxd56_freeep(struct usbdev_s *dev,

static int cxd56_getframe(struct usbdev_s *dev)
{
struct cxd56_usbdev_s *priv = (struct cxd56_usbdev_s *)dev;
irqstate_t flags;
int ret = 0;

Expand All @@ -2790,9 +2823,9 @@ static int cxd56_getframe(struct usbdev_s *dev)
* because the operation is not atomic.
*/

flags = enter_critical_section();
flags = spin_lock_irqsave(&priv->lock);
ret = getreg32(CXD56_USB_DEV_STATUS) >> 18;
leave_critical_section(flags);
spin_unlock_irqrestore(&priv->lock, flags);
return ret;
}

Expand All @@ -2806,13 +2839,14 @@ static int cxd56_getframe(struct usbdev_s *dev)

static int cxd56_wakeup(struct usbdev_s *dev)
{
struct cxd56_usbdev_s *priv = (struct cxd56_usbdev_s *)dev;
irqstate_t flags;

usbtrace(TRACE_DEVWAKEUP, 0);

flags = enter_critical_section();
flags = spin_lock_irqsave(&priv->lock);
putreg32(getreg32(CXD56_USB_DEV_CONTROL) | 1, CXD56_USB_DEV_CONTROL);
leave_critical_section(flags);
spin_unlock_irqrestore(&priv->lock, flags);
return OK;
}

Expand Down Expand Up @@ -3076,6 +3110,10 @@ void arm_usbinitialize(void)

cxd56_usb_clock_enable();

/* Initialize driver lock */

spin_lock_init(&g_usbdev.lock);

if (irq_attach(CXD56_IRQ_USB_SYS, cxd56_sysinterrupt, &g_usbdev) != 0)
{
usbtrace(TRACE_DEVERROR(CXD56_TRACEERR_ATTACHIRQREG), 0);
Expand Down Expand Up @@ -3135,7 +3173,8 @@ void arm_usbuninitialize(void)
usbdev_unregister(priv->driver);
}

flags = enter_critical_section();
flags = spin_lock_irqsave(&priv->lock);
sched_lock();
cxd56_pullup(&priv->usbdev, false);
priv->usbdev.speed = USB_SPEED_UNKNOWN;

Expand All @@ -3152,7 +3191,8 @@ void arm_usbuninitialize(void)
irq_detach(CXD56_IRQ_USB_VBUSN);

cxd56_usb_clock_disable();
leave_critical_section(flags);
spin_unlock_irqrestore(&priv->lock, flags);
sched_unlock();

/* Clear signal */

Expand Down Expand Up @@ -3246,7 +3286,8 @@ int usbdev_unregister(struct usbdevclass_driver_s *driver)

CLASS_UNBIND(driver, &g_usbdev.usbdev);

flags = enter_critical_section();
flags = spin_lock_irqsave(&priv->lock);
sched_lock();

/* Disable IRQs */

Expand All @@ -3266,7 +3307,8 @@ int usbdev_unregister(struct usbdevclass_driver_s *driver)

cxd56_usbhwuninit();

leave_critical_section(flags);
spin_unlock_irqrestore(&priv->lock, flags);
sched_unlock();

up_pm_release_freqlock(&g_hv_lock);
up_pm_release_wakelock(&g_wake_lock);
Expand Down
Loading
Loading