mirror of
https://github.com/apache/nuttx.git
synced 2026-10-09 23:35:47 +00:00
risc-v/mpfs: usb: fix fierce cpu polling if remote closes
If the remote end just closes an endpoint and no longer handles it, the system is prone to intensive cpu polling via mpfs_write_tx_fifo() especially if the device side doesn't know a thing about what the remote did. Fix this by marking the EP as dead, which will skip all writes causing unnecessary polling. The EP is back in business if the remote end sends some data (rx) or the connection is re-established. Signed-off-by: Eero Nurkkala <eero.nurkkala@offcode.fi> Signed-off-by: Ville Juven <ville.juven@unikie.com>
This commit is contained in:
parent
19a8e2403f
commit
95163f504c
2 changed files with 61 additions and 8 deletions
|
|
@ -421,6 +421,7 @@ struct mpfs_ep_s
|
|||
struct mpfs_rqhead_s reqq; /* Read/write request queue */
|
||||
struct mpfs_rqhead_s pendq; /* Write requests pending stall sent */
|
||||
struct usbdev_epdesc_s *descb[2]; /* Pointers to this endpoint descriptors */
|
||||
uint32_t linkdead; /* Remote end has closed the connection */
|
||||
volatile uint8_t epstate; /* State of the endpoint (see enum mpfs_epstate_e) */
|
||||
uint8_t stalled:1; /* true: Endpoint is stalled */
|
||||
uint8_t pending:1; /* true: IN Endpoint stall is pending */
|
||||
|
|
|
|||
|
|
@ -130,6 +130,8 @@
|
|||
#define MPFS_MIN_EP_FIFO_SIZE 8
|
||||
#define MPFS_USB_REG_MAX 0x2000
|
||||
|
||||
#define LINKDEAD_THRESHOLD 20
|
||||
|
||||
/* Request queue operations *************************************************/
|
||||
|
||||
#define mpfs_rqempty(q) ((q)->head == NULL)
|
||||
|
|
@ -228,6 +230,7 @@ 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 const struct usbdev_epops_s g_epops =
|
||||
{
|
||||
|
|
@ -771,11 +774,26 @@ static int mpfs_req_wrsetup(struct mpfs_usbdev_s *priv,
|
|||
|
||||
if (nbytes > packetsize)
|
||||
{
|
||||
ret = mpfs_write_tx_fifo(buf, packetsize, epno);
|
||||
if (ret != OK)
|
||||
if (privep->linkdead < LINKDEAD_THRESHOLD)
|
||||
{
|
||||
privep->epstate = USB_EPSTATE_IDLE;
|
||||
return ret;
|
||||
ret = mpfs_write_tx_fifo(buf, packetsize, epno);
|
||||
if (ret != OK)
|
||||
{
|
||||
privep->linkdead++;
|
||||
privep->epstate = USB_EPSTATE_IDLE;
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
privep->linkdead = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We're in trouble, remote has likely closed */
|
||||
|
||||
g_linkdead = true;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (epno == EP0)
|
||||
|
|
@ -796,11 +814,26 @@ static int mpfs_req_wrsetup(struct mpfs_usbdev_s *priv,
|
|||
}
|
||||
else
|
||||
{
|
||||
ret = mpfs_write_tx_fifo(buf, nbytes, epno);
|
||||
if (ret != OK)
|
||||
if (privep->linkdead < LINKDEAD_THRESHOLD)
|
||||
{
|
||||
privep->epstate = USB_EPSTATE_IDLE;
|
||||
return ret;
|
||||
ret = mpfs_write_tx_fifo(buf, nbytes, epno);
|
||||
if (ret != OK)
|
||||
{
|
||||
privep->linkdead++;
|
||||
privep->epstate = USB_EPSTATE_IDLE;
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
privep->linkdead = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We're in trouble, remote has likely closed */
|
||||
|
||||
g_linkdead = true;
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2443,6 +2476,8 @@ static void mpfs_reset(struct mpfs_usbdev_s *priv)
|
|||
|
||||
mpfs_req_cancel(privep, -ESHUTDOWN);
|
||||
|
||||
privep->linkdead = 0;
|
||||
|
||||
/* Reset endpoint status */
|
||||
|
||||
privep->stalled = false;
|
||||
|
|
@ -3455,11 +3490,28 @@ static int mpfs_usb_interrupt(int irq, void *context, void *arg)
|
|||
{
|
||||
for (i = 0; i < MPFS_USB_NENDPOINTS; i++)
|
||||
{
|
||||
/* Check if dead connections are back in business */
|
||||
|
||||
if (g_linkdead)
|
||||
{
|
||||
/* This releases all, which is a problem if only some
|
||||
* endpoints are closed on the remote; whereas some
|
||||
* are functioning; for example ACM and mass storage;
|
||||
* now the functioning one likely marks the closed ones
|
||||
* as no longer dead.
|
||||
*/
|
||||
|
||||
struct mpfs_ep_s *privep = &priv->eplist[i];
|
||||
privep->linkdead = 0;
|
||||
}
|
||||
|
||||
if ((pending_rx_ep & (1 << i)) != 0)
|
||||
{
|
||||
mpfs_ep_rx_interrupt(priv, i);
|
||||
}
|
||||
}
|
||||
|
||||
g_linkdead = false;
|
||||
}
|
||||
|
||||
if ((isr & SUSPEND_IRQ_MASK) != 0)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue