All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jan Glauber <jglauber@cavium.com>
To: Ulf Hansson <ulf.hansson@linaro.org>
Cc: linux-mmc@vger.kernel.org, linux-kernel@vger.kernel.org,
	David Daney <ddaney@caviumnetworks.com>,
	"Steven J . Hill" <Steven.Hill@cavium.com>,
	Jan Glauber <jglauber@cavium.com>
Subject: [PATCH v10 3/8] mmc: octeon: Work-around hardware bug on cn6xxx and cnf7xxx
Date: Mon, 19 Dec 2016 13:15:47 +0100	[thread overview]
Message-ID: <20161219121552.18316-4-jglauber@cavium.com> (raw)
In-Reply-To: <20161219121552.18316-1-jglauber@cavium.com>

Prevent data corruption on cn6xxx and cnf7xxx.
Due to an imperfection in the design of the MMC bus hardware,
the 2nd to last cache block of a DMA read must be locked into the L2
cache.

Signed-off-by: Jan Glauber <jglauber@cavium.com>
---
 arch/mips/cavium-octeon/Makefile      |  1 +
 arch/mips/cavium-octeon/octeon-mmc.c  | 98 +++++++++++++++++++++++++++++++++++
 drivers/mmc/host/cavium_core_mmc.c    |  5 ++
 drivers/mmc/host/cavium_mmc.h         |  5 ++
 drivers/mmc/host/octeon_platdrv_mmc.c | 30 +++++++++++
 5 files changed, 139 insertions(+)
 create mode 100644 arch/mips/cavium-octeon/octeon-mmc.c

diff --git a/arch/mips/cavium-octeon/Makefile b/arch/mips/cavium-octeon/Makefile
index 2a59265..5f09d26 100644
--- a/arch/mips/cavium-octeon/Makefile
+++ b/arch/mips/cavium-octeon/Makefile
@@ -18,3 +18,4 @@ obj-y += crypto/
 obj-$(CONFIG_MTD)		      += flash_setup.o
 obj-$(CONFIG_SMP)		      += smp.o
 obj-$(CONFIG_OCTEON_ILM)	      += oct_ilm.o
+obj-$(CONFIG_MMC_OCTEON)	      += octeon-mmc.o
diff --git a/arch/mips/cavium-octeon/octeon-mmc.c b/arch/mips/cavium-octeon/octeon-mmc.c
new file mode 100644
index 0000000..6aaaf73
--- /dev/null
+++ b/arch/mips/cavium-octeon/octeon-mmc.c
@@ -0,0 +1,98 @@
+/*
+ * Driver for MMC and SSD cards for Cavium OCTEON SOCs.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2012-2016 Cavium Inc.
+ */
+#include <linux/export.h>
+#include <asm/octeon/octeon.h>
+
+/*
+ * The functions below are used for the EMMC-17978 workaround.
+ *
+ * Due to an imperfection in the design of the MMC bus hardware,
+ * the 2nd to last cache block of a DMA read must be locked into the L2 Cache.
+ * Otherwise, data corruption may occur.
+ */
+
+static inline void *phys_to_ptr(u64 address)
+{
+	return (void *)(address | (1ull << 63)); /* XKPHYS */
+}
+
+/**
+ * Lock a single line into L2. The line is zeroed before locking
+ * to make sure no dram accesses are made.
+ *
+ * @addr   Physical address to lock
+ */
+static void l2c_lock_line(u64 addr)
+{
+	char *addr_ptr = phys_to_ptr(addr);
+
+	asm volatile (
+		"cache 31, %[line]"	/* Unlock the line */
+		:: [line] "m" (*addr_ptr));
+}
+
+/**
+ * Unlock a single line in the L2 cache.
+ *
+ * @addr	Physical address to unlock
+ *
+ * Return Zero on success
+ */
+static void l2c_unlock_line(u64 addr)
+{
+	char *addr_ptr = phys_to_ptr(addr);
+
+	asm volatile (
+		"cache 23, %[line]"	/* Unlock the line */
+		:: [line] "m" (*addr_ptr));
+}
+
+/**
+ * Locks a memory region in the L2 cache
+ *
+ * @start - start address to begin locking
+ * @len - length in bytes to lock
+ */
+void l2c_lock_mem_region(u64 start, u64 len)
+{
+	u64 end;
+
+	/* Round start/end to cache line boundaries */
+	end = ALIGN(start + len - 1, CVMX_CACHE_LINE_SIZE);
+	start = ALIGN(start, CVMX_CACHE_LINE_SIZE);
+
+	while (start <= end) {
+		l2c_lock_line(start);
+		start += CVMX_CACHE_LINE_SIZE;
+	}
+	asm volatile("sync");
+}
+EXPORT_SYMBOL_GPL(l2c_lock_mem_region);
+
+/**
+ * Unlock a memory region in the L2 cache
+ *
+ * @start - start address to unlock
+ * @len - length to unlock in bytes
+ */
+void l2c_unlock_mem_region(u64 start, u64 len)
+{
+	u64 end;
+
+	/* Round start/end to cache line boundaries */
+	end = ALIGN(start + len - 1, CVMX_CACHE_LINE_SIZE);
+	start = ALIGN(start, CVMX_CACHE_LINE_SIZE);
+
+	while (start <= end) {
+		l2c_unlock_line(start);
+		start += CVMX_CACHE_LINE_SIZE;
+	}
+}
+EXPORT_SYMBOL_GPL(l2c_unlock_mem_region);
diff --git a/drivers/mmc/host/cavium_core_mmc.c b/drivers/mmc/host/cavium_core_mmc.c
index 89d23d3..1bdba06 100644
--- a/drivers/mmc/host/cavium_core_mmc.c
+++ b/drivers/mmc/host/cavium_core_mmc.c
@@ -438,6 +438,8 @@ irqreturn_t cvm_mmc_interrupt(int irq, void *dev_id)
 	req->done(req);
 
 no_req_done:
