@@ -61,6 +61,31 @@ typedef struct {
6161
6262TU_VERIFY_STATIC ( sizeof (ohci_hcca_t ) ==  256 , "size is not correct"  );
6363
64+ // An OHCI host controller is controlled using data structures placed in memory (RAM). 
65+ // It needs to both read and write these data structures (as defined by the OHCI specification), 
66+ // and this can be mentally conceptualized similar to two software threads running on 
67+ // two different CPUs. In order to prevent a _data race_ where data gets corrupted, 
68+ // the CPU and the OHCI host controller need to agree on how the memory should be accessed. 
69+ // In this driver, we do this by transferring logical ownership of transfer descriptors (TDs) 
70+ // between the CPU and the OHCI host controller. Only the device which holds the logical ownership 
71+ // is allowed to read or write the TD. This ownership is not visible anywhere in the code, 
72+ // but it instead must be inferred based on the logical state of the transfer. 
73+ // 
74+ // If dcache-supporting mode is enabled, we need to do additional manual cache operations 
75+ // in order to correctly transfer this logical ownership and prevent data corruption. 
76+ // In order to do this, we also choose to align each OHCI TD so that it doesn't 
77+ // share CPU cache lines with other TDs. This is because manual cache operations 
78+ // can only be performed on cache line granularity. In other words, one cache line is 
79+ // the _smallest_ amount that can be read/written at a time. If there were to be multiple TDs 
80+ // in the same cache line, they would be required to always have the same logical ownership. 
81+ // This ends up being impossible to guarantee, so we choose a design which avoids the situation entirely. 
82+ // 
83+ // TDs have a minimum alignment requirement according to the OHCI specification. This is 16 bytes for 
84+ // a general TD but 32 bytes for an isochronous TD. It happens that typical CPU cache line sizes are usually 
85+ // a power of 2 at least 32. In order to simplify code later in this file, we assume this 
86+ // as an additional requirement. 
87+ TU_VERIFY_STATIC ( (CFG_TUH_MEM_DCACHE_ENABLE  ? CFG_TUH_MEM_DCACHE_LINE_SIZE  : 0 ) % 32  ==  0 , "cache line not multiple of 32"  );
88+ 
6489// common link item for gtd and itd for list travel 
6590// use as pointer only 
6691typedef  struct  TU_ATTR_ALIGNED (16 ) {
@@ -69,7 +94,7 @@ typedef struct TU_ATTR_ALIGNED(16) {
6994  uint32_t  reserved2 ;
7095}ohci_td_item_t ;
7196
72- typedef  struct  TU_ATTR_ALIGNED (16 )
97+ typedef  struct  TU_ATTR_ALIGNED (CFG_TUH_MEM_DCACHE_ENABLE  ?  CFG_TUH_MEM_DCACHE_LINE_SIZE  :  16 )
7398{
7499	// Word 0 
75100	uint32_t  used                     : 1 ;
@@ -92,7 +117,7 @@ typedef struct TU_ATTR_ALIGNED(16)
92117	uint8_t *  buffer_end ;
93118} ohci_gtd_t ;
94119
95- TU_VERIFY_STATIC ( sizeof (ohci_gtd_t ) ==  16 , "size is not correct"  );
120+ TU_VERIFY_STATIC ( sizeof (ohci_gtd_t ) ==  CFG_TUH_MEM_DCACHE_ENABLE  ?  CFG_TUH_MEM_DCACHE_LINE_SIZE  :  16 , "size is not correct"  );
96121
97122typedef  struct  TU_ATTR_ALIGNED (16 )
98123{
@@ -129,7 +154,7 @@ typedef struct TU_ATTR_ALIGNED(16)
129154
130155TU_VERIFY_STATIC ( sizeof (ohci_ed_t ) ==  16 , "size is not correct"  );
131156
132- typedef  struct  TU_ATTR_ALIGNED (32 )
157+ typedef  struct  TU_ATTR_ALIGNED (CFG_TUH_MEM_DCACHE_ENABLE  ?  CFG_TUH_MEM_DCACHE_LINE_SIZE  :  32 )
133158{
134159	/*---------- Word 1 ----------*/ 
135160  uint32_t  starting_frame           : 16 ;
@@ -152,7 +177,7 @@ typedef struct TU_ATTR_ALIGNED(32)
152177	volatile  uint16_t  offset_packetstatus [8 ];
153178} ochi_itd_t ;
154179
155- TU_VERIFY_STATIC ( sizeof (ochi_itd_t ) ==  32 , "size is not correct"  );
180+ TU_VERIFY_STATIC ( sizeof (ochi_itd_t ) ==  CFG_TUH_MEM_DCACHE_ENABLE  ?  CFG_TUH_MEM_DCACHE_LINE_SIZE  :  32 , "size is not correct"  );
156181
157182typedef  struct  {
158183  uint16_t  expected_bytes ; // up to 8192 bytes so max is 13 bits 
0 commit comments