summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorR <[email protected]>2025-09-12 22:16:46 +0100
committerR <[email protected]>2025-09-12 22:17:10 +0100
commit839149c5c0b667a8080de39c85cdbdd291be4dc5 (patch)
treec903545fb447344bc78359a1f61ff21ef65efa11
parent2d979ee4a9e7de6b956c373842e8c81c2e6382b4 (diff)
ohci: Align TDs to cache lines
-rw-r--r--src/portable/ohci/ohci.h33
1 files changed, 29 insertions, 4 deletions
diff --git a/src/portable/ohci/ohci.h b/src/portable/ohci/ohci.h
index 94bad5df7..12c411764 100644
--- a/src/portable/ohci/ohci.h
+++ b/src/portable/ohci/ohci.h
@@ -61,6 +61,31 @@ typedef struct {
TU_VERIFY_STATIC( sizeof(ohci_hcca_t) == 256, "size is not correct" );
+// An OHCI host controller is controlled using data structures placed in memory (RAM).
+// It needs to both read and write these data structures (as defined by the OHCI specification),
+// and this can be mentally conceptualized similar to two software threads running on
+// two different CPUs. In order to prevent a _data race_ where data gets corrupted,
+// the CPU and the OHCI host controller need to agree on how the memory should be accessed.
+// In this driver, we do this by transferring logical ownership of transfer descriptors (TDs)
+// between the CPU and the OHCI host controller. Only the device which holds the logical ownership
+// is allowed to read or write the TD. This ownership is not visible anywhere in the code,
+// but it instead must be inferred based on the logical state of the transfer.
+//
+// If dcache-supporting mode is enabled, we need to do additional manual cache operations
+// in order to correctly transfer this logical ownership and prevent data corruption.
+// In order to do this, we also choose to align each OHCI TD so that it doesn't
+// share CPU cache lines with other TDs. This is because manual cache operations
+// can only be performed on cache line granularity. In other words, one cache line is
+// the _smallest_ amount that can be read/written at a time. If there were to be multiple TDs
+// in the same cache line, they would be required to always have the same logical ownership.
+// This ends up being impossible to guarantee, so we choose a design which avoids the situation entirely.
+//
+// TDs have a minimum alignment requirement according to the OHCI specification. This is 16 bytes for
+// a general TD but 32 bytes for an isochronous TD. It happens that typical CPU cache line sizes are usually
+// a power of 2 at least 32. In order to simplify code later in this file, we assume this
+// as an additional requirement.
+TU_VERIFY_STATIC( (CFG_TUH_MEM_DCACHE_ENABLE ? CFG_TUH_MEM_DCACHE_LINE_SIZE : 0) % 32 == 0, "cache line not multiple of 32" );
+
// common link item for gtd and itd for list travel
// use as pointer only
typedef struct TU_ATTR_ALIGNED(16) {
@@ -69,7 +94,7 @@ typedef struct TU_ATTR_ALIGNED(16) {
uint32_t reserved2;
}ohci_td_item_t;
-typedef struct TU_ATTR_ALIGNED(16)
+typedef struct TU_ATTR_ALIGNED(CFG_TUH_MEM_DCACHE_ENABLE ? CFG_TUH_MEM_DCACHE_LINE_SIZE : 16)
{
// Word 0
uint32_t used : 1;
@@ -92,7 +117,7 @@ typedef struct TU_ATTR_ALIGNED(16)
uint8_t* buffer_end;
} ohci_gtd_t;
-TU_VERIFY_STATIC( sizeof(ohci_gtd_t) == 16, "size is not correct" );
+TU_VERIFY_STATIC( sizeof(ohci_gtd_t) == CFG_TUH_MEM_DCACHE_ENABLE ? CFG_TUH_MEM_DCACHE_LINE_SIZE : 16, "size is not correct" );
typedef struct TU_ATTR_ALIGNED(16)
{
@@ -129,7 +154,7 @@ typedef struct TU_ATTR_ALIGNED(16)
TU_VERIFY_STATIC( sizeof(ohci_ed_t) == 16, "size is not correct" );
-typedef struct TU_ATTR_ALIGNED(32)
+typedef struct TU_ATTR_ALIGNED(CFG_TUH_MEM_DCACHE_ENABLE ? CFG_TUH_MEM_DCACHE_LINE_SIZE : 32)
{
/*---------- Word 1 ----------*/
uint32_t starting_frame : 16;
@@ -152,7 +177,7 @@ typedef struct TU_ATTR_ALIGNED(32)
volatile uint16_t offset_packetstatus[8];
} ochi_itd_t;
-TU_VERIFY_STATIC( sizeof(ochi_itd_t) == 32, "size is not correct" );
+TU_VERIFY_STATIC( sizeof(ochi_itd_t) == CFG_TUH_MEM_DCACHE_ENABLE ? CFG_TUH_MEM_DCACHE_LINE_SIZE : 32, "size is not correct" );
typedef struct {
uint16_t expected_bytes; // up to 8192 bytes so max is 13 bits