diff --git a/cherryusb_config_template.h b/cherryusb_config_template.h index 6e8576b..9b7334b 100644 --- a/cherryusb_config_template.h +++ b/cherryusb_config_template.h @@ -265,8 +265,8 @@ #define CONFIG_USB_EHCI_HCCR_OFFSET (0x0) #define CONFIG_USB_EHCI_FRAME_LIST_SIZE 1024 #define CONFIG_USB_EHCI_QH_NUM CONFIG_USBHOST_PIPE_NUM -#define CONFIG_USB_EHCI_QTD_NUM 3 -#define CONFIG_USB_EHCI_ITD_NUM 20 +#define CONFIG_USB_EHCI_QTD_NUM (CONFIG_USB_EHCI_QH_NUM * 3) +#define CONFIG_USB_EHCI_ITD_NUM 4 // #define CONFIG_USB_EHCI_HCOR_RESERVED_DISABLE // #define CONFIG_USB_EHCI_CONFIGFLAG // #define CONFIG_USB_EHCI_ISO diff --git a/port/ehci/usb_hc_ehci.c b/port/ehci/usb_hc_ehci.c index f835443..dd91544 100644 --- a/port/ehci/usb_hc_ehci.c +++ b/port/ehci/usb_hc_ehci.c @@ -17,6 +17,7 @@ struct ehci_hcd g_ehci_hcd[CONFIG_USBHOST_MAX_BUS]; USB_NOCACHE_RAM_SECTION struct ehci_qh_hw ehci_qh_pool[CONFIG_USBHOST_MAX_BUS][CONFIG_USB_EHCI_QH_NUM]; +USB_NOCACHE_RAM_SECTION struct ehci_qtd_hw ehci_qtd_pool[CONFIG_USBHOST_MAX_BUS][CONFIG_USB_EHCI_QTD_NUM]; /* The head of the asynchronous queue */ USB_NOCACHE_RAM_SECTION struct ehci_qh_hw g_async_qh_head[CONFIG_USBHOST_MAX_BUS]; @@ -26,32 +27,60 @@ USB_NOCACHE_RAM_SECTION struct ehci_qh_hw g_periodic_qh_head[CONFIG_USBHOST_MAX_ /* The frame list */ USB_NOCACHE_RAM_SECTION uint32_t g_framelist[CONFIG_USBHOST_MAX_BUS][USB_ALIGN_UP(CONFIG_USB_EHCI_FRAME_LIST_SIZE, 1024)] __attribute__((aligned(4096))); -static struct ehci_qh_hw *ehci_qh_alloc(struct usbh_bus *bus) +static struct ehci_qtd_hw *ehci_qtd_alloc(struct usbh_bus *bus) { - struct ehci_qh_hw *qh; struct ehci_qtd_hw *qtd; size_t flags; flags = usb_osal_enter_critical_section(); - for (uint32_t i = 0; i < CONFIG_USB_EHCI_QH_NUM; i++) { - if (!g_ehci_hcd[bus->hcd.hcd_id].ehci_qh_used[i]) { - g_ehci_hcd[bus->hcd.hcd_id].ehci_qh_used[i] = true; + for (uint32_t i = 0; i < CONFIG_USB_EHCI_QTD_NUM; i++) { + qtd = &ehci_qtd_pool[bus->hcd.hcd_id][i]; + if (!qtd->inuse) { + qtd->inuse = true; + usb_osal_leave_critical_section(flags); + + memset(&qtd->hw, 0, sizeof(struct ehci_qtd)); + qtd->hw.next_qtd = QTD_LIST_END; + qtd->urb = NULL; + qtd->bufaddr = 0; + qtd->length = 0; + + return qtd; + } + } + usb_osal_leave_critical_section(flags); + return NULL; +} + +static void ehci_qtd_free(struct usbh_bus *bus, struct ehci_qtd_hw *qtd) +{ + size_t flags; + + flags = usb_osal_enter_critical_section(); + qtd->inuse = false; + qtd->urb = NULL; + usb_osal_leave_critical_section(flags); +} + +static struct ehci_qh_hw *ehci_qh_alloc(struct usbh_bus *bus) +{ + struct ehci_qh_hw *qh; + size_t flags; + + flags = usb_osal_enter_critical_section(); + for (uint32_t i = 0; i < CONFIG_USB_EHCI_QH_NUM; i++) { + qh = &ehci_qh_pool[bus->hcd.hcd_id][i]; + if (!qh->inuse) { + qh->inuse = true; usb_osal_leave_critical_section(flags); - qh = &ehci_qh_pool[bus->hcd.hcd_id][i]; memset(&qh->hw, 0, sizeof(struct ehci_qh)); qh->hw.hlp = QTD_LIST_END; qh->hw.overlay.next_qtd = QTD_LIST_END; qh->hw.overlay.alt_next_qtd = QTD_LIST_END; qh->urb = NULL; - - for (uint32_t j = 0; j < CONFIG_USB_EHCI_QTD_NUM; j++) { - qtd = &qh->qtd_pool[j]; - qtd->hw.next_qtd = QTD_LIST_END; - qtd->hw.alt_next_qtd = QTD_LIST_END; - qtd->hw.token = QTD_TOKEN_STATUS_HALTED; - qtd->urb = NULL; - } + qh->first_qtd = QTD_LIST_END; + qh->remove_in_iaad = 0; return qh; } @@ -62,18 +91,20 @@ static struct ehci_qh_hw *ehci_qh_alloc(struct usbh_bus *bus) static void ehci_qh_free(struct usbh_bus *bus, struct ehci_qh_hw *qh) { + struct ehci_qtd_hw *qtd; size_t flags; - for (uint32_t i = 0; i < CONFIG_USB_EHCI_QH_NUM; i++) { - if (&ehci_qh_pool[bus->hcd.hcd_id][i] == qh) { - flags = usb_osal_enter_critical_section(); - g_ehci_hcd[bus->hcd.hcd_id].ehci_qh_used[i] = false; - usb_osal_leave_critical_section(flags); + flags = usb_osal_enter_critical_section(); + qtd = EHCI_ADDR2QTD(qh->first_qtd); - qh->urb = NULL; - return; - } + while (qtd) { + ehci_qtd_free(bus, qtd); + qtd = EHCI_ADDR2QTD(qtd->hw.next_qtd); } + + qh->inuse = false; + qh->first_qtd = QTD_LIST_END; + usb_osal_leave_critical_section(flags); } #if defined(CONFIG_USB_EHCI_DESC_DCACHE_ENABLE) @@ -300,9 +331,15 @@ static struct ehci_qh_hw *ehci_control_urb_init(struct usbh_bus *bus, struct usb return NULL; } - qtd_setup = &qh->qtd_pool[0]; - qtd_data = &qh->qtd_pool[1]; - qtd_status = &qh->qtd_pool[2]; + qtd_setup = ehci_qtd_alloc(bus); + qtd_data = ehci_qtd_alloc(bus); + qtd_status = ehci_qtd_alloc(bus); + + if (!qtd_setup || !qtd_data || !qtd_status) { + USB_LOG_ERR("qtd alloc failed\r\n"); + while (1) { + } + } ehci_qh_fill(qh, urb->hport->dev_addr, @@ -409,7 +446,12 @@ static struct ehci_qh_hw *ehci_bulk_urb_init(struct usbh_bus *bus, struct usbh_u urb->hport->port); while (1) { - qtd = &qh->qtd_pool[qtd_num]; + qtd = ehci_qtd_alloc(bus); + if (qtd == NULL) { + USB_LOG_ERR("qtd alloc failed\r\n"); + while (1) { + } + } if (buflen > 0x4000) { xfer_len = 0x4000; @@ -510,7 +552,12 @@ static struct ehci_qh_hw *ehci_intr_urb_init(struct usbh_bus *bus, struct usbh_u urb->hport->port); while (1) { - qtd = &qh->qtd_pool[qtd_num]; + qtd = ehci_qtd_alloc(bus); + if (qtd == NULL) { + USB_LOG_ERR("qtd alloc failed\r\n"); + while (1) { + } + } if (buflen > 0x4000) { xfer_len = 0x4000; @@ -621,8 +668,7 @@ static void ehci_qh_scan_qtds(struct usbh_bus *bus, struct ehci_qh_hw *qhead, st while (qtd) { qtd->urb->actual_length += (qtd->length - ((qtd->hw.token & QTD_TOKEN_NBYTES_MASK) >> QTD_TOKEN_NBYTES_SHIFT)); - qh->first_qtd = qtd->hw.next_qtd; - qtd = EHCI_ADDR2QTD(qh->first_qtd); + qtd = EHCI_ADDR2QTD(qtd->hw.next_qtd); } } @@ -687,18 +733,9 @@ static void ehci_check_qh(struct usbh_bus *bus, struct ehci_qh_hw *qhead, struct static void ehci_kill_qh(struct usbh_bus *bus, struct ehci_qh_hw *qhead, struct ehci_qh_hw *qh) { - struct ehci_qtd_hw *qtd; - (void)bus; ehci_qh_remove(qhead, qh); - - qtd = EHCI_ADDR2QTD(qh->first_qtd); - - while (qtd) { - qh->first_qtd = qtd->hw.next_qtd; - qtd = EHCI_ADDR2QTD(qh->first_qtd); - } } static int usbh_reset_port(struct usbh_bus *bus, const uint8_t port) @@ -749,12 +786,14 @@ __WEAK void usb_hc_low_level_deinit(struct usbh_bus *bus) int usb_hc_init(struct usbh_bus *bus) { struct ehci_qh_hw *qh; + struct ehci_qtd_hw *qtd; volatile uint32_t timeout = 0; uint32_t regval; memset(&g_ehci_hcd[bus->hcd.hcd_id], 0, sizeof(struct ehci_hcd)); memset(ehci_qh_pool[bus->hcd.hcd_id], 0, sizeof(struct ehci_qh_hw) * CONFIG_USB_EHCI_QH_NUM); + memset(ehci_qtd_pool[bus->hcd.hcd_id], 0, sizeof(struct ehci_qtd_hw) * CONFIG_USB_EHCI_QTD_NUM); for (uint8_t index = 0; index < CONFIG_USB_EHCI_QH_NUM; index++) { qh = &ehci_qh_pool[bus->hcd.hcd_id][index]; @@ -762,11 +801,13 @@ int usb_hc_init(struct usbh_bus *bus) USB_LOG_ERR("struct ehci_qh_hw is not align 32\r\n"); return -USB_ERR_INVAL; } - for (uint8_t i = 0; i < CONFIG_USB_EHCI_QTD_NUM; i++) { - if ((uint32_t)&qh->qtd_pool[i] % 32) { - USB_LOG_ERR("struct ehci_qtd_hw is not align 32\r\n"); - return -USB_ERR_INVAL; - } + } + + for (uint8_t index = 0; index < CONFIG_USB_EHCI_QTD_NUM; index++) { + qtd = &ehci_qtd_pool[bus->hcd.hcd_id][index]; + if ((uint32_t)&qtd->hw % 32) { + USB_LOG_ERR("struct ehci_qtd_hw is not align 32\r\n"); + return -USB_ERR_INVAL; } } @@ -1408,14 +1449,7 @@ void USBH_IRQHandler(uint8_t busid) extern void USB_EhcihostPhyDisconnectDetectCmd(uint8_t controllerId, uint8_t enable); USB_EhcihostPhyDisconnectDetectCmd(2 + busid, 0); #endif - for (uint8_t index = 0; index < CONFIG_USB_EHCI_QH_NUM; index++) { - g_ehci_hcd[bus->hcd.hcd_id].ehci_qh_used[index] = false; - } - for (uint8_t index = 0; index < CONFIG_USB_EHCI_ISO_NUM; index++) { - g_ehci_hcd[bus->hcd.hcd_id].ehci_iso_used[index] = false; - } } - bus->hcd.roothub.int_buffer[0] |= (1 << (port + 1)); usbh_hub_thread_wakeup(&bus->hcd.roothub); } @@ -1425,7 +1459,7 @@ void USBH_IRQHandler(uint8_t busid) if (usbsts & EHCI_USBSTS_IAA) { for (uint8_t index = 0; index < CONFIG_USB_EHCI_QH_NUM; index++) { struct ehci_qh_hw *qh = &ehci_qh_pool[bus->hcd.hcd_id][index]; - if (g_ehci_hcd[bus->hcd.hcd_id].ehci_qh_used[index] && qh->remove_in_iaad) { + if (qh->remove_in_iaad) { ehci_urb_waitup(bus, qh->urb); } } @@ -1433,4 +1467,4 @@ void USBH_IRQHandler(uint8_t busid) if (usbsts & EHCI_USBSTS_FATAL) { } -} +} \ No newline at end of file diff --git a/port/ehci/usb_hc_ehci.h b/port/ehci/usb_hc_ehci.h index 3ae618a..80ab8b6 100644 --- a/port/ehci/usb_hc_ehci.h +++ b/port/ehci/usb_hc_ehci.h @@ -19,31 +19,36 @@ #define EHCI_ADDR2ITD(x) ((struct ehci_itd_hw *)(uintptr_t)((uint32_t)(x) & ~0x1F)) #ifndef CONFIG_USB_EHCI_QH_NUM -#define CONFIG_USB_EHCI_QH_NUM CONFIG_USBHOST_PIPE_NUM +#define CONFIG_USB_EHCI_QH_NUM CONFIG_USBHOST_PIPE_NUM #endif #ifndef CONFIG_USB_EHCI_QTD_NUM -#define CONFIG_USB_EHCI_QTD_NUM 3 +#define CONFIG_USB_EHCI_QTD_NUM (CONFIG_USB_EHCI_QH_NUM * 3) #endif #ifndef CONFIG_USB_EHCI_ITD_NUM -#define CONFIG_USB_EHCI_ITD_NUM 5 +#define CONFIG_USB_EHCI_ITD_NUM 5 #endif #ifndef CONFIG_USB_EHCI_ISO_NUM -#define CONFIG_USB_EHCI_ISO_NUM 4 +#define CONFIG_USB_EHCI_ISO_NUM 4 #endif #if CONFIG_USB_ALIGN_SIZE <= 32 -#define CONFIG_USB_EHCI_ALIGN_SIZE 32 +#define CONFIG_USB_EHCI_ALIGN_SIZE 32 #elif CONFIG_USB_ALIGN_SIZE <= 64 -#define CONFIG_USB_EHCI_ALIGN_SIZE 64 +#define CONFIG_USB_EHCI_ALIGN_SIZE 64 #else #error "CONFIG_USB_ALIGN_SIZE must be 32 or 64" #endif +#if CONFIG_USB_EHCI_QTD_NUM < 9 +#error CONFIG_USB_EHCI_QTD_NUM is too small, recommand CONFIG_USB_EHCI_QH_NUM * 3 +#endif + struct ehci_qtd_hw { struct ehci_qtd hw; #if defined(CONFIG_USB_EHCI_DESC_DCACHE_ENABLE) && (CONFIG_USB_ALIGN_SIZE == 64) uint8_t pad[32]; #endif + bool inuse; struct usbh_urb *urb; uintptr_t bufaddr; uint32_t length; @@ -54,7 +59,7 @@ struct ehci_qh_hw { #if defined(CONFIG_USB_EHCI_DESC_DCACHE_ENABLE) uint16_t pad[16]; #endif - struct ehci_qtd_hw qtd_pool[CONFIG_USB_EHCI_QTD_NUM]; + bool inuse; uint32_t first_qtd; struct usbh_urb *urb; usb_osal_sem_t waitsem; @@ -71,16 +76,14 @@ struct ehci_itd_hw { bool dir_in; } __attribute__((aligned(CONFIG_USB_EHCI_ALIGN_SIZE))); -struct ehci_iso_hw -{ +struct ehci_iso_hw { struct ehci_itd_hw itd_pool[CONFIG_USB_EHCI_ITD_NUM]; uint32_t itd_num; }; struct ehci_hcd { - bool ehci_qh_used[CONFIG_USB_EHCI_QH_NUM]; bool ehci_iso_used[CONFIG_USB_EHCI_ISO_NUM]; - bool ppc; /* Port Power Control */ + bool ppc; /* Port Power Control */ bool has_tt; /* if use tt instead of Companion Controller */ uint8_t n_cc; /* Number of Companion Controller */ uint8_t n_pcc; /* Number of ports supported per companion host controller */