Skip to content

Commit 04240ad

Browse files
committed
pbio/drv: Handle cache ops for EV3 drivers
This allows the main memory to be write-back cached. Special note regarding DMA buffers and the uncached alias mapping: DMA buffers and uncached data cannot safely share cache lines with unrelated data! We use a special macro to align these buffers so that issues do not occur. If DMA RX buffers share cache lines with other data, it can lead to race conditions which corrupt data. If we flush and invalidate the cache before performing the DMA, reading the unrelated data can cause the cache line to be loaded back into cache, cancelling out the invalidation. If we wait until after performing the DMA and perform a flush and invalidate, the flush can corrupt part of the data which was written by the DMA. If we only perform an invalidate, writes to the unrelated data can be lost. A similar race condition can happen if an uncached alias is used to read/write to data which sits next to unrelated data. This currently applies to the ADC RX buffer. The USB driver's CPPI descriptors are safe as they happen to already be cache line aligned. The solution we use here is to place each buffer in its own cache-line-aligned block of memory and only perform an invalidate upon DMA completion. This makes sure that no unrelated data can get caught up in the same cache lines. This issue does not affect DMA TX buffers written using the normal cached mapping. Those are handled by flushing the cache.
1 parent 66b735e commit 04240ad

File tree

7 files changed

+79
-36
lines changed

7 files changed

+79
-36
lines changed

lib/pbio/drv/block_device/block_device_ev3.c

Lines changed: 55 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include "block_device_ev3.h"
3535

3636
#include <pbdrv/block_device.h>
37+
#include <pbdrv/cache.h>
3738
#include <pbdrv/clock.h>
3839
#include <pbdrv/compiler.h>
3940
#include <pbdrv/gpio.h>
@@ -93,17 +94,27 @@ enum {
9394
static struct {
9495
/** HAL Transfer status */
9596
volatile spi_status_t status;
96-
// This is used when SPI only needs to receive. It should always stay as 0.
97-
uint8_t tx_dummy_byte;
98-
// This is used when received data is to be discarded. Its value should be ignored.
99-
uint8_t rx_dummy_byte;
97+
// This stores the RX buffer address so that we clean the cache when DMA is complete
98+
uint32_t rx_user_buf_addr;
99+
// This stores the RX buffer size;
100+
uint32_t rx_user_buf_sz;
101+
} spi_dev;
102+
103+
/**
104+
* SPI small DMA buffers
105+
*/
106+
static struct {
100107
// This is used when transmitting so that the last byte clears CSHOLD.
101108
uint32_t tx_last_word;
102109
// This is used to hold the initial command to the SPI peripheral.
103110
uint8_t spi_cmd_buf_tx[SPI_CMD_BUF_SZ];
104111
// This is used to hold the replies to commands to the SPI peripheral.
105112
uint8_t spi_cmd_buf_rx[SPI_CMD_BUF_SZ];
106-
} spi_dev;
113+
// This is used when SPI only needs to receive. It should always stay as 0.
114+
uint8_t tx_dummy_byte;
115+
// This is used when received data is to be discarded. Its value should be ignored.
116+
uint8_t rx_dummy_byte;
117+
} spi_dev_bufs PBDRV_DMA_BUF;
107118

108119
static uint32_t last_spi_dma_complete_time;
109120

@@ -114,6 +125,10 @@ static void spi_dma_complete(void) {
114125
}
115126
SPIIntDisable(SOC_SPI_0_REGS, SPI_DMA_REQUEST_ENA_INT);
116127
pbio_os_request_poll();
128+
pbdrv_cache_prepare_after_dma(&spi_dev_bufs, sizeof(spi_dev_bufs));
129+
if (spi_dev.rx_user_buf_addr && spi_dev.rx_user_buf_sz) {
130+
pbdrv_cache_prepare_after_dma((void *)spi_dev.rx_user_buf_addr, spi_dev.rx_user_buf_sz);
131+
}
117132
last_spi_dma_complete_time = pbdrv_clock_get_ms();
118133
}
119134

@@ -153,7 +168,7 @@ static void spi0_isr(void) {
153168
continue;
154169
}
155170

