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:
Ville Juven 2025-03-19 15:51:15 +02:00 committed by Xiang Xiao
parent 4c7fedebd1
commit 04df2ccead
2 changed files with 44 additions and 48 deletions

View file

@ -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 */

View file

@ -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;
}