Преглед изворни кода

update(port/ehci): use static qtd pool for qtd alloc & free

Signed-off-by: sakumisu <1203593632@qq.com>
sakumisu пре 8 месеци
родитељ
комит
33dd56b7ce
3 измењених фајлова са 100 додато и 63 уклоњено
  1. 2 2
      cherryusb_config_template.h
  2. 84 50
      port/ehci/usb_hc_ehci.c
  3. 14 11
      port/ehci/usb_hc_ehci.h

+ 2 - 2
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

+ 84 - 50
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_qtd_hw *ehci_qtd_alloc(struct usbh_bus *bus)
+{
+    struct ehci_qtd_hw *qtd;
+    size_t flags;
+
+    flags = usb_osal_enter_critical_section();
+    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;
-    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;
+        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) {
     }
-}
+}

+ 14 - 11
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 */