stm32: Disable usb irqs in usbotg handlers

It appears the usbotg controller can get confused if the usb irq
handler runs while processing a usb request.  Disable usb irqs during
usb processing to avoid this.

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
Kevin O'Connor 2019-09-11 09:51:56 -04:00
parent 361de30ad1
commit 60ae92d143
1 changed files with 56 additions and 17 deletions

View File

@ -14,6 +14,18 @@
#include "internal.h" // GPIO #include "internal.h" // GPIO
#include "sched.h" // DECL_INIT #include "sched.h" // DECL_INIT
static void
usb_irq_disable(void)
{
NVIC_DisableIRQ(OTG_FS_IRQn);
}
static void
usb_irq_enable(void)
{
NVIC_EnableIRQ(OTG_FS_IRQn);
}
/**************************************************************** /****************************************************************
* USB transfer memory * USB transfer memory
@ -64,6 +76,7 @@ fifo_write_packet(uint32_t ep, const uint8_t *src, uint32_t len)
{ {
void *fifo = EPFIFO(ep); void *fifo = EPFIFO(ep);
USB_OTG_INEndpointTypeDef *epi = EPIN(ep); USB_OTG_INEndpointTypeDef *epi = EPIN(ep);
epi->DIEPINT = USB_OTG_DIEPINT_XFRC;
epi->DIEPTSIZ = len | (1 << USB_OTG_DIEPTSIZ_PKTCNT_Pos); epi->DIEPTSIZ = len | (1 << USB_OTG_DIEPTSIZ_PKTCNT_Pos);
epi->DIEPCTL |= USB_OTG_DIEPCTL_EPENA | USB_OTG_DIEPCTL_CNAK; epi->DIEPCTL |= USB_OTG_DIEPCTL_EPENA | USB_OTG_DIEPCTL_CNAK;
int32_t count = len; int32_t count = len;
@ -153,53 +166,73 @@ peek_rx_queue(uint32_t ep)
int_fast8_t int_fast8_t
usb_read_bulk_out(void *data, uint_fast8_t max_len) usb_read_bulk_out(void *data, uint_fast8_t max_len)
{ {
usb_irq_disable();
uint32_t grx = peek_rx_queue(USB_CDC_EP_BULK_OUT); uint32_t grx = peek_rx_queue(USB_CDC_EP_BULK_OUT);
if (!grx) { if (!grx) {
// Wait for packet // Wait for packet
OTG->GINTMSK |= USB_OTG_GINTMSK_RXFLVLM; OTG->GINTMSK |= USB_OTG_GINTMSK_RXFLVLM;
usb_irq_enable();
return -1; return -1;
} }
return fifo_read_packet(data, max_len); int_fast8_t ret = fifo_read_packet(data, max_len);
usb_irq_enable();
return ret;
} }
int_fast8_t int_fast8_t
usb_send_bulk_in(void *data, uint_fast8_t len) usb_send_bulk_in(void *data, uint_fast8_t len)
{ {
usb_irq_disable();
uint32_t ctl = EPIN(USB_CDC_EP_BULK_IN)->DIEPCTL; uint32_t ctl = EPIN(USB_CDC_EP_BULK_IN)->DIEPCTL;
if (!(ctl & USB_OTG_DIEPCTL_USBAEP)) if (!(ctl & USB_OTG_DIEPCTL_USBAEP)) {
// Controller not enabled - discard data // Controller not enabled - discard data
usb_irq_enable();
return len; return len;
if (ctl & USB_OTG_DIEPCTL_EPENA) }
if (ctl & USB_OTG_DIEPCTL_EPENA) {
// Wait for space to transmit // Wait for space to transmit
OTGD->DAINTMSK |= 1 << USB_CDC_EP_BULK_IN;
usb_irq_enable();
return -1; return -1;
return fifo_write_packet(USB_CDC_EP_BULK_IN, data, len); }
int_fast8_t ret = fifo_write_packet(USB_CDC_EP_BULK_IN, data, len);
usb_irq_enable();
return ret;
} }
int_fast8_t int_fast8_t
usb_read_ep0(void *data, uint_fast8_t max_len) usb_read_ep0(void *data, uint_fast8_t max_len)
{ {
usb_irq_disable();
uint32_t grx = peek_rx_queue(0); uint32_t grx = peek_rx_queue(0);
if (!grx) { if (!grx) {
// Wait for packet // Wait for packet
OTG->GINTMSK |= USB_OTG_GINTMSK_RXFLVLM; OTG->GINTMSK |= USB_OTG_GINTMSK_RXFLVLM;
usb_irq_enable();
return -1; return -1;
} }
uint32_t pktsts = ((grx & USB_OTG_GRXSTSP_PKTSTS_Msk) uint32_t pktsts = ((grx & USB_OTG_GRXSTSP_PKTSTS_Msk)
>> USB_OTG_GRXSTSP_PKTSTS_Pos); >> USB_OTG_GRXSTSP_PKTSTS_Pos);
if (pktsts != 2) if (pktsts != 2) {
// Transfer interrupted // Transfer interrupted
usb_irq_enable();
return -2; return -2;
return fifo_read_packet(data, max_len); }
int_fast8_t ret = fifo_read_packet(data, max_len);
usb_irq_enable();
return ret;
} }
int_fast8_t int_fast8_t
usb_read_ep0_setup(void *data, uint_fast8_t max_len) usb_read_ep0_setup(void *data, uint_fast8_t max_len)
{ {
usb_irq_disable();
for (;;) { for (;;) {
uint32_t grx = peek_rx_queue(0); uint32_t grx = peek_rx_queue(0);
if (!grx) { if (!grx) {
// Wait for packet // Wait for packet
OTG->GINTMSK |= USB_OTG_GINTMSK_RXFLVLM; OTG->GINTMSK |= USB_OTG_GINTMSK_RXFLVLM;
usb_irq_enable();
return -1; return -1;
} }
uint32_t pktsts = ((grx & USB_OTG_GRXSTSP_PKTSTS_Msk) uint32_t pktsts = ((grx & USB_OTG_GRXSTSP_PKTSTS_Msk)
@ -220,30 +253,40 @@ usb_read_ep0_setup(void *data, uint_fast8_t max_len)
while (OTG->GRSTCTL & USB_OTG_GRSTCTL_TXFFLSH) while (OTG->GRSTCTL & USB_OTG_GRSTCTL_TXFFLSH)
; ;
} }
return fifo_read_packet(data, max_len); int_fast8_t ret = fifo_read_packet(data, max_len);
usb_irq_enable();
return ret;
} }
int_fast8_t int_fast8_t
usb_send_ep0(const void *data, uint_fast8_t len) usb_send_ep0(const void *data, uint_fast8_t len)
{ {
usb_irq_disable();
uint32_t grx = peek_rx_queue(0); uint32_t grx = peek_rx_queue(0);
if (grx) { if (grx) {
// Transfer interrupted // Transfer interrupted
usb_irq_enable();
return -2; return -2;
} }
if (EPIN(0)->DIEPCTL & USB_OTG_DIEPCTL_EPENA) { if (EPIN(0)->DIEPCTL & USB_OTG_DIEPCTL_EPENA) {
// Wait for space to transmit // Wait for space to transmit
OTG->GINTMSK |= USB_OTG_GINTMSK_RXFLVLM; OTG->GINTMSK |= USB_OTG_GINTMSK_RXFLVLM;
OTGD->DAINTMSK |= 1 << 0;
usb_irq_enable();
return -1; return -1;
} }
return fifo_write_packet(0, data, len); int_fast8_t ret = fifo_write_packet(0, data, len);
usb_irq_enable();
return ret;
} }
void void
usb_stall_ep0(void) usb_stall_ep0(void)
{ {
usb_irq_disable();
EPIN(0)->DIEPCTL |= USB_OTG_DIEPCTL_STALL; EPIN(0)->DIEPCTL |= USB_OTG_DIEPCTL_STALL;
usb_notify_ep0(); // XXX - wake from main usb_cdc.c code? usb_notify_ep0(); // XXX - wake from main usb_cdc.c code?
usb_irq_enable();
} }
void void
@ -258,6 +301,7 @@ usb_set_address(uint_fast8_t addr)
void void
usb_set_configure(void) usb_set_configure(void)
{ {
usb_irq_disable();
// Configure and enable USB_CDC_EP_ACM // Configure and enable USB_CDC_EP_ACM
USB_OTG_INEndpointTypeDef *epi = EPIN(USB_CDC_EP_ACM); USB_OTG_INEndpointTypeDef *epi = EPIN(USB_CDC_EP_ACM);
epi->DIEPTSIZ = (USB_CDC_EP_ACM_SIZE epi->DIEPTSIZ = (USB_CDC_EP_ACM_SIZE
@ -291,6 +335,7 @@ usb_set_configure(void)
| USB_OTG_GRSTCTL_TXFFLSH); | USB_OTG_GRSTCTL_TXFFLSH);
while (OTG->GRSTCTL & USB_OTG_GRSTCTL_TXFFLSH) while (OTG->GRSTCTL & USB_OTG_GRSTCTL_TXFFLSH)
; ;
usb_irq_enable();
} }
void void
@ -320,18 +365,13 @@ OTG_FS_IRQHandler(void)
if (sts & USB_OTG_GINTSTS_IEPINT) { if (sts & USB_OTG_GINTSTS_IEPINT) {
// Can transmit data - disable irq and notify endpoint // Can transmit data - disable irq and notify endpoint
uint32_t daint = OTGD->DAINT; uint32_t daint = OTGD->DAINT;
if (daint & (1 << 0)) { OTGD->DAINTMSK &= ~daint;
USB_OTG_INEndpointTypeDef *epi = EPIN(0); if (daint & (1 << 0))
epi->DIEPINT = epi->DIEPINT;
usb_notify_ep0(); usb_notify_ep0();
} if (daint & (1 << USB_CDC_EP_BULK_IN))
if (daint & (1 << USB_CDC_EP_BULK_IN)) {
USB_OTG_INEndpointTypeDef *epi = EPIN(USB_CDC_EP_BULK_IN);
epi->DIEPINT = epi->DIEPINT;
usb_notify_bulk_in(); usb_notify_bulk_in();
} }
} }
}
DECL_CONSTANT_STR("RESERVE_PINS_USB", "PA11,PA12"); DECL_CONSTANT_STR("RESERVE_PINS_USB", "PA11,PA12");
@ -371,7 +411,6 @@ usb_init(void)
epo->DOEPCTL = mpsize_ep0 | USB_OTG_DOEPCTL_EPENA | USB_OTG_DOEPCTL_CNAK; epo->DOEPCTL = mpsize_ep0 | USB_OTG_DOEPCTL_EPENA | USB_OTG_DOEPCTL_CNAK;
// Enable interrupts // Enable interrupts
OTGD->DAINTMSK = (1 << 0) | (1 << USB_CDC_EP_BULK_IN);
OTGD->DIEPMSK = USB_OTG_DIEPMSK_XFRCM; OTGD->DIEPMSK = USB_OTG_DIEPMSK_XFRCM;
OTG->GINTMSK = USB_OTG_GINTMSK_RXFLVLM | USB_OTG_GINTMSK_IEPINT; OTG->GINTMSK = USB_OTG_GINTMSK_RXFLVLM | USB_OTG_GINTMSK_IEPINT;
OTG->GAHBCFG = USB_OTG_GAHBCFG_GINT; OTG->GAHBCFG = USB_OTG_GAHBCFG_GINT;