From 01000e60447dc6c24528518d1c842bd93153f134 Mon Sep 17 00:00:00 2001 From: wangzhi16 Date: Wed, 15 Jan 2025 16:51:53 +0800 Subject: [PATCH] Use small lock to protect usbdev and endpoint in arch ARM. Signed-off-by: wangzhi16 --- arch/arm/src/cxd56xx/cxd56_usbdev.c | 96 ++++++++---- arch/arm/src/dm320/dm320_usbdev.c | 82 +++++++--- arch/arm/src/efm32/efm32_usbdev.c | 100 ++++++++---- arch/arm/src/imxrt/imxrt_usbdev.c | 76 +++++++--- arch/arm/src/kinetis/kinetis_usbdev.c | 64 +++++--- arch/arm/src/lpc17xx_40xx/lpc17_40_usbdev.c | 153 +++++++++++++------ arch/arm/src/lpc214x/lpc214x_usbdev.c | 159 +++++++++++++++----- arch/arm/src/lpc31xx/lpc31_usbdev.c | 77 +++++++--- arch/arm/src/rp2040/rp2040_usbdev.c | 67 ++++++--- arch/arm/src/rp23xx/rp23xx_usbdev.c | 75 ++++++--- arch/arm/src/samv7/sam_usbdevhs.c | 78 ++++++---- arch/arm/src/stm32/stm32_usbdev.c | 88 +++++++---- arch/arm/src/stm32f0l0g0/stm32_usbdev.c | 100 ++++++++---- arch/arm/src/stm32l4/stm32l4_usbdev.c | 95 ++++++++---- 14 files changed, 927 insertions(+), 383 deletions(-) diff --git a/arch/arm/src/cxd56xx/cxd56_usbdev.c b/arch/arm/src/cxd56xx/cxd56_usbdev.c index 2ec84ba7cecd6..610b10b90223e 100644 --- a/arch/arm/src/cxd56xx/cxd56_usbdev.c +++ b/arch/arm/src/cxd56xx/cxd56_usbdev.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -49,6 +50,7 @@ #include #include +#include #include #include #include @@ -383,6 +385,10 @@ struct cxd56_usbdev_s int signo; pid_t pid; + + /* spinlock */ + + spinlock_t lock; }; /* For maintaining tables of endpoint info */ @@ -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) { @@ -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 * @@ -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) { @@ -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) @@ -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 * @@ -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); - cxd56_cancelrequests(privep); - leave_critical_section(flags); + cxd56_cancelrequests_nolock(privep); + spin_unlock_irqrestore(&privep->dev->lock, flags); + sched_unlock(); return OK; } @@ -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 */ @@ -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) @@ -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; } @@ -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; } @@ -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; } } @@ -2758,9 +2790,9 @@ static void cxd56_freeep(struct usbdev_s *dev, cxd56_freeepbuffer(privep); - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); pdev->avail |= 1 << privep->epphy; - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); } /**************************************************************************** @@ -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; @@ -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; } @@ -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; } @@ -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); @@ -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; @@ -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 */ @@ -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 */ @@ -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); diff --git a/arch/arm/src/dm320/dm320_usbdev.c b/arch/arm/src/dm320/dm320_usbdev.c index 93f47cc8c8af1..66882d65255fb 100644 --- a/arch/arm/src/dm320/dm320_usbdev.c +++ b/arch/arm/src/dm320/dm320_usbdev.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -42,6 +43,7 @@ #include #include +#include #include #include "chip.h" @@ -233,6 +235,10 @@ struct dm320_usbdev_s /* The endpoint list */ struct dm320_ep_s eplist[DM320_NENDPOINTS]; + + /* Spinlock */ + + spinlock_t lock; }; /* For maintaining tables of endpoint info */ @@ -892,17 +898,15 @@ static inline void dm320_abortrequest(struct dm320_ep_s *privep, * ****************************************************************************/ -static void dm320_reqcomplete(struct dm320_ep_s *privep, int16_t result) +static void dm320_reqcomplete_nolock(struct dm320_ep_s *privep, + int16_t result) { struct dm320_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 = dm320_rqdequeue(privep); - leave_critical_section(flags); if (privreq) { @@ -933,6 +937,17 @@ static void dm320_reqcomplete(struct dm320_ep_s *privep, int16_t result) } } +static void dm320_reqcomplete(struct dm320_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: dm320_wrrequest * @@ -944,7 +959,7 @@ static void dm320_reqcomplete(struct dm320_ep_s *privep, int16_t result) * ****************************************************************************/ -static int dm320_wrrequest(struct dm320_ep_s *privep) +static int dm320_wrrequest_nolock(struct dm320_ep_s *privep) { struct dm320_req_s *privreq; uint8_t *buf; @@ -1019,7 +1034,7 @@ static int dm320_wrrequest(struct dm320_ep_s *privep) { usbtrace(TRACE_COMPLETE(privep->epphy), privreq->req.xfrd); privep->txnullpkt = 0; - dm320_reqcomplete(privep, OK); + dm320_reqcomplete_nolock(privep, OK); return OK; } } @@ -1027,6 +1042,20 @@ static int dm320_wrrequest(struct dm320_ep_s *privep) return OK; /* Won't get here */ } +static int dm320_wrrequest(struct dm320_ep_s *privep) +{ + int ret; + irqstate_t flags = spin_lock_irqsave(&privep->dev->lock); + sched_lock(); + + ret = dm320_wrrequest_nolock(privep); + + spin_unlock_irqrestore(&privep->dev->lock, flags); + sched_unlock(); + + return ret; +} + /**************************************************************************** * Name: dm320_rdrequest * @@ -1091,7 +1120,7 @@ static void dm320_cancelrequests(struct dm320_ep_s *privep) { usbtrace(TRACE_COMPLETE(privep->epphy), (dm320_rqpeek(privep))->req.xfrd); - dm320_reqcomplete(privep, -ESHUTDOWN); + dm320_reqcomplete_nolock(privep, -ESHUTDOWN); } } @@ -1998,11 +2027,13 @@ static int dm320_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(); dm320_cancelrequests(privep); dm320_epreset(privep->epphy); - leave_critical_section(flags); + spin_unlock_irqrestore(&privep->dev->lock, flags); + sched_unlock(); return OK; } @@ -2141,7 +2172,8 @@ static int dm320_epsubmit(struct usbdev_ep_s *ep, req->result = -EINPROGRESS; req->xfrd = 0; - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); + sched_lock(); /* Check for NULL packet */ @@ -2179,7 +2211,7 @@ static int dm320_epsubmit(struct usbdev_ep_s *ep, dm320_rqenqueue(privep, privreq); usbtrace(TRACE_INREQQUEUED(privep->epphy), privreq->req.len); - ret = dm320_wrrequest(privep); + ret = dm320_wrrequest_nolock(privep); } /* Handle OUT (host-to-device) requests */ @@ -2201,7 +2233,8 @@ static int dm320_epsubmit(struct usbdev_ep_s *ep, } } - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); + sched_unlock(); return ret; } @@ -2231,9 +2264,11 @@ static int dm320_epcancel(struct usbdev_ep_s *ep, usbtrace(TRACE_EPCANCEL, privep->epphy); priv = privep->dev; - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); + sched_lock(); dm320_cancelrequests(privep); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); + sched_unlock(); return OK; } @@ -2341,6 +2376,7 @@ static void dm320_freeep(struct usbdev_s *dev, static int dm320_getframe(struct usbdev_s *dev) { + struct dm320_usbdev_s *priv = (struct dm320_usbdev_s *)dev; irqstate_t flags; int ret; @@ -2358,10 +2394,10 @@ static int dm320_getframe(struct usbdev_s *dev) * because the operation is not atomic. */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); ret = dm320_getreg8(DM320_USB_FRAME2) << 8; ret |= dm320_getreg8(DM320_USB_FRAME1); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); return ret; } @@ -2375,12 +2411,13 @@ static int dm320_getframe(struct usbdev_s *dev) static int dm320_wakeup(struct usbdev_s *dev) { + struct dm320_usbdev_s *priv = (struct dm320_usbdev_s *)dev; irqstate_t flags; usbtrace(TRACE_DEVWAKEUP, 0); - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); dm320_putreg8(USB_POWER_RESUME, DM320_USB_POWER); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); return OK; } @@ -2421,11 +2458,12 @@ static int dm320_selfpowered(struct usbdev_s *dev, bool selfpowered) #ifdef CONFIG_DM320_GIO_USBDPPULLUP static int dm320_pullup(struct usbdev_s *dev, bool enable) { + struct dm320_usbdev_s *priv = (struct dm320_usbdev_s *)dev; irqstate_t flags; usbtrace(TRACE_DEVPULLUP, (uint16_t)enable); - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); if (enable) { GIO_SET_OUTPUT(CONFIG_DM320_GIO_USBDPPULLUP); /* Set D+ pullup */ @@ -2435,7 +2473,7 @@ static int dm320_pullup(struct usbdev_s *dev, bool enable) GIO_CLEAR_OUTPUT(CONFIG_DM320_GIO_USBDPPULLUP); /* Clear D+ pullup */ } - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); return OK; } #endif @@ -2463,6 +2501,10 @@ void arm_usbinitialize(void) usbtrace(TRACE_DEVINIT, 0); + /* Initialize dev lock */ + + spin_lock_init(&priv->lock); + /* Initialize the device state structure */ memset(priv, 0, sizeof(struct dm320_usbdev_s)); diff --git a/arch/arm/src/efm32/efm32_usbdev.c b/arch/arm/src/efm32/efm32_usbdev.c index e4fd0157a096e..02d4c07c29589 100644 --- a/arch/arm/src/efm32/efm32_usbdev.c +++ b/arch/arm/src/efm32/efm32_usbdev.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -43,6 +44,7 @@ #include #include +#include #include #include "chip.h" @@ -455,6 +457,10 @@ struct efm32_usbdev_s struct efm32_ep_s epin[EFM32_NENDPOINTS]; struct efm32_ep_s epout[EFM32_NENDPOINTS]; + + /* Spinlock */ + + spinlock_t lock; }; /**************************************************************************** @@ -4123,7 +4129,8 @@ static void efm32_epout_disable(struct efm32_ep_s *privep) * Global OUT NAK mode in the core. */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(&privep->dev->lock); + sched_lock(); efm32_enablegonak(privep); /* Disable the required OUT endpoint by setting the EPDIS and SNAK bits @@ -4170,7 +4177,8 @@ static void efm32_epout_disable(struct efm32_ep_s *privep) efm32_req_cancel(privep, -ESHUTDOWN); - leave_critical_section(flags); + spin_unlock_irqrestore(&privep->dev->lock, flags); + sched_unlock(); } /**************************************************************************** @@ -4235,7 +4243,8 @@ static void efm32_epin_disable(struct efm32_ep_s *privep) * the DIEPCTLx register. */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(&privep->dev->lock); + sched_lock(); regaddr = EFM32_USB_DIEPCTL(privep->epphy); regval = efm32_getreg(regaddr); regval &= ~USB_DIEPCTL_USBACTEP; @@ -4266,7 +4275,8 @@ static void efm32_epin_disable(struct efm32_ep_s *privep) /* Cancel any queued write requests */ efm32_req_cancel(privep, -ESHUTDOWN); - leave_critical_section(flags); + spin_unlock_irqrestore(&privep->dev->lock, flags); + sched_unlock(); } /**************************************************************************** @@ -4457,7 +4467,8 @@ static int efm32_ep_submit(struct usbdev_ep_s *ep, /* Disable Interrupts */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); + sched_lock(); /* If we are stalled, then drop all requests on the floor */ @@ -4502,7 +4513,8 @@ static int efm32_ep_submit(struct usbdev_ep_s *ep, } } - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); + sched_unlock(); return ret; } @@ -4530,7 +4542,8 @@ static int efm32_ep_cancel(struct usbdev_ep_s *ep, usbtrace(TRACE_EPCANCEL, privep->epphy); - flags = enter_critical_section(); + flags = spin_lock_irqsave(&privep->dev->lock); + sched_lock(); /* FIXME: if the request is the first, then we need to flush the EP * otherwise just remove it from the list @@ -4539,7 +4552,8 @@ static int efm32_ep_cancel(struct usbdev_ep_s *ep, */ efm32_req_cancel(privep, -ESHUTDOWN); - leave_critical_section(flags); + spin_unlock_irqrestore(&privep->dev->lock, flags); + sched_unlock(); return OK; } @@ -4749,7 +4763,8 @@ static int efm32_ep_stall(struct usbdev_ep_s *ep, bool resume) /* Set or clear the stall condition as requested */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(&privep->dev->lock); + sched_lock(); if (resume) { ret = efm32_ep_clrstall(privep); @@ -4759,7 +4774,8 @@ static int efm32_ep_stall(struct usbdev_ep_s *ep, bool resume) ret = efm32_ep_setstall(privep); } - leave_critical_section(flags); + spin_unlock_irqrestore(&privep->dev->lock, flags); + sched_unlock(); return ret; } @@ -4819,7 +4835,8 @@ static struct usbdev_ep_s *efm32_ep_alloc(struct usbdev_s *dev, /* Get the set of available endpoints depending on the direction */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); + sched_lock(); epavail = priv->epavail[in]; /* A physical address of 0 means that any endpoint will do */ @@ -4866,7 +4883,8 @@ static struct usbdev_ep_s *efm32_ep_alloc(struct usbdev_s *dev, /* And return the pointer to the standard endpoint structure */ - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); + sched_unlock(); return in ? &priv->epin[epno].ep : &priv->epout[epno].ep; } } @@ -4875,7 +4893,8 @@ static struct usbdev_ep_s *efm32_ep_alloc(struct usbdev_s *dev, } usbtrace(TRACE_DEVERROR(EFM32_TRACEERR_NOEP), (uint16_t)eplog); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); + sched_unlock(); return NULL; } @@ -4900,9 +4919,9 @@ static void efm32_ep_free(struct usbdev_s *dev, { /* Mark the endpoint as available */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); priv->epavail[privep->isin] |= (1 << privep->epphy); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); } } @@ -4944,7 +4963,8 @@ static int efm32_wakeup(struct usbdev_s *dev) /* Is wakeup enabled? */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); + sched_lock(); if (priv->wakeup) { /* Yes... is the core suspended? */ @@ -4970,7 +4990,8 @@ static int efm32_wakeup(struct usbdev_s *dev) } } - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); + sched_unlock(); return OK; } @@ -5008,13 +5029,12 @@ static int efm32_selfpowered(struct usbdev_s *dev, bool selfpowered) * ****************************************************************************/ -static int efm32_pullup(struct usbdev_s *dev, bool enable) +static int efm32_pullup_nolock(struct usbdev_s *dev, bool enable) { uint32_t regval; usbtrace(TRACE_DEVPULLUP, (uint16_t)enable); - irqstate_t flags = enter_critical_section(); regval = efm32_getreg(EFM32_USB_DCTL); if (enable) { @@ -5034,10 +5054,24 @@ static int efm32_pullup(struct usbdev_s *dev, bool enable) } efm32_putreg(regval, EFM32_USB_DCTL); - leave_critical_section(flags); + return OK; } +static int efm32_pullup(struct usbdev_s *dev, bool enable) +{ + uint32_t ret; + struct efm32_usbdev_s *priv = (struct efm32_usbdev_s *)dev; + + irqstate_t flags = spin_lock_irqsave(&priv->lock); + sched_lock(); + ret = efm32_pullup_nolock(dev, enable); + spin_unlock_irqrestore(&priv->lock, flags); + sched_unlock(); + + return ret; +} + /**************************************************************************** * Name: efm32_setaddress * @@ -5585,6 +5619,10 @@ void arm_usbinitialize(void) * 10. Start initializing the USB core ... */ + /* Initialize driver lock */ + + spin_lock_init(&priv->lock); + /* Uninitialize the hardware so that we know that we are starting from a * known state. */ @@ -5657,8 +5695,9 @@ void arm_usbuninitialize(void) /* Disconnect device */ - flags = enter_critical_section(); - efm32_pullup(&priv->usbdev, false); + flags = spin_lock_irqsave(&priv->lock); + sched_lock(); + efm32_pullup_nolock(&priv->usbdev, false); priv->usbdev.speed = USB_SPEED_UNKNOWN; /* Disable and detach IRQs */ @@ -5693,7 +5732,8 @@ void arm_usbuninitialize(void) /* TODO: Turn off USB power and clocking */ priv->devstate = DEVSTATE_DEFAULT; - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); + sched_unlock(); } /**************************************************************************** @@ -5804,9 +5844,11 @@ int usbdev_unregister(struct usbdevclass_driver_s *driver) * canceled while the class driver is still bound. */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); + sched_lock(); efm32_usbreset(priv); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); + sched_unlock(); /* Unbind the class driver */ @@ -5814,17 +5856,19 @@ int usbdev_unregister(struct usbdevclass_driver_s *driver) /* Disable USB controller interrupts */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); + sched_lock(); up_disable_irq(EFM32_IRQ_USB); /* Disconnect device */ - efm32_pullup(&priv->usbdev, false); + efm32_pullup_nolock(&priv->usbdev, false); /* Unhook the driver */ priv->driver = NULL; - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); + sched_unlock(); return OK; } diff --git a/arch/arm/src/imxrt/imxrt_usbdev.c b/arch/arm/src/imxrt/imxrt_usbdev.c index e4de158199f08..b5d6524db189b 100644 --- a/arch/arm/src/imxrt/imxrt_usbdev.c +++ b/arch/arm/src/imxrt/imxrt_usbdev.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -42,6 +43,7 @@ #include #include +#include #include #include "chip.h" @@ -388,6 +390,10 @@ struct imxrt_usbdev_s /* The endpoint list */ struct imxrt_ep_s eplist[IMXRT_NPHYSENDPOINTS]; + + /* Spinlock */ + + spinlock_t lock; }; #define EP0STATE_IDLE 0 /* Idle State, leave on receiving a setup packet or epsubmit */ @@ -2238,7 +2244,8 @@ static int imxrt_epdisable(struct usbdev_ep_s *ep) usbtrace(TRACE_EPDISABLE, privep->epphy); - flags = enter_critical_section(); + flags = spin_lock_irqsave(&privep->dev->lock); + sched_lock(); /* Disable Endpoint */ @@ -2259,7 +2266,8 @@ static int imxrt_epdisable(struct usbdev_ep_s *ep) imxrt_cancelrequests(privep, -ESHUTDOWN); - leave_critical_section(flags); + spin_unlock_irqrestore(&privep->dev->lock, flags); + sched_unlock(); return OK; } @@ -2416,7 +2424,8 @@ static int imxrt_epsubmit(struct usbdev_ep_s *ep, /* Disable Interrupts */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); + sched_lock(); /* If we are stalled, then drop all requests on the floor */ @@ -2443,7 +2452,8 @@ static int imxrt_epsubmit(struct usbdev_ep_s *ep, } } - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); + sched_unlock(); return ret; } @@ -2471,7 +2481,8 @@ static int imxrt_epcancel(struct usbdev_ep_s *ep, usbtrace(TRACE_EPCANCEL, privep->epphy); - flags = enter_critical_section(); + flags = spin_lock_irqsave(&privep->dev->lock); + sched_lock(); /* FIXME: if the request is the first, then we need to flush the EP * otherwise just remove it from the list @@ -2480,7 +2491,8 @@ static int imxrt_epcancel(struct usbdev_ep_s *ep, */ imxrt_cancelrequests(privep, -ESHUTDOWN); - leave_critical_section(flags); + spin_unlock_irqrestore(&privep->dev->lock, flags); + sched_unlock(); return OK; } @@ -2499,7 +2511,8 @@ static int imxrt_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(); usbtrace(resume ? TRACE_EPRESUME : TRACE_EPSTALL, privep->epphy); uint32_t addr = IMXRT_USBDEV_ENDPTCTRL(privep->epphy >> 1); @@ -2523,7 +2536,8 @@ static int imxrt_epstall(struct usbdev_ep_s *ep, bool resume) imxrt_setbits(ctrl_xs, addr); } - leave_critical_section(flags); + spin_unlock_irqrestore(&privep->dev->lock, flags); + sched_unlock(); return OK; } @@ -2627,7 +2641,7 @@ static struct usbdev_ep_s *imxrt_allocep(struct usbdev_s *dev, { /* Yes.. now see if any of the request endpoints are available */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); epset &= priv->epavail; if (epset) { @@ -2643,7 +2657,7 @@ static struct usbdev_ep_s *imxrt_allocep(struct usbdev_s *dev, /* Mark endpoint no longer available */ priv->epavail &= ~bit; - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); /* And return the pointer to the standard endpoint * structure @@ -2656,7 +2670,7 @@ static struct usbdev_ep_s *imxrt_allocep(struct usbdev_s *dev, /* Shouldn't get here */ } - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); } usbtrace(TRACE_DEVERROR(IMXRT_TRACEERR_NOEP), (uint16_t)eplog); @@ -2684,9 +2698,9 @@ static void imxrt_freeep(struct usbdev_s *dev, { /* Mark the endpoint as available */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); priv->epavail |= (1 << privep->epphy); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); } } @@ -2730,13 +2744,14 @@ static int imxrt_getframe(struct usbdev_s *dev) static int imxrt_wakeup(struct usbdev_s *dev) { + struct imxrt_usbdev_s *priv = (struct imxrt_usbdev_s *)dev; irqstate_t flags; usbtrace(TRACE_DEVWAKEUP, 0); - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); imxrt_setbits(USBDEV_PRTSC1_FPR, IMXRT_USBDEV_PORTSC1); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); return OK; } @@ -2774,11 +2789,10 @@ static int imxrt_selfpowered(struct usbdev_s *dev, bool selfpowered) * ****************************************************************************/ -static int imxrt_pullup(struct usbdev_s *dev, bool enable) +static int imxrt_pullup_nolock(struct usbdev_s *dev, bool enable) { usbtrace(TRACE_DEVPULLUP, (uint16_t)enable); - irqstate_t flags = enter_critical_section(); if (enable) { imxrt_setbits(USBDEV_USBCMD_RS, IMXRT_USBDEV_USBCMD); @@ -2795,10 +2809,23 @@ static int imxrt_pullup(struct usbdev_s *dev, bool enable) imxrt_clrbits(USBDEV_USBCMD_RS, IMXRT_USBDEV_USBCMD); } - leave_critical_section(flags); return OK; } +static int imxrt_pullup(struct usbdev_s *dev, bool enable) +{ + struct imxrt_usbdev_s *priv = (struct imxrt_usbdev_s *)dev; + int ret; + + irqstate_t flags = spin_lock_irqsave(&priv->lock); + sched_lock(); + ret = imxrt_pullup_nolock(dev, enable); + spin_unlock_irqrestore(&priv->lock, flags); + sched_unlock(); + + return ret; +} + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -2823,14 +2850,13 @@ void arm_usbinitialize(void) int i; irqstate_t flags; - flags = enter_critical_section(); - /* Initialize the device state structure */ memset(priv, 0, sizeof(struct imxrt_usbdev_s)); priv->usbdev.ops = &g_devops; priv->usbdev.ep0 = &priv->eplist[IMXRT_EP0_IN].ep; priv->epavail = IMXRT_EPALLSET & ~IMXRT_EPCTRLSET; + priv->lock = SP_UNLOCKED; /* Initialize the endpoint list */ @@ -2948,8 +2974,6 @@ void arm_usbinitialize(void) irq_attach(IMXRT_IRQ_USBOTG1, imxrt_usbinterrupt, NULL); up_enable_irq(IMXRT_IRQ_USBOTG1); - leave_critical_section(flags); - /* Reset/Re-initialize the USB hardware */ imxrt_usbreset(priv); @@ -2972,11 +2996,12 @@ void arm_usbuninitialize(void) usbdev_unregister(priv->driver); } - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); + sched_lock(); /* Disconnect device */ - imxrt_pullup(&priv->usbdev, false); + imxrt_pullup_nolock(&priv->usbdev, false); priv->usbdev.speed = USB_SPEED_UNKNOWN; /* Disable and detach IRQs */ @@ -3003,7 +3028,8 @@ void arm_usbuninitialize(void) imxrt_clockoff_usboh3(); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); + sched_unlock(); } /**************************************************************************** diff --git a/arch/arm/src/kinetis/kinetis_usbdev.c b/arch/arm/src/kinetis/kinetis_usbdev.c index 1b48acfcb36d3..92999d4ac17f6 100644 --- a/arch/arm/src/kinetis/kinetis_usbdev.c +++ b/arch/arm/src/kinetis/kinetis_usbdev.c @@ -48,6 +48,7 @@ #include #include #include +#include #include #include @@ -57,6 +58,7 @@ #include #include +#include #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 */ diff --git a/arch/arm/src/lpc17xx_40xx/lpc17_40_usbdev.c b/arch/arm/src/lpc17xx_40xx/lpc17_40_usbdev.c index fa433c4acb608..2b1c14dd8e35b 100644 --- a/arch/arm/src/lpc17xx_40xx/lpc17_40_usbdev.c +++ b/arch/arm/src/lpc17xx_40xx/lpc17_40_usbdev.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -42,6 +43,7 @@ #include #include +#include #include #include "arm_internal.h" @@ -353,6 +355,10 @@ struct lpc17_40_usbdev_s /* The endpoint list */ struct lpc17_40_ep_s eplist[LPC17_40_NPHYSENDPOINTS]; + + /* Spinlock */ + + spinlock_t lock; }; /**************************************************************************** @@ -651,16 +657,12 @@ static void lpc17_40_putreg(uint32_t val, uint32_t addr) * ****************************************************************************/ -static uint32_t lpc17_40_usbcmd(uint16_t cmd, uint8_t data) +static uint32_t lpc17_40_usbcmd_nolock(uint16_t cmd, uint8_t data) { - irqstate_t flags; uint32_t cmd32; uint32_t data32; uint32_t tmp = 0; - /* Disable interrupt and clear CDFULL and CCEMPTY interrupt status */ - - flags = enter_critical_section(); lpc17_40_putreg(USBDEV_INT_CDFULL | USBDEV_INT_CCEMPTY, LPC17_40_USBDEV_INTCLR); @@ -797,9 +799,22 @@ static uint32_t lpc17_40_usbcmd(uint16_t cmd, uint8_t data) break; } - /* Restore the interrupt flags */ + return tmp; +} + +static uint32_t lpc17_40_usbcmd(uint16_t cmd, uint8_t data) +{ + irqstate_t flags; + uint32_t tmp; + + /* Disable interrupt and clear CDFULL and CCEMPTY interrupt status */ + + flags = spin_lock_irqsave(&g_usbdev.lock); + sched_lock(); + tmp = lpc17_40_usbcmd_nolock(cmd, data); + spin_unlock_irqrestore(&g_usbdev.lock, flags); + sched_unlock(); - leave_critical_section(flags); return tmp; } @@ -1037,18 +1052,15 @@ static inline void lpc17_40_abortrequest(struct lpc17_40_ep_s *privep, * ****************************************************************************/ -static void lpc17_40_reqcomplete(struct lpc17_40_ep_s *privep, - int16_t result) +static void lpc17_40_reqcomplete_nolock(struct lpc17_40_ep_s *privep, + int16_t result) { struct lpc17_40_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 = lpc17_40_rqdequeue(privep); - leave_critical_section(flags); if (privreq) { @@ -1076,6 +1088,16 @@ static void lpc17_40_reqcomplete(struct lpc17_40_ep_s *privep, } } +static void lpc17_40_reqcomplete(struct lpc17_40_ep_s *privep, + int16_t result) +{ + irqstate_t flags = spin_lock_irqsave(&privep->dev->lock); + + lpc17_40_reqcomplete_nolock(privep, result); + + spin_unlock_irqrestore(&privep->dev->lock, flags); +} + /**************************************************************************** * Name: lpc17_40_wrrequest * @@ -1084,7 +1106,7 @@ static void lpc17_40_reqcomplete(struct lpc17_40_ep_s *privep, * ****************************************************************************/ -static int lpc17_40_wrrequest(struct lpc17_40_ep_s *privep) +static int lpc17_40_wrrequest_nolock(struct lpc17_40_ep_s *privep) { struct lpc17_40_req_s *privreq; uint8_t *buf; @@ -1119,7 +1141,7 @@ static int lpc17_40_wrrequest(struct lpc17_40_ep_s *privep) /* In any event, the request is complete */ - lpc17_40_reqcomplete(privep, OK); + lpc17_40_reqcomplete_nolock(privep, OK); return OK; } @@ -1181,12 +1203,25 @@ static int lpc17_40_wrrequest(struct lpc17_40_ep_s *privep) { usbtrace(TRACE_COMPLETE(privep->epphy), privreq->req.xfrd); privep->txnullpkt = 0; - lpc17_40_reqcomplete(privep, OK); + lpc17_40_reqcomplete_nolock(privep, OK); } return OK; } +static int lpc17_40_wrrequest(struct lpc17_40_ep_s *privep) +{ + int ret; + + irqstate_t flags = spin_lock_irqsave(&privep->dev->lock); + sched_lock(); + ret = lpc17_40_wrrequest_nolock(privep); + spin_unlock_irqrestore(&privep->dev->lock, flags); + sched_unlock(); + + return ret; +} + /**************************************************************************** * Name: lpc17_40_rdrequest * @@ -1263,7 +1298,7 @@ static void lpc17_40_cancelrequests(struct lpc17_40_ep_s *privep) { usbtrace(TRACE_COMPLETE(privep->epphy), (lpc17_40_rqpeek(privep))->req.xfrd); - lpc17_40_reqcomplete(privep, -ESHUTDOWN); + lpc17_40_reqcomplete_nolock(privep, -ESHUTDOWN); } } @@ -2727,7 +2762,8 @@ static int lpc17_40_epdisable(struct usbdev_ep_s *ep) /* Cancel any ongoing activity */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(&privep->dev->lock); + sched_lock(); lpc17_40_cancelrequests(privep); /* Disable endpoint and interrupt */ @@ -2742,7 +2778,8 @@ static int lpc17_40_epdisable(struct usbdev_ep_s *ep) regval &= ~mask; lpc17_40_putreg(regval, LPC17_40_USBDEV_EPINTEN); - leave_critical_section(flags); + spin_unlock_irqrestore(&privep->dev->lock, flags); + sched_unlock(); return OK; } @@ -2931,7 +2968,8 @@ static int lpc17_40_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 */ @@ -2977,7 +3015,8 @@ static int lpc17_40_epsubmit(struct usbdev_ep_s *ep, } } - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); + sched_unlock(); return ret; } @@ -3005,9 +3044,11 @@ static int lpc17_40_epcancel(struct usbdev_ep_s *ep, usbtrace(TRACE_EPCANCEL, privep->epphy); - flags = enter_critical_section(); + flags = spin_lock_irqsave(&privep->dev->lock); + sched_lock(); lpc17_40_cancelrequests(privep); - leave_critical_section(flags); + spin_unlock_irqrestore(&privep->dev->lock, flags); + sched_unlock(); return OK; } @@ -3026,19 +3067,21 @@ static int lpc17_40_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(); usbtrace(resume ? TRACE_EPRESUME : TRACE_EPSTALL, privep->epphy); - lpc17_40_usbcmd(CMD_USBDEV_EPSETSTATUS | privep->epphy, - (resume ? 0 : CMD_SETSTAUS_ST)); + lpc17_40_usbcmd_nolock(CMD_USBDEV_EPSETSTATUS | privep->epphy, + (resume ? 0 : CMD_SETSTAUS_ST)); /* If the endpoint of was resumed, then restart any queue write requests */ if (resume) { - lpc17_40_wrrequest(privep); + lpc17_40_wrrequest_nolock(privep); } - leave_critical_section(flags); + spin_unlock_irqrestore(&privep->dev->lock, flags); + sched_unlock(); return OK; } @@ -3145,7 +3188,7 @@ static struct usbdev_ep_s *lpc17_40_allocep(struct usbdev_s *dev, { /* Yes.. now see if any of the request endpoints are available */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); epset &= priv->epavail; if (epset) { @@ -3161,7 +3204,7 @@ static struct usbdev_ep_s *lpc17_40_allocep(struct usbdev_s *dev, /* Mark the IN/OUT endpoint no longer available */ priv->epavail &= ~(3 << (epndx & ~1)); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); /* And return the pointer to the standard endpoint * structure @@ -3174,7 +3217,7 @@ static struct usbdev_ep_s *lpc17_40_allocep(struct usbdev_s *dev, /* Shouldn't get here */ } - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); } usbtrace(TRACE_DEVERROR(LPC17_40_TRACEERR_NOEP), (uint16_t)eplog); @@ -3202,9 +3245,9 @@ static void lpc17_40_freeep(struct usbdev_s *dev, { /* Mark the IN/OUT endpoint as available */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); priv->epavail |= (3 << (privep->epphy & ~1)); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); } } @@ -3243,19 +3286,22 @@ static int lpc17_40_getframe(struct usbdev_s *dev) static int lpc17_40_wakeup(struct usbdev_s *dev) { + struct lpc17_40_usbdev_s *priv = (struct lpc17_40_usbdev_s *)dev; uint8_t arg = CMD_STATUS_SUSPEND; irqstate_t flags; usbtrace(TRACE_DEVWAKEUP, (uint16_t)g_usbdev.devstatus); - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); + sched_lock(); if (DEVSTATUS_CONNECT(g_usbdev.devstatus)) { arg |= CMD_STATUS_CONNECT; } - lpc17_40_usbcmd(CMD_USBDEV_SETSTATUS, arg); - leave_critical_section(flags); + lpc17_40_usbcmd_nolock(CMD_USBDEV_SETSTATUS, arg); + spin_unlock_irqrestore(&priv->lock, flags); + sched_unlock(); return OK; } @@ -3293,6 +3339,19 @@ static int lpc17_40_selfpowered(struct usbdev_s *dev, bool selfpowered) * ****************************************************************************/ +static int lpc17_40_pullup_nolock(struct usbdev_s *dev, bool enable) +{ + usbtrace(TRACE_DEVPULLUP, (uint16_t)enable); + + /* The CMD_STATUS_CONNECT bit in the CMD_USBDEV_SETSTATUS command + * controls the LPC17xx/LPC40xx SoftConnect_N output pin that is used for + * SoftConnect. + */ + + lpc17_40_usbcmd_nolock(CMD_USBDEV_SETSTATUS, (enable ? CMD_STATUS_CONNECT : 0)); + return OK; +} + static int lpc17_40_pullup(struct usbdev_s *dev, bool enable) { usbtrace(TRACE_DEVPULLUP, (uint16_t)enable); @@ -3331,9 +3390,14 @@ void arm_usbinitialize(void) usbtrace(TRACE_DEVINIT, 0); + /* Initialize driver lock */ + + spin_lock_init(&priv->lock); + /* Step 1: Enable power by setting PCUSB in the PCONP register */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); + sched_lock(); regval = lpc17_40_getreg(LPC17_40_SYSCON_PCONP); regval |= SYSCON_PCONP_PCUSB; lpc17_40_putreg(regval, LPC17_40_SYSCON_PCONP); @@ -3374,7 +3438,8 @@ void arm_usbinitialize(void) regval = lpc17_40_getreg(LPC17_40_SYSCON_USBINTST); regval &= ~SYSCON_USBINTST_ENINTS; lpc17_40_putreg(regval, LPC17_40_SYSCON_USBINTST); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); + sched_unlock(); /* Initialize the device state structure */ @@ -3460,11 +3525,11 @@ void arm_usbinitialize(void) * driver */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); regval = lpc17_40_getreg(LPC17_40_SYSCON_USBINTST); regval |= SYSCON_USBINTST_ENINTS; lpc17_40_putreg(regval, LPC17_40_SYSCON_USBINTST); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); /* Disconnect device */ @@ -3508,10 +3573,11 @@ void arm_usbuninitialize(void) /* Disconnect device */ - flags = enter_critical_section(); - lpc17_40_pullup(&priv->usbdev, false); + flags = spin_lock_irqsave(&priv->lock); + sched_lock(); + lpc17_40_pullup_nolock(&priv->usbdev, false); priv->usbdev.speed = USB_SPEED_UNKNOWN; - lpc17_40_usbcmd(CMD_USBDEV_CONFIG, 0); + lpc17_40_usbcmd_nolock(CMD_USBDEV_CONFIG, 0); /* Disable and detach IRQs */ @@ -3523,7 +3589,8 @@ void arm_usbuninitialize(void) regval = lpc17_40_getreg(LPC17_40_SYSCON_PCONP); regval &= ~SYSCON_PCONP_PCUSB; lpc17_40_putreg(regval, LPC17_40_SYSCON_PCONP); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); + sched_unlock(); } /**************************************************************************** diff --git a/arch/arm/src/lpc214x/lpc214x_usbdev.c b/arch/arm/src/lpc214x/lpc214x_usbdev.c index 1496d563cef05..9b8f68418e7d6 100644 --- a/arch/arm/src/lpc214x/lpc214x_usbdev.c +++ b/arch/arm/src/lpc214x/lpc214x_usbdev.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -42,6 +43,7 @@ #include #include +#include #include #include "chip.h" @@ -361,6 +363,10 @@ struct lpc214x_usbdev_s /* The endpoint list */ struct lpc214x_ep_s eplist[LPC214X_NPHYSENDPOINTS]; + + /* Spinlock */ + + spinlock_t lock; }; /**************************************************************************** @@ -595,14 +601,10 @@ static void lpc214x_putreg(uint32_t val, uint32_t addr) * ****************************************************************************/ -static uint32_t lpc214x_usbcmd(uint16_t cmd, uint8_t data) +static uint32_t lpc214x_usbcmd_nolock(uint16_t cmd, uint8_t data) { - irqstate_t flags; uint32_t tmp = 0; - /* Disable interrupt and clear CDFULL and CCEMPTY interrupt status */ - - flags = enter_critical_section(); lpc214x_putreg(USBDEV_DEVINT_CDFULL | USBDEV_DEVINT_CCEMTY, LPC214X_USBDEV_DEVINTCLR); @@ -734,9 +736,26 @@ static uint32_t lpc214x_usbcmd(uint16_t cmd, uint8_t data) break; } + return tmp; +} + +static uint32_t lpc214x_usbcmd(uint16_t cmd, uint8_t data) +{ + irqstate_t flags; + uint32_t tmp = 0; + + /* Disable interrupt and clear CDFULL and CCEMPTY interrupt status */ + + flags = spin_lock_irqsave(&g_usbdev.lock); + sched_lock(); + + tmp = lpc214x_usbcmd_nolock(cmd, data); + /* Restore the interrupt flags */ - leave_critical_section(flags); + spin_unlock_irqrestore(&g_usbdev.lock, flags); + sched_unlock(); + return tmp; } @@ -975,17 +994,15 @@ static inline void lpc214x_abortrequest(struct lpc214x_ep_s *privep, * ****************************************************************************/ -static void lpc214x_reqcomplete(struct lpc214x_ep_s *privep, int16_t result) +static void lpc214x_reqcomplete_nolock(struct lpc214x_ep_s *privep, + int16_t result) { struct lpc214x_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 = lpc214x_rqdequeue(privep); - leave_critical_section(flags); if (privreq) { @@ -1013,6 +1030,15 @@ static void lpc214x_reqcomplete(struct lpc214x_ep_s *privep, int16_t result) } } +static void lpc214x_reqcomplete(struct lpc214x_ep_s *privep, int16_t result) +{ + irqstate_t flags = spin_lock_irqsave(&privep->dev->lock); + + lpc214x_reqcomplete_nolock(privep, result); + + spin_unlock_irqrestore(&privep->dev->lock, flags); +} + /**************************************************************************** * Name: lpc214x_wrrequest * @@ -1021,7 +1047,7 @@ static void lpc214x_reqcomplete(struct lpc214x_ep_s *privep, int16_t result) * ****************************************************************************/ -static int lpc214x_wrrequest(struct lpc214x_ep_s *privep) +static int lpc214x_wrrequest_nolock(struct lpc214x_ep_s *privep) { struct lpc214x_req_s *privreq; uint8_t *buf; @@ -1056,7 +1082,7 @@ static int lpc214x_wrrequest(struct lpc214x_ep_s *privep) /* In any event, the request is complete */ - lpc214x_reqcomplete(privep, OK); + lpc214x_reqcomplete_nolock(privep, OK); return OK; } @@ -1118,12 +1144,25 @@ static int lpc214x_wrrequest(struct lpc214x_ep_s *privep) { usbtrace(TRACE_COMPLETE(privep->epphy), privreq->req.xfrd); privep->txnullpkt = 0; - lpc214x_reqcomplete(privep, OK); + lpc214x_reqcomplete_nolock(privep, OK); } return OK; } +static int lpc214x_wrrequest(struct lpc214x_ep_s *privep) +{ + int ret; + + irqstate_t flags = spin_lock_irqsave(&privep->dev->lock); + sched_lock(); + ret = lpc214x_wrrequest_nolock(privep); + spin_unlock_irqrestore(&privep->dev->lock, flags); + sched_unlock(); + + return ret; +} + /**************************************************************************** * Name: lpc214x_rdrequest * @@ -1194,16 +1233,25 @@ static int lpc214x_rdrequest(struct lpc214x_ep_s *privep) * ****************************************************************************/ -static void lpc214x_cancelrequests(struct lpc214x_ep_s *privep) +static void lpc214x_cancelrequests_nolock(struct lpc214x_ep_s *privep) { while (!lpc214x_rqempty(privep)) { usbtrace(TRACE_COMPLETE(privep->epphy), (lpc214x_rqpeek(privep))->req.xfrd); - lpc214x_reqcomplete(privep, -ESHUTDOWN); + lpc214x_reqcomplete_nolock(privep, -ESHUTDOWN); } } +static void lpc214x_cancelrequests(struct lpc214x_ep_s *privep) +{ + irqstate_t flags = spin_lock_irqsave(&privep->dev->lock); + sched_lock(); + lpc214x_cancelrequests_nolock(privep); + spin_unlock_irqrestore(&privep->dev->lock, flags); + sched_unlock(); +} + /**************************************************************************** * Name: lpc214x_epfindbyaddr * @@ -2687,8 +2735,9 @@ static int lpc214x_epdisable(struct usbdev_ep_s *ep) /* Cancel any ongoing activity */ - flags = enter_critical_section(); - lpc214x_cancelrequests(privep); + flags = spin_lock_irqsave(&privep->dev->lock); + sched_lock(); + lpc214x_cancelrequests_nolock(privep); /* Disable endpoint and interrupt */ @@ -2702,7 +2751,8 @@ static int lpc214x_epdisable(struct usbdev_ep_s *ep) reg &= ~mask; lpc214x_putreg(reg, LPC214X_USBDEV_EPINTEN); - leave_critical_section(flags); + spin_unlock_irqrestore(&privep->dev->lock, flags); + sched_unlock(); return OK; } @@ -2890,7 +2940,8 @@ static int lpc214x_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 */ @@ -2913,7 +2964,7 @@ static int lpc214x_epsubmit(struct usbdev_ep_s *ep, if (privep->txbusy == 0) { - ret = lpc214x_wrrequest(privep); + ret = lpc214x_wrrequest_nolock(privep); } } @@ -2936,7 +2987,8 @@ static int lpc214x_epsubmit(struct usbdev_ep_s *ep, } } - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); + sched_unlock(); return ret; } @@ -2964,9 +3016,11 @@ static int lpc214x_epcancel(struct usbdev_ep_s *ep, usbtrace(TRACE_EPCANCEL, privep->epphy); - flags = enter_critical_section(); - lpc214x_cancelrequests(privep); - leave_critical_section(flags); + flags = spin_lock_irqsave(&privep->dev->lock); + sched_lock(); + lpc214x_cancelrequests_nolock(privep); + spin_unlock_irqrestore(&privep->dev->lock, flags); + sched_unlock(); return OK; } @@ -2985,19 +3039,21 @@ static int lpc214x_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(); usbtrace(resume ? TRACE_EPRESUME : TRACE_EPSTALL, privep->epphy); - lpc214x_usbcmd(CMD_USB_EP_SETSTATUS | privep->epphy, + lpc214x_usbcmd_nolock(CMD_USB_EP_SETSTATUS | privep->epphy, (resume ? 0 : USBDEV_EPSTALL)); /* If the endpoint of was resumed, then restart any queue write requests */ if (resume) { - lpc214x_wrrequest(privep); + lpc214x_wrrequest_nolock(privep); } - leave_critical_section(flags); + spin_unlock_irqrestore(&privep->dev->lock, flags); + sched_unlock(); return OK; } @@ -3103,7 +3159,7 @@ static struct usbdev_ep_s *lcp214x_allocep(struct usbdev_s *dev, { /* Yes.. now see if any of the request endpoints are available */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); epset &= priv->epavail; if (epset) { @@ -3119,7 +3175,7 @@ static struct usbdev_ep_s *lcp214x_allocep(struct usbdev_s *dev, /* Mark the IN/OUT endpoint no longer available */ priv->epavail &= ~(3 << (bit & ~1)); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); /* And return the pointer to the standard endpoint * structure @@ -3132,7 +3188,7 @@ static struct usbdev_ep_s *lcp214x_allocep(struct usbdev_s *dev, /* Shouldn't get here */ } - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); } usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_NOEP), (uint16_t)eplog); @@ -3160,9 +3216,9 @@ static void lpc214x_freeep(struct usbdev_s *dev, { /* Mark the endpoint as available */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); priv->epavail |= (1 << privep->epphy); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); } } @@ -3201,19 +3257,22 @@ static int lpc214x_getframe(struct usbdev_s *dev) static int lpc214x_wakeup(struct usbdev_s *dev) { + struct lpc214x_usbdev_s *priv = (struct lpc214x_usbdev_s *)dev; uint8_t arg = USBDEV_DEVSTATUS_SUSPEND; irqstate_t flags; usbtrace(TRACE_DEVWAKEUP, (uint16_t)g_usbdev.devstatus); - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); + sched_lock(); if (DEVSTATUS_CONNECT(g_usbdev.devstatus)) { arg |= USBDEV_DEVSTATUS_CONNECT; } - lpc214x_usbcmd(CMD_USB_DEV_SETSTATUS, arg); - leave_critical_section(flags); + lpc214x_usbcmd_nolock(CMD_USB_DEV_SETSTATUS, arg); + spin_unlock_irqrestore(&priv->lock, flags); + sched_unlock(); return OK; } @@ -3251,6 +3310,20 @@ static int lpc214x_selfpowered(struct usbdev_s *dev, bool selfpowered) * ****************************************************************************/ +static int lpc214x_pullup_nolock(struct usbdev_s *dev, bool enable) +{ + usbtrace(TRACE_DEVPULLUP, (uint16_t)enable); + + /* The USBDEV_DEVSTATUS_CONNECT bit in the CMD_USB_DEV_SETSTATUS command + * controls the LPC214x SoftConnect_N output pin that is used for + * SoftConnect. + */ + + lpc214x_usbcmd_nolock(CMD_USB_DEV_SETSTATUS, + (enable ? USBDEV_DEVSTATUS_CONNECT : 0)); + return OK; +} + static int lpc214x_pullup(struct usbdev_s *dev, bool enable) { usbtrace(TRACE_DEVPULLUP, (uint16_t)enable); @@ -3292,6 +3365,10 @@ void arm_usbinitialize(void) usbtrace(TRACE_DEVINIT, 0); + /* Initialize driver lock */ + + spin_lock_init(&priv->lock); + /* Disable USB interrupts */ lpc214x_putreg(0, LPC214X_USBDEV_INTST); @@ -3416,10 +3493,11 @@ void arm_usbuninitialize(void) /* Disconnect device */ - flags = enter_critical_section(); - lpc214x_pullup(&priv->usbdev, false); + flags = spin_lock_irqsave(&priv->lock); + sched_lock(); + lpc214x_pullup_nolock(&priv->usbdev, false); priv->usbdev.speed = USB_SPEED_UNKNOWN; - lpc214x_usbcmd(CMD_USB_DEV_CONFIG, 0); + lpc214x_usbcmd_nolock(CMD_USB_DEV_CONFIG, 0); /* Disable and detach IRQs */ @@ -3431,7 +3509,8 @@ void arm_usbuninitialize(void) reg = lpc214x_getreg(LPC214X_PCON_PCONP); reg &= ~LPC214X_PCONP_PCUSB; lpc214x_putreg(reg, LPC214X_PCON_PCONP); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); + sched_unlock(); } /**************************************************************************** diff --git a/arch/arm/src/lpc31xx/lpc31_usbdev.c b/arch/arm/src/lpc31xx/lpc31_usbdev.c index c65ea484c02b9..706daa86e285e 100644 --- a/arch/arm/src/lpc31xx/lpc31_usbdev.c +++ b/arch/arm/src/lpc31xx/lpc31_usbdev.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -42,6 +43,7 @@ #include #include +#include #include #include "chip.h" @@ -319,7 +321,11 @@ struct lpc31_usbdev_s /* The endpoint list */ - struct lpc31_ep_s eplist[LPC31_NPHYSENDPOINTS]; + struct lpc31_ep_s eplist[LPC31_NPHYSENDPOINTS]; + + /* Spinlock */ + + spinlock_t lock; }; #define EP0STATE_IDLE 0 /* Idle State, leave on receiving a setup packet or epsubmit */ @@ -2096,7 +2102,8 @@ static int lpc31_epdisable(struct usbdev_ep_s *ep) usbtrace(TRACE_EPDISABLE, privep->epphy); - flags = enter_critical_section(); + flags = spin_lock_irqsave(&privep->dev->lock); + sched_lock(); /* Disable Endpoint */ @@ -2113,7 +2120,8 @@ static int lpc31_epdisable(struct usbdev_ep_s *ep) lpc31_cancelrequests(privep, -ESHUTDOWN); - leave_critical_section(flags); + spin_unlock_irqrestore(&privep->dev->lock, flags); + sched_unlock(); return OK; } @@ -2262,7 +2270,8 @@ static int lpc31_epsubmit(struct usbdev_ep_s *ep, /* Disable Interrupts */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(&privep->dev->lock); + sched_lock(); /* If we are stalled, then drop all requests on the floor */ @@ -2285,7 +2294,8 @@ static int lpc31_epsubmit(struct usbdev_ep_s *ep, } } - leave_critical_section(flags); + spin_unlock_irqrestore(&privep->dev->lock, flags); + sched_unlock(); return ret; } @@ -2313,7 +2323,8 @@ static int lpc31_epcancel(struct usbdev_ep_s *ep, usbtrace(TRACE_EPCANCEL, privep->epphy); - flags = enter_critical_section(); + flags = spin_lock_irqsave(&privep->dev->lock); + sched_lock(); /* FIXME: if the request is the first, then we need to flush the EP * otherwise just remove it from the list @@ -2322,7 +2333,8 @@ static int lpc31_epcancel(struct usbdev_ep_s *ep, */ lpc31_cancelrequests(privep, -ESHUTDOWN); - leave_critical_section(flags); + spin_unlock_irqrestore(&privep->dev->lock, flags); + sched_unlock(); return OK; } @@ -2341,7 +2353,8 @@ static int lpc31_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(); usbtrace(resume ? TRACE_EPRESUME : TRACE_EPSTALL, privep->epphy); uint32_t addr = LPC31_USBDEV_ENDPTCTRL(privep->epphy); @@ -2365,7 +2378,8 @@ static int lpc31_epstall(struct usbdev_ep_s *ep, bool resume) lpc31_setbits (ctrl_xs, addr); } - leave_critical_section(flags); + spin_unlock_irqrestore(&privep->dev->lock, flags); + sched_unlock(); return OK; } @@ -2472,7 +2486,7 @@ static struct usbdev_ep_s *lpc31_allocep(struct usbdev_s *dev, * now see if any of the request endpoints are available */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); epset &= priv->epavail; if (epset) { @@ -2488,7 +2502,7 @@ static struct usbdev_ep_s *lpc31_allocep(struct usbdev_s *dev, /* Mark the IN/OUT endpoint no longer available */ priv->epavail &= ~(3 << (bit & ~1)); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); /* And return the pointer to the standard endpoint * structure @@ -2501,7 +2515,7 @@ static struct usbdev_ep_s *lpc31_allocep(struct usbdev_s *dev, /* Shouldn't get here */ } - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); } usbtrace(TRACE_DEVERROR(LPC31_TRACEERR_NOEP), (uint16_t)eplog); @@ -2529,9 +2543,9 @@ static void lpc31_freeep(struct usbdev_s *dev, { /* Mark the endpoint as available */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); priv->epavail |= (1 << privep->epphy); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); } } @@ -2573,13 +2587,14 @@ static int lpc31_getframe(struct usbdev_s *dev) static int lpc31_wakeup(struct usbdev_s *dev) { + struct lpc31_usbdev_s *priv = (struct lpc31_usbdev_s *)dev; irqstate_t flags; usbtrace(TRACE_DEVWAKEUP, 0); - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); lpc31_setbits(USBDEV_PRTSC1_FPR, LPC31_USBDEV_PORTSC1); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); return OK; } @@ -2617,19 +2632,31 @@ static int lpc31_selfpowered(struct usbdev_s *dev, bool selfpowered) * ****************************************************************************/ -static int lpc31_pullup(struct usbdev_s *dev, bool enable) +static int lpc31_pullup_nolock(struct usbdev_s *dev, bool enable) { usbtrace(TRACE_DEVPULLUP, (uint16_t)enable); - irqstate_t flags = enter_critical_section(); if (enable) lpc31_setbits (USBDEV_USBCMD_RS, LPC31_USBDEV_USBCMD); else lpc31_clrbits (USBDEV_USBCMD_RS, LPC31_USBDEV_USBCMD); - leave_critical_section(flags); return OK; } +static int lpc31_pullup(struct usbdev_s *dev, bool enable) +{ + struct lpc31_usbdev_s *priv = (struct lpc31_usbdev_s *)dev; + int ret; + + irqstate_t flags = spin_lock_irqsave(&priv->lock); + sched_lock(); + ret = lpc31_pullup_nolock(dev, enable); + spin_unlock_irqrestore(&priv->lock, flags); + sched_unlock(); + + return ret; +} + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -2656,6 +2683,10 @@ void arm_usbinitialize(void) usbtrace(TRACE_DEVINIT, 0); + /* Initialize driver lock */ + + spin_lock_init(&priv->lock); + /* Disable USB interrupts */ lpc31_putreg(0, LPC31_USBDEV_USBINTR); @@ -2793,8 +2824,9 @@ void arm_usbuninitialize(void) /* Disconnect device */ - flags = enter_critical_section(); - lpc31_pullup(&priv->usbdev, false); + flags = spin_lock_irqsave(&priv->lock); + sched_lock(); + lpc31_pullup_nolock(&priv->usbdev, false); priv->usbdev.speed = USB_SPEED_UNKNOWN; /* Disable and detach IRQs */ @@ -2813,7 +2845,8 @@ void arm_usbuninitialize(void) lpc31_disableclock (CLKID_USBOTGAHBCLK); lpc31_disableclock (CLKID_EVENTROUTERPCLK); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); + sched_unlock(); } /**************************************************************************** diff --git a/arch/arm/src/rp2040/rp2040_usbdev.c b/arch/arm/src/rp2040/rp2040_usbdev.c index 32a1068bc7954..b473a0ad458a8 100644 --- a/arch/arm/src/rp2040/rp2040_usbdev.c +++ b/arch/arm/src/rp2040/rp2040_usbdev.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -515,9 +516,9 @@ static int rp2040_epwrite(struct rp2040_ep_s *privep, uint8_t *buf, /* Start the transfer */ - flags = spin_lock_irqsave(&priv->lock); + flags = spin_lock_irqsave(&privep->dev->lock); rp2040_update_buffer_control(privep, 0, val); - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irqrestore(&privep->dev->lock, flags); return nbytes; } @@ -545,9 +546,9 @@ static int rp2040_epread(struct rp2040_ep_s *privep, uint16_t nbytes) /* Start the transfer */ - flags = spin_lock_irqsave(&priv->lock); + flags = spin_lock_irqsave(&privep->dev->lock); rp2040_update_buffer_control(privep, 0, val); - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irqrestore(&privep->dev->lock, flags); return OK; } @@ -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; } @@ -2039,7 +2066,7 @@ void arm_usbinitialize(void) g_usbdev.eplist[i].ep.eplog = 0; } - spin_lock_init(&g_usbdev.lock); + spin_lock_init(&priv->lock); if (irq_attach(RP2040_USBCTRL_IRQ, rp2040_usbinterrupt, &g_usbdev) != 0) { usbtrace(TRACE_DEVERROR(RP2040_TRACEERR_IRQREGISTRATION), @@ -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; } diff --git a/arch/arm/src/rp23xx/rp23xx_usbdev.c b/arch/arm/src/rp23xx/rp23xx_usbdev.c index 48fd0873256b8..6d72c10e87215 100644 --- a/arch/arm/src/rp23xx/rp23xx_usbdev.c +++ b/arch/arm/src/rp23xx/rp23xx_usbdev.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -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; } diff --git a/arch/arm/src/samv7/sam_usbdevhs.c b/arch/arm/src/samv7/sam_usbdevhs.c index 0f92a54598381..7a5bad276506e 100644 --- a/arch/arm/src/samv7/sam_usbdevhs.c +++ b/arch/arm/src/samv7/sam_usbdevhs.c @@ -50,6 +50,7 @@ #include #include #include +#include #include #include @@ -58,6 +59,7 @@ #include #include +#include #include #include "arm_internal.h" @@ -428,6 +430,10 @@ struct sam_usbdev_s */ uint8_t ep0out[SAM_EP0_MAXPACKET]; + + /* Spinlock */ + + spinlock_t lock; }; /**************************************************************************** @@ -1195,16 +1201,13 @@ sam_req_abort(struct sam_ep_s *privep, struct sam_req_s *privreq, * ****************************************************************************/ -static void sam_req_complete(struct sam_ep_s *privep, int16_t result) +static void sam_req_complete_nolock(struct sam_ep_s *privep, int16_t result) { struct sam_req_s *privreq; - irqstate_t flags; /* Remove the completed request at the head of the endpoint request list */ - flags = enter_critical_section(); privreq = sam_req_dequeue(&privep->reqq); - leave_critical_section(flags); if (privreq) { @@ -1235,6 +1238,15 @@ static void sam_req_complete(struct sam_ep_s *privep, int16_t result) } } +static void sam_req_complete(struct sam_ep_s *privep, int16_t result) +{ + irqstate_t flags = spin_lock_irqsave(&privep->dev->lock); + + sam_req_complete_nolock(privep, result); + + spin_unlock_irqrestore(&privep->dev->lock, flags); +} + /**************************************************************************** * * Name: sam_ep_fifocon @@ -1789,7 +1801,7 @@ static void sam_req_cancel(struct sam_ep_s *privep, int16_t result) { usbtrace(TRACE_COMPLETE(USB_EPNO(privep->ep.eplog)), (sam_rqpeek(&privep->reqq))->req.xfrd); - sam_req_complete(privep, result); + sam_req_complete_nolock(privep, result); } } @@ -3531,7 +3543,7 @@ sam_ep_reserve(struct sam_usbdev_s *priv, uint16_t epset) irqstate_t flags; int epndx = 0; - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); epset &= priv->epavail; if (epset) { @@ -3556,7 +3568,7 @@ sam_ep_reserve(struct sam_usbdev_s *priv, uint16_t epset) } } - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); return privep; } @@ -3573,9 +3585,9 @@ sam_ep_reserve(struct sam_usbdev_s *priv, uint16_t epset) static inline void sam_ep_unreserve(struct sam_usbdev_s *priv, struct sam_ep_s *privep) { - irqstate_t flags = enter_critical_section(); + irqstate_t flags = spin_lock_irqsave(&priv->lock); priv->epavail |= SAM_EP_BIT(USB_EPNO(privep->ep.eplog)); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); } /**************************************************************************** @@ -3898,14 +3910,14 @@ static int sam_ep_disable(struct usbdev_ep_s *ep) /* Reset the endpoint and cancel any ongoing activity */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); priv = privep->dev; sam_ep_reset(priv, epno); /* Revert to the addressed-but-not-configured state */ priv->devstate = USBHS_DEVSTATE_ADDRESSED; - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); return OK; } @@ -4021,7 +4033,8 @@ static int sam_ep_submit(struct usbdev_ep_s *ep, struct usbdev_req_s *req) req->result = -EINPROGRESS; req->xfrd = 0; privreq->inflight = 0; - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); + sched_lock(); /* Handle IN (device-to-host) requests. NOTE: If the class device is * using the bi-directional EP0, then we assume that they intend the EP0 @@ -4073,7 +4086,8 @@ static int sam_ep_submit(struct usbdev_ep_s *ep, struct usbdev_req_s *req) } } - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); + sched_unlock(); return ret; } @@ -4091,9 +4105,11 @@ static int sam_ep_cancel(struct usbdev_ep_s *ep, struct usbdev_req_s *req) DEBUGASSERT(ep != NULL && req != NULL); usbtrace(TRACE_EPCANCEL, USB_EPNO(ep->eplog)); - flags = enter_critical_section(); + flags = spin_lock_irqsave(&privep->dev->lock); + sched_lock(); sam_req_cancel(privep, -EAGAIN); - leave_critical_section(flags); + spin_unlock_irqrestore(&privep->dev->lock, flags); + sched_unlock(); return OK; } @@ -4124,7 +4140,8 @@ static int sam_ep_stall(struct usbdev_ep_s *ep, bool resume) /* STALL or RESUME the endpoint */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); + sched_lock(); usbtrace(resume ? TRACE_EPRESUME : TRACE_EPSTALL, USB_EPNO(ep->eplog)); /* Handle the resume condition */ @@ -4208,7 +4225,7 @@ static int sam_ep_stall(struct usbdev_ep_s *ep, bool resume) else if (privep->epstate == USBHS_EPSTATE_RECEIVING) { - sam_req_complete(privep, -EPERM); + sam_req_complete_nolock(privep, -EPERM); } /* Put endpoint into stalled state */ @@ -4247,7 +4264,8 @@ static int sam_ep_stall(struct usbdev_ep_s *ep, bool resume) } } - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); + sched_unlock(); return OK; } @@ -4391,7 +4409,7 @@ static int sam_wakeup(struct usbdev_s *dev) /* Resume normal operation */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); sam_resume(priv); /* Activate a remote wakeup. @@ -4404,7 +4422,7 @@ static int sam_wakeup(struct usbdev_s *dev) regval = sam_getreg(SAM_USBHS_DEVCTRL); regval |= USBHS_DEVCTRL_RMWKUP; sam_putreg(regval, SAM_USBHS_DEVCTRL); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); /* This bit is automatically cleared by hardware at the end of the Upstream * Resume @@ -4451,7 +4469,7 @@ static int sam_pullup(struct usbdev_s *dev, bool enable) usbtrace(TRACE_DEVPULLUP, (uint16_t)enable); - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); if (enable) { /* Un-freeze clocking. @@ -4603,7 +4621,7 @@ static int sam_pullup(struct usbdev_s *dev, bool enable) } } - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); return OK; } @@ -4996,6 +5014,10 @@ void arm_usbinitialize(void) usbtrace(TRACE_DEVINIT, 0); + /* Initialize driver lock */ + + spin_lock_init(&priv->lock); + /* Software initialization */ sam_sw_setup(priv); @@ -5054,7 +5076,8 @@ void arm_usbuninitialize(void) * easier. */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); + sched_lock(); usbtrace(TRACE_DEVUNINIT, 0); /* Disable and detach the USBHS IRQ */ @@ -5072,7 +5095,8 @@ void arm_usbuninitialize(void) sam_hw_shutdown(priv); sam_sw_shutdown(priv); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); + sched_unlock(); } /**************************************************************************** @@ -5149,7 +5173,8 @@ int usbdev_unregister(struct usbdevclass_driver_s *driver) * canceled while the class driver is still bound. */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); + sched_lock(); /* Unbind the class driver */ @@ -5173,7 +5198,8 @@ int usbdev_unregister(struct usbdevclass_driver_s *driver) /* Unhook the driver */ priv->driver = NULL; - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); + sched_unlock(); return OK; } diff --git a/arch/arm/src/stm32/stm32_usbdev.c b/arch/arm/src/stm32/stm32_usbdev.c index 9cb27c1e62872..c90fe34b52b03 100644 --- a/arch/arm/src/stm32/stm32_usbdev.c +++ b/arch/arm/src/stm32/stm32_usbdev.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -48,6 +49,7 @@ #include #include +#include #include "arm_internal.h" #include "stm32.h" @@ -357,6 +359,10 @@ struct stm32_usbdev_s /* The endpoint list */ struct stm32_ep_s eplist[STM32_NENDPOINTS]; + + /* Spinlock */ + + spinlock_t lock; }; /**************************************************************************** @@ -1215,16 +1221,14 @@ stm32_abortrequest(struct stm32_ep_s *privep, * Name: stm32_reqcomplete ****************************************************************************/ -static void stm32_reqcomplete(struct stm32_ep_s *privep, int16_t result) +static void stm32_reqcomplete_nolock(struct stm32_ep_s *privep, + int16_t result) { struct stm32_req_s *privreq; - irqstate_t flags; /* Remove the completed request at the head of the endpoint request list */ - flags = enter_critical_section(); privreq = stm32_rqdequeue(privep); - leave_critical_section(flags); if (privreq) { @@ -1253,6 +1257,15 @@ static void stm32_reqcomplete(struct stm32_ep_s *privep, int16_t result) } } +static void stm32_reqcomplete(struct stm32_ep_s *privep, int16_t result) +{ + irqstate_t flags = spin_lock_irqsave(&privep->dev->lock); + + stm32_reqcomplete_nolock(privep, result); + + spin_unlock_irqrestore(&privep->dev->lock, flags); +} + /**************************************************************************** * Name: tm32_epwrite ****************************************************************************/ @@ -1540,7 +1553,7 @@ static void stm32_cancelrequests(struct stm32_ep_s *privep) { usbtrace(TRACE_COMPLETE(USB_EPNO(privep->ep.eplog)), (stm32_rqpeek(privep))->req.xfrd); - stm32_reqcomplete(privep, -ESHUTDOWN); + stm32_reqcomplete_nolock(privep, -ESHUTDOWN); } } @@ -2745,7 +2758,7 @@ stm32_epreserve(struct stm32_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) { @@ -2770,7 +2783,7 @@ stm32_epreserve(struct stm32_usbdev_s *priv, uint8_t epset) } } - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); return privep; } @@ -2781,9 +2794,9 @@ stm32_epreserve(struct stm32_usbdev_s *priv, uint8_t epset) static inline void stm32_epunreserve(struct stm32_usbdev_s *priv, struct stm32_ep_s *privep) { - irqstate_t flags = enter_critical_section(); + irqstate_t flags = spin_lock_irqsave(&priv->lock); priv->epavail |= STM32_ENDP_BIT(USB_EPNO(privep->ep.eplog)); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); } /**************************************************************************** @@ -2806,7 +2819,7 @@ static int stm32_epallocpma(struct stm32_usbdev_s *priv) int bufno = ERROR; int bufndx; - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); for (bufndx = 2; bufndx < STM32_NBUFFERS; bufndx++) { /* Check if this buffer is available */ @@ -2825,7 +2838,7 @@ static int stm32_epallocpma(struct stm32_usbdev_s *priv) } } - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); return bufno; } @@ -2836,9 +2849,9 @@ static int stm32_epallocpma(struct stm32_usbdev_s *priv) static inline void stm32_epfreepma(struct stm32_usbdev_s *priv, struct stm32_ep_s *privep) { - irqstate_t flags = enter_critical_section(); + irqstate_t flags = spin_lock_irqsave(&priv->lock); priv->epavail |= STM32_ENDP_BIT(privep->bufno); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); } /**************************************************************************** @@ -2970,7 +2983,8 @@ static int stm32_epdisable(struct usbdev_ep_s *ep) /* Cancel any ongoing activity */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(&privep->dev->lock); + sched_lock(); stm32_cancelrequests(privep); /* Disable TX; disable RX */ @@ -2979,7 +2993,8 @@ static int stm32_epdisable(struct usbdev_ep_s *ep) stm32_seteprxstatus(epno, USB_EPR_STATRX_DIS); stm32_seteptxstatus(epno, USB_EPR_STATTX_DIS); - leave_critical_section(flags); + spin_unlock_irqrestore(&privep->dev->lock, flags); + sched_unlock(); return OK; } @@ -3072,7 +3087,8 @@ static int stm32_epsubmit(struct usbdev_ep_s *ep, struct usbdev_req_s *req) epno = USB_EPNO(ep->eplog); 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 */ @@ -3145,7 +3161,8 @@ static int stm32_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; } @@ -3167,9 +3184,11 @@ static int stm32_epcancel(struct usbdev_ep_s *ep, struct usbdev_req_s *req) #endif usbtrace(TRACE_EPCANCEL, USB_EPNO(ep->eplog)); - flags = enter_critical_section(); + flags = spin_lock_irqsave(&privep->dev->lock); + sched_lock(); stm32_cancelrequests(privep); - leave_critical_section(flags); + spin_unlock_irqrestore(&privep->dev->lock, flags); + sched_unlock(); return OK; } @@ -3199,7 +3218,8 @@ static int stm32_epstall(struct usbdev_ep_s *ep, bool resume) /* STALL or RESUME the endpoint */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); + sched_lock(); usbtrace(resume ? TRACE_EPRESUME : TRACE_EPSTALL, USB_EPNO(ep->eplog)); /* Get status of the endpoint; stall the request if the endpoint is @@ -3224,7 +3244,8 @@ static int stm32_epstall(struct usbdev_ep_s *ep, bool resume) priv->ep0state = EP0STATE_STALLED; } - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); + sched_unlock(); return -ENODEV; } @@ -3310,7 +3331,8 @@ static int stm32_epstall(struct usbdev_ep_s *ep, bool resume) } } - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); + sched_unlock(); return OK; } @@ -3474,7 +3496,8 @@ static int stm32_wakeup(struct usbdev_s *dev) * by the ESOF interrupt. */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); + sched_lock(); stm32_initresume(priv); priv->rsmstate = RSMSTATE_STARTED; @@ -3486,7 +3509,8 @@ static int stm32_wakeup(struct usbdev_s *dev) stm32_setimask(priv, USB_CNTR_ESOFM, USB_CNTR_WKUPM | USB_CNTR_SUSPM); stm32_putreg(~USB_ISTR_ESOF, STM32_USB_ISTR); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); + sched_unlock(); return OK; } @@ -3748,6 +3772,10 @@ void arm_usbinitialize(void) usbtrace(TRACE_DEVINIT, 0); stm32_checksetup(); + /* Initialize driver lock */ + + spin_lock_init(&priv->lock); + /* Configure USB GPIO alternate function pins */ #ifdef CONFIG_STM32_STM32F30XX @@ -3823,7 +3851,8 @@ void arm_usbuninitialize(void) struct stm32_usbdev_s *priv = &g_usbdev; irqstate_t flags; - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); + sched_lock(); usbtrace(TRACE_DEVUNINIT, 0); /* Disable and detach the USB IRQs */ @@ -3842,7 +3871,8 @@ void arm_usbuninitialize(void) /* Put the hardware in an inactive state */ stm32_hwshutdown(priv); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); + sched_unlock(); } /**************************************************************************** @@ -3951,7 +3981,8 @@ int usbdev_unregister(struct usbdevclass_driver_s *driver) * canceled while the class driver is still bound. */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); + sched_lock(); stm32_reset(priv); /* Unbind the class driver */ @@ -3974,7 +4005,8 @@ int usbdev_unregister(struct usbdevclass_driver_s *driver) /* Unhook the driver */ priv->driver = NULL; - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); + sched_unlock(); return OK; } diff --git a/arch/arm/src/stm32f0l0g0/stm32_usbdev.c b/arch/arm/src/stm32f0l0g0/stm32_usbdev.c index 9c84c9371e39b..8283347a5d95f 100644 --- a/arch/arm/src/stm32f0l0g0/stm32_usbdev.c +++ b/arch/arm/src/stm32f0l0g0/stm32_usbdev.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -48,6 +49,7 @@ #include #include +#include #include "arm_internal.h" #include "hardware/stm32_rcc.h" @@ -342,6 +344,10 @@ struct stm32_usbdev_s /* The endpoint list */ struct stm32_ep_s eplist[STM32_NENDPOINTS]; + + /* Spinlock */ + + spinlock_t lock; }; /**************************************************************************** @@ -479,6 +485,8 @@ static void stm32_hwreset(struct stm32_usbdev_s *priv); static void stm32_hwsetup(struct stm32_usbdev_s *priv); static void stm32_hwshutdown(struct stm32_usbdev_s *priv); +static int usbdev_unregister_nolock(struct usbdevclass_driver_s *driver); + /**************************************************************************** * Private Data ****************************************************************************/ @@ -1161,16 +1169,14 @@ stm32_abortrequest(struct stm32_ep_s *privep, * Name: stm32_reqcomplete ****************************************************************************/ -static void stm32_reqcomplete(struct stm32_ep_s *privep, int16_t result) +static void stm32_reqcomplete_nolock(struct stm32_ep_s *privep, + int16_t result) { struct stm32_req_s *privreq; - irqstate_t flags; /* Remove the completed request at the head of the endpoint request list */ - flags = enter_critical_section(); privreq = stm32_rqdequeue(privep); - leave_critical_section(flags); if (privreq) { @@ -1199,6 +1205,15 @@ static void stm32_reqcomplete(struct stm32_ep_s *privep, int16_t result) } } +static void stm32_reqcomplete(struct stm32_ep_s *privep, int16_t result) +{ + irqstate_t flags = spin_lock_irqsave(&privep->dev->lock); + + stm32_reqcomplete_nolock(privep, result); + + spin_unlock_irqrestore(&privep->dev->lock, flags); +} + /**************************************************************************** * Name: tm32_epwrite ****************************************************************************/ @@ -2669,7 +2684,7 @@ stm32_epreserve(struct stm32_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) { @@ -2694,7 +2709,7 @@ stm32_epreserve(struct stm32_usbdev_s *priv, uint8_t epset) } } - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); return privep; } @@ -2705,9 +2720,9 @@ stm32_epreserve(struct stm32_usbdev_s *priv, uint8_t epset) static inline void stm32_epunreserve(struct stm32_usbdev_s *priv, struct stm32_ep_s *privep) { - irqstate_t flags = enter_critical_section(); + irqstate_t flags = spin_lock_irqsave(&priv->lock); priv->epavail |= STM32_ENDP_BIT(USB_EPNO(privep->ep.eplog)); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); } /**************************************************************************** @@ -2730,7 +2745,7 @@ static int stm32_epallocpma(struct stm32_usbdev_s *priv) int bufno = ERROR; int bufndx; - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); for (bufndx = 2; bufndx < STM32_NBUFFERS; bufndx++) { /* Check if this buffer is available */ @@ -2749,7 +2764,7 @@ static int stm32_epallocpma(struct stm32_usbdev_s *priv) } } - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); return bufno; } @@ -2760,9 +2775,9 @@ static int stm32_epallocpma(struct stm32_usbdev_s *priv) static inline void stm32_epfreepma(struct stm32_usbdev_s *priv, struct stm32_ep_s *privep) { - irqstate_t flags = enter_critical_section(); + irqstate_t flags = spin_lock_irqsave(&priv->lock); priv->epavail |= STM32_ENDP_BIT(privep->bufno); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); } /**************************************************************************** @@ -2894,7 +2909,8 @@ static int stm32_epdisable(struct usbdev_ep_s *ep) /* Cancel any ongoing activity */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(&privep->dev->lock); + sched_lock(); stm32_cancelrequests(privep); /* Disable TX; disable RX */ @@ -2903,7 +2919,8 @@ static int stm32_epdisable(struct usbdev_ep_s *ep) stm32_seteprxstatus(epno, USB_EPR_STATRX_DIS); stm32_seteptxstatus(epno, USB_EPR_STATTX_DIS); - leave_critical_section(flags); + spin_unlock_irqrestore(&privep->dev->lock, flags); + sched_unlock(); return OK; } @@ -2997,7 +3014,8 @@ static int stm32_epsubmit(struct usbdev_ep_s *ep, epno = USB_EPNO(ep->eplog); 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 */ @@ -3072,7 +3090,8 @@ static int stm32_epsubmit(struct usbdev_ep_s *ep, } } - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); + sched_unlock(); return ret; } @@ -3095,9 +3114,11 @@ static int stm32_epcancel(struct usbdev_ep_s *ep, #endif usbtrace(TRACE_EPCANCEL, USB_EPNO(ep->eplog)); - flags = enter_critical_section(); + flags = spin_lock_irqsave(&privep->dev->lock); + sched_lock(); stm32_cancelrequests(privep); - leave_critical_section(flags); + spin_unlock_irqrestore(&privep->dev->lock, flags); + sched_unlock(); return OK; } @@ -3127,7 +3148,8 @@ static int stm32_epstall(struct usbdev_ep_s *ep, bool resume) /* STALL or RESUME the endpoint */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); + sched_lock(); usbtrace(resume ? TRACE_EPRESUME : TRACE_EPSTALL, USB_EPNO(ep->eplog)); /* Get status of the endpoint; stall the request if the endpoint is @@ -3152,7 +3174,8 @@ static int stm32_epstall(struct usbdev_ep_s *ep, bool resume) priv->ep0state = EP0STATE_STALLED; } - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); + sched_unlock(); return -ENODEV; } @@ -3238,7 +3261,8 @@ static int stm32_epstall(struct usbdev_ep_s *ep, bool resume) } } - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); + sched_unlock(); return OK; } @@ -3403,7 +3427,7 @@ static int stm32_wakeup(struct usbdev_s *dev) * by the ESOF interrupt. */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); stm32_initresume(priv); priv->rsmstate = RSMSTATE_STARTED; @@ -3415,7 +3439,7 @@ static int stm32_wakeup(struct usbdev_s *dev) stm32_setimask(priv, USB_CNTR_ESOFM, USB_CNTR_WKUPM | USB_CNTR_SUSPM); stm32_putreg(~USB_ISTR_ESOF, STM32_USB_ISTR); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); return OK; } @@ -3677,6 +3701,10 @@ void arm_usbinitialize(void) usbtrace(TRACE_DEVINIT, 0); + /* Initialize driver lock */ + + spin_lock_init(&priv->lock); + /* Configure USB GPIO alternate function pins */ stm32_configgpio(GPIO_USB_DM); @@ -3733,7 +3761,8 @@ void arm_usbuninitialize(void) struct stm32_usbdev_s *priv = &g_usbdev; irqstate_t flags; - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); + sched_lock(); usbtrace(TRACE_DEVUNINIT, 0); /* Disable and detach the USB IRQs */ @@ -3744,13 +3773,14 @@ void arm_usbuninitialize(void) if (priv->driver) { usbtrace(TRACE_DEVERROR(STM32_TRACEERR_DRIVERREGISTERED), 0); - usbdev_unregister(priv->driver); + usbdev_unregister_nolock(priv->driver); } /* Put the hardware in an inactive state */ stm32_hwshutdown(priv); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); + sched_unlock(); } /**************************************************************************** @@ -3835,7 +3865,7 @@ int usbdev_register(struct usbdevclass_driver_s *driver) * ****************************************************************************/ -int usbdev_unregister(struct usbdevclass_driver_s *driver) +static int usbdev_unregister_nolock(struct usbdevclass_driver_s *driver) { /* For now there is only one USB controller, but we will always refer to * it using a pointer to make any future ports to multiple USB controllers @@ -3843,7 +3873,6 @@ int usbdev_unregister(struct usbdevclass_driver_s *driver) */ struct stm32_usbdev_s *priv = &g_usbdev; - irqstate_t flags; usbtrace(TRACE_DEVUNREGISTER, 0); @@ -3859,7 +3888,6 @@ int usbdev_unregister(struct usbdevclass_driver_s *driver) * canceled while the class driver is still bound. */ - flags = enter_critical_section(); stm32_reset(priv); /* Unbind the class driver */ @@ -3881,8 +3909,20 @@ int usbdev_unregister(struct usbdevclass_driver_s *driver) /* Unhook the driver */ priv->driver = NULL; - leave_critical_section(flags); return OK; } +int usbdev_unregister(struct usbdevclass_driver_s *driver) +{ + int ret; + + irqstate_t flags = spin_lock_irqsave(&g_usbdev.lock); + sched_lock(); + ret = usbdev_unregister_nolock(driver); + spin_unlock_irqrestore(&g_usbdev.lock, flags); + sched_unlock(); + + return ret; +} + #endif /* CONFIG_USBDEV && CONFIG_STM32F0L0G0_USB */ diff --git a/arch/arm/src/stm32l4/stm32l4_usbdev.c b/arch/arm/src/stm32l4/stm32l4_usbdev.c index 03776e2ba58ec..b80a5d4d9908a 100644 --- a/arch/arm/src/stm32l4/stm32l4_usbdev.c +++ b/arch/arm/src/stm32l4/stm32l4_usbdev.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -43,6 +44,7 @@ #include #include +#include #include "arm_internal.h" #include "stm32l4.h" @@ -342,7 +344,11 @@ struct stm32l4_usbdev_s /* The endpoint list */ - struct stm32l4_ep_s eplist[STM32L4_NENDPOINTS]; + struct stm32l4_ep_s eplist[STM32L4_NENDPOINTS]; + + /* Spinlock */ + + spinlock_t lock; }; /**************************************************************************** @@ -1215,16 +1221,14 @@ stm32l4_abortrequest(struct stm32l4_ep_s *privep, * Name: stm32l4_reqcomplete ****************************************************************************/ -static void stm32l4_reqcomplete(struct stm32l4_ep_s *privep, int16_t result) +static void stm32l4_reqcomplete_nolock(struct stm32l4_ep_s *privep, + int16_t result) { struct stm32l4_req_s *privreq; - irqstate_t flags; /* Remove the completed request at the head of the endpoint request list */ - flags = enter_critical_section(); privreq = stm32l4_rqdequeue(privep); - leave_critical_section(flags); if (privreq) { @@ -1253,6 +1257,15 @@ static void stm32l4_reqcomplete(struct stm32l4_ep_s *privep, int16_t result) } } +static void stm32l4_reqcomplete(struct stm32l4_ep_s *privep, int16_t result) +{ + flags = spin_lock_irqsave(&privep->dev->lock); + + stm32l4_reqcomplete_nolock(privep, result); + + spin_unlock_irqrestore(&privep->dev->lock, flags); +} + /**************************************************************************** * Name: tm32_epwrite ****************************************************************************/ @@ -1539,7 +1552,7 @@ static void stm32l4_cancelrequests(struct stm32l4_ep_s *privep) { usbtrace(TRACE_COMPLETE(USB_EPNO(privep->ep.eplog)), (stm32l4_rqpeek(privep))->req.xfrd); - stm32l4_reqcomplete(privep, -ESHUTDOWN); + stm32l4_reqcomplete_nolock(privep, -ESHUTDOWN); } } @@ -2702,7 +2715,7 @@ stm32l4_epreserve(struct stm32l4_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) { @@ -2727,7 +2740,7 @@ stm32l4_epreserve(struct stm32l4_usbdev_s *priv, uint8_t epset) } } - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); return privep; } @@ -2739,9 +2752,9 @@ static inline void stm32l4_epunreserve(struct stm32l4_usbdev_s *priv, struct stm32l4_ep_s *privep) { - irqstate_t flags = enter_critical_section(); + irqstate_t flags = spin_lock_irqsave(&priv->lock); priv->epavail |= STM32L4_ENDP_BIT(USB_EPNO(privep->ep.eplog)); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); } /**************************************************************************** @@ -2764,7 +2777,7 @@ static int stm32l4_epallocpma(struct stm32l4_usbdev_s *priv) int bufno = ERROR; int bufndx; - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); for (bufndx = 2; bufndx < STM32L4_NBUFFERS; bufndx++) { /* Check if this buffer is available */ @@ -2783,7 +2796,7 @@ static int stm32l4_epallocpma(struct stm32l4_usbdev_s *priv) } } - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); return bufno; } @@ -2794,9 +2807,9 @@ static int stm32l4_epallocpma(struct stm32l4_usbdev_s *priv) static inline void stm32l4_epfreepma(struct stm32l4_usbdev_s *priv, struct stm32l4_ep_s *privep) { - irqstate_t flags = enter_critical_section(); + irqstate_t flags = spin_lock_irqsave(&priv->lock); priv->epavail |= STM32L4_ENDP_BIT(privep->bufno); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); } /**************************************************************************** @@ -2928,7 +2941,8 @@ static int stm32l4_epdisable(struct usbdev_ep_s *ep) /* Cancel any ongoing activity */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(&privep->dev->lock); + sched_lock(); stm32l4_cancelrequests(privep); /* Disable TX; disable RX */ @@ -2937,7 +2951,8 @@ static int stm32l4_epdisable(struct usbdev_ep_s *ep) stm32l4_seteprxstatus(epno, USB_EPR_STATRX_DIS); stm32l4_seteptxstatus(epno, USB_EPR_STATTX_DIS); - leave_critical_section(flags); + spin_unlock_irqrestore(&privep->dev->lock, flags); + sched_unlock(); return OK; } @@ -3033,7 +3048,8 @@ static int stm32l4_epsubmit(struct usbdev_ep_s *ep, struct usbdev_req_s *req) epno = USB_EPNO(ep->eplog); 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 */ @@ -3106,7 +3122,8 @@ static int stm32l4_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; } @@ -3129,9 +3146,11 @@ static int stm32l4_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(); stm32l4_cancelrequests(privep); - leave_critical_section(flags); + spin_unlock_irqrestore(&privep->dev->lock, flags); + sched_unlock(); return OK; } @@ -3161,7 +3180,8 @@ static int stm32l4_epstall(struct usbdev_ep_s *ep, bool resume) /* STALL or RESUME the endpoint */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); + sched_lock(); usbtrace(resume ? TRACE_EPRESUME : TRACE_EPSTALL, USB_EPNO(ep->eplog)); /* Get status of the endpoint; stall the request if the endpoint is @@ -3186,7 +3206,8 @@ static int stm32l4_epstall(struct usbdev_ep_s *ep, bool resume) priv->ep0state = EP0STATE_STALLED; } - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); + sched_unlock(); return -ENODEV; } @@ -3272,7 +3293,8 @@ static int stm32l4_epstall(struct usbdev_ep_s *ep, bool resume) } } - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); + sched_unlock(); return OK; } @@ -3438,7 +3460,8 @@ static int stm32l4_wakeup(struct usbdev_s *dev) * by the ESOF interrupt. */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); + sched_lock(); stm32l4_initresume(priv); priv->rsmstate = RSMSTATE_STARTED; @@ -3450,7 +3473,8 @@ static int stm32l4_wakeup(struct usbdev_s *dev) stm32l4_setimask(priv, USB_CNTR_ESOFM, USB_CNTR_WKUPM | USB_CNTR_SUSPM); stm32l4_putreg(~USB_ISTR_ESOF, STM32L4_USB_ISTR); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); + sched_unlock(); return OK; } @@ -3482,12 +3506,13 @@ static int stm32l4_selfpowered(struct usbdev_s *dev, bool selfpowered) static int stm32l4_pullup(struct usbdev_s *dev, bool enable) { + struct stm32l4_usbdev_s *priv = (struct stm32l4_usbdev_s *)dev; uint32_t regval; irqstate_t flags; usbtrace(TRACE_DEVPULLUP, (uint16_t)enable); - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); regval = stm32l4_getreg(STM32L4_USB_BCDR); if (enable) { @@ -3507,7 +3532,7 @@ static int stm32l4_pullup(struct usbdev_s *dev, bool enable) } stm32l4_putreg(regval, STM32L4_USB_BCDR); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); return OK; } @@ -3743,6 +3768,10 @@ void arm_usbinitialize(void) usbtrace(TRACE_DEVINIT, 0); stm32l4_checksetup(); + /* Initialize driver lock */ + + spin_lock_init(&priv->lock); + /* Enable Vbus monitoring in the Power control */ stm32l4_pwr_enableusv(true); @@ -3782,7 +3811,8 @@ void arm_usbuninitialize(void) struct stm32l4_usbdev_s *priv = &g_usbdev; irqstate_t flags; - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); + sched_lock(); usbtrace(TRACE_DEVUNINIT, 0); /* Disable and detach the USB IRQ */ @@ -3804,7 +3834,8 @@ void arm_usbuninitialize(void) stm32l4_pwr_enableusv(false); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); + sched_unlock(); } /**************************************************************************** @@ -3912,7 +3943,8 @@ int usbdev_unregister(struct usbdevclass_driver_s *driver) * canceled while the class driver is still bound. */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->lock); + sched_lock(); stm32l4_reset(priv); /* Unbind the class driver */ @@ -3934,7 +3966,8 @@ int usbdev_unregister(struct usbdevclass_driver_s *driver) /* Unhook the driver */ priv->driver = NULL; - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->lock, flags); + sched_unlock(); return OK; }