linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v11 0/9] Cavium MMC driver
@ 2017-02-06 13:39 Jan Glauber
  2017-02-06 13:39 ` [PATCH v11 1/9] dt-bindings: mmc: Add Cavium SOCs MMC bindings Jan Glauber
                   ` (8 more replies)
  0 siblings, 9 replies; 24+ messages in thread
From: Jan Glauber @ 2017-02-06 13:39 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc, linux-kernel, David Daney, Steven J . Hill, Jan Glauber

Hi Ulf,

I've implemented the fixed regulator support as requested. Nevertheless
we need to keep the code for the global power gpio around because that
will still be used by existing Octeon systems (where we can't update the DT).

I've kept the dummy device approach for mmc_of_parse() and devm*,
because a device per child node is required and while we could adopt
mmc_of_parse() we can't change the devm* functions. So I don't see a better
solution at the moment.

Patches are against linux-next.

Changes to v10:
- Renamed files to get a common prefix
- Select GPIO driver in Kconfig
- Support a fixed regulator
- dts: fixed quotes and re-ordered example
- Use new MMC_CAP_3_3V_DDR instead of 1_8V hack
- Use blksz instead of now internal mmc_card_blockaddr
- Added some maintainers

Previous versions:
v10: https://www.mail-archive.com/linux-kernel@vger.kernel.org/msg1295316.html
v9:  http://marc.info/?l=linux-mmc&m=147431759215233&w=2

Cheers,
Jan

-----------

Jan Glauber (9):
  dt-bindings: mmc: Add Cavium SOCs MMC bindings
  mmc: cavium: Add core MMC driver for Cavium SOCs
  mmc: cavium: Add MMC platform driver for Octeon SOCs
  mmc: cavium: Work-around hardware bug on cn6xxx and cnf7xxx
  mmc: cavium: Add support for Octeon cn7890
  mmc: cavium: Add MMC PCI driver for ThunderX SOCs
  mmc: cavium: Add scatter-gather DMA support
  mmc: cavium: Support DDR mode for eMMC devices
  MAINTAINERS: Add entry for Cavium MMC driver

 .../devicetree/bindings/mmc/cavium-mmc.txt         |   60 +
 MAINTAINERS                                        |    8 +
 arch/mips/cavium-octeon/Makefile                   |    1 +
 arch/mips/cavium-octeon/octeon-mmc-l2c.c           |   98 ++
 drivers/mmc/host/Kconfig                           |   20 +
 drivers/mmc/host/Makefile                          |    4 +
 drivers/mmc/host/cavium-mmc.c                      | 1157 ++++++++++++++++++++
 drivers/mmc/host/cavium-mmc.h                      |  429 ++++++++
 drivers/mmc/host/cavium-pci-thunderx.c             |  206 ++++
 drivers/mmc/host/cavium-pltfm-octeon.c             |  258 +++++
 10 files changed, 2241 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mmc/cavium-mmc.txt
 create mode 100644 arch/mips/cavium-octeon/octeon-mmc-l2c.c
 create mode 100644 drivers/mmc/host/cavium-mmc.c
 create mode 100644 drivers/mmc/host/cavium-mmc.h
 create mode 100644 drivers/mmc/host/cavium-pci-thunderx.c
 create mode 100644 drivers/mmc/host/cavium-pltfm-octeon.c

-- 
2.9.0.rc0.21.g7777322

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH v11 1/9] dt-bindings: mmc: Add Cavium SOCs MMC bindings
  2017-02-06 13:39 [PATCH v11 0/9] Cavium MMC driver Jan Glauber
@ 2017-02-06 13:39 ` Jan Glauber
  2017-02-09  0:40   ` Rob Herring
  2017-03-03 11:47   ` Ulf Hansson
  2017-02-06 13:39 ` [PATCH v11 2/9] mmc: cavium: Add core MMC driver for Cavium SOCs Jan Glauber
                   ` (7 subsequent siblings)
  8 siblings, 2 replies; 24+ messages in thread
From: Jan Glauber @ 2017-02-06 13:39 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc, linux-kernel, David Daney, Steven J . Hill,
	Jan Glauber, Rob Herring, Mark Rutland, devicetree, David Daney,
	Steven J . Hill

Add description of Cavium Octeon and ThunderX SOC device tree bindings.

CC: Ulf Hansson <ulf.hansson@linaro.org>
CC: Rob Herring <robh+dt@kernel.org>
CC: Mark Rutland <mark.rutland@arm.com>
CC: devicetree@vger.kernel.org

Signed-off-by: Jan Glauber <jglauber@cavium.com>
Signed-off-by: David Daney <david.daney@cavium.com>
Signed-off-by: Steven J. Hill <steven.hill@cavium.com>
---
 .../devicetree/bindings/mmc/cavium-mmc.txt         | 60 ++++++++++++++++++++++
 1 file changed, 60 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mmc/cavium-mmc.txt

diff --git a/Documentation/devicetree/bindings/mmc/cavium-mmc.txt b/Documentation/devicetree/bindings/mmc/cavium-mmc.txt
new file mode 100644
index 0000000..b79e356
--- /dev/null
+++ b/Documentation/devicetree/bindings/mmc/cavium-mmc.txt
@@ -0,0 +1,60 @@
+* Cavium Octeon & ThunderX MMC controller
+
+The highspeed MMC host controller on Caviums SoCs provides an interface
+for MMC and SD types of memory cards.
+
+Supported maximum speeds are the ones of the eMMC standard 4.41 as well
+as the speed of SD standard 4.0. Only 3.3 Volt is supported.
+
+Required properties:
+ - compatible : should be one of:
+   cavium,octeon-6130-mmc
+   cavium,octeon-6130-mmc-slot
+   cavium,octeon-7890-mmc
+   cavium,octeon-7890-mmc-slot
+   cavium,thunder-8190-mmc
+   cavium,thunder-8190-mmc-slot
+   cavium,thunder-8390-mmc
+   cavium,thunder-8390-mmc-slot
+ - reg : mmc controller base registers
+ - clocks : phandle
+
+Optional properties:
+ - for cd, bus-width and additional generic mmc parameters
+   please refer to mmc.txt within this directory
+ - cavium,cmd-clk-skew : number of coprocessor clocks before sampling command
+ - cavium,dat-clk-skew : number of coprocessor clocks before sampling data
+
+Deprecated properties:
+- spi-max-frequency : use max-frequency instead
+- cavium,bus-max-width : use bus-width instead
+
+Examples:
+	mmc_1_4: mmc@1,4 {
+		compatible = "cavium,thunder-8390-mmc";
+		reg = <0x0c00 0 0 0 0>;	/* DEVFN = 0x0c (1:4) */
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clocks = <&sclk>;
+
+		mmc-slot@0 {
+			compatible = "cavium,thunder-8390-mmc-slot";
+			reg = <0>;
+			voltage-ranges = <3300 3300>;
+			vmmc-supply = <&mmc_supply_3v3>;
+			max-frequency = <42000000>;
+			bus-width = <4>;
+			cap-sd-highspeed;
+		};
+
+		mmc-slot@1 {
+			compatible = "cavium,thunder-8390-mmc-slot";
+			reg = <1>;
+			voltage-ranges = <3300 3300>;
+			vmmc-supply = <&mmc_supply_3v3>;
+			max-frequency = <42000000>;
+			bus-width = <8>;
+			cap-mmc-highspeed;
+			non-removable;
+		};
+	};
-- 
2.9.0.rc0.21.g7777322

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v11 2/9] mmc: cavium: Add core MMC driver for Cavium SOCs
  2017-02-06 13:39 [PATCH v11 0/9] Cavium MMC driver Jan Glauber
  2017-02-06 13:39 ` [PATCH v11 1/9] dt-bindings: mmc: Add Cavium SOCs MMC bindings Jan Glauber
@ 2017-02-06 13:39 ` Jan Glauber
  2017-03-03 11:47   ` Ulf Hansson
  2017-02-06 13:39 ` [PATCH v11 3/9] mmc: cavium: Add MMC platform driver for Octeon SOCs Jan Glauber
                   ` (6 subsequent siblings)
  8 siblings, 1 reply; 24+ messages in thread
From: Jan Glauber @ 2017-02-06 13:39 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc, linux-kernel, David Daney, Steven J . Hill,
	Jan Glauber, David Daney, Steven J . Hill

This core driver will be used by a MIPS platform driver
or by an ARM64 PCI driver. The core driver implements the
mmc_host_ops and slot probe & remove functions.
Callbacks are provided to allow platform specific interrupt
enable and bus locking.

The host controller supports:
- up to 4 slots that can contain sd-cards or eMMC chips
- 1, 4 and 8 bit bus width
- SDR and DDR
- transfers up to 52 Mhz (might be less when multiple slots are used)
- DMA read/write
- multi-block read/write (but not stream mode)

Voltage is limited to 3.3v and shared for all slots.

A global lock for all MMC devices is required because the host
controller is shared.

Signed-off-by: Jan Glauber <jglauber@cavium.com>
Signed-off-by: David Daney <david.daney@cavium.com>
Signed-off-by: Steven J. Hill <steven.hill@cavium.com>
---
 drivers/mmc/host/cavium-mmc.c | 1029 +++++++++++++++++++++++++++++++++++++++++
 drivers/mmc/host/cavium-mmc.h |  303 ++++++++++++
 2 files changed, 1332 insertions(+)
 create mode 100644 drivers/mmc/host/cavium-mmc.c
 create mode 100644 drivers/mmc/host/cavium-mmc.h

diff --git a/drivers/mmc/host/cavium-mmc.c b/drivers/mmc/host/cavium-mmc.c
new file mode 100644
index 0000000..40aee08
--- /dev/null
+++ b/drivers/mmc/host/cavium-mmc.c
@@ -0,0 +1,1029 @@
+/*
+ * Shared part of driver for MMC/SDHC controller on Cavium OCTEON and
+ * ThunderX 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.
+ * Authors:
+ *   David Daney <david.daney@cavium.com>
+ *   Peter Swain <pswain@cavium.com>
+ *   Steven J. Hill <steven.hill@cavium.com>
+ *   Jan Glauber <jglauber@cavium.com>
+ */
+#include <linux/delay.h>
+#include <linux/dma-direction.h>
+#include <linux/dma-mapping.h>
+#include <linux/gpio/consumer.h>
+#include <linux/interrupt.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/slot-gpio.h>
+#include <linux/module.h>
+#include <linux/regulator/consumer.h>
+#include <linux/scatterlist.h>
+#include <linux/time.h>
+
+#include "cavium-mmc.h"
+
+/*
+ * The Cavium MMC host hardware assumes that all commands have fixed
+ * command and response types.  These are correct if MMC devices are
+ * being used.  However, non-MMC devices like SD use command and
+ * response types that are unexpected by the host hardware.
+ *
+ * The command and response types can be overridden by supplying an
+ * XOR value that is applied to the type.  We calculate the XOR value
+ * from the values in this table and the flags passed from the MMC
+ * core.
+ */
+static struct cvm_mmc_cr_type cvm_mmc_cr_types[] = {
+	{0, 0},		/* CMD0 */
+	{0, 3},		/* CMD1 */
+	{0, 2},		/* CMD2 */
+	{0, 1},		/* CMD3 */
+	{0, 0},		/* CMD4 */
+	{0, 1},		/* CMD5 */
+	{0, 1},		/* CMD6 */
+	{0, 1},		/* CMD7 */
+	{1, 1},		/* CMD8 */
+	{0, 2},		/* CMD9 */
+	{0, 2},		/* CMD10 */
+	{1, 1},		/* CMD11 */
+	{0, 1},		/* CMD12 */
+	{0, 1},		/* CMD13 */
+	{1, 1},		/* CMD14 */
+	{0, 0},		/* CMD15 */
+	{0, 1},		/* CMD16 */
+	{1, 1},		/* CMD17 */
+	{1, 1},		/* CMD18 */
+	{3, 1},		/* CMD19 */
+	{2, 1},		/* CMD20 */
+	{0, 0},		/* CMD21 */
+	{0, 0},		/* CMD22 */
+	{0, 1},		/* CMD23 */
+	{2, 1},		/* CMD24 */
+	{2, 1},		/* CMD25 */
+	{2, 1},		/* CMD26 */
+	{2, 1},		/* CMD27 */
+	{0, 1},		/* CMD28 */
+	{0, 1},		/* CMD29 */
+	{1, 1},		/* CMD30 */
+	{1, 1},		/* CMD31 */
+	{0, 0},		/* CMD32 */
+	{0, 0},		/* CMD33 */
+	{0, 0},		/* CMD34 */
+	{0, 1},		/* CMD35 */
+	{0, 1},		/* CMD36 */
+	{0, 0},		/* CMD37 */
+	{0, 1},		/* CMD38 */
+	{0, 4},		/* CMD39 */
+	{0, 5},		/* CMD40 */
+	{0, 0},		/* CMD41 */
+	{2, 1},		/* CMD42 */
+	{0, 0},		/* CMD43 */
+	{0, 0},		/* CMD44 */
+	{0, 0},		/* CMD45 */
+	{0, 0},		/* CMD46 */
+	{0, 0},		/* CMD47 */
+	{0, 0},		/* CMD48 */
+	{0, 0},		/* CMD49 */
+	{0, 0},		/* CMD50 */
+	{0, 0},		/* CMD51 */
+	{0, 0},		/* CMD52 */
+	{0, 0},		/* CMD53 */
+	{0, 0},		/* CMD54 */
+	{0, 1},		/* CMD55 */
+	{0xff, 0xff},	/* CMD56 */
+	{0, 0},		/* CMD57 */
+	{0, 0},		/* CMD58 */
+	{0, 0},		/* CMD59 */
+	{0, 0},		/* CMD60 */
+	{0, 0},		/* CMD61 */
+	{0, 0},		/* CMD62 */
+	{0, 0}		/* CMD63 */
+};
+
+static struct cvm_mmc_cr_mods cvm_mmc_get_cr_mods(struct mmc_command *cmd)
+{
+	struct cvm_mmc_cr_type *cr;
+	u8 hardware_ctype, hardware_rtype;
+	u8 desired_ctype = 0, desired_rtype = 0;
+	struct cvm_mmc_cr_mods r;
+
+	cr = cvm_mmc_cr_types + (cmd->opcode & 0x3f);
+	hardware_ctype = cr->ctype;
+	hardware_rtype = cr->rtype;
+	if (cmd->opcode == MMC_GEN_CMD)
+		hardware_ctype = (cmd->arg & 1) ? 1 : 2;
+
+	switch (mmc_cmd_type(cmd)) {
+	case MMC_CMD_ADTC:
+		desired_ctype = (cmd->data->flags & MMC_DATA_WRITE) ? 2 : 1;
+		break;
+	case MMC_CMD_AC:
+	case MMC_CMD_BC:
+	case MMC_CMD_BCR:
+		desired_ctype = 0;
+		break;
+	}
+
+	switch (mmc_resp_type(cmd)) {
+	case MMC_RSP_NONE:
+		desired_rtype = 0;
+		break;
+	case MMC_RSP_R1:/* MMC_RSP_R5, MMC_RSP_R6, MMC_RSP_R7 */
+	case MMC_RSP_R1B:
+		desired_rtype = 1;
+		break;
+	case MMC_RSP_R2:
+		desired_rtype = 2;
+		break;
+	case MMC_RSP_R3: /* MMC_RSP_R4 */
+		desired_rtype = 3;
+		break;
+	}
+	r.ctype_xor = desired_ctype ^ hardware_ctype;
+	r.rtype_xor = desired_rtype ^ hardware_rtype;
+	return r;
+}
+
+static void check_switch_errors(struct cvm_mmc_host *host)
+{
+	union mio_emm_switch emm_switch;
+
+	emm_switch.val = readq(host->base + MIO_EMM_SWITCH);
+	if (emm_switch.s.switch_err0)
+		dev_err(host->dev, "Switch power class error\n");
+	if (emm_switch.s.switch_err1)
+		dev_err(host->dev, "Switch hs timing error\n");
+	if (emm_switch.s.switch_err2)
+		dev_err(host->dev, "Switch bus width error\n");
+}
+
+/*
+ * We never set the switch_exe bit since that would interfere
+ * with the commands send by the MMC core.
+ */
+static void do_switch(struct cvm_mmc_host *host, u64 val)
+{
+	union mio_emm_rsp_sts rsp_sts;
+	union mio_emm_switch emm_switch;
+	int retries = 100;
+	int bus_id;
+
+	emm_switch.val = val;
+
+	/*
+	 * Modes setting only taken from slot 0. Work around that hardware
+	 * issue by first switching to slot 0.
+	 */
+	bus_id = emm_switch.s.bus_id;
+	emm_switch.s.bus_id = 0;
+	writeq(emm_switch.val, host->base + MIO_EMM_SWITCH);
+
+	emm_switch.s.bus_id = bus_id;
+	writeq(emm_switch.val, host->base + MIO_EMM_SWITCH);
+
+	/* wait for the switch to finish */
+	do {
+		rsp_sts.val = readq(host->base + MIO_EMM_RSP_STS);
+		if (!rsp_sts.s.switch_val)
+			break;
+		udelay(10);
+	} while (--retries);
+
+	check_switch_errors(host);
+}
+
+static bool switch_val_changed(struct cvm_mmc_slot *slot, u64 new_val)
+{
+	/* Match BUS_ID, HS_TIMING, BUS_WIDTH, POWER_CLASS, CLK_HI, CLK_LO */
+	u64 match = 0x3001070fffffffffull;
+
+	return (slot->cached_switch & match) != (new_val & match);
+}
+
+static void set_wdog(struct cvm_mmc_slot *slot, unsigned int ns)
+{
+	u64 timeout;
+
+	WARN_ON_ONCE(!slot->clock);
+	if (ns)
+		timeout = (slot->clock * ns) / NSEC_PER_SEC;
+	else
+		timeout = (slot->clock * 850ull) / 1000ull;
+	writeq(timeout, slot->host->base + MIO_EMM_WDOG);
+}
+
+static void cvm_mmc_reset_bus(struct cvm_mmc_slot *slot)
+{
+	union mio_emm_switch emm_switch;
+	u64 wdog = 0;
+
+	emm_switch.val = readq(slot->host->base + MIO_EMM_SWITCH);
+	wdog = readq(slot->host->base + MIO_EMM_WDOG);
+
+	emm_switch.s.switch_exe = 0;
+	emm_switch.s.switch_err0 = 0;
+	emm_switch.s.switch_err1 = 0;
+	emm_switch.s.switch_err2 = 0;
+	emm_switch.s.bus_id = slot->bus_id;
+	do_switch(slot->host, emm_switch.val);
+
+	slot->cached_switch = emm_switch.val;
+
+	msleep(20);
+
+	writeq(wdog, slot->host->base + MIO_EMM_WDOG);
+}
+
+/* Switch to another slot if needed */
+static void cvm_mmc_switch_to(struct cvm_mmc_slot *slot)
+{
+	struct cvm_mmc_host *host = slot->host;
+	struct cvm_mmc_slot *old_slot;
+	union mio_emm_switch emm_switch;
+	union mio_emm_sample emm_sample;
+
+	if (slot->bus_id == host->last_slot)
+		return;
+
+	if (host->last_slot >= 0 && host->slot[host->last_slot]) {
+		old_slot = host->slot[host->last_slot];
+		old_slot->cached_switch = readq(host->base + MIO_EMM_SWITCH);
+		old_slot->cached_rca = readq(host->base + MIO_EMM_RCA);
+	}
+
+	writeq(slot->cached_rca, host->base + MIO_EMM_RCA);
+	emm_switch.val = slot->cached_switch;
+	emm_switch.s.bus_id = slot->bus_id;
+	do_switch(host, emm_switch.val);
+
+	emm_sample.val = 0;
+	emm_sample.s.cmd_cnt = slot->cmd_cnt;
+	emm_sample.s.dat_cnt = slot->dat_cnt;
+	writeq(emm_sample.val, host->base + MIO_EMM_SAMPLE);
+
+	host->last_slot = slot->bus_id;
+}
+
+static void do_read(struct cvm_mmc_host *host, struct mmc_request *req,
+		    u64 dbuf)
+{
+	struct sg_mapping_iter *smi = &host->smi;
+	int data_len = req->data->blocks * req->data->blksz;
+	int bytes_xfered, shift = -1;
+	u64 dat = 0;
+
+	/* Auto inc from offset zero */
+	writeq((0x10000 | (dbuf << 6)), host->base + MIO_EMM_BUF_IDX);
+
+	for (bytes_xfered = 0; bytes_xfered < data_len;) {
+		if (smi->consumed >= smi->length) {
+			if (!sg_miter_next(smi))
+				break;
+			smi->consumed = 0;
+		}
+
+		if (shift < 0) {
+			dat = readq(host->base + MIO_EMM_BUF_DAT);
+			shift = 56;
+		}
+
+		while (smi->consumed < smi->length && shift >= 0) {
+			((u8 *)smi->addr)[smi->consumed] = (dat >> shift) & 0xff;
+			bytes_xfered++;
+			smi->consumed++;
+			shift -= 8;
+		}
+	}
+
+	sg_miter_stop(smi);
+	req->data->bytes_xfered = bytes_xfered;
+	req->data->error = 0;
+}
+
+static void do_write(struct mmc_request *req)
+{
+	req->data->bytes_xfered = req->data->blocks * req->data->blksz;
+	req->data->error = 0;
+}
+
+static void set_cmd_response(struct cvm_mmc_host *host, struct mmc_request *req,
+			     union mio_emm_rsp_sts *rsp_sts)
+{
+	u64 rsp_hi, rsp_lo;
+
+	if (!rsp_sts->s.rsp_val)
+		return;
+
+	rsp_lo = readq(host->base + MIO_EMM_RSP_LO);
+
+	switch (rsp_sts->s.rsp_type) {
+	case 1:
+	case 3:
+		req->cmd->resp[0] = (rsp_lo >> 8) & 0xffffffff;
+		req->cmd->resp[1] = 0;
+		req->cmd->resp[2] = 0;
+		req->cmd->resp[3] = 0;
+		break;
+	case 2:
+		req->cmd->resp[3] = rsp_lo & 0xffffffff;
+		req->cmd->resp[2] = (rsp_lo >> 32) & 0xffffffff;
+		rsp_hi = readq(host->base + MIO_EMM_RSP_HI);
+		req->cmd->resp[1] = rsp_hi & 0xffffffff;
+		req->cmd->resp[0] = (rsp_hi >> 32) & 0xffffffff;
+		break;
+	}
+}
+
+static int get_dma_dir(struct mmc_data *data)
+{
+	return (data->flags & MMC_DATA_WRITE) ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
+}
+
+static int finish_dma_single(struct cvm_mmc_host *host, struct mmc_data *data)
+{
+	data->bytes_xfered = data->blocks * data->blksz;
+	data->error = 0;
+	return 1;
+}
+
+static int finish_dma(struct cvm_mmc_host *host, struct mmc_data *data)
+{
+	return finish_dma_single(host, data);
+}
+
+static bool bad_status(union mio_emm_rsp_sts *rsp_sts)
+{
+	if (rsp_sts->s.rsp_bad_sts || rsp_sts->s.rsp_crc_err ||
+	    rsp_sts->s.rsp_timeout || rsp_sts->s.blk_crc_err ||
+	    rsp_sts->s.blk_timeout || rsp_sts->s.dbuf_err)
+		return true;
+
+	return false;
+}
+
+/* Try to clean up failed DMA. */
+static void cleanup_dma(struct cvm_mmc_host *host,
+			union mio_emm_rsp_sts *rsp_sts)
+{
+	union mio_emm_dma emm_dma;
+
+	emm_dma.val = readq(host->base + MIO_EMM_DMA);
+	emm_dma.s.dma_val = 1;
+	emm_dma.s.dat_null = 1;
+	emm_dma.s.bus_id = rsp_sts->s.bus_id;
+	writeq(emm_dma.val, host->base + MIO_EMM_DMA);
+}
+
+irqreturn_t cvm_mmc_interrupt(int irq, void *dev_id)
+{
+	struct cvm_mmc_host *host = dev_id;
+	union mio_emm_rsp_sts rsp_sts;
+	union mio_emm_int emm_int;
+	struct mmc_request *req;
+	bool host_done;
+
+	/* Clear interrupt bits (write 1 clears ). */
+	emm_int.val = readq(host->base + MIO_EMM_INT);
+	writeq(emm_int.val, host->base + MIO_EMM_INT);
+
+	if (emm_int.s.switch_err)
+		check_switch_errors(host);
+
+	req = host->current_req;
+	if (!req)
+		goto out;
+
+	rsp_sts.val = readq(host->base + MIO_EMM_RSP_STS);
+	/*
+	 * dma_val set means DMA is still in progress. Don't touch
+	 * the request and wait for the interrupt indicating that
+	 * the DMA is finished.
+	 */
+	if (rsp_sts.s.dma_val && host->dma_active)
+		goto out;
+
+	if (!host->dma_active && emm_int.s.buf_done && req->data) {
+		unsigned int type = (rsp_sts.val >> 7) & 3;
+
+		if (type == 1)
+			do_read(host, req, rsp_sts.s.dbuf);
+		else if (type == 2)
+			do_write(req);
+	}
+
+	host_done = emm_int.s.cmd_done || emm_int.s.dma_done ||
+		    emm_int.s.cmd_err || emm_int.s.dma_err;
+
+	if (!(host_done && req->done))
+		goto no_req_done;
+
+	if (bad_status(&rsp_sts))
+		req->cmd->error = -EILSEQ;
+	else
+		req->cmd->error = 0;
+
+	if (host->dma_active && req->data)
+		if (!finish_dma(host, req->data))
+			goto no_req_done;
+
+	set_cmd_response(host, req, &rsp_sts);
+	if (emm_int.s.dma_err && rsp_sts.s.dma_pend)
+		cleanup_dma(host, &rsp_sts);
+
+	host->current_req = NULL;
+	req->done(req);
+
+no_req_done:
+	if (host_done)
+		host->release_bus(host);
+out:
+	return IRQ_RETVAL(emm_int.val != 0);
+}
+
+/*
+ * Program DMA_CFG and if needed DMA_ADR.
+ * Returns 0 on error, DMA address otherwise.
+ */
+static u64 prepare_dma_single(struct cvm_mmc_host *host, struct mmc_data *data)
+{
+	union mio_emm_dma_cfg dma_cfg;
+	int count;
+	u64 addr;
+
+	count = dma_map_sg(host->dev, data->sg, data->sg_len,
+			   get_dma_dir(data));
+	if (!count)
+		return 0;
+
+	dma_cfg.val = 0;
+	dma_cfg.s.en = 1;
+	dma_cfg.s.rw = (data->flags & MMC_DATA_WRITE) ? 1 : 0;
+#ifdef __LITTLE_ENDIAN
+	dma_cfg.s.endian = 1;
+#endif
+	dma_cfg.s.size = (sg_dma_len(&data->sg[0]) / 8) - 1;
+
+	addr = sg_dma_address(&data->sg[0]);
+	dma_cfg.s.adr = addr;
+	writeq(dma_cfg.val, host->dma_base + MIO_EMM_DMA_CFG);
+
+	pr_debug("[%s] sg_dma_len: %u  total sg_elem: %d\n",
+		 (dma_cfg.s.rw) ? "W" : "R", sg_dma_len(&data->sg[0]), count);
+	return addr;
+}
+
+static u64 prepare_dma(struct cvm_mmc_host *host, struct mmc_data *data)
+{
+	return prepare_dma_single(host, data);
+}
+
+static void prepare_ext_dma(struct mmc_host *mmc, struct mmc_request *mrq,
+			    union mio_emm_dma *emm_dma)
+{
+	struct cvm_mmc_slot *slot = mmc_priv(mmc);
+
+	/*
+	 * Our MMC host hardware does not issue single commands,
+	 * because that would require the driver and the MMC core
+	 * to do work to determine the proper sequence of commands.
+	 * Instead, our hardware is superior to most other MMC bus
+	 * hosts. The sequence of MMC commands required to execute
+	 * a transfer are issued automatically by the bus hardware.
+	 *
+	 * - David Daney <ddaney@cavium.com>
+	 */
+	emm_dma->val = 0;
+	emm_dma->s.bus_id = slot->bus_id;
+	emm_dma->s.dma_val = 1;
+	emm_dma->s.sector = (mrq->data->blksz == 512) ? 1 : 0;
+	emm_dma->s.rw = (mrq->data->flags & MMC_DATA_WRITE) ? 1 : 0;
+	emm_dma->s.block_cnt = mrq->data->blocks;
+	emm_dma->s.card_addr = mrq->cmd->arg;
+	if (mmc_card_mmc(mmc->card) || (mmc_card_sd(mmc->card) &&
+	    (mmc->card->scr.cmds & SD_SCR_CMD23_SUPPORT)))
+		emm_dma->s.multi = 1;
+
+	pr_debug("[%s] blocks: %u  multi: %d\n", (emm_dma->s.rw) ? "W" : "R",
+		 mrq->data->blocks, emm_dma->s.multi);
+}
+
+static void prepare_emm_int(union mio_emm_int *emm_int)
+{
+	emm_int->val = 0;
+	emm_int->s.cmd_err = 1;
+	emm_int->s.dma_done = 1;
+	emm_int->s.dma_err = 1;
+}
+
+static void cvm_mmc_dma_request(struct mmc_host *mmc,
+				struct mmc_request *mrq)
+{
+	struct cvm_mmc_slot *slot = mmc_priv(mmc);
+	struct cvm_mmc_host *host = slot->host;
+	union mio_emm_dma emm_dma;
+	union mio_emm_int emm_int;
+	struct mmc_data *data;
+	u64 addr;
+
+	if (!mrq->data || !mrq->data->sg || !mrq->data->sg_len ||
+	    !mrq->stop || mrq->stop->opcode != MMC_STOP_TRANSMISSION) {
+		dev_err(&mmc->card->dev,
+			"Error: cmv_mmc_dma_request no data\n");
+		goto error;
+	}
+
+	cvm_mmc_switch_to(slot);
+
+	data = mrq->data;
+	pr_debug("DMA request  blocks: %d  block_size: %d  total_size: %d\n",
+		 data->blocks, data->blksz, data->blocks * data->blksz);
+	if (data->timeout_ns)
+		set_wdog(slot, data->timeout_ns);
+
+	WARN_ON(host->current_req);
+	host->current_req = mrq;
+
+	prepare_ext_dma(mmc, mrq, &emm_dma);
+	addr = prepare_dma(host, data);
+	if (!addr) {
+		dev_err(host->dev, "prepare_dma failed\n");
+		goto error;
+	}
+	prepare_emm_int(&emm_int);
+
+	host->dma_active = true;
+	host->int_enable(host, emm_int.val);
+
+	/*
+	 * If we have a valid SD card in the slot, we set the response
+	 * bit mask to check for CRC errors and timeouts only.
+	 * Otherwise, use the default power reset value.
+	 */
+	if (mmc->card && mmc_card_sd(mmc->card))
+		writeq(0x00b00000ull, host->base + MIO_EMM_STS_MASK);
+	else
+		writeq(0xe4390080ull, host->base + MIO_EMM_STS_MASK);
+	writeq(emm_dma.val, host->base + MIO_EMM_DMA);
+	return;
+
+error:
+	mrq->cmd->error = -EINVAL;
+	if (mrq->done)
+		mrq->done(mrq);
+	host->release_bus(host);
+}
+
+static void do_read_request(struct cvm_mmc_host *host, struct mmc_request *mrq)
+{
+	sg_miter_start(&host->smi, mrq->data->sg, mrq->data->sg_len,
+		       SG_MITER_ATOMIC | SG_MITER_TO_SG);
+}
+
+static void do_write_request(struct cvm_mmc_host *host, struct mmc_request *mrq)
+{
+	unsigned int data_len = mrq->data->blocks * mrq->data->blksz;
+	struct sg_mapping_iter *smi = &host->smi;
+	unsigned int bytes_xfered;
+	int shift = 56;
+	u64 dat = 0;
+
+	/* Copy data to the xmit buffer before issuing the command. */
+	sg_miter_start(smi, mrq->data->sg, mrq->data->sg_len, SG_MITER_FROM_SG);
+
+	/* Auto inc from offset zero, dbuf zero */
+	writeq(0x10000ull, host->base + MIO_EMM_BUF_IDX);
+
+	for (bytes_xfered = 0; bytes_xfered < data_len;) {
+		if (smi->consumed >= smi->length) {
+			if (!sg_miter_next(smi))
+				break;
+			smi->consumed = 0;
+		}
+
+		while (smi->consumed < smi->length && shift >= 0) {
+			dat |= ((u8 *)smi->addr)[smi->consumed] << shift;
+			bytes_xfered++;
+			smi->consumed++;
+			shift -= 8;
+		}
+
+		if (shift < 0) {
+			writeq(dat, host->base + MIO_EMM_BUF_DAT);
+			shift = 56;
+			dat = 0;
+		}
+	}
+	sg_miter_stop(smi);
+}
+
+static void cvm_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+	struct cvm_mmc_slot *slot = mmc_priv(mmc);
+	struct cvm_mmc_host *host = slot->host;
+	struct mmc_command *cmd = mrq->cmd;
+	union mio_emm_int emm_int;
+	union mio_emm_cmd emm_cmd;
+	struct cvm_mmc_cr_mods mods;
+	union mio_emm_rsp_sts rsp_sts;
+	int retries = 100;
+
+	/*
+	 * Note about locking:
+	 * All MMC devices share the same bus and controller. Allow only a
+	 * single user of the bootbus/MMC bus at a time. The lock is acquired
+	 * on all entry points from the MMC layer.
+	 *
+	 * For requests the lock is only released after the completion
+	 * interrupt!
+	 */
+	host->acquire_bus(host);
+
+	if (cmd->opcode == MMC_READ_MULTIPLE_BLOCK ||
+	    cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK)
+		return cvm_mmc_dma_request(mmc, mrq);
+
+	cvm_mmc_switch_to(slot);
+
+	mods = cvm_mmc_get_cr_mods(cmd);
+
+	WARN_ON(host->current_req);
+	host->current_req = mrq;
+
+	emm_int.val = 0;
+	emm_int.s.cmd_done = 1;
+	emm_int.s.cmd_err = 1;
+
+	if (cmd->data) {
+		if (cmd->data->flags & MMC_DATA_READ)
+			do_read_request(host, mrq);
+		else
+			do_write_request(host, mrq);
+
+		if (cmd->data->timeout_ns)
+			set_wdog(slot, cmd->data->timeout_ns);
+	} else
+		set_wdog(slot, 0);
+
+	host->dma_active = false;
+	host->int_enable(host, emm_int.val);
+
+	emm_cmd.val = 0;
+	emm_cmd.s.cmd_val = 1;
+	emm_cmd.s.ctype_xor = mods.ctype_xor;
+	emm_cmd.s.rtype_xor = mods.rtype_xor;
+	if (mmc_cmd_type(cmd) == MMC_CMD_ADTC)
+		emm_cmd.s.offset = 64 - ((cmd->data->blocks * cmd->data->blksz) / 8);
+	emm_cmd.s.bus_id = slot->bus_id;
+	emm_cmd.s.cmd_idx = cmd->opcode;
+	emm_cmd.s.arg = cmd->arg;
+
+	writeq(0, host->base + MIO_EMM_STS_MASK);
+
+retry:
+	rsp_sts.val = readq(host->base + MIO_EMM_RSP_STS);
+	if (rsp_sts.s.dma_val || rsp_sts.s.cmd_val ||
+	    rsp_sts.s.switch_val || rsp_sts.s.dma_pend) {
+		udelay(10);
+		if (--retries)
+			goto retry;
+	}
+	if (!retries)
+		dev_err(host->dev, "Bad status: %Lx before command write\n", rsp_sts.val);
+	writeq(emm_cmd.val, host->base + MIO_EMM_CMD);
+}
+
+static void cvm_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+	struct cvm_mmc_slot *slot = mmc_priv(mmc);
+	struct cvm_mmc_host *host = slot->host;
+	int clk_period, power_class = 10, bus_width = 0;
+	union mio_emm_switch emm_switch;
+	u64 clock;
+
+	host->acquire_bus(host);
+	cvm_mmc_switch_to(slot);
+
+	/* Set the power state */
+	switch (ios->power_mode) {
+	case MMC_POWER_ON:
+		break;
+
+	case MMC_POWER_OFF:
+		cvm_mmc_reset_bus(slot);
+
+		if (host->global_pwr_gpiod)
+			gpiod_set_value_cansleep(host->global_pwr_gpiod, 0);
+		else
+			mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
+		break;
+
+	case MMC_POWER_UP:
+		if (host->global_pwr_gpiod)
+			gpiod_set_value_cansleep(host->global_pwr_gpiod, 1);
+		else
+			mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd);
+		break;
+	}
+
+	/* Set bus width */
+	switch (ios->bus_width) {
+	case MMC_BUS_WIDTH_8:
+		bus_width = 2;
+		break;
+	case MMC_BUS_WIDTH_4:
+		bus_width = 1;
+		break;
+	case MMC_BUS_WIDTH_1:
+		bus_width = 0;
+		break;
+	}
+
+	slot->bus_width = bus_width;
+
+	if (!ios->clock)
+		goto out;
+
+	/* Change the clock frequency. */
+	clock = ios->clock;
+	if (clock > 52000000)
+		clock = 52000000;
+	slot->clock = clock;
+	clk_period = (host->sys_freq + clock - 1) / (2 * clock);
+
+	emm_switch.val = 0;
+	emm_switch.s.hs_timing = (ios->timing == MMC_TIMING_MMC_HS);
+	emm_switch.s.bus_width = bus_width;
+	emm_switch.s.power_class = power_class;
+	emm_switch.s.clk_hi = clk_period;
+	emm_switch.s.clk_lo = clk_period;
+	emm_switch.s.bus_id = slot->bus_id;
+
+	if (!switch_val_changed(slot, emm_switch.val))
+		goto out;
+
+	set_wdog(slot, 0);
+	do_switch(host, emm_switch.val);
+	slot->cached_switch = emm_switch.val;
+out:
+	host->release_bus(host);
+}
+
+const struct mmc_host_ops cvm_mmc_ops = {
+	.request        = cvm_mmc_request,
+	.set_ios        = cvm_mmc_set_ios,
+	.get_ro		= mmc_gpio_get_ro,
+	.get_cd		= mmc_gpio_get_cd,
+};
+
+static void cvm_mmc_set_clock(struct cvm_mmc_slot *slot, unsigned int clock)
+{
+	struct mmc_host *mmc = slot->mmc;
+
+	clock = min(clock, mmc->f_max);
+	clock = max(clock, mmc->f_min);
+	slot->clock = clock;
+}
+
+static int cvm_mmc_init_lowlevel(struct cvm_mmc_slot *slot)
+{
+	struct cvm_mmc_host *host = slot->host;
+	union mio_emm_switch emm_switch;
+
+	/* Enable this bus slot. */
+	host->emm_cfg |= (1ull << slot->bus_id);
+	writeq(host->emm_cfg, slot->host->base + MIO_EMM_CFG);
+	udelay(10);
+
+	/* Program initial clock speed and power. */
+	cvm_mmc_set_clock(slot, slot->mmc->f_min);
+	emm_switch.val = 0;
+	emm_switch.s.power_class = 10;
+	emm_switch.s.clk_hi = (slot->sclock / slot->clock) / 2;
+	emm_switch.s.clk_lo = (slot->sclock / slot->clock) / 2;
+
+	/* Make the changes take effect on this bus slot. */
+	emm_switch.s.bus_id = slot->bus_id;
+	do_switch(host, emm_switch.val);
+
+	slot->cached_switch = emm_switch.val;
+
+	/*
+	 * Set watchdog timeout value and default reset value
+	 * for the mask register. Finally, set the CARD_RCA
+	 * bit so that we can get the card address relative
+	 * to the CMD register for CMD7 transactions.
+	 */
+	set_wdog(slot, 0);
+	writeq(0xe4390080ull, host->base + MIO_EMM_STS_MASK);
+	writeq(1, host->base + MIO_EMM_RCA);
+	return 0;
+}
+
+static int set_bus_width(struct device *dev, struct cvm_mmc_slot *slot, u32 id)
+{
+	u32 bus_width;
+	int ret;
+
+	/*
+	 * The "cavium,bus-max-width" property is DEPRECATED and should
+	 * not be used. We handle it here to support older firmware.
+	 * Going forward, the standard "bus-width" property is used
+	 * instead of the Cavium-specific property.
+	 */
+	if (!(slot->mmc->caps & (MMC_CAP_8_BIT_DATA | MMC_CAP_4_BIT_DATA))) {
+		/* Try legacy "cavium,bus-max-width" property. */
+		ret = of_property_read_u32(dev->of_node, "cavium,bus-max-width",
+					   &bus_width);
+		if (ret) {
+			/* No bus width specified, use default. */
+			bus_width = 8;
+			dev_info(dev, "Default width 8 used for slot %u\n", id);
+		}
+	} else {
+		/* Hosts capable of 8-bit transfers can also do 4 bits */
+		bus_width = (slot->mmc->caps & MMC_CAP_8_BIT_DATA) ? 8 : 4;
+	}
+
+	switch (bus_width) {
+	case 8:
+		slot->bus_width = (MMC_BUS_WIDTH_8 - 1);
+		slot->mmc->caps = MMC_CAP_8_BIT_DATA | MMC_CAP_4_BIT_DATA;
+		break;
+	case 4:
+		slot->bus_width = (MMC_BUS_WIDTH_4 - 1);
+		slot->mmc->caps = MMC_CAP_4_BIT_DATA;
+		break;
+	case 1:
+		slot->bus_width = MMC_BUS_WIDTH_1;
+		break;
+	default:
+		dev_err(dev, "Invalid bus width for slot %u\n", id);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static void set_frequency(struct device *dev, struct mmc_host *mmc, u32 id)
+{
+	int ret;
+
+	/*
+	 * The "spi-max-frequency" property is DEPRECATED and should
+	 * not be used. We handle it here to support older firmware.
+	 * Going forward, the standard "max-frequency" property is
+	 * used instead of the Cavium-specific property.
+	 */
+	if (mmc->f_max == 0) {
+		/* Try legacy "spi-max-frequency" property. */
+		ret = of_property_read_u32(dev->of_node, "spi-max-frequency",
+					   &mmc->f_max);
+		if (ret) {
+			/* No frequency properties found, use default. */
+			mmc->f_max = 52000000;
+			dev_info(dev, "Default %u frequency used for slot %u\n",
+				 mmc->f_max, id);
+		}
+	} else if (mmc->f_max > 52000000)
+		mmc->f_max = 52000000;
+
+	/* Set minimum frequency */
+	mmc->f_min = 400000;
+}
+
+static int set_voltage(struct device *dev, struct mmc_host *mmc,
+		       struct cvm_mmc_host *host)
+{
+	int ret;
+
+	/*
+	 * Legacy platform doesn't support regulator but enables power gpio
+	 * directly during platform probe.
+	 */
+	if (host->global_pwr_gpiod)
+		/* Get a sane OCR mask for other parts of the MMC subsytem. */
+		return mmc_of_parse_voltage(dev->of_node, &mmc->ocr_avail);
+
+	mmc->supply.vmmc = devm_regulator_get(dev, "vmmc");
+	if (IS_ERR(mmc->supply.vmmc)) {
+		ret = PTR_ERR(mmc->supply.vmmc);
+	} else {
+		ret = mmc_regulator_get_ocrmask(mmc->supply.vmmc);
+		if (ret > 0) {
+			mmc->ocr_avail = ret;
+			ret = 0;
+		}
+	}
+	return ret;
+}
+
+int cvm_mmc_slot_probe(struct device *dev, struct cvm_mmc_host *host)
+{
+	struct device_node *node = dev->of_node;
+	u32 id, cmd_skew, dat_skew;
+	struct cvm_mmc_slot *slot;
+	struct mmc_host *mmc;
+	u64 clock_period;
+	int ret;
+
+	ret = of_property_read_u32(node, "reg", &id);
+	if (ret) {
+		dev_err(dev, "Missing or invalid reg property on %s\n",
+			of_node_full_name(node));
+		return ret;
+	}
+
+	if (id >= CAVIUM_MAX_MMC || host->slot[id]) {
+		dev_err(dev, "Invalid reg property on %s\n",
+			of_node_full_name(node));
+		return -EINVAL;
+	}
+
+	mmc = mmc_alloc_host(sizeof(struct cvm_mmc_slot), dev);
+	if (!mmc)
+		return -ENOMEM;
+
+	slot = mmc_priv(mmc);
+	slot->mmc = mmc;
+	slot->host = host;
+
+	ret = mmc_of_parse(mmc);
+	if (ret)
+		goto error;
+
+	ret = set_bus_width(dev, slot, id);
+	if (ret)
+		goto error;
+
+	set_frequency(dev, mmc, id);
+
+	/* Octeon-specific DT properties. */
+	ret = of_property_read_u32(node, "cavium,cmd-clk-skew", &cmd_skew);
+	if (ret)
+		cmd_skew = 0;
+	ret = of_property_read_u32(node, "cavium,dat-clk-skew", &dat_skew);
+	if (ret)
+		dat_skew = 0;
+
+	ret = set_voltage(dev, mmc, host);
+	if (ret < 0)
+		goto error;
+
+	/* Set up host parameters */
+	mmc->ops = &cvm_mmc_ops;
+
+	mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
+		     MMC_CAP_ERASE | MMC_CAP_CMD23 | MMC_CAP_POWER_OFF_CARD;
+
+	mmc->max_segs = 1;
+
+	/* DMA size field can address up to 8 MB */
+	mmc->max_seg_size = 8 * 1024 * 1024;
+	mmc->max_req_size = mmc->max_seg_size;
+	/* External DMA is in 512 byte blocks */
+	mmc->max_blk_size = 512;
+	/* DMA block count field is 15 bits */
+	mmc->max_blk_count = 32767;
+
+	slot->clock = mmc->f_min;
+	slot->sclock = host->sys_freq;
+
+	/* Period in picoseconds. */
+	clock_period = 1000000000000ull / slot->sclock;
+	slot->cmd_cnt = (cmd_skew + clock_period / 2) / clock_period;
+	slot->dat_cnt = (dat_skew + clock_period / 2) / clock_period;
+
+	slot->bus_id = id;
+	slot->cached_rca = 1;
+
+	host->acquire_bus(host);
+	host->slot[id] = slot;
+	cvm_mmc_switch_to(slot);
+	cvm_mmc_init_lowlevel(slot);
+	host->release_bus(host);
+
+	ret = mmc_add_host(mmc);
+	if (ret) {
+		dev_err(dev, "mmc_add_host() returned %d\n", ret);
+		goto error;
+	}
+
+	return 0;
+
+error:
+	slot->host->slot[id] = NULL;
+	mmc_free_host(slot->mmc);
+	return ret;
+}
+
+int cvm_mmc_slot_remove(struct cvm_mmc_slot *slot)
+{
+	mmc_remove_host(slot->mmc);
+	slot->host->slot[slot->bus_id] = NULL;
+	mmc_free_host(slot->mmc);
+	return 0;
+}
diff --git a/drivers/mmc/host/cavium-mmc.h b/drivers/mmc/host/cavium-mmc.h
new file mode 100644
index 0000000..27fb02b
--- /dev/null
+++ b/drivers/mmc/host/cavium-mmc.h
@@ -0,0 +1,303 @@
+/*
+ * Driver for MMC and SSD cards for Cavium OCTEON and ThunderX 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/clk.h>
+#include <linux/io.h>
+#include <linux/mmc/host.h>
+#include <linux/of.h>
+#include <linux/scatterlist.h>
+#include <linux/semaphore.h>
+
+#define CAVIUM_MAX_MMC		4
+
+struct cvm_mmc_host {
+	struct device *dev;
+	void __iomem *base;
+	void __iomem *dma_base;
+	u64 emm_cfg;
+	int last_slot;
+	struct clk *clk;
+	int sys_freq;
+
+	struct mmc_request *current_req;
+	struct sg_mapping_iter smi;
+	bool dma_active;
+
+	struct gpio_desc *global_pwr_gpiod;
+
+	struct cvm_mmc_slot *slot[CAVIUM_MAX_MMC];
+
+	void (*acquire_bus)(struct cvm_mmc_host *);
+	void (*release_bus)(struct cvm_mmc_host *);
+	void (*int_enable)(struct cvm_mmc_host *, u64);
+};
+
+struct cvm_mmc_slot {
+	struct mmc_host *mmc;		/* slot-level mmc_core object */
+	struct cvm_mmc_host *host;	/* common hw for all slots */
+
+	u64 clock;
+	unsigned int sclock;
+
+	u64 cached_switch;
+	u64 cached_rca;
+
+	unsigned int cmd_cnt;		/* sample delay */
+	unsigned int dat_cnt;		/* sample delay */
+
+	int bus_width;
+	int bus_id;
+};
+
+struct cvm_mmc_cr_type {
+	u8 ctype;
+	u8 rtype;
+};
+
+struct cvm_mmc_cr_mods {
+	u8 ctype_xor;
+	u8 rtype_xor;
+};
+
+/* Bitfield definitions */
+
+union mio_emm_cmd {
+	u64 val;
+	struct mio_emm_cmd_s {
+#ifdef __BIG_ENDIAN_BITFIELD
+		u64 :2;
+		u64 bus_id:2;
+		u64 cmd_val:1;
+		u64 :3;
+		u64 dbuf:1;
+		u64 offset:6;
+		u64 :6;
+		u64 ctype_xor:2;
+		u64 rtype_xor:3;
+		u64 cmd_idx:6;
+		u64 arg:32;
+#else
+		u64 arg:32;
+		u64 cmd_idx:6;
+		u64 rtype_xor:3;
+		u64 ctype_xor:2;
+		u64 :6;
+		u64 offset:6;
+		u64 dbuf:1;
+		u64 :3;
+		u64 cmd_val:1;
+		u64 bus_id:2;
+		u64 :2;
+#endif
+	} s;
+};
+
+union mio_emm_dma {
+	u64 val;
+	struct mio_emm_dma_s {
+#ifdef __BIG_ENDIAN_BITFIELD
+		u64 :2;
+		u64 bus_id:2;
+		u64 dma_val:1;
+		u64 sector:1;
+		u64 dat_null:1;
+		u64 thres:6;
+		u64 rel_wr:1;
+		u64 rw:1;
+		u64 multi:1;
+		u64 block_cnt:16;
+		u64 card_addr:32;
+#else
+		u64 card_addr:32;
+		u64 block_cnt:16;
+		u64 multi:1;
+		u64 rw:1;
+		u64 rel_wr:1;
+		u64 thres:6;
+		u64 dat_null:1;
+		u64 sector:1;
+		u64 dma_val:1;
+		u64 bus_id:2;
+		u64 :2;
+#endif
+	} s;
+};
+
+union mio_emm_dma_cfg {
+	u64 val;
+	struct mio_emm_dma_cfg_s {
+#ifdef __BIG_ENDIAN_BITFIELD
+		u64 en:1;
+		u64 rw:1;
+		u64 clr:1;
+		u64 :1;
+		u64 swap32:1;
+		u64 swap16:1;
+		u64 swap8:1;
+		u64 endian:1;
+		u64 size:20;
+		u64 adr:36;
+#else
+		u64 adr:36;
+		u64 size:20;
+		u64 endian:1;
+		u64 swap8:1;
+		u64 swap16:1;
+		u64 swap32:1;
+		u64 :1;
+		u64 clr:1;
+		u64 rw:1;
+		u64 en:1;
+#endif
+	} s;
+};
+
+union mio_emm_int {
+	u64 val;
+	struct mio_emm_int_s {
+#ifdef __BIG_ENDIAN_BITFIELD
+		u64 :57;
+		u64 switch_err:1;
+		u64 switch_done:1;
+		u64 dma_err:1;
+		u64 cmd_err:1;
+		u64 dma_done:1;
+		u64 cmd_done:1;
+		u64 buf_done:1;
+#else
+		u64 buf_done:1;
+		u64 cmd_done:1;
+		u64 dma_done:1;
+		u64 cmd_err:1;
+		u64 dma_err:1;
+		u64 switch_done:1;
+		u64 switch_err:1;
+		u64 :57;
+#endif
+	} s;
+};
+
+union mio_emm_rsp_sts {
+	u64 val;
+	struct mio_emm_rsp_sts_s {
+#ifdef __BIG_ENDIAN_BITFIELD
+		u64 :2;
+		u64 bus_id:2;
+		u64 cmd_val:1;
+		u64 switch_val:1;
+		u64 dma_val:1;
+		u64 dma_pend:1;
+		u64 :27;
+		u64 dbuf_err:1;
+		u64 :4;
+		u64 dbuf:1;
+		u64 blk_timeout:1;
+		u64 blk_crc_err:1;
+		u64 rsp_busybit:1;
+		u64 stp_timeout:1;
+		u64 stp_crc_err:1;
+		u64 stp_bad_sts:1;
+		u64 stp_val:1;
+		u64 rsp_timeout:1;
+		u64 rsp_crc_err:1;
+		u64 rsp_bad_sts:1;
+		u64 rsp_val:1;
+		u64 rsp_type:3;
+		u64 cmd_type:2;
+		u64 cmd_idx:6;
+		u64 cmd_done:1;
+#else
+		u64 cmd_done:1;
+		u64 cmd_idx:6;
+		u64 cmd_type:2;
+		u64 rsp_type:3;
+		u64 rsp_val:1;
+		u64 rsp_bad_sts:1;
+		u64 rsp_crc_err:1;
+		u64 rsp_timeout:1;
+		u64 stp_val:1;
+		u64 stp_bad_sts:1;
+		u64 stp_crc_err:1;
+		u64 stp_timeout:1;
+		u64 rsp_busybit:1;
+		u64 blk_crc_err:1;
+		u64 blk_timeout:1;
+		u64 dbuf:1;
+		u64 :4;
+		u64 dbuf_err:1;
+		u64 :27;
+		u64 dma_pend:1;
+		u64 dma_val:1;
+		u64 switch_val:1;
+		u64 cmd_val:1;
+		u64 bus_id:2;
+		u64 :2;
+#endif
+	} s;
+};
+
+union mio_emm_sample {
+	u64 val;
+	struct mio_emm_sample_s {
+#ifdef __BIG_ENDIAN_BITFIELD
+		u64 :38;
+		u64 cmd_cnt:10;
+		u64 :6;
+		u64 dat_cnt:10;
+#else
+		u64 dat_cnt:10;
+		u64 :6;
+		u64 cmd_cnt:10;
+		u64 :38;
+#endif
+	} s;
+};
+
+union mio_emm_switch {
+	u64 val;
+	struct mio_emm_switch_s {
+#ifdef __BIG_ENDIAN_BITFIELD
+		u64 :2;
+		u64 bus_id:2;
+		u64 switch_exe:1;
+		u64 switch_err0:1;
+		u64 switch_err1:1;
+		u64 switch_err2:1;
+		u64 :7;
+		u64 hs_timing:1;
+		u64 :5;
+		u64 bus_width:3;
+		u64 :4;
+		u64 power_class:4;
+		u64 clk_hi:16;
+		u64 clk_lo:16;
+#else
+		u64 clk_lo:16;
+		u64 clk_hi:16;
+		u64 power_class:4;
+		u64 :4;
+		u64 bus_width:3;
+		u64 :5;
+		u64 hs_timing:1;
+		u64 :7;
+		u64 switch_err2:1;
+		u64 switch_err1:1;
+		u64 switch_err0:1;
+		u64 switch_exe:1;
+		u64 bus_id:2;
+		u64 :2;
+#endif
+	} s;
+};
+
+/* Protoypes */
+irqreturn_t cvm_mmc_interrupt(int irq, void *dev_id);
+int cvm_mmc_slot_probe(struct device *dev, struct cvm_mmc_host *host);
+int cvm_mmc_slot_remove(struct cvm_mmc_slot *slot);
+extern const struct mmc_host_ops cvm_mmc_ops;
-- 
2.9.0.rc0.21.g7777322

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v11 3/9] mmc: cavium: Add MMC platform driver for Octeon SOCs
  2017-02-06 13:39 [PATCH v11 0/9] Cavium MMC driver Jan Glauber
  2017-02-06 13:39 ` [PATCH v11 1/9] dt-bindings: mmc: Add Cavium SOCs MMC bindings Jan Glauber
  2017-02-06 13:39 ` [PATCH v11 2/9] mmc: cavium: Add core MMC driver for Cavium SOCs Jan Glauber
@ 2017-02-06 13:39 ` Jan Glauber
  2017-02-06 13:39 ` [PATCH v11 4/9] mmc: cavium: Work-around hardware bug on cn6xxx and cnf7xxx Jan Glauber
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 24+ messages in thread
From: Jan Glauber @ 2017-02-06 13:39 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc, linux-kernel, David Daney, Steven J . Hill,
	Jan Glauber, David Daney, Steven J . Hill

Add a platform driver for Octeon MIPS SOCs.

Signed-off-by: Jan Glauber <jglauber@cavium.com>
Signed-off-by: David Daney <david.daney@cavium.com>
Signed-off-by: Steven J. Hill <steven.hill@cavium.com>
---
 drivers/mmc/host/Kconfig               |  10 ++
 drivers/mmc/host/Makefile              |   2 +
 drivers/mmc/host/cavium-mmc.h          |  19 ++++
 drivers/mmc/host/cavium-pltfm-octeon.c | 181 +++++++++++++++++++++++++++++++++
 4 files changed, 212 insertions(+)
 create mode 100644 drivers/mmc/host/cavium-pltfm-octeon.c

diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index f08691a..68cc811 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -622,6 +622,16 @@ config SDH_BFIN_MISSING_CMD_PULLUP_WORKAROUND
 	help
 	  If you say yes here SD-Cards may work on the EZkit.
 
+config MMC_CAVIUM_OCTEON
+	tristate "Cavium OCTEON SD/MMC Card Interface support"
+	depends on CAVIUM_OCTEON_SOC
+	help
+	  This selects Cavium OCTEON SD/MMC card Interface.
+	  If you have an OCTEON board with a Multimedia Card slot,
+	  say Y or M here.
+
+	  If unsure, say N.
+
 config MMC_DW
 	tristate "Synopsys DesignWare Memory Card Interface"
 	depends on HAS_DMA
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 6d548c4..c7f0ccf 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -42,6 +42,8 @@ obj-$(CONFIG_MMC_SDHI)		+= sh_mobile_sdhi.o
 obj-$(CONFIG_MMC_CB710)		+= cb710-mmc.o
 obj-$(CONFIG_MMC_VIA_SDMMC)	+= via-sdmmc.o
 obj-$(CONFIG_SDH_BFIN)		+= bfin_sdh.o
+octeon-mmc-objs := cavium-mmc.o cavium-pltfm-octeon.o
+obj-$(CONFIG_MMC_CAVIUM_OCTEON) += octeon-mmc.o
 obj-$(CONFIG_MMC_DW)		+= dw_mmc.o
 obj-$(CONFIG_MMC_DW_PLTFM)	+= dw_mmc-pltfm.o
 obj-$(CONFIG_MMC_DW_EXYNOS)	+= dw_mmc-exynos.o
diff --git a/drivers/mmc/host/cavium-mmc.h b/drivers/mmc/host/cavium-mmc.h
index 27fb02b..e900dd1 100644
--- a/drivers/mmc/host/cavium-mmc.h
+++ b/drivers/mmc/host/cavium-mmc.h
@@ -16,6 +16,25 @@
 
 #define CAVIUM_MAX_MMC		4
 
+#define MIO_EMM_DMA_CFG		0x00
+#define MIO_EMM_DMA_ADR		0x08
+
+#define MIO_EMM_CFG		0x00
+#define MIO_EMM_SWITCH		0x48
+#define MIO_EMM_DMA		0x50
+#define MIO_EMM_CMD		0x58
+#define MIO_EMM_RSP_STS		0x60
+#define MIO_EMM_RSP_LO		0x68
+#define MIO_EMM_RSP_HI		0x70
+#define MIO_EMM_INT		0x78
+#define MIO_EMM_INT_EN		0x80
+#define MIO_EMM_WDOG		0x88
+#define MIO_EMM_SAMPLE		0x90
+#define MIO_EMM_STS_MASK	0x98
+#define MIO_EMM_RCA		0xa0
+#define MIO_EMM_BUF_IDX		0xe0
+#define MIO_EMM_BUF_DAT		0xe8
+
 struct cvm_mmc_host {
 	struct device *dev;
 	void __iomem *base;
diff --git a/drivers/mmc/host/cavium-pltfm-octeon.c b/drivers/mmc/host/cavium-pltfm-octeon.c
new file mode 100644
index 0000000..e2a1d1f
--- /dev/null
+++ b/drivers/mmc/host/cavium-pltfm-octeon.c
@@ -0,0 +1,181 @@
+/*
+ * 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/gpio/consumer.h>
+#include <linux/interrupt.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/slot-gpio.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <asm/octeon/octeon.h>
+#include "cavium-mmc.h"
+
+#define CVMX_MIO_BOOT_CTL CVMX_ADD_IO_SEG(0x00011800000000D0ull)
+
+static void octeon_mmc_acquire_bus(struct cvm_mmc_host *host)
+{
+	/* Switch the MMC controller onto the bus. */
+	down(&octeon_bootbus_sem);
+	writeq(0, (void __iomem *)CVMX_MIO_BOOT_CTL);
+}
+
+static void octeon_mmc_release_bus(struct cvm_mmc_host *host)
+{
+	up(&octeon_bootbus_sem);
+}
+
+static void octeon_mmc_int_enable(struct cvm_mmc_host *host, u64 val)
+{
+	writeq(val, host->base + MIO_EMM_INT);
+	writeq(val, host->base + MIO_EMM_INT_EN);
+}
+
+static int octeon_mmc_probe(struct platform_device *pdev)
+{
+	struct device_node *cn, *node = pdev->dev.of_node;
+	struct cvm_mmc_host *host;
+	struct resource	*res;
+	void __iomem *base;
+	int mmc_irq[9];
+	int i, ret = 0;
+	u64 val;
+
+	host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
+	if (!host)
+		return -ENOMEM;
+
+	host->dev = &pdev->dev;
+	host->acquire_bus = octeon_mmc_acquire_bus;
+	host->release_bus = octeon_mmc_release_bus;
+	host->int_enable = octeon_mmc_int_enable;
+
+	host->sys_freq = octeon_get_io_clock_rate();
+
+	/* First one is EMM second DMA */
+	for (i = 0; i < 2; i++) {
+		mmc_irq[i] = platform_get_irq(pdev, i);
+		if (mmc_irq[i] < 0)
+			return mmc_irq[i];
+	}
+	host->last_slot = -1;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "Platform resource[0] is missing\n");
+		return -ENXIO;
+	}
+	base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+	host->base = (void __iomem *)base;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (!res) {
+		dev_err(&pdev->dev, "Platform resource[1] is missing\n");
+		return -EINVAL;
+	}
+	base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+	host->dma_base = (void __iomem *)base;
+
+	/*
+	 * Clear out any pending interrupts that may be left over from
+	 * bootloader.
+	 */
+	val = readq(host->base + MIO_EMM_INT);
+	writeq(val, host->base + MIO_EMM_INT);
+
+	ret = devm_request_irq(&pdev->dev, mmc_irq[0],
+			       cvm_mmc_interrupt, 0, KBUILD_MODNAME, host);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Error: devm_request_irq %d\n",
+			mmc_irq[0]);
+		return ret;
+	}
+
+	host->global_pwr_gpiod = devm_gpiod_get_optional(&pdev->dev, "power",
+							 GPIOD_OUT_HIGH);
+	if (IS_ERR(host->global_pwr_gpiod)) {
+		dev_err(&pdev->dev, "Invalid power GPIO\n");
+		return PTR_ERR(host->global_pwr_gpiod);
+	}
+
+	platform_set_drvdata(pdev, host);
+
+	for_each_child_of_node(node, cn) {
+		struct platform_device *slot_pdev;
+
+		slot_pdev = of_platform_device_create(cn, NULL, &pdev->dev);
+		ret = cvm_mmc_slot_probe(&slot_pdev->dev, host);
+		if (ret) {
+			dev_err(&pdev->dev, "Error populating slots\n");
+			gpiod_set_value_cansleep(host->global_pwr_gpiod, 0);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int octeon_mmc_remove(struct platform_device *pdev)
+{
+	union mio_emm_dma_cfg dma_cfg;
+	struct cvm_mmc_host *host = platform_get_drvdata(pdev);
+	int i;
+
+	for (i = 0; i < CAVIUM_MAX_MMC; i++)
+		if (host->slot[i])
+			cvm_mmc_slot_remove(host->slot[i]);
+
+	dma_cfg.val = readq(host->dma_base + MIO_EMM_DMA_CFG);
+	dma_cfg.s.en = 0;
+	writeq(dma_cfg.val, host->dma_base + MIO_EMM_DMA_CFG);
+
+	gpiod_set_value_cansleep(host->global_pwr_gpiod, 0);
+
+	return 0;
+}
+
+static const struct of_device_id octeon_mmc_match[] = {
+	{
+		.compatible = "cavium,octeon-6130-mmc",
+	},
+	{
+		.compatible = "cavium,octeon-7890-mmc",
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, octeon_mmc_match);
+
+static struct platform_driver octeon_mmc_driver = {
+	.probe		= octeon_mmc_probe,
+	.remove		= octeon_mmc_remove,
+	.driver		= {
+		.name	= KBUILD_MODNAME,
+		.of_match_table = octeon_mmc_match,
+	},
+};
+
+static int __init octeon_mmc_init(void)
+{
+	return platform_driver_register(&octeon_mmc_driver);
+}
+
+static void __exit octeon_mmc_cleanup(void)
+{
+	platform_driver_unregister(&octeon_mmc_driver);
+}
+
+module_init(octeon_mmc_init);
+module_exit(octeon_mmc_cleanup);
+
+MODULE_AUTHOR("Cavium Inc. <support@cavium.com>");
+MODULE_DESCRIPTION("Low-level driver for Cavium OCTEON MMC/SSD card");
+MODULE_LICENSE("GPL");
-- 
2.9.0.rc0.21.g7777322

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v11 4/9] mmc: cavium: Work-around hardware bug on cn6xxx and cnf7xxx
  2017-02-06 13:39 [PATCH v11 0/9] Cavium MMC driver Jan Glauber
                   ` (2 preceding siblings ...)
  2017-02-06 13:39 ` [PATCH v11 3/9] mmc: cavium: Add MMC platform driver for Octeon SOCs Jan Glauber
@ 2017-02-06 13:39 ` Jan Glauber
  2017-02-06 13:39 ` [PATCH v11 5/9] mmc: cavium: Add support for Octeon cn7890 Jan Glauber
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 24+ messages in thread
From: Jan Glauber @ 2017-02-06 13:39 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc, linux-kernel, David Daney, Steven J . Hill,
	Jan Glauber, David Daney, Steven J . Hill

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>
Signed-off-by: David Daney <david.daney@cavium.com>
Signed-off-by: Steven J. Hill <steven.hill@cavium.com>
---
 arch/mips/cavium-octeon/Makefile         |  1 +
 arch/mips/cavium-octeon/octeon-mmc-l2c.c | 98 ++++++++++++++++++++++++++++++++
 drivers/mmc/host/cavium-mmc.c            |  5 ++
 drivers/mmc/host/cavium-mmc.h            |  5 ++
 drivers/mmc/host/cavium-pltfm-octeon.c   | 30 ++++++++++
 5 files changed, 139 insertions(+)
 create mode 100644 arch/mips/cavium-octeon/octeon-mmc-l2c.c

diff --git a/arch/mips/cavium-octeon/Makefile b/arch/mips/cavium-octeon/Makefile
index 2a59265..4e17617 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_CAVIUM_OCTEON)	      += octeon-mmc-l2c.o
diff --git a/arch/mips/cavium-octeon/octeon-mmc-l2c.c b/arch/mips/cavium-octeon/octeon-mmc-l2c.c
new file mode 100644
index 0000000..6aaaf73
--- /dev/null
+++ b/arch/mips/cavium-octeon/octeon-mmc-l2c.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-mmc.c b/drivers/mmc/host/cavium-mmc.c
index 40aee08..e9e6f76 100644
--- a/drivers/mmc/host/cavium-mmc.c
+++ b/drivers/mmc/host/cavium-mmc.c
@@ -439,6 +439,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:
@@ -559,6 +561,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/cavium-pltfm-octeon.c b/drivers/mmc/host/cavium-pltfm-octeon.c
index e2a1d1f..4fbc67e 100644
--- a/drivers/mmc/host/cavium-pltfm-octeon.c
+++ b/drivers/mmc/host/cavium-pltfm-octeon.c
@@ -18,6 +18,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. */
@@ -36,6 +39,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;
@@ -54,6 +79,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

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v11 5/9] mmc: cavium: Add support for Octeon cn7890
  2017-02-06 13:39 [PATCH v11 0/9] Cavium MMC driver Jan Glauber
                   ` (3 preceding siblings ...)
  2017-02-06 13:39 ` [PATCH v11 4/9] mmc: cavium: Work-around hardware bug on cn6xxx and cnf7xxx Jan Glauber
@ 2017-02-06 13:39 ` Jan Glauber
  2017-02-06 13:39 ` [PATCH v11 6/9] mmc: cavium: Add MMC PCI driver for ThunderX SOCs Jan Glauber
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 24+ messages in thread
From: Jan Glauber @ 2017-02-06 13:39 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc, linux-kernel, David Daney, Steven J . Hill,
	Jan Glauber, David Daney, Steven J . Hill

The MMC unit on Octeon cn7890 differs in that it has multiple
interrupts. Requires a lock for the interrupt handler. DMA addresses
have a dedicated 64 bit register now, so use that when available.

Signed-off-by: Jan Glauber <jglauber@cavium.com>
Signed-off-by: David Daney <david.daney@cavium.com>
Signed-off-by: Steven J. Hill <steven.hill@cavium.com>
---
 drivers/mmc/host/cavium-mmc.c          | 16 ++++++-
 drivers/mmc/host/cavium-mmc.h          |  6 +++
 drivers/mmc/host/cavium-pltfm-octeon.c | 79 +++++++++++++++++++++++++++-------
 3 files changed, 84 insertions(+), 17 deletions(-)

diff --git a/drivers/mmc/host/cavium-mmc.c b/drivers/mmc/host/cavium-mmc.c
index e9e6f76..f1fe291 100644
--- a/drivers/mmc/host/cavium-mmc.c
+++ b/drivers/mmc/host/cavium-mmc.c
@@ -385,8 +385,14 @@ irqreturn_t cvm_mmc_interrupt(int irq, void *dev_id)
 	union mio_emm_rsp_sts rsp_sts;
 	union mio_emm_int emm_int;
 	struct mmc_request *req;
+	unsigned long flags = 0;
 	bool host_done;
 
+	if (host->need_irq_handler_lock)
+		spin_lock_irqsave(&host->irq_handler_lock, flags);
+	else
+		__acquire(&host->irq_handler_lock);
+
 	/* Clear interrupt bits (write 1 clears ). */
 	emm_int.val = readq(host->base + MIO_EMM_INT);
 	writeq(emm_int.val, host->base + MIO_EMM_INT);
@@ -444,6 +450,10 @@ irqreturn_t cvm_mmc_interrupt(int irq, void *dev_id)
 	if (host_done)
 		host->release_bus(host);
 out:
+	if (host->need_irq_handler_lock)
+		spin_unlock_irqrestore(&host->irq_handler_lock, flags);
+	else
+		__release(&host->irq_handler_lock);
 	return IRQ_RETVAL(emm_int.val != 0);
 }
 
@@ -471,11 +481,15 @@ static u64 prepare_dma_single(struct cvm_mmc_host *host, struct mmc_data *data)
 	dma_cfg.s.size = (sg_dma_len(&data->sg[0]) / 8) - 1;
 
 	addr = sg_dma_address(&data->sg[0]);
-	dma_cfg.s.adr = addr;
+	if (!host->big_dma_addr)
+		dma_cfg.s.adr = addr;
 	writeq(dma_cfg.val, host->dma_base + MIO_EMM_DMA_CFG);
 
 	pr_debug("[%s] sg_dma_len: %u  total sg_elem: %d\n",
 		 (dma_cfg.s.rw) ? "W" : "R", sg_dma_len(&data->sg[0]), count);
+
+	if (host->big_dma_addr)
+		writeq(addr, host->dma_base + MIO_EMM_DMA_ADR);
 	return addr;
 }
 
diff --git a/drivers/mmc/host/cavium-mmc.h b/drivers/mmc/host/cavium-mmc.h
index f350212..5f41be9 100644
--- a/drivers/mmc/host/cavium-mmc.h
+++ b/drivers/mmc/host/cavium-mmc.h
@@ -49,6 +49,12 @@ struct cvm_mmc_host {
 	struct sg_mapping_iter smi;
 	bool dma_active;
 
+	bool has_ciu3;
+	bool big_dma_addr;
+	bool need_irq_handler_lock;
+	spinlock_t irq_handler_lock;
+	struct semaphore mmc_serializer;
+
 	struct gpio_desc *global_pwr_gpiod;
 
 	struct cvm_mmc_slot *slot[CAVIUM_MAX_MMC];
diff --git a/drivers/mmc/host/cavium-pltfm-octeon.c b/drivers/mmc/host/cavium-pltfm-octeon.c
index 4fbc67e..ad82a13 100644
--- a/drivers/mmc/host/cavium-pltfm-octeon.c
+++ b/drivers/mmc/host/cavium-pltfm-octeon.c
@@ -23,20 +23,28 @@ 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. */
-	down(&octeon_bootbus_sem);
-	writeq(0, (void __iomem *)CVMX_MIO_BOOT_CTL);
+	if (!host->has_ciu3) {
+		/* Switch the MMC controller onto the bus. */
+		down(&octeon_bootbus_sem);
+		writeq(0, (void __iomem *)CVMX_MIO_BOOT_CTL);
+	} else {
+		down(&host->mmc_serializer);
+	}
 }
 
 static void octeon_mmc_release_bus(struct cvm_mmc_host *host)
 {
-	up(&octeon_bootbus_sem);
+	if (!host->has_ciu3)
+		up(&octeon_bootbus_sem);
+	else
+		up(&host->mmc_serializer);
 }
 
 static void octeon_mmc_int_enable(struct cvm_mmc_host *host, u64 val)
 {
 	writeq(val, host->base + MIO_EMM_INT);
-	writeq(val, host->base + MIO_EMM_INT_EN);
+	if (!host->dma_active || (host->dma_active && !host->has_ciu3))
+		writeq(val, host->base + MIO_EMM_INT_EN);
 }
 
 static void octeon_mmc_dmar_fixup(struct cvm_mmc_host *host,
@@ -75,6 +83,9 @@ static int octeon_mmc_probe(struct platform_device *pdev)
 	if (!host)
 		return -ENOMEM;
 
+	spin_lock_init(&host->irq_handler_lock);
+	sema_init(&host->mmc_serializer, 1);
+
 	host->dev = &pdev->dev;
 	host->acquire_bus = octeon_mmc_acquire_bus;
 	host->release_bus = octeon_mmc_release_bus;
@@ -87,12 +98,34 @@ static int octeon_mmc_probe(struct platform_device *pdev)
 
 	host->sys_freq = octeon_get_io_clock_rate();
 
-	/* First one is EMM second DMA */
-	for (i = 0; i < 2; i++) {
-		mmc_irq[i] = platform_get_irq(pdev, i);
-		if (mmc_irq[i] < 0)
-			return mmc_irq[i];
+	if (of_device_is_compatible(node, "cavium,octeon-7890-mmc")) {
+		host->big_dma_addr = true;
+		host->need_irq_handler_lock = true;
+		host->has_ciu3 = true;
+		/*
+		 * First seven are the EMM_INT bits 0..6, then two for
+		 * the EMM_DMA_INT bits
+		 */
+		for (i = 0; i < 9; i++) {
+			mmc_irq[i] = platform_get_irq(pdev, i);
+			if (mmc_irq[i] < 0)
+				return mmc_irq[i];
+
+			/* work around legacy u-boot device trees */
+			irq_set_irq_type(mmc_irq[i], IRQ_TYPE_EDGE_RISING);
+		}
+	} else {
+		host->big_dma_addr = false;
+		host->need_irq_handler_lock = false;
+		host->has_ciu3 = false;
+		/* First one is EMM second DMA */
+		for (i = 0; i < 2; i++) {
+			mmc_irq[i] = platform_get_irq(pdev, i);
+			if (mmc_irq[i] < 0)
+				return mmc_irq[i];
+		}
 	}
+
 	host->last_slot = -1;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -122,12 +155,26 @@ static int octeon_mmc_probe(struct platform_device *pdev)
 	val = readq(host->base + MIO_EMM_INT);
 	writeq(val, host->base + MIO_EMM_INT);
 
-	ret = devm_request_irq(&pdev->dev, mmc_irq[0],
-			       cvm_mmc_interrupt, 0, KBUILD_MODNAME, host);
-	if (ret < 0) {
-		dev_err(&pdev->dev, "Error: devm_request_irq %d\n",
-			mmc_irq[0]);
-		return ret;
+	if (host->has_ciu3) {
+		/* Only CMD_DONE, DMA_DONE, CMD_ERR, DMA_ERR */
+		for (i = 1; i <= 4; i++) {
+			ret = devm_request_irq(&pdev->dev, mmc_irq[i],
+					       cvm_mmc_interrupt,
+					       0, KBUILD_MODNAME, host);
+			if (ret < 0) {
+				dev_err(&pdev->dev, "Error: devm_request_irq %d\n",
+					mmc_irq[i]);
+				return ret;
+			}
+		}
+	} else {
+		ret = devm_request_irq(&pdev->dev, mmc_irq[0],
+				       cvm_mmc_interrupt, 0, KBUILD_MODNAME, host);
+		if (ret < 0) {
+			dev_err(&pdev->dev, "Error: devm_request_irq %d\n",
+				mmc_irq[0]);
+			return ret;
+		}
 	}
 
 	host->global_pwr_gpiod = devm_gpiod_get_optional(&pdev->dev, "power",
-- 
2.9.0.rc0.21.g7777322

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v11 6/9] mmc: cavium: Add MMC PCI driver for ThunderX SOCs
  2017-02-06 13:39 [PATCH v11 0/9] Cavium MMC driver Jan Glauber
                   ` (4 preceding siblings ...)
  2017-02-06 13:39 ` [PATCH v11 5/9] mmc: cavium: Add support for Octeon cn7890 Jan Glauber
@ 2017-02-06 13:39 ` Jan Glauber
  2017-02-12  1:09   ` kbuild test robot
  2017-02-06 13:39 ` [PATCH v11 7/9] mmc: cavium: Add scatter-gather DMA support Jan Glauber
                   ` (2 subsequent siblings)
  8 siblings, 1 reply; 24+ messages in thread
From: Jan Glauber @ 2017-02-06 13:39 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc, linux-kernel, David Daney, Steven J . Hill,
	Jan Glauber, David Daney, Steven J . Hill

Add a platform driver for ThunderX ARM SOCs.

Signed-off-by: Jan Glauber <jglauber@cavium.com>
Signed-off-by: David Daney <david.daney@cavium.com>
Signed-off-by: Steven J. Hill <steven.hill@cavium.com>
---
 drivers/mmc/host/Kconfig               |  10 ++
 drivers/mmc/host/Makefile              |   2 +
 drivers/mmc/host/cavium-mmc.h          |  38 ++++++
 drivers/mmc/host/cavium-pci-thunderx.c | 203 +++++++++++++++++++++++++++++++++
 4 files changed, 253 insertions(+)
 create mode 100644 drivers/mmc/host/cavium-pci-thunderx.c

diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 68cc811..3983dee 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -632,6 +632,16 @@ config MMC_CAVIUM_OCTEON
 
 	  If unsure, say N.
 
+config MMC_CAVIUM_THUNDERX
+	tristate "Cavium ThunderX SD/MMC Card Interface support"
+	depends on PCI && 64BIT && (ARM64 || COMPILE_TEST)
+	select GPIO_THUNDERX
+	help
+	  This selects Cavium ThunderX SD/MMC Card Interface.
+	  If you have an Cavium ARM64 board with a Multimedia Card slot
+	  or builtin eMMC chip say Y or M here. If built as a module
+	  the module will be called thunderx_mmc.ko.
+
 config MMC_DW
 	tristate "Synopsys DesignWare Memory Card Interface"
 	depends on HAS_DMA
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index c7f0ccf..0068610 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -44,6 +44,8 @@ obj-$(CONFIG_MMC_VIA_SDMMC)	+= via-sdmmc.o
 obj-$(CONFIG_SDH_BFIN)		+= bfin_sdh.o
 octeon-mmc-objs := cavium-mmc.o cavium-pltfm-octeon.o
 obj-$(CONFIG_MMC_CAVIUM_OCTEON) += octeon-mmc.o
+thunderx-mmc-objs := cavium-mmc.o cavium-pci-thunderx.o
+obj-$(CONFIG_MMC_CAVIUM_THUNDERX) += thunderx-mmc.o
 obj-$(CONFIG_MMC_DW)		+= dw_mmc.o
 obj-$(CONFIG_MMC_DW_PLTFM)	+= dw_mmc-pltfm.o
 obj-$(CONFIG_MMC_DW_EXYNOS)	+= dw_mmc-exynos.o
diff --git a/drivers/mmc/host/cavium-mmc.h b/drivers/mmc/host/cavium-mmc.h
index 5f41be9..64a837c 100644
--- a/drivers/mmc/host/cavium-mmc.h
+++ b/drivers/mmc/host/cavium-mmc.h
@@ -11,11 +11,14 @@
 #include <linux/io.h>
 #include <linux/mmc/host.h>
 #include <linux/of.h>
+#include <linux/pci.h>
 #include <linux/scatterlist.h>
 #include <linux/semaphore.h>
 
 #define CAVIUM_MAX_MMC		4
 
+#if IS_ENABLED(CONFIG_MMC_CAVIUM_OCTEON)
+
 #define MIO_EMM_DMA_CFG		0x00
 #define MIO_EMM_DMA_ADR		0x08
 
@@ -35,6 +38,36 @@
 #define MIO_EMM_BUF_IDX		0xe0
 #define MIO_EMM_BUF_DAT		0xe8
 
+#elif CONFIG_MMC_CAVIUM_THUNDERX
+
+#define MIO_EMM_DMA_CFG		0x180
+#define MIO_EMM_DMA_ADR		0x188
+#define MIO_EMM_DMA_INT		0x190
+#define MIO_EMM_DMA_INT_W1S	0x198
+#define MIO_EMM_DMA_INT_ENA_W1S	0x1a0
+#define MIO_EMM_DMA_INT_ENA_W1C	0x1a8
+
+#define MIO_EMM_CFG		0x2000
+#define MIO_EMM_SWITCH		0x2048
+#define MIO_EMM_DMA		0x2050
+#define MIO_EMM_CMD		0x2058
+#define MIO_EMM_RSP_STS		0x2060
+#define MIO_EMM_RSP_LO		0x2068
+#define MIO_EMM_RSP_HI		0x2070
+#define MIO_EMM_INT		0x2078
+#define MIO_EMM_INT_EN		0x2080
+#define MIO_EMM_WDOG		0x2088
+#define MIO_EMM_SAMPLE		0x2090
+#define MIO_EMM_STS_MASK	0x2098
+#define MIO_EMM_RCA		0x20a0
+#define MIO_EMM_BUF_IDX		0x20e0
+#define MIO_EMM_BUF_DAT		0x20e8
+
+#define MIO_EMM_INT_EN_SET	0x20b0
+#define MIO_EMM_INT_EN_CLR	0x20b8
+
+#endif
+
 struct cvm_mmc_host {
 	struct device *dev;
 	void __iomem *base;
@@ -66,6 +99,11 @@ struct cvm_mmc_host {
 	void (*dmar_fixup)(struct cvm_mmc_host *, struct mmc_command *,
 			   struct mmc_data *, u64);
 	void (*dmar_fixup_done)(struct cvm_mmc_host *);
+
+#if IS_ENABLED(CONFIG_MMC_CAVIUM_THUNDERX)
+	struct msix_entry	*mmc_msix;
+	unsigned int		msix_count;
+#endif
 };
 
 struct cvm_mmc_slot {
diff --git a/drivers/mmc/host/cavium-pci-thunderx.c b/drivers/mmc/host/cavium-pci-thunderx.c
new file mode 100644
index 0000000..5052c4e
--- /dev/null
+++ b/drivers/mmc/host/cavium-pci-thunderx.c
@@ -0,0 +1,203 @@
+/*
+ * Driver for MMC and SSD cards for Cavium ThunderX 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) 2016 Cavium Inc.
+ */
+#include <linux/dma-mapping.h>
+#include <linux/gpio/consumer.h>
+#include <linux/interrupt.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/slot-gpio.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include "cavium-mmc.h"
+
+struct platform_device *slot_pdev[2];
+
+static void thunder_mmc_acquire_bus(struct cvm_mmc_host *host)
+{
+	down(&host->mmc_serializer);
+}
+
+static void thunder_mmc_release_bus(struct cvm_mmc_host *host)
+{
+	up(&host->mmc_serializer);
+}
+
+static void thunder_mmc_int_enable(struct cvm_mmc_host *host, u64 val)
+{
+	writeq(val, host->base + MIO_EMM_INT);
+	writeq(val, host->base + MIO_EMM_INT_EN_SET);
+}
+
+static int thunder_mmc_register_interrupts(struct cvm_mmc_host *host,
+					   struct pci_dev *pdev)
+{
+	int ret, i;
+
+	host->msix_count = pci_msix_vec_count(pdev);
+	host->mmc_msix = devm_kzalloc(&pdev->dev,
+		(sizeof(struct msix_entry)) * host->msix_count, GFP_KERNEL);
+	if (!host->mmc_msix)
+		return -ENOMEM;
+
+	for (i = 0; i < host->msix_count; i++)
+		host->mmc_msix[i].entry = i;
+
+	ret = pci_enable_msix(pdev, host->mmc_msix, host->msix_count);
+	if (ret)
+		return ret;
+
+	/* register interrupts */
+	for (i = 0; i < host->msix_count; i++) {
+		ret = devm_request_irq(&pdev->dev, host->mmc_msix[i].vector,
+				       cvm_mmc_interrupt,
+				       0, KBUILD_MODNAME, host);
+		if (ret)
+			return ret;
+	}
+	return 0;
+}
+
+static int thunder_mmc_probe(struct pci_dev *pdev,
+			     const struct pci_device_id *id)
+{
+	struct device_node *node = pdev->dev.of_node;
+	struct device *dev = &pdev->dev;
+	struct device_node *child_node;
+	struct cvm_mmc_host *host;
+	int ret, i = 0;
+
+	host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
+	if (!host)
+		return -ENOMEM;
+
+	pci_set_drvdata(pdev, host);
+	ret = pcim_enable_device(pdev);
+	if (ret)
+		return ret;
+
+	ret = pci_request_regions(pdev, KBUILD_MODNAME);
+	if (ret)
+		return ret;
+
+	host->base = pcim_iomap(pdev, 0, pci_resource_len(pdev, 0));
+	if (!host->base)
+		return -EINVAL;
+
+	/* On ThunderX these are identical */
+	host->dma_base = host->base;
+
+	host->clk = devm_clk_get(dev, NULL);
+	if (IS_ERR(host->clk))
+		return PTR_ERR(host->clk);
+
+	ret = clk_prepare_enable(host->clk);
+	if (ret)
+		return ret;
+	host->sys_freq = clk_get_rate(host->clk);
+
+	spin_lock_init(&host->irq_handler_lock);
+	sema_init(&host->mmc_serializer, 1);
+
+	host->dev = dev;
+	host->acquire_bus = thunder_mmc_acquire_bus;
+	host->release_bus = thunder_mmc_release_bus;
+	host->int_enable = thunder_mmc_int_enable;
+
+	host->big_dma_addr = true;
+	host->need_irq_handler_lock = true;
+	host->last_slot = -1;
+
+	ret = dma_set_mask(dev, DMA_BIT_MASK(48));
+	if (ret)
+		goto error;
+
+	/*
+	 * Clear out any pending interrupts that may be left over from
+	 * bootloader. Writing 1 to the bits clears them.
+	 */
+	writeq(127, host->base + MIO_EMM_INT_EN);
+	writeq(3, host->base + MIO_EMM_DMA_INT_ENA_W1C);
+
+	ret = thunder_mmc_register_interrupts(host, pdev);
+	if (ret)
+		goto error;
+
+	for_each_child_of_node(node, child_node) {
+		/*
+		 * TODO: mmc_of_parse and devm* require one device per slot.
+		 * Create a dummy device per slot and set the node pointer to
+		 * the slot. The easiest way to get this is using
+		 * of_platform_device_create.
+		 */
+		if (!slot_pdev[i])
+			slot_pdev[i] = of_platform_device_create(child_node, NULL,
+						      &pdev->dev);
+		if (!slot_pdev[i])
+			continue;
+		ret = cvm_mmc_slot_probe(&slot_pdev[i]->dev, host);
+		if (ret)
+			goto error;
+		i++;
+	}
+	dev_info(dev, "probed\n");
+	return 0;
+
+error:
+	clk_disable_unprepare(host->clk);
+	return ret;
+}
+
+static void thunder_mmc_remove(struct pci_dev *pdev)
+{
+	struct cvm_mmc_host *host = pci_get_drvdata(pdev);
+	union mio_emm_dma_cfg dma_cfg;
+	int i;
+
+	for (i = 0; i < CAVIUM_MAX_MMC; i++)
+		if (host->slot[i]) {
+			cvm_mmc_slot_remove(host->slot[i]);
+			platform_device_del(slot_pdev[i]);
+		}
+
+	dma_cfg.val = readq(host->dma_base + MIO_EMM_DMA_CFG);
+	dma_cfg.s.en = 0;
+	writeq(dma_cfg.val, host->dma_base + MIO_EMM_DMA_CFG);
+
+	clk_disable_unprepare(host->clk);
+}
+
+static const struct pci_device_id thunder_mmc_id_table[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, 0xa010) },
+	{ 0, }  /* end of table */
+};
+
+static struct pci_driver thunder_mmc_driver = {
+	.name = KBUILD_MODNAME,
+	.id_table = thunder_mmc_id_table,
+	.probe = thunder_mmc_probe,
+	.remove = thunder_mmc_remove,
+};
+
+static int __init thunder_mmc_init_module(void)
+{
+	return pci_register_driver(&thunder_mmc_driver);
+}
+
+static void __exit thunder_mmc_exit_module(void)
+{
+	pci_unregister_driver(&thunder_mmc_driver);
+}
+
+module_init(thunder_mmc_init_module);
+module_exit(thunder_mmc_exit_module);
+
+MODULE_AUTHOR("Cavium Inc.");
+MODULE_DESCRIPTION("Cavium ThunderX eMMC Driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, thunder_mmc_id_table);
-- 
2.9.0.rc0.21.g7777322

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v11 7/9] mmc: cavium: Add scatter-gather DMA support
  2017-02-06 13:39 [PATCH v11 0/9] Cavium MMC driver Jan Glauber
                   ` (5 preceding siblings ...)
  2017-02-06 13:39 ` [PATCH v11 6/9] mmc: cavium: Add MMC PCI driver for ThunderX SOCs Jan Glauber
@ 2017-02-06 13:39 ` Jan Glauber
  2017-02-12  1:27   ` kbuild test robot
  2017-02-06 13:39 ` [PATCH v11 8/9] mmc: cavium: Support DDR mode for eMMC devices Jan Glauber
  2017-02-06 13:39 ` [PATCH v11 9/9] MAINTAINERS: Add entry for Cavium MMC driver Jan Glauber
  8 siblings, 1 reply; 24+ messages in thread
From: Jan Glauber @ 2017-02-06 13:39 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc, linux-kernel, David Daney, Steven J . Hill,
	Jan Glauber, David Daney, Steven J . Hill

Add Support for the scatter-gather DMA available in the
ThunderX MMC units. Up to 16 DMA requests can be processed
together.

Signed-off-by: Jan Glauber <jglauber@cavium.com>
Signed-off-by: David Daney <david.daney@cavium.com>
Signed-off-by: Steven J. Hill <steven.hill@cavium.com>
---
 drivers/mmc/host/cavium-mmc.c          | 105 ++++++++++++++++++++++++++++++++-
 drivers/mmc/host/cavium-mmc.h          |  58 ++++++++++++++++++
 drivers/mmc/host/cavium-pci-thunderx.c |   3 +
 3 files changed, 163 insertions(+), 3 deletions(-)

diff --git a/drivers/mmc/host/cavium-mmc.c b/drivers/mmc/host/cavium-mmc.c
index f1fe291..3d3c9c7 100644
--- a/drivers/mmc/host/cavium-mmc.c
+++ b/drivers/mmc/host/cavium-mmc.c
@@ -351,9 +351,31 @@ static int finish_dma_single(struct cvm_mmc_host *host, struct mmc_data *data)
 	return 1;
 }
 
+static int finish_dma_sg(struct cvm_mmc_host *host, struct mmc_data *data)
+{
+	union mio_emm_dma_fifo_cfg fifo_cfg;
+
+	/* Check if there are any pending requests left */
+	fifo_cfg.val = readq(host->dma_base + MIO_EMM_DMA_FIFO_CFG);
+	if (fifo_cfg.s.count)
+		dev_err(host->dev, "%u requests still pending\n",
+			fifo_cfg.s.count);
+
+	data->bytes_xfered = data->blocks * data->blksz;
+	data->error = 0;
+
+	/* Clear and disable FIFO */
+	writeq(BIT_ULL(16), host->dma_base + MIO_EMM_DMA_FIFO_CFG);
+	dma_unmap_sg(host->dev, data->sg, data->sg_len, get_dma_dir(data));
+	return 1;
+}
+
 static int finish_dma(struct cvm_mmc_host *host, struct mmc_data *data)
 {
-	return finish_dma_single(host, data);
+	if (host->use_sg && data->sg_len > 1)
+		return finish_dma_sg(host, data);
+	else
+		return finish_dma_single(host, data);
 }
 
 static bool bad_status(union mio_emm_rsp_sts *rsp_sts)
@@ -493,9 +515,83 @@ static u64 prepare_dma_single(struct cvm_mmc_host *host, struct mmc_data *data)
 	return addr;
 }
 
+/*
+ * Queue complete sg list into the FIFO.
+ * Returns 0 on error, 1 otherwise.
+ */
+static u64 prepare_dma_sg(struct cvm_mmc_host *host, struct mmc_data *data)
+{
+	union mio_emm_dma_fifo_cmd fifo_cmd;
+	struct scatterlist *sg;
+	int count, i;
+	u64 addr;
+
+	count = dma_map_sg(host->dev, data->sg, data->sg_len,
+			   get_dma_dir(data));
+	if (!count)
+		return 0;
+	if (count > 16)
+		goto error;
+
+	/* Enable FIFO by removing CLR bit */
+	writeq(0, host->dma_base + MIO_EMM_DMA_FIFO_CFG);
+
+	for_each_sg(data->sg, sg, count, i) {
+		/* Program DMA address */
+		addr = sg_dma_address(sg);
+		if (addr & 7)
+			goto error;
+		writeq(addr, host->dma_base + MIO_EMM_DMA_FIFO_ADR);
+
+		/*
+		 * If we have scatter-gather support we also have an extra
+		 * register for the DMA addr, so no need to check
+		 * host->big_dma_addr here.
+		 */
+		fifo_cmd.val = 0;
+		fifo_cmd.s.rw = (data->flags & MMC_DATA_WRITE) ? 1 : 0;
+
+		/* enable interrupts on the last element */
+		if (i + 1 == count)
+			fifo_cmd.s.intdis = 0;
+		else
+			fifo_cmd.s.intdis = 1;
+
+#ifdef __LITTLE_ENDIAN
+		fifo_cmd.s.endian = 1;
+#endif
+		fifo_cmd.s.size = sg_dma_len(sg) / 8 - 1;
+		/*
+		 * The write copies the address and the command to the FIFO
+		 * and increments the FIFO's COUNT field.
+		 */
+		writeq(fifo_cmd.val, host->dma_base + MIO_EMM_DMA_FIFO_CMD);
+		pr_debug("[%s] sg_dma_len: %u  sg_elem: %d/%d\n",
+			 (fifo_cmd.s.rw) ? "W" : "R", sg_dma_len(sg), i, count);
+	}
+
+	/*
+	 * In difference to prepare_dma_single we don't return the
+	 * address here, as it would not make sense for scatter-gather.
+	 * The dma fixup is only required on models that don't support
+	 * scatter-gather, so that is not a problem.
+	 */
+	return 1;
+
+error:
+	WARN_ON_ONCE(1);
+	dma_unmap_sg(host->dev, data->sg, data->sg_len, get_dma_dir(data));
+	/* Disable FIFO */
+	writeq(BIT_ULL(16), host->dma_base + MIO_EMM_DMA_FIFO_CFG);
+	return 0;
+}
+
 static u64 prepare_dma(struct cvm_mmc_host *host, struct mmc_data *data)
 {
-	return prepare_dma_single(host, data);
+	if (host->use_sg && data->sg_len > 1)
+		return prepare_dma_sg(host, data);
+	else
+		return prepare_dma_single(host, data);
 }
 
 static void prepare_ext_dma(struct mmc_host *mmc, struct mmc_request *mrq,
@@ -998,7 +1094,10 @@ int cvm_mmc_slot_probe(struct device *dev, struct cvm_mmc_host *host)
 	mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
 		     MMC_CAP_ERASE | MMC_CAP_CMD23 | MMC_CAP_POWER_OFF_CARD;
 
-	mmc->max_segs = 1;
+	if (host->use_sg)
+		mmc->max_segs = 16;
+	else
+		mmc->max_segs = 1;
 
 	/* DMA size field can address up to 8 MB */
 	mmc->max_seg_size = 8 * 1024 * 1024;
diff --git a/drivers/mmc/host/cavium-mmc.h b/drivers/mmc/host/cavium-mmc.h
index 64a837c..04898b8 100644
--- a/drivers/mmc/host/cavium-mmc.h
+++ b/drivers/mmc/host/cavium-mmc.h
@@ -22,6 +22,10 @@
 #define MIO_EMM_DMA_CFG		0x00
 #define MIO_EMM_DMA_ADR		0x08
 
+#define MIO_EMM_DMA_FIFO_CFG	0x00
+#define MIO_EMM_DMA_FIFO_ADR	0x00
+#define MIO_EMM_DMA_FIFO_CMD	0x00
+
 #define MIO_EMM_CFG		0x00
 #define MIO_EMM_SWITCH		0x48
 #define MIO_EMM_DMA		0x50
@@ -40,6 +44,9 @@
 
 #elif CONFIG_MMC_CAVIUM_THUNDERX
 
+#define MIO_EMM_DMA_FIFO_CFG	0x160
+#define MIO_EMM_DMA_FIFO_ADR	0x170
+#define MIO_EMM_DMA_FIFO_CMD	0x178
 #define MIO_EMM_DMA_CFG		0x180
 #define MIO_EMM_DMA_ADR		0x188
 #define MIO_EMM_DMA_INT		0x190
@@ -81,6 +88,7 @@ struct cvm_mmc_host {
 	struct mmc_request *current_req;
 	struct sg_mapping_iter smi;
 	bool dma_active;
+	bool use_sg;
 
 	bool has_ciu3;
 	bool big_dma_addr;
@@ -135,6 +143,56 @@ struct cvm_mmc_cr_mods {
 
 /* Bitfield definitions */
 
+union mio_emm_dma_fifo_cfg {
+	u64 val;
+	struct mio_emm_dma_fifo_cfg_s {
+#ifdef __BIG_ENDIAN_BITFIELD
+		u64 :48;
+		u64 clr:1;
+		u64 :3;
+		u64 int_lvl:4;
+		u64 :3;
+		u64 count:5;
+#else
+		u64 count:5;
+		u64 :3;
+		u64 int_lvl:4;
+		u64 :3;
+		u64 clr:1;
+		u64 :48;
+#endif
+	} s;
+};
+
+union mio_emm_dma_fifo_cmd {
+	u64 val;
+	struct mio_emm_dma_fifo_cmd_s {
+#ifdef __BIG_ENDIAN_BITFIELD
+		u64 :1;
+		u64 rw:1;
+		u64 :1;
+		u64 intdis:1;
+		u64 swap32:1;
+		u64 swap16:1;
+		u64 swap8:1;
+		u64 endian:1;
+		u64 size:20;
+		u64 :36;
+#else
+		u64 :36;
+		u64 size:20;
+		u64 endian:1;
+		u64 swap8:1;
+		u64 swap16:1;
+		u64 swap32:1;
+		u64 intdis:1;
+		u64 :1;
+		u64 rw:1;
+		u64 :1;
+#endif
+	} s;
+};
+
 union mio_emm_cmd {
 	u64 val;
 	struct mio_emm_cmd_s {
diff --git a/drivers/mmc/host/cavium-pci-thunderx.c b/drivers/mmc/host/cavium-pci-thunderx.c
index 5052c4e..579e063 100644
--- a/drivers/mmc/host/cavium-pci-thunderx.c
+++ b/drivers/mmc/host/cavium-pci-thunderx.c
@@ -109,6 +109,7 @@ static int thunder_mmc_probe(struct pci_dev *pdev,
 	host->release_bus = thunder_mmc_release_bus;
 	host->int_enable = thunder_mmc_int_enable;
 
+	host->use_sg = true;
 	host->big_dma_addr = true;
 	host->need_irq_handler_lock = true;
 	host->last_slot = -1;
@@ -123,6 +124,8 @@ static int thunder_mmc_probe(struct pci_dev *pdev,
 	 */
 	writeq(127, host->base + MIO_EMM_INT_EN);
 	writeq(3, host->base + MIO_EMM_DMA_INT_ENA_W1C);
+	/* Clear DMA FIFO */
+	writeq(BIT_ULL(16), host->base + MIO_EMM_DMA_FIFO_CFG);
 
 	ret = thunder_mmc_register_interrupts(host, pdev);
 	if (ret)
-- 
2.9.0.rc0.21.g7777322

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v11 8/9] mmc: cavium: Support DDR mode for eMMC devices
  2017-02-06 13:39 [PATCH v11 0/9] Cavium MMC driver Jan Glauber
                   ` (6 preceding siblings ...)
  2017-02-06 13:39 ` [PATCH v11 7/9] mmc: cavium: Add scatter-gather DMA support Jan Glauber
@ 2017-02-06 13:39 ` Jan Glauber
  2017-02-06 13:39 ` [PATCH v11 9/9] MAINTAINERS: Add entry for Cavium MMC driver Jan Glauber
  8 siblings, 0 replies; 24+ messages in thread
From: Jan Glauber @ 2017-02-06 13:39 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc, linux-kernel, David Daney, Steven J . Hill,
	Jan Glauber, David Daney, Steven J . Hill

Add support for switching to DDR mode for eMMC devices.
Although the host controller only supports 3.3 Volt
and DDR52 uses 1.8 Volt according to the specification
it is possible to use DDR also with 3.3 Volt for eMMC chips.

To switch to DDR mode MMC_CAP_1_8V_DDR is required.

Signed-off-by: Jan Glauber <jglauber@cavium.com>
Signed-off-by: David Daney <david.daney@cavium.com>
Signed-off-by: Steven J. Hill <steven.hill@cavium.com>
---
 drivers/mmc/host/cavium-mmc.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/host/cavium-mmc.c b/drivers/mmc/host/cavium-mmc.c
index 3d3c9c7..8fcb82a 100644
--- a/drivers/mmc/host/cavium-mmc.c
+++ b/drivers/mmc/host/cavium-mmc.c
@@ -858,6 +858,10 @@ static void cvm_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 		break;
 	}
 
+	/* DDR is available for 4/8 bit bus width */
+	if (ios->bus_width && ios->timing == MMC_TIMING_MMC_DDR52)
+		bus_width |= 4;
+
 	slot->bus_width = bus_width;
 
 	if (!ios->clock)
@@ -1091,8 +1095,14 @@ int cvm_mmc_slot_probe(struct device *dev, struct cvm_mmc_host *host)
 	/* Set up host parameters */
 	mmc->ops = &cvm_mmc_ops;
 
+	/*
+	 * We only have a 3.3v supply, we cannot support any
+	 * of the UHS modes. We do support the high speed DDR
+	 * modes up to 52MHz.
+	 */
 	mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
-		     MMC_CAP_ERASE | MMC_CAP_CMD23 | MMC_CAP_POWER_OFF_CARD;
+		     MMC_CAP_ERASE | MMC_CAP_CMD23 | MMC_CAP_POWER_OFF_CARD |
+		     MMC_CAP_3_3V_DDR;
 
 	if (host->use_sg)
 		mmc->max_segs = 16;
-- 
2.9.0.rc0.21.g7777322

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v11 9/9] MAINTAINERS: Add entry for Cavium MMC driver
  2017-02-06 13:39 [PATCH v11 0/9] Cavium MMC driver Jan Glauber
                   ` (7 preceding siblings ...)
  2017-02-06 13:39 ` [PATCH v11 8/9] mmc: cavium: Support DDR mode for eMMC devices Jan Glauber
@ 2017-02-06 13:39 ` Jan Glauber
  8 siblings, 0 replies; 24+ messages in thread
From: Jan Glauber @ 2017-02-06 13:39 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc, linux-kernel, David Daney, Steven J . Hill,
	Jan Glauber, David Daney, Steven J . Hill

Signed-off-by: Jan Glauber <jglauber@cavium.com>
Signed-off-by: David Daney <david.daney@cavium.com>
Signed-off-by: Steven J. Hill <steven.hill@cavium.com>
---
 MAINTAINERS | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 2c171ad..81afd78 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2999,6 +2999,14 @@ S:	Supported
 F:	drivers/i2c/busses/i2c-octeon*
 F:	drivers/i2c/busses/i2c-thunderx*
 
+CAVIUM MMC DRIVER
+M:	Jan Glauber <jglauber@cavium.com>
+M:	David Daney <david.daney@cavium.com>
+M:	Steven J. Hill <Steven.Hill@cavium.com>
+W:	http://www.cavium.com
+S:	Supported
+F:	drivers/mmc/host/cavium-*
+
 CAVIUM LIQUIDIO NETWORK DRIVER
 M:     Derek Chickles <derek.chickles@caviumnetworks.com>
 M:     Satanand Burla <satananda.burla@caviumnetworks.com>
-- 
2.9.0.rc0.21.g7777322

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* Re: [PATCH v11 1/9] dt-bindings: mmc: Add Cavium SOCs MMC bindings
  2017-02-06 13:39 ` [PATCH v11 1/9] dt-bindings: mmc: Add Cavium SOCs MMC bindings Jan Glauber
@ 2017-02-09  0:40   ` Rob Herring
  2017-03-03 11:47   ` Ulf Hansson
  1 sibling, 0 replies; 24+ messages in thread
From: Rob Herring @ 2017-02-09  0:40 UTC (permalink / raw)
  To: Jan Glauber
  Cc: Ulf Hansson, linux-mmc, linux-kernel, David Daney,
	Steven J . Hill, Mark Rutland, devicetree, David Daney

On Mon, Feb 06, 2017 at 02:39:44PM +0100, Jan Glauber wrote:
> Add description of Cavium Octeon and ThunderX SOC device tree bindings.
> 
> CC: Ulf Hansson <ulf.hansson@linaro.org>
> CC: Rob Herring <robh+dt@kernel.org>
> CC: Mark Rutland <mark.rutland@arm.com>
> CC: devicetree@vger.kernel.org
> 
> Signed-off-by: Jan Glauber <jglauber@cavium.com>
> Signed-off-by: David Daney <david.daney@cavium.com>
> Signed-off-by: Steven J. Hill <steven.hill@cavium.com>
> ---
>  .../devicetree/bindings/mmc/cavium-mmc.txt         | 60 ++++++++++++++++++++++
>  1 file changed, 60 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/mmc/cavium-mmc.txt

Acked-by: Rob Herring <robh@kernel.org>

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v11 6/9] mmc: cavium: Add MMC PCI driver for ThunderX SOCs
  2017-02-06 13:39 ` [PATCH v11 6/9] mmc: cavium: Add MMC PCI driver for ThunderX SOCs Jan Glauber
@ 2017-02-12  1:09   ` kbuild test robot
  2017-02-13 15:24     ` Jan Glauber
  0 siblings, 1 reply; 24+ messages in thread
From: kbuild test robot @ 2017-02-12  1:09 UTC (permalink / raw)
  To: Jan Glauber
  Cc: kbuild-all, Ulf Hansson, linux-mmc, linux-kernel, David Daney,
	Steven J . Hill, Jan Glauber, David Daney

[-- Attachment #1: Type: text/plain, Size: 48326 bytes --]

Hi Jan,

[auto build test ERROR on linus/master]
[also build test ERROR on v4.10-rc7 next-20170210]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Jan-Glauber/Cavium-MMC-driver/20170206-214740
config: arm64-allmodconfig (attached as .config)
compiler: aarch64-linux-gnu-gcc (Debian 6.1.1-9) 6.1.1 20160705
reproduce:
        wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=arm64 

All errors (new ones prefixed by >>):

   In file included from drivers/mmc/host/cavium-mmc.c:28:0:
   drivers/mmc/host/cavium-mmc.h:41:7: warning: "CONFIG_MMC_CAVIUM_THUNDERX" is not defined [-Wundef]
    #elif CONFIG_MMC_CAVIUM_THUNDERX
          ^~~~~~~~~~~~~~~~~~~~~~~~~~
   In file included from include/linux/swab.h:4:0,
                    from include/uapi/linux/byteorder/big_endian.h:12,
                    from include/linux/byteorder/big_endian.h:4,
                    from arch/arm64/include/uapi/asm/byteorder.h:20,
                    from include/asm-generic/bitops/le.h:5,
                    from arch/arm64/include/asm/bitops.h:50,
                    from include/linux/bitops.h:36,
                    from include/linux/kernel.h:10,
                    from include/linux/delay.h:10,
                    from drivers/mmc/host/cavium-mmc.c:16:
   drivers/mmc/host/cavium-mmc.c: In function 'check_switch_errors':
>> drivers/mmc/host/cavium-mmc.c:156:38: error: 'MIO_EMM_SWITCH' undeclared (first use in this function)
     emm_switch.val = readq(host->base + MIO_EMM_SWITCH);
                                         ^
   include/uapi/linux/swab.h:129:32: note: in definition of macro '__swab64'
     (__builtin_constant_p((__u64)(x)) ? \
                                   ^
   include/linux/byteorder/generic.h:86:21: note: in expansion of macro '__le64_to_cpu'
    #define le64_to_cpu __le64_to_cpu
                        ^~~~~~~~~~~~~
   arch/arm64/include/asm/io.h:137:32: note: in expansion of macro 'readq_relaxed'
    #define readq(c)  ({ u64 __v = readq_relaxed(c); __iormb(); __v; })
                                   ^~~~~~~~~~~~~
   drivers/mmc/host/cavium-mmc.c:156:19: note: in expansion of macro 'readq'
     emm_switch.val = readq(host->base + MIO_EMM_SWITCH);
                      ^~~~~
   drivers/mmc/host/cavium-mmc.c:156:38: note: each undeclared identifier is reported only once for each function it appears in
     emm_switch.val = readq(host->base + MIO_EMM_SWITCH);
                                         ^
   include/uapi/linux/swab.h:129:32: note: in definition of macro '__swab64'
     (__builtin_constant_p((__u64)(x)) ? \
                                   ^
   include/linux/byteorder/generic.h:86:21: note: in expansion of macro '__le64_to_cpu'
    #define le64_to_cpu __le64_to_cpu
                        ^~~~~~~~~~~~~
   arch/arm64/include/asm/io.h:137:32: note: in expansion of macro 'readq_relaxed'
    #define readq(c)  ({ u64 __v = readq_relaxed(c); __iormb(); __v; })
                                   ^~~~~~~~~~~~~
   drivers/mmc/host/cavium-mmc.c:156:19: note: in expansion of macro 'readq'
     emm_switch.val = readq(host->base + MIO_EMM_SWITCH);
                      ^~~~~
   In file included from include/linux/scatterlist.h:8:0,
                    from include/linux/dma-mapping.h:10,
                    from drivers/mmc/host/cavium-mmc.c:18:
   drivers/mmc/host/cavium-mmc.c: In function 'do_switch':
   drivers/mmc/host/cavium-mmc.c:184:38: error: 'MIO_EMM_SWITCH' undeclared (first use in this function)
     writeq(emm_switch.val, host->base + MIO_EMM_SWITCH);
                                         ^
   arch/arm64/include/asm/io.h:127:78: note: in definition of macro 'writeq_relaxed'
    #define writeq_relaxed(v,c) ((void)__raw_writeq((__force u64)cpu_to_le64(v),(c)))
                                                                                 ^
   drivers/mmc/host/cavium-mmc.c:184:2: note: in expansion of macro 'writeq'
     writeq(emm_switch.val, host->base + MIO_EMM_SWITCH);
     ^~~~~~
   In file included from include/linux/swab.h:4:0,
                    from include/uapi/linux/byteorder/big_endian.h:12,
                    from include/linux/byteorder/big_endian.h:4,
                    from arch/arm64/include/uapi/asm/byteorder.h:20,
                    from include/asm-generic/bitops/le.h:5,
                    from arch/arm64/include/asm/bitops.h:50,
                    from include/linux/bitops.h:36,
                    from include/linux/kernel.h:10,
                    from include/linux/delay.h:10,
                    from drivers/mmc/host/cavium-mmc.c:16:
>> drivers/mmc/host/cavium-mmc.c:191:36: error: 'MIO_EMM_RSP_STS' undeclared (first use in this function)
      rsp_sts.val = readq(host->base + MIO_EMM_RSP_STS);
                                       ^
   include/uapi/linux/swab.h:129:32: note: in definition of macro '__swab64'
     (__builtin_constant_p((__u64)(x)) ? \
                                   ^
   include/linux/byteorder/generic.h:86:21: note: in expansion of macro '__le64_to_cpu'
    #define le64_to_cpu __le64_to_cpu
                        ^~~~~~~~~~~~~
   arch/arm64/include/asm/io.h:137:32: note: in expansion of macro 'readq_relaxed'
    #define readq(c)  ({ u64 __v = readq_relaxed(c); __iormb(); __v; })
                                   ^~~~~~~~~~~~~
   drivers/mmc/host/cavium-mmc.c:191:17: note: in expansion of macro 'readq'
      rsp_sts.val = readq(host->base + MIO_EMM_RSP_STS);
                    ^~~~~
   In file included from include/linux/scatterlist.h:8:0,
                    from include/linux/dma-mapping.h:10,
                    from drivers/mmc/host/cavium-mmc.c:18:
   drivers/mmc/host/cavium-mmc.c: In function 'set_wdog':
>> drivers/mmc/host/cavium-mmc.c:217:37: error: 'MIO_EMM_WDOG' undeclared (first use in this function)
     writeq(timeout, slot->host->base + MIO_EMM_WDOG);
                                        ^
   arch/arm64/include/asm/io.h:127:78: note: in definition of macro 'writeq_relaxed'
    #define writeq_relaxed(v,c) ((void)__raw_writeq((__force u64)cpu_to_le64(v),(c)))
                                                                                 ^
   drivers/mmc/host/cavium-mmc.c:217:2: note: in expansion of macro 'writeq'
     writeq(timeout, slot->host->base + MIO_EMM_WDOG);
     ^~~~~~
   In file included from include/linux/swab.h:4:0,
                    from include/uapi/linux/byteorder/big_endian.h:12,
                    from include/linux/byteorder/big_endian.h:4,
                    from arch/arm64/include/uapi/asm/byteorder.h:20,
                    from include/asm-generic/bitops/le.h:5,
                    from arch/arm64/include/asm/bitops.h:50,
                    from include/linux/bitops.h:36,
                    from include/linux/kernel.h:10,
                    from include/linux/delay.h:10,
                    from drivers/mmc/host/cavium-mmc.c:16:
   drivers/mmc/host/cavium-mmc.c: In function 'cvm_mmc_reset_bus':
   drivers/mmc/host/cavium-mmc.c:225:44: error: 'MIO_EMM_SWITCH' undeclared (first use in this function)
     emm_switch.val = readq(slot->host->base + MIO_EMM_SWITCH);
                                               ^
   include/uapi/linux/swab.h:129:32: note: in definition of macro '__swab64'
     (__builtin_constant_p((__u64)(x)) ? \
                                   ^
   include/linux/byteorder/generic.h:86:21: note: in expansion of macro '__le64_to_cpu'
    #define le64_to_cpu __le64_to_cpu
                        ^~~~~~~~~~~~~
   arch/arm64/include/asm/io.h:137:32: note: in expansion of macro 'readq_relaxed'
    #define readq(c)  ({ u64 __v = readq_relaxed(c); __iormb(); __v; })
                                   ^~~~~~~~~~~~~
   drivers/mmc/host/cavium-mmc.c:225:19: note: in expansion of macro 'readq'
     emm_switch.val = readq(slot->host->base + MIO_EMM_SWITCH);
                      ^~~~~
   drivers/mmc/host/cavium-mmc.c:226:34: error: 'MIO_EMM_WDOG' undeclared (first use in this function)
     wdog = readq(slot->host->base + MIO_EMM_WDOG);
                                     ^
   include/uapi/linux/swab.h:129:32: note: in definition of macro '__swab64'
     (__builtin_constant_p((__u64)(x)) ? \
                                   ^
   include/linux/byteorder/generic.h:86:21: note: in expansion of macro '__le64_to_cpu'
    #define le64_to_cpu __le64_to_cpu
                        ^~~~~~~~~~~~~
   arch/arm64/include/asm/io.h:137:32: note: in expansion of macro 'readq_relaxed'
    #define readq(c)  ({ u64 __v = readq_relaxed(c); __iormb(); __v; })
                                   ^~~~~~~~~~~~~
   drivers/mmc/host/cavium-mmc.c:226:9: note: in expansion of macro 'readq'
     wdog = readq(slot->host->base + MIO_EMM_WDOG);
            ^~~~~
   drivers/mmc/host/cavium-mmc.c: In function 'cvm_mmc_switch_to':
   drivers/mmc/host/cavium-mmc.c:255:48: error: 'MIO_EMM_SWITCH' undeclared (first use in this function)
      old_slot->cached_switch = readq(host->base + MIO_EMM_SWITCH);
                                                   ^
   include/uapi/linux/swab.h:129:32: note: in definition of macro '__swab64'
     (__builtin_constant_p((__u64)(x)) ? \
                                   ^
   include/linux/byteorder/generic.h:86:21: note: in expansion of macro '__le64_to_cpu'
    #define le64_to_cpu __le64_to_cpu
                        ^~~~~~~~~~~~~
   arch/arm64/include/asm/io.h:137:32: note: in expansion of macro 'readq_relaxed'
    #define readq(c)  ({ u64 __v = readq_relaxed(c); __iormb(); __v; })
                                   ^~~~~~~~~~~~~
   drivers/mmc/host/cavium-mmc.c:255:29: note: in expansion of macro 'readq'
      old_slot->cached_switch = readq(host->base + MIO_EMM_SWITCH);
                                ^~~~~
>> drivers/mmc/host/cavium-mmc.c:256:45: error: 'MIO_EMM_RCA' undeclared (first use in this function)
      old_slot->cached_rca = readq(host->base + MIO_EMM_RCA);
                                                ^
   include/uapi/linux/swab.h:129:32: note: in definition of macro '__swab64'
     (__builtin_constant_p((__u64)(x)) ? \
                                   ^
   include/linux/byteorder/generic.h:86:21: note: in expansion of macro '__le64_to_cpu'
    #define le64_to_cpu __le64_to_cpu
                        ^~~~~~~~~~~~~
   arch/arm64/include/asm/io.h:137:32: note: in expansion of macro 'readq_relaxed'
    #define readq(c)  ({ u64 __v = readq_relaxed(c); __iormb(); __v; })
                                   ^~~~~~~~~~~~~
   drivers/mmc/host/cavium-mmc.c:256:26: note: in expansion of macro 'readq'
      old_slot->cached_rca = readq(host->base + MIO_EMM_RCA);
                             ^~~~~
   In file included from include/linux/scatterlist.h:8:0,
                    from include/linux/dma-mapping.h:10,
                    from drivers/mmc/host/cavium-mmc.c:18:
>> drivers/mmc/host/cavium-mmc.c:267:38: error: 'MIO_EMM_SAMPLE' undeclared (first use in this function)
     writeq(emm_sample.val, host->base + MIO_EMM_SAMPLE);
                                         ^
   arch/arm64/include/asm/io.h:127:78: note: in definition of macro 'writeq_relaxed'
    #define writeq_relaxed(v,c) ((void)__raw_writeq((__force u64)cpu_to_le64(v),(c)))
                                                                                 ^
   drivers/mmc/host/cavium-mmc.c:267:2: note: in expansion of macro 'writeq'
     writeq(emm_sample.val, host->base + MIO_EMM_SAMPLE);
     ^~~~~~
   drivers/mmc/host/cavium-mmc.c: In function 'do_read':
>> drivers/mmc/host/cavium-mmc.c:281:47: error: 'MIO_EMM_BUF_IDX' undeclared (first use in this function)
     writeq((0x10000 | (dbuf << 6)), host->base + MIO_EMM_BUF_IDX);
                                                  ^
   arch/arm64/include/asm/io.h:127:78: note: in definition of macro 'writeq_relaxed'
    #define writeq_relaxed(v,c) ((void)__raw_writeq((__force u64)cpu_to_le64(v),(c)))
                                                                                 ^
   drivers/mmc/host/cavium-mmc.c:281:2: note: in expansion of macro 'writeq'
     writeq((0x10000 | (dbuf << 6)), host->base + MIO_EMM_BUF_IDX);
     ^~~~~~
   In file included from include/linux/swab.h:4:0,
                    from include/uapi/linux/byteorder/big_endian.h:12,
                    from include/linux/byteorder/big_endian.h:4,
                    from arch/arm64/include/uapi/asm/byteorder.h:20,
                    from include/asm-generic/bitops/le.h:5,
                    from arch/arm64/include/asm/bitops.h:50,
                    from include/linux/bitops.h:36,
                    from include/linux/kernel.h:10,
                    from include/linux/delay.h:10,
                    from drivers/mmc/host/cavium-mmc.c:16:
>> drivers/mmc/host/cavium-mmc.c:291:29: error: 'MIO_EMM_BUF_DAT' undeclared (first use in this function)
       dat = readq(host->base + MIO_EMM_BUF_DAT);
                                ^
   include/uapi/linux/swab.h:129:32: note: in definition of macro '__swab64'
     (__builtin_constant_p((__u64)(x)) ? \
                                   ^
   include/linux/byteorder/generic.h:86:21: note: in expansion of macro '__le64_to_cpu'
    #define le64_to_cpu __le64_to_cpu
                        ^~~~~~~~~~~~~
   arch/arm64/include/asm/io.h:137:32: note: in expansion of macro 'readq_relaxed'
    #define readq(c)  ({ u64 __v = readq_relaxed(c); __iormb(); __v; })
                                   ^~~~~~~~~~~~~
   drivers/mmc/host/cavium-mmc.c:291:10: note: in expansion of macro 'readq'
       dat = readq(host->base + MIO_EMM_BUF_DAT);
             ^~~~~
   drivers/mmc/host/cavium-mmc.c: In function 'set_cmd_response':
>> drivers/mmc/host/cavium-mmc.c:322:30: error: 'MIO_EMM_RSP_LO' undeclared (first use in this function)
     rsp_lo = readq(host->base + MIO_EMM_RSP_LO);
                                 ^
   include/uapi/linux/swab.h:129:32: note: in definition of macro '__swab64'
     (__builtin_constant_p((__u64)(x)) ? \
                                   ^
   include/linux/byteorder/generic.h:86:21: note: in expansion of macro '__le64_to_cpu'
    #define le64_to_cpu __le64_to_cpu
                        ^~~~~~~~~~~~~
   arch/arm64/include/asm/io.h:137:32: note: in expansion of macro 'readq_relaxed'
    #define readq(c)  ({ u64 __v = readq_relaxed(c); __iormb(); __v; })
                                   ^~~~~~~~~~~~~
   drivers/mmc/host/cavium-mmc.c:322:11: note: in expansion of macro 'readq'
     rsp_lo = readq(host->base + MIO_EMM_RSP_LO);
              ^~~~~
>> drivers/mmc/host/cavium-mmc.c:335:31: error: 'MIO_EMM_RSP_HI' undeclared (first use in this function)
      rsp_hi = readq(host->base + MIO_EMM_RSP_HI);
                                  ^
   include/uapi/linux/swab.h:129:32: note: in definition of macro '__swab64'
     (__builtin_constant_p((__u64)(x)) ? \
                                   ^
   include/linux/byteorder/generic.h:86:21: note: in expansion of macro '__le64_to_cpu'
    #define le64_to_cpu __le64_to_cpu
                        ^~~~~~~~~~~~~
   arch/arm64/include/asm/io.h:137:32: note: in expansion of macro 'readq_relaxed'
    #define readq(c)  ({ u64 __v = readq_relaxed(c); __iormb(); __v; })
                                   ^~~~~~~~~~~~~
   drivers/mmc/host/cavium-mmc.c:335:12: note: in expansion of macro 'readq'
      rsp_hi = readq(host->base + MIO_EMM_RSP_HI);
               ^~~~~
   drivers/mmc/host/cavium-mmc.c: In function 'cleanup_dma':
>> drivers/mmc/host/cavium-mmc.c:375:35: error: 'MIO_EMM_DMA' undeclared (first use in this function)
     emm_dma.val = readq(host->base + MIO_EMM_DMA);
                                      ^
   include/uapi/linux/swab.h:129:32: note: in definition of macro '__swab64'
     (__builtin_constant_p((__u64)(x)) ? \
                                   ^
   include/linux/byteorder/generic.h:86:21: note: in expansion of macro '__le64_to_cpu'
    #define le64_to_cpu __le64_to_cpu
                        ^~~~~~~~~~~~~
   arch/arm64/include/asm/io.h:137:32: note: in expansion of macro 'readq_relaxed'
    #define readq(c)  ({ u64 __v = readq_relaxed(c); __iormb(); __v; })
                                   ^~~~~~~~~~~~~
   drivers/mmc/host/cavium-mmc.c:375:16: note: in expansion of macro 'readq'
     emm_dma.val = readq(host->base + MIO_EMM_DMA);
                   ^~~~~
   drivers/mmc/host/cavium-mmc.c: In function 'cvm_mmc_interrupt':
>> drivers/mmc/host/cavium-mmc.c:397:35: error: 'MIO_EMM_INT' undeclared (first use in this function)
     emm_int.val = readq(host->base + MIO_EMM_INT);
                                      ^
   include/uapi/linux/swab.h:129:32: note: in definition of macro '__swab64'
     (__builtin_constant_p((__u64)(x)) ? \
                                   ^
   include/linux/byteorder/generic.h:86:21: note: in expansion of macro '__le64_to_cpu'
    #define le64_to_cpu __le64_to_cpu
                        ^~~~~~~~~~~~~
   arch/arm64/include/asm/io.h:137:32: note: in expansion of macro 'readq_relaxed'
    #define readq(c)  ({ u64 __v = readq_relaxed(c); __iormb(); __v; })
                                   ^~~~~~~~~~~~~
   drivers/mmc/host/cavium-mmc.c:397:16: note: in expansion of macro 'readq'
     emm_int.val = readq(host->base + MIO_EMM_INT);
                   ^~~~~
   drivers/mmc/host/cavium-mmc.c:407:35: error: 'MIO_EMM_RSP_STS' undeclared (first use in this function)
     rsp_sts.val = readq(host->base + MIO_EMM_RSP_STS);
                                      ^
   include/uapi/linux/swab.h:129:32: note: in definition of macro '__swab64'
     (__builtin_constant_p((__u64)(x)) ? \
                                   ^
   include/linux/byteorder/generic.h:86:21: note: in expansion of macro '__le64_to_cpu'
    #define le64_to_cpu __le64_to_cpu
                        ^~~~~~~~~~~~~
   arch/arm64/include/asm/io.h:137:32: note: in expansion of macro 'readq_relaxed'
    #define readq(c)  ({ u64 __v = readq_relaxed(c); __iormb(); __v; })
                                   ^~~~~~~~~~~~~
   drivers/mmc/host/cavium-mmc.c:407:16: note: in expansion of macro 'readq'
     rsp_sts.val = readq(host->base + MIO_EMM_RSP_STS);
                   ^~~~~
   In file included from include/linux/scatterlist.h:8:0,
                    from include/linux/dma-mapping.h:10,
                    from drivers/mmc/host/cavium-mmc.c:18:
   drivers/mmc/host/cavium-mmc.c: In function 'prepare_dma_single':
>> drivers/mmc/host/cavium-mmc.c:486:39: error: 'MIO_EMM_DMA_CFG' undeclared (first use in this function)
     writeq(dma_cfg.val, host->dma_base + MIO_EMM_DMA_CFG);
                                          ^
   arch/arm64/include/asm/io.h:127:78: note: in definition of macro 'writeq_relaxed'
    #define writeq_relaxed(v,c) ((void)__raw_writeq((__force u64)cpu_to_le64(v),(c)))
                                                                                 ^
   drivers/mmc/host/cavium-mmc.c:486:2: note: in expansion of macro 'writeq'
     writeq(dma_cfg.val, host->dma_base + MIO_EMM_DMA_CFG);
     ^~~~~~
>> drivers/mmc/host/cavium-mmc.c:492:33: error: 'MIO_EMM_DMA_ADR' undeclared (first use in this function)
      writeq(addr, host->dma_base + MIO_EMM_DMA_ADR);
                                    ^
   arch/arm64/include/asm/io.h:127:78: note: in definition of macro 'writeq_relaxed'
    #define writeq_relaxed(v,c) ((void)__raw_writeq((__force u64)cpu_to_le64(v),(c)))
                                                                                 ^
   drivers/mmc/host/cavium-mmc.c:492:3: note: in expansion of macro 'writeq'
      writeq(addr, host->dma_base + MIO_EMM_DMA_ADR);
      ^~~~~~
   drivers/mmc/host/cavium-mmc.c: In function 'cvm_mmc_dma_request':
>> drivers/mmc/host/cavium-mmc.c:587:38: error: 'MIO_EMM_STS_MASK' undeclared (first use in this function)
      writeq(0x00b00000ull, host->base + MIO_EMM_STS_MASK);
                                         ^
   arch/arm64/include/asm/io.h:127:78: note: in definition of macro 'writeq_relaxed'
    #define writeq_relaxed(v,c) ((void)__raw_writeq((__force u64)cpu_to_le64(v),(c)))
                                                                                 ^
   drivers/mmc/host/cavium-mmc.c:587:3: note: in expansion of macro 'writeq'
      writeq(0x00b00000ull, host->base + MIO_EMM_STS_MASK);
      ^~~~~~
   drivers/mmc/host/cavium-mmc.c:590:35: error: 'MIO_EMM_DMA' undeclared (first use in this function)
     writeq(emm_dma.val, host->base + MIO_EMM_DMA);
                                      ^
   arch/arm64/include/asm/io.h:127:78: note: in definition of macro 'writeq_relaxed'
    #define writeq_relaxed(v,c) ((void)__raw_writeq((__force u64)cpu_to_le64(v),(c)))
                                                                                 ^
   drivers/mmc/host/cavium-mmc.c:590:2: note: in expansion of macro 'writeq'
     writeq(emm_dma.val, host->base + MIO_EMM_DMA);
     ^~~~~~
   drivers/mmc/host/cavium-mmc.c: In function 'do_write_request':
   drivers/mmc/host/cavium-mmc.c:618:34: error: 'MIO_EMM_BUF_IDX' undeclared (first use in this function)
     writeq(0x10000ull, host->base + MIO_EMM_BUF_IDX);
                                     ^
   arch/arm64/include/asm/io.h:127:78: note: in definition of macro 'writeq_relaxed'
    #define writeq_relaxed(v,c) ((void)__raw_writeq((__force u64)cpu_to_le64(v),(c)))
                                                                                 ^
   drivers/mmc/host/cavium-mmc.c:618:2: note: in expansion of macro 'writeq'
     writeq(0x10000ull, host->base + MIO_EMM_BUF_IDX);
     ^~~~~~
   drivers/mmc/host/cavium-mmc.c:635:29: error: 'MIO_EMM_BUF_DAT' undeclared (first use in this function)
       writeq(dat, host->base + MIO_EMM_BUF_DAT);
                                ^
   arch/arm64/include/asm/io.h:127:78: note: in definition of macro 'writeq_relaxed'
    #define writeq_relaxed(v,c) ((void)__raw_writeq((__force u64)cpu_to_le64(v),(c)))
                                                                                 ^
   drivers/mmc/host/cavium-mmc.c:635:4: note: in expansion of macro 'writeq'
       writeq(dat, host->base + MIO_EMM_BUF_DAT);
       ^~~~~~
   drivers/mmc/host/cavium-mmc.c: In function 'cvm_mmc_request':
   drivers/mmc/host/cavium-mmc.c:704:25: error: 'MIO_EMM_STS_MASK' undeclared (first use in this function)
     writeq(0, host->base + MIO_EMM_STS_MASK);
                            ^
   arch/arm64/include/asm/io.h:127:78: note: in definition of macro 'writeq_relaxed'
    #define writeq_relaxed(v,c) ((void)__raw_writeq((__force u64)cpu_to_le64(v),(c)))
                                                                                 ^
   drivers/mmc/host/cavium-mmc.c:704:2: note: in expansion of macro 'writeq'
     writeq(0, host->base + MIO_EMM_STS_MASK);
     ^~~~~~
   In file included from include/linux/swab.h:4:0,
                    from include/uapi/linux/byteorder/big_endian.h:12,
                    from include/linux/byteorder/big_endian.h:4,
                    from arch/arm64/include/uapi/asm/byteorder.h:20,
                    from include/asm-generic/bitops/le.h:5,
                    from arch/arm64/include/asm/bitops.h:50,
                    from include/linux/bitops.h:36,
                    from include/linux/kernel.h:10,
                    from include/linux/delay.h:10,
                    from drivers/mmc/host/cavium-mmc.c:16:
   drivers/mmc/host/cavium-mmc.c:707:35: error: 'MIO_EMM_RSP_STS' undeclared (first use in this function)
     rsp_sts.val = readq(host->base + MIO_EMM_RSP_STS);
                                      ^
   include/uapi/linux/swab.h:129:32: note: in definition of macro '__swab64'
     (__builtin_constant_p((__u64)(x)) ? \
                                   ^
   include/linux/byteorder/generic.h:86:21: note: in expansion of macro '__le64_to_cpu'
    #define le64_to_cpu __le64_to_cpu
                        ^~~~~~~~~~~~~
   arch/arm64/include/asm/io.h:137:32: note: in expansion of macro 'readq_relaxed'
    #define readq(c)  ({ u64 __v = readq_relaxed(c); __iormb(); __v; })
                                   ^~~~~~~~~~~~~
   drivers/mmc/host/cavium-mmc.c:707:16: note: in expansion of macro 'readq'
     rsp_sts.val = readq(host->base + MIO_EMM_RSP_STS);
                   ^~~~~
   In file included from include/linux/scatterlist.h:8:0,
                    from include/linux/dma-mapping.h:10,
                    from drivers/mmc/host/cavium-mmc.c:18:
>> drivers/mmc/host/cavium-mmc.c:716:35: error: 'MIO_EMM_CMD' undeclared (first use in this function)
     writeq(emm_cmd.val, host->base + MIO_EMM_CMD);
                                      ^
   arch/arm64/include/asm/io.h:127:78: note: in definition of macro 'writeq_relaxed'
    #define writeq_relaxed(v,c) ((void)__raw_writeq((__force u64)cpu_to_le64(v),(c)))
                                                                                 ^
   drivers/mmc/host/cavium-mmc.c:716:2: note: in expansion of macro 'writeq'
     writeq(emm_cmd.val, host->base + MIO_EMM_CMD);
     ^~~~~~
   drivers/mmc/host/cavium-mmc.c: In function 'cvm_mmc_init_lowlevel':
>> drivers/mmc/host/cavium-mmc.c:818:43: error: 'MIO_EMM_CFG' undeclared (first use in this function)
     writeq(host->emm_cfg, slot->host->base + MIO_EMM_CFG);
                                              ^
   arch/arm64/include/asm/io.h:127:78: note: in definition of macro 'writeq_relaxed'
    #define writeq_relaxed(v,c) ((void)__raw_writeq((__force u64)cpu_to_le64(v),(c)))
                                                                                 ^
   drivers/mmc/host/cavium-mmc.c:818:2: note: in expansion of macro 'writeq'
     writeq(host->emm_cfg, slot->host->base + MIO_EMM_CFG);
     ^~~~~~
   drivers/mmc/host/cavium-mmc.c:841:37: error: 'MIO_EMM_STS_MASK' undeclared (first use in this function)
     writeq(0xe4390080ull, host->base + MIO_EMM_STS_MASK);
                                        ^
   arch/arm64/include/asm/io.h:127:78: note: in definition of macro 'writeq_relaxed'
    #define writeq_relaxed(v,c) ((void)__raw_writeq((__force u64)cpu_to_le64(v),(c)))
                                                                                 ^
   drivers/mmc/host/cavium-mmc.c:841:2: note: in expansion of macro 'writeq'
     writeq(0xe4390080ull, host->base + MIO_EMM_STS_MASK);
     ^~~~~~
   drivers/mmc/host/cavium-mmc.c:842:25: error: 'MIO_EMM_RCA' undeclared (first use in this function)
     writeq(1, host->base + MIO_EMM_RCA);
                            ^
   arch/arm64/include/asm/io.h:127:78: note: in definition of macro 'writeq_relaxed'
    #define writeq_relaxed(v,c) ((void)__raw_writeq((__force u64)cpu_to_le64(v),(c)))
                                                                                 ^
   drivers/mmc/host/cavium-mmc.c:842:2: note: in expansion of macro 'writeq'
     writeq(1, host->base + MIO_EMM_RCA);
     ^~~~~~
..

vim +/MIO_EMM_SWITCH +156 drivers/mmc/host/cavium-mmc.c

a16e92de Jan Glauber 2017-02-06   10   * Authors:
a16e92de Jan Glauber 2017-02-06   11   *   David Daney <david.daney@cavium.com>
a16e92de Jan Glauber 2017-02-06   12   *   Peter Swain <pswain@cavium.com>
a16e92de Jan Glauber 2017-02-06   13   *   Steven J. Hill <steven.hill@cavium.com>
a16e92de Jan Glauber 2017-02-06   14   *   Jan Glauber <jglauber@cavium.com>
a16e92de Jan Glauber 2017-02-06   15   */
a16e92de Jan Glauber 2017-02-06  @16  #include <linux/delay.h>
a16e92de Jan Glauber 2017-02-06   17  #include <linux/dma-direction.h>
a16e92de Jan Glauber 2017-02-06   18  #include <linux/dma-mapping.h>
a16e92de Jan Glauber 2017-02-06   19  #include <linux/gpio/consumer.h>
a16e92de Jan Glauber 2017-02-06   20  #include <linux/interrupt.h>
a16e92de Jan Glauber 2017-02-06   21  #include <linux/mmc/mmc.h>
a16e92de Jan Glauber 2017-02-06   22  #include <linux/mmc/slot-gpio.h>
a16e92de Jan Glauber 2017-02-06   23  #include <linux/module.h>
a16e92de Jan Glauber 2017-02-06   24  #include <linux/regulator/consumer.h>
a16e92de Jan Glauber 2017-02-06   25  #include <linux/scatterlist.h>
a16e92de Jan Glauber 2017-02-06   26  #include <linux/time.h>
a16e92de Jan Glauber 2017-02-06   27  
a16e92de Jan Glauber 2017-02-06   28  #include "cavium-mmc.h"
a16e92de Jan Glauber 2017-02-06   29  
a16e92de Jan Glauber 2017-02-06   30  /*
a16e92de Jan Glauber 2017-02-06   31   * The Cavium MMC host hardware assumes that all commands have fixed
a16e92de Jan Glauber 2017-02-06   32   * command and response types.  These are correct if MMC devices are
a16e92de Jan Glauber 2017-02-06   33   * being used.  However, non-MMC devices like SD use command and
a16e92de Jan Glauber 2017-02-06   34   * response types that are unexpected by the host hardware.
a16e92de Jan Glauber 2017-02-06   35   *
a16e92de Jan Glauber 2017-02-06   36   * The command and response types can be overridden by supplying an
a16e92de Jan Glauber 2017-02-06   37   * XOR value that is applied to the type.  We calculate the XOR value
a16e92de Jan Glauber 2017-02-06   38   * from the values in this table and the flags passed from the MMC
a16e92de Jan Glauber 2017-02-06   39   * core.
a16e92de Jan Glauber 2017-02-06   40   */
a16e92de Jan Glauber 2017-02-06   41  static struct cvm_mmc_cr_type cvm_mmc_cr_types[] = {
a16e92de Jan Glauber 2017-02-06   42  	{0, 0},		/* CMD0 */
a16e92de Jan Glauber 2017-02-06   43  	{0, 3},		/* CMD1 */
a16e92de Jan Glauber 2017-02-06   44  	{0, 2},		/* CMD2 */
a16e92de Jan Glauber 2017-02-06   45  	{0, 1},		/* CMD3 */
a16e92de Jan Glauber 2017-02-06   46  	{0, 0},		/* CMD4 */
a16e92de Jan Glauber 2017-02-06   47  	{0, 1},		/* CMD5 */
a16e92de Jan Glauber 2017-02-06   48  	{0, 1},		/* CMD6 */
a16e92de Jan Glauber 2017-02-06   49  	{0, 1},		/* CMD7 */
a16e92de Jan Glauber 2017-02-06   50  	{1, 1},		/* CMD8 */
a16e92de Jan Glauber 2017-02-06   51  	{0, 2},		/* CMD9 */
a16e92de Jan Glauber 2017-02-06   52  	{0, 2},		/* CMD10 */
a16e92de Jan Glauber 2017-02-06   53  	{1, 1},		/* CMD11 */
a16e92de Jan Glauber 2017-02-06   54  	{0, 1},		/* CMD12 */
a16e92de Jan Glauber 2017-02-06   55  	{0, 1},		/* CMD13 */
a16e92de Jan Glauber 2017-02-06   56  	{1, 1},		/* CMD14 */
a16e92de Jan Glauber 2017-02-06   57  	{0, 0},		/* CMD15 */
a16e92de Jan Glauber 2017-02-06   58  	{0, 1},		/* CMD16 */
a16e92de Jan Glauber 2017-02-06   59  	{1, 1},		/* CMD17 */
a16e92de Jan Glauber 2017-02-06   60  	{1, 1},		/* CMD18 */
a16e92de Jan Glauber 2017-02-06   61  	{3, 1},		/* CMD19 */
a16e92de Jan Glauber 2017-02-06   62  	{2, 1},		/* CMD20 */
a16e92de Jan Glauber 2017-02-06   63  	{0, 0},		/* CMD21 */
a16e92de Jan Glauber 2017-02-06   64  	{0, 0},		/* CMD22 */
a16e92de Jan Glauber 2017-02-06   65  	{0, 1},		/* CMD23 */
a16e92de Jan Glauber 2017-02-06   66  	{2, 1},		/* CMD24 */
a16e92de Jan Glauber 2017-02-06   67  	{2, 1},		/* CMD25 */
a16e92de Jan Glauber 2017-02-06   68  	{2, 1},		/* CMD26 */
a16e92de Jan Glauber 2017-02-06   69  	{2, 1},		/* CMD27 */
a16e92de Jan Glauber 2017-02-06   70  	{0, 1},		/* CMD28 */
a16e92de Jan Glauber 2017-02-06   71  	{0, 1},		/* CMD29 */
a16e92de Jan Glauber 2017-02-06   72  	{1, 1},		/* CMD30 */
a16e92de Jan Glauber 2017-02-06   73  	{1, 1},		/* CMD31 */
a16e92de Jan Glauber 2017-02-06   74  	{0, 0},		/* CMD32 */
a16e92de Jan Glauber 2017-02-06   75  	{0, 0},		/* CMD33 */
a16e92de Jan Glauber 2017-02-06   76  	{0, 0},		/* CMD34 */
a16e92de Jan Glauber 2017-02-06   77  	{0, 1},		/* CMD35 */
a16e92de Jan Glauber 2017-02-06   78  	{0, 1},		/* CMD36 */
a16e92de Jan Glauber 2017-02-06   79  	{0, 0},		/* CMD37 */
a16e92de Jan Glauber 2017-02-06   80  	{0, 1},		/* CMD38 */
a16e92de Jan Glauber 2017-02-06   81  	{0, 4},		/* CMD39 */
a16e92de Jan Glauber 2017-02-06   82  	{0, 5},		/* CMD40 */
a16e92de Jan Glauber 2017-02-06   83  	{0, 0},		/* CMD41 */
a16e92de Jan Glauber 2017-02-06   84  	{2, 1},		/* CMD42 */
a16e92de Jan Glauber 2017-02-06   85  	{0, 0},		/* CMD43 */
a16e92de Jan Glauber 2017-02-06   86  	{0, 0},		/* CMD44 */
a16e92de Jan Glauber 2017-02-06   87  	{0, 0},		/* CMD45 */
a16e92de Jan Glauber 2017-02-06   88  	{0, 0},		/* CMD46 */
a16e92de Jan Glauber 2017-02-06   89  	{0, 0},		/* CMD47 */
a16e92de Jan Glauber 2017-02-06   90  	{0, 0},		/* CMD48 */
a16e92de Jan Glauber 2017-02-06   91  	{0, 0},		/* CMD49 */
a16e92de Jan Glauber 2017-02-06   92  	{0, 0},		/* CMD50 */
a16e92de Jan Glauber 2017-02-06   93  	{0, 0},		/* CMD51 */
a16e92de Jan Glauber 2017-02-06   94  	{0, 0},		/* CMD52 */
a16e92de Jan Glauber 2017-02-06   95  	{0, 0},		/* CMD53 */
a16e92de Jan Glauber 2017-02-06   96  	{0, 0},		/* CMD54 */
a16e92de Jan Glauber 2017-02-06   97  	{0, 1},		/* CMD55 */
a16e92de Jan Glauber 2017-02-06   98  	{0xff, 0xff},	/* CMD56 */
a16e92de Jan Glauber 2017-02-06   99  	{0, 0},		/* CMD57 */
a16e92de Jan Glauber 2017-02-06  100  	{0, 0},		/* CMD58 */
a16e92de Jan Glauber 2017-02-06  101  	{0, 0},		/* CMD59 */
a16e92de Jan Glauber 2017-02-06  102  	{0, 0},		/* CMD60 */
a16e92de Jan Glauber 2017-02-06  103  	{0, 0},		/* CMD61 */
a16e92de Jan Glauber 2017-02-06  104  	{0, 0},		/* CMD62 */
a16e92de Jan Glauber 2017-02-06  105  	{0, 0}		/* CMD63 */
a16e92de Jan Glauber 2017-02-06  106  };
a16e92de Jan Glauber 2017-02-06  107  
a16e92de Jan Glauber 2017-02-06  108  static struct cvm_mmc_cr_mods cvm_mmc_get_cr_mods(struct mmc_command *cmd)
a16e92de Jan Glauber 2017-02-06  109  {
a16e92de Jan Glauber 2017-02-06  110  	struct cvm_mmc_cr_type *cr;
a16e92de Jan Glauber 2017-02-06  111  	u8 hardware_ctype, hardware_rtype;
a16e92de Jan Glauber 2017-02-06  112  	u8 desired_ctype = 0, desired_rtype = 0;
a16e92de Jan Glauber 2017-02-06  113  	struct cvm_mmc_cr_mods r;
a16e92de Jan Glauber 2017-02-06  114  
a16e92de Jan Glauber 2017-02-06  115  	cr = cvm_mmc_cr_types + (cmd->opcode & 0x3f);
a16e92de Jan Glauber 2017-02-06  116  	hardware_ctype = cr->ctype;
a16e92de Jan Glauber 2017-02-06  117  	hardware_rtype = cr->rtype;
a16e92de Jan Glauber 2017-02-06  118  	if (cmd->opcode == MMC_GEN_CMD)
a16e92de Jan Glauber 2017-02-06  119  		hardware_ctype = (cmd->arg & 1) ? 1 : 2;
a16e92de Jan Glauber 2017-02-06  120  
a16e92de Jan Glauber 2017-02-06  121  	switch (mmc_cmd_type(cmd)) {
a16e92de Jan Glauber 2017-02-06  122  	case MMC_CMD_ADTC:
a16e92de Jan Glauber 2017-02-06  123  		desired_ctype = (cmd->data->flags & MMC_DATA_WRITE) ? 2 : 1;
a16e92de Jan Glauber 2017-02-06  124  		break;
a16e92de Jan Glauber 2017-02-06  125  	case MMC_CMD_AC:
a16e92de Jan Glauber 2017-02-06  126  	case MMC_CMD_BC:
a16e92de Jan Glauber 2017-02-06  127  	case MMC_CMD_BCR:
a16e92de Jan Glauber 2017-02-06  128  		desired_ctype = 0;
a16e92de Jan Glauber 2017-02-06  129  		break;
a16e92de Jan Glauber 2017-02-06  130  	}
a16e92de Jan Glauber 2017-02-06  131  
a16e92de Jan Glauber 2017-02-06  132  	switch (mmc_resp_type(cmd)) {
a16e92de Jan Glauber 2017-02-06  133  	case MMC_RSP_NONE:
a16e92de Jan Glauber 2017-02-06  134  		desired_rtype = 0;
a16e92de Jan Glauber 2017-02-06  135  		break;
a16e92de Jan Glauber 2017-02-06  136  	case MMC_RSP_R1:/* MMC_RSP_R5, MMC_RSP_R6, MMC_RSP_R7 */
a16e92de Jan Glauber 2017-02-06  137  	case MMC_RSP_R1B:
a16e92de Jan Glauber 2017-02-06  138  		desired_rtype = 1;
a16e92de Jan Glauber 2017-02-06  139  		break;
a16e92de Jan Glauber 2017-02-06  140  	case MMC_RSP_R2:
a16e92de Jan Glauber 2017-02-06  141  		desired_rtype = 2;
a16e92de Jan Glauber 2017-02-06  142  		break;
a16e92de Jan Glauber 2017-02-06  143  	case MMC_RSP_R3: /* MMC_RSP_R4 */
a16e92de Jan Glauber 2017-02-06  144  		desired_rtype = 3;
a16e92de Jan Glauber 2017-02-06  145  		break;
a16e92de Jan Glauber 2017-02-06  146  	}
a16e92de Jan Glauber 2017-02-06  147  	r.ctype_xor = desired_ctype ^ hardware_ctype;
a16e92de Jan Glauber 2017-02-06  148  	r.rtype_xor = desired_rtype ^ hardware_rtype;
a16e92de Jan Glauber 2017-02-06  149  	return r;
a16e92de Jan Glauber 2017-02-06  150  }
a16e92de Jan Glauber 2017-02-06  151  
a16e92de Jan Glauber 2017-02-06  152  static void check_switch_errors(struct cvm_mmc_host *host)
a16e92de Jan Glauber 2017-02-06  153  {
a16e92de Jan Glauber 2017-02-06  154  	union mio_emm_switch emm_switch;
a16e92de Jan Glauber 2017-02-06  155  
a16e92de Jan Glauber 2017-02-06 @156  	emm_switch.val = readq(host->base + MIO_EMM_SWITCH);
a16e92de Jan Glauber 2017-02-06  157  	if (emm_switch.s.switch_err0)
a16e92de Jan Glauber 2017-02-06  158  		dev_err(host->dev, "Switch power class error\n");
a16e92de Jan Glauber 2017-02-06  159  	if (emm_switch.s.switch_err1)
a16e92de Jan Glauber 2017-02-06  160  		dev_err(host->dev, "Switch hs timing error\n");
a16e92de Jan Glauber 2017-02-06  161  	if (emm_switch.s.switch_err2)
a16e92de Jan Glauber 2017-02-06  162  		dev_err(host->dev, "Switch bus width error\n");
a16e92de Jan Glauber 2017-02-06  163  }
a16e92de Jan Glauber 2017-02-06  164  
a16e92de Jan Glauber 2017-02-06  165  /*
a16e92de Jan Glauber 2017-02-06  166   * We never set the switch_exe bit since that would interfere
a16e92de Jan Glauber 2017-02-06  167   * with the commands send by the MMC core.
a16e92de Jan Glauber 2017-02-06  168   */
a16e92de Jan Glauber 2017-02-06  169  static void do_switch(struct cvm_mmc_host *host, u64 val)
a16e92de Jan Glauber 2017-02-06  170  {
a16e92de Jan Glauber 2017-02-06  171  	union mio_emm_rsp_sts rsp_sts;
a16e92de Jan Glauber 2017-02-06  172  	union mio_emm_switch emm_switch;
a16e92de Jan Glauber 2017-02-06  173  	int retries = 100;
a16e92de Jan Glauber 2017-02-06  174  	int bus_id;
a16e92de Jan Glauber 2017-02-06  175  
a16e92de Jan Glauber 2017-02-06  176  	emm_switch.val = val;
a16e92de Jan Glauber 2017-02-06  177  
a16e92de Jan Glauber 2017-02-06  178  	/*
a16e92de Jan Glauber 2017-02-06  179  	 * Modes setting only taken from slot 0. Work around that hardware
a16e92de Jan Glauber 2017-02-06  180  	 * issue by first switching to slot 0.
a16e92de Jan Glauber 2017-02-06  181  	 */
a16e92de Jan Glauber 2017-02-06  182  	bus_id = emm_switch.s.bus_id;
a16e92de Jan Glauber 2017-02-06  183  	emm_switch.s.bus_id = 0;
a16e92de Jan Glauber 2017-02-06  184  	writeq(emm_switch.val, host->base + MIO_EMM_SWITCH);
a16e92de Jan Glauber 2017-02-06  185  
a16e92de Jan Glauber 2017-02-06  186  	emm_switch.s.bus_id = bus_id;
a16e92de Jan Glauber 2017-02-06  187  	writeq(emm_switch.val, host->base + MIO_EMM_SWITCH);
a16e92de Jan Glauber 2017-02-06  188  
a16e92de Jan Glauber 2017-02-06  189  	/* wait for the switch to finish */
a16e92de Jan Glauber 2017-02-06  190  	do {
a16e92de Jan Glauber 2017-02-06 @191  		rsp_sts.val = readq(host->base + MIO_EMM_RSP_STS);
a16e92de Jan Glauber 2017-02-06  192  		if (!rsp_sts.s.switch_val)
a16e92de Jan Glauber 2017-02-06  193  			break;
a16e92de Jan Glauber 2017-02-06  194  		udelay(10);
a16e92de Jan Glauber 2017-02-06  195  	} while (--retries);
a16e92de Jan Glauber 2017-02-06  196  
a16e92de Jan Glauber 2017-02-06  197  	check_switch_errors(host);
a16e92de Jan Glauber 2017-02-06  198  }
a16e92de Jan Glauber 2017-02-06  199  
a16e92de Jan Glauber 2017-02-06  200  static bool switch_val_changed(struct cvm_mmc_slot *slot, u64 new_val)
a16e92de Jan Glauber 2017-02-06  201  {
a16e92de Jan Glauber 2017-02-06  202  	/* Match BUS_ID, HS_TIMING, BUS_WIDTH, POWER_CLASS, CLK_HI, CLK_LO */
a16e92de Jan Glauber 2017-02-06  203  	u64 match = 0x3001070fffffffffull;
a16e92de Jan Glauber 2017-02-06  204  
a16e92de Jan Glauber 2017-02-06  205  	return (slot->cached_switch & match) != (new_val & match);
a16e92de Jan Glauber 2017-02-06  206  }
a16e92de Jan Glauber 2017-02-06  207  
a16e92de Jan Glauber 2017-02-06  208  static void set_wdog(struct cvm_mmc_slot *slot, unsigned int ns)
a16e92de Jan Glauber 2017-02-06  209  {
a16e92de Jan Glauber 2017-02-06  210  	u64 timeout;
a16e92de Jan Glauber 2017-02-06  211  
a16e92de Jan Glauber 2017-02-06  212  	WARN_ON_ONCE(!slot->clock);
a16e92de Jan Glauber 2017-02-06  213  	if (ns)
a16e92de Jan Glauber 2017-02-06  214  		timeout = (slot->clock * ns) / NSEC_PER_SEC;
a16e92de Jan Glauber 2017-02-06  215  	else
a16e92de Jan Glauber 2017-02-06  216  		timeout = (slot->clock * 850ull) / 1000ull;
a16e92de Jan Glauber 2017-02-06 @217  	writeq(timeout, slot->host->base + MIO_EMM_WDOG);
a16e92de Jan Glauber 2017-02-06  218  }
a16e92de Jan Glauber 2017-02-06  219  
a16e92de Jan Glauber 2017-02-06  220  static void cvm_mmc_reset_bus(struct cvm_mmc_slot *slot)
a16e92de Jan Glauber 2017-02-06  221  {
a16e92de Jan Glauber 2017-02-06  222  	union mio_emm_switch emm_switch;
a16e92de Jan Glauber 2017-02-06  223  	u64 wdog = 0;
a16e92de Jan Glauber 2017-02-06  224  
a16e92de Jan Glauber 2017-02-06  225  	emm_switch.val = readq(slot->host->base + MIO_EMM_SWITCH);
a16e92de Jan Glauber 2017-02-06  226  	wdog = readq(slot->host->base + MIO_EMM_WDOG);
a16e92de Jan Glauber 2017-02-06  227  
a16e92de Jan Glauber 2017-02-06  228  	emm_switch.s.switch_exe = 0;
a16e92de Jan Glauber 2017-02-06  229  	emm_switch.s.switch_err0 = 0;
a16e92de Jan Glauber 2017-02-06  230  	emm_switch.s.switch_err1 = 0;
a16e92de Jan Glauber 2017-02-06  231  	emm_switch.s.switch_err2 = 0;
a16e92de Jan Glauber 2017-02-06  232  	emm_switch.s.bus_id = slot->bus_id;
a16e92de Jan Glauber 2017-02-06  233  	do_switch(slot->host, emm_switch.val);
a16e92de Jan Glauber 2017-02-06  234  
a16e92de Jan Glauber 2017-02-06  235  	slot->cached_switch = emm_switch.val;
a16e92de Jan Glauber 2017-02-06  236  
a16e92de Jan Glauber 2017-02-06  237  	msleep(20);
a16e92de Jan Glauber 2017-02-06  238  
a16e92de Jan Glauber 2017-02-06  239  	writeq(wdog, slot->host->base + MIO_EMM_WDOG);
a16e92de Jan Glauber 2017-02-06  240  }
a16e92de Jan Glauber 2017-02-06  241  
a16e92de Jan Glauber 2017-02-06  242  /* Switch to another slot if needed */
a16e92de Jan Glauber 2017-02-06  243  static void cvm_mmc_switch_to(struct cvm_mmc_slot *slot)
a16e92de Jan Glauber 2017-02-06  244  {
a16e92de Jan Glauber 2017-02-06  245  	struct cvm_mmc_host *host = slot->host;
a16e92de Jan Glauber 2017-02-06  246  	struct cvm_mmc_slot *old_slot;
a16e92de Jan Glauber 2017-02-06  247  	union mio_emm_switch emm_switch;
a16e92de Jan Glauber 2017-02-06  248  	union mio_emm_sample emm_sample;
a16e92de Jan Glauber 2017-02-06  249  
a16e92de Jan Glauber 2017-02-06  250  	if (slot->bus_id == host->last_slot)
a16e92de Jan Glauber 2017-02-06  251  		return;
a16e92de Jan Glauber 2017-02-06  252  
a16e92de Jan Glauber 2017-02-06  253  	if (host->last_slot >= 0 && host->slot[host->last_slot]) {
a16e92de Jan Glauber 2017-02-06  254  		old_slot = host->slot[host->last_slot];
a16e92de Jan Glauber 2017-02-06 @255  		old_slot->cached_switch = readq(host->base + MIO_EMM_SWITCH);
a16e92de Jan Glauber 2017-02-06 @256  		old_slot->cached_rca = readq(host->base + MIO_EMM_RCA);
a16e92de Jan Glauber 2017-02-06  257  	}
a16e92de Jan Glauber 2017-02-06  258  
a16e92de Jan Glauber 2017-02-06  259  	writeq(slot->cached_rca, host->base + MIO_EMM_RCA);
a16e92de Jan Glauber 2017-02-06  260  	emm_switch.val = slot->cached_switch;
a16e92de Jan Glauber 2017-02-06  261  	emm_switch.s.bus_id = slot->bus_id;
a16e92de Jan Glauber 2017-02-06  262  	do_switch(host, emm_switch.val);
a16e92de Jan Glauber 2017-02-06  263  
a16e92de Jan Glauber 2017-02-06  264  	emm_sample.val = 0;
a16e92de Jan Glauber 2017-02-06  265  	emm_sample.s.cmd_cnt = slot->cmd_cnt;
a16e92de Jan Glauber 2017-02-06  266  	emm_sample.s.dat_cnt = slot->dat_cnt;
a16e92de Jan Glauber 2017-02-06 @267  	writeq(emm_sample.val, host->base + MIO_EMM_SAMPLE);
a16e92de Jan Glauber 2017-02-06  268  
a16e92de Jan Glauber 2017-02-06  269  	host->last_slot = slot->bus_id;
a16e92de Jan Glauber 2017-02-06  270  }
a16e92de Jan Glauber 2017-02-06  271  
a16e92de Jan Glauber 2017-02-06  272  static void do_read(struct cvm_mmc_host *host, struct mmc_request *req,
a16e92de Jan Glauber 2017-02-06  273  		    u64 dbuf)
a16e92de Jan Glauber 2017-02-06  274  {
a16e92de Jan Glauber 2017-02-06  275  	struct sg_mapping_iter *smi = &host->smi;
a16e92de Jan Glauber 2017-02-06  276  	int data_len = req->data->blocks * req->data->blksz;
a16e92de Jan Glauber 2017-02-06  277  	int bytes_xfered, shift = -1;
a16e92de Jan Glauber 2017-02-06  278  	u64 dat = 0;
a16e92de Jan Glauber 2017-02-06  279  
a16e92de Jan Glauber 2017-02-06  280  	/* Auto inc from offset zero */
a16e92de Jan Glauber 2017-02-06 @281  	writeq((0x10000 | (dbuf << 6)), host->base + MIO_EMM_BUF_IDX);
a16e92de Jan Glauber 2017-02-06  282  
a16e92de Jan Glauber 2017-02-06  283  	for (bytes_xfered = 0; bytes_xfered < data_len;) {
a16e92de Jan Glauber 2017-02-06  284  		if (smi->consumed >= smi->length) {
a16e92de Jan Glauber 2017-02-06  285  			if (!sg_miter_next(smi))
a16e92de Jan Glauber 2017-02-06  286  				break;
a16e92de Jan Glauber 2017-02-06  287  			smi->consumed = 0;
a16e92de Jan Glauber 2017-02-06  288  		}
a16e92de Jan Glauber 2017-02-06  289  
a16e92de Jan Glauber 2017-02-06  290  		if (shift < 0) {
a16e92de Jan Glauber 2017-02-06 @291  			dat = readq(host->base + MIO_EMM_BUF_DAT);
a16e92de Jan Glauber 2017-02-06  292  			shift = 56;
a16e92de Jan Glauber 2017-02-06  293  		}
a16e92de Jan Glauber 2017-02-06  294  
a16e92de Jan Glauber 2017-02-06  295  		while (smi->consumed < smi->length && shift >= 0) {
a16e92de Jan Glauber 2017-02-06  296  			((u8 *)smi->addr)[smi->consumed] = (dat >> shift) & 0xff;
a16e92de Jan Glauber 2017-02-06  297  			bytes_xfered++;
a16e92de Jan Glauber 2017-02-06  298  			smi->consumed++;
a16e92de Jan Glauber 2017-02-06  299  			shift -= 8;
a16e92de Jan Glauber 2017-02-06  300  		}
a16e92de Jan Glauber 2017-02-06  301  	}
a16e92de Jan Glauber 2017-02-06  302  
a16e92de Jan Glauber 2017-02-06  303  	sg_miter_stop(smi);
a16e92de Jan Glauber 2017-02-06  304  	req->data->bytes_xfered = bytes_xfered;
a16e92de Jan Glauber 2017-02-06  305  	req->data->error = 0;
a16e92de Jan Glauber 2017-02-06  306  }
a16e92de Jan Glauber 2017-02-06  307  
a16e92de Jan Glauber 2017-02-06  308  static void do_write(struct mmc_request *req)
a16e92de Jan Glauber 2017-02-06  309  {
a16e92de Jan Glauber 2017-02-06  310  	req->data->bytes_xfered = req->data->blocks * req->data->blksz;
a16e92de Jan Glauber 2017-02-06  311  	req->data->error = 0;
a16e92de Jan Glauber 2017-02-06  312  }
a16e92de Jan Glauber 2017-02-06  313  
a16e92de Jan Glauber 2017-02-06  314  static void set_cmd_response(struct cvm_mmc_host *host, struct mmc_request *req,
a16e92de Jan Glauber 2017-02-06  315  			     union mio_emm_rsp_sts *rsp_sts)
a16e92de Jan Glauber 2017-02-06  316  {
a16e92de Jan Glauber 2017-02-06  317  	u64 rsp_hi, rsp_lo;
a16e92de Jan Glauber 2017-02-06  318  
a16e92de Jan Glauber 2017-02-06  319  	if (!rsp_sts->s.rsp_val)
a16e92de Jan Glauber 2017-02-06  320  		return;
a16e92de Jan Glauber 2017-02-06  321  
a16e92de Jan Glauber 2017-02-06 @322  	rsp_lo = readq(host->base + MIO_EMM_RSP_LO);
a16e92de Jan Glauber 2017-02-06  323  
a16e92de Jan Glauber 2017-02-06  324  	switch (rsp_sts->s.rsp_type) {
a16e92de Jan Glauber 2017-02-06  325  	case 1:
a16e92de Jan Glauber 2017-02-06  326  	case 3:
a16e92de Jan Glauber 2017-02-06  327  		req->cmd->resp[0] = (rsp_lo >> 8) & 0xffffffff;
a16e92de Jan Glauber 2017-02-06  328  		req->cmd->resp[1] = 0;
a16e92de Jan Glauber 2017-02-06  329  		req->cmd->resp[2] = 0;
a16e92de Jan Glauber 2017-02-06  330  		req->cmd->resp[3] = 0;
a16e92de Jan Glauber 2017-02-06  331  		break;
a16e92de Jan Glauber 2017-02-06  332  	case 2:
a16e92de Jan Glauber 2017-02-06  333  		req->cmd->resp[3] = rsp_lo & 0xffffffff;
a16e92de Jan Glauber 2017-02-06  334  		req->cmd->resp[2] = (rsp_lo >> 32) & 0xffffffff;
a16e92de Jan Glauber 2017-02-06 @335  		rsp_hi = readq(host->base + MIO_EMM_RSP_HI);
a16e92de Jan Glauber 2017-02-06  336  		req->cmd->resp[1] = rsp_hi & 0xffffffff;
a16e92de Jan Glauber 2017-02-06  337  		req->cmd->resp[0] = (rsp_hi >> 32) & 0xffffffff;
a16e92de Jan Glauber 2017-02-06  338  		break;

:::::: The code at line 156 was first introduced by commit
:::::: a16e92dea256e2d09874770563fc9000029fc235 mmc: cavium: Add core MMC driver for Cavium SOCs

:::::: TO: Jan Glauber <jglauber@cavium.com>
:::::: CC: 0day robot <fengguang.wu@intel.com>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 53515 bytes --]

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v11 7/9] mmc: cavium: Add scatter-gather DMA support
  2017-02-06 13:39 ` [PATCH v11 7/9] mmc: cavium: Add scatter-gather DMA support Jan Glauber
@ 2017-02-12  1:27   ` kbuild test robot
  0 siblings, 0 replies; 24+ messages in thread
From: kbuild test robot @ 2017-02-12  1:27 UTC (permalink / raw)
  To: Jan Glauber
  Cc: kbuild-all, Ulf Hansson, linux-mmc, linux-kernel, David Daney,
	Steven J . Hill, Jan Glauber, David Daney

[-- Attachment #1: Type: text/plain, Size: 26981 bytes --]

Hi Jan,

[auto build test ERROR on linus/master]
[also build test ERROR on v4.10-rc7 next-20170210]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Jan-Glauber/Cavium-MMC-driver/20170206-214740
config: arm64-allmodconfig (attached as .config)
compiler: aarch64-linux-gnu-gcc (Debian 6.1.1-9) 6.1.1 20160705
reproduce:
        wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=arm64 

All errors (new ones prefixed by >>):

   arch/arm64/include/asm/io.h:137:32: note: in expansion of macro 'readq_relaxed'
    #define readq(c)  ({ u64 __v = readq_relaxed(c); __iormb(); __v; })
                                   ^~~~~~~~~~~~~
   drivers/mmc/host/cavium-mmc.c:255:29: note: in expansion of macro 'readq'
      old_slot->cached_switch = readq(host->base + MIO_EMM_SWITCH);
                                ^~~~~
   drivers/mmc/host/cavium-mmc.c:256:45: error: 'MIO_EMM_RCA' undeclared (first use in this function)
      old_slot->cached_rca = readq(host->base + MIO_EMM_RCA);
                                                ^
   include/uapi/linux/swab.h:129:32: note: in definition of macro '__swab64'
     (__builtin_constant_p((__u64)(x)) ? \
                                   ^
   include/linux/byteorder/generic.h:86:21: note: in expansion of macro '__le64_to_cpu'
    #define le64_to_cpu __le64_to_cpu
                        ^~~~~~~~~~~~~
   arch/arm64/include/asm/io.h:137:32: note: in expansion of macro 'readq_relaxed'
    #define readq(c)  ({ u64 __v = readq_relaxed(c); __iormb(); __v; })
                                   ^~~~~~~~~~~~~
   drivers/mmc/host/cavium-mmc.c:256:26: note: in expansion of macro 'readq'
      old_slot->cached_rca = readq(host->base + MIO_EMM_RCA);
                             ^~~~~
   In file included from include/linux/scatterlist.h:8:0,
                    from include/linux/dma-mapping.h:10,
                    from drivers/mmc/host/cavium-mmc.c:18:
   drivers/mmc/host/cavium-mmc.c:267:38: error: 'MIO_EMM_SAMPLE' undeclared (first use in this function)
     writeq(emm_sample.val, host->base + MIO_EMM_SAMPLE);
                                         ^
   arch/arm64/include/asm/io.h:127:78: note: in definition of macro 'writeq_relaxed'
    #define writeq_relaxed(v,c) ((void)__raw_writeq((__force u64)cpu_to_le64(v),(c)))
                                                                                 ^
   drivers/mmc/host/cavium-mmc.c:267:2: note: in expansion of macro 'writeq'
     writeq(emm_sample.val, host->base + MIO_EMM_SAMPLE);
     ^~~~~~
   drivers/mmc/host/cavium-mmc.c: In function 'do_read':
   drivers/mmc/host/cavium-mmc.c:281:47: error: 'MIO_EMM_BUF_IDX' undeclared (first use in this function)
     writeq((0x10000 | (dbuf << 6)), host->base + MIO_EMM_BUF_IDX);
                                                  ^
   arch/arm64/include/asm/io.h:127:78: note: in definition of macro 'writeq_relaxed'
    #define writeq_relaxed(v,c) ((void)__raw_writeq((__force u64)cpu_to_le64(v),(c)))
                                                                                 ^
   drivers/mmc/host/cavium-mmc.c:281:2: note: in expansion of macro 'writeq'
     writeq((0x10000 | (dbuf << 6)), host->base + MIO_EMM_BUF_IDX);
     ^~~~~~
   In file included from include/linux/swab.h:4:0,
                    from include/uapi/linux/byteorder/big_endian.h:12,
                    from include/linux/byteorder/big_endian.h:4,
                    from arch/arm64/include/uapi/asm/byteorder.h:20,
                    from include/asm-generic/bitops/le.h:5,
                    from arch/arm64/include/asm/bitops.h:50,
                    from include/linux/bitops.h:36,
                    from include/linux/kernel.h:10,
                    from include/linux/delay.h:10,
                    from drivers/mmc/host/cavium-mmc.c:16:
   drivers/mmc/host/cavium-mmc.c:291:29: error: 'MIO_EMM_BUF_DAT' undeclared (first use in this function)
       dat = readq(host->base + MIO_EMM_BUF_DAT);
                                ^
   include/uapi/linux/swab.h:129:32: note: in definition of macro '__swab64'
     (__builtin_constant_p((__u64)(x)) ? \
                                   ^
   include/linux/byteorder/generic.h:86:21: note: in expansion of macro '__le64_to_cpu'
    #define le64_to_cpu __le64_to_cpu
                        ^~~~~~~~~~~~~
   arch/arm64/include/asm/io.h:137:32: note: in expansion of macro 'readq_relaxed'
    #define readq(c)  ({ u64 __v = readq_relaxed(c); __iormb(); __v; })
                                   ^~~~~~~~~~~~~
   drivers/mmc/host/cavium-mmc.c:291:10: note: in expansion of macro 'readq'
       dat = readq(host->base + MIO_EMM_BUF_DAT);
             ^~~~~
   drivers/mmc/host/cavium-mmc.c: In function 'set_cmd_response':
   drivers/mmc/host/cavium-mmc.c:322:30: error: 'MIO_EMM_RSP_LO' undeclared (first use in this function)
     rsp_lo = readq(host->base + MIO_EMM_RSP_LO);
                                 ^
   include/uapi/linux/swab.h:129:32: note: in definition of macro '__swab64'
     (__builtin_constant_p((__u64)(x)) ? \
                                   ^
   include/linux/byteorder/generic.h:86:21: note: in expansion of macro '__le64_to_cpu'
    #define le64_to_cpu __le64_to_cpu
                        ^~~~~~~~~~~~~
   arch/arm64/include/asm/io.h:137:32: note: in expansion of macro 'readq_relaxed'
    #define readq(c)  ({ u64 __v = readq_relaxed(c); __iormb(); __v; })
                                   ^~~~~~~~~~~~~
   drivers/mmc/host/cavium-mmc.c:322:11: note: in expansion of macro 'readq'
     rsp_lo = readq(host->base + MIO_EMM_RSP_LO);
              ^~~~~
   drivers/mmc/host/cavium-mmc.c:335:31: error: 'MIO_EMM_RSP_HI' undeclared (first use in this function)
      rsp_hi = readq(host->base + MIO_EMM_RSP_HI);
                                  ^
   include/uapi/linux/swab.h:129:32: note: in definition of macro '__swab64'
     (__builtin_constant_p((__u64)(x)) ? \
                                   ^
   include/linux/byteorder/generic.h:86:21: note: in expansion of macro '__le64_to_cpu'
    #define le64_to_cpu __le64_to_cpu
                        ^~~~~~~~~~~~~
   arch/arm64/include/asm/io.h:137:32: note: in expansion of macro 'readq_relaxed'
    #define readq(c)  ({ u64 __v = readq_relaxed(c); __iormb(); __v; })
                                   ^~~~~~~~~~~~~
   drivers/mmc/host/cavium-mmc.c:335:12: note: in expansion of macro 'readq'
      rsp_hi = readq(host->base + MIO_EMM_RSP_HI);
               ^~~~~
   drivers/mmc/host/cavium-mmc.c: In function 'finish_dma_sg':
>> drivers/mmc/host/cavium-mmc.c:359:40: error: 'MIO_EMM_DMA_FIFO_CFG' undeclared (first use in this function)
     fifo_cfg.val = readq(host->dma_base + MIO_EMM_DMA_FIFO_CFG);
                                           ^
   include/uapi/linux/swab.h:129:32: note: in definition of macro '__swab64'
     (__builtin_constant_p((__u64)(x)) ? \
                                   ^
   include/linux/byteorder/generic.h:86:21: note: in expansion of macro '__le64_to_cpu'
    #define le64_to_cpu __le64_to_cpu
                        ^~~~~~~~~~~~~
   arch/arm64/include/asm/io.h:137:32: note: in expansion of macro 'readq_relaxed'
    #define readq(c)  ({ u64 __v = readq_relaxed(c); __iormb(); __v; })
                                   ^~~~~~~~~~~~~
   drivers/mmc/host/cavium-mmc.c:359:17: note: in expansion of macro 'readq'
     fifo_cfg.val = readq(host->dma_base + MIO_EMM_DMA_FIFO_CFG);
                    ^~~~~
   drivers/mmc/host/cavium-mmc.c: In function 'cleanup_dma':
   drivers/mmc/host/cavium-mmc.c:397:35: error: 'MIO_EMM_DMA' undeclared (first use in this function)
     emm_dma.val = readq(host->base + MIO_EMM_DMA);
                                      ^
   include/uapi/linux/swab.h:129:32: note: in definition of macro '__swab64'
     (__builtin_constant_p((__u64)(x)) ? \
                                   ^
   include/linux/byteorder/generic.h:86:21: note: in expansion of macro '__le64_to_cpu'
    #define le64_to_cpu __le64_to_cpu
                        ^~~~~~~~~~~~~
   arch/arm64/include/asm/io.h:137:32: note: in expansion of macro 'readq_relaxed'
    #define readq(c)  ({ u64 __v = readq_relaxed(c); __iormb(); __v; })
                                   ^~~~~~~~~~~~~
   drivers/mmc/host/cavium-mmc.c:397:16: note: in expansion of macro 'readq'
     emm_dma.val = readq(host->base + MIO_EMM_DMA);
                   ^~~~~
   drivers/mmc/host/cavium-mmc.c: In function 'cvm_mmc_interrupt':
   drivers/mmc/host/cavium-mmc.c:419:35: error: 'MIO_EMM_INT' undeclared (first use in this function)
     emm_int.val = readq(host->base + MIO_EMM_INT);
                                      ^
   include/uapi/linux/swab.h:129:32: note: in definition of macro '__swab64'
     (__builtin_constant_p((__u64)(x)) ? \
                                   ^
   include/linux/byteorder/generic.h:86:21: note: in expansion of macro '__le64_to_cpu'
    #define le64_to_cpu __le64_to_cpu
                        ^~~~~~~~~~~~~
   arch/arm64/include/asm/io.h:137:32: note: in expansion of macro 'readq_relaxed'
    #define readq(c)  ({ u64 __v = readq_relaxed(c); __iormb(); __v; })
                                   ^~~~~~~~~~~~~
   drivers/mmc/host/cavium-mmc.c:419:16: note: in expansion of macro 'readq'
     emm_int.val = readq(host->base + MIO_EMM_INT);
                   ^~~~~
   drivers/mmc/host/cavium-mmc.c:429:35: error: 'MIO_EMM_RSP_STS' undeclared (first use in this function)
     rsp_sts.val = readq(host->base + MIO_EMM_RSP_STS);
                                      ^
   include/uapi/linux/swab.h:129:32: note: in definition of macro '__swab64'
     (__builtin_constant_p((__u64)(x)) ? \
                                   ^
   include/linux/byteorder/generic.h:86:21: note: in expansion of macro '__le64_to_cpu'
    #define le64_to_cpu __le64_to_cpu
                        ^~~~~~~~~~~~~
   arch/arm64/include/asm/io.h:137:32: note: in expansion of macro 'readq_relaxed'
    #define readq(c)  ({ u64 __v = readq_relaxed(c); __iormb(); __v; })
                                   ^~~~~~~~~~~~~
   drivers/mmc/host/cavium-mmc.c:429:16: note: in expansion of macro 'readq'
     rsp_sts.val = readq(host->base + MIO_EMM_RSP_STS);
                   ^~~~~
   In file included from include/linux/scatterlist.h:8:0,
                    from include/linux/dma-mapping.h:10,
                    from drivers/mmc/host/cavium-mmc.c:18:
   drivers/mmc/host/cavium-mmc.c: In function 'prepare_dma_single':
   drivers/mmc/host/cavium-mmc.c:508:39: error: 'MIO_EMM_DMA_CFG' undeclared (first use in this function)
     writeq(dma_cfg.val, host->dma_base + MIO_EMM_DMA_CFG);
                                          ^
   arch/arm64/include/asm/io.h:127:78: note: in definition of macro 'writeq_relaxed'
    #define writeq_relaxed(v,c) ((void)__raw_writeq((__force u64)cpu_to_le64(v),(c)))
                                                                                 ^
   drivers/mmc/host/cavium-mmc.c:508:2: note: in expansion of macro 'writeq'
     writeq(dma_cfg.val, host->dma_base + MIO_EMM_DMA_CFG);
     ^~~~~~
   drivers/mmc/host/cavium-mmc.c:514:33: error: 'MIO_EMM_DMA_ADR' undeclared (first use in this function)
      writeq(addr, host->dma_base + MIO_EMM_DMA_ADR);
                                    ^
   arch/arm64/include/asm/io.h:127:78: note: in definition of macro 'writeq_relaxed'
    #define writeq_relaxed(v,c) ((void)__raw_writeq((__force u64)cpu_to_le64(v),(c)))
                                                                                 ^
   drivers/mmc/host/cavium-mmc.c:514:3: note: in expansion of macro 'writeq'
      writeq(addr, host->dma_base + MIO_EMM_DMA_ADR);
      ^~~~~~
   drivers/mmc/host/cavium-mmc.c: In function 'prepare_dma_sg':
   drivers/mmc/host/cavium-mmc.c:537:29: error: 'MIO_EMM_DMA_FIFO_CFG' undeclared (first use in this function)
     writeq(0, host->dma_base + MIO_EMM_DMA_FIFO_CFG);
                                ^
   arch/arm64/include/asm/io.h:127:78: note: in definition of macro 'writeq_relaxed'
    #define writeq_relaxed(v,c) ((void)__raw_writeq((__force u64)cpu_to_le64(v),(c)))
                                                                                 ^
   drivers/mmc/host/cavium-mmc.c:537:2: note: in expansion of macro 'writeq'
     writeq(0, host->dma_base + MIO_EMM_DMA_FIFO_CFG);
     ^~~~~~
>> drivers/mmc/host/cavium-mmc.c:544:33: error: 'MIO_EMM_DMA_FIFO_ADR' undeclared (first use in this function)
      writeq(addr, host->dma_base + MIO_EMM_DMA_FIFO_ADR);
                                    ^
   arch/arm64/include/asm/io.h:127:78: note: in definition of macro 'writeq_relaxed'
    #define writeq_relaxed(v,c) ((void)__raw_writeq((__force u64)cpu_to_le64(v),(c)))
                                                                                 ^
   drivers/mmc/host/cavium-mmc.c:544:3: note: in expansion of macro 'writeq'
      writeq(addr, host->dma_base + MIO_EMM_DMA_FIFO_ADR);
      ^~~~~~
>> drivers/mmc/host/cavium-mmc.c:568:41: error: 'MIO_EMM_DMA_FIFO_CMD' undeclared (first use in this function)
      writeq(fifo_cmd.val, host->dma_base + MIO_EMM_DMA_FIFO_CMD);
                                            ^
   arch/arm64/include/asm/io.h:127:78: note: in definition of macro 'writeq_relaxed'
    #define writeq_relaxed(v,c) ((void)__raw_writeq((__force u64)cpu_to_le64(v),(c)))
                                                                                 ^
   drivers/mmc/host/cavium-mmc.c:568:3: note: in expansion of macro 'writeq'
      writeq(fifo_cmd.val, host->dma_base + MIO_EMM_DMA_FIFO_CMD);
      ^~~~~~
   drivers/mmc/host/cavium-mmc.c: In function 'cvm_mmc_dma_request':
   drivers/mmc/host/cavium-mmc.c:683:38: error: 'MIO_EMM_STS_MASK' undeclared (first use in this function)
      writeq(0x00b00000ull, host->base + MIO_EMM_STS_MASK);
                                         ^
   arch/arm64/include/asm/io.h:127:78: note: in definition of macro 'writeq_relaxed'
    #define writeq_relaxed(v,c) ((void)__raw_writeq((__force u64)cpu_to_le64(v),(c)))
                                                                                 ^
   drivers/mmc/host/cavium-mmc.c:683:3: note: in expansion of macro 'writeq'
      writeq(0x00b00000ull, host->base + MIO_EMM_STS_MASK);
      ^~~~~~
   drivers/mmc/host/cavium-mmc.c:686:35: error: 'MIO_EMM_DMA' undeclared (first use in this function)
     writeq(emm_dma.val, host->base + MIO_EMM_DMA);
                                      ^
   arch/arm64/include/asm/io.h:127:78: note: in definition of macro 'writeq_relaxed'
    #define writeq_relaxed(v,c) ((void)__raw_writeq((__force u64)cpu_to_le64(v),(c)))
                                                                                 ^
   drivers/mmc/host/cavium-mmc.c:686:2: note: in expansion of macro 'writeq'
     writeq(emm_dma.val, host->base + MIO_EMM_DMA);
     ^~~~~~
   drivers/mmc/host/cavium-mmc.c: In function 'do_write_request':
   drivers/mmc/host/cavium-mmc.c:714:34: error: 'MIO_EMM_BUF_IDX' undeclared (first use in this function)
     writeq(0x10000ull, host->base + MIO_EMM_BUF_IDX);
                                     ^
   arch/arm64/include/asm/io.h:127:78: note: in definition of macro 'writeq_relaxed'
    #define writeq_relaxed(v,c) ((void)__raw_writeq((__force u64)cpu_to_le64(v),(c)))
                                                                                 ^
   drivers/mmc/host/cavium-mmc.c:714:2: note: in expansion of macro 'writeq'
     writeq(0x10000ull, host->base + MIO_EMM_BUF_IDX);
     ^~~~~~
   drivers/mmc/host/cavium-mmc.c:731:29: error: 'MIO_EMM_BUF_DAT' undeclared (first use in this function)
       writeq(dat, host->base + MIO_EMM_BUF_DAT);
                                ^
   arch/arm64/include/asm/io.h:127:78: note: in definition of macro 'writeq_relaxed'
    #define writeq_relaxed(v,c) ((void)__raw_writeq((__force u64)cpu_to_le64(v),(c)))
                                                                                 ^
   drivers/mmc/host/cavium-mmc.c:731:4: note: in expansion of macro 'writeq'
       writeq(dat, host->base + MIO_EMM_BUF_DAT);
       ^~~~~~
   drivers/mmc/host/cavium-mmc.c: In function 'cvm_mmc_request':
   drivers/mmc/host/cavium-mmc.c:800:25: error: 'MIO_EMM_STS_MASK' undeclared (first use in this function)
     writeq(0, host->base + MIO_EMM_STS_MASK);
                            ^
   arch/arm64/include/asm/io.h:127:78: note: in definition of macro 'writeq_relaxed'
    #define writeq_relaxed(v,c) ((void)__raw_writeq((__force u64)cpu_to_le64(v),(c)))
                                                                                 ^
   drivers/mmc/host/cavium-mmc.c:800:2: note: in expansion of macro 'writeq'
     writeq(0, host->base + MIO_EMM_STS_MASK);
     ^~~~~~
   In file included from include/linux/swab.h:4:0,
                    from include/uapi/linux/byteorder/big_endian.h:12,
                    from include/linux/byteorder/big_endian.h:4,
                    from arch/arm64/include/uapi/asm/byteorder.h:20,
                    from include/asm-generic/bitops/le.h:5,
                    from arch/arm64/include/asm/bitops.h:50,
                    from include/linux/bitops.h:36,
                    from include/linux/kernel.h:10,
                    from include/linux/delay.h:10,
                    from drivers/mmc/host/cavium-mmc.c:16:
   drivers/mmc/host/cavium-mmc.c:803:35: error: 'MIO_EMM_RSP_STS' undeclared (first use in this function)
     rsp_sts.val = readq(host->base + MIO_EMM_RSP_STS);
                                      ^
   include/uapi/linux/swab.h:129:32: note: in definition of macro '__swab64'
     (__builtin_constant_p((__u64)(x)) ? \
                                   ^
   include/linux/byteorder/generic.h:86:21: note: in expansion of macro '__le64_to_cpu'
    #define le64_to_cpu __le64_to_cpu
                        ^~~~~~~~~~~~~
   arch/arm64/include/asm/io.h:137:32: note: in expansion of macro 'readq_relaxed'
    #define readq(c)  ({ u64 __v = readq_relaxed(c); __iormb(); __v; })
                                   ^~~~~~~~~~~~~
   drivers/mmc/host/cavium-mmc.c:803:16: note: in expansion of macro 'readq'
     rsp_sts.val = readq(host->base + MIO_EMM_RSP_STS);
                   ^~~~~
   In file included from include/linux/scatterlist.h:8:0,
                    from include/linux/dma-mapping.h:10,
                    from drivers/mmc/host/cavium-mmc.c:18:
   drivers/mmc/host/cavium-mmc.c:812:35: error: 'MIO_EMM_CMD' undeclared (first use in this function)
     writeq(emm_cmd.val, host->base + MIO_EMM_CMD);
                                      ^
   arch/arm64/include/asm/io.h:127:78: note: in definition of macro 'writeq_relaxed'
    #define writeq_relaxed(v,c) ((void)__raw_writeq((__force u64)cpu_to_le64(v),(c)))
                                                                                 ^
   drivers/mmc/host/cavium-mmc.c:812:2: note: in expansion of macro 'writeq'
     writeq(emm_cmd.val, host->base + MIO_EMM_CMD);
     ^~~~~~
   drivers/mmc/host/cavium-mmc.c: In function 'cvm_mmc_init_lowlevel':
   drivers/mmc/host/cavium-mmc.c:914:43: error: 'MIO_EMM_CFG' undeclared (first use in this function)
     writeq(host->emm_cfg, slot->host->base + MIO_EMM_CFG);
                                              ^
   arch/arm64/include/asm/io.h:127:78: note: in definition of macro 'writeq_relaxed'
    #define writeq_relaxed(v,c) ((void)__raw_writeq((__force u64)cpu_to_le64(v),(c)))
                                                                                 ^
..

vim +/MIO_EMM_DMA_FIFO_CFG +359 drivers/mmc/host/cavium-mmc.c

   329			req->cmd->resp[2] = 0;
   330			req->cmd->resp[3] = 0;
   331			break;
   332		case 2:
   333			req->cmd->resp[3] = rsp_lo & 0xffffffff;
   334			req->cmd->resp[2] = (rsp_lo >> 32) & 0xffffffff;
 > 335			rsp_hi = readq(host->base + MIO_EMM_RSP_HI);
   336			req->cmd->resp[1] = rsp_hi & 0xffffffff;
   337			req->cmd->resp[0] = (rsp_hi >> 32) & 0xffffffff;
   338			break;
   339		}
   340	}
   341	
   342	static int get_dma_dir(struct mmc_data *data)
   343	{
   344		return (data->flags & MMC_DATA_WRITE) ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
   345	}
   346	
   347	static int finish_dma_single(struct cvm_mmc_host *host, struct mmc_data *data)
   348	{
   349		data->bytes_xfered = data->blocks * data->blksz;
   350		data->error = 0;
   351		return 1;
   352	}
   353	
   354	static int finish_dma_sg(struct cvm_mmc_host *host, struct mmc_data *data)
   355	{
   356		union mio_emm_dma_fifo_cfg fifo_cfg;
   357	
   358		/* Check if there are any pending requests left */
 > 359		fifo_cfg.val = readq(host->dma_base + MIO_EMM_DMA_FIFO_CFG);
   360		if (fifo_cfg.s.count)
   361			dev_err(host->dev, "%u requests still pending\n",
   362				fifo_cfg.s.count);
   363	
   364		data->bytes_xfered = data->blocks * data->blksz;
   365		data->error = 0;
   366	
   367		/* Clear and disable FIFO */
   368		writeq(BIT_ULL(16), host->dma_base + MIO_EMM_DMA_FIFO_CFG);
   369		dma_unmap_sg(host->dev, data->sg, data->sg_len, get_dma_dir(data));
   370		return 1;
   371	}
   372	
   373	static int finish_dma(struct cvm_mmc_host *host, struct mmc_data *data)
   374	{
   375		if (host->use_sg && data->sg_len > 1)
   376			return finish_dma_sg(host, data);
   377		else
   378			return finish_dma_single(host, data);
   379	}
   380	
   381	static bool bad_status(union mio_emm_rsp_sts *rsp_sts)
   382	{
   383		if (rsp_sts->s.rsp_bad_sts || rsp_sts->s.rsp_crc_err ||
   384		    rsp_sts->s.rsp_timeout || rsp_sts->s.blk_crc_err ||
   385		    rsp_sts->s.blk_timeout || rsp_sts->s.dbuf_err)
   386			return true;
   387	
   388		return false;
   389	}
   390	
   391	/* Try to clean up failed DMA. */
   392	static void cleanup_dma(struct cvm_mmc_host *host,
   393				union mio_emm_rsp_sts *rsp_sts)
   394	{
   395		union mio_emm_dma emm_dma;
   396	
   397		emm_dma.val = readq(host->base + MIO_EMM_DMA);
   398		emm_dma.s.dma_val = 1;
   399		emm_dma.s.dat_null = 1;
   400		emm_dma.s.bus_id = rsp_sts->s.bus_id;
   401		writeq(emm_dma.val, host->base + MIO_EMM_DMA);
   402	}
   403	
   404	irqreturn_t cvm_mmc_interrupt(int irq, void *dev_id)
   405	{
   406		struct cvm_mmc_host *host = dev_id;
   407		union mio_emm_rsp_sts rsp_sts;
   408		union mio_emm_int emm_int;
   409		struct mmc_request *req;
   410		unsigned long flags = 0;
   411		bool host_done;
   412	
   413		if (host->need_irq_handler_lock)
   414			spin_lock_irqsave(&host->irq_handler_lock, flags);
   415		else
   416			__acquire(&host->irq_handler_lock);
   417	
   418		/* Clear interrupt bits (write 1 clears ). */
   419		emm_int.val = readq(host->base + MIO_EMM_INT);
   420		writeq(emm_int.val, host->base + MIO_EMM_INT);
   421	
   422		if (emm_int.s.switch_err)
   423			check_switch_errors(host);
   424	
   425		req = host->current_req;
   426		if (!req)
   427			goto out;
   428	
   429		rsp_sts.val = readq(host->base + MIO_EMM_RSP_STS);
   430		/*
   431		 * dma_val set means DMA is still in progress. Don't touch
   432		 * the request and wait for the interrupt indicating that
   433		 * the DMA is finished.
   434		 */
   435		if (rsp_sts.s.dma_val && host->dma_active)
   436			goto out;
   437	
   438		if (!host->dma_active && emm_int.s.buf_done && req->data) {
   439			unsigned int type = (rsp_sts.val >> 7) & 3;
   440	
   441			if (type == 1)
   442				do_read(host, req, rsp_sts.s.dbuf);
   443			else if (type == 2)
   444				do_write(req);
   445		}
   446	
   447		host_done = emm_int.s.cmd_done || emm_int.s.dma_done ||
   448			    emm_int.s.cmd_err || emm_int.s.dma_err;
   449	
   450		if (!(host_done && req->done))
   451			goto no_req_done;
   452	
   453		if (bad_status(&rsp_sts))
   454			req->cmd->error = -EILSEQ;
   455		else
   456			req->cmd->error = 0;
   457	
   458		if (host->dma_active && req->data)
   459			if (!finish_dma(host, req->data))
   460				goto no_req_done;
   461	
   462		set_cmd_response(host, req, &rsp_sts);
   463		if (emm_int.s.dma_err && rsp_sts.s.dma_pend)
   464			cleanup_dma(host, &rsp_sts);
   465	
   466		host->current_req = NULL;
   467		req->done(req);
   468	
   469	no_req_done:
   470		if (host->dmar_fixup_done)
   471			host->dmar_fixup_done(host);
   472		if (host_done)
   473			host->release_bus(host);
   474	out:
   475		if (host->need_irq_handler_lock)
   476			spin_unlock_irqrestore(&host->irq_handler_lock, flags);
   477		else
   478			__release(&host->irq_handler_lock);
   479		return IRQ_RETVAL(emm_int.val != 0);
   480	}
   481	
   482	/*
   483	 * Program DMA_CFG and if needed DMA_ADR.
   484	 * Returns 0 on error, DMA address otherwise.
   485	 */
   486	static u64 prepare_dma_single(struct cvm_mmc_host *host, struct mmc_data *data)
   487	{
   488		union mio_emm_dma_cfg dma_cfg;
   489		int count;
   490		u64 addr;
   491	
   492		count = dma_map_sg(host->dev, data->sg, data->sg_len,
   493				   get_dma_dir(data));
   494		if (!count)
   495			return 0;
   496	
   497		dma_cfg.val = 0;
   498		dma_cfg.s.en = 1;
   499		dma_cfg.s.rw = (data->flags & MMC_DATA_WRITE) ? 1 : 0;
   500	#ifdef __LITTLE_ENDIAN
   501		dma_cfg.s.endian = 1;
   502	#endif
   503		dma_cfg.s.size = (sg_dma_len(&data->sg[0]) / 8) - 1;
   504	
   505		addr = sg_dma_address(&data->sg[0]);
   506		if (!host->big_dma_addr)
   507			dma_cfg.s.adr = addr;
   508		writeq(dma_cfg.val, host->dma_base + MIO_EMM_DMA_CFG);
   509	
   510		pr_debug("[%s] sg_dma_len: %u  total sg_elem: %d\n",
   511			 (dma_cfg.s.rw) ? "W" : "R", sg_dma_len(&data->sg[0]), count);
   512	
   513		if (host->big_dma_addr)
   514			writeq(addr, host->dma_base + MIO_EMM_DMA_ADR);
   515		return addr;
   516	}
   517	
   518	/*
   519	 * Queue complete sg list into the FIFO.
   520	 * Returns 0 on error, 1 otherwise.
   521	 */
   522	static u64 prepare_dma_sg(struct cvm_mmc_host *host, struct mmc_data *data)
   523	{
   524		union mio_emm_dma_fifo_cmd fifo_cmd;
   525		struct scatterlist *sg;
   526		int count, i;
   527		u64 addr;
   528	
   529		count = dma_map_sg(host->dev, data->sg, data->sg_len,
   530				   get_dma_dir(data));
   531		if (!count)
   532			return 0;
   533		if (count > 16)
   534			goto error;
   535	
   536		/* Enable FIFO by removing CLR bit */
 > 537		writeq(0, host->dma_base + MIO_EMM_DMA_FIFO_CFG);
   538	
   539		for_each_sg(data->sg, sg, count, i) {
   540			/* Program DMA address */
   541			addr = sg_dma_address(sg);
   542			if (addr & 7)
   543				goto error;
 > 544			writeq(addr, host->dma_base + MIO_EMM_DMA_FIFO_ADR);
   545	
   546			/*
   547			 * If we have scatter-gather support we also have an extra

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 53515 bytes --]

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v11 6/9] mmc: cavium: Add MMC PCI driver for ThunderX SOCs
  2017-02-12  1:09   ` kbuild test robot
@ 2017-02-13 15:24     ` Jan Glauber
  2017-02-13 15:45       ` Ulf Hansson
  0 siblings, 1 reply; 24+ messages in thread
From: Jan Glauber @ 2017-02-13 15:24 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: kbuild-all, linux-mmc, linux-kernel, David Daney,
	Steven J . Hill, David Daney

On Sun, Feb 12, 2017 at 09:09:29AM +0800, kbuild test robot wrote:
> Hi Jan,
> 
> [auto build test ERROR on linus/master]
> [also build test ERROR on v4.10-rc7 next-20170210]
> [if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
> 
> url:    https://github.com/0day-ci/linux/commits/Jan-Glauber/Cavium-MMC-driver/20170206-214740
> config: arm64-allmodconfig (attached as .config)
> compiler: aarch64-linux-gnu-gcc (Debian 6.1.1-9) 6.1.1 20160705
> reproduce:
>         wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
>         chmod +x ~/bin/make.cross
>         # save the attached .config to linux build tree
>         make.cross ARCH=arm64 
> 
> All errors (new ones prefixed by >>):
> 
>    In file included from drivers/mmc/host/cavium-mmc.c:28:0:
>    drivers/mmc/host/cavium-mmc.h:41:7: warning: "CONFIG_MMC_CAVIUM_THUNDERX" is not defined [-Wundef]
>     #elif CONFIG_MMC_CAVIUM_THUNDERX
>           ^~~~~~~~~~~~~~~~~~~~~~~~~~

Hi Ulf,

We are aware of this build error, the line above should be:
#elif IS_ENABLED(CONFIG_MMC_CAVIUM_THUNDERX)

instead of:
#elif CONFIG_MMC_CAVIUM_THUNDERX

Unless you want it otherwise I'll wait for your review of the series
and fix this build error with the next revision.

thanks,
Jan

>    In file included from include/linux/swab.h:4:0,
>                     from include/uapi/linux/byteorder/big_endian.h:12,
>                     from include/linux/byteorder/big_endian.h:4,
>                     from arch/arm64/include/uapi/asm/byteorder.h:20,
>                     from include/asm-generic/bitops/le.h:5,
>                     from arch/arm64/include/asm/bitops.h:50,
>                     from include/linux/bitops.h:36,
>                     from include/linux/kernel.h:10,
>                     from include/linux/delay.h:10,
>                     from drivers/mmc/host/cavium-mmc.c:16:
>    drivers/mmc/host/cavium-mmc.c: In function 'check_switch_errors':
> >> drivers/mmc/host/cavium-mmc.c:156:38: error: 'MIO_EMM_SWITCH' undeclared (first use in this function)
>      emm_switch.val = readq(host->base + MIO_EMM_SWITCH);
>                                          ^
>    include/uapi/linux/swab.h:129:32: note: in definition of macro '__swab64'
>      (__builtin_constant_p((__u64)(x)) ? \
>                                    ^
>    include/linux/byteorder/generic.h:86:21: note: in expansion of macro '__le64_to_cpu'
>     #define le64_to_cpu __le64_to_cpu
>                         ^~~~~~~~~~~~~
>    arch/arm64/include/asm/io.h:137:32: note: in expansion of macro 'readq_relaxed'
>     #define readq(c)  ({ u64 __v = readq_relaxed(c); __iormb(); __v; })
>                                    ^~~~~~~~~~~~~
>    drivers/mmc/host/cavium-mmc.c:156:19: note: in expansion of macro 'readq'
>      emm_switch.val = readq(host->base + MIO_EMM_SWITCH);
>                       ^~~~~
>    drivers/mmc/host/cavium-mmc.c:156:38: note: each undeclared identifier is reported only once for each function it appears in
>      emm_switch.val = readq(host->base + MIO_EMM_SWITCH);
>                                          ^
>    include/uapi/linux/swab.h:129:32: note: in definition of macro '__swab64'
>      (__builtin_constant_p((__u64)(x)) ? \
>                                    ^
>    include/linux/byteorder/generic.h:86:21: note: in expansion of macro '__le64_to_cpu'
>     #define le64_to_cpu __le64_to_cpu
>                         ^~~~~~~~~~~~~
>    arch/arm64/include/asm/io.h:137:32: note: in expansion of macro 'readq_relaxed'
>     #define readq(c)  ({ u64 __v = readq_relaxed(c); __iormb(); __v; })
>                                    ^~~~~~~~~~~~~
>    drivers/mmc/host/cavium-mmc.c:156:19: note: in expansion of macro 'readq'
>      emm_switch.val = readq(host->base + MIO_EMM_SWITCH);
>                       ^~~~~
>    In file included from include/linux/scatterlist.h:8:0,
>                     from include/linux/dma-mapping.h:10,
>                     from drivers/mmc/host/cavium-mmc.c:18:
>    drivers/mmc/host/cavium-mmc.c: In function 'do_switch':
>    drivers/mmc/host/cavium-mmc.c:184:38: error: 'MIO_EMM_SWITCH' undeclared (first use in this function)
>      writeq(emm_switch.val, host->base + MIO_EMM_SWITCH);
>                                          ^
>    arch/arm64/include/asm/io.h:127:78: note: in definition of macro 'writeq_relaxed'
>     #define writeq_relaxed(v,c) ((void)__raw_writeq((__force u64)cpu_to_le64(v),(c)))
>                                                                                  ^
>    drivers/mmc/host/cavium-mmc.c:184:2: note: in expansion of macro 'writeq'
>      writeq(emm_switch.val, host->base + MIO_EMM_SWITCH);
>      ^~~~~~
>    In file included from include/linux/swab.h:4:0,
>                     from include/uapi/linux/byteorder/big_endian.h:12,
>                     from include/linux/byteorder/big_endian.h:4,
>                     from arch/arm64/include/uapi/asm/byteorder.h:20,
>                     from include/asm-generic/bitops/le.h:5,
>                     from arch/arm64/include/asm/bitops.h:50,
>                     from include/linux/bitops.h:36,
>                     from include/linux/kernel.h:10,
>                     from include/linux/delay.h:10,
>                     from drivers/mmc/host/cavium-mmc.c:16:
> >> drivers/mmc/host/cavium-mmc.c:191:36: error: 'MIO_EMM_RSP_STS' undeclared (first use in this function)
>       rsp_sts.val = readq(host->base + MIO_EMM_RSP_STS);
>                                        ^
>    include/uapi/linux/swab.h:129:32: note: in definition of macro '__swab64'
>      (__builtin_constant_p((__u64)(x)) ? \
>                                    ^
>    include/linux/byteorder/generic.h:86:21: note: in expansion of macro '__le64_to_cpu'
>     #define le64_to_cpu __le64_to_cpu
>                         ^~~~~~~~~~~~~
>    arch/arm64/include/asm/io.h:137:32: note: in expansion of macro 'readq_relaxed'
>     #define readq(c)  ({ u64 __v = readq_relaxed(c); __iormb(); __v; })
>                                    ^~~~~~~~~~~~~
>    drivers/mmc/host/cavium-mmc.c:191:17: note: in expansion of macro 'readq'
>       rsp_sts.val = readq(host->base + MIO_EMM_RSP_STS);
>                     ^~~~~
>    In file included from include/linux/scatterlist.h:8:0,
>                     from include/linux/dma-mapping.h:10,
>                     from drivers/mmc/host/cavium-mmc.c:18:
>    drivers/mmc/host/cavium-mmc.c: In function 'set_wdog':
> >> drivers/mmc/host/cavium-mmc.c:217:37: error: 'MIO_EMM_WDOG' undeclared (first use in this function)
>      writeq(timeout, slot->host->base + MIO_EMM_WDOG);
>                                         ^
>    arch/arm64/include/asm/io.h:127:78: note: in definition of macro 'writeq_relaxed'
>     #define writeq_relaxed(v,c) ((void)__raw_writeq((__force u64)cpu_to_le64(v),(c)))
>                                                                                  ^
>    drivers/mmc/host/cavium-mmc.c:217:2: note: in expansion of macro 'writeq'
>      writeq(timeout, slot->host->base + MIO_EMM_WDOG);
>      ^~~~~~
>    In file included from include/linux/swab.h:4:0,
>                     from include/uapi/linux/byteorder/big_endian.h:12,
>                     from include/linux/byteorder/big_endian.h:4,
>                     from arch/arm64/include/uapi/asm/byteorder.h:20,
>                     from include/asm-generic/bitops/le.h:5,
>                     from arch/arm64/include/asm/bitops.h:50,
>                     from include/linux/bitops.h:36,
>                     from include/linux/kernel.h:10,
>                     from include/linux/delay.h:10,
>                     from drivers/mmc/host/cavium-mmc.c:16:
>    drivers/mmc/host/cavium-mmc.c: In function 'cvm_mmc_reset_bus':
>    drivers/mmc/host/cavium-mmc.c:225:44: error: 'MIO_EMM_SWITCH' undeclared (first use in this function)
>      emm_switch.val = readq(slot->host->base + MIO_EMM_SWITCH);
>                                                ^
>    include/uapi/linux/swab.h:129:32: note: in definition of macro '__swab64'
>      (__builtin_constant_p((__u64)(x)) ? \
>                                    ^
>    include/linux/byteorder/generic.h:86:21: note: in expansion of macro '__le64_to_cpu'
>     #define le64_to_cpu __le64_to_cpu
>                         ^~~~~~~~~~~~~
>    arch/arm64/include/asm/io.h:137:32: note: in expansion of macro 'readq_relaxed'
>     #define readq(c)  ({ u64 __v = readq_relaxed(c); __iormb(); __v; })
>                                    ^~~~~~~~~~~~~
>    drivers/mmc/host/cavium-mmc.c:225:19: note: in expansion of macro 'readq'
>      emm_switch.val = readq(slot->host->base + MIO_EMM_SWITCH);
>                       ^~~~~
>    drivers/mmc/host/cavium-mmc.c:226:34: error: 'MIO_EMM_WDOG' undeclared (first use in this function)
>      wdog = readq(slot->host->base + MIO_EMM_WDOG);
>                                      ^
>    include/uapi/linux/swab.h:129:32: note: in definition of macro '__swab64'
>      (__builtin_constant_p((__u64)(x)) ? \
>                                    ^
>    include/linux/byteorder/generic.h:86:21: note: in expansion of macro '__le64_to_cpu'
>     #define le64_to_cpu __le64_to_cpu
>                         ^~~~~~~~~~~~~
>    arch/arm64/include/asm/io.h:137:32: note: in expansion of macro 'readq_relaxed'
>     #define readq(c)  ({ u64 __v = readq_relaxed(c); __iormb(); __v; })
>                                    ^~~~~~~~~~~~~
>    drivers/mmc/host/cavium-mmc.c:226:9: note: in expansion of macro 'readq'
>      wdog = readq(slot->host->base + MIO_EMM_WDOG);
>             ^~~~~
>    drivers/mmc/host/cavium-mmc.c: In function 'cvm_mmc_switch_to':
>    drivers/mmc/host/cavium-mmc.c:255:48: error: 'MIO_EMM_SWITCH' undeclared (first use in this function)
>       old_slot->cached_switch = readq(host->base + MIO_EMM_SWITCH);
>                                                    ^
>    include/uapi/linux/swab.h:129:32: note: in definition of macro '__swab64'
>      (__builtin_constant_p((__u64)(x)) ? \
>                                    ^
>    include/linux/byteorder/generic.h:86:21: note: in expansion of macro '__le64_to_cpu'
>     #define le64_to_cpu __le64_to_cpu
>                         ^~~~~~~~~~~~~
>    arch/arm64/include/asm/io.h:137:32: note: in expansion of macro 'readq_relaxed'
>     #define readq(c)  ({ u64 __v = readq_relaxed(c); __iormb(); __v; })
>                                    ^~~~~~~~~~~~~
>    drivers/mmc/host/cavium-mmc.c:255:29: note: in expansion of macro 'readq'
>       old_slot->cached_switch = readq(host->base + MIO_EMM_SWITCH);
>                                 ^~~~~
> >> drivers/mmc/host/cavium-mmc.c:256:45: error: 'MIO_EMM_RCA' undeclared (first use in this function)
>       old_slot->cached_rca = readq(host->base + MIO_EMM_RCA);
>                                                 ^
>    include/uapi/linux/swab.h:129:32: note: in definition of macro '__swab64'
>      (__builtin_constant_p((__u64)(x)) ? \
>                                    ^
>    include/linux/byteorder/generic.h:86:21: note: in expansion of macro '__le64_to_cpu'
>     #define le64_to_cpu __le64_to_cpu
>                         ^~~~~~~~~~~~~
>    arch/arm64/include/asm/io.h:137:32: note: in expansion of macro 'readq_relaxed'
>     #define readq(c)  ({ u64 __v = readq_relaxed(c); __iormb(); __v; })
>                                    ^~~~~~~~~~~~~
>    drivers/mmc/host/cavium-mmc.c:256:26: note: in expansion of macro 'readq'
>       old_slot->cached_rca = readq(host->base + MIO_EMM_RCA);
>                              ^~~~~
>    In file included from include/linux/scatterlist.h:8:0,
>                     from include/linux/dma-mapping.h:10,
>                     from drivers/mmc/host/cavium-mmc.c:18:
> >> drivers/mmc/host/cavium-mmc.c:267:38: error: 'MIO_EMM_SAMPLE' undeclared (first use in this function)
>      writeq(emm_sample.val, host->base + MIO_EMM_SAMPLE);
>                                          ^
>    arch/arm64/include/asm/io.h:127:78: note: in definition of macro 'writeq_relaxed'
>     #define writeq_relaxed(v,c) ((void)__raw_writeq((__force u64)cpu_to_le64(v),(c)))
>                                                                                  ^
>    drivers/mmc/host/cavium-mmc.c:267:2: note: in expansion of macro 'writeq'
>      writeq(emm_sample.val, host->base + MIO_EMM_SAMPLE);
>      ^~~~~~
>    drivers/mmc/host/cavium-mmc.c: In function 'do_read':
> >> drivers/mmc/host/cavium-mmc.c:281:47: error: 'MIO_EMM_BUF_IDX' undeclared (first use in this function)
>      writeq((0x10000 | (dbuf << 6)), host->base + MIO_EMM_BUF_IDX);
>                                                   ^
>    arch/arm64/include/asm/io.h:127:78: note: in definition of macro 'writeq_relaxed'
>     #define writeq_relaxed(v,c) ((void)__raw_writeq((__force u64)cpu_to_le64(v),(c)))
>                                                                                  ^
>    drivers/mmc/host/cavium-mmc.c:281:2: note: in expansion of macro 'writeq'
>      writeq((0x10000 | (dbuf << 6)), host->base + MIO_EMM_BUF_IDX);
>      ^~~~~~
>    In file included from include/linux/swab.h:4:0,
>                     from include/uapi/linux/byteorder/big_endian.h:12,
>                     from include/linux/byteorder/big_endian.h:4,
>                     from arch/arm64/include/uapi/asm/byteorder.h:20,
>                     from include/asm-generic/bitops/le.h:5,
>                     from arch/arm64/include/asm/bitops.h:50,
>                     from include/linux/bitops.h:36,
>                     from include/linux/kernel.h:10,
>                     from include/linux/delay.h:10,
>                     from drivers/mmc/host/cavium-mmc.c:16:
> >> drivers/mmc/host/cavium-mmc.c:291:29: error: 'MIO_EMM_BUF_DAT' undeclared (first use in this function)
>        dat = readq(host->base + MIO_EMM_BUF_DAT);
>                                 ^
>    include/uapi/linux/swab.h:129:32: note: in definition of macro '__swab64'
>      (__builtin_constant_p((__u64)(x)) ? \
>                                    ^
>    include/linux/byteorder/generic.h:86:21: note: in expansion of macro '__le64_to_cpu'
>     #define le64_to_cpu __le64_to_cpu
>                         ^~~~~~~~~~~~~
>    arch/arm64/include/asm/io.h:137:32: note: in expansion of macro 'readq_relaxed'
>     #define readq(c)  ({ u64 __v = readq_relaxed(c); __iormb(); __v; })
>                                    ^~~~~~~~~~~~~
>    drivers/mmc/host/cavium-mmc.c:291:10: note: in expansion of macro 'readq'
>        dat = readq(host->base + MIO_EMM_BUF_DAT);
>              ^~~~~
>    drivers/mmc/host/cavium-mmc.c: In function 'set_cmd_response':
> >> drivers/mmc/host/cavium-mmc.c:322:30: error: 'MIO_EMM_RSP_LO' undeclared (first use in this function)
>      rsp_lo = readq(host->base + MIO_EMM_RSP_LO);
>                                  ^
>    include/uapi/linux/swab.h:129:32: note: in definition of macro '__swab64'
>      (__builtin_constant_p((__u64)(x)) ? \
>                                    ^
>    include/linux/byteorder/generic.h:86:21: note: in expansion of macro '__le64_to_cpu'
>     #define le64_to_cpu __le64_to_cpu
>                         ^~~~~~~~~~~~~
>    arch/arm64/include/asm/io.h:137:32: note: in expansion of macro 'readq_relaxed'
>     #define readq(c)  ({ u64 __v = readq_relaxed(c); __iormb(); __v; })
>                                    ^~~~~~~~~~~~~
>    drivers/mmc/host/cavium-mmc.c:322:11: note: in expansion of macro 'readq'
>      rsp_lo = readq(host->base + MIO_EMM_RSP_LO);
>               ^~~~~
> >> drivers/mmc/host/cavium-mmc.c:335:31: error: 'MIO_EMM_RSP_HI' undeclared (first use in this function)
>       rsp_hi = readq(host->base + MIO_EMM_RSP_HI);
>                                   ^
>    include/uapi/linux/swab.h:129:32: note: in definition of macro '__swab64'
>      (__builtin_constant_p((__u64)(x)) ? \
>                                    ^
>    include/linux/byteorder/generic.h:86:21: note: in expansion of macro '__le64_to_cpu'
>     #define le64_to_cpu __le64_to_cpu
>                         ^~~~~~~~~~~~~
>    arch/arm64/include/asm/io.h:137:32: note: in expansion of macro 'readq_relaxed'
>     #define readq(c)  ({ u64 __v = readq_relaxed(c); __iormb(); __v; })
>                                    ^~~~~~~~~~~~~
>    drivers/mmc/host/cavium-mmc.c:335:12: note: in expansion of macro 'readq'
>       rsp_hi = readq(host->base + MIO_EMM_RSP_HI);
>                ^~~~~
>    drivers/mmc/host/cavium-mmc.c: In function 'cleanup_dma':
> >> drivers/mmc/host/cavium-mmc.c:375:35: error: 'MIO_EMM_DMA' undeclared (first use in this function)
>      emm_dma.val = readq(host->base + MIO_EMM_DMA);
>                                       ^
>    include/uapi/linux/swab.h:129:32: note: in definition of macro '__swab64'
>      (__builtin_constant_p((__u64)(x)) ? \
>                                    ^
>    include/linux/byteorder/generic.h:86:21: note: in expansion of macro '__le64_to_cpu'
>     #define le64_to_cpu __le64_to_cpu
>                         ^~~~~~~~~~~~~
>    arch/arm64/include/asm/io.h:137:32: note: in expansion of macro 'readq_relaxed'
>     #define readq(c)  ({ u64 __v = readq_relaxed(c); __iormb(); __v; })
>                                    ^~~~~~~~~~~~~
>    drivers/mmc/host/cavium-mmc.c:375:16: note: in expansion of macro 'readq'
>      emm_dma.val = readq(host->base + MIO_EMM_DMA);
>                    ^~~~~
>    drivers/mmc/host/cavium-mmc.c: In function 'cvm_mmc_interrupt':
> >> drivers/mmc/host/cavium-mmc.c:397:35: error: 'MIO_EMM_INT' undeclared (first use in this function)
>      emm_int.val = readq(host->base + MIO_EMM_INT);
>                                       ^
>    include/uapi/linux/swab.h:129:32: note: in definition of macro '__swab64'
>      (__builtin_constant_p((__u64)(x)) ? \
>                                    ^
>    include/linux/byteorder/generic.h:86:21: note: in expansion of macro '__le64_to_cpu'
>     #define le64_to_cpu __le64_to_cpu
>                         ^~~~~~~~~~~~~
>    arch/arm64/include/asm/io.h:137:32: note: in expansion of macro 'readq_relaxed'
>     #define readq(c)  ({ u64 __v = readq_relaxed(c); __iormb(); __v; })
>                                    ^~~~~~~~~~~~~
>    drivers/mmc/host/cavium-mmc.c:397:16: note: in expansion of macro 'readq'
>      emm_int.val = readq(host->base + MIO_EMM_INT);
>                    ^~~~~
>    drivers/mmc/host/cavium-mmc.c:407:35: error: 'MIO_EMM_RSP_STS' undeclared (first use in this function)
>      rsp_sts.val = readq(host->base + MIO_EMM_RSP_STS);
>                                       ^
>    include/uapi/linux/swab.h:129:32: note: in definition of macro '__swab64'
>      (__builtin_constant_p((__u64)(x)) ? \
>                                    ^
>    include/linux/byteorder/generic.h:86:21: note: in expansion of macro '__le64_to_cpu'
>     #define le64_to_cpu __le64_to_cpu
>                         ^~~~~~~~~~~~~
>    arch/arm64/include/asm/io.h:137:32: note: in expansion of macro 'readq_relaxed'
>     #define readq(c)  ({ u64 __v = readq_relaxed(c); __iormb(); __v; })
>                                    ^~~~~~~~~~~~~
>    drivers/mmc/host/cavium-mmc.c:407:16: note: in expansion of macro 'readq'
>      rsp_sts.val = readq(host->base + MIO_EMM_RSP_STS);
>                    ^~~~~
>    In file included from include/linux/scatterlist.h:8:0,
>                     from include/linux/dma-mapping.h:10,
>                     from drivers/mmc/host/cavium-mmc.c:18:
>    drivers/mmc/host/cavium-mmc.c: In function 'prepare_dma_single':
> >> drivers/mmc/host/cavium-mmc.c:486:39: error: 'MIO_EMM_DMA_CFG' undeclared (first use in this function)
>      writeq(dma_cfg.val, host->dma_base + MIO_EMM_DMA_CFG);
>                                           ^
>    arch/arm64/include/asm/io.h:127:78: note: in definition of macro 'writeq_relaxed'
>     #define writeq_relaxed(v,c) ((void)__raw_writeq((__force u64)cpu_to_le64(v),(c)))
>                                                                                  ^
>    drivers/mmc/host/cavium-mmc.c:486:2: note: in expansion of macro 'writeq'
>      writeq(dma_cfg.val, host->dma_base + MIO_EMM_DMA_CFG);
>      ^~~~~~
> >> drivers/mmc/host/cavium-mmc.c:492:33: error: 'MIO_EMM_DMA_ADR' undeclared (first use in this function)
>       writeq(addr, host->dma_base + MIO_EMM_DMA_ADR);
>                                     ^
>    arch/arm64/include/asm/io.h:127:78: note: in definition of macro 'writeq_relaxed'
>     #define writeq_relaxed(v,c) ((void)__raw_writeq((__force u64)cpu_to_le64(v),(c)))
>                                                                                  ^
>    drivers/mmc/host/cavium-mmc.c:492:3: note: in expansion of macro 'writeq'
>       writeq(addr, host->dma_base + MIO_EMM_DMA_ADR);
>       ^~~~~~
>    drivers/mmc/host/cavium-mmc.c: In function 'cvm_mmc_dma_request':
> >> drivers/mmc/host/cavium-mmc.c:587:38: error: 'MIO_EMM_STS_MASK' undeclared (first use in this function)
>       writeq(0x00b00000ull, host->base + MIO_EMM_STS_MASK);
>                                          ^
>    arch/arm64/include/asm/io.h:127:78: note: in definition of macro 'writeq_relaxed'
>     #define writeq_relaxed(v,c) ((void)__raw_writeq((__force u64)cpu_to_le64(v),(c)))
>                                                                                  ^
>    drivers/mmc/host/cavium-mmc.c:587:3: note: in expansion of macro 'writeq'
>       writeq(0x00b00000ull, host->base + MIO_EMM_STS_MASK);
>       ^~~~~~
>    drivers/mmc/host/cavium-mmc.c:590:35: error: 'MIO_EMM_DMA' undeclared (first use in this function)
>      writeq(emm_dma.val, host->base + MIO_EMM_DMA);
>                                       ^
>    arch/arm64/include/asm/io.h:127:78: note: in definition of macro 'writeq_relaxed'
>     #define writeq_relaxed(v,c) ((void)__raw_writeq((__force u64)cpu_to_le64(v),(c)))
>                                                                                  ^
>    drivers/mmc/host/cavium-mmc.c:590:2: note: in expansion of macro 'writeq'
>      writeq(emm_dma.val, host->base + MIO_EMM_DMA);
>      ^~~~~~
>    drivers/mmc/host/cavium-mmc.c: In function 'do_write_request':
>    drivers/mmc/host/cavium-mmc.c:618:34: error: 'MIO_EMM_BUF_IDX' undeclared (first use in this function)
>      writeq(0x10000ull, host->base + MIO_EMM_BUF_IDX);
>                                      ^
>    arch/arm64/include/asm/io.h:127:78: note: in definition of macro 'writeq_relaxed'
>     #define writeq_relaxed(v,c) ((void)__raw_writeq((__force u64)cpu_to_le64(v),(c)))
>                                                                                  ^
>    drivers/mmc/host/cavium-mmc.c:618:2: note: in expansion of macro 'writeq'
>      writeq(0x10000ull, host->base + MIO_EMM_BUF_IDX);
>      ^~~~~~
>    drivers/mmc/host/cavium-mmc.c:635:29: error: 'MIO_EMM_BUF_DAT' undeclared (first use in this function)
>        writeq(dat, host->base + MIO_EMM_BUF_DAT);
>                                 ^
>    arch/arm64/include/asm/io.h:127:78: note: in definition of macro 'writeq_relaxed'
>     #define writeq_relaxed(v,c) ((void)__raw_writeq((__force u64)cpu_to_le64(v),(c)))
>                                                                                  ^
>    drivers/mmc/host/cavium-mmc.c:635:4: note: in expansion of macro 'writeq'
>        writeq(dat, host->base + MIO_EMM_BUF_DAT);
>        ^~~~~~
>    drivers/mmc/host/cavium-mmc.c: In function 'cvm_mmc_request':
>    drivers/mmc/host/cavium-mmc.c:704:25: error: 'MIO_EMM_STS_MASK' undeclared (first use in this function)
>      writeq(0, host->base + MIO_EMM_STS_MASK);
>                             ^
>    arch/arm64/include/asm/io.h:127:78: note: in definition of macro 'writeq_relaxed'
>     #define writeq_relaxed(v,c) ((void)__raw_writeq((__force u64)cpu_to_le64(v),(c)))
>                                                                                  ^
>    drivers/mmc/host/cavium-mmc.c:704:2: note: in expansion of macro 'writeq'
>      writeq(0, host->base + MIO_EMM_STS_MASK);
>      ^~~~~~
>    In file included from include/linux/swab.h:4:0,
>                     from include/uapi/linux/byteorder/big_endian.h:12,
>                     from include/linux/byteorder/big_endian.h:4,
>                     from arch/arm64/include/uapi/asm/byteorder.h:20,
>                     from include/asm-generic/bitops/le.h:5,
>                     from arch/arm64/include/asm/bitops.h:50,
>                     from include/linux/bitops.h:36,
>                     from include/linux/kernel.h:10,
>                     from include/linux/delay.h:10,
>                     from drivers/mmc/host/cavium-mmc.c:16:
>    drivers/mmc/host/cavium-mmc.c:707:35: error: 'MIO_EMM_RSP_STS' undeclared (first use in this function)
>      rsp_sts.val = readq(host->base + MIO_EMM_RSP_STS);
>                                       ^
>    include/uapi/linux/swab.h:129:32: note: in definition of macro '__swab64'
>      (__builtin_constant_p((__u64)(x)) ? \
>                                    ^
>    include/linux/byteorder/generic.h:86:21: note: in expansion of macro '__le64_to_cpu'
>     #define le64_to_cpu __le64_to_cpu
>                         ^~~~~~~~~~~~~
>    arch/arm64/include/asm/io.h:137:32: note: in expansion of macro 'readq_relaxed'
>     #define readq(c)  ({ u64 __v = readq_relaxed(c); __iormb(); __v; })
>                                    ^~~~~~~~~~~~~
>    drivers/mmc/host/cavium-mmc.c:707:16: note: in expansion of macro 'readq'
>      rsp_sts.val = readq(host->base + MIO_EMM_RSP_STS);
>                    ^~~~~
>    In file included from include/linux/scatterlist.h:8:0,
>                     from include/linux/dma-mapping.h:10,
>                     from drivers/mmc/host/cavium-mmc.c:18:
> >> drivers/mmc/host/cavium-mmc.c:716:35: error: 'MIO_EMM_CMD' undeclared (first use in this function)
>      writeq(emm_cmd.val, host->base + MIO_EMM_CMD);
>                                       ^
>    arch/arm64/include/asm/io.h:127:78: note: in definition of macro 'writeq_relaxed'
>     #define writeq_relaxed(v,c) ((void)__raw_writeq((__force u64)cpu_to_le64(v),(c)))
>                                                                                  ^
>    drivers/mmc/host/cavium-mmc.c:716:2: note: in expansion of macro 'writeq'
>      writeq(emm_cmd.val, host->base + MIO_EMM_CMD);
>      ^~~~~~
>    drivers/mmc/host/cavium-mmc.c: In function 'cvm_mmc_init_lowlevel':
> >> drivers/mmc/host/cavium-mmc.c:818:43: error: 'MIO_EMM_CFG' undeclared (first use in this function)
>      writeq(host->emm_cfg, slot->host->base + MIO_EMM_CFG);
>                                               ^
>    arch/arm64/include/asm/io.h:127:78: note: in definition of macro 'writeq_relaxed'
>     #define writeq_relaxed(v,c) ((void)__raw_writeq((__force u64)cpu_to_le64(v),(c)))
>                                                                                  ^
>    drivers/mmc/host/cavium-mmc.c:818:2: note: in expansion of macro 'writeq'
>      writeq(host->emm_cfg, slot->host->base + MIO_EMM_CFG);
>      ^~~~~~
>    drivers/mmc/host/cavium-mmc.c:841:37: error: 'MIO_EMM_STS_MASK' undeclared (first use in this function)
>      writeq(0xe4390080ull, host->base + MIO_EMM_STS_MASK);
>                                         ^
>    arch/arm64/include/asm/io.h:127:78: note: in definition of macro 'writeq_relaxed'
>     #define writeq_relaxed(v,c) ((void)__raw_writeq((__force u64)cpu_to_le64(v),(c)))
>                                                                                  ^
>    drivers/mmc/host/cavium-mmc.c:841:2: note: in expansion of macro 'writeq'
>      writeq(0xe4390080ull, host->base + MIO_EMM_STS_MASK);
>      ^~~~~~
>    drivers/mmc/host/cavium-mmc.c:842:25: error: 'MIO_EMM_RCA' undeclared (first use in this function)
>      writeq(1, host->base + MIO_EMM_RCA);
>                             ^
>    arch/arm64/include/asm/io.h:127:78: note: in definition of macro 'writeq_relaxed'
>     #define writeq_relaxed(v,c) ((void)__raw_writeq((__force u64)cpu_to_le64(v),(c)))
>                                                                                  ^
>    drivers/mmc/host/cavium-mmc.c:842:2: note: in expansion of macro 'writeq'
>      writeq(1, host->base + MIO_EMM_RCA);
>      ^~~~~~
> ..
> 
> vim +/MIO_EMM_SWITCH +156 drivers/mmc/host/cavium-mmc.c
> 
> a16e92de Jan Glauber 2017-02-06   10   * Authors:
> a16e92de Jan Glauber 2017-02-06   11   *   David Daney <david.daney@cavium.com>
> a16e92de Jan Glauber 2017-02-06   12   *   Peter Swain <pswain@cavium.com>
> a16e92de Jan Glauber 2017-02-06   13   *   Steven J. Hill <steven.hill@cavium.com>
> a16e92de Jan Glauber 2017-02-06   14   *   Jan Glauber <jglauber@cavium.com>
> a16e92de Jan Glauber 2017-02-06   15   */
> a16e92de Jan Glauber 2017-02-06  @16  #include <linux/delay.h>
> a16e92de Jan Glauber 2017-02-06   17  #include <linux/dma-direction.h>
> a16e92de Jan Glauber 2017-02-06   18  #include <linux/dma-mapping.h>
> a16e92de Jan Glauber 2017-02-06   19  #include <linux/gpio/consumer.h>
> a16e92de Jan Glauber 2017-02-06   20  #include <linux/interrupt.h>
> a16e92de Jan Glauber 2017-02-06   21  #include <linux/mmc/mmc.h>
> a16e92de Jan Glauber 2017-02-06   22  #include <linux/mmc/slot-gpio.h>
> a16e92de Jan Glauber 2017-02-06   23  #include <linux/module.h>
> a16e92de Jan Glauber 2017-02-06   24  #include <linux/regulator/consumer.h>
> a16e92de Jan Glauber 2017-02-06   25  #include <linux/scatterlist.h>
> a16e92de Jan Glauber 2017-02-06   26  #include <linux/time.h>
> a16e92de Jan Glauber 2017-02-06   27  
> a16e92de Jan Glauber 2017-02-06   28  #include "cavium-mmc.h"
> a16e92de Jan Glauber 2017-02-06   29  
> a16e92de Jan Glauber 2017-02-06   30  /*
> a16e92de Jan Glauber 2017-02-06   31   * The Cavium MMC host hardware assumes that all commands have fixed
> a16e92de Jan Glauber 2017-02-06   32   * command and response types.  These are correct if MMC devices are
> a16e92de Jan Glauber 2017-02-06   33   * being used.  However, non-MMC devices like SD use command and
> a16e92de Jan Glauber 2017-02-06   34   * response types that are unexpected by the host hardware.
> a16e92de Jan Glauber 2017-02-06   35   *
> a16e92de Jan Glauber 2017-02-06   36   * The command and response types can be overridden by supplying an
> a16e92de Jan Glauber 2017-02-06   37   * XOR value that is applied to the type.  We calculate the XOR value
> a16e92de Jan Glauber 2017-02-06   38   * from the values in this table and the flags passed from the MMC
> a16e92de Jan Glauber 2017-02-06   39   * core.
> a16e92de Jan Glauber 2017-02-06   40   */
> a16e92de Jan Glauber 2017-02-06   41  static struct cvm_mmc_cr_type cvm_mmc_cr_types[] = {
> a16e92de Jan Glauber 2017-02-06   42  	{0, 0},		/* CMD0 */
> a16e92de Jan Glauber 2017-02-06   43  	{0, 3},		/* CMD1 */
> a16e92de Jan Glauber 2017-02-06   44  	{0, 2},		/* CMD2 */
> a16e92de Jan Glauber 2017-02-06   45  	{0, 1},		/* CMD3 */
> a16e92de Jan Glauber 2017-02-06   46  	{0, 0},		/* CMD4 */
> a16e92de Jan Glauber 2017-02-06   47  	{0, 1},		/* CMD5 */
> a16e92de Jan Glauber 2017-02-06   48  	{0, 1},		/* CMD6 */
> a16e92de Jan Glauber 2017-02-06   49  	{0, 1},		/* CMD7 */
> a16e92de Jan Glauber 2017-02-06   50  	{1, 1},		/* CMD8 */
> a16e92de Jan Glauber 2017-02-06   51  	{0, 2},		/* CMD9 */
> a16e92de Jan Glauber 2017-02-06   52  	{0, 2},		/* CMD10 */
> a16e92de Jan Glauber 2017-02-06   53  	{1, 1},		/* CMD11 */
> a16e92de Jan Glauber 2017-02-06   54  	{0, 1},		/* CMD12 */
> a16e92de Jan Glauber 2017-02-06   55  	{0, 1},		/* CMD13 */
> a16e92de Jan Glauber 2017-02-06   56  	{1, 1},		/* CMD14 */
> a16e92de Jan Glauber 2017-02-06   57  	{0, 0},		/* CMD15 */
> a16e92de Jan Glauber 2017-02-06   58  	{0, 1},		/* CMD16 */
> a16e92de Jan Glauber 2017-02-06   59  	{1, 1},		/* CMD17 */
> a16e92de Jan Glauber 2017-02-06   60  	{1, 1},		/* CMD18 */
> a16e92de Jan Glauber 2017-02-06   61  	{3, 1},		/* CMD19 */
> a16e92de Jan Glauber 2017-02-06   62  	{2, 1},		/* CMD20 */
> a16e92de Jan Glauber 2017-02-06   63  	{0, 0},		/* CMD21 */
> a16e92de Jan Glauber 2017-02-06   64  	{0, 0},		/* CMD22 */
> a16e92de Jan Glauber 2017-02-06   65  	{0, 1},		/* CMD23 */
> a16e92de Jan Glauber 2017-02-06   66  	{2, 1},		/* CMD24 */
> a16e92de Jan Glauber 2017-02-06   67  	{2, 1},		/* CMD25 */
> a16e92de Jan Glauber 2017-02-06   68  	{2, 1},		/* CMD26 */
> a16e92de Jan Glauber 2017-02-06   69  	{2, 1},		/* CMD27 */
> a16e92de Jan Glauber 2017-02-06   70  	{0, 1},		/* CMD28 */
> a16e92de Jan Glauber 2017-02-06   71  	{0, 1},		/* CMD29 */
> a16e92de Jan Glauber 2017-02-06   72  	{1, 1},		/* CMD30 */
> a16e92de Jan Glauber 2017-02-06   73  	{1, 1},		/* CMD31 */
> a16e92de Jan Glauber 2017-02-06   74  	{0, 0},		/* CMD32 */
> a16e92de Jan Glauber 2017-02-06   75  	{0, 0},		/* CMD33 */
> a16e92de Jan Glauber 2017-02-06   76  	{0, 0},		/* CMD34 */
> a16e92de Jan Glauber 2017-02-06   77  	{0, 1},		/* CMD35 */
> a16e92de Jan Glauber 2017-02-06   78  	{0, 1},		/* CMD36 */
> a16e92de Jan Glauber 2017-02-06   79  	{0, 0},		/* CMD37 */
> a16e92de Jan Glauber 2017-02-06   80  	{0, 1},		/* CMD38 */
> a16e92de Jan Glauber 2017-02-06   81  	{0, 4},		/* CMD39 */
> a16e92de Jan Glauber 2017-02-06   82  	{0, 5},		/* CMD40 */
> a16e92de Jan Glauber 2017-02-06   83  	{0, 0},		/* CMD41 */
> a16e92de Jan Glauber 2017-02-06   84  	{2, 1},		/* CMD42 */
> a16e92de Jan Glauber 2017-02-06   85  	{0, 0},		/* CMD43 */
> a16e92de Jan Glauber 2017-02-06   86  	{0, 0},		/* CMD44 */
> a16e92de Jan Glauber 2017-02-06   87  	{0, 0},		/* CMD45 */
> a16e92de Jan Glauber 2017-02-06   88  	{0, 0},		/* CMD46 */
> a16e92de Jan Glauber 2017-02-06   89  	{0, 0},		/* CMD47 */
> a16e92de Jan Glauber 2017-02-06   90  	{0, 0},		/* CMD48 */
> a16e92de Jan Glauber 2017-02-06   91  	{0, 0},		/* CMD49 */
> a16e92de Jan Glauber 2017-02-06   92  	{0, 0},		/* CMD50 */
> a16e92de Jan Glauber 2017-02-06   93  	{0, 0},		/* CMD51 */
> a16e92de Jan Glauber 2017-02-06   94  	{0, 0},		/* CMD52 */
> a16e92de Jan Glauber 2017-02-06   95  	{0, 0},		/* CMD53 */
> a16e92de Jan Glauber 2017-02-06   96  	{0, 0},		/* CMD54 */
> a16e92de Jan Glauber 2017-02-06   97  	{0, 1},		/* CMD55 */
> a16e92de Jan Glauber 2017-02-06   98  	{0xff, 0xff},	/* CMD56 */
> a16e92de Jan Glauber 2017-02-06   99  	{0, 0},		/* CMD57 */
> a16e92de Jan Glauber 2017-02-06  100  	{0, 0},		/* CMD58 */
> a16e92de Jan Glauber 2017-02-06  101  	{0, 0},		/* CMD59 */
> a16e92de Jan Glauber 2017-02-06  102  	{0, 0},		/* CMD60 */
> a16e92de Jan Glauber 2017-02-06  103  	{0, 0},		/* CMD61 */
> a16e92de Jan Glauber 2017-02-06  104  	{0, 0},		/* CMD62 */
> a16e92de Jan Glauber 2017-02-06  105  	{0, 0}		/* CMD63 */
> a16e92de Jan Glauber 2017-02-06  106  };
> a16e92de Jan Glauber 2017-02-06  107  
> a16e92de Jan Glauber 2017-02-06  108  static struct cvm_mmc_cr_mods cvm_mmc_get_cr_mods(struct mmc_command *cmd)
> a16e92de Jan Glauber 2017-02-06  109  {
> a16e92de Jan Glauber 2017-02-06  110  	struct cvm_mmc_cr_type *cr;
> a16e92de Jan Glauber 2017-02-06  111  	u8 hardware_ctype, hardware_rtype;
> a16e92de Jan Glauber 2017-02-06  112  	u8 desired_ctype = 0, desired_rtype = 0;
> a16e92de Jan Glauber 2017-02-06  113  	struct cvm_mmc_cr_mods r;
> a16e92de Jan Glauber 2017-02-06  114  
> a16e92de Jan Glauber 2017-02-06  115  	cr = cvm_mmc_cr_types + (cmd->opcode & 0x3f);
> a16e92de Jan Glauber 2017-02-06  116  	hardware_ctype = cr->ctype;
> a16e92de Jan Glauber 2017-02-06  117  	hardware_rtype = cr->rtype;
> a16e92de Jan Glauber 2017-02-06  118  	if (cmd->opcode == MMC_GEN_CMD)
> a16e92de Jan Glauber 2017-02-06  119  		hardware_ctype = (cmd->arg & 1) ? 1 : 2;
> a16e92de Jan Glauber 2017-02-06  120  
> a16e92de Jan Glauber 2017-02-06  121  	switch (mmc_cmd_type(cmd)) {
> a16e92de Jan Glauber 2017-02-06  122  	case MMC_CMD_ADTC:
> a16e92de Jan Glauber 2017-02-06  123  		desired_ctype = (cmd->data->flags & MMC_DATA_WRITE) ? 2 : 1;
> a16e92de Jan Glauber 2017-02-06  124  		break;
> a16e92de Jan Glauber 2017-02-06  125  	case MMC_CMD_AC:
> a16e92de Jan Glauber 2017-02-06  126  	case MMC_CMD_BC:
> a16e92de Jan Glauber 2017-02-06  127  	case MMC_CMD_BCR:
> a16e92de Jan Glauber 2017-02-06  128  		desired_ctype = 0;
> a16e92de Jan Glauber 2017-02-06  129  		break;
> a16e92de Jan Glauber 2017-02-06  130  	}
> a16e92de Jan Glauber 2017-02-06  131  
> a16e92de Jan Glauber 2017-02-06  132  	switch (mmc_resp_type(cmd)) {
> a16e92de Jan Glauber 2017-02-06  133  	case MMC_RSP_NONE:
> a16e92de Jan Glauber 2017-02-06  134  		desired_rtype = 0;
> a16e92de Jan Glauber 2017-02-06  135  		break;
> a16e92de Jan Glauber 2017-02-06  136  	case MMC_RSP_R1:/* MMC_RSP_R5, MMC_RSP_R6, MMC_RSP_R7 */
> a16e92de Jan Glauber 2017-02-06  137  	case MMC_RSP_R1B:
> a16e92de Jan Glauber 2017-02-06  138  		desired_rtype = 1;
> a16e92de Jan Glauber 2017-02-06  139  		break;
> a16e92de Jan Glauber 2017-02-06  140  	case MMC_RSP_R2:
> a16e92de Jan Glauber 2017-02-06  141  		desired_rtype = 2;
> a16e92de Jan Glauber 2017-02-06  142  		break;
> a16e92de Jan Glauber 2017-02-06  143  	case MMC_RSP_R3: /* MMC_RSP_R4 */
> a16e92de Jan Glauber 2017-02-06  144  		desired_rtype = 3;
> a16e92de Jan Glauber 2017-02-06  145  		break;
> a16e92de Jan Glauber 2017-02-06  146  	}
> a16e92de Jan Glauber 2017-02-06  147  	r.ctype_xor = desired_ctype ^ hardware_ctype;
> a16e92de Jan Glauber 2017-02-06  148  	r.rtype_xor = desired_rtype ^ hardware_rtype;
> a16e92de Jan Glauber 2017-02-06  149  	return r;
> a16e92de Jan Glauber 2017-02-06  150  }
> a16e92de Jan Glauber 2017-02-06  151  
> a16e92de Jan Glauber 2017-02-06  152  static void check_switch_errors(struct cvm_mmc_host *host)
> a16e92de Jan Glauber 2017-02-06  153  {
> a16e92de Jan Glauber 2017-02-06  154  	union mio_emm_switch emm_switch;
> a16e92de Jan Glauber 2017-02-06  155  
> a16e92de Jan Glauber 2017-02-06 @156  	emm_switch.val = readq(host->base + MIO_EMM_SWITCH);
> a16e92de Jan Glauber 2017-02-06  157  	if (emm_switch.s.switch_err0)
> a16e92de Jan Glauber 2017-02-06  158  		dev_err(host->dev, "Switch power class error\n");
> a16e92de Jan Glauber 2017-02-06  159  	if (emm_switch.s.switch_err1)
> a16e92de Jan Glauber 2017-02-06  160  		dev_err(host->dev, "Switch hs timing error\n");
> a16e92de Jan Glauber 2017-02-06  161  	if (emm_switch.s.switch_err2)
> a16e92de Jan Glauber 2017-02-06  162  		dev_err(host->dev, "Switch bus width error\n");
> a16e92de Jan Glauber 2017-02-06  163  }
> a16e92de Jan Glauber 2017-02-06  164  
> a16e92de Jan Glauber 2017-02-06  165  /*
> a16e92de Jan Glauber 2017-02-06  166   * We never set the switch_exe bit since that would interfere
> a16e92de Jan Glauber 2017-02-06  167   * with the commands send by the MMC core.
> a16e92de Jan Glauber 2017-02-06  168   */
> a16e92de Jan Glauber 2017-02-06  169  static void do_switch(struct cvm_mmc_host *host, u64 val)
> a16e92de Jan Glauber 2017-02-06  170  {
> a16e92de Jan Glauber 2017-02-06  171  	union mio_emm_rsp_sts rsp_sts;
> a16e92de Jan Glauber 2017-02-06  172  	union mio_emm_switch emm_switch;
> a16e92de Jan Glauber 2017-02-06  173  	int retries = 100;
> a16e92de Jan Glauber 2017-02-06  174  	int bus_id;
> a16e92de Jan Glauber 2017-02-06  175  
> a16e92de Jan Glauber 2017-02-06  176  	emm_switch.val = val;
> a16e92de Jan Glauber 2017-02-06  177  
> a16e92de Jan Glauber 2017-02-06  178  	/*
> a16e92de Jan Glauber 2017-02-06  179  	 * Modes setting only taken from slot 0. Work around that hardware
> a16e92de Jan Glauber 2017-02-06  180  	 * issue by first switching to slot 0.
> a16e92de Jan Glauber 2017-02-06  181  	 */
> a16e92de Jan Glauber 2017-02-06  182  	bus_id = emm_switch.s.bus_id;
> a16e92de Jan Glauber 2017-02-06  183  	emm_switch.s.bus_id = 0;
> a16e92de Jan Glauber 2017-02-06  184  	writeq(emm_switch.val, host->base + MIO_EMM_SWITCH);
> a16e92de Jan Glauber 2017-02-06  185  
> a16e92de Jan Glauber 2017-02-06  186  	emm_switch.s.bus_id = bus_id;
> a16e92de Jan Glauber 2017-02-06  187  	writeq(emm_switch.val, host->base + MIO_EMM_SWITCH);
> a16e92de Jan Glauber 2017-02-06  188  
> a16e92de Jan Glauber 2017-02-06  189  	/* wait for the switch to finish */
> a16e92de Jan Glauber 2017-02-06  190  	do {
> a16e92de Jan Glauber 2017-02-06 @191  		rsp_sts.val = readq(host->base + MIO_EMM_RSP_STS);
> a16e92de Jan Glauber 2017-02-06  192  		if (!rsp_sts.s.switch_val)
> a16e92de Jan Glauber 2017-02-06  193  			break;
> a16e92de Jan Glauber 2017-02-06  194  		udelay(10);
> a16e92de Jan Glauber 2017-02-06  195  	} while (--retries);
> a16e92de Jan Glauber 2017-02-06  196  
> a16e92de Jan Glauber 2017-02-06  197  	check_switch_errors(host);
> a16e92de Jan Glauber 2017-02-06  198  }
> a16e92de Jan Glauber 2017-02-06  199  
> a16e92de Jan Glauber 2017-02-06  200  static bool switch_val_changed(struct cvm_mmc_slot *slot, u64 new_val)
> a16e92de Jan Glauber 2017-02-06  201  {
> a16e92de Jan Glauber 2017-02-06  202  	/* Match BUS_ID, HS_TIMING, BUS_WIDTH, POWER_CLASS, CLK_HI, CLK_LO */
> a16e92de Jan Glauber 2017-02-06  203  	u64 match = 0x3001070fffffffffull;
> a16e92de Jan Glauber 2017-02-06  204  
> a16e92de Jan Glauber 2017-02-06  205  	return (slot->cached_switch & match) != (new_val & match);
> a16e92de Jan Glauber 2017-02-06  206  }
> a16e92de Jan Glauber 2017-02-06  207  
> a16e92de Jan Glauber 2017-02-06  208  static void set_wdog(struct cvm_mmc_slot *slot, unsigned int ns)
> a16e92de Jan Glauber 2017-02-06  209  {
> a16e92de Jan Glauber 2017-02-06  210  	u64 timeout;
> a16e92de Jan Glauber 2017-02-06  211  
> a16e92de Jan Glauber 2017-02-06  212  	WARN_ON_ONCE(!slot->clock);
> a16e92de Jan Glauber 2017-02-06  213  	if (ns)
> a16e92de Jan Glauber 2017-02-06  214  		timeout = (slot->clock * ns) / NSEC_PER_SEC;
> a16e92de Jan Glauber 2017-02-06  215  	else
> a16e92de Jan Glauber 2017-02-06  216  		timeout = (slot->clock * 850ull) / 1000ull;
> a16e92de Jan Glauber 2017-02-06 @217  	writeq(timeout, slot->host->base + MIO_EMM_WDOG);
> a16e92de Jan Glauber 2017-02-06  218  }
> a16e92de Jan Glauber 2017-02-06  219  
> a16e92de Jan Glauber 2017-02-06  220  static void cvm_mmc_reset_bus(struct cvm_mmc_slot *slot)
> a16e92de Jan Glauber 2017-02-06  221  {
> a16e92de Jan Glauber 2017-02-06  222  	union mio_emm_switch emm_switch;
> a16e92de Jan Glauber 2017-02-06  223  	u64 wdog = 0;
> a16e92de Jan Glauber 2017-02-06  224  
> a16e92de Jan Glauber 2017-02-06  225  	emm_switch.val = readq(slot->host->base + MIO_EMM_SWITCH);
> a16e92de Jan Glauber 2017-02-06  226  	wdog = readq(slot->host->base + MIO_EMM_WDOG);
> a16e92de Jan Glauber 2017-02-06  227  
> a16e92de Jan Glauber 2017-02-06  228  	emm_switch.s.switch_exe = 0;
> a16e92de Jan Glauber 2017-02-06  229  	emm_switch.s.switch_err0 = 0;
> a16e92de Jan Glauber 2017-02-06  230  	emm_switch.s.switch_err1 = 0;
> a16e92de Jan Glauber 2017-02-06  231  	emm_switch.s.switch_err2 = 0;
> a16e92de Jan Glauber 2017-02-06  232  	emm_switch.s.bus_id = slot->bus_id;
> a16e92de Jan Glauber 2017-02-06  233  	do_switch(slot->host, emm_switch.val);
> a16e92de Jan Glauber 2017-02-06  234  
> a16e92de Jan Glauber 2017-02-06  235  	slot->cached_switch = emm_switch.val;
> a16e92de Jan Glauber 2017-02-06  236  
> a16e92de Jan Glauber 2017-02-06  237  	msleep(20);
> a16e92de Jan Glauber 2017-02-06  238  
> a16e92de Jan Glauber 2017-02-06  239  	writeq(wdog, slot->host->base + MIO_EMM_WDOG);
> a16e92de Jan Glauber 2017-02-06  240  }
> a16e92de Jan Glauber 2017-02-06  241  
> a16e92de Jan Glauber 2017-02-06  242  /* Switch to another slot if needed */
> a16e92de Jan Glauber 2017-02-06  243  static void cvm_mmc_switch_to(struct cvm_mmc_slot *slot)
> a16e92de Jan Glauber 2017-02-06  244  {
> a16e92de Jan Glauber 2017-02-06  245  	struct cvm_mmc_host *host = slot->host;
> a16e92de Jan Glauber 2017-02-06  246  	struct cvm_mmc_slot *old_slot;
> a16e92de Jan Glauber 2017-02-06  247  	union mio_emm_switch emm_switch;
> a16e92de Jan Glauber 2017-02-06  248  	union mio_emm_sample emm_sample;
> a16e92de Jan Glauber 2017-02-06  249  
> a16e92de Jan Glauber 2017-02-06  250  	if (slot->bus_id == host->last_slot)
> a16e92de Jan Glauber 2017-02-06  251  		return;
> a16e92de Jan Glauber 2017-02-06  252  
> a16e92de Jan Glauber 2017-02-06  253  	if (host->last_slot >= 0 && host->slot[host->last_slot]) {
> a16e92de Jan Glauber 2017-02-06  254  		old_slot = host->slot[host->last_slot];
> a16e92de Jan Glauber 2017-02-06 @255  		old_slot->cached_switch = readq(host->base + MIO_EMM_SWITCH);
> a16e92de Jan Glauber 2017-02-06 @256  		old_slot->cached_rca = readq(host->base + MIO_EMM_RCA);
> a16e92de Jan Glauber 2017-02-06  257  	}
> a16e92de Jan Glauber 2017-02-06  258  
> a16e92de Jan Glauber 2017-02-06  259  	writeq(slot->cached_rca, host->base + MIO_EMM_RCA);
> a16e92de Jan Glauber 2017-02-06  260  	emm_switch.val = slot->cached_switch;
> a16e92de Jan Glauber 2017-02-06  261  	emm_switch.s.bus_id = slot->bus_id;
> a16e92de Jan Glauber 2017-02-06  262  	do_switch(host, emm_switch.val);
> a16e92de Jan Glauber 2017-02-06  263  
> a16e92de Jan Glauber 2017-02-06  264  	emm_sample.val = 0;
> a16e92de Jan Glauber 2017-02-06  265  	emm_sample.s.cmd_cnt = slot->cmd_cnt;
> a16e92de Jan Glauber 2017-02-06  266  	emm_sample.s.dat_cnt = slot->dat_cnt;
> a16e92de Jan Glauber 2017-02-06 @267  	writeq(emm_sample.val, host->base + MIO_EMM_SAMPLE);
> a16e92de Jan Glauber 2017-02-06  268  
> a16e92de Jan Glauber 2017-02-06  269  	host->last_slot = slot->bus_id;
> a16e92de Jan Glauber 2017-02-06  270  }
> a16e92de Jan Glauber 2017-02-06  271  
> a16e92de Jan Glauber 2017-02-06  272  static void do_read(struct cvm_mmc_host *host, struct mmc_request *req,
> a16e92de Jan Glauber 2017-02-06  273  		    u64 dbuf)
> a16e92de Jan Glauber 2017-02-06  274  {
> a16e92de Jan Glauber 2017-02-06  275  	struct sg_mapping_iter *smi = &host->smi;
> a16e92de Jan Glauber 2017-02-06  276  	int data_len = req->data->blocks * req->data->blksz;
> a16e92de Jan Glauber 2017-02-06  277  	int bytes_xfered, shift = -1;
> a16e92de Jan Glauber 2017-02-06  278  	u64 dat = 0;
> a16e92de Jan Glauber 2017-02-06  279  
> a16e92de Jan Glauber 2017-02-06  280  	/* Auto inc from offset zero */
> a16e92de Jan Glauber 2017-02-06 @281  	writeq((0x10000 | (dbuf << 6)), host->base + MIO_EMM_BUF_IDX);
> a16e92de Jan Glauber 2017-02-06  282  
> a16e92de Jan Glauber 2017-02-06  283  	for (bytes_xfered = 0; bytes_xfered < data_len;) {
> a16e92de Jan Glauber 2017-02-06  284  		if (smi->consumed >= smi->length) {
> a16e92de Jan Glauber 2017-02-06  285  			if (!sg_miter_next(smi))
> a16e92de Jan Glauber 2017-02-06  286  				break;
> a16e92de Jan Glauber 2017-02-06  287  			smi->consumed = 0;
> a16e92de Jan Glauber 2017-02-06  288  		}
> a16e92de Jan Glauber 2017-02-06  289  
> a16e92de Jan Glauber 2017-02-06  290  		if (shift < 0) {
> a16e92de Jan Glauber 2017-02-06 @291  			dat = readq(host->base + MIO_EMM_BUF_DAT);
> a16e92de Jan Glauber 2017-02-06  292  			shift = 56;
> a16e92de Jan Glauber 2017-02-06  293  		}
> a16e92de Jan Glauber 2017-02-06  294  
> a16e92de Jan Glauber 2017-02-06  295  		while (smi->consumed < smi->length && shift >= 0) {
> a16e92de Jan Glauber 2017-02-06  296  			((u8 *)smi->addr)[smi->consumed] = (dat >> shift) & 0xff;
> a16e92de Jan Glauber 2017-02-06  297  			bytes_xfered++;
> a16e92de Jan Glauber 2017-02-06  298  			smi->consumed++;
> a16e92de Jan Glauber 2017-02-06  299  			shift -= 8;
> a16e92de Jan Glauber 2017-02-06  300  		}
> a16e92de Jan Glauber 2017-02-06  301  	}
> a16e92de Jan Glauber 2017-02-06  302  
> a16e92de Jan Glauber 2017-02-06  303  	sg_miter_stop(smi);
> a16e92de Jan Glauber 2017-02-06  304  	req->data->bytes_xfered = bytes_xfered;
> a16e92de Jan Glauber 2017-02-06  305  	req->data->error = 0;
> a16e92de Jan Glauber 2017-02-06  306  }
> a16e92de Jan Glauber 2017-02-06  307  
> a16e92de Jan Glauber 2017-02-06  308  static void do_write(struct mmc_request *req)
> a16e92de Jan Glauber 2017-02-06  309  {
> a16e92de Jan Glauber 2017-02-06  310  	req->data->bytes_xfered = req->data->blocks * req->data->blksz;
> a16e92de Jan Glauber 2017-02-06  311  	req->data->error = 0;
> a16e92de Jan Glauber 2017-02-06  312  }
> a16e92de Jan Glauber 2017-02-06  313  
> a16e92de Jan Glauber 2017-02-06  314  static void set_cmd_response(struct cvm_mmc_host *host, struct mmc_request *req,
> a16e92de Jan Glauber 2017-02-06  315  			     union mio_emm_rsp_sts *rsp_sts)
> a16e92de Jan Glauber 2017-02-06  316  {
> a16e92de Jan Glauber 2017-02-06  317  	u64 rsp_hi, rsp_lo;
> a16e92de Jan Glauber 2017-02-06  318  
> a16e92de Jan Glauber 2017-02-06  319  	if (!rsp_sts->s.rsp_val)
> a16e92de Jan Glauber 2017-02-06  320  		return;
> a16e92de Jan Glauber 2017-02-06  321  
> a16e92de Jan Glauber 2017-02-06 @322  	rsp_lo = readq(host->base + MIO_EMM_RSP_LO);
> a16e92de Jan Glauber 2017-02-06  323  
> a16e92de Jan Glauber 2017-02-06  324  	switch (rsp_sts->s.rsp_type) {
> a16e92de Jan Glauber 2017-02-06  325  	case 1:
> a16e92de Jan Glauber 2017-02-06  326  	case 3:
> a16e92de Jan Glauber 2017-02-06  327  		req->cmd->resp[0] = (rsp_lo >> 8) & 0xffffffff;
> a16e92de Jan Glauber 2017-02-06  328  		req->cmd->resp[1] = 0;
> a16e92de Jan Glauber 2017-02-06  329  		req->cmd->resp[2] = 0;
> a16e92de Jan Glauber 2017-02-06  330  		req->cmd->resp[3] = 0;
> a16e92de Jan Glauber 2017-02-06  331  		break;
> a16e92de Jan Glauber 2017-02-06  332  	case 2:
> a16e92de Jan Glauber 2017-02-06  333  		req->cmd->resp[3] = rsp_lo & 0xffffffff;
> a16e92de Jan Glauber 2017-02-06  334  		req->cmd->resp[2] = (rsp_lo >> 32) & 0xffffffff;
> a16e92de Jan Glauber 2017-02-06 @335  		rsp_hi = readq(host->base + MIO_EMM_RSP_HI);
> a16e92de Jan Glauber 2017-02-06  336  		req->cmd->resp[1] = rsp_hi & 0xffffffff;
> a16e92de Jan Glauber 2017-02-06  337  		req->cmd->resp[0] = (rsp_hi >> 32) & 0xffffffff;
> a16e92de Jan Glauber 2017-02-06  338  		break;
> 
> :::::: The code at line 156 was first introduced by commit
> :::::: a16e92dea256e2d09874770563fc9000029fc235 mmc: cavium: Add core MMC driver for Cavium SOCs
> 
> :::::: TO: Jan Glauber <jglauber@cavium.com>
> :::::: CC: 0day robot <fengguang.wu@intel.com>
> 
> ---
> 0-DAY kernel test infrastructure                Open Source Technology Center
> https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v11 6/9] mmc: cavium: Add MMC PCI driver for ThunderX SOCs
  2017-02-13 15:24     ` Jan Glauber
@ 2017-02-13 15:45       ` Ulf Hansson
  2017-02-15 12:34         ` Arnd Bergmann
  0 siblings, 1 reply; 24+ messages in thread
From: Ulf Hansson @ 2017-02-13 15:45 UTC (permalink / raw)
  To: Jan Glauber
  Cc: kbuild-all, linux-mmc, linux-kernel, David Daney,
	Steven J . Hill, David Daney

On 13 February 2017 at 16:24, Jan Glauber
<jan.glauber@caviumnetworks.com> wrote:
> On Sun, Feb 12, 2017 at 09:09:29AM +0800, kbuild test robot wrote:
>> Hi Jan,
>>
>> [auto build test ERROR on linus/master]
>> [also build test ERROR on v4.10-rc7 next-20170210]
>> [if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
>>
>> url:    https://github.com/0day-ci/linux/commits/Jan-Glauber/Cavium-MMC-driver/20170206-214740
>> config: arm64-allmodconfig (attached as .config)
>> compiler: aarch64-linux-gnu-gcc (Debian 6.1.1-9) 6.1.1 20160705
>> reproduce:
>>         wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
>>         chmod +x ~/bin/make.cross
>>         # save the attached .config to linux build tree
>>         make.cross ARCH=arm64
>>
>> All errors (new ones prefixed by >>):
>>
>>    In file included from drivers/mmc/host/cavium-mmc.c:28:0:
>>    drivers/mmc/host/cavium-mmc.h:41:7: warning: "CONFIG_MMC_CAVIUM_THUNDERX" is not defined [-Wundef]
>>     #elif CONFIG_MMC_CAVIUM_THUNDERX
>>           ^~~~~~~~~~~~~~~~~~~~~~~~~~
>
> Hi Ulf,
>
> We are aware of this build error, the line above should be:
> #elif IS_ENABLED(CONFIG_MMC_CAVIUM_THUNDERX)

Please avoid using IS_ENABLED() - unless really needed.

Doesn't "#ifdef" work here?

>
> instead of:
> #elif CONFIG_MMC_CAVIUM_THUNDERX
>
> Unless you want it otherwise I'll wait for your review of the series
> and fix this build error with the next revision.

I have started to look at the series (I have comments). So, unless
some other provides you with relevant comments, you can wait for mine
before re-spin.

[...]

Kind regards
Uffe

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v11 6/9] mmc: cavium: Add MMC PCI driver for ThunderX SOCs
  2017-02-13 15:45       ` Ulf Hansson
@ 2017-02-15 12:34         ` Arnd Bergmann
  2017-02-15 13:54           ` Jan Glauber
  0 siblings, 1 reply; 24+ messages in thread
From: Arnd Bergmann @ 2017-02-15 12:34 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: Jan Glauber, kbuild-all, linux-mmc, linux-kernel, David Daney,
	Steven J . Hill, David Daney

On Mon, Feb 13, 2017 at 4:45 PM, Ulf Hansson <ulf.hansson@linaro.org> wrote:
> On 13 February 2017 at 16:24, Jan Glauber
> <jan.glauber@caviumnetworks.com> wrote:
>> On Sun, Feb 12, 2017 at 09:09:29AM +0800, kbuild test robot wrote:
>>> Hi Jan,
>>>
>>> [auto build test ERROR on linus/master]
>>> [also build test ERROR on v4.10-rc7 next-20170210]
>>> [if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
>>>
>>> url:    https://github.com/0day-ci/linux/commits/Jan-Glauber/Cavium-MMC-driver/20170206-214740
>>> config: arm64-allmodconfig (attached as .config)
>>> compiler: aarch64-linux-gnu-gcc (Debian 6.1.1-9) 6.1.1 20160705
>>> reproduce:
>>>         wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
>>>         chmod +x ~/bin/make.cross
>>>         # save the attached .config to linux build tree
>>>         make.cross ARCH=arm64
>>>
>>> All errors (new ones prefixed by >>):
>>>
>>>    In file included from drivers/mmc/host/cavium-mmc.c:28:0:
>>>    drivers/mmc/host/cavium-mmc.h:41:7: warning: "CONFIG_MMC_CAVIUM_THUNDERX" is not defined [-Wundef]
>>>     #elif CONFIG_MMC_CAVIUM_THUNDERX
>>>           ^~~~~~~~~~~~~~~~~~~~~~~~~~
>>
>> Hi Ulf,
>>
>> We are aware of this build error, the line above should be:
>> #elif IS_ENABLED(CONFIG_MMC_CAVIUM_THUNDERX)
>
> Please avoid using IS_ENABLED() - unless really needed.
>
> Doesn't "#ifdef" work here?
>

No, CONFIG_MMC_CAVIUM_THUNDERX is a tristate symbol and #ifdef won't
work for =m.

Ideally, the base driver would not have any such preprocessor checks at
all though, and just work either way. While I realize that octeon and thunderx
are mutually exclusive in practice, the patch as it is written here is somewhat
confusing as turning on both options (with COMPILE_TEST) will break
at least one of the two.

    Arnd

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v11 6/9] mmc: cavium: Add MMC PCI driver for ThunderX SOCs
  2017-02-15 12:34         ` Arnd Bergmann
@ 2017-02-15 13:54           ` Jan Glauber
  0 siblings, 0 replies; 24+ messages in thread
From: Jan Glauber @ 2017-02-15 13:54 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Ulf Hansson, kbuild-all, linux-mmc, linux-kernel, David Daney,
	Steven J . Hill, David Daney

On Wed, Feb 15, 2017 at 01:34:40PM +0100, Arnd Bergmann wrote:
> On Mon, Feb 13, 2017 at 4:45 PM, Ulf Hansson <ulf.hansson@linaro.org> wrote:
> > On 13 February 2017 at 16:24, Jan Glauber
> > <jan.glauber@caviumnetworks.com> wrote:
> >> On Sun, Feb 12, 2017 at 09:09:29AM +0800, kbuild test robot wrote:
> >>> Hi Jan,
> >>>
> >>> [auto build test ERROR on linus/master]
> >>> [also build test ERROR on v4.10-rc7 next-20170210]
> >>> [if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
> >>>
> >>> url:    https://github.com/0day-ci/linux/commits/Jan-Glauber/Cavium-MMC-driver/20170206-214740
> >>> config: arm64-allmodconfig (attached as .config)
> >>> compiler: aarch64-linux-gnu-gcc (Debian 6.1.1-9) 6.1.1 20160705
> >>> reproduce:
> >>>         wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
> >>>         chmod +x ~/bin/make.cross
> >>>         # save the attached .config to linux build tree
> >>>         make.cross ARCH=arm64
> >>>
> >>> All errors (new ones prefixed by >>):
> >>>
> >>>    In file included from drivers/mmc/host/cavium-mmc.c:28:0:
> >>>    drivers/mmc/host/cavium-mmc.h:41:7: warning: "CONFIG_MMC_CAVIUM_THUNDERX" is not defined [-Wundef]
> >>>     #elif CONFIG_MMC_CAVIUM_THUNDERX
> >>>           ^~~~~~~~~~~~~~~~~~~~~~~~~~
> >>
> >> Hi Ulf,
> >>
> >> We are aware of this build error, the line above should be:
> >> #elif IS_ENABLED(CONFIG_MMC_CAVIUM_THUNDERX)
> >
> > Please avoid using IS_ENABLED() - unless really needed.
> >
> > Doesn't "#ifdef" work here?
> >
> 
> No, CONFIG_MMC_CAVIUM_THUNDERX is a tristate symbol and #ifdef won't
> work for =m.

Yes, that was the reason for using IS_ENABLED().

> Ideally, the base driver would not have any such preprocessor checks at
> all though, and just work either way. While I realize that octeon and thunderx
> are mutually exclusive in practice, the patch as it is written here is somewhat
> confusing as turning on both options (with COMPILE_TEST) will break
> at least one of the two.

I'll try to get rid of the preprocessor checks for the next version.

--Jan

>     Arnd

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v11 1/9] dt-bindings: mmc: Add Cavium SOCs MMC bindings
  2017-02-06 13:39 ` [PATCH v11 1/9] dt-bindings: mmc: Add Cavium SOCs MMC bindings Jan Glauber
  2017-02-09  0:40   ` Rob Herring
@ 2017-03-03 11:47   ` Ulf Hansson
  2017-03-06 11:09     ` Jan Glauber
  1 sibling, 1 reply; 24+ messages in thread
From: Ulf Hansson @ 2017-03-03 11:47 UTC (permalink / raw)
  To: Jan Glauber
  Cc: linux-mmc, linux-kernel, David Daney, Steven J . Hill,
	Rob Herring, Mark Rutland, devicetree, David Daney

On 6 February 2017 at 14:39, Jan Glauber <jglauber@cavium.com> wrote:
> Add description of Cavium Octeon and ThunderX SOC device tree bindings.
>
> CC: Ulf Hansson <ulf.hansson@linaro.org>
> CC: Rob Herring <robh+dt@kernel.org>
> CC: Mark Rutland <mark.rutland@arm.com>
> CC: devicetree@vger.kernel.org
>
> Signed-off-by: Jan Glauber <jglauber@cavium.com>
> Signed-off-by: David Daney <david.daney@cavium.com>
> Signed-off-by: Steven J. Hill <steven.hill@cavium.com>
> ---
>  .../devicetree/bindings/mmc/cavium-mmc.txt         | 60 ++++++++++++++++++++++
>  1 file changed, 60 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/mmc/cavium-mmc.txt
>
> diff --git a/Documentation/devicetree/bindings/mmc/cavium-mmc.txt b/Documentation/devicetree/bindings/mmc/cavium-mmc.txt
> new file mode 100644
> index 0000000..b79e356
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mmc/cavium-mmc.txt
> @@ -0,0 +1,60 @@
> +* Cavium Octeon & ThunderX MMC controller
> +
> +The highspeed MMC host controller on Caviums SoCs provides an interface
> +for MMC and SD types of memory cards.
> +
> +Supported maximum speeds are the ones of the eMMC standard 4.41 as well
> +as the speed of SD standard 4.0. Only 3.3 Volt is supported.
> +
> +Required properties:
> + - compatible : should be one of:
> +   cavium,octeon-6130-mmc
> +   cavium,octeon-6130-mmc-slot
> +   cavium,octeon-7890-mmc
> +   cavium,octeon-7890-mmc-slot
> +   cavium,thunder-8190-mmc
> +   cavium,thunder-8190-mmc-slot
> +   cavium,thunder-8390-mmc
> +   cavium,thunder-8390-mmc-slot
> + - reg : mmc controller base registers
> + - clocks : phandle
> +
> +Optional properties:
> + - for cd, bus-width and additional generic mmc parameters
> +   please refer to mmc.txt within this directory
> + - cavium,cmd-clk-skew : number of coprocessor clocks before sampling command
> + - cavium,dat-clk-skew : number of coprocessor clocks before sampling data
> +
> +Deprecated properties:
> +- spi-max-frequency : use max-frequency instead
> +- cavium,bus-max-width : use bus-width instead
> +
> +Examples:
> +       mmc_1_4: mmc@1,4 {
> +               compatible = "cavium,thunder-8390-mmc";
> +               reg = <0x0c00 0 0 0 0>; /* DEVFN = 0x0c (1:4) */
> +               #address-cells = <1>;
> +               #size-cells = <0>;
> +               clocks = <&sclk>;
> +
> +               mmc-slot@0 {
> +                       compatible = "cavium,thunder-8390-mmc-slot";
> +                       reg = <0>;
> +                       voltage-ranges = <3300 3300>;
> +                       vmmc-supply = <&mmc_supply_3v3>;

The vmmc supply as a regulator provides you with the voltage range,
thus you don't need the "voltage-ranges" here. Please remove this.

> +                       max-frequency = <42000000>;
> +                       bus-width = <4>;
> +                       cap-sd-highspeed;
> +               };
> +
> +               mmc-slot@1 {
> +                       compatible = "cavium,thunder-8390-mmc-slot";
> +                       reg = <1>;
> +                       voltage-ranges = <3300 3300>;
> +                       vmmc-supply = <&mmc_supply_3v3>;

Ditto.

> +                       max-frequency = <42000000>;
> +                       bus-width = <8>;
> +                       cap-mmc-highspeed;
> +                       non-removable;
> +               };
> +       };
> --
> 2.9.0.rc0.21.g7777322
>

Kind regards
Uffe

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v11 2/9] mmc: cavium: Add core MMC driver for Cavium SOCs
  2017-02-06 13:39 ` [PATCH v11 2/9] mmc: cavium: Add core MMC driver for Cavium SOCs Jan Glauber
@ 2017-03-03 11:47   ` Ulf Hansson
  2017-03-03 18:39     ` David Daney
  2017-03-07 10:49     ` Jan Glauber
  0 siblings, 2 replies; 24+ messages in thread
From: Ulf Hansson @ 2017-03-03 11:47 UTC (permalink / raw)
  To: Jan Glauber
  Cc: linux-mmc, linux-kernel, David Daney, Steven J . Hill, David Daney

On 6 February 2017 at 14:39, Jan Glauber <jglauber@cavium.com> wrote:
> This core driver will be used by a MIPS platform driver
> or by an ARM64 PCI driver. The core driver implements the
> mmc_host_ops and slot probe & remove functions.
> Callbacks are provided to allow platform specific interrupt
> enable and bus locking.
>
> The host controller supports:
> - up to 4 slots that can contain sd-cards or eMMC chips
> - 1, 4 and 8 bit bus width
> - SDR and DDR
> - transfers up to 52 Mhz (might be less when multiple slots are used)
> - DMA read/write
> - multi-block read/write (but not stream mode)
>
> Voltage is limited to 3.3v and shared for all slots.

What voltage? The I/O voltage or the voltage for the card?

VMMC or VMMCQ?

>
> A global lock for all MMC devices is required because the host
> controller is shared.
>
> Signed-off-by: Jan Glauber <jglauber@cavium.com>
> Signed-off-by: David Daney <david.daney@cavium.com>
> Signed-off-by: Steven J. Hill <steven.hill@cavium.com>
> ---
>  drivers/mmc/host/cavium-mmc.c | 1029 +++++++++++++++++++++++++++++++++++++++++
>  drivers/mmc/host/cavium-mmc.h |  303 ++++++++++++
>  2 files changed, 1332 insertions(+)
>  create mode 100644 drivers/mmc/host/cavium-mmc.c
>  create mode 100644 drivers/mmc/host/cavium-mmc.h
>
> diff --git a/drivers/mmc/host/cavium-mmc.c b/drivers/mmc/host/cavium-mmc.c
> new file mode 100644
> index 0000000..40aee08
> --- /dev/null
> +++ b/drivers/mmc/host/cavium-mmc.c

[...]

> +
> +static bool bad_status(union mio_emm_rsp_sts *rsp_sts)
> +{
> +       if (rsp_sts->s.rsp_bad_sts || rsp_sts->s.rsp_crc_err ||
> +           rsp_sts->s.rsp_timeout || rsp_sts->s.blk_crc_err ||
> +           rsp_sts->s.blk_timeout || rsp_sts->s.dbuf_err)
> +               return true;
> +
> +       return false;
> +}
> +
> +/* Try to clean up failed DMA. */
> +static void cleanup_dma(struct cvm_mmc_host *host,
> +                       union mio_emm_rsp_sts *rsp_sts)
> +{
> +       union mio_emm_dma emm_dma;
> +
> +       emm_dma.val = readq(host->base + MIO_EMM_DMA);
> +       emm_dma.s.dma_val = 1;
> +       emm_dma.s.dat_null = 1;
> +       emm_dma.s.bus_id = rsp_sts->s.bus_id;
> +       writeq(emm_dma.val, host->base + MIO_EMM_DMA);
> +}
> +
> +irqreturn_t cvm_mmc_interrupt(int irq, void *dev_id)
> +{
> +       struct cvm_mmc_host *host = dev_id;
> +       union mio_emm_rsp_sts rsp_sts;
> +       union mio_emm_int emm_int;
> +       struct mmc_request *req;
> +       bool host_done;
> +
> +       /* Clear interrupt bits (write 1 clears ). */
> +       emm_int.val = readq(host->base + MIO_EMM_INT);
> +       writeq(emm_int.val, host->base + MIO_EMM_INT);
> +
> +       if (emm_int.s.switch_err)
> +               check_switch_errors(host);
> +
> +       req = host->current_req;
> +       if (!req)
> +               goto out;
> +
> +       rsp_sts.val = readq(host->base + MIO_EMM_RSP_STS);
> +       /*
> +        * dma_val set means DMA is still in progress. Don't touch
> +        * the request and wait for the interrupt indicating that
> +        * the DMA is finished.
> +        */
> +       if (rsp_sts.s.dma_val && host->dma_active)
> +               goto out;
> +
> +       if (!host->dma_active && emm_int.s.buf_done && req->data) {
> +               unsigned int type = (rsp_sts.val >> 7) & 3;
> +
> +               if (type == 1)
> +                       do_read(host, req, rsp_sts.s.dbuf);
> +               else if (type == 2)
> +                       do_write(req);
> +       }
> +
> +       host_done = emm_int.s.cmd_done || emm_int.s.dma_done ||
> +                   emm_int.s.cmd_err || emm_int.s.dma_err;
> +
> +       if (!(host_done && req->done))
> +               goto no_req_done;
> +
> +       if (bad_status(&rsp_sts))
> +               req->cmd->error = -EILSEQ;

I don't think you should treat all errors as -EILSEQ. Please assign a
proper error code, depending on the error.

> +       else
> +               req->cmd->error = 0;
> +
> +       if (host->dma_active && req->data)
> +               if (!finish_dma(host, req->data))
> +                       goto no_req_done;
> +
> +       set_cmd_response(host, req, &rsp_sts);
> +       if (emm_int.s.dma_err && rsp_sts.s.dma_pend)
> +               cleanup_dma(host, &rsp_sts);
> +
> +       host->current_req = NULL;
> +       req->done(req);
> +
> +no_req_done:
> +       if (host_done)
> +               host->release_bus(host);
> +out:
> +       return IRQ_RETVAL(emm_int.val != 0);
> +}
> +
> +/*
> + * Program DMA_CFG and if needed DMA_ADR.
> + * Returns 0 on error, DMA address otherwise.
> + */
> +static u64 prepare_dma_single(struct cvm_mmc_host *host, struct mmc_data *data)
> +{
> +       union mio_emm_dma_cfg dma_cfg;
> +       int count;
> +       u64 addr;
> +
> +       count = dma_map_sg(host->dev, data->sg, data->sg_len,
> +                          get_dma_dir(data));
> +       if (!count)
> +               return 0;
> +
> +       dma_cfg.val = 0;
> +       dma_cfg.s.en = 1;
> +       dma_cfg.s.rw = (data->flags & MMC_DATA_WRITE) ? 1 : 0;
> +#ifdef __LITTLE_ENDIAN
> +       dma_cfg.s.endian = 1;
> +#endif
> +       dma_cfg.s.size = (sg_dma_len(&data->sg[0]) / 8) - 1;
> +
> +       addr = sg_dma_address(&data->sg[0]);
> +       dma_cfg.s.adr = addr;
> +       writeq(dma_cfg.val, host->dma_base + MIO_EMM_DMA_CFG);
> +
> +       pr_debug("[%s] sg_dma_len: %u  total sg_elem: %d\n",
> +                (dma_cfg.s.rw) ? "W" : "R", sg_dma_len(&data->sg[0]), count);
> +       return addr;
> +}
> +
> +static u64 prepare_dma(struct cvm_mmc_host *host, struct mmc_data *data)
> +{
> +       return prepare_dma_single(host, data);
> +}
> +
> +static void prepare_ext_dma(struct mmc_host *mmc, struct mmc_request *mrq,
> +                           union mio_emm_dma *emm_dma)
> +{
> +       struct cvm_mmc_slot *slot = mmc_priv(mmc);
> +
> +       /*
> +        * Our MMC host hardware does not issue single commands,
> +        * because that would require the driver and the MMC core
> +        * to do work to determine the proper sequence of commands.

I don't get this. The allowed sequence of the commands is determined
by the SD/(e)MMC/SDIO spec and much of this knowledge is the
responsibility of the mmc core.

> +        * Instead, our hardware is superior to most other MMC bus

No need to brag about your HW. Let's just describe how it works instead.

> +        * hosts. The sequence of MMC commands required to execute
> +        * a transfer are issued automatically by the bus hardware.

What does this really mean? Is this about HW support for better
dealing with data requests?

> +        *
> +        * - David Daney <ddaney@cavium.com>
> +        */
> +       emm_dma->val = 0;
> +       emm_dma->s.bus_id = slot->bus_id;
> +       emm_dma->s.dma_val = 1;
> +       emm_dma->s.sector = (mrq->data->blksz == 512) ? 1 : 0;
> +       emm_dma->s.rw = (mrq->data->flags & MMC_DATA_WRITE) ? 1 : 0;
> +       emm_dma->s.block_cnt = mrq->data->blocks;
> +       emm_dma->s.card_addr = mrq->cmd->arg;
> +       if (mmc_card_mmc(mmc->card) || (mmc_card_sd(mmc->card) &&
> +           (mmc->card->scr.cmds & SD_SCR_CMD23_SUPPORT)))
> +               emm_dma->s.multi = 1;
> +
> +       pr_debug("[%s] blocks: %u  multi: %d\n", (emm_dma->s.rw) ? "W" : "R",
> +                mrq->data->blocks, emm_dma->s.multi);
> +}
> +

[...]

> +
> +static void cvm_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
> +{
> +       struct cvm_mmc_slot *slot = mmc_priv(mmc);
> +       struct cvm_mmc_host *host = slot->host;
> +       int clk_period, power_class = 10, bus_width = 0;
> +       union mio_emm_switch emm_switch;
> +       u64 clock;
> +
> +       host->acquire_bus(host);
> +       cvm_mmc_switch_to(slot);
> +
> +       /* Set the power state */
> +       switch (ios->power_mode) {
> +       case MMC_POWER_ON:
> +               break;
> +
> +       case MMC_POWER_OFF:
> +               cvm_mmc_reset_bus(slot);
> +
> +               if (host->global_pwr_gpiod)
> +                       gpiod_set_value_cansleep(host->global_pwr_gpiod, 0);
> +               else
> +                       mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
> +               break;
> +
> +       case MMC_POWER_UP:
> +               if (host->global_pwr_gpiod)
> +                       gpiod_set_value_cansleep(host->global_pwr_gpiod, 1);
> +               else
> +                       mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd);
> +               break;
> +       }
> +
> +       /* Set bus width */
> +       switch (ios->bus_width) {
> +       case MMC_BUS_WIDTH_8:
> +               bus_width = 2;
> +               break;
> +       case MMC_BUS_WIDTH_4:
> +               bus_width = 1;
> +               break;
> +       case MMC_BUS_WIDTH_1:
> +               bus_width = 0;
> +               break;
> +       }
> +
> +       slot->bus_width = bus_width;
> +
> +       if (!ios->clock)

There are cases when the core change the clock rate to 0, and then it
expects the mmc host to gate the clock. It probably a good idea for
you to do that as well.

> +               goto out;
> +
> +       /* Change the clock frequency. */
> +       clock = ios->clock;
> +       if (clock > 52000000)
> +               clock = 52000000;
> +       slot->clock = clock;
> +       clk_period = (host->sys_freq + clock - 1) / (2 * clock);
> +
> +       emm_switch.val = 0;
> +       emm_switch.s.hs_timing = (ios->timing == MMC_TIMING_MMC_HS);
> +       emm_switch.s.bus_width = bus_width;
> +       emm_switch.s.power_class = power_class;
> +       emm_switch.s.clk_hi = clk_period;
> +       emm_switch.s.clk_lo = clk_period;
> +       emm_switch.s.bus_id = slot->bus_id;
> +
> +       if (!switch_val_changed(slot, emm_switch.val))
> +               goto out;
> +
> +       set_wdog(slot, 0);
> +       do_switch(host, emm_switch.val);
> +       slot->cached_switch = emm_switch.val;
> +out:
> +       host->release_bus(host);
> +}

[...]

> +
> +static int set_bus_width(struct device *dev, struct cvm_mmc_slot *slot, u32 id)
> +{
> +       u32 bus_width;
> +       int ret;
> +
> +       /*
> +        * The "cavium,bus-max-width" property is DEPRECATED and should
> +        * not be used. We handle it here to support older firmware.
> +        * Going forward, the standard "bus-width" property is used
> +        * instead of the Cavium-specific property.
> +        */
> +       if (!(slot->mmc->caps & (MMC_CAP_8_BIT_DATA | MMC_CAP_4_BIT_DATA))) {
> +               /* Try legacy "cavium,bus-max-width" property. */
> +               ret = of_property_read_u32(dev->of_node, "cavium,bus-max-width",
> +                                          &bus_width);
> +               if (ret) {
> +                       /* No bus width specified, use default. */
> +                       bus_width = 8;
> +                       dev_info(dev, "Default width 8 used for slot %u\n", id);
> +               }
> +       } else {
> +               /* Hosts capable of 8-bit transfers can also do 4 bits */
> +               bus_width = (slot->mmc->caps & MMC_CAP_8_BIT_DATA) ? 8 : 4;
> +       }

This looks a bit unnessarry complex.

I would instead suggest the following order of how to perform the OF
parsing. Bindings that get parsed later, overrides the earlier.

1. Parse deprecated bindings.
2. Parse cavium specific bindings.
3. Parse common mmc bindings.
4. Check some caps, to make sure those have valid values as to cover
cases when the OF parsing didn't find values.

The same comment applies for the other OF parsing functions below.

> +
> +       switch (bus_width) {
> +       case 8:
> +               slot->bus_width = (MMC_BUS_WIDTH_8 - 1);
> +               slot->mmc->caps = MMC_CAP_8_BIT_DATA | MMC_CAP_4_BIT_DATA;
> +               break;
> +       case 4:
> +               slot->bus_width = (MMC_BUS_WIDTH_4 - 1);
> +               slot->mmc->caps = MMC_CAP_4_BIT_DATA;
> +               break;
> +       case 1:
> +               slot->bus_width = MMC_BUS_WIDTH_1;
> +               break;
> +       default:
> +               dev_err(dev, "Invalid bus width for slot %u\n", id);
> +               return -EINVAL;
> +       }
> +       return 0;
> +}
> +
> +static void set_frequency(struct device *dev, struct mmc_host *mmc, u32 id)
> +{
> +       int ret;
> +
> +       /*
> +        * The "spi-max-frequency" property is DEPRECATED and should
> +        * not be used. We handle it here to support older firmware.
> +        * Going forward, the standard "max-frequency" property is
> +        * used instead of the Cavium-specific property.
> +        */
> +       if (mmc->f_max == 0) {
> +               /* Try legacy "spi-max-frequency" property. */
> +               ret = of_property_read_u32(dev->of_node, "spi-max-frequency",
> +                                          &mmc->f_max);
> +               if (ret) {
> +                       /* No frequency properties found, use default. */
> +                       mmc->f_max = 52000000;
> +                       dev_info(dev, "Default %u frequency used for slot %u\n",
> +                                mmc->f_max, id);
> +               }
> +       } else if (mmc->f_max > 52000000)
> +               mmc->f_max = 52000000;
> +
> +       /* Set minimum frequency */
> +       mmc->f_min = 400000;
> +}
> +
> +static int set_voltage(struct device *dev, struct mmc_host *mmc,
> +                      struct cvm_mmc_host *host)
> +{
> +       int ret;
> +
> +       /*
> +        * Legacy platform doesn't support regulator but enables power gpio
> +        * directly during platform probe.
> +        */
> +       if (host->global_pwr_gpiod)
> +               /* Get a sane OCR mask for other parts of the MMC subsytem. */
> +               return mmc_of_parse_voltage(dev->of_node, &mmc->ocr_avail);

Does really the legacy platforms use the mmc voltage range DT bindings!?

I would rather see that you assign a default value to mmc->ocr_avail,
than using this binding.

> +
> +       mmc->supply.vmmc = devm_regulator_get(dev, "vmmc");
> +       if (IS_ERR(mmc->supply.vmmc)) {
> +               ret = PTR_ERR(mmc->supply.vmmc);
> +       } else {
> +               ret = mmc_regulator_get_ocrmask(mmc->supply.vmmc);
> +               if (ret > 0) {
> +                       mmc->ocr_avail = ret;
> +                       ret = 0;
> +               }
> +       }

This if-else-if is a bit messy.

Why not just return when you get an error instead. That should simply the code.

Maybe you can have look and try to clean up this in the hole file
where you think it would make an improvment.

> +       return ret;
> +}
> +
> +int cvm_mmc_slot_probe(struct device *dev, struct cvm_mmc_host *host)

To reflect that OF is needed, perhaps rename function to
cvm_mmc_of_slot_probe().

> +{
> +       struct device_node *node = dev->of_node;
> +       u32 id, cmd_skew, dat_skew;
> +       struct cvm_mmc_slot *slot;
> +       struct mmc_host *mmc;
> +       u64 clock_period;
> +       int ret;
> +
> +       ret = of_property_read_u32(node, "reg", &id);
> +       if (ret) {
> +               dev_err(dev, "Missing or invalid reg property on %s\n",
> +                       of_node_full_name(node));
> +               return ret;
> +       }
> +
> +       if (id >= CAVIUM_MAX_MMC || host->slot[id]) {
> +               dev_err(dev, "Invalid reg property on %s\n",
> +                       of_node_full_name(node));
> +               return -EINVAL;
> +       }
> +
> +       mmc = mmc_alloc_host(sizeof(struct cvm_mmc_slot), dev);
> +       if (!mmc)
> +               return -ENOMEM;
> +
> +       slot = mmc_priv(mmc);
> +       slot->mmc = mmc;
> +       slot->host = host;
> +
> +       ret = mmc_of_parse(mmc);
> +       if (ret)
> +               goto error;
> +
> +       ret = set_bus_width(dev, slot, id);
> +       if (ret)
> +               goto error;
> +
> +       set_frequency(dev, mmc, id);
> +
> +       /* Octeon-specific DT properties. */
> +       ret = of_property_read_u32(node, "cavium,cmd-clk-skew", &cmd_skew);
> +       if (ret)
> +               cmd_skew = 0;
> +       ret = of_property_read_u32(node, "cavium,dat-clk-skew", &dat_skew);
> +       if (ret)
> +               dat_skew = 0;
> +
> +       ret = set_voltage(dev, mmc, host);
> +       if (ret < 0)
> +               goto error;

The functions set_bus_width(), set_freqeuncy(), set_voltage() all
performs OF parsing and there are some parsing also being done above.

I would suggest you bundle all OF parsing into one function, perhaps
name it "cvm_mmc_of_parse()" or similar. That should make the code a
lot cleaner.

> +
> +       /* Set up host parameters */
> +       mmc->ops = &cvm_mmc_ops;
> +
> +       mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
> +                    MMC_CAP_ERASE | MMC_CAP_CMD23 | MMC_CAP_POWER_OFF_CARD;
> +
> +       mmc->max_segs = 1;
> +
> +       /* DMA size field can address up to 8 MB */
> +       mmc->max_seg_size = 8 * 1024 * 1024;
> +       mmc->max_req_size = mmc->max_seg_size;
> +       /* External DMA is in 512 byte blocks */
> +       mmc->max_blk_size = 512;
> +       /* DMA block count field is 15 bits */
> +       mmc->max_blk_count = 32767;
> +
> +       slot->clock = mmc->f_min;
> +       slot->sclock = host->sys_freq;
> +
> +       /* Period in picoseconds. */
> +       clock_period = 1000000000000ull / slot->sclock;
> +       slot->cmd_cnt = (cmd_skew + clock_period / 2) / clock_period;
> +       slot->dat_cnt = (dat_skew + clock_period / 2) / clock_period;
> +
> +       slot->bus_id = id;
> +       slot->cached_rca = 1;
> +
> +       host->acquire_bus(host);
> +       host->slot[id] = slot;
> +       cvm_mmc_switch_to(slot);
> +       cvm_mmc_init_lowlevel(slot);
> +       host->release_bus(host);
> +
> +       ret = mmc_add_host(mmc);
> +       if (ret) {
> +               dev_err(dev, "mmc_add_host() returned %d\n", ret);
> +               goto error;
> +       }
> +
> +       return 0;
> +
> +error:
> +       slot->host->slot[id] = NULL;
> +       mmc_free_host(slot->mmc);
> +       return ret;
> +}
> +
> +int cvm_mmc_slot_remove(struct cvm_mmc_slot *slot)
> +{
> +       mmc_remove_host(slot->mmc);
> +       slot->host->slot[slot->bus_id] = NULL;
> +       mmc_free_host(slot->mmc);
> +       return 0;
> +}
> diff --git a/drivers/mmc/host/cavium-mmc.h b/drivers/mmc/host/cavium-mmc.h
> new file mode 100644
> index 0000000..27fb02b
> --- /dev/null
> +++ b/drivers/mmc/host/cavium-mmc.h
> @@ -0,0 +1,303 @@
> +/*
> + * Driver for MMC and SSD cards for Cavium OCTEON and ThunderX 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/clk.h>
> +#include <linux/io.h>
> +#include <linux/mmc/host.h>
> +#include <linux/of.h>
> +#include <linux/scatterlist.h>
> +#include <linux/semaphore.h>
> +
> +#define CAVIUM_MAX_MMC         4
> +
> +struct cvm_mmc_host {
> +       struct device *dev;
> +       void __iomem *base;
> +       void __iomem *dma_base;
> +       u64 emm_cfg;
> +       int last_slot;
> +       struct clk *clk;
> +       int sys_freq;
> +
> +       struct mmc_request *current_req;
> +       struct sg_mapping_iter smi;
> +       bool dma_active;
> +
> +       struct gpio_desc *global_pwr_gpiod;
> +
> +       struct cvm_mmc_slot *slot[CAVIUM_MAX_MMC];
> +
> +       void (*acquire_bus)(struct cvm_mmc_host *);
> +       void (*release_bus)(struct cvm_mmc_host *);
> +       void (*int_enable)(struct cvm_mmc_host *, u64);
> +};
> +
> +struct cvm_mmc_slot {
> +       struct mmc_host *mmc;           /* slot-level mmc_core object */
> +       struct cvm_mmc_host *host;      /* common hw for all slots */
> +
> +       u64 clock;
> +       unsigned int sclock;
> +
> +       u64 cached_switch;
> +       u64 cached_rca;
> +
> +       unsigned int cmd_cnt;           /* sample delay */
> +       unsigned int dat_cnt;           /* sample delay */
> +
> +       int bus_width;
> +       int bus_id;
> +};
> +
> +struct cvm_mmc_cr_type {
> +       u8 ctype;
> +       u8 rtype;
> +};
> +
> +struct cvm_mmc_cr_mods {
> +       u8 ctype_xor;
> +       u8 rtype_xor;
> +};
> +
> +/* Bitfield definitions */
> +
> +union mio_emm_cmd {
> +       u64 val;
> +       struct mio_emm_cmd_s {
> +#ifdef __BIG_ENDIAN_BITFIELD

Huh. Sorry, but this is a big nack from me.

This isn't the common method for how we deal with endian issues in the
kernel. Please remove all use of the union types here and below. The
follow common patterns for how we deal with endian issues.

> +               u64 :2;
> +               u64 bus_id:2;
> +               u64 cmd_val:1;
> +               u64 :3;
> +               u64 dbuf:1;
> +               u64 offset:6;
> +               u64 :6;
> +               u64 ctype_xor:2;
> +               u64 rtype_xor:3;
> +               u64 cmd_idx:6;
> +               u64 arg:32;
> +#else
> +               u64 arg:32;
> +               u64 cmd_idx:6;
> +               u64 rtype_xor:3;
> +               u64 ctype_xor:2;
> +               u64 :6;
> +               u64 offset:6;
> +               u64 dbuf:1;
> +               u64 :3;
> +               u64 cmd_val:1;
> +               u64 bus_id:2;
> +               u64 :2;
> +#endif
> +       } s;
> +};
> +
> +union mio_emm_dma {
> +       u64 val;
> +       struct mio_emm_dma_s {
> +#ifdef __BIG_ENDIAN_BITFIELD
> +               u64 :2;
> +               u64 bus_id:2;
> +               u64 dma_val:1;
> +               u64 sector:1;
> +               u64 dat_null:1;
> +               u64 thres:6;
> +               u64 rel_wr:1;
> +               u64 rw:1;
> +               u64 multi:1;
> +               u64 block_cnt:16;
> +               u64 card_addr:32;
> +#else
> +               u64 card_addr:32;
> +               u64 block_cnt:16;
> +               u64 multi:1;
> +               u64 rw:1;
> +               u64 rel_wr:1;
> +               u64 thres:6;
> +               u64 dat_null:1;
> +               u64 sector:1;
> +               u64 dma_val:1;
> +               u64 bus_id:2;
> +               u64 :2;
> +#endif
> +       } s;
> +};
> +
> +union mio_emm_dma_cfg {
> +       u64 val;
> +       struct mio_emm_dma_cfg_s {
> +#ifdef __BIG_ENDIAN_BITFIELD
> +               u64 en:1;
> +               u64 rw:1;
> +               u64 clr:1;
> +               u64 :1;
> +               u64 swap32:1;
> +               u64 swap16:1;
> +               u64 swap8:1;
> +               u64 endian:1;
> +               u64 size:20;
> +               u64 adr:36;
> +#else
> +               u64 adr:36;
> +               u64 size:20;
> +               u64 endian:1;
> +               u64 swap8:1;
> +               u64 swap16:1;
> +               u64 swap32:1;
> +               u64 :1;
> +               u64 clr:1;
> +               u64 rw:1;
> +               u64 en:1;
> +#endif
> +       } s;
> +};
> +
> +union mio_emm_int {
> +       u64 val;
> +       struct mio_emm_int_s {
> +#ifdef __BIG_ENDIAN_BITFIELD
> +               u64 :57;
> +               u64 switch_err:1;
> +               u64 switch_done:1;
> +               u64 dma_err:1;
> +               u64 cmd_err:1;
> +               u64 dma_done:1;
> +               u64 cmd_done:1;
> +               u64 buf_done:1;
> +#else
> +               u64 buf_done:1;
> +               u64 cmd_done:1;
> +               u64 dma_done:1;
> +               u64 cmd_err:1;
> +               u64 dma_err:1;
> +               u64 switch_done:1;
> +               u64 switch_err:1;
> +               u64 :57;
> +#endif
> +       } s;
> +};
> +
> +union mio_emm_rsp_sts {
> +       u64 val;
> +       struct mio_emm_rsp_sts_s {
> +#ifdef __BIG_ENDIAN_BITFIELD
> +               u64 :2;
> +               u64 bus_id:2;
> +               u64 cmd_val:1;
> +               u64 switch_val:1;
> +               u64 dma_val:1;
> +               u64 dma_pend:1;
> +               u64 :27;
> +               u64 dbuf_err:1;
> +               u64 :4;
> +               u64 dbuf:1;
> +               u64 blk_timeout:1;
> +               u64 blk_crc_err:1;
> +               u64 rsp_busybit:1;
> +               u64 stp_timeout:1;
> +               u64 stp_crc_err:1;
> +               u64 stp_bad_sts:1;
> +               u64 stp_val:1;
> +               u64 rsp_timeout:1;
> +               u64 rsp_crc_err:1;
> +               u64 rsp_bad_sts:1;
> +               u64 rsp_val:1;
> +               u64 rsp_type:3;
> +               u64 cmd_type:2;
> +               u64 cmd_idx:6;
> +               u64 cmd_done:1;
> +#else
> +               u64 cmd_done:1;
> +               u64 cmd_idx:6;
> +               u64 cmd_type:2;
> +               u64 rsp_type:3;
> +               u64 rsp_val:1;
> +               u64 rsp_bad_sts:1;
> +               u64 rsp_crc_err:1;
> +               u64 rsp_timeout:1;
> +               u64 stp_val:1;
> +               u64 stp_bad_sts:1;
> +               u64 stp_crc_err:1;
> +               u64 stp_timeout:1;
> +               u64 rsp_busybit:1;
> +               u64 blk_crc_err:1;
> +               u64 blk_timeout:1;
> +               u64 dbuf:1;
> +               u64 :4;
> +               u64 dbuf_err:1;
> +               u64 :27;
> +               u64 dma_pend:1;
> +               u64 dma_val:1;
> +               u64 switch_val:1;
> +               u64 cmd_val:1;
> +               u64 bus_id:2;
> +               u64 :2;
> +#endif
> +       } s;
> +};
> +
> +union mio_emm_sample {
> +       u64 val;
> +       struct mio_emm_sample_s {
> +#ifdef __BIG_ENDIAN_BITFIELD
> +               u64 :38;
> +               u64 cmd_cnt:10;
> +               u64 :6;
> +               u64 dat_cnt:10;
> +#else
> +               u64 dat_cnt:10;
> +               u64 :6;
> +               u64 cmd_cnt:10;
> +               u64 :38;
> +#endif
> +       } s;
> +};
> +
> +union mio_emm_switch {
> +       u64 val;
> +       struct mio_emm_switch_s {
> +#ifdef __BIG_ENDIAN_BITFIELD
> +               u64 :2;
> +               u64 bus_id:2;
> +               u64 switch_exe:1;
> +               u64 switch_err0:1;
> +               u64 switch_err1:1;
> +               u64 switch_err2:1;
> +               u64 :7;
> +               u64 hs_timing:1;
> +               u64 :5;
> +               u64 bus_width:3;
> +               u64 :4;
> +               u64 power_class:4;
> +               u64 clk_hi:16;
> +               u64 clk_lo:16;
> +#else
> +               u64 clk_lo:16;
> +               u64 clk_hi:16;
> +               u64 power_class:4;
> +               u64 :4;
> +               u64 bus_width:3;
> +               u64 :5;
> +               u64 hs_timing:1;
> +               u64 :7;
> +               u64 switch_err2:1;
> +               u64 switch_err1:1;
> +               u64 switch_err0:1;
> +               u64 switch_exe:1;
> +               u64 bus_id:2;
> +               u64 :2;
> +#endif
> +       } s;
> +};
> +
> +/* Protoypes */
> +irqreturn_t cvm_mmc_interrupt(int irq, void *dev_id);
> +int cvm_mmc_slot_probe(struct device *dev, struct cvm_mmc_host *host);
> +int cvm_mmc_slot_remove(struct cvm_mmc_slot *slot);

Why do you need this here? Are those intended as library functions for
the different cavium variant drivers?

> +extern const struct mmc_host_ops cvm_mmc_ops;

Why do you need this?

Kind regards
Uffe

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v11 2/9] mmc: cavium: Add core MMC driver for Cavium SOCs
  2017-03-03 11:47   ` Ulf Hansson
@ 2017-03-03 18:39     ` David Daney
  2017-03-07 10:49     ` Jan Glauber
  1 sibling, 0 replies; 24+ messages in thread
From: David Daney @ 2017-03-03 18:39 UTC (permalink / raw)
  To: Ulf Hansson, Jan Glauber
  Cc: linux-mmc, linux-kernel, Steven J . Hill, David Daney

On 03/03/2017 03:47 AM, Ulf Hansson wrote:
> On 6 February 2017 at 14:39, Jan Glauber <jglauber@cavium.com> wrote:
[...]
>> +}
>> +
>> +static void prepare_ext_dma(struct mmc_host *mmc, struct mmc_request *mrq,
>> +                           union mio_emm_dma *emm_dma)
>> +{
>> +       struct cvm_mmc_slot *slot = mmc_priv(mmc);
>> +
>> +       /*
>> +        * Our MMC host hardware does not issue single commands,
>> +        * because that would require the driver and the MMC core
>> +        * to do work to determine the proper sequence of commands.
>
> I don't get this. The allowed sequence of the commands is determined
> by the SD/(e)MMC/SDIO spec and much of this knowledge is the
> responsibility of the mmc core.
>
>> +        * Instead, our hardware is superior to most other MMC bus
>
> No need to brag about your HW. Let's just describe how it works instead.
>
>> +        * hosts. The sequence of MMC commands required to execute
>> +        * a transfer are issued automatically by the bus hardware.
>
> What does this really mean? Is this about HW support for better
> dealing with data requests?


The entire comment should be removed.   It is laced with sarcasm that is 
very difficult for people not intimately familiar with the discussions 
to detect and decipher.

The real story is that the Cavium MMC hardware was designed based on a 
defective premise.  Hardwired in to the core of the MMC bus interface 
hardware is a multi-command synthesizer/sequencer that is hard coded to 
work with a limited subset of MMC-only command sequences.  This allows 
you to read data from the first few MB of an MMC device with only a 
handful of assembly language instructions contained in the on-die 
mask-ROM of the SoC.

When it comes to actually using the MMC/SD bus interface from within the 
Linux MMC framework, we have to apply a transform to the command 
sequences supplied by the Linux MMC core so that the command sequence 
synthesized by Cavium MMC hardware matches as closely as possible what 
was actually requested.  For many command sequences, the match between 
what is synthesized by the hardware and what was requested is not exact.

>
>> +        *
>> +        * - David Daney <ddaney@cavium.com>
>> +        */
>> +       emm_dma->val = 0;
>> +       emm_dma->s.bus_id = slot->bus_id;
>> +       emm_dma->s.dma_val = 1;
>> +       emm_dma->s.sector = (mrq->data->blksz == 512) ? 1 : 0;
>> +       emm_dma->s.rw = (mrq->data->flags & MMC_DATA_WRITE) ? 1 : 0;
>> +       emm_dma->s.block_cnt = mrq->data->blocks;
>> +       emm_dma->s.card_addr = mrq->cmd->arg;
>> +       if (mmc_card_mmc(mmc->card) || (mmc_card_sd(mmc->card) &&
>> +           (mmc->card->scr.cmds & SD_SCR_CMD23_SUPPORT)))
>> +               emm_dma->s.multi = 1;

Here is a prefect example.

If a multi-block transfer was requested, the hardware command 
synthesizer uses the "multi" bit to determine if it should generate a 
command sequence for a single multi-block transfer, or multiple 
single-block transfers.

Probably the MMC core would never request a multi-block transfer from a 
device that doesn't support it, but we check here just-in-case.



>> +
>> +       pr_debug("[%s] blocks: %u  multi: %d\n", (emm_dma->s.rw) ? "W" : "R",
>> +                mrq->data->blocks, emm_dma->s.multi);
>> +}
>> +

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v11 1/9] dt-bindings: mmc: Add Cavium SOCs MMC bindings
  2017-03-03 11:47   ` Ulf Hansson
@ 2017-03-06 11:09     ` Jan Glauber
  0 siblings, 0 replies; 24+ messages in thread
From: Jan Glauber @ 2017-03-06 11:09 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc, linux-kernel, David Daney, Steven J . Hill,
	Rob Herring, Mark Rutland, devicetree, David Daney

On Fri, Mar 03, 2017 at 12:47:06PM +0100, Ulf Hansson wrote:
> On 6 February 2017 at 14:39, Jan Glauber <jglauber@cavium.com> wrote:
> > Add description of Cavium Octeon and ThunderX SOC device tree bindings.
> >
> > CC: Ulf Hansson <ulf.hansson@linaro.org>
> > CC: Rob Herring <robh+dt@kernel.org>
> > CC: Mark Rutland <mark.rutland@arm.com>
> > CC: devicetree@vger.kernel.org
> >
> > Signed-off-by: Jan Glauber <jglauber@cavium.com>
> > Signed-off-by: David Daney <david.daney@cavium.com>
> > Signed-off-by: Steven J. Hill <steven.hill@cavium.com>
> > ---
> >  .../devicetree/bindings/mmc/cavium-mmc.txt         | 60 ++++++++++++++++++++++
> >  1 file changed, 60 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/mmc/cavium-mmc.txt
> >
> > diff --git a/Documentation/devicetree/bindings/mmc/cavium-mmc.txt b/Documentation/devicetree/bindings/mmc/cavium-mmc.txt
> > new file mode 100644
> > index 0000000..b79e356
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/mmc/cavium-mmc.txt
> > @@ -0,0 +1,60 @@
> > +* Cavium Octeon & ThunderX MMC controller
> > +
> > +The highspeed MMC host controller on Caviums SoCs provides an interface
> > +for MMC and SD types of memory cards.
> > +
> > +Supported maximum speeds are the ones of the eMMC standard 4.41 as well
> > +as the speed of SD standard 4.0. Only 3.3 Volt is supported.
> > +
> > +Required properties:
> > + - compatible : should be one of:
> > +   cavium,octeon-6130-mmc
> > +   cavium,octeon-6130-mmc-slot
> > +   cavium,octeon-7890-mmc
> > +   cavium,octeon-7890-mmc-slot
> > +   cavium,thunder-8190-mmc
> > +   cavium,thunder-8190-mmc-slot
> > +   cavium,thunder-8390-mmc
> > +   cavium,thunder-8390-mmc-slot
> > + - reg : mmc controller base registers
> > + - clocks : phandle
> > +
> > +Optional properties:
> > + - for cd, bus-width and additional generic mmc parameters
> > +   please refer to mmc.txt within this directory
> > + - cavium,cmd-clk-skew : number of coprocessor clocks before sampling command
> > + - cavium,dat-clk-skew : number of coprocessor clocks before sampling data
> > +
> > +Deprecated properties:
> > +- spi-max-frequency : use max-frequency instead
> > +- cavium,bus-max-width : use bus-width instead
> > +
> > +Examples:
> > +       mmc_1_4: mmc@1,4 {
> > +               compatible = "cavium,thunder-8390-mmc";
> > +               reg = <0x0c00 0 0 0 0>; /* DEVFN = 0x0c (1:4) */
> > +               #address-cells = <1>;
> > +               #size-cells = <0>;
> > +               clocks = <&sclk>;
> > +
> > +               mmc-slot@0 {
> > +                       compatible = "cavium,thunder-8390-mmc-slot";
> > +                       reg = <0>;
> > +                       voltage-ranges = <3300 3300>;
> > +                       vmmc-supply = <&mmc_supply_3v3>;
> 
> The vmmc supply as a regulator provides you with the voltage range,
> thus you don't need the "voltage-ranges" here. Please remove this.

OK, I'll drop these.

thanks,
Jan

> > +                       max-frequency = <42000000>;
> > +                       bus-width = <4>;
> > +                       cap-sd-highspeed;
> > +               };
> > +
> > +               mmc-slot@1 {
> > +                       compatible = "cavium,thunder-8390-mmc-slot";
> > +                       reg = <1>;
> > +                       voltage-ranges = <3300 3300>;
> > +                       vmmc-supply = <&mmc_supply_3v3>;
> 
> Ditto.
> 
> > +                       max-frequency = <42000000>;
> > +                       bus-width = <8>;
> > +                       cap-mmc-highspeed;
> > +                       non-removable;
> > +               };
> > +       };
> > --
> > 2.9.0.rc0.21.g7777322
> >
> 
> Kind regards
> Uffe

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v11 2/9] mmc: cavium: Add core MMC driver for Cavium SOCs
  2017-03-03 11:47   ` Ulf Hansson
  2017-03-03 18:39     ` David Daney
@ 2017-03-07 10:49     ` Jan Glauber
  2017-03-08  9:45       ` Ulf Hansson
  1 sibling, 1 reply; 24+ messages in thread
From: Jan Glauber @ 2017-03-07 10:49 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc, linux-kernel, David Daney, Steven J . Hill, David Daney

On Fri, Mar 03, 2017 at 12:47:14PM +0100, Ulf Hansson wrote:
> On 6 February 2017 at 14:39, Jan Glauber <jglauber@cavium.com> wrote:
> > This core driver will be used by a MIPS platform driver
> > or by an ARM64 PCI driver. The core driver implements the
> > mmc_host_ops and slot probe & remove functions.
> > Callbacks are provided to allow platform specific interrupt
> > enable and bus locking.
> >
> > The host controller supports:
> > - up to 4 slots that can contain sd-cards or eMMC chips
> > - 1, 4 and 8 bit bus width
> > - SDR and DDR
> > - transfers up to 52 Mhz (might be less when multiple slots are used)
> > - DMA read/write
> > - multi-block read/write (but not stream mode)
> >
> > Voltage is limited to 3.3v and shared for all slots.
> 
> What voltage? The I/O voltage or the voltage for the card?
> 
> VMMC or VMMCQ?

>From my understanding both, VMMC and VMMCQ are fixed at 3.3v.

> >
> > A global lock for all MMC devices is required because the host
> > controller is shared.
> >
> > Signed-off-by: Jan Glauber <jglauber@cavium.com>
> > Signed-off-by: David Daney <david.daney@cavium.com>
> > Signed-off-by: Steven J. Hill <steven.hill@cavium.com>
> > ---
> >  drivers/mmc/host/cavium-mmc.c | 1029 +++++++++++++++++++++++++++++++++++++++++
> >  drivers/mmc/host/cavium-mmc.h |  303 ++++++++++++
> >  2 files changed, 1332 insertions(+)
> >  create mode 100644 drivers/mmc/host/cavium-mmc.c
> >  create mode 100644 drivers/mmc/host/cavium-mmc.h
> >
> > diff --git a/drivers/mmc/host/cavium-mmc.c b/drivers/mmc/host/cavium-mmc.c
> > new file mode 100644
> > index 0000000..40aee08
> > --- /dev/null
> > +++ b/drivers/mmc/host/cavium-mmc.c
> 
> [...]
> 
> > +
> > +static bool bad_status(union mio_emm_rsp_sts *rsp_sts)
> > +{
> > +       if (rsp_sts->s.rsp_bad_sts || rsp_sts->s.rsp_crc_err ||
> > +           rsp_sts->s.rsp_timeout || rsp_sts->s.blk_crc_err ||
> > +           rsp_sts->s.blk_timeout || rsp_sts->s.dbuf_err)
> > +               return true;
> > +
> > +       return false;
> > +}
> > +
> > +/* Try to clean up failed DMA. */
> > +static void cleanup_dma(struct cvm_mmc_host *host,
> > +                       union mio_emm_rsp_sts *rsp_sts)
> > +{
> > +       union mio_emm_dma emm_dma;
> > +
> > +       emm_dma.val = readq(host->base + MIO_EMM_DMA);
> > +       emm_dma.s.dma_val = 1;
> > +       emm_dma.s.dat_null = 1;
> > +       emm_dma.s.bus_id = rsp_sts->s.bus_id;
> > +       writeq(emm_dma.val, host->base + MIO_EMM_DMA);
> > +}
> > +
> > +irqreturn_t cvm_mmc_interrupt(int irq, void *dev_id)
> > +{
> > +       struct cvm_mmc_host *host = dev_id;
> > +       union mio_emm_rsp_sts rsp_sts;
> > +       union mio_emm_int emm_int;
> > +       struct mmc_request *req;
> > +       bool host_done;
> > +
> > +       /* Clear interrupt bits (write 1 clears ). */
> > +       emm_int.val = readq(host->base + MIO_EMM_INT);
> > +       writeq(emm_int.val, host->base + MIO_EMM_INT);
> > +
> > +       if (emm_int.s.switch_err)
> > +               check_switch_errors(host);
> > +
> > +       req = host->current_req;
> > +       if (!req)
> > +               goto out;
> > +
> > +       rsp_sts.val = readq(host->base + MIO_EMM_RSP_STS);
> > +       /*
> > +        * dma_val set means DMA is still in progress. Don't touch
> > +        * the request and wait for the interrupt indicating that
> > +        * the DMA is finished.
> > +        */
> > +       if (rsp_sts.s.dma_val && host->dma_active)
> > +               goto out;
> > +
> > +       if (!host->dma_active && emm_int.s.buf_done && req->data) {
> > +               unsigned int type = (rsp_sts.val >> 7) & 3;
> > +
> > +               if (type == 1)
> > +                       do_read(host, req, rsp_sts.s.dbuf);
> > +               else if (type == 2)
> > +                       do_write(req);
> > +       }
> > +
> > +       host_done = emm_int.s.cmd_done || emm_int.s.dma_done ||
> > +                   emm_int.s.cmd_err || emm_int.s.dma_err;
> > +
> > +       if (!(host_done && req->done))
> > +               goto no_req_done;
> > +
> > +       if (bad_status(&rsp_sts))
> > +               req->cmd->error = -EILSEQ;
> 
> I don't think you should treat all errors as -EILSEQ. Please assign a
> proper error code, depending on the error.

Agreed, -ETIMEDOUT seems more appropriate for the timeouts. I'll go for
-EIO for the dbuf_err (buffer space missing). What should I use for the
CRC errors, -EILSEQ?

> > +       else
> > +               req->cmd->error = 0;
> > +
> > +       if (host->dma_active && req->data)
> > +               if (!finish_dma(host, req->data))
> > +                       goto no_req_done;
> > +
> > +       set_cmd_response(host, req, &rsp_sts);
> > +       if (emm_int.s.dma_err && rsp_sts.s.dma_pend)
> > +               cleanup_dma(host, &rsp_sts);
> > +
> > +       host->current_req = NULL;
> > +       req->done(req);
> > +
> > +no_req_done:
> > +       if (host_done)
> > +               host->release_bus(host);
> > +out:
> > +       return IRQ_RETVAL(emm_int.val != 0);
> > +}
> > +
> > +/*
> > + * Program DMA_CFG and if needed DMA_ADR.
> > + * Returns 0 on error, DMA address otherwise.
> > + */
> > +static u64 prepare_dma_single(struct cvm_mmc_host *host, struct mmc_data *data)
> > +{
> > +       union mio_emm_dma_cfg dma_cfg;
> > +       int count;
> > +       u64 addr;
> > +
> > +       count = dma_map_sg(host->dev, data->sg, data->sg_len,
> > +                          get_dma_dir(data));
> > +       if (!count)
> > +               return 0;
> > +
> > +       dma_cfg.val = 0;
> > +       dma_cfg.s.en = 1;
> > +       dma_cfg.s.rw = (data->flags & MMC_DATA_WRITE) ? 1 : 0;
> > +#ifdef __LITTLE_ENDIAN
> > +       dma_cfg.s.endian = 1;
> > +#endif
> > +       dma_cfg.s.size = (sg_dma_len(&data->sg[0]) / 8) - 1;
> > +
> > +       addr = sg_dma_address(&data->sg[0]);
> > +       dma_cfg.s.adr = addr;
> > +       writeq(dma_cfg.val, host->dma_base + MIO_EMM_DMA_CFG);
> > +
> > +       pr_debug("[%s] sg_dma_len: %u  total sg_elem: %d\n",
> > +                (dma_cfg.s.rw) ? "W" : "R", sg_dma_len(&data->sg[0]), count);
> > +       return addr;
> > +}
> > +
> > +static u64 prepare_dma(struct cvm_mmc_host *host, struct mmc_data *data)
> > +{
> > +       return prepare_dma_single(host, data);
> > +}
> > +
> > +static void prepare_ext_dma(struct mmc_host *mmc, struct mmc_request *mrq,
> > +                           union mio_emm_dma *emm_dma)
> > +{
> > +       struct cvm_mmc_slot *slot = mmc_priv(mmc);
> > +
> > +       /*
> > +        * Our MMC host hardware does not issue single commands,
> > +        * because that would require the driver and the MMC core
> > +        * to do work to determine the proper sequence of commands.
> 
> I don't get this. The allowed sequence of the commands is determined
> by the SD/(e)MMC/SDIO spec and much of this knowledge is the
> responsibility of the mmc core.
> 
> > +        * Instead, our hardware is superior to most other MMC bus
> 
> No need to brag about your HW. Let's just describe how it works instead.

I'll remove the comment.

> > +        * hosts. The sequence of MMC commands required to execute
> > +        * a transfer are issued automatically by the bus hardware.
> 
> What does this really mean? Is this about HW support for better
> dealing with data requests?

Did David's reponse answer your questions?

> > +        *
> > +        * - David Daney <ddaney@cavium.com>
> > +        */
> > +       emm_dma->val = 0;
> > +       emm_dma->s.bus_id = slot->bus_id;
> > +       emm_dma->s.dma_val = 1;
> > +       emm_dma->s.sector = (mrq->data->blksz == 512) ? 1 : 0;
> > +       emm_dma->s.rw = (mrq->data->flags & MMC_DATA_WRITE) ? 1 : 0;
> > +       emm_dma->s.block_cnt = mrq->data->blocks;
> > +       emm_dma->s.card_addr = mrq->cmd->arg;
> > +       if (mmc_card_mmc(mmc->card) || (mmc_card_sd(mmc->card) &&
> > +           (mmc->card->scr.cmds & SD_SCR_CMD23_SUPPORT)))
> > +               emm_dma->s.multi = 1;
> > +
> > +       pr_debug("[%s] blocks: %u  multi: %d\n", (emm_dma->s.rw) ? "W" : "R",
> > +                mrq->data->blocks, emm_dma->s.multi);
> > +}
> > +
> 
> [...]
> 
> > +
> > +static void cvm_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
> > +{
> > +       struct cvm_mmc_slot *slot = mmc_priv(mmc);
> > +       struct cvm_mmc_host *host = slot->host;
> > +       int clk_period, power_class = 10, bus_width = 0;
> > +       union mio_emm_switch emm_switch;
> > +       u64 clock;
> > +
> > +       host->acquire_bus(host);
> > +       cvm_mmc_switch_to(slot);
> > +
> > +       /* Set the power state */
> > +       switch (ios->power_mode) {
> > +       case MMC_POWER_ON:
> > +               break;
> > +
> > +       case MMC_POWER_OFF:
> > +               cvm_mmc_reset_bus(slot);
> > +
> > +               if (host->global_pwr_gpiod)
> > +                       gpiod_set_value_cansleep(host->global_pwr_gpiod, 0);
> > +               else
> > +                       mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
> > +               break;
> > +
> > +       case MMC_POWER_UP:
> > +               if (host->global_pwr_gpiod)
> > +                       gpiod_set_value_cansleep(host->global_pwr_gpiod, 1);
> > +               else
> > +                       mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd);
> > +               break;
> > +       }
> > +
> > +       /* Set bus width */
> > +       switch (ios->bus_width) {
> > +       case MMC_BUS_WIDTH_8:
> > +               bus_width = 2;
> > +               break;
> > +       case MMC_BUS_WIDTH_4:
> > +               bus_width = 1;
> > +               break;
> > +       case MMC_BUS_WIDTH_1:
> > +               bus_width = 0;
> > +               break;
> > +       }
> > +
> > +       slot->bus_width = bus_width;
> > +
> > +       if (!ios->clock)
> 
> There are cases when the core change the clock rate to 0, and then it
> expects the mmc host to gate the clock. It probably a good idea for
> you to do that as well.

OK, seems to work.

> > +               goto out;
> > +
> > +       /* Change the clock frequency. */
> > +       clock = ios->clock;
> > +       if (clock > 52000000)
> > +               clock = 52000000;
> > +       slot->clock = clock;
> > +       clk_period = (host->sys_freq + clock - 1) / (2 * clock);
> > +
> > +       emm_switch.val = 0;
> > +       emm_switch.s.hs_timing = (ios->timing == MMC_TIMING_MMC_HS);
> > +       emm_switch.s.bus_width = bus_width;
> > +       emm_switch.s.power_class = power_class;
> > +       emm_switch.s.clk_hi = clk_period;
> > +       emm_switch.s.clk_lo = clk_period;
> > +       emm_switch.s.bus_id = slot->bus_id;
> > +
> > +       if (!switch_val_changed(slot, emm_switch.val))
> > +               goto out;
> > +
> > +       set_wdog(slot, 0);
> > +       do_switch(host, emm_switch.val);
> > +       slot->cached_switch = emm_switch.val;
> > +out:
> > +       host->release_bus(host);
> > +}
> 
> [...]
> 
> > +
> > +static int set_bus_width(struct device *dev, struct cvm_mmc_slot *slot, u32 id)
> > +{
> > +       u32 bus_width;
> > +       int ret;
> > +
> > +       /*
> > +        * The "cavium,bus-max-width" property is DEPRECATED and should
> > +        * not be used. We handle it here to support older firmware.
> > +        * Going forward, the standard "bus-width" property is used
> > +        * instead of the Cavium-specific property.
> > +        */
> > +       if (!(slot->mmc->caps & (MMC_CAP_8_BIT_DATA | MMC_CAP_4_BIT_DATA))) {
> > +               /* Try legacy "cavium,bus-max-width" property. */
> > +               ret = of_property_read_u32(dev->of_node, "cavium,bus-max-width",
> > +                                          &bus_width);
> > +               if (ret) {
> > +                       /* No bus width specified, use default. */
> > +                       bus_width = 8;
> > +                       dev_info(dev, "Default width 8 used for slot %u\n", id);
> > +               }
> > +       } else {
> > +               /* Hosts capable of 8-bit transfers can also do 4 bits */
> > +               bus_width = (slot->mmc->caps & MMC_CAP_8_BIT_DATA) ? 8 : 4;
> > +       }
> 
> This looks a bit unnessarry complex.
> 
> I would instead suggest the following order of how to perform the OF
> parsing. Bindings that get parsed later, overrides the earlier.
> 
> 1. Parse deprecated bindings.
> 2. Parse cavium specific bindings.
> 3. Parse common mmc bindings.
> 4. Check some caps, to make sure those have valid values as to cover
> cases when the OF parsing didn't find values.
> 
> The same comment applies for the other OF parsing functions below.

OK.

> > +
> > +       switch (bus_width) {
> > +       case 8:
> > +               slot->bus_width = (MMC_BUS_WIDTH_8 - 1);
> > +               slot->mmc->caps = MMC_CAP_8_BIT_DATA | MMC_CAP_4_BIT_DATA;
> > +               break;
> > +       case 4:
> > +               slot->bus_width = (MMC_BUS_WIDTH_4 - 1);
> > +               slot->mmc->caps = MMC_CAP_4_BIT_DATA;
> > +               break;
> > +       case 1:
> > +               slot->bus_width = MMC_BUS_WIDTH_1;
> > +               break;
> > +       default:
> > +               dev_err(dev, "Invalid bus width for slot %u\n", id);
> > +               return -EINVAL;
> > +       }
> > +       return 0;
> > +}
> > +
> > +static void set_frequency(struct device *dev, struct mmc_host *mmc, u32 id)
> > +{
> > +       int ret;
> > +
> > +       /*
> > +        * The "spi-max-frequency" property is DEPRECATED and should
> > +        * not be used. We handle it here to support older firmware.
> > +        * Going forward, the standard "max-frequency" property is
> > +        * used instead of the Cavium-specific property.
> > +        */
> > +       if (mmc->f_max == 0) {
> > +               /* Try legacy "spi-max-frequency" property. */
> > +               ret = of_property_read_u32(dev->of_node, "spi-max-frequency",
> > +                                          &mmc->f_max);
> > +               if (ret) {
> > +                       /* No frequency properties found, use default. */
> > +                       mmc->f_max = 52000000;
> > +                       dev_info(dev, "Default %u frequency used for slot %u\n",
> > +                                mmc->f_max, id);
> > +               }
> > +       } else if (mmc->f_max > 52000000)
> > +               mmc->f_max = 52000000;
> > +
> > +       /* Set minimum frequency */
> > +       mmc->f_min = 400000;
> > +}
> > +
> > +static int set_voltage(struct device *dev, struct mmc_host *mmc,
> > +                      struct cvm_mmc_host *host)
> > +{
> > +       int ret;
> > +
> > +       /*
> > +        * Legacy platform doesn't support regulator but enables power gpio
> > +        * directly during platform probe.
> > +        */
> > +       if (host->global_pwr_gpiod)
> > +               /* Get a sane OCR mask for other parts of the MMC subsytem. */
> > +               return mmc_of_parse_voltage(dev->of_node, &mmc->ocr_avail);
> 
> Does really the legacy platforms use the mmc voltage range DT bindings!?

The legacy DT's use (in the mmc slot nodes):

voltage-ranges = <3300 3300>;

> I would rather see that you assign a default value to mmc->ocr_avail,
> than using this binding.

The volatage seems to be identical for all legacy bindings I can find,
so is it better to not parse it and use the 3.3 as default?

> > +
> > +       mmc->supply.vmmc = devm_regulator_get(dev, "vmmc");
> > +       if (IS_ERR(mmc->supply.vmmc)) {
> > +               ret = PTR_ERR(mmc->supply.vmmc);
> > +       } else {
> > +               ret = mmc_regulator_get_ocrmask(mmc->supply.vmmc);
> > +               if (ret > 0) {
> > +                       mmc->ocr_avail = ret;
> > +                       ret = 0;
> > +               }
> > +       }
> 
> This if-else-if is a bit messy.
> 
> Why not just return when you get an error instead. That should simply the code.

OK, I'll simplify it.

> Maybe you can have look and try to clean up this in the hole file
> where you think it would make an improvment.
> 
> > +       return ret;
> > +}
> > +
> > +int cvm_mmc_slot_probe(struct device *dev, struct cvm_mmc_host *host)
> 
> To reflect that OF is needed, perhaps rename function to
> cvm_mmc_of_slot_probe().

OK.

> > +{
> > +       struct device_node *node = dev->of_node;
> > +       u32 id, cmd_skew, dat_skew;
> > +       struct cvm_mmc_slot *slot;
> > +       struct mmc_host *mmc;
> > +       u64 clock_period;
> > +       int ret;
> > +
> > +       ret = of_property_read_u32(node, "reg", &id);
> > +       if (ret) {
> > +               dev_err(dev, "Missing or invalid reg property on %s\n",
> > +                       of_node_full_name(node));
> > +               return ret;
> > +       }
> > +
> > +       if (id >= CAVIUM_MAX_MMC || host->slot[id]) {
> > +               dev_err(dev, "Invalid reg property on %s\n",
> > +                       of_node_full_name(node));
> > +               return -EINVAL;
> > +       }
> > +
> > +       mmc = mmc_alloc_host(sizeof(struct cvm_mmc_slot), dev);
> > +       if (!mmc)
> > +               return -ENOMEM;
> > +
> > +       slot = mmc_priv(mmc);
> > +       slot->mmc = mmc;
> > +       slot->host = host;
> > +
> > +       ret = mmc_of_parse(mmc);
> > +       if (ret)
> > +               goto error;
> > +
> > +       ret = set_bus_width(dev, slot, id);
> > +       if (ret)
> > +               goto error;
> > +
> > +       set_frequency(dev, mmc, id);
> > +
> > +       /* Octeon-specific DT properties. */
> > +       ret = of_property_read_u32(node, "cavium,cmd-clk-skew", &cmd_skew);
> > +       if (ret)
> > +               cmd_skew = 0;
> > +       ret = of_property_read_u32(node, "cavium,dat-clk-skew", &dat_skew);
> > +       if (ret)
> > +               dat_skew = 0;
> > +
> > +       ret = set_voltage(dev, mmc, host);
> > +       if (ret < 0)
> > +               goto error;
> 
> The functions set_bus_width(), set_freqeuncy(), set_voltage() all
> performs OF parsing and there are some parsing also being done above.
> 
> I would suggest you bundle all OF parsing into one function, perhaps
> name it "cvm_mmc_of_parse()" or similar. That should make the code a
> lot cleaner.

OK.

> > +
> > +       /* Set up host parameters */
> > +       mmc->ops = &cvm_mmc_ops;
> > +
> > +       mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
> > +                    MMC_CAP_ERASE | MMC_CAP_CMD23 | MMC_CAP_POWER_OFF_CARD;
> > +
> > +       mmc->max_segs = 1;
> > +
> > +       /* DMA size field can address up to 8 MB */
> > +       mmc->max_seg_size = 8 * 1024 * 1024;
> > +       mmc->max_req_size = mmc->max_seg_size;
> > +       /* External DMA is in 512 byte blocks */
> > +       mmc->max_blk_size = 512;
> > +       /* DMA block count field is 15 bits */
> > +       mmc->max_blk_count = 32767;
> > +
> > +       slot->clock = mmc->f_min;
> > +       slot->sclock = host->sys_freq;
> > +
> > +       /* Period in picoseconds. */
> > +       clock_period = 1000000000000ull / slot->sclock;
> > +       slot->cmd_cnt = (cmd_skew + clock_period / 2) / clock_period;
> > +       slot->dat_cnt = (dat_skew + clock_period / 2) / clock_period;
> > +
> > +       slot->bus_id = id;
> > +       slot->cached_rca = 1;
> > +
> > +       host->acquire_bus(host);
> > +       host->slot[id] = slot;
> > +       cvm_mmc_switch_to(slot);
> > +       cvm_mmc_init_lowlevel(slot);
> > +       host->release_bus(host);
> > +
> > +       ret = mmc_add_host(mmc);
> > +       if (ret) {
> > +               dev_err(dev, "mmc_add_host() returned %d\n", ret);
> > +               goto error;
> > +       }
> > +
> > +       return 0;
> > +
> > +error:
> > +       slot->host->slot[id] = NULL;
> > +       mmc_free_host(slot->mmc);
> > +       return ret;
> > +}
> > +
> > +int cvm_mmc_slot_remove(struct cvm_mmc_slot *slot)
> > +{
> > +       mmc_remove_host(slot->mmc);
> > +       slot->host->slot[slot->bus_id] = NULL;
> > +       mmc_free_host(slot->mmc);
> > +       return 0;
> > +}
> > diff --git a/drivers/mmc/host/cavium-mmc.h b/drivers/mmc/host/cavium-mmc.h
> > new file mode 100644
> > index 0000000..27fb02b
> > --- /dev/null
> > +++ b/drivers/mmc/host/cavium-mmc.h
> > @@ -0,0 +1,303 @@
> > +/*
> > + * Driver for MMC and SSD cards for Cavium OCTEON and ThunderX 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/clk.h>
> > +#include <linux/io.h>
> > +#include <linux/mmc/host.h>
> > +#include <linux/of.h>
> > +#include <linux/scatterlist.h>
> > +#include <linux/semaphore.h>
> > +
> > +#define CAVIUM_MAX_MMC         4
> > +
> > +struct cvm_mmc_host {
> > +       struct device *dev;
> > +       void __iomem *base;
> > +       void __iomem *dma_base;
> > +       u64 emm_cfg;
> > +       int last_slot;
> > +       struct clk *clk;
> > +       int sys_freq;
> > +
> > +       struct mmc_request *current_req;
> > +       struct sg_mapping_iter smi;
> > +       bool dma_active;
> > +
> > +       struct gpio_desc *global_pwr_gpiod;
> > +
> > +       struct cvm_mmc_slot *slot[CAVIUM_MAX_MMC];
> > +
> > +       void (*acquire_bus)(struct cvm_mmc_host *);
> > +       void (*release_bus)(struct cvm_mmc_host *);
> > +       void (*int_enable)(struct cvm_mmc_host *, u64);
> > +};
> > +
> > +struct cvm_mmc_slot {
> > +       struct mmc_host *mmc;           /* slot-level mmc_core object */
> > +       struct cvm_mmc_host *host;      /* common hw for all slots */
> > +
> > +       u64 clock;
> > +       unsigned int sclock;
> > +
> > +       u64 cached_switch;
> > +       u64 cached_rca;
> > +
> > +       unsigned int cmd_cnt;           /* sample delay */
> > +       unsigned int dat_cnt;           /* sample delay */
> > +
> > +       int bus_width;
> > +       int bus_id;
> > +};
> > +
> > +struct cvm_mmc_cr_type {
> > +       u8 ctype;
> > +       u8 rtype;
> > +};
> > +
> > +struct cvm_mmc_cr_mods {
> > +       u8 ctype_xor;
> > +       u8 rtype_xor;
> > +};
> > +
> > +/* Bitfield definitions */
> > +
> > +union mio_emm_cmd {
> > +       u64 val;
> > +       struct mio_emm_cmd_s {
> > +#ifdef __BIG_ENDIAN_BITFIELD
> 
> Huh. Sorry, but this is a big nack from me.
> 
> This isn't the common method for how we deal with endian issues in the
> kernel. Please remove all use of the union types here and below. The
> follow common patterns for how we deal with endian issues.

May I ask why you dislike the bitfields? Or maybe it is easier when I
explain why I decided to keep them:

- One drawback of bitfields is poor performance on some architectures.
  That is not the case here, both MIPS64 and ARM64 have instructions
  capable of using bitfields without performance impact.

- The used bitfield are all aligned to word size, usually the pattern in
  the driver is to readq / writeq the whole word (therefore the union
  val) and then set or read certain fields. That should avoid IMHO the
  unspecified behaviour the C standard mentions.

- I prefer BIT_ULL and friends for single bits, but using macros for
  more then one bit is (again IMHO) much less readable then using
  bitfiels here. And all the endianess definitions are _only_ in the
  header file.

Also, if I need to convert all of these I'll probably add some new bugs.
What we have currently works fine on both MIPS and ARM64.

> > +               u64 :2;
> > +               u64 bus_id:2;
> > +               u64 cmd_val:1;
> > +               u64 :3;
> > +               u64 dbuf:1;
> > +               u64 offset:6;
> > +               u64 :6;
> > +               u64 ctype_xor:2;
> > +               u64 rtype_xor:3;
> > +               u64 cmd_idx:6;
> > +               u64 arg:32;
> > +#else
> > +               u64 arg:32;
> > +               u64 cmd_idx:6;
> > +               u64 rtype_xor:3;
> > +               u64 ctype_xor:2;
> > +               u64 :6;
> > +               u64 offset:6;
> > +               u64 dbuf:1;
> > +               u64 :3;
> > +               u64 cmd_val:1;
> > +               u64 bus_id:2;
> > +               u64 :2;
> > +#endif
> > +       } s;
> > +};
> > +
> > +union mio_emm_dma {
> > +       u64 val;
> > +       struct mio_emm_dma_s {
> > +#ifdef __BIG_ENDIAN_BITFIELD
> > +               u64 :2;
> > +               u64 bus_id:2;
> > +               u64 dma_val:1;
> > +               u64 sector:1;
> > +               u64 dat_null:1;
> > +               u64 thres:6;
> > +               u64 rel_wr:1;
> > +               u64 rw:1;
> > +               u64 multi:1;
> > +               u64 block_cnt:16;
> > +               u64 card_addr:32;
> > +#else
> > +               u64 card_addr:32;
> > +               u64 block_cnt:16;
> > +               u64 multi:1;
> > +               u64 rw:1;
> > +               u64 rel_wr:1;
> > +               u64 thres:6;
> > +               u64 dat_null:1;
> > +               u64 sector:1;
> > +               u64 dma_val:1;
> > +               u64 bus_id:2;
> > +               u64 :2;
> > +#endif
> > +       } s;
> > +};
> > +
> > +union mio_emm_dma_cfg {
> > +       u64 val;
> > +       struct mio_emm_dma_cfg_s {
> > +#ifdef __BIG_ENDIAN_BITFIELD
> > +               u64 en:1;
> > +               u64 rw:1;
> > +               u64 clr:1;
> > +               u64 :1;
> > +               u64 swap32:1;
> > +               u64 swap16:1;
> > +               u64 swap8:1;
> > +               u64 endian:1;
> > +               u64 size:20;
> > +               u64 adr:36;
> > +#else
> > +               u64 adr:36;
> > +               u64 size:20;
> > +               u64 endian:1;
> > +               u64 swap8:1;
> > +               u64 swap16:1;
> > +               u64 swap32:1;
> > +               u64 :1;
> > +               u64 clr:1;
> > +               u64 rw:1;
> > +               u64 en:1;
> > +#endif
> > +       } s;
> > +};
> > +
> > +union mio_emm_int {
> > +       u64 val;
> > +       struct mio_emm_int_s {
> > +#ifdef __BIG_ENDIAN_BITFIELD
> > +               u64 :57;
> > +               u64 switch_err:1;
> > +               u64 switch_done:1;
> > +               u64 dma_err:1;
> > +               u64 cmd_err:1;
> > +               u64 dma_done:1;
> > +               u64 cmd_done:1;
> > +               u64 buf_done:1;
> > +#else
> > +               u64 buf_done:1;
> > +               u64 cmd_done:1;
> > +               u64 dma_done:1;
> > +               u64 cmd_err:1;
> > +               u64 dma_err:1;
> > +               u64 switch_done:1;
> > +               u64 switch_err:1;
> > +               u64 :57;
> > +#endif
> > +       } s;
> > +};
> > +
> > +union mio_emm_rsp_sts {
> > +       u64 val;
> > +       struct mio_emm_rsp_sts_s {
> > +#ifdef __BIG_ENDIAN_BITFIELD
> > +               u64 :2;
> > +               u64 bus_id:2;
> > +               u64 cmd_val:1;
> > +               u64 switch_val:1;
> > +               u64 dma_val:1;
> > +               u64 dma_pend:1;
> > +               u64 :27;
> > +               u64 dbuf_err:1;
> > +               u64 :4;
> > +               u64 dbuf:1;
> > +               u64 blk_timeout:1;
> > +               u64 blk_crc_err:1;
> > +               u64 rsp_busybit:1;
> > +               u64 stp_timeout:1;
> > +               u64 stp_crc_err:1;
> > +               u64 stp_bad_sts:1;
> > +               u64 stp_val:1;
> > +               u64 rsp_timeout:1;
> > +               u64 rsp_crc_err:1;
> > +               u64 rsp_bad_sts:1;
> > +               u64 rsp_val:1;
> > +               u64 rsp_type:3;
> > +               u64 cmd_type:2;
> > +               u64 cmd_idx:6;
> > +               u64 cmd_done:1;
> > +#else
> > +               u64 cmd_done:1;
> > +               u64 cmd_idx:6;
> > +               u64 cmd_type:2;
> > +               u64 rsp_type:3;
> > +               u64 rsp_val:1;
> > +               u64 rsp_bad_sts:1;
> > +               u64 rsp_crc_err:1;
> > +               u64 rsp_timeout:1;
> > +               u64 stp_val:1;
> > +               u64 stp_bad_sts:1;
> > +               u64 stp_crc_err:1;
> > +               u64 stp_timeout:1;
> > +               u64 rsp_busybit:1;
> > +               u64 blk_crc_err:1;
> > +               u64 blk_timeout:1;
> > +               u64 dbuf:1;
> > +               u64 :4;
> > +               u64 dbuf_err:1;
> > +               u64 :27;
> > +               u64 dma_pend:1;
> > +               u64 dma_val:1;
> > +               u64 switch_val:1;
> > +               u64 cmd_val:1;
> > +               u64 bus_id:2;
> > +               u64 :2;
> > +#endif
> > +       } s;
> > +};
> > +
> > +union mio_emm_sample {
> > +       u64 val;
> > +       struct mio_emm_sample_s {
> > +#ifdef __BIG_ENDIAN_BITFIELD
> > +               u64 :38;
> > +               u64 cmd_cnt:10;
> > +               u64 :6;
> > +               u64 dat_cnt:10;
> > +#else
> > +               u64 dat_cnt:10;
> > +               u64 :6;
> > +               u64 cmd_cnt:10;
> > +               u64 :38;
> > +#endif
> > +       } s;
> > +};
> > +
> > +union mio_emm_switch {
> > +       u64 val;
> > +       struct mio_emm_switch_s {
> > +#ifdef __BIG_ENDIAN_BITFIELD
> > +               u64 :2;
> > +               u64 bus_id:2;
> > +               u64 switch_exe:1;
> > +               u64 switch_err0:1;
> > +               u64 switch_err1:1;
> > +               u64 switch_err2:1;
> > +               u64 :7;
> > +               u64 hs_timing:1;
> > +               u64 :5;
> > +               u64 bus_width:3;
> > +               u64 :4;
> > +               u64 power_class:4;
> > +               u64 clk_hi:16;
> > +               u64 clk_lo:16;
> > +#else
> > +               u64 clk_lo:16;
> > +               u64 clk_hi:16;
> > +               u64 power_class:4;
> > +               u64 :4;
> > +               u64 bus_width:3;
> > +               u64 :5;
> > +               u64 hs_timing:1;
> > +               u64 :7;
> > +               u64 switch_err2:1;
> > +               u64 switch_err1:1;
> > +               u64 switch_err0:1;
> > +               u64 switch_exe:1;
> > +               u64 bus_id:2;
> > +               u64 :2;
> > +#endif
> > +       } s;
> > +};
> > +
> > +/* Protoypes */
> > +irqreturn_t cvm_mmc_interrupt(int irq, void *dev_id);
> > +int cvm_mmc_slot_probe(struct device *dev, struct cvm_mmc_host *host);
> > +int cvm_mmc_slot_remove(struct cvm_mmc_slot *slot);
> 
> Why do you need this here? Are those intended as library functions for
> the different cavium variant drivers?

Yes, this is the minimum I need to share the cavium-mmc-core.

> > +extern const struct mmc_host_ops cvm_mmc_ops;
> 
> Why do you need this?

Left-over from development, can be removed now.

> Kind regards
> Uffe

Thanks for the review!

Jan

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v11 2/9] mmc: cavium: Add core MMC driver for Cavium SOCs
  2017-03-07 10:49     ` Jan Glauber
@ 2017-03-08  9:45       ` Ulf Hansson
  2017-03-08 17:52         ` Jan Glauber
  0 siblings, 1 reply; 24+ messages in thread
From: Ulf Hansson @ 2017-03-08  9:45 UTC (permalink / raw)
  To: Jan Glauber
  Cc: linux-mmc, linux-kernel, David Daney, Steven J . Hill, David Daney

[...]

>> > Voltage is limited to 3.3v and shared for all slots.
>>
>> What voltage? The I/O voltage or the voltage for the card?
>>
>> VMMC or VMMCQ?
>
> From my understanding both, VMMC and VMMCQ are fixed at 3.3v.

Okay, then make sure to explicitly state that here.

[...]

>> > +       if (bad_status(&rsp_sts))
>> > +               req->cmd->error = -EILSEQ;
>>
>> I don't think you should treat all errors as -EILSEQ. Please assign a
>> proper error code, depending on the error.
>
> Agreed, -ETIMEDOUT seems more appropriate for the timeouts. I'll go for
> -EIO for the dbuf_err (buffer space missing). What should I use for the
> CRC errors, -EILSEQ?

Yes, correct.

[...]

>> What does this really mean? Is this about HW support for better
>> dealing with data requests?
>
> Did David's reponse answer your questions?

Yes.

[...]

>> > +       /*
>> > +        * Legacy platform doesn't support regulator but enables power gpio
>> > +        * directly during platform probe.
>> > +        */
>> > +       if (host->global_pwr_gpiod)
>> > +               /* Get a sane OCR mask for other parts of the MMC subsytem. */
>> > +               return mmc_of_parse_voltage(dev->of_node, &mmc->ocr_avail);
>>
>> Does really the legacy platforms use the mmc voltage range DT bindings!?
>
> The legacy DT's use (in the mmc slot nodes):
>
> voltage-ranges = <3300 3300>;
>
>> I would rather see that you assign a default value to mmc->ocr_avail,
>> than using this binding.
>
> The volatage seems to be identical for all legacy bindings I can find,
> so is it better to not parse it and use the 3.3 as default?

Yes, I think so.

[...]

>> > +union mio_emm_cmd {
>> > +       u64 val;
>> > +       struct mio_emm_cmd_s {
>> > +#ifdef __BIG_ENDIAN_BITFIELD
>>
>> Huh. Sorry, but this is a big nack from me.
>>
>> This isn't the common method for how we deal with endian issues in the
>> kernel. Please remove all use of the union types here and below. The
>> follow common patterns for how we deal with endian issues.
>
> May I ask why you dislike the bitfields? Or maybe it is easier when I
> explain why I decided to keep them:

My main concern is that is different compared to how we deal with
endian issues in the kernel.

I just don't like homebrewed hacks, but prefers sticking to defacto
standard methods.

>
> - One drawback of bitfields is poor performance on some architectures.
>   That is not the case here, both MIPS64 and ARM64 have instructions
>   capable of using bitfields without performance impact.
>
> - The used bitfield are all aligned to word size, usually the pattern in
>   the driver is to readq / writeq the whole word (therefore the union
>   val) and then set or read certain fields. That should avoid IMHO the
>   unspecified behaviour the C standard mentions.
>
> - I prefer BIT_ULL and friends for single bits, but using macros for
>   more then one bit is (again IMHO) much less readable then using
>   bitfiels here. And all the endianess definitions are _only_ in the
>   header file.
>
> Also, if I need to convert all of these I'll probably add some new bugs.
> What we have currently works fine on both MIPS and ARM64.

I understand that is will have an impact, however there are plenty of
good references in the kernel for how to do this.

[...]

Kind regards
Uffe

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v11 2/9] mmc: cavium: Add core MMC driver for Cavium SOCs
  2017-03-08  9:45       ` Ulf Hansson
@ 2017-03-08 17:52         ` Jan Glauber
  0 siblings, 0 replies; 24+ messages in thread
From: Jan Glauber @ 2017-03-08 17:52 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc, linux-kernel, David Daney, Steven J . Hill, David Daney

On Wed, Mar 08, 2017 at 10:45:19AM +0100, Ulf Hansson wrote:
[...]

> > May I ask why you dislike the bitfields? Or maybe it is easier when I
> > explain why I decided to keep them:
> 
> My main concern is that is different compared to how we deal with
> endian issues in the kernel.
> 
> I just don't like homebrewed hacks, but prefers sticking to defacto
> standard methods.

I don't see it as a homebrew hack, the BIG/LITTLE_ENDIAN_BITFIELD macros
are already used in the kernel. In my eyes it is a straight-forward and
obvious thing.

> >
> > - One drawback of bitfields is poor performance on some architectures.
> >   That is not the case here, both MIPS64 and ARM64 have instructions
> >   capable of using bitfields without performance impact.
> >
> > - The used bitfield are all aligned to word size, usually the pattern in
> >   the driver is to readq / writeq the whole word (therefore the union
> >   val) and then set or read certain fields. That should avoid IMHO the
> >   unspecified behaviour the C standard mentions.
> >
> > - I prefer BIT_ULL and friends for single bits, but using macros for
> >   more then one bit is (again IMHO) much less readable then using
> >   bitfiels here. And all the endianess definitions are _only_ in the
> >   header file.
> >
> > Also, if I need to convert all of these I'll probably add some new bugs.
> > What we have currently works fine on both MIPS and ARM64.
> 
> I understand that is will have an impact, however there are plenty of
> good references in the kernel for how to do this.

As an experiment I've converted the bitfields to use FIELD_PREP|GET or
plain logic, see below patch (against unreleased v12, just to show the
difference).

While the header file looks cleaner I think the code is much harder to
read. Is there a better way to do this? Is it really worth it?

thanks,
Jan

> [...]
> 
> Kind regards
> Uffe

---

diff --git a/drivers/mmc/host/cavium-mmc.c b/drivers/mmc/host/cavium-mmc.c
index b507a7a..b899720 100644
--- a/drivers/mmc/host/cavium-mmc.c
+++ b/drivers/mmc/host/cavium-mmc.c
@@ -13,6 +13,7 @@
  *   Steven J. Hill <steven.hill@cavium.com>
  *   Jan Glauber <jglauber@cavium.com>
  */
+#include <linux/bitfield.h>
 #include <linux/delay.h>
 #include <linux/dma-direction.h>
 #include <linux/dma-mapping.h>
@@ -151,14 +152,14 @@ static struct cvm_mmc_cr_mods cvm_mmc_get_cr_mods(struct mmc_command *cmd)
 
 static void check_switch_errors(struct cvm_mmc_host *host)
 {
-	union mio_emm_switch emm_switch;
+	u64 emm_switch;
 
-	emm_switch.val = readq(host->base + MIO_EMM_SWITCH(host));
-	if (emm_switch.s.switch_err0)
+	emm_switch = readq(host->base + MIO_EMM_SWITCH(host));
+	if (emm_switch & MIO_EMM_SWITCH_ERR0)
 		dev_err(host->dev, "Switch power class error\n");
-	if (emm_switch.s.switch_err1)
+	if (emm_switch & MIO_EMM_SWITCH_ERR1)
 		dev_err(host->dev, "Switch hs timing error\n");
-	if (emm_switch.s.switch_err2)
+	if (emm_switch & MIO_EMM_SWITCH_ERR2)
 		dev_err(host->dev, "Switch bus width error\n");
 }
 
@@ -168,28 +169,25 @@ static void check_switch_errors(struct cvm_mmc_host *host)
  */
 static void do_switch(struct cvm_mmc_host *host, u64 val)
 {
-	union mio_emm_rsp_sts rsp_sts;
-	union mio_emm_switch emm_switch;
+	u64 rsp_sts, emm_switch = val;
 	int retries = 100;
 	int bus_id;
 
-	emm_switch.val = val;
-
 	/*
 	 * Modes setting only taken from slot 0. Work around that hardware
 	 * issue by first switching to slot 0.
 	 */
-	bus_id = emm_switch.s.bus_id;
-	emm_switch.s.bus_id = 0;
-	writeq(emm_switch.val, host->base + MIO_EMM_SWITCH(host));
+	bus_id = FIELD_GET(MIO_EMM_SWITCH_BUS_ID, emm_switch);
+	emm_switch &= ~MIO_EMM_SWITCH_BUS_ID;
+	writeq(emm_switch, host->base + MIO_EMM_SWITCH(host));
 
-	emm_switch.s.bus_id = bus_id;
-	writeq(emm_switch.val, host->base + MIO_EMM_SWITCH(host));
+	emm_switch |= FIELD_PREP(MIO_EMM_SWITCH_BUS_ID, bus_id);
+	writeq(emm_switch, host->base + MIO_EMM_SWITCH(host));
 
 	/* wait for the switch to finish */
 	do {
-		rsp_sts.val = readq(host->base + MIO_EMM_RSP_STS(host));
-		if (!rsp_sts.s.switch_val)
+		rsp_sts = readq(host->base + MIO_EMM_RSP_STS(host));
+		if (!(rsp_sts & MIO_EMM_RSP_STS_SWITCH_VAL))
 			break;
 		udelay(10);
 	} while (--retries);
@@ -222,20 +220,18 @@ static void set_wdog(struct cvm_mmc_slot *slot, unsigned int ns)
 static void cvm_mmc_reset_bus(struct cvm_mmc_slot *slot)
 {
 	struct cvm_mmc_host *host = slot->host;
-	union mio_emm_switch emm_switch;
-	u64 wdog = 0;
+	u64 emm_switch, wdog;
 
-	emm_switch.val = readq(slot->host->base + MIO_EMM_SWITCH(host));
-	wdog = readq(slot->host->base + MIO_EMM_WDOG(host));
+	emm_switch = readq(slot->host->base + MIO_EMM_SWITCH(host));
+	emm_switch &= ~(MIO_EMM_SWITCH_EXE | MIO_EMM_SWITCH_ERR0 |
+			MIO_EMM_SWITCH_ERR1 | MIO_EMM_SWITCH_ERR2 |
+			MIO_EMM_SWITCH_BUS_ID);
+	emm_switch |= FIELD_PREP(MIO_EMM_SWITCH_BUS_ID, slot->bus_id);
 
-	emm_switch.s.switch_exe = 0;
-	emm_switch.s.switch_err0 = 0;
-	emm_switch.s.switch_err1 = 0;
-	emm_switch.s.switch_err2 = 0;
-	emm_switch.s.bus_id = slot->bus_id;
-	do_switch(slot->host, emm_switch.val);
+	wdog = readq(slot->host->base + MIO_EMM_WDOG(host));
+	do_switch(slot->host, emm_switch);
 
-	slot->cached_switch = emm_switch.val;
+	slot->cached_switch = emm_switch;
 
 	msleep(20);
 
@@ -247,8 +243,7 @@ static void cvm_mmc_switch_to(struct cvm_mmc_slot *slot)
 {
 	struct cvm_mmc_host *host = slot->host;
 	struct cvm_mmc_slot *old_slot;
-	union mio_emm_switch emm_switch;
-	union mio_emm_sample emm_sample;
+	u64 emm_sample, emm_switch;
 
 	if (slot->bus_id == host->last_slot)
 		return;
@@ -260,14 +255,14 @@ static void cvm_mmc_switch_to(struct cvm_mmc_slot *slot)
 	}
 
 	writeq(slot->cached_rca, host->base + MIO_EMM_RCA(host));
-	emm_switch.val = slot->cached_switch;
-	emm_switch.s.bus_id = slot->bus_id;
-	do_switch(host, emm_switch.val);
+	emm_switch = slot->cached_switch;
+	emm_switch &= ~MIO_EMM_SWITCH_BUS_ID;
+	emm_switch |= FIELD_PREP(MIO_EMM_SWITCH_BUS_ID, slot->bus_id);
+	do_switch(host, emm_switch);
 
-	emm_sample.val = 0;
-	emm_sample.s.cmd_cnt = slot->cmd_cnt;
-	emm_sample.s.dat_cnt = slot->dat_cnt;
-	writeq(emm_sample.val, host->base + MIO_EMM_SAMPLE(host));
+	emm_sample = FIELD_PREP(MIO_EMM_SAMPLE_CMD_CNT, slot->cmd_cnt) |
+		     FIELD_PREP(MIO_EMM_SAMPLE_DAT_CNT, slot->dat_cnt);
+	writeq(emm_sample, host->base + MIO_EMM_SAMPLE(host));
 
 	host->last_slot = slot->bus_id;
 }
@@ -315,16 +310,16 @@ static void do_write(struct mmc_request *req)
 }
 
 static void set_cmd_response(struct cvm_mmc_host *host, struct mmc_request *req,
-			     union mio_emm_rsp_sts *rsp_sts)
+			     u64 rsp_sts)
 {
 	u64 rsp_hi, rsp_lo;
 
-	if (!rsp_sts->s.rsp_val)
+	if (!(rsp_sts & MIO_EMM_RSP_STS_RSP_VAL))
 		return;
 
 	rsp_lo = readq(host->base + MIO_EMM_RSP_LO(host));
 
-	switch (rsp_sts->s.rsp_type) {
+	switch (FIELD_GET(MIO_EMM_RSP_STS_RSP_TYPE, rsp_sts)) {
 	case 1:
 	case 3:
 		req->cmd->resp[0] = (rsp_lo >> 8) & 0xffffffff;
@@ -356,13 +351,14 @@ static int finish_dma_single(struct cvm_mmc_host *host, struct mmc_data *data)
 
 static int finish_dma_sg(struct cvm_mmc_host *host, struct mmc_data *data)
 {
-	union mio_emm_dma_fifo_cfg fifo_cfg;
+	u64 fifo_cfg;
+	int count;
 
 	/* Check if there are any pending requests left */
-	fifo_cfg.val = readq(host->dma_base + MIO_EMM_DMA_FIFO_CFG(host));
-	if (fifo_cfg.s.count)
-		dev_err(host->dev, "%u requests still pending\n",
-			fifo_cfg.s.count);
+	fifo_cfg = readq(host->dma_base + MIO_EMM_DMA_FIFO_CFG(host));
+	count = FIELD_GET(MIO_EMM_DMA_FIFO_CFG_COUNT, fifo_cfg);
+	if (count)
+		dev_err(host->dev, "%u requests still pending\n", count);
 
 	data->bytes_xfered = data->blocks * data->blksz;
 	data->error = 0;
@@ -381,38 +377,39 @@ static int finish_dma(struct cvm_mmc_host *host, struct mmc_data *data)
 		return finish_dma_single(host, data);
 }
 
-static int check_status(union mio_emm_rsp_sts *rsp_sts)
+static int check_status(u64 rsp_sts)
 {
-	if (rsp_sts->s.rsp_bad_sts || rsp_sts->s.rsp_crc_err ||
-	    rsp_sts->s.blk_crc_err)
+	if (rsp_sts & MIO_EMM_RSP_STS_RSP_BAD_STS ||
+	    rsp_sts & MIO_EMM_RSP_STS_RSP_CRC_ERR ||
+	    rsp_sts & MIO_EMM_RSP_STS_BLK_CRC_ERR)
 		return -EILSEQ;
-	if (rsp_sts->s.rsp_timeout || rsp_sts->s.blk_timeout)
+	if (rsp_sts & MIO_EMM_RSP_STS_RSP_TIMEOUT ||
+	    rsp_sts & MIO_EMM_RSP_STS_BLK_TIMEOUT)
 		return -ETIMEDOUT;
-	if (rsp_sts->s.dbuf_err)
+	if (rsp_sts & MIO_EMM_RSP_STS_DBUF_ERR)
 		return -EIO;
 	return 0;
 }
 
 /* Try to clean up failed DMA. */
-static void cleanup_dma(struct cvm_mmc_host *host,
-			union mio_emm_rsp_sts *rsp_sts)
+static void cleanup_dma(struct cvm_mmc_host *host, u64 rsp_sts)
 {
-	union mio_emm_dma emm_dma;
-
-	emm_dma.val = readq(host->base + MIO_EMM_DMA(host));
-	emm_dma.s.dma_val = 1;
-	emm_dma.s.dat_null = 1;
-	emm_dma.s.bus_id = rsp_sts->s.bus_id;
-	writeq(emm_dma.val, host->base + MIO_EMM_DMA(host));
+	u64 emm_dma;
+
+	emm_dma = readq(host->base + MIO_EMM_DMA(host));
+	emm_dma &= ~MIO_EMM_DMA_BUS_ID;
+	emm_dma |= FIELD_PREP(MIO_EMM_DMA_VAL, 1) |
+		   FIELD_PREP(MIO_EMM_DMA_DAT_NULL, 1) |
+		   FIELD_PREP(MIO_EMM_DMA_BUS_ID, FIELD_GET(MIO_EMM_RSP_STS_BUS_ID, rsp_sts));
+	writeq(emm_dma, host->base + MIO_EMM_DMA(host));
 }
 
 irqreturn_t cvm_mmc_interrupt(int irq, void *dev_id)
 {
 	struct cvm_mmc_host *host = dev_id;
-	union mio_emm_rsp_sts rsp_sts;
-	union mio_emm_int emm_int;
 	struct mmc_request *req;
 	unsigned long flags = 0;
+	u64 emm_int, rsp_sts;
 	bool host_done;
 
 	if (host->need_irq_handler_lock)
@@ -421,49 +418,53 @@ irqreturn_t cvm_mmc_interrupt(int irq, void *dev_id)
 		__acquire(&host->irq_handler_lock);
 
 	/* Clear interrupt bits (write 1 clears ). */
-	emm_int.val = readq(host->base + MIO_EMM_INT(host));
-	writeq(emm_int.val, host->base + MIO_EMM_INT(host));
+	emm_int = readq(host->base + MIO_EMM_INT(host));
+	writeq(emm_int, host->base + MIO_EMM_INT(host));
 
-	if (emm_int.s.switch_err)
+	if (emm_int & MIO_EMM_INT_SWITCH_ERR)
 		check_switch_errors(host);
 
 	req = host->current_req;
 	if (!req)
 		goto out;
 
-	rsp_sts.val = readq(host->base + MIO_EMM_RSP_STS(host));
+	rsp_sts = readq(host->base + MIO_EMM_RSP_STS(host));
 	/*
 	 * dma_val set means DMA is still in progress. Don't touch
 	 * the request and wait for the interrupt indicating that
 	 * the DMA is finished.
 	 */
-	if (rsp_sts.s.dma_val && host->dma_active)
+	if ((rsp_sts & MIO_EMM_RSP_STS_DMA_VAL) && host->dma_active)
 		goto out;
 
-	if (!host->dma_active && emm_int.s.buf_done && req->data) {
-		unsigned int type = (rsp_sts.val >> 7) & 3;
+	if (!host->dma_active && req->data &&
+	    (emm_int & MIO_EMM_INT_BUF_DONE)) {
+		unsigned int type = (rsp_sts >> 7) & 3;
 
 		if (type == 1)
-			do_read(host, req, rsp_sts.s.dbuf);
+			do_read(host, req, rsp_sts & MIO_EMM_RSP_STS_DBUF);
 		else if (type == 2)
 			do_write(req);
 	}
 
-	host_done = emm_int.s.cmd_done || emm_int.s.dma_done ||
-		    emm_int.s.cmd_err || emm_int.s.dma_err;
+	host_done = emm_int & MIO_EMM_INT_CMD_DONE ||
+		    emm_int & MIO_EMM_INT_DMA_DONE ||
+		    emm_int & MIO_EMM_INT_CMD_ERR  ||
+		    emm_int & MIO_EMM_INT_DMA_ERR;
 
 	if (!(host_done && req->done))
 		goto no_req_done;
 
-	req->cmd->error = check_status(&rsp_sts);
+	req->cmd->error = check_status(rsp_sts);
 
 	if (host->dma_active && req->data)
 		if (!finish_dma(host, req->data))
 			goto no_req_done;
 
-	set_cmd_response(host, req, &rsp_sts);
-	if (emm_int.s.dma_err && rsp_sts.s.dma_pend)
-		cleanup_dma(host, &rsp_sts);
+	set_cmd_response(host, req, rsp_sts);
+	if ((emm_int & MIO_EMM_INT_DMA_ERR) &&
+	    (rsp_sts & MIO_EMM_RSP_STS_DMA_PEND))
+		cleanup_dma(host, rsp_sts);
 
 	host->current_req = NULL;
 	req->done(req);
@@ -478,7 +479,7 @@ irqreturn_t cvm_mmc_interrupt(int irq, void *dev_id)
 		spin_unlock_irqrestore(&host->irq_handler_lock, flags);
 	else
 		__release(&host->irq_handler_lock);
-	return IRQ_RETVAL(emm_int.val != 0);
+	return IRQ_RETVAL(emm_int != 0);
 }
 
 /*
@@ -487,30 +488,30 @@ irqreturn_t cvm_mmc_interrupt(int irq, void *dev_id)
  */
 static u64 prepare_dma_single(struct cvm_mmc_host *host, struct mmc_data *data)
 {
-	union mio_emm_dma_cfg dma_cfg;
-	int count;
-	u64 addr;
+	u64 dma_cfg, addr;
+	int count, rw;
 
 	count = dma_map_sg(host->dev, data->sg, data->sg_len,
 			   get_dma_dir(data));
 	if (!count)
 		return 0;
 
-	dma_cfg.val = 0;
-	dma_cfg.s.en = 1;
-	dma_cfg.s.rw = (data->flags & MMC_DATA_WRITE) ? 1 : 0;
+	rw = (data->flags & MMC_DATA_WRITE) ? 1 : 0;
+	dma_cfg = FIELD_PREP(MIO_EMM_DMA_CFG_EN, 1) |
+		  FIELD_PREP(MIO_EMM_DMA_CFG_RW, rw);
 #ifdef __LITTLE_ENDIAN
-	dma_cfg.s.endian = 1;
+	dma_cfg |= FIELD_PREP(MIO_EMM_DMA_CFG_ENDIAN, 1);
 #endif
-	dma_cfg.s.size = (sg_dma_len(&data->sg[0]) / 8) - 1;
+	dma_cfg |= FIELD_PREP(MIO_EMM_DMA_CFG_SIZE,
+			      (sg_dma_len(&data->sg[0]) / 8) - 1);
 
 	addr = sg_dma_address(&data->sg[0]);
 	if (!host->big_dma_addr)
-		dma_cfg.s.adr = addr;
-	writeq(dma_cfg.val, host->dma_base + MIO_EMM_DMA_CFG(host));
+		dma_cfg |= FIELD_PREP(MIO_EMM_DMA_CFG_ADR, addr);
+	writeq(dma_cfg, host->dma_base + MIO_EMM_DMA_CFG(host));
 
 	pr_debug("[%s] sg_dma_len: %u  total sg_elem: %d\n",
-		 (dma_cfg.s.rw) ? "W" : "R", sg_dma_len(&data->sg[0]), count);
+		 (rw) ? "W" : "R", sg_dma_len(&data->sg[0]), count);
 
 	if (host->big_dma_addr)
 		writeq(addr, host->dma_base + MIO_EMM_DMA_ADR(host));
@@ -523,10 +524,9 @@ static u64 prepare_dma_single(struct cvm_mmc_host *host, struct mmc_data *data)
  */
 static u64 prepare_dma_sg(struct cvm_mmc_host *host, struct mmc_data *data)
 {
-	union mio_emm_dma_fifo_cmd fifo_cmd;
 	struct scatterlist *sg;
-	int count, i;
-	u64 addr;
+	u64 fifo_cmd, addr;
+	int count, i, rw;
 
 	count = dma_map_sg(host->dev, data->sg, data->sg_len,
 			   get_dma_dir(data));
@@ -550,26 +550,25 @@ static u64 prepare_dma_sg(struct cvm_mmc_host *host, struct mmc_data *data)
 		 * register for the DMA addr, so no need to check
 		 * host->big_dma_addr here.
 		 */
-		fifo_cmd.val = 0;
-		fifo_cmd.s.rw = (data->flags & MMC_DATA_WRITE) ? 1 : 0;
+		rw = (data->flags & MMC_DATA_WRITE) ? 1 : 0;
+		fifo_cmd = FIELD_PREP(MIO_EMM_DMA_FIFO_CMD_RW, rw);
 
 		/* enable interrupts on the last element */
-		if (i + 1 == count)
-			fifo_cmd.s.intdis = 0;
-		else
-			fifo_cmd.s.intdis = 1;
+		fifo_cmd |= FIELD_PREP(MIO_EMM_DMA_FIFO_CMD_INTDIS,
+				       (i + 1 == count) ? 0 : 1);
 
 #ifdef __LITTLE_ENDIAN
-		fifo_cmd.s.endian = 1;
+		fifo_cmd |= FIELD_PREP(MIO_EMM_DMA_FIFO_CMD_ENDIAN, 1);
 #endif
-		fifo_cmd.s.size = sg_dma_len(sg) / 8 - 1;
+		fifo_cmd |= FIELD_PREP(MIO_EMM_DMA_FIFO_CMD_SIZE,
+				       sg_dma_len(sg) / 8 - 1);
 		/*
 		 * The write copies the address and the command to the FIFO
 		 * and increments the FIFO's COUNT field.
 		 */
-		writeq(fifo_cmd.val, host->dma_base + MIO_EMM_DMA_FIFO_CMD(host));
+		writeq(fifo_cmd, host->dma_base + MIO_EMM_DMA_FIFO_CMD(host));
 		pr_debug("[%s] sg_dma_len: %u  sg_elem: %d/%d\n",
-			 (fifo_cmd.s.rw) ? "W" : "R", sg_dma_len(sg), i, count);
+			 (rw) ? "W" : "R", sg_dma_len(sg), i, count);
 	}
 
 	/*
@@ -596,32 +595,28 @@ static u64 prepare_dma(struct cvm_mmc_host *host, struct mmc_data *data)
 		return prepare_dma_single(host, data);
 }
 
-static void prepare_ext_dma(struct mmc_host *mmc, struct mmc_request *mrq,
-			    union mio_emm_dma *emm_dma)
+static u64 prepare_ext_dma(struct mmc_host *mmc, struct mmc_request *mrq)
 {
 	struct cvm_mmc_slot *slot = mmc_priv(mmc);
+	u64 emm_dma = 0;
+
+	emm_dma = FIELD_PREP(MIO_EMM_DMA_BUS_ID, slot->bus_id) |
+		  FIELD_PREP(MIO_EMM_DMA_VAL, 1) |
+		  FIELD_PREP(MIO_EMM_DMA_SECTOR,
+			     (mrq->data->blksz == 512) ? 1 : 0) |
+		  FIELD_PREP(MIO_EMM_DMA_RW,
+			     (mrq->data->flags & MMC_DATA_WRITE) ? 1 : 0) |
+		  FIELD_PREP(MIO_EMM_DMA_BLOCK_CNT, mrq->data->blocks) |
+		  FIELD_PREP(MIO_EMM_DMA_CARD_ADDR, mrq->cmd->arg);
 
-	emm_dma->val = 0;
-	emm_dma->s.bus_id = slot->bus_id;
-	emm_dma->s.dma_val = 1;
-	emm_dma->s.sector = (mrq->data->blksz == 512) ? 1 : 0;
-	emm_dma->s.rw = (mrq->data->flags & MMC_DATA_WRITE) ? 1 : 0;
-	emm_dma->s.block_cnt = mrq->data->blocks;
-	emm_dma->s.card_addr = mrq->cmd->arg;
 	if (mmc_card_mmc(mmc->card) || (mmc_card_sd(mmc->card) &&
 	    (mmc->card->scr.cmds & SD_SCR_CMD23_SUPPORT)))
-		emm_dma->s.multi = 1;
-
-	pr_debug("[%s] blocks: %u  multi: %d\n", (emm_dma->s.rw) ? "W" : "R",
-		 mrq->data->blocks, emm_dma->s.multi);
-}
+		emm_dma |= FIELD_PREP(MIO_EMM_DMA_MULTI, 1);
 
-static void prepare_emm_int(union mio_emm_int *emm_int)
-{
-	emm_int->val = 0;
-	emm_int->s.cmd_err = 1;
-	emm_int->s.dma_done = 1;
-	emm_int->s.dma_err = 1;
+	pr_debug("[%s] blocks: %u  multi: %d\n",
+		(emm_dma & MIO_EMM_DMA_RW) ? "W" : "R",
+		 mrq->data->blocks, (emm_dma & MIO_EMM_DMA_MULTI) ? 1 : 0);
+	return emm_dma;
 }
 
 static void cvm_mmc_dma_request(struct mmc_host *mmc,
@@ -629,10 +624,8 @@ static void cvm_mmc_dma_request(struct mmc_host *mmc,
 {
 	struct cvm_mmc_slot *slot = mmc_priv(mmc);
 	struct cvm_mmc_host *host = slot->host;
-	union mio_emm_dma emm_dma;
-	union mio_emm_int emm_int;
 	struct mmc_data *data;
-	u64 addr;
+	u64 emm_dma, addr;
 
 	if (!mrq->data || !mrq->data->sg || !mrq->data->sg_len ||
 	    !mrq->stop || mrq->stop->opcode != MMC_STOP_TRANSMISSION) {
@@ -652,16 +645,16 @@ static void cvm_mmc_dma_request(struct mmc_host *mmc,
 	WARN_ON(host->current_req);
 	host->current_req = mrq;
 
-	prepare_ext_dma(mmc, mrq, &emm_dma);
+	emm_dma = prepare_ext_dma(mmc, mrq);
 	addr = prepare_dma(host, data);
 	if (!addr) {
 		dev_err(host->dev, "prepare_dma failed\n");
 		goto error;
 	}
-	prepare_emm_int(&emm_int);
 
 	host->dma_active = true;
-	host->int_enable(host, emm_int.val);
+	host->int_enable(host, MIO_EMM_INT_CMD_ERR | MIO_EMM_INT_DMA_DONE |
+			 MIO_EMM_INT_DMA_ERR);
 
 	if (host->dmar_fixup)
 		host->dmar_fixup(host, mrq->cmd, data, addr);
@@ -675,7 +668,7 @@ static void cvm_mmc_dma_request(struct mmc_host *mmc,
 		writeq(0x00b00000ull, host->base + MIO_EMM_STS_MASK(host));
 	else
 		writeq(0xe4390080ull, host->base + MIO_EMM_STS_MASK(host));
-	writeq(emm_dma.val, host->base + MIO_EMM_DMA(host));
+	writeq(emm_dma, host->base + MIO_EMM_DMA(host));
 	return;
 
 error:
@@ -733,10 +726,8 @@ static void cvm_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
 	struct cvm_mmc_slot *slot = mmc_priv(mmc);
 	struct cvm_mmc_host *host = slot->host;
 	struct mmc_command *cmd = mrq->cmd;
-	union mio_emm_int emm_int;
-	union mio_emm_cmd emm_cmd;
 	struct cvm_mmc_cr_mods mods;
-	union mio_emm_rsp_sts rsp_sts;
+	u64 emm_cmd, rsp_sts;
 	int retries = 100;
 
 	/*
@@ -761,10 +752,6 @@ static void cvm_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
 	WARN_ON(host->current_req);
 	host->current_req = mrq;
 
-	emm_int.val = 0;
-	emm_int.s.cmd_done = 1;
-	emm_int.s.cmd_err = 1;
-
 	if (cmd->data) {
 		if (cmd->data->flags & MMC_DATA_READ)
 			do_read_request(host, mrq);
@@ -777,31 +764,33 @@ static void cvm_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
 		set_wdog(slot, 0);
 
 	host->dma_active = false;
-	host->int_enable(host, emm_int.val);
-
-	emm_cmd.val = 0;
-	emm_cmd.s.cmd_val = 1;
-	emm_cmd.s.ctype_xor = mods.ctype_xor;
-	emm_cmd.s.rtype_xor = mods.rtype_xor;
+	host->int_enable(host, MIO_EMM_INT_CMD_DONE | MIO_EMM_INT_CMD_ERR);
+
+	emm_cmd = FIELD_PREP(MIO_EMM_CMD_VAL, 1) |
+		  FIELD_PREP(MIO_EMM_CMD_CTYPE_XOR, mods.ctype_xor) |
+		  FIELD_PREP(MIO_EMM_CMD_RTYPE_XOR, mods.rtype_xor) |
+		  FIELD_PREP(MIO_EMM_CMD_BUS_ID, slot->bus_id) |
+		  FIELD_PREP(MIO_EMM_CMD_IDX, cmd->opcode) |
+		  FIELD_PREP(MIO_EMM_CMD_ARG, cmd->arg);
 	if (mmc_cmd_type(cmd) == MMC_CMD_ADTC)
-		emm_cmd.s.offset = 64 - ((cmd->data->blocks * cmd->data->blksz) / 8);
-	emm_cmd.s.bus_id = slot->bus_id;
-	emm_cmd.s.cmd_idx = cmd->opcode;
-	emm_cmd.s.arg = cmd->arg;
+		emm_cmd |= FIELD_PREP(MIO_EMM_CMD_OFFSET,
+				64 - ((cmd->data->blocks * cmd->data->blksz) / 8));
 
 	writeq(0, host->base + MIO_EMM_STS_MASK(host));
 
 retry:
-	rsp_sts.val = readq(host->base + MIO_EMM_RSP_STS(host));
-	if (rsp_sts.s.dma_val || rsp_sts.s.cmd_val ||
-	    rsp_sts.s.switch_val || rsp_sts.s.dma_pend) {
+	rsp_sts = readq(host->base + MIO_EMM_RSP_STS(host));
+	if (rsp_sts & MIO_EMM_RSP_STS_DMA_VAL ||
+	    rsp_sts & MIO_EMM_RSP_STS_CMD_VAL ||
+	    rsp_sts & MIO_EMM_RSP_STS_SWITCH_VAL ||
+	    rsp_sts & MIO_EMM_RSP_STS_DMA_PEND) {
 		udelay(10);
 		if (--retries)
 			goto retry;
 	}
 	if (!retries)
-		dev_err(host->dev, "Bad status: %Lx before command write\n", rsp_sts.val);
-	writeq(emm_cmd.val, host->base + MIO_EMM_CMD(host));
+		dev_err(host->dev, "Bad status: %Lx before command write\n", rsp_sts);
+	writeq(emm_cmd, host->base + MIO_EMM_CMD(host));
 }
 
 static void cvm_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
@@ -809,8 +798,7 @@ static void cvm_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 	struct cvm_mmc_slot *slot = mmc_priv(mmc);
 	struct cvm_mmc_host *host = slot->host;
 	int clk_period = 0, power_class = 10, bus_width = 0;
-	union mio_emm_switch emm_switch;
-	u64 clock;
+	u64 clock, emm_switch;
 
 	host->acquire_bus(host);
 	cvm_mmc_switch_to(slot);
@@ -865,20 +853,20 @@ static void cvm_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 	if (clock)
 		clk_period = (host->sys_freq + clock - 1) / (2 * clock);
 
-	emm_switch.val = 0;
-	emm_switch.s.hs_timing = (ios->timing == MMC_TIMING_MMC_HS);
-	emm_switch.s.bus_width = bus_width;
-	emm_switch.s.power_class = power_class;
-	emm_switch.s.clk_hi = clk_period;
-	emm_switch.s.clk_lo = clk_period;
-	emm_switch.s.bus_id = slot->bus_id;
+	emm_switch = FIELD_PREP(MIO_EMM_SWITCH_HS_TIMING,
+				(ios->timing == MMC_TIMING_MMC_HS)) |
+		     FIELD_PREP(MIO_EMM_SWITCH_BUS_WIDTH, bus_width) |
+		     FIELD_PREP(MIO_EMM_SWITCH_POWER_CLASS, power_class) |
+		     FIELD_PREP(MIO_EMM_SWITCH_CLK_HI, clk_period) |
+		     FIELD_PREP(MIO_EMM_SWITCH_CLK_LO, clk_period) |
+		     FIELD_PREP(MIO_EMM_SWITCH_BUS_ID, slot->bus_id);
 
-	if (!switch_val_changed(slot, emm_switch.val))
+	if (!switch_val_changed(slot, emm_switch))
 		goto out;
 
 	set_wdog(slot, 0);
-	do_switch(host, emm_switch.val);
-	slot->cached_switch = emm_switch.val;
+	do_switch(host, emm_switch);
+	slot->cached_switch = emm_switch;
 out:
 	host->release_bus(host);
 }
@@ -902,7 +890,7 @@ static void cvm_mmc_set_clock(struct cvm_mmc_slot *slot, unsigned int clock)
 static int cvm_mmc_init_lowlevel(struct cvm_mmc_slot *slot)
 {
 	struct cvm_mmc_host *host = slot->host;
-	union mio_emm_switch emm_switch;
+	u64 emm_switch;
 
 	/* Enable this bus slot. */
 	host->emm_cfg |= (1ull << slot->bus_id);
@@ -911,16 +899,17 @@ static int cvm_mmc_init_lowlevel(struct cvm_mmc_slot *slot)
 
 	/* Program initial clock speed and power. */
 	cvm_mmc_set_clock(slot, slot->mmc->f_min);
-	emm_switch.val = 0;
-	emm_switch.s.power_class = 10;
-	emm_switch.s.clk_hi = (host->sys_freq / slot->clock) / 2;
-	emm_switch.s.clk_lo = (host->sys_freq / slot->clock) / 2;
+	emm_switch = FIELD_PREP(MIO_EMM_SWITCH_POWER_CLASS, 10);
+	emm_switch |= FIELD_PREP(MIO_EMM_SWITCH_CLK_HI,
+				 (host->sys_freq / slot->clock) / 2);
+	emm_switch |= FIELD_PREP(MIO_EMM_SWITCH_CLK_LO,
+				 (host->sys_freq / slot->clock) / 2);
 
 	/* Make the changes take effect on this bus slot. */
-	emm_switch.s.bus_id = slot->bus_id;
-	do_switch(host, emm_switch.val);
+	emm_switch |= FIELD_PREP(MIO_EMM_SWITCH_BUS_ID, slot->bus_id);
+	do_switch(host, emm_switch);
 
-	slot->cached_switch = emm_switch.val;
+	slot->cached_switch = emm_switch;
 
 	/*
 	 * Set watchdog timeout value and default reset value
diff --git a/drivers/mmc/host/cavium-mmc.h b/drivers/mmc/host/cavium-mmc.h
index 007f812..54aae61 100644
--- a/drivers/mmc/host/cavium-mmc.h
+++ b/drivers/mmc/host/cavium-mmc.h
@@ -7,6 +7,7 @@
  *
  * Copyright (C) 2012-2017 Cavium Inc.
  */
+#include <linux/bitops.h>
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/mmc/host.h>
@@ -110,284 +111,94 @@ struct cvm_mmc_cr_mods {
 
 /* Bitfield definitions */
 
-union mio_emm_dma_fifo_cfg {
-	u64 val;
-	struct mio_emm_dma_fifo_cfg_s {
-#ifdef __BIG_ENDIAN_BITFIELD
-		u64 :48;
-		u64 clr:1;
-		u64 :3;
-		u64 int_lvl:4;
-		u64 :3;
-		u64 count:5;
-#else
-		u64 count:5;
-		u64 :3;
-		u64 int_lvl:4;
-		u64 :3;
-		u64 clr:1;
-		u64 :48;
-#endif
-	} s;
-};
-
-union mio_emm_dma_fifo_cmd {
-	u64 val;
-	struct mio_emm_dma_fifo_cmd_s {
-#ifdef __BIG_ENDIAN_BITFIELD
-		u64 :1;
-		u64 rw:1;
-		u64 :1;
-		u64 intdis:1;
-		u64 swap32:1;
-		u64 swap16:1;
-		u64 swap8:1;
-		u64 endian:1;
-		u64 size:20;
-		u64 :36;
-#else
-		u64 :36;
-		u64 size:20;
-		u64 endian:1;
-		u64 swap8:1;
-		u64 swap16:1;
-		u64 swap32:1;
-		u64 intdis:1;
-		u64 :1;
-		u64 rw:1;
-		u64 :1;
-#endif
-	} s;
-};
-
-union mio_emm_cmd {
-	u64 val;
-	struct mio_emm_cmd_s {
-#ifdef __BIG_ENDIAN_BITFIELD
-		u64 :2;
-		u64 bus_id:2;
-		u64 cmd_val:1;
-		u64 :3;
-		u64 dbuf:1;
-		u64 offset:6;
-		u64 :6;
-		u64 ctype_xor:2;
-		u64 rtype_xor:3;
-		u64 cmd_idx:6;
-		u64 arg:32;
-#else
-		u64 arg:32;
-		u64 cmd_idx:6;
-		u64 rtype_xor:3;
-		u64 ctype_xor:2;
-		u64 :6;
-		u64 offset:6;
-		u64 dbuf:1;
-		u64 :3;
-		u64 cmd_val:1;
-		u64 bus_id:2;
-		u64 :2;
-#endif
-	} s;
-};
-
-union mio_emm_dma {
-	u64 val;
-	struct mio_emm_dma_s {
-#ifdef __BIG_ENDIAN_BITFIELD
-		u64 :2;
-		u64 bus_id:2;
-		u64 dma_val:1;
-		u64 sector:1;
-		u64 dat_null:1;
-		u64 thres:6;
-		u64 rel_wr:1;
-		u64 rw:1;
-		u64 multi:1;
-		u64 block_cnt:16;
-		u64 card_addr:32;
-#else
-		u64 card_addr:32;
-		u64 block_cnt:16;
-		u64 multi:1;
-		u64 rw:1;
-		u64 rel_wr:1;
-		u64 thres:6;
-		u64 dat_null:1;
-		u64 sector:1;
-		u64 dma_val:1;
-		u64 bus_id:2;
-		u64 :2;
-#endif
-	} s;
-};
-
-union mio_emm_dma_cfg {
-	u64 val;
-	struct mio_emm_dma_cfg_s {
-#ifdef __BIG_ENDIAN_BITFIELD
-		u64 en:1;
-		u64 rw:1;
-		u64 clr:1;
-		u64 :1;
-		u64 swap32:1;
-		u64 swap16:1;
-		u64 swap8:1;
-		u64 endian:1;
-		u64 size:20;
-		u64 adr:36;
-#else
-		u64 adr:36;
-		u64 size:20;
-		u64 endian:1;
-		u64 swap8:1;
-		u64 swap16:1;
-		u64 swap32:1;
-		u64 :1;
-		u64 clr:1;
-		u64 rw:1;
-		u64 en:1;
-#endif
-	} s;
-};
-
-union mio_emm_int {
-	u64 val;
-	struct mio_emm_int_s {
-#ifdef __BIG_ENDIAN_BITFIELD
-		u64 :57;
-		u64 switch_err:1;
-		u64 switch_done:1;
-		u64 dma_err:1;
-		u64 cmd_err:1;
-		u64 dma_done:1;
-		u64 cmd_done:1;
-		u64 buf_done:1;
-#else
-		u64 buf_done:1;
-		u64 cmd_done:1;
-		u64 dma_done:1;
-		u64 cmd_err:1;
-		u64 dma_err:1;
-		u64 switch_done:1;
-		u64 switch_err:1;
-		u64 :57;
-#endif
-	} s;
-};
-
-union mio_emm_rsp_sts {
-	u64 val;
-	struct mio_emm_rsp_sts_s {
-#ifdef __BIG_ENDIAN_BITFIELD
-		u64 :2;
-		u64 bus_id:2;
-		u64 cmd_val:1;
-		u64 switch_val:1;
-		u64 dma_val:1;
-		u64 dma_pend:1;
-		u64 :27;
-		u64 dbuf_err:1;
-		u64 :4;
-		u64 dbuf:1;
-		u64 blk_timeout:1;
-		u64 blk_crc_err:1;
-		u64 rsp_busybit:1;
-		u64 stp_timeout:1;
-		u64 stp_crc_err:1;
-		u64 stp_bad_sts:1;
-		u64 stp_val:1;
-		u64 rsp_timeout:1;
-		u64 rsp_crc_err:1;
-		u64 rsp_bad_sts:1;
-		u64 rsp_val:1;
-		u64 rsp_type:3;
-		u64 cmd_type:2;
-		u64 cmd_idx:6;
-		u64 cmd_done:1;
-#else
-		u64 cmd_done:1;
-		u64 cmd_idx:6;
-		u64 cmd_type:2;
-		u64 rsp_type:3;
-		u64 rsp_val:1;
-		u64 rsp_bad_sts:1;
-		u64 rsp_crc_err:1;
-		u64 rsp_timeout:1;
-		u64 stp_val:1;
-		u64 stp_bad_sts:1;
-		u64 stp_crc_err:1;
-		u64 stp_timeout:1;
-		u64 rsp_busybit:1;
-		u64 blk_crc_err:1;
-		u64 blk_timeout:1;
-		u64 dbuf:1;
-		u64 :4;
-		u64 dbuf_err:1;
-		u64 :27;
-		u64 dma_pend:1;
-		u64 dma_val:1;
-		u64 switch_val:1;
-		u64 cmd_val:1;
-		u64 bus_id:2;
-		u64 :2;
-#endif
-	} s;
-};
-
-union mio_emm_sample {
-	u64 val;
-	struct mio_emm_sample_s {
-#ifdef __BIG_ENDIAN_BITFIELD
-		u64 :38;
-		u64 cmd_cnt:10;
-		u64 :6;
-		u64 dat_cnt:10;
-#else
-		u64 dat_cnt:10;
-		u64 :6;
-		u64 cmd_cnt:10;
-		u64 :38;
-#endif
-	} s;
-};
-
-union mio_emm_switch {
-	u64 val;
-	struct mio_emm_switch_s {
-#ifdef __BIG_ENDIAN_BITFIELD
-		u64 :2;
-		u64 bus_id:2;
-		u64 switch_exe:1;
-		u64 switch_err0:1;
-		u64 switch_err1:1;
-		u64 switch_err2:1;
-		u64 :7;
-		u64 hs_timing:1;
-		u64 :5;
-		u64 bus_width:3;
-		u64 :4;
-		u64 power_class:4;
-		u64 clk_hi:16;
-		u64 clk_lo:16;
-#else
-		u64 clk_lo:16;
-		u64 clk_hi:16;
-		u64 power_class:4;
-		u64 :4;
-		u64 bus_width:3;
-		u64 :5;
-		u64 hs_timing:1;
-		u64 :7;
-		u64 switch_err2:1;
-		u64 switch_err1:1;
-		u64 switch_err0:1;
-		u64 switch_exe:1;
-		u64 bus_id:2;
-		u64 :2;
-#endif
-	} s;
-};
+#define MIO_EMM_DMA_FIFO_CFG_CLR	BIT_ULL(16)
+#define MIO_EMM_DMA_FIFO_CFG_INT_LVL	GENMASK_ULL(12, 8)
+#define MIO_EMM_DMA_FIFO_CFG_COUNT	GENMASK_ULL(4, 0)
+
+#define MIO_EMM_DMA_FIFO_CMD_RW		BIT_ULL(62)
+#define MIO_EMM_DMA_FIFO_CMD_INTDIS	BIT_ULL(60)
+#define MIO_EMM_DMA_FIFO_CMD_SWAP32	BIT_ULL(59)
+#define MIO_EMM_DMA_FIFO_CMD_SWAP16	BIT_ULL(58)
+#define MIO_EMM_DMA_FIFO_CMD_SWAP8	BIT_ULL(57)
+#define MIO_EMM_DMA_FIFO_CMD_ENDIAN	BIT_ULL(56)
+#define MIO_EMM_DMA_FIFO_CMD_SIZE	GENMASK_ULL(55,36)
+
+#define MIO_EMM_CMD_SKIP_BUSY	BIT_ULL(62)
+#define MIO_EMM_CMD_BUS_ID	GENMASK_ULL(61, 60)
+#define MIO_EMM_CMD_VAL		BIT_ULL(59)
+#define MIO_EMM_CMD_DBUF	BIT_ULL(55)
+#define MIO_EMM_CMD_OFFSET	GENMASK_ULL(54, 49)
+#define MIO_EMM_CMD_CTYPE_XOR	GENMASK_ULL(42, 41)
+#define MIO_EMM_CMD_RTYPE_XOR	GENMASK_ULL(40, 38)
+#define MIO_EMM_CMD_IDX		GENMASK_ULL(37, 32)
+#define MIO_EMM_CMD_ARG		GENMASK_ULL(31, 0)
+
+#define MIO_EMM_DMA_SKIP_BUSY	BIT_ULL(62)
+#define MIO_EMM_DMA_BUS_ID	GENMASK_ULL(61, 60)
+#define MIO_EMM_DMA_VAL		BIT_ULL(59)
+#define MIO_EMM_DMA_SECTOR	BIT_ULL(58)
+#define MIO_EMM_DMA_DAT_NULL	BIT_ULL(57)
+#define MIO_EMM_DMA_THRES	GENMASK_ULL(56, 51)
+#define MIO_EMM_DMA_REL_WR	BIT_ULL(50)
+#define MIO_EMM_DMA_RW		BIT_ULL(49)
+#define MIO_EMM_DMA_MULTI	BIT_ULL(48)
+#define MIO_EMM_DMA_BLOCK_CNT	GENMASK_ULL(47, 32)
+#define MIO_EMM_DMA_CARD_ADDR	GENMASK_ULL(31, 0)
+
+#define MIO_EMM_DMA_CFG_EN	BIT_ULL(63)
+#define MIO_EMM_DMA_CFG_RW	BIT_ULL(62)
+#define MIO_EMM_DMA_CFG_CLR	BIT_ULL(61)
+#define MIO_EMM_DMA_CFG_SWAP32	BIT_ULL(59)
+#define MIO_EMM_DMA_CFG_SWAP16	BIT_ULL(58)
+#define MIO_EMM_DMA_CFG_SWAP8	BIT_ULL(57)
+#define MIO_EMM_DMA_CFG_ENDIAN	BIT_ULL(56)
+#define MIO_EMM_DMA_CFG_SIZE	GENMASK_ULL(55, 36)
+#define MIO_EMM_DMA_CFG_ADR	GENMASK_ULL(35, 0)
+
+#define MIO_EMM_INT_SWITCH_ERR	BIT_ULL(6)
+#define MIO_EMM_INT_SWITCH_DONE	BIT_ULL(5)
+#define MIO_EMM_INT_DMA_ERR	BIT_ULL(4)
+#define MIO_EMM_INT_CMD_ERR	BIT_ULL(3)
+#define MIO_EMM_INT_DMA_DONE	BIT_ULL(2)
+#define MIO_EMM_INT_CMD_DONE	BIT_ULL(1)
+#define MIO_EMM_INT_BUF_DONE	BIT_ULL(0)
+
+#define MIO_EMM_RSP_STS_BUS_ID		GENMASK_ULL(61, 60)
+#define MIO_EMM_RSP_STS_CMD_VAL		BIT_ULL(59)
+#define MIO_EMM_RSP_STS_SWITCH_VAL	BIT_ULL(58)
+#define MIO_EMM_RSP_STS_DMA_VAL		BIT_ULL(57)
+#define MIO_EMM_RSP_STS_DMA_PEND	BIT_ULL(56)
+#define MIO_EMM_RSP_STS_DBUF_ERR	BIT_ULL(28)
+#define MIO_EMM_RSP_STS_DBUF		BIT_ULL(23)
+#define MIO_EMM_RSP_STS_BLK_TIMEOUT	BIT_ULL(22)
+#define MIO_EMM_RSP_STS_BLK_CRC_ERR	BIT_ULL(21)
+#define MIO_EMM_RSP_STS_RSP_BUSYBIT	BIT_ULL(20)
+#define MIO_EMM_RSP_STS_STP_TIMEOUT	BIT_ULL(19)
+#define MIO_EMM_RSP_STS_STP_CRC_ERR	BIT_ULL(18)
+#define MIO_EMM_RSP_STS_STP_BAD_STS	BIT_ULL(17)
+#define MIO_EMM_RSP_STS_STP_VAL		BIT_ULL(16)
+#define MIO_EMM_RSP_STS_RSP_TIMEOUT	BIT_ULL(15)
+#define MIO_EMM_RSP_STS_RSP_CRC_ERR	BIT_ULL(14)
+#define MIO_EMM_RSP_STS_RSP_BAD_STS	BIT_ULL(13)
+#define MIO_EMM_RSP_STS_RSP_VAL		BIT_ULL(12)
+#define MIO_EMM_RSP_STS_RSP_TYPE	GENMASK_ULL(11, 9)
+#define MIO_EMM_RSP_STS_CMD_TYPE	GENMASK_ULL(8, 7)
+#define MIO_EMM_RSP_STS_CMD_IDX		GENMASK_ULL(6, 1)
+#define MIO_EMM_RSP_STS_CMD_DONE	BIT_ULL(0)
+
+#define MIO_EMM_SAMPLE_CMD_CNT		GENMASK_ULL(25, 16)
+#define MIO_EMM_SAMPLE_DAT_CNT		GENMASK_ULL(9, 0)
+
+#define MIO_EMM_SWITCH_BUS_ID		GENMASK_ULL(61, 60)
+#define MIO_EMM_SWITCH_EXE		BIT_ULL(59)
+#define MIO_EMM_SWITCH_ERR0		BIT_ULL(58)
+#define MIO_EMM_SWITCH_ERR1		BIT_ULL(57)
+#define MIO_EMM_SWITCH_ERR2		BIT_ULL(56)
+#define MIO_EMM_SWITCH_HS_TIMING	BIT_ULL(48)
+#define MIO_EMM_SWITCH_BUS_WIDTH	GENMASK_ULL(42, 40)
+#define MIO_EMM_SWITCH_POWER_CLASS	GENMASK_ULL(35, 32)
+#define MIO_EMM_SWITCH_CLK_HI		GENMASK_ULL(31, 16)
+#define MIO_EMM_SWITCH_CLK_LO		GENMASK_ULL(15, 0)
 
 /* Protoypes */
 irqreturn_t cvm_mmc_interrupt(int irq, void *dev_id);
diff --git a/drivers/mmc/host/cavium-pci-thunderx.c b/drivers/mmc/host/cavium-pci-thunderx.c
index 8564612..7dc626a 100644
--- a/drivers/mmc/host/cavium-pci-thunderx.c
+++ b/drivers/mmc/host/cavium-pci-thunderx.c
@@ -155,7 +155,7 @@ static int thunder_mmc_probe(struct pci_dev *pdev,
 static void thunder_mmc_remove(struct pci_dev *pdev)
 {
 	struct cvm_mmc_host *host = pci_get_drvdata(pdev);
-	union mio_emm_dma_cfg dma_cfg;
+	u64 dma_cfg;
 	int i;
 
 	for (i = 0; i < CAVIUM_MAX_MMC; i++)
@@ -164,9 +164,9 @@ static void thunder_mmc_remove(struct pci_dev *pdev)
 			platform_device_del(slot_pdev[i]);
 		}
 
-	dma_cfg.val = readq(host->dma_base + MIO_EMM_DMA_CFG(host));
-	dma_cfg.s.en = 0;
-	writeq(dma_cfg.val, host->dma_base + MIO_EMM_DMA_CFG(host));
+	dma_cfg = readq(host->dma_base + MIO_EMM_DMA_CFG(host));
+	dma_cfg &= ~MIO_EMM_DMA_CFG_EN;
+	writeq(dma_cfg, host->dma_base + MIO_EMM_DMA_CFG(host));
 
 	clk_disable_unprepare(host->clk);
 }

^ permalink raw reply related	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2017-03-08 17:54 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-02-06 13:39 [PATCH v11 0/9] Cavium MMC driver Jan Glauber
2017-02-06 13:39 ` [PATCH v11 1/9] dt-bindings: mmc: Add Cavium SOCs MMC bindings Jan Glauber
2017-02-09  0:40   ` Rob Herring
2017-03-03 11:47   ` Ulf Hansson
2017-03-06 11:09     ` Jan Glauber
2017-02-06 13:39 ` [PATCH v11 2/9] mmc: cavium: Add core MMC driver for Cavium SOCs Jan Glauber
2017-03-03 11:47   ` Ulf Hansson
2017-03-03 18:39     ` David Daney
2017-03-07 10:49     ` Jan Glauber
2017-03-08  9:45       ` Ulf Hansson
2017-03-08 17:52         ` Jan Glauber
2017-02-06 13:39 ` [PATCH v11 3/9] mmc: cavium: Add MMC platform driver for Octeon SOCs Jan Glauber
2017-02-06 13:39 ` [PATCH v11 4/9] mmc: cavium: Work-around hardware bug on cn6xxx and cnf7xxx Jan Glauber
2017-02-06 13:39 ` [PATCH v11 5/9] mmc: cavium: Add support for Octeon cn7890 Jan Glauber
2017-02-06 13:39 ` [PATCH v11 6/9] mmc: cavium: Add MMC PCI driver for ThunderX SOCs Jan Glauber
2017-02-12  1:09   ` kbuild test robot
2017-02-13 15:24     ` Jan Glauber
2017-02-13 15:45       ` Ulf Hansson
2017-02-15 12:34         ` Arnd Bergmann
2017-02-15 13:54           ` Jan Glauber
2017-02-06 13:39 ` [PATCH v11 7/9] mmc: cavium: Add scatter-gather DMA support Jan Glauber
2017-02-12  1:27   ` kbuild test robot
2017-02-06 13:39 ` [PATCH v11 8/9] mmc: cavium: Support DDR mode for eMMC devices Jan Glauber
2017-02-06 13:39 ` [PATCH v11 9/9] MAINTAINERS: Add entry for Cavium MMC driver Jan Glauber

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).