mirror of
https://github.com/apache/nuttx.git
synced 2026-08-04 13:49:06 +00:00
arch/mpfs/mpfs_usb.c: Replace big kernel lock with spin lock
Remove call to enter_critical_section (big kernel lock) and replace it with a smaller lock to protect the USB clock and its reference counter. Signed-off-by: Ville Juven <ville.juven@unikie.com>
This commit is contained in:
parent
4c7fedebd1
commit
04df2ccead
2 changed files with 44 additions and 48 deletions
|
|
@ -409,6 +409,7 @@ union wb_u
|
|||
|
||||
struct mpfs_rqhead_s
|
||||
{
|
||||
spinlock_t qlock; /* Lock to protect access to the queue */
|
||||
struct mpfs_req_s *head; /* Requests are added to the head of the list */
|
||||
struct mpfs_req_s *tail; /* Requests are removed from the tail of the list */
|
||||
};
|
||||
|
|
@ -417,6 +418,7 @@ struct mpfs_ep_s
|
|||
{
|
||||
struct usbdev_ep_s ep; /* Standard endpoint structure */
|
||||
|
||||
spinlock_t eplock; /* Lock for endpoint access */
|
||||
struct mpfs_usbdev_s *dev; /* Reference to private driver data */
|
||||
struct mpfs_rqhead_s reqq; /* Read/write request queue */
|
||||
struct mpfs_rqhead_s pendq; /* Write requests pending stall sent */
|
||||
|
|
@ -447,6 +449,10 @@ struct mpfs_usbdev_s
|
|||
|
||||
struct usbdevclass_driver_s *driver;
|
||||
|
||||
/* Device specific fields */
|
||||
|
||||
spinlock_t lock; /* Device lock */
|
||||
|
||||
/* USB-specific fields */
|
||||
|
||||
struct usb_ctrlreq_s ctrl; /* Last EP0 request */
|
||||
|
|
|
|||
|
|
@ -226,11 +226,12 @@ static void mpfs_epset_reset(struct mpfs_usbdev_s *priv, uint16_t epset);
|
|||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static spinlock_t g_mpfs_modifyreg_lock = SP_UNLOCKED;
|
||||
|
||||
static struct mpfs_usbdev_s g_usbd;
|
||||
static uint8_t g_clkrefs;
|
||||
static bool g_linkdead;
|
||||
|
||||
static spinlock_t g_mpfs_modifyreg_lock = SP_UNLOCKED;
|
||||
static spinlock_t g_clklock = SP_UNLOCKED;
|
||||
static uint8_t g_clkrefs;
|
||||
static bool g_linkdead;
|
||||
|
||||
static const struct usbdev_epops_s g_epops =
|
||||
{
|
||||
|
|
@ -438,7 +439,7 @@ static void mpfs_enableclk(void)
|
|||
{
|
||||
/* Handle the counter atomically */
|
||||
|
||||
irqstate_t flags = enter_critical_section();
|
||||
irqstate_t flags = spin_lock_irqsave(&g_clklock);
|
||||
|
||||
if (g_clkrefs == 0)
|
||||
{
|
||||
|
|
@ -447,7 +448,7 @@ static void mpfs_enableclk(void)
|
|||
}
|
||||
|
||||
g_clkrefs++;
|
||||
leave_critical_section(flags);
|
||||
spin_unlock_irqrestore(&g_clklock, flags);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
|
@ -468,7 +469,7 @@ static void mpfs_disableclk(void)
|
|||
{
|
||||
/* Handle the counter atomically */
|
||||
|
||||
irqstate_t flags = enter_critical_section();
|
||||
irqstate_t flags = spin_lock_irqsave(&g_clklock);
|
||||
|
||||
g_clkrefs--;
|
||||
if (g_clkrefs == 0)
|
||||
|
|
@ -477,7 +478,7 @@ static void mpfs_disableclk(void)
|
|||
0);
|
||||
}
|
||||
|
||||
leave_critical_section(flags);
|
||||
spin_unlock_irqrestore(&g_clklock, flags);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
|
@ -500,6 +501,7 @@ static void mpfs_disableclk(void)
|
|||
|
||||
static struct mpfs_req_s *mpfs_req_dequeue(struct mpfs_rqhead_s *queue)
|
||||
{
|
||||
irqstate_t flags = spin_lock_irqsave(&queue->qlock);
|
||||
struct mpfs_req_s *ret = queue->head;
|
||||
|
||||
if (ret != NULL)
|
||||
|
|
@ -513,6 +515,7 @@ static struct mpfs_req_s *mpfs_req_dequeue(struct mpfs_rqhead_s *queue)
|
|||
ret->flink = NULL;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&queue->qlock, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -534,6 +537,8 @@ static struct mpfs_req_s *mpfs_req_dequeue(struct mpfs_rqhead_s *queue)
|
|||
static void mpfs_req_enqueue(struct mpfs_rqhead_s *queue,
|
||||
struct mpfs_req_s *req)
|
||||
{
|
||||
irqstate_t flags = spin_lock_irqsave(&queue->qlock);
|
||||
|
||||
req->flink = NULL;
|
||||
|
||||
if (queue->head == NULL)
|
||||
|
|
@ -546,6 +551,8 @@ static void mpfs_req_enqueue(struct mpfs_rqhead_s *queue,
|
|||
queue->tail->flink = req;
|
||||
queue->tail = req;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&queue->qlock, flags);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
|
@ -566,14 +573,10 @@ static void mpfs_req_enqueue(struct mpfs_rqhead_s *queue,
|
|||
static void mpfs_req_complete(struct mpfs_ep_s *privep, int16_t result)
|
||||
{
|
||||
struct mpfs_req_s *privreq;
|
||||
irqstate_t flags;
|
||||
|
||||
/* Remove the completed request at the head of the endpoint request list */
|
||||
|
||||
flags = enter_critical_section();
|
||||
privreq = mpfs_req_dequeue(&privep->reqq);
|
||||
leave_critical_section(flags);
|
||||
|
||||
if (privreq)
|
||||
{
|
||||
/* Save the result in the request structure */
|
||||
|
|
@ -886,7 +889,7 @@ static int mpfs_ep_stall(struct mpfs_ep_s *privep)
|
|||
|
||||
/* Check that endpoint is enabled and not already in Halt state */
|
||||
|
||||
flags = enter_critical_section();
|
||||
flags = spin_lock_irqsave(&privep->eplock);
|
||||
if ((privep->epstate != USB_EPSTATE_DISABLED) &&
|
||||
(privep->epstate != USB_EPSTATE_STALLED))
|
||||
{
|
||||
|
|
@ -932,7 +935,7 @@ static int mpfs_ep_stall(struct mpfs_ep_s *privep)
|
|||
}
|
||||
}
|
||||
|
||||
leave_critical_section(flags);
|
||||
spin_unlock_irqrestore(&privep->eplock, flags);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
|
@ -989,10 +992,6 @@ static int mpfs_req_write(struct mpfs_usbdev_s *priv,
|
|||
return -ENOENT;
|
||||
}
|
||||
|
||||
uinfo("epno=%d req=%p: len=%zu xfrd=%zu inflight=%d\n",
|
||||
epno, privreq, privreq->req.len, privreq->req.xfrd,
|
||||
privreq->inflight);
|
||||
|
||||
/* Handle any bytes in flight. */
|
||||
|
||||
privreq->req.xfrd += privreq->inflight;
|
||||
|
|
@ -1168,9 +1167,6 @@ static int mpfs_req_read(struct mpfs_usbdev_s *priv,
|
|||
return OK;
|
||||
}
|
||||
|
||||
uinfo("EP%d: req.len=%zu xfrd=%zu recvsize=%d\n",
|
||||
epno, privreq->req.len, privreq->req.xfrd, recvsize);
|
||||
|
||||
/* Ignore any attempt to receive a zero length packet */
|
||||
|
||||
if (privreq->req.len == 0)
|
||||
|
|
@ -1619,8 +1615,6 @@ static void mpfs_ep_reset(struct mpfs_usbdev_s *priv, uint8_t epno)
|
|||
|
||||
static void mpfs_setdevaddr(struct mpfs_usbdev_s *priv, uint8_t address)
|
||||
{
|
||||
uinfo("ENTRY address=0x%x\n", address);
|
||||
|
||||
DEBUGASSERT(address <= 0x7f);
|
||||
|
||||
mpfs_putreg8(address, MPFS_USB_FADDR);
|
||||
|
|
@ -1662,14 +1656,14 @@ static int mpfs_ep_disable(struct usbdev_ep_s *ep)
|
|||
|
||||
/* Reset the endpoint and cancel any ongoing activity */
|
||||
|
||||
flags = enter_critical_section();
|
||||
flags = spin_lock_irqsave(&privep->eplock);
|
||||
priv = privep->dev;
|
||||
mpfs_ep_reset(priv, epno);
|
||||
|
||||
/* Revert to the addressed-but-not-configured state */
|
||||
|
||||
mpfs_setdevaddr(priv, priv->devaddr);
|
||||
leave_critical_section(flags);
|
||||
spin_unlock_irqrestore(&privep->eplock, flags);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
|
@ -1815,7 +1809,7 @@ static int mpfs_ep_submit(struct usbdev_ep_s *ep, struct usbdev_req_s *req)
|
|||
req->xfrd = 0;
|
||||
privreq->inflight = 0;
|
||||
|
||||
flags = enter_critical_section();
|
||||
flags = spin_lock_irqsave(&privep->eplock);
|
||||
|
||||
/* 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
|
||||
|
|
@ -1884,7 +1878,7 @@ static int mpfs_ep_submit(struct usbdev_ep_s *ep, struct usbdev_req_s *req)
|
|||
}
|
||||
}
|
||||
|
||||
leave_critical_section(flags);
|
||||
spin_unlock_irqrestore(&privep->eplock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -1907,13 +1901,9 @@ static int mpfs_ep_submit(struct usbdev_ep_s *ep, struct usbdev_req_s *req)
|
|||
static int mpfs_ep_cancel(struct usbdev_ep_s *ep, struct usbdev_req_s *req)
|
||||
{
|
||||
struct mpfs_ep_s *privep = (struct mpfs_ep_s *)ep;
|
||||
irqstate_t flags;
|
||||
|
||||
usbtrace(TRACE_EPCANCEL, USB_EPNO(ep->eplog));
|
||||
|
||||
flags = enter_critical_section();
|
||||
mpfs_req_cancel(privep, -EAGAIN);
|
||||
leave_critical_section(flags);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
|
@ -1945,7 +1935,7 @@ static int mpfs_ep_resume(struct mpfs_ep_s *privep)
|
|||
|
||||
usbtrace(TRACE_EPRESUME, USB_EPNO(privep->ep.eplog));
|
||||
|
||||
flags = enter_critical_section();
|
||||
flags = spin_lock_irqsave(&privep->eplock);
|
||||
|
||||
/* Check if the endpoint is stalled */
|
||||
|
||||
|
|
@ -2008,7 +1998,7 @@ static int mpfs_ep_resume(struct mpfs_ep_s *privep)
|
|||
}
|
||||
}
|
||||
|
||||
leave_critical_section(flags);
|
||||
spin_unlock_irqrestore(&privep->eplock, flags);
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
|
@ -2052,7 +2042,7 @@ static int mpfs_ep_stallresume(struct usbdev_ep_s *ep, bool resume)
|
|||
* requests before sending the stall.
|
||||
*/
|
||||
|
||||
flags = enter_critical_section();
|
||||
flags = spin_lock_irqsave(&privep->eplock);
|
||||
epno = USB_EPNO(ep->eplog);
|
||||
if (epno != 0 && USB_ISEPIN(ep->eplog))
|
||||
{
|
||||
|
|
@ -2068,7 +2058,7 @@ static int mpfs_ep_stallresume(struct usbdev_ep_s *ep, bool resume)
|
|||
*/
|
||||
|
||||
privep->pending = true;
|
||||
leave_critical_section(flags);
|
||||
spin_unlock_irqrestore(&privep->eplock, flags);
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
|
|
@ -2077,8 +2067,8 @@ static int mpfs_ep_stallresume(struct usbdev_ep_s *ep, bool resume)
|
|||
* Stall the endpoint now.
|
||||
*/
|
||||
|
||||
spin_unlock_irqrestore(&privep->eplock, flags);
|
||||
ret = mpfs_ep_stall(privep);
|
||||
leave_critical_section(flags);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
@ -2111,7 +2101,7 @@ mpfs_ep_reserve(struct mpfs_usbdev_s *priv, uint16_t epset, bool in)
|
|||
irqstate_t flags;
|
||||
int epndx = 0;
|
||||
|
||||
flags = enter_critical_section();
|
||||
flags = spin_lock_irqsave(&priv->lock);
|
||||
epset &= priv->epavail;
|
||||
|
||||
if (epset != 0)
|
||||
|
|
@ -2159,7 +2149,7 @@ mpfs_ep_reserve(struct mpfs_usbdev_s *priv, uint16_t epset, bool in)
|
|||
|
||||
DEBUGASSERT(privep != NULL);
|
||||
|
||||
leave_critical_section(flags);
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
return privep;
|
||||
}
|
||||
|
||||
|
|
@ -2249,9 +2239,9 @@ static struct usbdev_ep_s *mpfs_allocep(struct usbdev_s *dev, uint8_t epno,
|
|||
static inline void
|
||||
mpfs_ep_unreserve(struct mpfs_usbdev_s *priv, struct mpfs_ep_s *privep)
|
||||
{
|
||||
irqstate_t flags = enter_critical_section();
|
||||
irqstate_t flags = spin_lock_irqsave(&priv->lock);
|
||||
priv->epavail |= MPFS_EP_BIT(USB_EPNO(privep->ep.eplog));
|
||||
leave_critical_section(flags);
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
|
@ -2383,13 +2373,13 @@ static int mpfs_wakeup(struct usbdev_s *dev)
|
|||
|
||||
/* Resume normal operation */
|
||||
|
||||
flags = enter_critical_section();
|
||||
flags = spin_lock_irqsave(&priv->lock);
|
||||
|
||||
mpfs_resume(priv);
|
||||
|
||||
/* Device is always self-powered. Remote wakeup is not supported */
|
||||
|
||||
leave_critical_section(flags);
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
|
@ -3977,15 +3967,15 @@ int usbdev_unregister(struct usbdevclass_driver_s *driver)
|
|||
struct mpfs_usbdev_s *priv = &g_usbd;
|
||||
irqstate_t flags;
|
||||
|
||||
/* Unbind the class driver */
|
||||
|
||||
CLASS_UNBIND(driver, &priv->usbdev);
|
||||
|
||||
/* Reset the hardware and cancel all requests. All requests must be
|
||||
* canceled while the class driver is still bound.
|
||||
*/
|
||||
|
||||
flags = enter_critical_section();
|
||||
|
||||
/* Unbind the class driver */
|
||||
|
||||
CLASS_UNBIND(driver, &priv->usbdev);
|
||||
flags = spin_lock_irqsave(&priv->lock);
|
||||
|
||||
mpfs_hw_shutdown(priv);
|
||||
mpfs_sw_shutdown(priv);
|
||||
|
|
@ -3993,7 +3983,7 @@ int usbdev_unregister(struct usbdevclass_driver_s *driver)
|
|||
/* Unhook the driver */
|
||||
|
||||
priv->driver = NULL;
|
||||
leave_critical_section(flags);
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue