From 90b276f6a2a9e197eadce297fd593d85397bc430 Mon Sep 17 00:00:00 2001 From: Taylor Hutt Date: Mon, 29 Oct 2012 05:23:59 +0000 Subject: ahci: flush / invalidate dcache around SATA commands Exynos5 automatically performs DMA when the SATA controller executes commands. This adds the necessary dcache-to-memory flush & invalidation calls to allow the DMA to properly function. Signed-off-by: Taylor Hutt Signed-off-by: Simon Glass --- drivers/block/ahci.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'drivers/block') diff --git a/drivers/block/ahci.c b/drivers/block/ahci.c index 00de086..a05d9cf 100644 --- a/drivers/block/ahci.c +++ b/drivers/block/ahci.c @@ -70,6 +70,39 @@ static void ahci_setup_port(struct ahci_ioports *port, unsigned long base, #define msleep(a) udelay(a * 1000) +static void ahci_dcache_flush_range(unsigned begin, unsigned len) +{ + const unsigned long start = begin; + const unsigned long end = start + len; + + debug("%s: flush dcache: [%#lx, %#lx)\n", __func__, start, end); + flush_dcache_range(start, end); +} + +/* + * SATA controller DMAs to physical RAM. Ensure data from the + * controller is invalidated from dcache; next access comes from + * physical RAM. + */ +static void ahci_dcache_invalidate_range(unsigned begin, unsigned len) +{ + const unsigned long start = begin; + const unsigned long end = start + len; + + debug("%s: invalidate dcache: [%#lx, %#lx)\n", __func__, start, end); + invalidate_dcache_range(start, end); +} + +/* + * Ensure data for SATA controller is flushed out of dcache and + * written to physical memory. + */ +static void ahci_dcache_flush_sata_cmd(struct ahci_ioports *pp) +{ + ahci_dcache_flush_range((unsigned long)pp->cmd_slot, + AHCI_PORT_PRIV_DMA_SZ); +} + static int waiting_for_cmd_completed(volatile u8 *offset, int timeout_msec, u32 sign) @@ -392,6 +425,7 @@ static void ahci_set_feature(u8 port) memcpy((unsigned char *)pp->cmd_tbl, fis, sizeof(fis)); ahci_fill_cmd_slot(pp, cmd_fis_len); + ahci_dcache_flush_sata_cmd(pp); writel(1, port_mmio + PORT_CMD_ISSUE); readl(port_mmio + PORT_CMD_ISSUE); @@ -496,12 +530,17 @@ static int ahci_device_data_io(u8 port, u8 *fis, int fis_len, u8 *buf, opts = (fis_len >> 2) | (sg_count << 16) | (is_write << 6); ahci_fill_cmd_slot(pp, opts); + ahci_dcache_flush_sata_cmd(pp); + ahci_dcache_flush_range((unsigned)buf, (unsigned)buf_len); + writel_with_flush(1, port_mmio + PORT_CMD_ISSUE); if (waiting_for_cmd_completed(port_mmio + PORT_CMD_ISSUE, 150, 0x1)) { printf("timeout exit!\n"); return -1; } + + ahci_dcache_invalidate_range((unsigned)buf, (unsigned)buf_len); debug("%s: %d byte transferred.\n", __func__, pp->cmd_slot->status); return 0; -- cgit v1.1