Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

risc-v/mpfs: usb: fix fierce cpu polling if remote closes #224

Merged
merged 1 commit into from
Mar 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading