diff --git a/common/usb_dcache.h b/common/usb_dcache.h new file mode 100644 index 00000000..60fbb7e9 --- /dev/null +++ b/common/usb_dcache.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2024, sakumisu + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef USB_DCACHE_H +#define USB_DCACHE_H + +#ifdef CONFIG_USB_DCACHE_ENABLE +#if CONFIG_USB_ALIGN_SIZE % 32 +#error "CONFIG_USB_ALIGN_SIZE must be multiple of 32" +#endif +#else +#define usb_dcache_clean(addr, size) +#define usb_dcache_invalidate(addr, size) +#define usb_dcache_flush(addr, size) +#endif + +#endif /* USB_DCACHE_H */ diff --git a/common/usb_errno.h b/common/usb_errno.h index 57f37c16..6c2c790a 100644 --- a/common/usb_errno.h +++ b/common/usb_errno.h @@ -20,5 +20,6 @@ #define USB_ERR_IO 12 #define USB_ERR_SHUTDOWN 13 #define USB_ERR_TIMEOUT 14 +#define USB_ERR_ALIGN 15 #endif /* USB_ERRNO_H */ diff --git a/core/usbh_core.h b/core/usbh_core.h index eaddb304..1bed410d 100644 --- a/core/usbh_core.h +++ b/core/usbh_core.h @@ -21,6 +21,7 @@ #include "usb_osal.h" #include "usbh_hub.h" #include "usb_memcpy.h" +#include "usb_dcache.h" #include "usb_version.h" #ifdef __cplusplus diff --git a/port/ehci/usb_hc_ehci.c b/port/ehci/usb_hc_ehci.c index 4f61854a..ad46aaee 100644 --- a/port/ehci/usb_hc_ehci.c +++ b/port/ehci/usb_hc_ehci.c @@ -76,10 +76,36 @@ static void ehci_qh_free(struct usbh_bus *bus, struct ehci_qh_hw *qh) } } +#ifdef CONFIG_USB_DCACHE_ENABLE +static inline void usb_ehci_qh_qtd_flush(struct ehci_qh_hw *qh) +{ + struct ehci_qtd_hw *qtd; + + qtd = EHCI_ADDR2QTD(qh->first_qtd); + + while (qtd) { + usb_dcache_clean((uintptr_t)&qtd->hw, CONFIG_USB_EHCI_ALIGN_SIZE); + + if (!qtd->dir_in) { + usb_dcache_clean(qtd->bufaddr, USB_ALIGN_UP(qtd->length, CONFIG_USB_ALIGN_SIZE)); + } + qtd = EHCI_ADDR2QTD(qtd->hw.next_qtd); + } + + usb_dcache_clean((uintptr_t)&qh->hw, CONFIG_USB_EHCI_ALIGN_SIZE); +} +#else +#define usb_ehci_qh_qtd_flush(qh) +#endif + static inline void ehci_qh_add_head(struct ehci_qh_hw *head, struct ehci_qh_hw *n) { n->hw.hlp = head->hw.hlp; + usb_ehci_qh_qtd_flush(n); + head->hw.hlp = QH_HLP_QH(n); + + usb_dcache_clean((uintptr_t)&head->hw, CONFIG_USB_EHCI_ALIGN_SIZE); } static inline void ehci_qh_remove(struct ehci_qh_hw *head, struct ehci_qh_hw *n) @@ -92,6 +118,7 @@ static inline void ehci_qh_remove(struct ehci_qh_hw *head, struct ehci_qh_hw *n) if (tmp) { tmp->hw.hlp = n->hw.hlp; + usb_dcache_clean((uintptr_t)&tmp->hw, CONFIG_USB_EHCI_ALIGN_SIZE); } } @@ -255,6 +282,8 @@ static void ehci_qtd_fill(struct ehci_qtd_hw *qtd, uint32_t bufaddr, size_t bufl qtd->hw.token = token; ehci_qtd_bpl_fill(qtd, bufaddr, buflen); + qtd->dir_in = ((token & QTD_TOKEN_PID_MASK) == QTD_TOKEN_PID_IN) ? true : false; + qtd->bufaddr = bufaddr; qtd->length = buflen; } @@ -591,6 +620,9 @@ static void ehci_qh_scan_qtds(struct usbh_bus *bus, struct ehci_qh_hw *qhead, st qtd = EHCI_ADDR2QTD(qh->first_qtd); while (qtd) { + if (qtd->dir_in) { + usb_dcache_invalidate(qtd->bufaddr, USB_ALIGN_UP(qtd->length - ((qtd->hw.token & QTD_TOKEN_NBYTES_MASK) >> QTD_TOKEN_NBYTES_SHIFT), CONFIG_USB_ALIGN_SIZE)); + } qtd->urb->actual_length += (qtd->length - ((qtd->hw.token & QTD_TOKEN_NBYTES_MASK) >> QTD_TOKEN_NBYTES_SHIFT)); qh->first_qtd = qtd->hw.next_qtd; @@ -611,6 +643,7 @@ static void ehci_check_qh(struct usbh_bus *bus, struct ehci_qh_hw *qhead, struct } while (qtd) { + usb_dcache_invalidate((uintptr_t)&qtd->hw, CONFIG_USB_EHCI_ALIGN_SIZE); token = qtd->hw.token; if (token & QTD_TOKEN_STATUS_ERRORS) { @@ -766,6 +799,10 @@ int usb_hc_init(struct usbh_bus *bus) g_framelist[bus->hcd.hcd_id][i] = QH_HLP_QH(&g_periodic_qh_head[bus->hcd.hcd_id]); } + usb_dcache_clean((uintptr_t)&g_async_qh_head[bus->hcd.hcd_id].hw, CONFIG_USB_EHCI_ALIGN_SIZE); + usb_dcache_clean((uintptr_t)&g_periodic_qh_head[bus->hcd.hcd_id].hw, CONFIG_USB_EHCI_ALIGN_SIZE); + usb_dcache_clean((uintptr_t)g_framelist[bus->hcd.hcd_id], sizeof(uint32_t) * CONFIG_USB_EHCI_FRAME_LIST_SIZE); + usb_hc_low_level_init(bus); USB_LOG_INFO("EHCI HCIVERSION:0x%04x\r\n", (unsigned int)EHCI_HCCR->hciversion); @@ -1138,6 +1175,12 @@ int usbh_submit_urb(struct usbh_urb *urb) return -USB_ERR_INVAL; } +#ifdef CONFIG_USB_DCACHE_ENABLE + if (((uintptr_t)urb->setup % CONFIG_USB_ALIGN_SIZE) || ((uintptr_t)urb->transfer_buffer % CONFIG_USB_ALIGN_SIZE)) { + USB_LOG_ERR("urb buffer is not align with %d\r\n", CONFIG_USB_ALIGN_SIZE); + return -USB_ERR_ALIGN; + } +#endif bus = urb->hport->bus; /* find active hubport in roothub */ diff --git a/port/ehci/usb_hc_ehci.h b/port/ehci/usb_hc_ehci.h index 714128bc..f4c22b77 100644 --- a/port/ehci/usb_hc_ehci.h +++ b/port/ehci/usb_hc_ehci.h @@ -30,14 +30,19 @@ #ifndef CONFIG_USB_EHCI_ISO_NUM #define CONFIG_USB_EHCI_ISO_NUM 4 #endif +#ifndef CONFIG_USB_EHCI_ALIGN_SIZE +#define CONFIG_USB_EHCI_ALIGN_SIZE 64 +#endif extern uint8_t usbh_get_port_speed(struct usbh_bus *bus, const uint8_t port); struct ehci_qtd_hw { struct ehci_qtd hw; struct usbh_urb *urb; + bool dir_in; + uintptr_t bufaddr; uint32_t length; -} __attribute__((aligned(32))); +} __attribute__((aligned(CONFIG_USB_EHCI_ALIGN_SIZE))); struct ehci_qh_hw { struct ehci_qh hw; @@ -46,7 +51,7 @@ struct ehci_qh_hw { struct usbh_urb *urb; usb_osal_sem_t waitsem; uint8_t remove_in_iaad; -} __attribute__((aligned(32))); +} __attribute__((aligned(CONFIG_USB_EHCI_ALIGN_SIZE))); struct ehci_itd_hw { struct ehci_itd hw; @@ -55,7 +60,10 @@ struct ehci_itd_hw { uint8_t mf_unmask; uint8_t mf_valid; uint32_t pkt_idx[8]; -} __attribute__((aligned(32))); + bool dir_in; + uintptr_t bufaddr; + uint32_t length; +} __attribute__((aligned(CONFIG_USB_EHCI_ALIGN_SIZE))); struct ehci_iso_hw { diff --git a/port/ohci/usb_hc_ohci.h b/port/ohci/usb_hc_ohci.h index 19d51909..1b322007 100644 --- a/port/ohci/usb_hc_ohci.h +++ b/port/ohci/usb_hc_ohci.h @@ -22,14 +22,18 @@ #ifndef CONFIG_USB_OHCI_TD_NUM #define CONFIG_USB_OHCI_TD_NUM 3 #endif +#ifndef CONFIG_USB_OHCI_ALIGN_SIZE +#define CONFIG_USB_OHCI_ALIGN_SIZE 64 +#endif struct ohci_ed_hw; struct ohci_td_hw { struct ohci_gtd hw; struct usbh_urb *urb; + bool dir_in; uint32_t buf_start; uint32_t length; -} __attribute__((aligned(32))); /* min is 16bytes, we use 32 for cacheline */ +} __attribute__((aligned(CONFIG_USB_OHCI_ALIGN_SIZE))); /* min is 16bytes, we use CONFIG_USB_OHCI_ALIGN_SIZE for cacheline */ struct ohci_ed_hw { struct ohci_ed hw; @@ -37,7 +41,7 @@ struct ohci_ed_hw { uint32_t td_count; uint8_t ed_type; usb_osal_sem_t waitsem; -} __attribute__((aligned(32))); /* min is 16bytes, we use 32 for cacheline */ +} __attribute__((aligned(CONFIG_USB_OHCI_ALIGN_SIZE))); /* min is 16bytes, we use CONFIG_USB_OHCI_ALIGN_SIZE for cacheline */ struct ohci_hcd { bool ohci_ed_used[CONFIG_USB_OHCI_ED_NUM];