mirror of
https://github.com/hathach/tinyusb.git
synced 2025-03-28 05:37:15 +00:00
refactor ehci: add attached_buffer for dcache invalidate for IN transfer
This commit is contained in:
parent
27acaa013b
commit
ec4bd39a92
@ -154,6 +154,7 @@ static inline ehci_qhd_t* qhd_next (ehci_qhd_t const * p_qhd);
|
|||||||
static inline ehci_qhd_t* qhd_find_free (void);
|
static inline ehci_qhd_t* qhd_find_free (void);
|
||||||
static inline ehci_qhd_t* qhd_get_from_addr (uint8_t dev_addr, uint8_t ep_addr);
|
static inline ehci_qhd_t* qhd_get_from_addr (uint8_t dev_addr, uint8_t ep_addr);
|
||||||
static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc);
|
static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc);
|
||||||
|
static void qhd_attach_qtd(ehci_qhd_t *qhd, ehci_qtd_t *qtd);
|
||||||
|
|
||||||
static inline ehci_qtd_t* qtd_find_free (void);
|
static inline ehci_qtd_t* qtd_find_free (void);
|
||||||
static void qtd_init (ehci_qtd_t* qtd, void const* buffer, uint16_t total_bytes);
|
static void qtd_init (ehci_qtd_t* qtd, void const* buffer, uint16_t total_bytes);
|
||||||
@ -468,13 +469,9 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet
|
|||||||
td->pid = EHCI_PID_SETUP;
|
td->pid = EHCI_PID_SETUP;
|
||||||
|
|
||||||
hcd_dcache_clean((void *) setup_packet, 8);
|
hcd_dcache_clean((void *) setup_packet, 8);
|
||||||
hcd_dcache_clean_invalidate(td, sizeof(ehci_qtd_t));
|
|
||||||
|
|
||||||
// attach TD
|
// attach TD to QHD -> start transferring
|
||||||
qhd->p_attached_qtd = td; // software management
|
qhd_attach_qtd(qhd, td);
|
||||||
qhd->qtd_overlay.next.address = (uint32_t) td;
|
|
||||||
|
|
||||||
hcd_dcache_clean_invalidate(qhd, sizeof(ehci_qhd_t));
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -513,13 +510,9 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *
|
|||||||
}else {
|
}else {
|
||||||
hcd_dcache_clean(buffer, buflen);
|
hcd_dcache_clean(buffer, buflen);
|
||||||
}
|
}
|
||||||
hcd_dcache_clean_invalidate(qtd, sizeof(ehci_qtd_t));
|
|
||||||
|
|
||||||
// attach TD to QHD start transferring
|
// attach TD to QHD -> start transferring
|
||||||
qhd->p_attached_qtd = qtd; // software management
|
qhd_attach_qtd(qhd, qtd);
|
||||||
qhd->qtd_overlay.next.address = (uint32_t) qtd;
|
|
||||||
|
|
||||||
hcd_dcache_clean_invalidate(qhd, sizeof(ehci_qhd_t));
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -569,10 +562,9 @@ void port_connect_status_change_isr(uint8_t rhport)
|
|||||||
}
|
}
|
||||||
|
|
||||||
TU_ATTR_ALWAYS_INLINE static inline
|
TU_ATTR_ALWAYS_INLINE static inline
|
||||||
void qhd_xfer_complete_isr(ehci_qhd_t * p_qhd)
|
void qhd_xfer_complete_isr(ehci_qhd_t * qhd) {
|
||||||
{
|
|
||||||
// examine TD attached to queue head
|
// examine TD attached to queue head
|
||||||
ehci_qtd_t * volatile qtd = (ehci_qtd_t * volatile) p_qhd->p_attached_qtd;
|
ehci_qtd_t * volatile qtd = (ehci_qtd_t * volatile) qhd->attached_qtd;
|
||||||
if (qtd == NULL) return; // no TD attached
|
if (qtd == NULL) return; // no TD attached
|
||||||
hcd_dcache_invalidate(qtd, sizeof(ehci_qtd_t));
|
hcd_dcache_invalidate(qtd, sizeof(ehci_qtd_t));
|
||||||
|
|
||||||
@ -581,15 +573,22 @@ void qhd_xfer_complete_isr(ehci_qhd_t * p_qhd)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t dir = (qtd->pid == EHCI_PID_IN) ? 1 : 0;
|
||||||
uint32_t const xferred_bytes = qtd->expected_bytes - qtd->total_bytes;
|
uint32_t const xferred_bytes = qtd->expected_bytes - qtd->total_bytes;
|
||||||
uint8_t const ep_addr = tu_edpt_addr(p_qhd->ep_number, qtd->pid == EHCI_PID_IN ? 1 : 0);
|
|
||||||
|
// invalidate dcache if IN transfer
|
||||||
|
if (dir == 1 && qhd->attached_buffer != 0) {
|
||||||
|
hcd_dcache_invalidate((void*) qhd->attached_buffer, xferred_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
// remove and free TD before invoking callback
|
// remove and free TD before invoking callback
|
||||||
p_qhd->p_attached_qtd = NULL;
|
qhd->attached_qtd = NULL;
|
||||||
|
qhd->attached_buffer = 0;
|
||||||
qtd->used = 0; // free QTD
|
qtd->used = 0; // free QTD
|
||||||
|
|
||||||
// IOC is always set
|
// notify usbh
|
||||||
hcd_event_xfer_complete(p_qhd->dev_addr, ep_addr, xferred_bytes, XFER_RESULT_SUCCESS, true);
|
uint8_t const ep_addr = tu_edpt_addr(qhd->ep_number, dir);
|
||||||
|
hcd_event_xfer_complete(qhd->dev_addr, ep_addr, xferred_bytes, XFER_RESULT_SUCCESS, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
TU_ATTR_ALWAYS_INLINE static inline
|
TU_ATTR_ALWAYS_INLINE static inline
|
||||||
@ -651,10 +650,11 @@ void period_list_xfer_complete_isr(uint8_t rhport, uint32_t interval_ms)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO merge with qhd_xfer_complete_isr()
|
||||||
TU_ATTR_ALWAYS_INLINE static inline
|
TU_ATTR_ALWAYS_INLINE static inline
|
||||||
void qhd_xfer_error_isr(ehci_qhd_t * p_qhd)
|
void qhd_xfer_error_isr(ehci_qhd_t * qhd)
|
||||||
{
|
{
|
||||||
volatile ehci_qtd_t *qtd_overlay = &p_qhd->qtd_overlay;
|
volatile ehci_qtd_t *qtd_overlay = &qhd->qtd_overlay;
|
||||||
|
|
||||||
// TD has error
|
// TD has error
|
||||||
if (qtd_overlay->halted) {
|
if (qtd_overlay->halted) {
|
||||||
@ -674,28 +674,37 @@ void qhd_xfer_error_isr(ehci_qhd_t * p_qhd)
|
|||||||
// while(1){}
|
// while(1){}
|
||||||
// }
|
// }
|
||||||
|
|
||||||
ehci_qtd_t * volatile qtd = (ehci_qtd_t * volatile) p_qhd->p_attached_qtd;
|
ehci_qtd_t * volatile qtd = (ehci_qtd_t * volatile) qhd->attached_qtd;
|
||||||
TU_ASSERT(qtd, ); // No TD yet, probably a race condition or cache issue !?
|
TU_ASSERT(qtd, ); // No TD yet, probably a race condition or cache issue !?
|
||||||
|
|
||||||
hcd_dcache_invalidate(qtd, sizeof(ehci_qtd_t));
|
hcd_dcache_invalidate(qtd, sizeof(ehci_qtd_t));
|
||||||
|
|
||||||
|
uint8_t dir = (qtd->pid == EHCI_PID_IN) ? 1 : 0;
|
||||||
uint32_t const xferred_bytes = qtd->expected_bytes - qtd->total_bytes;
|
uint32_t const xferred_bytes = qtd->expected_bytes - qtd->total_bytes;
|
||||||
|
|
||||||
p_qhd->p_attached_qtd = NULL;
|
// invalidate dcache if IN transfer
|
||||||
|
if (dir == 1 && qhd->attached_buffer != 0) {
|
||||||
|
hcd_dcache_invalidate((void*) qhd->attached_buffer, xferred_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove and free TD before invoking callback
|
||||||
|
qhd->attached_qtd = NULL;
|
||||||
|
qhd->attached_buffer = 0;
|
||||||
qtd->used = 0; // free QTD
|
qtd->used = 0; // free QTD
|
||||||
|
|
||||||
if ( 0 == p_qhd->ep_number ) {
|
if (0 == qhd->ep_number ) {
|
||||||
// control cannot be halted
|
// control cannot be halted
|
||||||
p_qhd->qtd_overlay.next.terminate = 1;
|
qhd->qtd_overlay.next.terminate = 1;
|
||||||
p_qhd->qtd_overlay.alternate.terminate = 1;
|
qhd->qtd_overlay.alternate.terminate = 1;
|
||||||
p_qhd->qtd_overlay.halted = 0;
|
qhd->qtd_overlay.halted = 0;
|
||||||
|
|
||||||
ehci_qtd_t *p_setup = qtd_control(p_qhd->dev_addr);
|
ehci_qtd_t *p_setup = qtd_control(qhd->dev_addr);
|
||||||
p_setup->used = 0;
|
p_setup->used = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// notify usbh
|
// notify usbh
|
||||||
uint8_t const ep_addr = tu_edpt_addr(p_qhd->ep_number, p_qhd->pid == EHCI_PID_IN ? 1 : 0);
|
uint8_t const ep_addr = tu_edpt_addr(qhd->ep_number, dir);
|
||||||
hcd_event_xfer_complete(p_qhd->dev_addr, ep_addr, xferred_bytes, xfer_result, true);
|
hcd_event_xfer_complete(qhd->dev_addr, ep_addr, xferred_bytes, xfer_result, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -846,22 +855,10 @@ static inline ehci_qhd_t* qhd_get_from_addr(uint8_t dev_addr, uint8_t ep_addr)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------- TD helper -------------//
|
|
||||||
static inline ehci_qtd_t* qtd_find_free(void)
|
|
||||||
{
|
|
||||||
for (uint32_t i=0; i<QTD_MAX; i++)
|
|
||||||
{
|
|
||||||
if ( !ehci_data.qtd_pool[i].used ) return &ehci_data.qtd_pool[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc)
|
static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc)
|
||||||
{
|
{
|
||||||
// address 0 is used as async head, which always on the list --> cannot be cleared (ehci halted otherwise)
|
// address 0 is used as async head, which always on the list --> cannot be cleared (ehci halted otherwise)
|
||||||
if (dev_addr != 0)
|
if (dev_addr != 0) {
|
||||||
{
|
|
||||||
tu_memclr(p_qhd, sizeof(ehci_qhd_t));
|
tu_memclr(p_qhd, sizeof(ehci_qhd_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -911,26 +908,47 @@ static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, tusb_desc_endpoint_t c
|
|||||||
p_qhd->int_smask = p_qhd->fl_int_cmask = 0;
|
p_qhd->int_smask = p_qhd->fl_int_cmask = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
p_qhd->fl_hub_addr = devtree_info.hub_addr;
|
p_qhd->fl_hub_addr = devtree_info.hub_addr;
|
||||||
p_qhd->fl_hub_port = devtree_info.hub_port;
|
p_qhd->fl_hub_port = devtree_info.hub_port;
|
||||||
p_qhd->mult = 1; // TODO not use high bandwidth/park mode yet
|
p_qhd->mult = 1; // TODO not use high bandwidth/park mode yet
|
||||||
|
|
||||||
//------------- HCD Management Data -------------//
|
//------------- HCD Management Data -------------//
|
||||||
p_qhd->used = 1;
|
p_qhd->used = 1;
|
||||||
p_qhd->removing = 0;
|
p_qhd->removing = 0;
|
||||||
p_qhd->p_attached_qtd = NULL;
|
p_qhd->attached_qtd = NULL;
|
||||||
p_qhd->pid = tu_edpt_dir(ep_desc->bEndpointAddress) ? EHCI_PID_IN : EHCI_PID_OUT; // PID for TD under this endpoint
|
p_qhd->pid = tu_edpt_dir(ep_desc->bEndpointAddress) ? EHCI_PID_IN : EHCI_PID_OUT; // PID for TD under this endpoint
|
||||||
|
|
||||||
//------------- active, but no TD list -------------//
|
//------------- active, but no TD list -------------//
|
||||||
p_qhd->qtd_overlay.halted = 0;
|
p_qhd->qtd_overlay.halted = 0;
|
||||||
p_qhd->qtd_overlay.next.terminate = 1;
|
p_qhd->qtd_overlay.next.terminate = 1;
|
||||||
p_qhd->qtd_overlay.alternate.terminate = 1;
|
p_qhd->qtd_overlay.alternate.terminate = 1;
|
||||||
|
|
||||||
if (TUSB_XFER_BULK == xfer_type && p_qhd->ep_speed == TUSB_SPEED_HIGH && p_qhd->pid == EHCI_PID_OUT)
|
if (TUSB_XFER_BULK == xfer_type && p_qhd->ep_speed == TUSB_SPEED_HIGH && p_qhd->pid == EHCI_PID_OUT)
|
||||||
{
|
{
|
||||||
p_qhd->qtd_overlay.ping_err = 1; // do PING for Highspeed Bulk OUT, EHCI section 4.11
|
p_qhd->qtd_overlay.ping_err = 1; // do PING for Highspeed Bulk OUT, EHCI section 4.11
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void qhd_attach_qtd(ehci_qhd_t *qhd, ehci_qtd_t *qtd) {
|
||||||
|
qhd->attached_qtd = qtd;
|
||||||
|
qhd->attached_buffer = qtd->buffer[0];
|
||||||
|
|
||||||
|
// clean and invalidate cache before physically write
|
||||||
|
hcd_dcache_clean_invalidate(qtd, sizeof(ehci_qtd_t));
|
||||||
|
|
||||||
|
qhd->qtd_overlay.next.address = (uint32_t) qtd;
|
||||||
|
hcd_dcache_clean_invalidate(qhd, sizeof(ehci_qhd_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//------------- TD helper -------------//
|
||||||
|
static inline ehci_qtd_t *qtd_find_free(void) {
|
||||||
|
for (uint32_t i = 0; i < QTD_MAX; i++) {
|
||||||
|
if (!ehci_data.qtd_pool[i].used) return &ehci_data.qtd_pool[i];
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static void qtd_init(ehci_qtd_t* qtd, void const* buffer, uint16_t total_bytes)
|
static void qtd_init(ehci_qtd_t* qtd, void const* buffer, uint16_t total_bytes)
|
||||||
{
|
{
|
||||||
tu_memclr(qtd, sizeof(ehci_qtd_t));
|
tu_memclr(qtd, sizeof(ehci_qtd_t));
|
||||||
|
@ -164,10 +164,12 @@ typedef struct TU_ATTR_ALIGNED(32)
|
|||||||
uint8_t pid;
|
uint8_t pid;
|
||||||
uint8_t interval_ms; // polling interval in frames (or millisecond)
|
uint8_t interval_ms; // polling interval in frames (or millisecond)
|
||||||
|
|
||||||
uint8_t TU_RESERVED[8];
|
uint8_t TU_RESERVED[4];
|
||||||
|
|
||||||
// usbh will only queue 1 TD per QHD
|
// Attached TD management, note usbh will only queue 1 TD per QHD.
|
||||||
ehci_qtd_t * volatile p_attached_qtd;
|
// buffer for dcache invalidate since td's buffer is modified by HC and finding initial buffer address is not trivial
|
||||||
|
uint32_t attached_buffer;
|
||||||
|
ehci_qtd_t * volatile attached_qtd;
|
||||||
} ehci_qhd_t;
|
} ehci_qhd_t;
|
||||||
|
|
||||||
TU_VERIFY_STATIC( sizeof(ehci_qhd_t) == 64, "size is not correct" );
|
TU_VERIFY_STATIC( sizeof(ehci_qhd_t) == 64, "size is not correct" );
|
||||||
|
Loading…
x
Reference in New Issue
Block a user