Search code examples
cachingarmstm32cpu-cachecortex-m

ARM Cortex M7: can a cache clean overwrite changes made by DMA device?


I am developing a driver for a DMA bus master device in the STM32H743 SoC, powered by a Cortex M7 CPU. Suppose I have two memory locations, x and y, which map to the same cache line, which is in normal, write-back cacheable memory, and suppose the following sequence of events:

  1. Start with x = x1, y = y1, cache line invalid.
  2. CPU reads y
  3. DMA device sets x = x2, in memory
  4. CPU sets y = y2
  5. CPU cleans the cache line.

After 5. completes, from the point of view of the DMA device, x = ?

I think the DMA will see x = x1, here is my reasoning:

  • When CPU reads y in 2., the cache line gets pulled in cache. It reads x = x1, y = y1, and is marked as valid.
  • The DMA then updates x in memory, but the change is not reflected in the cache line.
  • When the CPU sets y = y2, the cache line is marked as dirty.
  • When the CPU cleans the cache line, as it is dirty it gets written back to memory.
  • When it gets written back to memory, it reads x = x1, y = y2, thus overwriting the change made by the DMA to x.

Does that sound like a good reasoning?


Solution

  • Shortly, if I get your question right, than yes, your description is correct.

    It's not very clear from question what "two memory locations, x and y".

    Based on how you put them in use in description, I'd presume that it's something like 2 pointers.

    int* x, y;
    

    and "Start with x = x1, y = y1" means assigning addresses to that pointers, eg

    x = (int*)(0x2000); // x = x1
    y = (int*)(0x8000); // y = y1
    

    Now to your question: "After 5. completes, from the point of view of the DMA device, x = ?"

    So after step 3, x = x2, y = y1 in memory, x = x1, y == y1 in cache.

    After step 4, x = x2, y = y1 in memory, x = x1, y = y2 in cache.

    DMA access values of x/y pointers in memory, CPU access value of x/y pointers in cache. Because cache and memory are not in sync (cache is dirty) at that stage CPU and DMA would get different values.

    And finally after step 5...
    It depends. Cache controller operates by cache lines, an area of memory of some size, something like 32Bytes, 64Bytes, etc (could be bigger or smaller). So when CPU does clean/flush cache line containing some address it flushes a content of a whole cache line to memory. Whatever was in memory is overwritten.

    There are basically 2 situations:

    • x and y pointers are both in same cache line. That means values from cache would override memory and, you are correct, that x = x1, y == y2 would finish in memory and cache after that.
    • x and y pointers are in different cache lines. That simple, only one variable would be affected, another cache line still is dirty.