156-
spi_dev.spi_cmd_buf_rx[0] = HWREG(SOC_SPI_0_REGS + SPI_SPIBUF);
171+
spi_dev_bufs.spi_cmd_buf_rx[0] = HWREG(SOC_SPI_0_REGS + SPI_SPIBUF);
157172
spi_dev.status &= ~SPI_STATUS_WAIT_RX;
158173
SPIIntDisable(SOC_SPI_0_REGS, SPI_RECV_INT);
159174
pbio_os_request_poll();
@@ -351,19 +366,24 @@ static pbio_error_t spi_begin_for_flash(
351366

352367
spi_dev.status = SPI_STATUS_WAIT_RX;
353368

369+
// Prevent write to spi_dev.status from being reordered
370+
pbdrv_compiler_memory_barrier();
371+
354372
uint32_t tx = spi0_last_dat1_for_flash(cmd[0]);
355373
SPIIntEnable(SOC_SPI_0_REGS, SPI_RECV_INT);
356374
HWREG(SOC_SPI_0_REGS + SPI_SPIDAT1) = tx;
357375
} else {
358-
memcpy(&spi_dev.spi_cmd_buf_tx, cmd, cmd_len);
376+
memcpy(spi_dev_bufs.spi_cmd_buf_tx, cmd, cmd_len);
377+
spi_dev.rx_user_buf_addr = (uint32_t)user_data_rx;
378+
spi_dev.rx_user_buf_sz = user_data_len;
359379

360380
if (user_data_len == 0) {
361381
// Only a command, no user data
362382

363-
spi_dev.tx_last_word = spi0_last_dat1_for_flash(cmd[cmd_len - 1]);
383+
spi_dev_bufs.tx_last_word = spi0_last_dat1_for_flash(cmd[cmd_len - 1]);
364384

365385
// TX everything except last byte
366-
ps.p.srcAddr = (unsigned int)(&spi_dev.spi_cmd_buf_tx);
386+
ps.p.srcAddr = (unsigned int)(&spi_dev_bufs.spi_cmd_buf_tx);
367387
ps.p.destAddr = SOC_SPI_0_REGS + SPI_SPIDAT1;
368388
ps.p.aCnt = 1;
369389
ps.p.bCnt = cmd_len - 1;
@@ -378,7 +398,7 @@ static pbio_error_t spi_begin_for_flash(
378398
edma3_set_param(EDMA3_CHA_SPI0_TX, &ps);
379399

380400
// TX last byte, clearing CSHOLD
381-
ps.p.srcAddr = (unsigned int)(&spi_dev.tx_last_word);
401+
ps.p.srcAddr = (unsigned int)(&spi_dev_bufs.tx_last_word);
382402
ps.p.aCnt = 4;
383403
ps.p.bCnt = 1;
384404
ps.p.linkAddr = 0xffff;
@@ -387,7 +407,7 @@ static pbio_error_t spi_begin_for_flash(
387407

388408
// RX all bytes
389409
ps.p.srcAddr = SOC_SPI_0_REGS + SPI_SPIBUF;
390-
ps.p.destAddr = (unsigned int)(&spi_dev.spi_cmd_buf_rx);
410+
ps.p.destAddr = (unsigned int)(&spi_dev_bufs.spi_cmd_buf_rx);
391411
ps.p.aCnt = 1;
392412
ps.p.bCnt = cmd_len;
393413
ps.p.cCnt = 1;
@@ -403,7 +423,7 @@ static pbio_error_t spi_begin_for_flash(
403423
// Command *and* user data
404424

405425
// TX the command
406-
ps.p.srcAddr = (unsigned int)(&spi_dev.spi_cmd_buf_tx);
426+
ps.p.srcAddr = (unsigned int)(&spi_dev_bufs.spi_cmd_buf_tx);
407427
ps.p.destAddr = SOC_SPI_0_REGS + SPI_SPIDAT1;
408428
ps.p.aCnt = 1;
409429
ps.p.bCnt = cmd_len;
@@ -418,7 +438,8 @@ static pbio_error_t spi_begin_for_flash(
418438
edma3_set_param(EDMA3_CHA_SPI0_TX, &ps);
419439

420440
if (user_data_tx) {
421-
spi_dev.tx_last_word = spi0_last_dat1_for_flash(user_data_tx[user_data_len - 1]);
441+
pbdrv_cache_prepare_before_dma(user_data_tx, user_data_len);
442+
spi_dev_bufs.tx_last_word = spi0_last_dat1_for_flash(user_data_tx[user_data_len - 1]);
422443

423444
// TX all but the last byte
424445
ps.p.srcAddr = (unsigned int)(user_data_tx);
@@ -427,24 +448,24 @@ static pbio_error_t spi_begin_for_flash(
427448
edma3_set_param(126, &ps);
428449

429450
// TX the last byte, clearing CSHOLD
430-
ps.p.srcAddr = (unsigned int)(&spi_dev.tx_last_word);
451+
ps.p.srcAddr = (unsigned int)(&spi_dev_bufs.tx_last_word);
431452
ps.p.aCnt = 4;
432453
ps.p.bCnt = 1;
433454
ps.p.linkAddr = 0xffff;
434455
ps.p.opt = EDMA3CC_OPT_TCINTEN | (EDMA3_CHA_SPI0_TX << EDMA3CC_OPT_TCC_SHIFT);
435456
edma3_set_param(127, &ps);
436457
} else {
437-
spi_dev.tx_last_word = spi0_last_dat1_for_flash(0);
458+
spi_dev_bufs.tx_last_word = spi0_last_dat1_for_flash(0);
438459

439460
// TX all but the last byte
440-
ps.p.srcAddr = (unsigned int)(&spi_dev.tx_dummy_byte);
461+
ps.p.srcAddr = (unsigned int)(&spi_dev_bufs.tx_dummy_byte);
441462
ps.p.bCnt = user_data_len - 1;
442463
ps.p.srcBIdx = 0;
443464
ps.p.linkAddr = 127 * 32;
444465
edma3_set_param(126, &ps);
445466

446467
// TX the last byte, clearing CSHOLD
447-
ps.p.srcAddr = (unsigned int)(&spi_dev.tx_last_word);
468+
ps.p.srcAddr = (unsigned int)(&spi_dev_bufs.tx_last_word);
448469
ps.p.aCnt = 4;
449470
ps.p.bCnt = 1;
450471
ps.p.linkAddr = 0xffff;
@@ -454,7 +475,7 @@ static pbio_error_t spi_begin_for_flash(
454475

455476
// RX the command
456477
ps.p.srcAddr = SOC_SPI_0_REGS + SPI_SPIBUF;
457-
ps.p.destAddr = (unsigned int)(&spi_dev.spi_cmd_buf_rx);
478+
ps.p.destAddr = (unsigned int)(&spi_dev_bufs.spi_cmd_buf_rx);
458479
ps.p.aCnt = 1;
459480
ps.p.bCnt = cmd_len;
460481
ps.p.cCnt = 1;
@@ -476,7 +497,7 @@ static pbio_error_t spi_begin_for_flash(
476497
edma3_set_param(125, &ps);
477498
} else {
478499
// RX dummy
479-
ps.p.destAddr = (unsigned int)(&spi_dev.rx_dummy_byte);
500+
ps.p.destAddr = (unsigned int)(&spi_dev_bufs.rx_dummy_byte);
480501
ps.p.bCnt = user_data_len;
481502
ps.p.destBIdx = 0;
482503
ps.p.linkAddr = 0xffff;
@@ -487,8 +508,9 @@ static pbio_error_t spi_begin_for_flash(
487508

488509
spi_dev.status = SPI_STATUS_WAIT_TX | SPI_STATUS_WAIT_RX;
489510

490-
// TODO: eventually needs DMA cache management
491-
pbdrv_compiler_memory_barrier();
511+
// Make sure writes to tx buffer leave cache
512+
// (we already flush the user buffer earlier)
513+
pbdrv_cache_prepare_before_dma(&spi_dev_bufs, sizeof(spi_dev_bufs));
492514

493515
EDMA3EnableTransfer(SOC_EDMA30CC_0_REGS, EDMA3_CHA_SPI0_TX, EDMA3_TRIG_MODE_EVENT);
494516
EDMA3EnableTransfer(SOC_EDMA30CC_0_REGS, EDMA3_CHA_SPI0_RX, EDMA3_TRIG_MODE_EVENT);
@@ -600,7 +622,7 @@ static pbio_error_t flash_wait_write(pbio_os_state_t *state) {
600622
}
601623
PBIO_OS_AWAIT_WHILE(state, spi_dev.status & SPI_STATUS_WAIT_ANY);
602624

603-
status = spi_dev.spi_cmd_buf_rx[1];
625+
status = spi_dev_bufs.spi_cmd_buf_rx[1];
604626
} while (status & FLASH_STATUS_BUSY);
605627

606628
PBIO_OS_ASYNC_END(PBIO_SUCCESS);
@@ -722,7 +744,7 @@ static const uint32_t channel_cmd[PBDRV_CONFIG_ADC_EV3_ADC_NUM_CHANNELS + PBDRV_
722744
MANUAL_ADC_CHANNEL(15),
723745
MANUAL_ADC_CHANNEL(15),
724746
};
725-
static volatile uint16_t channel_data[PBDRV_CONFIG_ADC_EV3_ADC_NUM_CHANNELS + PBDRV_ADC_EV3_NUM_DELAY_SAMPLES];
747+
static volatile uint16_t channel_data[PBDRV_CONFIG_ADC_EV3_ADC_NUM_CHANNELS + PBDRV_ADC_EV3_NUM_DELAY_SAMPLES] PBDRV_DMA_BUF;
726748

727749
pbio_error_t pbdrv_adc_get_ch(uint8_t ch, uint16_t *value) {
728750
if (ch >= PBDRV_CONFIG_ADC_EV3_ADC_NUM_CHANNELS) {
@@ -733,8 +755,8 @@ pbio_error_t pbdrv_adc_get_ch(uint8_t ch, uint16_t *value) {
733755
uint16_t a, b;
734756
do {
735757
// Values for the requested channel are received several samples later.
736-
a = channel_data[ch + PBDRV_ADC_EV3_NUM_DELAY_SAMPLES];
737-
b = channel_data[ch + PBDRV_ADC_EV3_NUM_DELAY_SAMPLES];
758+
a = PBDRV_UNCACHED(channel_data[ch + PBDRV_ADC_EV3_NUM_DELAY_SAMPLES]);
759+
b = PBDRV_UNCACHED(channel_data[ch + PBDRV_ADC_EV3_NUM_DELAY_SAMPLES]);
738760
} while (a != b);
739761

740762
// Mask the data to 10 bits
@@ -804,9 +826,14 @@ static pbio_error_t pbdrv_block_device_ev3_spi_begin_for_adc(const uint32_t *cmd
804826
ps.p.opt = EDMA3CC_OPT_TCINTEN | (EDMA3_CHA_SPI0_RX << EDMA3CC_OPT_TCC_SHIFT);
805827
edma3_set_param(EDMA3_CHA_SPI0_RX, &ps);
806828

829+
// We play dangerously and don't flush the cache for the ADC.
830+
// The commands are const, and the values are read through an uncached mapping.
831+
spi_dev.rx_user_buf_addr = 0;
832+
spi_dev.rx_user_buf_sz = 0;
833+
807834
spi_dev.status = SPI_STATUS_WAIT_TX | SPI_STATUS_WAIT_RX;
808835

809-
// TODO: eventually needs DMA cache management
836+
// Prevent write to spi_dev.status from being reordered
810837
pbdrv_compiler_memory_barrier();
811838

812839
EDMA3EnableTransfer(SOC_EDMA30CC_0_REGS, EDMA3_CHA_SPI0_TX, EDMA3_TRIG_MODE_EVENT);
@@ -836,7 +863,7 @@ static struct {
836863
pbsys_storage_data_map_t data_map;
837864
uint8_t data[PBDRV_CONFIG_BLOCK_DEVICE_RAM_SIZE];
838865
};
839-
} ramdisk __attribute__((section(".noinit"), used));
866+
} ramdisk __attribute__((aligned(PBDRV_CACHE_LINE_SZ), section(".noinit"), used));
840867

841868
uint32_t pbdrv_block_device_get_writable_size(void) {
842869
return PBDRV_CONFIG_BLOCK_DEVICE_EV3_SIZE - sizeof(ramdisk.saved_size);
@@ -869,7 +896,7 @@ pbio_error_t ev3_spi_process_thread(pbio_os_state_t *state, void *context) {
869896
return err;
870897
}
871898
PBIO_OS_AWAIT_WHILE(state, spi_dev.status & SPI_STATUS_WAIT_ANY);
872-
if (memcmp(device_id, &spi_dev.spi_cmd_buf_rx[1], sizeof(device_id))) {
899+
if (memcmp(device_id, spi_dev_bufs.spi_cmd_buf_rx[1], sizeof(device_id))) {
873900
return PBIO_ERROR_FAILED;
874901
}
875902

lib/pbio/drv/display/display_ev3.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <stdio.h>
1414
#include <string.h>
1515

16+
#include <pbdrv/cache.h>
1617
#include <pbdrv/display.h>
1718
#include <pbdrv/gpio.h>
1819

@@ -363,6 +364,8 @@ void pbdrv_display_st7586s_write_data_begin(uint8_t *data, uint32_t size) {
363364
spi_status = SPI_STATUS_WAIT;
364365
pbdrv_gpio_out_low(&pin_lcd_cs);
365366

367+
pbdrv_cache_prepare_before_dma(data, size);
368+
366369
// Parameter object must be volatile since it is copied byte-by-byte in the
367370
// TI API, causing it to be optimized out.
368371
volatile EDMA3CCPaRAMEntry paramSet = {

lib/pbio/drv/uart/uart_ev3.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <contiki.h>
1515
#include <contiki-lib.h>
1616

17+
#include <pbdrv/cache.h>
1718
#include <pbdrv/uart.h>
1819

1920
#include <pbio/busy_count.h>
@@ -220,6 +221,8 @@ pbio_error_t pbdrv_uart_write_hw(pbio_os_state_t *state, pbdrv_uart_dev_t *uart,
220221
.opt = EDMA3CC_OPT_DAM | ((pdata->sys_int_uart_tx_int_id << EDMA3CC_OPT_TCC_SHIFT) & EDMA3CC_OPT_TCC) | (1 << EDMA3CC_OPT_TCINTEN_SHIFT),
221222
};
222223

224+
pbdrv_cache_prepare_before_dma(uart->write_buf, length);
225+
223226
// Save configuration and start transfer.
224227
EDMA3SetPaRAM(SOC_EDMA30CC_0_REGS, pdata->sys_int_uart_tx_int_id, (EDMA3CCPaRAMEntry *)&paramSet);
225228
EDMA3EnableTransfer(SOC_EDMA30CC_0_REGS, pdata->sys_int_uart_tx_int_id, EDMA3_TRIG_MODE_EVENT);

lib/pbio/drv/usb/usb_ev3.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <string.h>
1414

1515
#include <pbdrv/bluetooth.h>
16+
#include <pbdrv/cache.h>
1617
#include <pbdrv/compiler.h>
1718
#include <pbdrv/usb.h>
1819
#include <pbio/os.h>
@@ -220,7 +221,7 @@ static bool pbdrv_usb_is_usb_hs;
220221
static bool pbdrv_usb_is_events_subscribed;
221222

222223
// Buffers, used for different logical flows on the data endpoint
223-
static uint8_t ep1_rx_buf[PYBRICKS_EP_PKT_SZ_HS];
224+
static uint8_t ep1_rx_buf[PYBRICKS_EP_PKT_SZ_HS] PBDRV_DMA_BUF;
224225
static uint8_t ep1_tx_response_buf[PYBRICKS_EP_PKT_SZ_HS];
225226
static uint8_t ep1_tx_status_buf[PYBRICKS_EP_PKT_SZ_HS];
226227
static uint8_t ep1_tx_stdout_buf[PYBRICKS_EP_PKT_SZ_HS];
@@ -283,7 +284,7 @@ static uint32_t cppi_linking_ram[CPPI_DESC_COUNT];
283284

284285
// Fill in the CPPI DMA descriptor to receive a packet
285286
static void usb_setup_rx_dma_desc(void) {
286-
cppi_descriptors[CPPI_DESC_RX] = (usb_cppi_hpd_t) {
287+
PBDRV_UNCACHED(cppi_descriptors[CPPI_DESC_RX]) = (usb_cppi_hpd_t) {
287288
.word0 = {
288289
.hostPktType = CPPI_HOST_PACKET_DESCRIPTOR_TYPE,
289290
},
@@ -307,7 +308,7 @@ static void usb_setup_rx_dma_desc(void) {
307308

308309
// Fill in the CPPI DMA descriptor to send a packet
309310
static void usb_setup_tx_dma_desc(int tx_type, void *buf, uint32_t buf_len) {
310-
cppi_descriptors[tx_type] = (usb_cppi_hpd_t) {
311+
PBDRV_UNCACHED(cppi_descriptors[tx_type]) = (usb_cppi_hpd_t) {
311312
.word0 = {
312313
.hostPktType = CPPI_HOST_PACKET_DESCRIPTOR_TYPE,
313314
.pktLength = buf_len,
@@ -904,11 +905,13 @@ static pbio_error_t pbdrv_usb_ev3_process_thread(pbio_os_state_t *state, void *c
904905
// (which is technically allowed by the as-if rule).
905906
pbdrv_compiler_memory_barrier();
906907

907-
uint32_t usb_rx_sz = cppi_descriptors[CPPI_DESC_RX].word0.pktLength;
908+
uint32_t usb_rx_sz = PBDRV_UNCACHED(cppi_descriptors[CPPI_DESC_RX].word0).pktLength;
908909
pbio_pybricks_error_t result;
909910
bool usb_send_response = false;
910911
// Skip empty commands, or commands sent when previous response is still busy
911912
if (usb_rx_sz && !usb_tx_response_is_not_ready) {
913+
pbdrv_cache_prepare_after_dma(ep1_rx_buf, sizeof(ep1_rx_buf));
914+
912915
switch (ep1_rx_buf[0]) {
913916
case PBIO_PYBRICKS_OUT_EP_MSG_SUBSCRIBE:
914917
pbio_os_timer_set(&keepalive_timer, 1000);
@@ -928,6 +931,7 @@ static pbio_error_t pbdrv_usb_ev3_process_thread(pbio_os_state_t *state, void *c
928931

929932
if (usb_send_response) {
930933
usb_tx_response_is_not_ready = true;
934+
pbdrv_cache_prepare_before_dma(ep1_tx_response_buf, sizeof(ep1_tx_response_buf));
931935
usb_setup_tx_dma_desc(CPPI_DESC_TX_RESPONSE, ep1_tx_response_buf, PBIO_PYBRICKS_USB_MESSAGE_SIZE(sizeof(uint32_t)));
932936
}
933937

@@ -944,6 +948,7 @@ static pbio_error_t pbdrv_usb_ev3_process_thread(pbio_os_state_t *state, void *c
944948
uint32_t usb_status_sz = PBIO_PYBRICKS_USB_MESSAGE_SIZE(pbsys_status_get_status_report(&ep1_tx_status_buf[1]));
945949

946950
usb_tx_status_is_not_ready = true;
951+
pbdrv_cache_prepare_before_dma(ep1_tx_status_buf, sizeof(ep1_tx_status_buf));
947952
usb_setup_tx_dma_desc(CPPI_DESC_TX_STATUS, ep1_tx_status_buf, usb_status_sz);
948953

949954
prev_status_flags = new_status_flags;
@@ -1124,6 +1129,7 @@ pbio_error_t pbdrv_usb_stdout_tx(const uint8_t *data, uint32_t *size) {
11241129
memcpy(ptr, data, *size);
11251130

11261131
usb_tx_stdout_is_not_ready = true;
1132+
pbdrv_cache_prepare_before_dma(ep1_tx_stdout_buf, sizeof(ep1_tx_stdout_buf));
11271133
usb_setup_tx_dma_desc(CPPI_DESC_TX_STDOUT, ep1_tx_stdout_buf, 2 + *size);
11281134

11291135
return PBIO_SUCCESS;

lib/pbio/include/pbdrv/cache.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,6 @@ void pbdrv_cache_prepare_after_dma(const void *buf, size_t sz);
2424
#define PBDRV_CACHE_LINE_SZ 32
2525

2626
// Align data to a cache line, which is needed for clean RX DMA
27-
#define PBDRV_CACHE_LINE_ALIGNED __attribute__((aligned(PBDRV_CACHE_LINE_SZ)))
27+
#define PBDRV_DMA_BUF __attribute__((aligned(PBDRV_CACHE_LINE_SZ), section(".dma")))
2828

2929
#endif

lib/pbio/platform/ev3/platform.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -721,8 +721,8 @@ static void mmu_init(void) {
721721
// Off-chip main DDR RAM
722722
for (unsigned int i = 0; i < SYSTEM_RAM_SZ_MB; i++) {
723723
uint32_t addr = 0xC0000000 + i * MMU_SECTION_SZ;
724-
// TODO: Enable caching once DMA code is upgraded to handle cache
725-
l1_page_table[addr >> MMU_SECTION_SHIFT] = MMU_L1_SECTION(addr, 0, 1, 0, 0);
724+
// Enable write-back caching
725+
l1_page_table[addr >> MMU_SECTION_SHIFT] = MMU_L1_SECTION(addr, 0, 1, 1, 1);
726726
}
727727
// Off-chip main DDR RAM, uncacheable mirror @ 0xD0000000
728728
for (unsigned int i = 0; i < SYSTEM_RAM_SZ_MB; i++) {

lib/pbio/platform/ev3/platform.ld

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,11 @@ SECTIONS
6666
_bss_start = .;
6767
*(.bss)
6868
*(.bss.*)
69-
. = ALIGN(4);
69+
/* Put DMA RX buffers here so that they never share cache lines with
70+
unrelated data. This makes sure that they can be invalidated properly. */
71+
. = ALIGN(32);
72+
*(.dma)
73+
. = ALIGN(32);
7074
_bss_end = .;
7175
} > DDR
7276

0 commit comments

Comments
 (0)