From 1b6e8cba62d0ea12bc39b0e3f60f66c3892ca1ff Mon Sep 17 00:00:00 2001 From: Amaury Pouly Date: Sun, 20 May 2012 01:23:17 +0200 Subject: imx233: make sure dma descriptors are cache friendly Because DMA descriptors needs to be committed and discarded from the cache, if they are not cache aligned and/or if their size is not a multiple of cache ligne, nasty side effects could occur with adjacents data. The same applies to DMA buffers which are still potentially broken. Add a macro to ensure that these constraints will not break by error in the future. Change-Id: I1dd69a5a9c29796c156d953eaa57c0d281e79846 --- firmware/export/imx233.h | 6 ++++++ firmware/target/arm/imx233/dma-imx233.h | 4 ++++ firmware/target/arm/imx233/i2c-imx233.c | 6 +++++- firmware/target/arm/imx233/pcm-imx233.c | 19 ++++++++++++++----- firmware/target/arm/imx233/ssp-imx233.c | 6 +++++- 5 files changed, 34 insertions(+), 7 deletions(-) diff --git a/firmware/export/imx233.h b/firmware/export/imx233.h index ba5ca7a284..70be3788ff 100644 --- a/firmware/export/imx233.h +++ b/firmware/export/imx233.h @@ -86,6 +86,12 @@ /* 32 bytes per cache line */ #define CACHEALIGN_BITS 5 +#define ___ENSURE_ZERO(line, x) static uint8_t __ensure_zero_##line[-(x)] __attribute__((unused)); +#define __ENSURE_ZERO(x) ___ENSURE_ZERO(__LINE__, x) +#define __ENSURE_MULTIPLE(x, y) __ENSURE_ZERO((x) % (y)) +#define __ENSURE_CACHELINE_MULTIPLE(x) __ENSURE_MULTIPLE(x, 1 << CACHEALIGN_BITS) +#define __ENSURE_STRUCT_CACHE_FRIENDLY(name) __ENSURE_CACHELINE_MULTIPLE(sizeof(name)) + #define __XTRACT(reg, field) ((reg & reg##__##field##_BM) >> reg##__##field##_BP) #define __XTRACT_EX(val, field) (((val) & field##_BM) >> field##_BP) #define __FIELD_SET(reg, field, val) reg = (reg & ~reg##__##field##_BM) | (val << reg##__##field##_BP) diff --git a/firmware/target/arm/imx233/dma-imx233.h b/firmware/target/arm/imx233/dma-imx233.h index fe220dc5f7..ee836c2186 100644 --- a/firmware/target/arm/imx233/dma-imx233.h +++ b/firmware/target/arm/imx233/dma-imx233.h @@ -118,6 +118,10 @@ * COMMON * **********/ +/* DMA structures should be cache aligned and be padded so that their size + * is a multiple of a cache line size. Otherwise some nasty side effects + * could occur with adjacents data fields. + * The same apply to DMA buffers for the same reasons */ struct apb_dma_command_t { struct apb_dma_command_t *next; diff --git a/firmware/target/arm/imx233/i2c-imx233.c b/firmware/target/arm/imx233/i2c-imx233.c index fd9801ec1d..0bf5213854 100644 --- a/firmware/target/arm/imx233/i2c-imx233.c +++ b/firmware/target/arm/imx233/i2c-imx233.c @@ -34,7 +34,11 @@ struct i2c_dma_command_t struct apb_dma_command_t dma; /* PIO words */ uint32_t ctrl0; -}; + /* padded to next multiple of cache line size (32 bytes) */ + uint32_t pad[4]; +} __attribute__((packed)) CACHEALIGN_ATTR; + +__ENSURE_STRUCT_CACHE_FRIENDLY(struct i2c_dma_command_t) #define I2C_NR_STAGES 4 /* Current transfer */ diff --git a/firmware/target/arm/imx233/pcm-imx233.c b/firmware/target/arm/imx233/pcm-imx233.c index e94260e457..5cce1591fa 100644 --- a/firmware/target/arm/imx233/pcm-imx233.c +++ b/firmware/target/arm/imx233/pcm-imx233.c @@ -26,8 +26,17 @@ #include "pcm-internal.h" #include "audioout-imx233.h" +struct pcm_dma_command_t +{ + struct apb_dma_command_t dma; + /* padded to next multiple of cache line size (32 bytes) */ + uint32_t pad[5]; +} __attribute__((packed)) CACHEALIGN_ATTR; + +__ENSURE_STRUCT_CACHE_FRIENDLY(struct pcm_dma_command_t) + static int locked = 0; -static struct apb_dma_command_t dac_dma; +static struct pcm_dma_command_t dac_dma; static bool pcm_freezed = false; /** @@ -37,14 +46,14 @@ static bool pcm_freezed = false; static void play(const void *addr, size_t size) { - dac_dma.next = NULL; - dac_dma.buffer = (void *)addr; - dac_dma.cmd = HW_APB_CHx_CMD__COMMAND__READ | + dac_dma.dma.next = NULL; + dac_dma.dma.buffer = (void *)addr; + dac_dma.dma.cmd = HW_APB_CHx_CMD__COMMAND__READ | HW_APB_CHx_CMD__IRQONCMPLT | HW_APB_CHx_CMD__SEMAPHORE | size << HW_APB_CHx_CMD__XFER_COUNT_BP; /* dma subsystem will make sure cached stuff is written to memory */ - imx233_dma_start_command(APB_AUDIO_DAC, &dac_dma); + imx233_dma_start_command(APB_AUDIO_DAC, &dac_dma.dma); } void INT_DAC_DMA(void) diff --git a/firmware/target/arm/imx233/ssp-imx233.c b/firmware/target/arm/imx233/ssp-imx233.c index 21dcba67aa..1b773a4dd0 100644 --- a/firmware/target/arm/imx233/ssp-imx233.c +++ b/firmware/target/arm/imx233/ssp-imx233.c @@ -43,7 +43,11 @@ struct ssp_dma_command_t uint32_t ctrl0; uint32_t cmd0; uint32_t cmd1; -}; + /* padded to next multiple of cache line size (32 bytes) */ + uint32_t pad[2]; +} __attribute__((packed)) CACHEALIGN_ATTR; + +__ENSURE_STRUCT_CACHE_FRIENDLY(struct ssp_dma_command_t) static bool ssp_in_use[2]; static int ssp_nr_in_use = 0; -- cgit v1.2.3