+	if (host->dmar_fixup_done)
+		host->dmar_fixup_done(host);
 	if (host_done)
 		host->release_bus(host);
 out:
@@ -558,6 +560,9 @@ static void cvm_mmc_dma_request(struct mmc_host *mmc,
 	host->dma_active = true;
 	host->int_enable(host, emm_int.val);
 
+	if (host->dmar_fixup)
+		host->dmar_fixup(host, mrq->cmd, data, addr);
+
 	/*
 	 * If we have a valid SD card in the slot, we set the response
 	 * bit mask to check for CRC errors and timeouts only.
diff --git a/drivers/mmc/host/cavium_mmc.h b/drivers/mmc/host/cavium_mmc.h
index e900dd1..f350212 100644
--- a/drivers/mmc/host/cavium_mmc.h
+++ b/drivers/mmc/host/cavium_mmc.h
@@ -40,6 +40,7 @@ struct cvm_mmc_host {
 	void __iomem *base;
 	void __iomem *dma_base;
 	u64 emm_cfg;
+	u64 n_minus_one;	/* OCTEON II workaround location */
 	int last_slot;
 	struct clk *clk;
 	int sys_freq;
@@ -55,6 +56,10 @@ struct cvm_mmc_host {
 	void (*acquire_bus)(struct cvm_mmc_host *);
 	void (*release_bus)(struct cvm_mmc_host *);
 	void (*int_enable)(struct cvm_mmc_host *, u64);
+	/* required on some MIPS models */
+	void (*dmar_fixup)(struct cvm_mmc_host *, struct mmc_command *,
+			   struct mmc_data *, u64);
+	void (*dmar_fixup_done)(struct cvm_mmc_host *);
 };
 
 struct cvm_mmc_slot {
diff --git a/drivers/mmc/host/octeon_platdrv_mmc.c b/drivers/mmc/host/octeon_platdrv_mmc.c
index f3f6581..59b73fb 100644
--- a/drivers/mmc/host/octeon_platdrv_mmc.c
+++ b/drivers/mmc/host/octeon_platdrv_mmc.c
@@ -20,6 +20,9 @@
 
 #define CVMX_MIO_BOOT_CTL CVMX_ADD_IO_SEG(0x00011800000000D0ull)
 
+extern void l2c_lock_mem_region(u64 start, u64 len);
+extern void l2c_unlock_mem_region(u64 start, u64 len);
+
 static void octeon_mmc_acquire_bus(struct cvm_mmc_host *host)
 {
 	/* Switch the MMC controller onto the bus. */
@@ -38,6 +41,28 @@ static void octeon_mmc_int_enable(struct cvm_mmc_host *host, u64 val)
 	writeq(val, host->base + MIO_EMM_INT_EN);
 }
 
+static void octeon_mmc_dmar_fixup(struct cvm_mmc_host *host,
+				  struct mmc_command *cmd,
+				  struct mmc_data *data,
+				  u64 addr)
+{
+	if (cmd->opcode != MMC_WRITE_MULTIPLE_BLOCK)
+		return;
+	if (data->blksz * data->blocks <= 1024)
+		return;
+
+	host->n_minus_one = addr + (data->blksz * data->blocks) - 1024;
+	l2c_lock_mem_region(host->n_minus_one, 512);
+}
+
+static void octeon_mmc_dmar_fixup_done(struct cvm_mmc_host *host)
+{
+	if (!host->n_minus_one)
+		return;
+	l2c_unlock_mem_region(host->n_minus_one, 512);
+	host->n_minus_one = 0;
+}
+
 static int octeon_mmc_probe(struct platform_device *pdev)
 {
 	struct device_node *cn, *node = pdev->dev.of_node;
@@ -56,6 +81,11 @@ static int octeon_mmc_probe(struct platform_device *pdev)
 	host->acquire_bus = octeon_mmc_acquire_bus;
 	host->release_bus = octeon_mmc_release_bus;
 	host->int_enable = octeon_mmc_int_enable;
+	if (OCTEON_IS_MODEL(OCTEON_CN6XXX) ||
+	    OCTEON_IS_MODEL(OCTEON_CNF7XXX)) {
+		host->dmar_fixup = octeon_mmc_dmar_fixup;
+		host->dmar_fixup_done = octeon_mmc_dmar_fixup_done;
+	}
 
 	host->sys_freq = octeon_get_io_clock_rate();
 
-- 
2.9.0.rc0.21.g7777322

  parent reply	other threads:[~2016-12-19 12:18 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-12-19 12:15 [PATCH v10 0/8] Cavium MMC driver Jan Glauber
2016-12-19 12:15 ` [PATCH v10 1/8] mmc: cavium: Add core MMC driver for Cavium SOCs Jan Glauber
2016-12-19 12:15 ` [PATCH v10 2/8] mmc: octeon: Add MMC platform driver for Octeon SOCs Jan Glauber
2016-12-19 12:15 ` Jan Glauber [this message]
2016-12-19 12:15 ` [PATCH v10 4/8] mmc: octeon: Add support for Octeon cn7890 Jan Glauber
2016-12-19 12:15 ` [PATCH v10 5/8] mmc: thunderx: Add MMC PCI driver for ThunderX SOCs Jan Glauber
2016-12-19 12:15 ` [PATCH v10 6/8] mmc: thunderx: Add scatter-gather DMA support Jan Glauber
2016-12-19 12:15 ` [PATCH v10 7/8] mmc: thunderx: Support DDR mode for eMMC devices Jan Glauber
2016-12-19 12:15 ` [PATCH v10 8/8] dt-bindings: mmc: Add Cavium SOCs MMC bindings Jan Glauber
2016-12-22 20:32   ` Rob Herring
2016-12-22 20:32     ` Rob Herring
2017-01-09 15:05     ` Jan Glauber
2017-01-09 15:05       ` Jan Glauber
2016-12-20 12:10 ` [PATCH v10 0/8] Cavium MMC driver Ulf Hansson
2016-12-20 12:24   ` Jan Glauber
2016-12-20 12:38     ` Ulf Hansson
2017-01-19 14:50   ` Jan Glauber
2017-01-19 17:47     ` David Daney
2017-01-20 10:37       ` Jan Glauber
2017-01-19 21:38     ` Ulf Hansson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20161219121552.18316-4-jglauber@cavium.com \
    --to=jglauber@cavium.com \
    --cc=Steven.Hill@cavium.com \
    --cc=ddaney@caviumnetworks.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mmc@vger.kernel.org \
    --cc=ulf.hansson@linaro.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.