Patchwork [U-Boot,v3,16/22] ahci: flush / invalidate dcache around SATA commands

login
register
mail settings
Submitter Simon Glass
Date Oct. 29, 2012, 3:23 p.m.
Message ID <1351524245-19584-17-git-send-email-sjg@chromium.org>
Download mbox | patch
Permalink /patch/195042/
State Accepted, archived
Delegated to: Tom Rini
Headers show

Comments

Simon Glass - Oct. 29, 2012, 3:23 p.m.
From: Taylor Hutt <thutt@chromium.org>

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 <thutt@chromium.org>
Signed-off-by: Simon Glass <sjg@chromium.org>
---

 drivers/block/ahci.c |   39 +++++++++++++++++++++++++++++++++++++++
 1 files changed, 39 insertions(+), 0 deletions(-)

Patch

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;