Skip to content

Commit

Permalink
risc-v/mpfs: usb: fix fierce cpu polling if remote closes
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
eenurkka authored and jnippula committed Mar 13, 2024
1 parent 2a029b0 commit 824f4b7
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 8 deletions.
1 change: 1 addition & 0 deletions arch/risc-v/src/mpfs/hardware/mpfs_usb.h
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,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 */
Expand Down
68 changes: 60 additions & 8 deletions arch/risc-v/src/mpfs/mpfs_usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,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)
Expand Down Expand Up @@ -229,6 +231,7 @@ static void mpfs_epset_reset(struct mpfs_usbdev_s *priv, uint16_t epset);

static struct mpfs_usbdev_s g_usbd;
static uint8_t g_clkrefs;
static bool g_linkdead;

static const struct usbdev_epops_s g_epops =
{
Expand Down Expand Up @@ -772,11 +775,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)
Expand All @@ -797,11 +815,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;
}
}

Expand Down Expand Up @@ -2444,6 +2477,8 @@ static void mpfs_reset(struct mpfs_usbdev_s *priv)

mpfs_req_cancel(privep, -ESHUTDOWN);

privep->linkdead = 0;

/* Reset endpoint status */

privep->stalled = false;
Expand Down Expand Up @@ -3456,11 +3491,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)
Expand Down

0 comments on commit 824f4b7

Please sign in to comment.