LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH 1/7] mmc: sdhci: add quirk for broken 3.0V support
From: Vincent Yang @ 2014-06-20  9:35 UTC (permalink / raw)
  To: chris, linux-mmc; +Cc: andy.green, anton, linuxppc-dev, Vincent.Yang, patches
In-Reply-To: <1403256928-11359-1-git-send-email-Vincent.Yang@tw.fujitsu.com>

This patch defines a quirk for platforms unable
to enable 3.0V support.
It is a preparation and will be used by Fujitsu
SDHCI controller f_sdh30 driver.

Signed-off-by: Vincent Yang <Vincent.Yang@tw.fujitsu.com>
---
 drivers/mmc/host/sdhci.c  | 3 +++
 include/linux/mmc/sdhci.h | 2 ++
 2 files changed, 5 insertions(+)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 47055f3..523075f 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -3069,6 +3069,9 @@ int sdhci_add_host(struct sdhci_host *host)
 	}
 #endif /* CONFIG_REGULATOR */
 
+	if (host->quirks2 & SDHCI_QUIRK2_NO_3_0_V)
+		caps[0] &= ~SDHCI_CAN_VDD_300;
+
 	/*
 	 * According to SD Host Controller spec v3.00, if the Host System
 	 * can afford more than 150mA, Host Driver should set XPC to 1. Also
diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
index 08abe99..cac0958 100644
--- a/include/linux/mmc/sdhci.h
+++ b/include/linux/mmc/sdhci.h
@@ -98,6 +98,8 @@ struct sdhci_host {
 #define SDHCI_QUIRK2_BROKEN_HS200			(1<<6)
 /* Controller does not support DDR50 */
 #define SDHCI_QUIRK2_BROKEN_DDR50			(1<<7)
+/* The system physically doesn't support 3.0v, even if the host does */
+#define SDHCI_QUIRK2_NO_3_0_V				(1<<8)
 
 	int irq;		/* Device IRQ */
 	void __iomem *ioaddr;	/* Mapped address */
-- 
1.9.0

^ permalink raw reply related

* [RFC PATCH 2/7] mmc: sdhci: add quirk for voltage switch callback
From: Vincent Yang @ 2014-06-20  9:35 UTC (permalink / raw)
  To: chris, linux-mmc; +Cc: andy.green, anton, linuxppc-dev, Vincent.Yang, patches
In-Reply-To: <1403256928-11359-1-git-send-email-Vincent.Yang@tw.fujitsu.com>

This patch defines a quirk to do a callback when
switching voltages so do controller-specific
actions.
It is a preparation and will be used by Fujitsu
SDHCI controller f_sdh30 driver.

Signed-off-by: Vincent Yang <Vincent.Yang@tw.fujitsu.com>
---
 drivers/mmc/host/sdhci.c  | 5 +++++
 drivers/mmc/host/sdhci.h  | 1 +
 include/linux/mmc/sdhci.h | 2 ++
 3 files changed, 8 insertions(+)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 523075f..98d996f 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1763,6 +1763,11 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
 		ctrl |= SDHCI_CTRL_VDD_180;
 		sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
 
+		/* Some controller need to do more when switching */
+		if ((host->quirks2 & SDHCI_QUIRK2_VOLTAGE_SWITCH) &&
+		    host->ops->voltage_switch)
+			host->ops->voltage_switch(host);
+
 		/* Wait for 5ms */
 		usleep_range(5000, 5500);
 
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 4a5cd5e..63c7a46 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -292,6 +292,7 @@ struct sdhci_ops {
 	void    (*adma_workaround)(struct sdhci_host *host, u32 intmask);
 	void	(*platform_init)(struct sdhci_host *host);
 	void    (*card_event)(struct sdhci_host *host);
+	void	(*voltage_switch)(struct sdhci_host *host);
 };
 
 #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
index cac0958..13ab139 100644
--- a/include/linux/mmc/sdhci.h
+++ b/include/linux/mmc/sdhci.h
@@ -100,6 +100,8 @@ struct sdhci_host {
 #define SDHCI_QUIRK2_BROKEN_DDR50			(1<<7)
 /* The system physically doesn't support 3.0v, even if the host does */
 #define SDHCI_QUIRK2_NO_3_0_V				(1<<8)
+/* Do a callback when switching voltages so do controller-specific actions */
+#define SDHCI_QUIRK2_VOLTAGE_SWITCH			(1<<9)
 
 	int irq;		/* Device IRQ */
 	void __iomem *ioaddr;	/* Mapped address */
-- 
1.9.0

^ permalink raw reply related

* [RFC PATCH 3/7] mmc: sdhci: add quirk for tuning work around
From: Vincent Yang @ 2014-06-20  9:35 UTC (permalink / raw)
  To: chris, linux-mmc; +Cc: andy.green, anton, linuxppc-dev, Vincent.Yang, patches
In-Reply-To: <1403256928-11359-1-git-send-email-Vincent.Yang@tw.fujitsu.com>

This patch defines a quirk for tuning work
around for some sdhci host controller. It sets
both SDHCI_CTRL_EXEC_TUNING and SDHCI_CTRL_TUNED_CLK
for tuning.
It is a preparation and will be used by Fujitsu
SDHCI controller f_sdh30 driver.

Signed-off-by: Vincent Yang <Vincent.Yang@tw.fujitsu.com>
---
 drivers/mmc/host/sdhci.c  | 2 ++
 include/linux/mmc/sdhci.h | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 98d996f..fe69cc5 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1867,6 +1867,8 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
 
 	ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
 	ctrl |= SDHCI_CTRL_EXEC_TUNING;
+	if (host->quirks2 & SDHCI_QUIRK2_TUNING_WORK_AROUND)
+		ctrl |= SDHCI_CTRL_TUNED_CLK;
 	sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
 
 	/*
diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
index 13ab139..5690a1f 100644
--- a/include/linux/mmc/sdhci.h
+++ b/include/linux/mmc/sdhci.h
@@ -102,6 +102,8 @@ struct sdhci_host {
 #define SDHCI_QUIRK2_NO_3_0_V				(1<<8)
 /* Do a callback when switching voltages so do controller-specific actions */
 #define SDHCI_QUIRK2_VOLTAGE_SWITCH			(1<<9)
+/* forced tuned clock */
+#define SDHCI_QUIRK2_TUNING_WORK_AROUND		(1<<10)
 
 	int irq;		/* Device IRQ */
 	void __iomem *ioaddr;	/* Mapped address */
-- 
1.9.0

^ permalink raw reply related

* [RFC PATCH 4/7] mmc: sdhci: add quirk for single block transactions
From: Vincent Yang @ 2014-06-20  9:35 UTC (permalink / raw)
  To: chris, linux-mmc; +Cc: andy.green, anton, linuxppc-dev, Vincent.Yang, patches
In-Reply-To: <1403256928-11359-1-git-send-email-Vincent.Yang@tw.fujitsu.com>

This patch defines a quirk to disable the block count
for single block transactions.
It is a preparation and will be used by Fujitsu
SDHCI controller f_sdh30 driver.

Signed-off-by: Vincent Yang <Vincent.Yang@tw.fujitsu.com>
---
 drivers/mmc/host/sdhci.c  | 8 +++++---
 include/linux/mmc/sdhci.h | 2 ++
 2 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index fe69cc5..21a29ae 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -876,7 +876,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
 static void sdhci_set_transfer_mode(struct sdhci_host *host,
 	struct mmc_command *cmd)
 {
-	u16 mode;
+	u16 mode = 0;
 	struct mmc_data *data = cmd->data;
 
 	if (data == NULL) {
@@ -889,9 +889,11 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host,
 
 	WARN_ON(!host->data);
 
-	mode = SDHCI_TRNS_BLK_CNT_EN;
+	if (!(host->quirks2 & SDHCI_QUIRK2_SUPPORT_SINGLE))
+		mode = SDHCI_TRNS_BLK_CNT_EN;
+
 	if (mmc_op_multi(cmd->opcode) || data->blocks > 1) {
-		mode |= SDHCI_TRNS_MULTI;
+		mode = SDHCI_TRNS_BLK_CNT_EN | SDHCI_TRNS_MULTI;
 		/*
 		 * If we are sending CMD23, CMD12 never gets sent
 		 * on successful completion (so no Auto-CMD12).
diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
index 5690a1f..ac645b9 100644
--- a/include/linux/mmc/sdhci.h
+++ b/include/linux/mmc/sdhci.h
@@ -104,6 +104,8 @@ struct sdhci_host {
 #define SDHCI_QUIRK2_VOLTAGE_SWITCH			(1<<9)
 /* forced tuned clock */
 #define SDHCI_QUIRK2_TUNING_WORK_AROUND		(1<<10)
+/* disable the block count for single block transactions */
+#define SDHCI_QUIRK2_SUPPORT_SINGLE			(1<<11)
 
 	int irq;		/* Device IRQ */
 	void __iomem *ioaddr;	/* Mapped address */
-- 
1.9.0

^ permalink raw reply related

* [RFC PATCH 5/7] mmc: sdhci: host: add new f_sdh30
From: Vincent Yang @ 2014-06-20  9:35 UTC (permalink / raw)
  To: chris, linux-mmc; +Cc: andy.green, anton, linuxppc-dev, Vincent.Yang, patches
In-Reply-To: <1403256928-11359-1-git-send-email-Vincent.Yang@tw.fujitsu.com>

This patch adds new host controller driver for
Fujitsu SDHCI controller f_sdh30.

Signed-off-by: Vincent Yang <Vincent.Yang@tw.fujitsu.com>
---
 .../devicetree/bindings/mmc/sdhci-fujitsu.txt      |  25 ++
 drivers/mmc/host/Kconfig                           |   7 +
 drivers/mmc/host/Makefile                          |   1 +
 drivers/mmc/host/sdhci_f_sdh30.c                   | 340 +++++++++++++++++++++
 drivers/mmc/host/sdhci_f_sdh30.h                   |  40 +++
 5 files changed, 413 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mmc/sdhci-fujitsu.txt
 create mode 100644 drivers/mmc/host/sdhci_f_sdh30.c
 create mode 100644 drivers/mmc/host/sdhci_f_sdh30.h

diff --git a/Documentation/devicetree/bindings/mmc/sdhci-fujitsu.txt b/Documentation/devicetree/bindings/mmc/sdhci-fujitsu.txt
new file mode 100644
index 0000000..b6704cd
--- /dev/null
+++ b/Documentation/devicetree/bindings/mmc/sdhci-fujitsu.txt
@@ -0,0 +1,25 @@
+* Fujitsu SDHCI controller
+
+This file documents differences between the core properties in mmc.txt
+and the properties used by the sdhci_f_sdh30 driver.
+
+Required properties:
+- compatible: "fujitsu,f_sdh30"
+
+Optional properties:
+- gpios: Specify gpios for controlling signal level
+- clocks: Specify clocks used by SDHCI controller
+- clock-names: Specify the clock-names to be used
+
+Example:
+
+	sdhci1: sdio@36600000 {
+		compatible = "fujitsu,f_sdh30";
+		reg = <0 0x36600000 0x1000>;
+		interrupts = <0 172 0x4>,
+			     <0 173 0x4>;
+		gpios = <&gpio0 7 0>;
+		clocks = <&clk_hdmi_2_0>, <&clk_hdmi_3_0>;
+		clock-names = "sd_sd4clk", "sd_bclk";
+	};
+
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 7fee224..a1f3207 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -281,6 +281,13 @@ config MMC_SDHCI_BCM2835
 	  This selects the BCM2835 SD/MMC controller. If you have a BCM2835
 	  platform with SD or MMC devices, say Y or M here.
 
+config MMC_SDHCI_F_SDH30
+	tristate "SDHCI support for Fujitsu Semiconductor F_SDH30"
+	depends on MMC_SDHCI && (ARCH_MB8AC0300 || ARCH_MB86S70)
+	help
+	  This selects the Secure Digital Host Controller Interface (SDHCI)
+	  Needed by some Fujitsu SoC for MMC / SD / SDIO support.
+	  If you have a controller with this interface, say Y or M here.
 	  If unsure, say N.
 
 config MMC_MOXART
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 7f81ddf..a4c89e5 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_MMC_SDHCI_PXAV3)	+= sdhci-pxav3.o
 obj-$(CONFIG_MMC_SDHCI_PXAV2)	+= sdhci-pxav2.o
 obj-$(CONFIG_MMC_SDHCI_S3C)	+= sdhci-s3c.o
 obj-$(CONFIG_MMC_SDHCI_SIRF)   	+= sdhci-sirf.o
+obj-$(CONFIG_MMC_SDHCI_F_SDH30)	+= sdhci_f_sdh30.o
 obj-$(CONFIG_MMC_SDHCI_SPEAR)	+= sdhci-spear.o
 obj-$(CONFIG_MMC_WBSD)		+= wbsd.o
 obj-$(CONFIG_MMC_AU1X)		+= au1xmmc.o
diff --git a/drivers/mmc/host/sdhci_f_sdh30.c b/drivers/mmc/host/sdhci_f_sdh30.c
new file mode 100644
index 0000000..d916c47
--- /dev/null
+++ b/drivers/mmc/host/sdhci_f_sdh30.c
@@ -0,0 +1,340 @@
+/*
+ * linux/drivers/mmc/host/sdhci_f_sdh30.c
+ *
+ * Copyright (C) 2013 - 2014 Fujitsu Semiconductor, Ltd
+ *              Vincent Yang <vincent.yang@tw.fujitsu.com>
+ * Copyright (C) 2014 Linaro Ltd  Andy Green <andy.green@linaro.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ */
+
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/mmc/sd.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/suspend.h>
+
+#include "sdhci.h"
+#include "sdhci-pltfm.h"
+#include "sdhci_f_sdh30.h"
+#include "../core/core.h"
+
+#define DRIVER_NAME "f_sdh30"
+
+
+struct f_sdhost_priv {
+	struct clk *clk_sd4;
+	struct clk *clk_b;
+	int gpio_select_1v8;
+	u32 vendor_hs200;
+	struct device *dev;
+};
+
+void sdhci_f_sdh30_soft_voltage_switch(struct sdhci_host *host)
+{
+	struct f_sdhost_priv *priv = sdhci_priv(host);
+	u32 ctrl = 0;
+
+	usleep_range(2500, 3000);
+	ctrl = sdhci_readl(host, F_SDH30_IO_CONTROL2);
+	ctrl |= F_SDH30_CRES_O_DN;
+	sdhci_writel(host, ctrl, F_SDH30_IO_CONTROL2);
+	ctrl |= F_SDH30_MSEL_O_1_8;
+	sdhci_writel(host, ctrl, F_SDH30_IO_CONTROL2);
+
+	if (gpio_is_valid(priv->gpio_select_1v8)) {
+		dev_info(priv->dev, "%s: setting gpio\n", __func__);
+		gpio_direction_output(priv->gpio_select_1v8, 0);
+	}
+
+	ctrl &= ~F_SDH30_CRES_O_DN;
+	sdhci_writel(host, ctrl, F_SDH30_IO_CONTROL2);
+	usleep_range(2500, 3000);
+
+	if (priv->vendor_hs200) {
+		dev_info(priv->dev, "%s: setting hs200\n", __func__);
+		ctrl = sdhci_readl(host, F_SDH30_ESD_CONTROL);
+		ctrl |= priv->vendor_hs200;
+		sdhci_writel(host, ctrl, F_SDH30_ESD_CONTROL);
+	}
+
+	ctrl = sdhci_readl(host, F_SDH30_TUNING_SETTING);
+	ctrl |= F_SDH30_CMD_CHK_DIS;
+	sdhci_writel(host, ctrl, F_SDH30_TUNING_SETTING);
+}
+
+unsigned int sdhci_f_sdh30_get_min_clock(struct sdhci_host *host)
+{
+	return F_SDH30_MIN_CLOCK;
+}
+
+void sdhci_f_sdh30_reset(struct sdhci_host *host, u8 mask)
+{
+	struct f_sdhost_priv *priv = sdhci_priv(host);
+
+	if (gpio_is_valid(priv->gpio_select_1v8))
+		gpio_direction_output(priv->gpio_select_1v8, 1);
+
+	if (sdhci_readw(host, SDHCI_CLOCK_CONTROL) == 0) {
+		sdhci_writew(host, 0xBC01, SDHCI_CLOCK_CONTROL);
+		mmiowb();
+	}
+
+	sdhci_reset(host, mask);
+}
+
+static const struct sdhci_ops sdhci_f_sdh30_ops = {
+	.voltage_switch = sdhci_f_sdh30_soft_voltage_switch,
+	.get_min_clock = sdhci_f_sdh30_get_min_clock,
+	.reset = sdhci_f_sdh30_reset,
+	.set_clock = sdhci_set_clock,
+	.set_bus_width = sdhci_set_bus_width,
+	.set_uhs_signaling = sdhci_set_uhs_signaling,
+};
+
+static int sdhci_f_sdh30_probe(struct platform_device *pdev)
+{
+	struct sdhci_host *host;
+	struct device *dev = &pdev->dev;
+	int irq, ctrl = 0, ret = 0;
+	struct f_sdhost_priv *priv;
+	u32 reg = 0, bus_width;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(dev, "%s: no irq specified\n", __func__);
+		ret = irq;
+		goto err;
+	}
+
+	host = sdhci_alloc_host(dev, sizeof(struct sdhci_host) +
+						sizeof(struct f_sdhost_priv));
+	if (IS_ERR(host)) {
+		dev_err(dev, "%s: host allocate error\n", __func__);
+		ret = -ENOMEM;
+		goto err;
+	}
+	priv = sdhci_priv(host);
+	priv->dev = dev;
+
+	host->quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC |
+		       SDHCI_QUIRK_INVERTED_WRITE_PROTECT;
+	host->quirks2 = SDHCI_QUIRK2_SUPPORT_SINGLE |
+			SDHCI_QUIRK2_NO_3_0_V |
+			SDHCI_QUIRK2_VOLTAGE_SWITCH |
+			SDHCI_QUIRK2_TUNING_WORK_AROUND;
+
+	if (!of_property_read_u32(pdev->dev.of_node, "vendor-hs200",
+				  &priv->vendor_hs200))
+		dev_info(dev, "Applying vendor-hs200 setting\n");
+	else
+		priv->vendor_hs200 = 0;
+
+	if (!of_property_read_u32(pdev->dev.of_node, "bus-width", &bus_width)) {
+		if (bus_width == 8) {
+			dev_info(dev, "Applying 8 bit bus width\n");
+			host->mmc->caps |= MMC_CAP_8_BIT_DATA;
+		}
+	}
+
+	host->hw_name = DRIVER_NAME;
+	host->ops = &sdhci_f_sdh30_ops;
+	host->irq = irq;
+
+	host->ioaddr = of_iomap(pdev->dev.of_node, 0);
+	if (!host->ioaddr) {
+		dev_err(dev, "%s: failed to remap registers\n", __func__);
+		ret = -ENXIO;
+		goto err_remap;
+	}
+
+	priv->clk_sd4 = of_clk_get(pdev->dev.of_node, 0);
+	if (!IS_ERR(priv->clk_sd4)) {
+		ret = clk_prepare_enable(priv->clk_sd4);
+		if (ret < 0) {
+			dev_err(dev, "Failed to enable sd4 clock: %d\n", ret);
+			goto err_clk1;
+		}
+	}
+	priv->clk_b = of_clk_get(pdev->dev.of_node, 1);
+	if (!IS_ERR(priv->clk_b)) {
+		ret = clk_prepare_enable(priv->clk_b);
+		if (ret < 0) {
+			dev_err(dev, "Failed to enable clk_b clock: %d\n", ret);
+			goto err_clk2;
+		}
+	}
+
+	/* optional */
+	priv->gpio_select_1v8 = of_get_gpio(pdev->dev.of_node, 0);
+	if (gpio_is_valid(priv->gpio_select_1v8)) {
+		ret = gpio_request(priv->gpio_select_1v8, "sdhci");
+		if (unlikely(ret)) {
+			dev_err(dev, " gpio %d request failed ",
+				priv->gpio_select_1v8);
+			goto err_gpio;
+		}
+		/* initially 3.3V */
+		ret = gpio_direction_output(priv->gpio_select_1v8, 1);
+		if (unlikely(ret)) {
+			dev_err(dev, "failed to set phy_enable gpio\n");
+			goto err_gpio;
+		}
+	}
+
+	ret = sdhci_add_host(host);
+	if (ret) {
+		dev_err(dev, "%s: host add error\n", __func__);
+		goto err_add_host;
+	}
+
+	platform_set_drvdata(pdev, host);
+
+#ifdef CONFIG_PM_RUNTIME
+	pm_runtime_enable(&pdev->dev);
+	ret = pm_runtime_get_sync(&pdev->dev);
+	if (ret < 0)
+		dev_err(dev, "Failed to pm_runtime_get_sync: %d\n", ret);
+#endif
+
+	/* init vendor specific regs */
+	ctrl = sdhci_readw(host, F_SDH30_AHB_CONFIG);
+	ctrl |= F_SDH30_SIN | F_SDH30_AHB_INCR_16 | F_SDH30_AHB_INCR_8 |
+		F_SDH30_AHB_INCR_4;
+	ctrl &= ~(F_SDH30_AHB_BIGED | F_SDH30_BUSLOCK_EN);
+	sdhci_writew(host, ctrl, F_SDH30_AHB_CONFIG);
+	mmiowb();
+
+	reg = sdhci_readl(host, F_SDH30_ESD_CONTROL);
+	sdhci_writel(host, reg & ~F_SDH30_EMMC_RST, F_SDH30_ESD_CONTROL);
+	msleep(20);
+	sdhci_writel(host, reg | F_SDH30_EMMC_RST, F_SDH30_ESD_CONTROL);
+	mmiowb();
+
+	return 0;
+
+err_add_host:
+	if (gpio_is_valid(priv->gpio_select_1v8)) {
+		gpio_direction_output(priv->gpio_select_1v8, 1);
+		gpio_free(priv->gpio_select_1v8);
+	}
+err_gpio:
+	clk_put(priv->clk_b);
+err_clk2:
+	clk_put(priv->clk_sd4);
+err_clk1:
+	iounmap(host->ioaddr);
+err_remap:
+	sdhci_free_host(host);
+err:
+	return ret;
+}
+
+static int sdhci_f_sdh30_remove(struct platform_device *pdev)
+{
+	struct sdhci_host *host = platform_get_drvdata(pdev);
+	struct f_sdhost_priv *priv = sdhci_priv(host);
+	struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	sdhci_remove_host(host, readl(host->ioaddr + SDHCI_INT_STATUS) ==
+			  0xffffffff);
+	iounmap(host->ioaddr);
+	release_mem_region(iomem->start, resource_size(iomem));
+
+	clk_disable_unprepare(priv->clk_sd4);
+	clk_disable_unprepare(priv->clk_b);
+
+	clk_put(priv->clk_b);
+	clk_put(priv->clk_sd4);
+
+	if (gpio_is_valid(priv->gpio_select_1v8)) {
+		gpio_direction_output(priv->gpio_select_1v8, 1);
+		gpio_free(priv->gpio_select_1v8);
+	}
+
+	sdhci_free_host(host);
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int sdhci_f_sdh30_suspend(struct device *dev)
+{
+	struct sdhci_host *host = dev_get_drvdata(dev);
+
+	return sdhci_suspend_host(host);
+}
+
+static int sdhci_f_sdh30_resume(struct device *dev)
+{
+	struct sdhci_host *host = dev_get_drvdata(dev);
+
+	return sdhci_resume_host(host);
+}
+#endif
+
+#ifdef CONFIG_PM_RUNTIME
+static int sdhci_f_sdh30_runtime_suspend(struct device *dev)
+{
+	struct sdhci_host *host = dev_get_drvdata(dev);
+
+	return sdhci_runtime_suspend_host(host);
+}
+
+static int sdhci_f_sdh30_runtime_resume(struct device *dev)
+{
+	struct sdhci_host *host = dev_get_drvdata(dev);
+
+	return sdhci_runtime_resume_host(host);
+}
+#endif
+
+#ifdef CONFIG_PM
+static const struct dev_pm_ops sdhci_f_sdh30_pmops = {
+	SET_SYSTEM_SLEEP_PM_OPS(sdhci_f_sdh30_suspend, sdhci_f_sdh30_resume)
+	SET_RUNTIME_PM_OPS(sdhci_f_sdh30_runtime_suspend,
+			   sdhci_f_sdh30_runtime_resume, NULL)
+};
+
+#define SDHCI_F_SDH30_PMOPS (&sdhci_f_sdh30_pmops)
+
+#else
+#define SDHCI_F_SDH30_PMOPS NULL
+#endif
+
+static const struct of_device_id f_sdh30_dt_ids[] = {
+	{ .compatible = "fujitsu,f_sdh30" },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, f_sdh30_dt_ids);
+
+static struct platform_driver sdhci_f_sdh30_driver = {
+	.driver = {
+		.name = DRIVER_NAME,
+		.owner = THIS_MODULE,
+		.of_match_table = f_sdh30_dt_ids,
+#ifdef CONFIG_PM_SLEEP
+		.pm	= SDHCI_F_SDH30_PMOPS,
+#endif
+	},
+	.probe	= sdhci_f_sdh30_probe,
+	.remove	= sdhci_f_sdh30_remove,
+};
+
+module_platform_driver(sdhci_f_sdh30_driver);
+
+MODULE_DESCRIPTION("F_SDH30 SD Card Controller driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("FUJITSU SEMICONDUCTOR LTD.");
+MODULE_ALIAS("platform: " DRIVER_NAME);
diff --git a/drivers/mmc/host/sdhci_f_sdh30.h b/drivers/mmc/host/sdhci_f_sdh30.h
new file mode 100644
index 0000000..50c51c9
--- /dev/null
+++ b/drivers/mmc/host/sdhci_f_sdh30.h
@@ -0,0 +1,40 @@
+/*
+ * linux/drivers/mmc/host/sdhci_f_sdh30.h
+ *
+ * Copyright (C) 2013 - 2014 Fujitsu Semiconductor, Ltd
+ *              Vincent Yang <vincent.yang@tw.fujitsu.com>
+ * Copyright (C) 2014 Linaro Ltd  Andy Green <andy.green@linaro.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ */
+
+#ifndef F_SDH30_H
+#define F_SDH30_H
+
+/* F_SDH30 extended Controller registers */
+#define F_SDH30_AHB_CONFIG		0x100
+#define  F_SDH30_AHB_BIGED		0x00000040
+#define  F_SDH30_BUSLOCK_DMA		0x00000020
+#define  F_SDH30_BUSLOCK_EN		0x00000010
+#define  F_SDH30_SIN			0x00000008
+#define  F_SDH30_AHB_INCR_16		0x00000004
+#define  F_SDH30_AHB_INCR_8		0x00000002
+#define  F_SDH30_AHB_INCR_4		0x00000001
+
+#define F_SDH30_TUNING_SETTING		0x108
+#define  F_SDH30_CMD_CHK_DIS		0x00010000
+
+#define F_SDH30_IO_CONTROL2		0x114
+#define  F_SDH30_CRES_O_DN		0x00080000
+#define  F_SDH30_MSEL_O_1_8		0x00040000
+
+#define F_SDH30_ESD_CONTROL		0x124
+#define  F_SDH30_EMMC_RST		0x00000002
+
+#define F_SDH30_CMD_DAT_DELAY		0x200
+
+#define F_SDH30_MIN_CLOCK		400000
+
+#endif
-- 
1.9.0

^ permalink raw reply related

* [RFC PATCH 6/7] mmc: core: hold SD Clock before CMD11 during Signal Voltage Switch Procedure
From: Vincent Yang @ 2014-06-20  9:35 UTC (permalink / raw)
  To: chris, linux-mmc; +Cc: andy.green, anton, linuxppc-dev, Vincent.Yang, patches
In-Reply-To: <1403256928-11359-1-git-send-email-Vincent.Yang@tw.fujitsu.com>

This patch is to fix an issue found on mb86s7x platforms.

[symptom]
There are some UHS-1 SD memory cards sometimes cannot be detected correctly,
e.g., Transcend 600x SDXC 64GB UHS-1 memory card.
During Signal Voltage Switch Procedure, failure to switch is indicated
by the card holding DAT[3:0] low.

[analysis]
According to SD Host Controller Simplified Specification Version 3.00
chapter 3.6.1, the Signal Voltage Switch Procedure should be:
(1) Check S18A; (2) Issue CMD11; (3) Check CMD 11 response;
(4) Stop providing SD clock; (5) Check DAT[3:0] should be 0000b;
(6) Set 1.8V Signal Enable; (7) Wait 5ms; (8) Check 1.8V Signal Enable;
(9) Provide SD Clock; (10) Wait 1ms; (11) Check DAT[3:0] should be 1111b;
(12) error handling

With CONFIG_MMC_CLKGATE=y, sometimes there is one more gating/un-gating
SD clock between (2) and (3). In this case, some UHS-1 SD cards will hold
DAT[3:0] 0000b at (11) and thus fails Signal Voltage Switch Procedure.

[solution]
By mmc_host_clk_hold() before CMD11, the additional gating/un-gating
SD clock between (2) and (3) can be prevented and thus no failure at (11).
It has been verified with many UHS-1 SD cards on mb86s7x platforms and
works correctly.

Signed-off-by: Vincent Yang <Vincent.Yang@tw.fujitsu.com>
---
 drivers/mmc/core/core.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 7dc0c85..764af63 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -1428,6 +1428,8 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, u32 ocr)
 		pr_warning("%s: cannot verify signal voltage switch\n",
 				mmc_hostname(host));
 
+	mmc_host_clk_hold(host);
+
 	cmd.opcode = SD_SWITCH_VOLTAGE;
 	cmd.arg = 0;
 	cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
@@ -1438,8 +1440,6 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, u32 ocr)
 
 	if (!mmc_host_is_spi(host) && (cmd.resp[0] & R1_ERROR))
 		return -EIO;
-
-	mmc_host_clk_hold(host);
 	/*
 	 * The card should drive cmd and dat[0:3] low immediately
 	 * after the response of cmd11, but wait 1 ms to be sure
-- 
1.9.0

^ permalink raw reply related

* [RFC PATCH 7/7] mmc: core: add manual resume capability
From: Vincent Yang @ 2014-06-20  9:35 UTC (permalink / raw)
  To: chris, linux-mmc; +Cc: andy.green, anton, linuxppc-dev, Vincent.Yang, patches
In-Reply-To: <1403256928-11359-1-git-send-email-Vincent.Yang@tw.fujitsu.com>

This patch adds manual resume for some embedded platforms with rootfs
stored in SD card. It references CONFIG_MMC_BLOCK_DEFERRED_RESUME in
kernel 3.10. It lets host controller driver to manually handle resume
by itself.

[symptom]
This issue is found on mb86s7x platforms with rootfs stored in SD card.
It failed to resume form STR suspend mode because SD card cannot be ready
in time. It take longer time (e.g., 600ms) to be ready for access.
The error log looks like below:

root@localhost:~# echo mem > /sys/power/state
[   30.441974] SUSPEND

SCB Firmware : Category 01 Version 02.03 Rev. 00_
    Config   : (no configuration)
root@localhost:~# [   30.702976] Buffer I/O error on device mmcblk1p2, logical block 31349
[   30.709678] Buffer I/O error on device mmcblk1p2, logical block 168073
[   30.716220] Buffer I/O error on device mmcblk1p2, logical block 168074
[   30.722759] Buffer I/O error on device mmcblk1p2, logical block 168075
[   30.729456] Buffer I/O error on device mmcblk1p2, logical block 31349
[   30.735916] Buffer I/O error on device mmcblk1p2, logical block 31350
[   30.742370] Buffer I/O error on device mmcblk1p2, logical block 31351
[   30.749025] Buffer I/O error on device mmcblk1p2, logical block 168075
[   30.755657] Buffer I/O error on device mmcblk1p2, logical block 31351
[   30.763130] Aborting journal on device mmcblk1p2-8.
[   30.768060] JBD2: Error -5 detected when updating journal superblock for mmcblk1p2-8.
[   30.776085] EXT4-fs error (device mmcblk1p2): ext4_journal_check_start:56: Detected aborted journal
[   30.785259] EXT4-fs (mmcblk1p2): Remounting filesystem read-only
[   31.370716] EXT4-fs error (device mmcblk1p2): ext4_find_entry:1309: inode #2490369: comm udevd: reading directory lblock 0
[   31.382485] EXT4-fs error (device mmcblk1p2): ext4_find_entry:1309: inode #1048577: comm udevd: reading directory lblock 0

[analysis]
In system resume path, mmc_sd_resume() is failed with error code -123
because at that time SD card is still not ready on mb86s7x platforms.

[solution]
In order to not blocking system resume path, this patch just sets a flag
MMC_BUSRESUME_MANUAL_RESUME when this error happened, and then host controller
driver can understand it by this flag. Then host controller driver have to
resume SD card manually and asynchronously.

Signed-off-by: Vincent Yang <Vincent.Yang@tw.fujitsu.com>
---
 drivers/mmc/core/core.c          |  4 ++
 drivers/mmc/core/sd.c            |  4 ++
 drivers/mmc/host/sdhci_f_sdh30.c | 89 ++++++++++++++++++++++++++++++++++++++++
 include/linux/mmc/host.h         | 14 +++++++
 4 files changed, 111 insertions(+)

diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 764af63..51fce49 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -2648,6 +2648,10 @@ int mmc_pm_notify(struct notifier_block *notify_block,
 	case PM_POST_RESTORE:
 
 		spin_lock_irqsave(&host->lock, flags);
+		if (mmc_bus_manual_resume(host)) {
+			spin_unlock_irqrestore(&host->lock, flags);
+			break;
+		}
 		host->rescan_disable = 0;
 		spin_unlock_irqrestore(&host->lock, flags);
 		_mmc_detect_change(host, 0, false);
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 0c44510..859390d 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -1133,6 +1133,10 @@ static int mmc_sd_resume(struct mmc_host *host)
 
 	if (!(host->caps & MMC_CAP_RUNTIME_RESUME)) {
 		err = _mmc_sd_resume(host);
+		if ((host->caps2 & MMC_CAP2_MANUAL_RESUME) && err)
+			mmc_set_bus_resume_policy(host, 1);
+		else
+			mmc_set_bus_resume_policy(host, 0);
 		pm_runtime_set_active(&host->card->dev);
 		pm_runtime_mark_last_busy(&host->card->dev);
 	}
diff --git a/drivers/mmc/host/sdhci_f_sdh30.c b/drivers/mmc/host/sdhci_f_sdh30.c
index d916c47..2ed6cac 100644
--- a/drivers/mmc/host/sdhci_f_sdh30.c
+++ b/drivers/mmc/host/sdhci_f_sdh30.c
@@ -30,6 +30,12 @@
 #include "../core/core.h"
 
 #define DRIVER_NAME "f_sdh30"
+#define RESUME_WAIT_COUNT	100
+#define RESUME_WAIT_TIME	50
+#define RESUME_WAIT_JIFFIES	msecs_to_jiffies(RESUME_DETECT_TIME)
+#define RESUME_DETECT_COUNT	16
+#define RESUME_DETECT_TIME	50
+#define RESUME_DETECT_JIFFIES	msecs_to_jiffies(RESUME_DETECT_TIME)
 
 
 struct f_sdhost_priv {
@@ -38,8 +44,59 @@ struct f_sdhost_priv {
 	int gpio_select_1v8;
 	u32 vendor_hs200;
 	struct device *dev;
+	unsigned int quirks;	/* Deviations from spec. */
+
+/* retry to detect mmc device when resume */
+#define F_SDH30_QUIRK_RESUME_DETECT_RETRY		(1<<0)
+
+	struct workqueue_struct *resume_detect_wq;
+	struct delayed_work resume_detect_work;
+	unsigned int		resume_detect_count;
+	unsigned int		resume_wait_count;
 };
 
+static void sdhci_f_sdh30_resume_detect_work_func(struct work_struct *work)
+{
+	struct f_sdhost_priv *priv = container_of(work, struct f_sdhost_priv,
+		resume_detect_work.work);
+	struct sdhci_host *host = dev_get_drvdata(priv->dev);
+	int err = 0;
+
+	if (mmc_bus_manual_resume(host->mmc)) {
+		pm_runtime_disable(&host->mmc->card->dev);
+		mmc_card_set_suspended(host->mmc->card);
+		err = host->mmc->bus_ops->resume(host->mmc);
+		if (priv->resume_detect_count-- && err)
+			queue_delayed_work(priv->resume_detect_wq,
+					   &priv->resume_detect_work,
+				RESUME_DETECT_JIFFIES);
+		else
+			pr_debug("%s: resume detection done (count:%d, wait:%d, err:%d)\n",
+				 mmc_hostname(host->mmc),
+				 priv->resume_detect_count,
+				 priv->resume_wait_count, err);
+	} else {
+		if (priv->resume_wait_count--)
+			queue_delayed_work(priv->resume_detect_wq,
+					   &priv->resume_detect_work,
+				RESUME_WAIT_JIFFIES);
+		else
+			pr_debug("%s: resume done\n", mmc_hostname(host->mmc));
+	}
+}
+
+static void sdhci_f_sdh30_resume_detect(struct mmc_host *mmc,
+					int detect, int wait)
+{
+	struct sdhci_host *host = mmc_priv(mmc);
+	struct f_sdhost_priv *priv = sdhci_priv(host);
+
+	priv->resume_detect_count = detect;
+	priv->resume_wait_count = wait;
+	queue_delayed_work(priv->resume_detect_wq,
+			   &priv->resume_detect_work, 0);
+}
+
 void sdhci_f_sdh30_soft_voltage_switch(struct sdhci_host *host)
 {
 	struct f_sdhost_priv *priv = sdhci_priv(host);
@@ -147,6 +204,12 @@ static int sdhci_f_sdh30_probe(struct platform_device *pdev)
 		}
 	}
 
+	if (of_find_property(pdev->dev.of_node, "resume-detect-retry", NULL)) {
+		dev_info(dev, "Applying resume detect retry quirk\n");
+		priv->quirks |= F_SDH30_QUIRK_RESUME_DETECT_RETRY;
+		host->mmc->caps2 |= MMC_CAP2_MANUAL_RESUME;
+	}
+
 	host->hw_name = DRIVER_NAME;
 	host->ops = &sdhci_f_sdh30_ops;
 	host->irq = irq;
@@ -192,6 +255,18 @@ static int sdhci_f_sdh30_probe(struct platform_device *pdev)
 		}
 	}
 
+	/* Init workqueue */
+	if (priv->quirks & F_SDH30_QUIRK_RESUME_DETECT_RETRY) {
+		priv->resume_detect_wq = create_workqueue("sdhci_f_sdh30");
+		if (priv->resume_detect_wq == NULL) {
+			ret = -ENOMEM;
+			dev_err(dev, "Failed to create resume detection workqueue\n");
+			goto err_init_wq;
+		}
+		INIT_DELAYED_WORK(&priv->resume_detect_work,
+				  sdhci_f_sdh30_resume_detect_work_func);
+	}
+
 	ret = sdhci_add_host(host);
 	if (ret) {
 		dev_err(dev, "%s: host add error\n", __func__);
@@ -224,6 +299,9 @@ static int sdhci_f_sdh30_probe(struct platform_device *pdev)
 	return 0;
 
 err_add_host:
+	if (priv->quirks & F_SDH30_QUIRK_RESUME_DETECT_RETRY)
+		destroy_workqueue(priv->resume_detect_wq);
+err_init_wq:
 	if (gpio_is_valid(priv->gpio_select_1v8)) {
 		gpio_direction_output(priv->gpio_select_1v8, 1);
 		gpio_free(priv->gpio_select_1v8);
@@ -262,6 +340,9 @@ static int sdhci_f_sdh30_remove(struct platform_device *pdev)
 		gpio_free(priv->gpio_select_1v8);
 	}
 
+	if (priv->quirks & F_SDH30_QUIRK_RESUME_DETECT_RETRY)
+		destroy_workqueue(priv->resume_detect_wq);
+
 	sdhci_free_host(host);
 	platform_set_drvdata(pdev, NULL);
 
@@ -279,7 +360,15 @@ static int sdhci_f_sdh30_suspend(struct device *dev)
 static int sdhci_f_sdh30_resume(struct device *dev)
 {
 	struct sdhci_host *host = dev_get_drvdata(dev);
+	struct f_sdhost_priv *priv = sdhci_priv(host);
 
+	if (priv->quirks & F_SDH30_QUIRK_RESUME_DETECT_RETRY) {
+		pr_debug("%s: start resume detect\n",
+			 mmc_hostname(host->mmc));
+		sdhci_f_sdh30_resume_detect(host->mmc,
+					    RESUME_DETECT_COUNT,
+					    RESUME_WAIT_COUNT);
+	}
 	return sdhci_resume_host(host);
 }
 #endif
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 7960424..55221dd 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -283,6 +283,7 @@ struct mmc_host {
 #define MMC_CAP2_HS400		(MMC_CAP2_HS400_1_8V | \
 				 MMC_CAP2_HS400_1_2V)
 #define MMC_CAP2_SDIO_IRQ_NOTHREAD (1 << 17)
+#define MMC_CAP2_MANUAL_RESUME     (1 << 18)	/* Resume manually when error */
 
 	mmc_pm_flag_t		pm_caps;	/* supported pm features */
 
@@ -338,6 +339,9 @@ struct mmc_host {
 	const struct mmc_bus_ops *bus_ops;	/* current bus driver */
 	unsigned int		bus_refs;	/* reference counter */
 
+	unsigned int		bus_resume_flags;
+#define MMC_BUSRESUME_MANUAL_RESUME	(1 << 0)
+
 	unsigned int		sdio_irqs;
 	struct task_struct	*sdio_irq_thread;
 	bool			sdio_irq_pending;
@@ -384,6 +388,16 @@ static inline void *mmc_priv(struct mmc_host *host)
 #define mmc_dev(x)	((x)->parent)
 #define mmc_classdev(x)	(&(x)->class_dev)
 #define mmc_hostname(x)	(dev_name(&(x)->class_dev))
+#define mmc_bus_manual_resume(host) ((host)->bus_resume_flags &		\
+	MMC_BUSRESUME_MANUAL_RESUME)
+
+static inline void mmc_set_bus_resume_policy(struct mmc_host *host, int manual)
+{
+	if (manual)
+		host->bus_resume_flags |= MMC_BUSRESUME_MANUAL_RESUME;
+	else
+		host->bus_resume_flags &= ~MMC_BUSRESUME_MANUAL_RESUME;
+}
 
 int mmc_power_save_host(struct mmc_host *host);
 int mmc_power_restore_host(struct mmc_host *host);
-- 
1.9.0

^ permalink raw reply related

* Re: [RFC PATCH 5/7] mmc: sdhci: host: add new f_sdh30
From: Arnd Bergmann @ 2014-06-20 10:00 UTC (permalink / raw)
  To: Vincent Yang
  Cc: andy.green, patches, anton, linux-mmc, chris, Vincent.Yang,
	linuxppc-dev
In-Reply-To: <1403256928-11359-6-git-send-email-Vincent.Yang@tw.fujitsu.com>

On Friday 20 June 2014 17:35:26 Vincent Yang wrote:
> +Required properties:
> +- compatible: "fujitsu,f_sdh30"
> +
> +Optional properties:
> +- gpios: Specify gpios for controlling signal level
> +- clocks: Specify clocks used by SDHCI controller
> +- clock-names: Specify the clock-names to be used

If you want to use "clock-names", you have to specify the exact names
of the clock input signals used by your device, and the order in which
they are listed.

For both the clocks and the gpios, you have to specify how many signals
there are, and ideally describe what they are used for. In case of a
gpio controlling the signal level, it may be better to model this
as a gpio-regulator device, depending on how exactly it is used.

When posting a DT binding document, please always add
devicetree@vger.kernel.org to Cc.

	Arnd

^ permalink raw reply

* Re: [RFC PATCH 5/7] mmc: sdhci: host: add new f_sdh30
From: Vincent Yang @ 2014-06-20 10:29 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Andy Green, patches, anton, linux-mmc, chris, Vincent Yang,
	linuxppc-dev
In-Reply-To: <5136245.WRbqGRMMHn@wuerfel>

Hi Arnd,
Thanks a lot for your review.
I will update it in next version.


Best regards,
Vincent Yang

2014-06-20 18:00 GMT+08:00 Arnd Bergmann <arnd@arndb.de>:
> On Friday 20 June 2014 17:35:26 Vincent Yang wrote:
>> +Required properties:
>> +- compatible: "fujitsu,f_sdh30"
>> +
>> +Optional properties:
>> +- gpios: Specify gpios for controlling signal level
>> +- clocks: Specify clocks used by SDHCI controller
>> +- clock-names: Specify the clock-names to be used
>
> If you want to use "clock-names", you have to specify the exact names
> of the clock input signals used by your device, and the order in which
> they are listed.
>
> For both the clocks and the gpios, you have to specify how many signals
> there are, and ideally describe what they are used for. In case of a
> gpio controlling the signal level, it may be better to model this
> as a gpio-regulator device, depending on how exactly it is used.
>
> When posting a DT binding document, please always add
> devicetree@vger.kernel.org to Cc.
>
>         Arnd

^ permalink raw reply

* Re: [PATCH] vfio: Fix endianness handling for emulated BARs
From: Alexey Kardashevskiy @ 2014-06-20 14:14 UTC (permalink / raw)
  To: Alex Williamson
  Cc: kvm, Nikunj A Dadhania, linux-kernel, Alexander Graf,
	linuxppc-dev
In-Reply-To: <1403234514.3707.278.camel@ul30vt.home>

On 06/20/2014 01:21 PM, Alex Williamson wrote:
> On Thu, 2014-06-19 at 13:48 +1000, Alexey Kardashevskiy wrote:
>> On 06/19/2014 11:50 AM, Alexey Kardashevskiy wrote:
>>> On 06/19/2014 10:50 AM, Alexey Kardashevskiy wrote:
>>>> On 06/19/2014 04:35 AM, Alex Williamson wrote:
>>>>> On Wed, 2014-06-18 at 21:36 +1000, Alexey Kardashevskiy wrote:
>>>>>> VFIO exposes BARs to user space as a byte stream so userspace can
>>>>>> read it using pread()/pwrite(). Since this is a byte stream, VFIO should
>>>>>> not do byte swapping and simply return values as it gets them from
>>>>>> PCI device.
>>>>>>
>>>>>> Instead, the existing code assumes that byte stream in read/write is
>>>>>> little-endian and it fixes endianness for values which it passes to
>>>>>> ioreadXX/iowriteXX helpers. This works for little-endian as PCI is
>>>>>> little endian and le32_to_cpu/... are stubs.
>>>>>
>>>>> vfio read32:
>>>>>
>>>>> val = cpu_to_le32(ioread32(io + off));
>>>>>
>>>>> Where the typical x86 case, ioread32 is:
>>>>>
>>>>> #define ioread32(addr)          readl(addr)
>>>>>
>>>>> and readl is:
>>>>>
>>>>> __le32_to_cpu(__raw_readl(addr));
>>>>>
>>>>> So we do canceling byte swaps, which are both nops on x86, and end up
>>>>> returning device endian, which we assume is little endian.
>>>>>
>>>>> vfio write32 is similar:
>>>>>
>>>>> iowrite32(le32_to_cpu(val), io + off);
>>>>>
>>>>> The implicit cpu_to_le32 of iowrite32() and our explicit swap cancel
>>>>> out, so input data is device endian, which is assumed little.
>>>>>
>>>>>> This also works for big endian but rather by an accident: it reads 4 bytes
>>>>>> from the stream (@val is big endian), converts to CPU format (which should
>>>>>> be big endian) as it was little endian (@val becomes actually little
>>>>>> endian) and calls iowrite32() which does not do swapping on big endian
>>>>>> system.
>>>>>
>>>>> Really?
>>>>>
>>>>> In arch/powerpc/kernel/iomap.c iowrite32() is just a wrapper around
>>>>> writel(), which seems to use the generic implementation, which does
>>>>> include a cpu_to_le32.
>>>>
>>>>
>>>> Ouch, wrong comment. iowrite32() does swapping. My bad.
>>>>
>>>>
>>>>>
>>>>> I also see other big endian archs like parisc doing cpu_to_le32 on
>>>>> iowrite32, so I don't think this statement is true.  I imagine it's
>>>>> probably working for you because the swap cancel.
>>>>>
>>>>>> This removes byte swapping and makes use ioread32be/iowrite32be
>>>>>> (and 16bit versions) on big-endian systems. The "be" helpers take
>>>>>> native endian values and do swapping at the moment of writing to a PCI
>>>>>> register using one of "store byte-reversed" instructions.
>>>>>
>>>>> So now you want iowrite32() on little endian and iowrite32be() on big
>>>>> endian, the former does a cpu_to_le32 (which is a nop on little endian)
>>>>> and the latter does a cpu_to_be32 (which is a nop on big endian)...
>>>>> should we just be using __raw_writel() on both?
>>>>
>>>>
>>>> We can do that too. The beauty of iowrite32be on ppc64 is that it does not
>>>> swap and write separately, it is implemented via the "Store Word
>>>> Byte-Reverse Indexed X-form" single instruction.
>>>>
>>>> And some archs (do not know which ones) may add memory barriers in their
>>>> implementations of ioread/iowrite. __raw_writel is too raw :)
>>>>
>>>>>  There doesn't actually
>>>>> seem to be any change in behavior here, it just eliminates back-to-back
>>>>> byte swaps, which are a nop on x86, but not power, right?
>>>>
>>>> Exactly. No dependency for QEMU.
>>>
>>> How about that:
>>> ===
>>>
>>> VFIO exposes BARs to user space as a byte stream so userspace can
>>> read it using pread()/pwrite(). Since this is a byte stream, VFIO should
>>> not do byte swapping and simply return values as it gets them from
>>> PCI device.
>>>
>>> Instead, the existing code assumes that byte stream in read/write is
>>> little-endian and it fixes endianness for values which it passes to
>>> ioreadXX/iowriteXX helpers in native format. The IO helpers do swapping
>>> again. Since both byte swaps are nops on little-endian host, this works.
>>>
>>> This also works for big endian but rather by an accident: it reads 4 bytes
>>> from the stream (@val is big endian), converts to CPU format (which should
>>> be big endian) as it was little endian (and @val becomes actually little
>>> endian) and calls iowrite32() which does swapping on big endian
>>> system again. So byte swap gets cancelled, __raw_writel() receives
>>> a native value and then
>>> *(volatile unsigned int __force *)PCI_FIX_ADDR(addr) = v;
>>> just does the right thing.
>>
>> I am wrong here, sorry. This is what happens when you watch soccer between
>> 2am and 4am :)
>>
>>
>>>
>>> This removes byte swaps and makes use of ioread32be/iowrite32be
>>> (and 16bit versions) which do explicit byte swapping at the moment
>>> of write to a PCI register. PPC64 uses a special "Store Word
>>> Byte-Reverse Indexed X-form" instruction which does swap and store.
>>
>> No swapping is done here if we use ioread32be as it calls in_be32 and that
>> animal does "lwz" which is simple load from memory.
>>
>> So @val (16/32 bit variable on stack) will have different values on LE and
>> BE but since we do not handle it the host and just memcpy it to the buffer,
>> nothing breaks here.
>>
>>
>> So it should be like this:
>> ===
>> VFIO exposes BARs to user space as a byte stream so userspace can
>> read it using pread()/pwrite(). Since this is a byte stream, VFIO should
>> not do byte swapping and simply return values as it gets them from
>> PCI device and copy_to_user will save bytes in the correct
>> same true for writes.
>>
>> Instead, the existing code assumes that byte stream in read/write is
>> little-endian and it fixes endianness for values which it passes to
>> ioreadXX/iowriteXX helpers in native format. The IO helpers do swapping
>> again. Since both byte swaps are nops on little-endian host, this works.
>>
>> This also works for big endian but rather by an accident: it reads 4 bytes
>> from the stream (@val is big endian), converts to CPU format (which should
>> be big endian) as it was little endian (and @val becomes actually little
>> endian) and calls iowrite32() which does swapping on big endian
>> system again. So byte swap in the host gets cancelled and __raw_writel()
>> writes the value which was swapped originally by the guest.
>>
>> This removes byte swaps and makes use of ioread32be/iowrite32be
>> (and 16bit versions) which do not do byte swap on BE hosts.
>> For LE hosts, ioread32/iowrite32 are still used.
>>
>> ===
> 
> Working on big endian being an accident may be a matter of perspective.
> The comment remains that this patch doesn't actually fix anything except
> the overhead on big endian systems doing redundant byte swapping and
> maybe the philosophy that vfio regions are little endian.


They are little-endian only between ioread32() and copy_to_user() calls,
besides that it is a bytes stream which does not have endianness so I do
not understand the comment about philosophy...


> I'm still not a fan of iowrite vs iowritebe, there must be something we
> can use that doesn't have an implicit swap.  Calling it iowrite*_native
> is also an abuse of the namespace.  Next thing we know some common code
> will legitimately use that name.  If we do need to define an alias
> (which I'd like to avoid) it should be something like vfio_iowrite32.


We can still use __raw_writel&co, would that be ok?



> Thanks,
> 
> Alex
> 
>>> ===
>>>
>>> any better?
>>>
>>>
>>>
>>>
>>>>>> Suggested-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
>>>>>> Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
>>>>>> ---
>>>>>>  drivers/vfio/pci/vfio_pci_rdwr.c | 20 ++++++++++++++++----
>>>>>>  1 file changed, 16 insertions(+), 4 deletions(-)
>>>>>>
>>>>>> diff --git a/drivers/vfio/pci/vfio_pci_rdwr.c b/drivers/vfio/pci/vfio_pci_rdwr.c
>>>>>> index 210db24..f363b5a 100644
>>>>>> --- a/drivers/vfio/pci/vfio_pci_rdwr.c
>>>>>> +++ b/drivers/vfio/pci/vfio_pci_rdwr.c
>>>>>> @@ -21,6 +21,18 @@
>>>>>>  
>>>>>>  #include "vfio_pci_private.h"
>>>>>>  
>>>>>> +#ifdef __BIG_ENDIAN__
>>>>>> +#define ioread16_native		ioread16be
>>>>>> +#define ioread32_native		ioread32be
>>>>>> +#define iowrite16_native	iowrite16be
>>>>>> +#define iowrite32_native	iowrite32be
>>>>>> +#else
>>>>>> +#define ioread16_native		ioread16
>>>>>> +#define ioread32_native		ioread32
>>>>>> +#define iowrite16_native	iowrite16
>>>>>> +#define iowrite32_native	iowrite32
>>>>>> +#endif
>>>>>> +
>>>>>>  /*
>>>>>>   * Read or write from an __iomem region (MMIO or I/O port) with an excluded
>>>>>>   * range which is inaccessible.  The excluded range drops writes and fills
>>>>>> @@ -50,9 +62,9 @@ static ssize_t do_io_rw(void __iomem *io, char __user *buf,
>>>>>>  				if (copy_from_user(&val, buf, 4))
>>>>>>  					return -EFAULT;
>>>>>>  
>>>>>> -				iowrite32(le32_to_cpu(val), io + off);
>>>>>> +				iowrite32_native(val, io + off);
>>>>>>  			} else {
>>>>>> -				val = cpu_to_le32(ioread32(io + off));
>>>>>> +				val = ioread32_native(io + off);
>>>>>>  
>>>>>>  				if (copy_to_user(buf, &val, 4))
>>>>>>  					return -EFAULT;
>>>>>> @@ -66,9 +78,9 @@ static ssize_t do_io_rw(void __iomem *io, char __user *buf,
>>>>>>  				if (copy_from_user(&val, buf, 2))
>>>>>>  					return -EFAULT;
>>>>>>  
>>>>>> -				iowrite16(le16_to_cpu(val), io + off);
>>>>>> +				iowrite16_native(val, io + off);
>>>>>>  			} else {
>>>>>> -				val = cpu_to_le16(ioread16(io + off));
>>>>>> +				val = ioread16_native(io + off);
>>>>>>  
>>>>>>  				if (copy_to_user(buf, &val, 2))
>>>>>>  					return -EFAULT;
>>>>>
>>>>>
>>>>>
>>>>
>>>>
>>>
>>>
>>
>>
> 
> 
> 


-- 
Alexey

^ permalink raw reply

* Re: [PATCH v2 2/2] flexcan: add err interrupt for p1010rdb
From: Scott Wood @ 2014-06-20 16:16 UTC (permalink / raw)
  To: Marc Kleine-Budde; +Cc: Zhao Qiang, B07421, linuxppc-dev, wg, linux-can
In-Reply-To: <53A3F660.4040807@pengutronix.de>

On Fri, 2014-06-20 at 10:52 +0200, Marc Kleine-Budde wrote:
> On 06/20/2014 04:01 AM, Zhao Qiang wrote:
> > add err interrupt for p1010rdb into dts.
> > 
> > Signed-off-by: Zhao Qiang <B45475@freescale.com>
> > ---
> > Changes for v2:
> > 	- add binding documentation update
> > 
> >  Documentation/devicetree/bindings/net/can/fsl-flexcan.txt | 7 +++++--
> >  arch/powerpc/boot/dts/fsl/p1010si-post.dtsi               | 6 ++++--
> >  2 files changed, 9 insertions(+), 4 deletions(-)
> > 
> > diff --git a/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt b/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt
> > index 56d6cc3..81929e5 100644
> > --- a/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt
> > +++ b/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt
> > @@ -10,7 +10,9 @@ Required properties:
> >    - fsl,p1010-flexcan
> >  
> >  - reg : Offset and length of the register set for this device
> > -- interrupts : Interrupt tuple for this device
> > +- interrupts : Interrupt tuple for this device.
> > +	The first interrupt is for FlexCAN(Message Buffer and Wake Up)
> > +	The second is for error(Shared with IFC, PEX1 and some other device)
> 
> The second interrupt is optional, at least on ARM we don't need it,
> please reflect this in the documentation update.

The binding also shouldn't specify that the interrupt is shared, much
less with specific things.  It's not relevant, and may not be
universally true.

-Scott

^ permalink raw reply

* Re: [PATCH v2 1/2] flexcan: add err_irq handler for flexcan
From: Scott Wood @ 2014-06-20 16:19 UTC (permalink / raw)
  To: Zhao Qiang; +Cc: B07421, mkl, linuxppc-dev, wg, linux-can
In-Reply-To: <1403229664-33912-1-git-send-email-B45475@freescale.com>

On Fri, 2014-06-20 at 10:01 +0800, Zhao Qiang wrote:
> when flexcan is not physically linked, command 'cantest' will
> trigger an err_irq, add err_irq handler for it.
> 
> Signed-off-by: Zhao Qiang <B45475@freescale.com>
> ---
> Changes for v2:
> 	- use a space instead of tab
> 	- use flexcan_poll_state instead of print
> 
>  drivers/net/can/flexcan.c | 31 ++++++++++++++++++++++++++++++-
>  1 file changed, 30 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c
> index f425ec2..7432ba4 100644
> --- a/drivers/net/can/flexcan.c
> +++ b/drivers/net/can/flexcan.c
> @@ -208,6 +208,7 @@ struct flexcan_priv {
>  	void __iomem *base;
>  	u32 reg_esr;
>  	u32 reg_ctrl_default;
> +	unsigned int err_irq;

Why unsigned?

> +static irqreturn_t flexcan_err_irq(int irq, void *dev_id)
> +{
> +	struct net_device *dev = dev_id;
> +	struct flexcan_priv *priv = netdev_priv(dev);
> +	struct flexcan_regs __iomem *regs = priv->base;
> +	u32 reg_ctrl, reg_esr;
> +
> +	reg_esr = flexcan_read(&regs->esr);
> +	reg_ctrl = flexcan_read(&regs->ctrl);
> +	if (reg_esr & FLEXCAN_ESR_TX_WRN) {
> +		flexcan_write(reg_esr & ~FLEXCAN_ESR_TX_WRN, &regs->esr);
> +		flexcan_write(reg_ctrl & ~FLEXCAN_CTRL_ERR_MSK, &regs->ctrl);
> +		flexcan_poll_state(dev, reg_esr);
> +	}
> +	return IRQ_HANDLED;
> +}

You should only return IRQ_HANDLED if there was something to handle.

> @@ -944,6 +962,12 @@ static int flexcan_open(struct net_device *dev)
>  	if (err)
>  		goto out_close;
>  
> +	if (priv->err_irq)
> +		err = request_irq(priv->err_irq, flexcan_err_irq, IRQF_SHARED,
> +				  dev->name, dev);
> +	if (err)
> +		goto out_close;

Is this really a fatal error?  And why do you check err outside the "if
(priv->err_irq)" block?  What if some previous code left err non-zero
(either now or after some future code change)?

> @@ -1126,6 +1150,10 @@ static int flexcan_probe(struct platform_device *pdev)
>  	if (irq <= 0)
>  		return -ENODEV;
>  
> +	err_irq = platform_get_irq(pdev, 1);
> +	if (err_irq <= 0)
> +		err_irq = 0;
> +

Why is this <= 0 check needed?

-Scott

^ permalink raw reply

* [PATCH] trivial: drivers/macintosh/smu.c: Fix closing brace followed by if
From: Rasmus Villemoes @ 2014-06-20 19:44 UTC (permalink / raw)
  To: Benjamin Herrenschmidt, Jiri Kosina
  Cc: Rasmus Villemoes, linuxppc-dev, linux-kernel

A closing brace followed by "if" is almost certainly a mistake. Maybe
"else if" was meant, but in this case it doesn't really matter.

Signed-off-by: Rasmus Villemoes <linux@rasmusvillemoes.dk>
---
 drivers/macintosh/smu.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c
index 23b4a3b..4eab93a 100644
--- a/drivers/macintosh/smu.c
+++ b/drivers/macintosh/smu.c
@@ -1257,7 +1257,8 @@ static unsigned int smu_fpoll(struct file *file, poll_table *wait)
 		if (pp->busy && pp->cmd.status != 1)
 			mask |= POLLIN;
 		spin_unlock_irqrestore(&pp->lock, flags);
-	} if (pp->mode == smu_file_events) {
+	}
+	if (pp->mode == smu_file_events) {
 		/* Not yet implemented */
 	}
 	return mask;
-- 
1.9.2

^ permalink raw reply related

* Re: [RFC PATCH 1/7] mmc: sdhci: add quirk for broken 3.0V support
From: Anton Vorontsov @ 2014-06-20 20:26 UTC (permalink / raw)
  To: Vincent Yang
  Cc: andy.green, patches, linux-mmc, chris, Vincent.Yang, linuxppc-dev
In-Reply-To: <1403256928-11359-2-git-send-email-Vincent.Yang@tw.fujitsu.com>

On Fri, Jun 20, 2014 at 05:35:22PM +0800, Vincent Yang wrote:
> This patch defines a quirk for platforms unable
> to enable 3.0V support.
> It is a preparation and will be used by Fujitsu
> SDHCI controller f_sdh30 driver.
> 
> Signed-off-by: Vincent Yang <Vincent.Yang@tw.fujitsu.com>

I don't think you need this patch. Instead, you can exclude 3V using the
voltage-ranges = <> in the device tree.

Thanks,

Anton

>  drivers/mmc/host/sdhci.c  | 3 +++
>  include/linux/mmc/sdhci.h | 2 ++
>  2 files changed, 5 insertions(+)
> 
> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> index 47055f3..523075f 100644
> --- a/drivers/mmc/host/sdhci.c
> +++ b/drivers/mmc/host/sdhci.c
> @@ -3069,6 +3069,9 @@ int sdhci_add_host(struct sdhci_host *host)
>  	}
>  #endif /* CONFIG_REGULATOR */
>  
> +	if (host->quirks2 & SDHCI_QUIRK2_NO_3_0_V)
> +		caps[0] &= ~SDHCI_CAN_VDD_300;
> +
>  	/*
>  	 * According to SD Host Controller spec v3.00, if the Host System
>  	 * can afford more than 150mA, Host Driver should set XPC to 1. Also
> diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
> index 08abe99..cac0958 100644
> --- a/include/linux/mmc/sdhci.h
> +++ b/include/linux/mmc/sdhci.h
> @@ -98,6 +98,8 @@ struct sdhci_host {
>  #define SDHCI_QUIRK2_BROKEN_HS200			(1<<6)
>  /* Controller does not support DDR50 */
>  #define SDHCI_QUIRK2_BROKEN_DDR50			(1<<7)
> +/* The system physically doesn't support 3.0v, even if the host does */
> +#define SDHCI_QUIRK2_NO_3_0_V				(1<<8)
>  
>  	int irq;		/* Device IRQ */
>  	void __iomem *ioaddr;	/* Mapped address */
> -- 
> 1.9.0

^ permalink raw reply

* Re: [PATCH] vfio: Fix endianness handling for emulated BARs
From: Benjamin Herrenschmidt @ 2014-06-20 23:12 UTC (permalink / raw)
  To: Alex Williamson
  Cc: kvm, Nikunj A Dadhania, Alexey Kardashevskiy, linux-kernel,
	Alexander Graf, linuxppc-dev
In-Reply-To: <1403234514.3707.278.camel@ul30vt.home>

On Thu, 2014-06-19 at 21:21 -0600, Alex Williamson wrote:

> Working on big endian being an accident may be a matter of perspective

 :-)

> The comment remains that this patch doesn't actually fix anything except
> the overhead on big endian systems doing redundant byte swapping and
> maybe the philosophy that vfio regions are little endian.

Yes, that works by accident because technically VFIO is a transport and
thus shouldn't perform any endian swapping of any sort, which remains
the responsibility of the end driver which is the only one to know
whether a given BAR location is a a register or some streaming data
and in the former case whether it's LE or BE (some PCI devices are BE
even ! :-)

But yes, in the end, it works with the dual "cancelling" swaps and the
overhead of those swaps is probably drowned in the noise of the syscall
overhead.

> I'm still not a fan of iowrite vs iowritebe, there must be something we
> can use that doesn't have an implicit swap.

Sadly there isn't ... In the old day we didn't even have the "be"
variant and readl/writel style accessors still don't have them either
for all archs.

There is __raw_readl/writel but here the semantics are much more than
just "don't swap", they also don't have memory barriers (which means
they are essentially useless to most drivers unless those are platform
specific drivers which know exactly what they are doing, or in the rare
cases such as accessing a framebuffer which we know never have side
effects). 

>  Calling it iowrite*_native is also an abuse of the namespace.


>  Next thing we know some common code
> will legitimately use that name. 

I might make sense to those definitions into a common header. There have
been a handful of cases in the past that wanted that sort of "native
byte order" MMIOs iirc (though don't ask me for examples, I can't really
remember).

>  If we do need to define an alias
> (which I'd like to avoid) it should be something like vfio_iowrite32.
> Thanks,

Cheers,
Ben.

> Alex
> 
> > > ===
> > > 
> > > any better?
> > > 
> > > 
> > > 
> > > 
> > >>>> Suggested-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> > >>>> Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
> > >>>> ---
> > >>>>  drivers/vfio/pci/vfio_pci_rdwr.c | 20 ++++++++++++++++----
> > >>>>  1 file changed, 16 insertions(+), 4 deletions(-)
> > >>>>
> > >>>> diff --git a/drivers/vfio/pci/vfio_pci_rdwr.c b/drivers/vfio/pci/vfio_pci_rdwr.c
> > >>>> index 210db24..f363b5a 100644
> > >>>> --- a/drivers/vfio/pci/vfio_pci_rdwr.c
> > >>>> +++ b/drivers/vfio/pci/vfio_pci_rdwr.c
> > >>>> @@ -21,6 +21,18 @@
> > >>>>  
> > >>>>  #include "vfio_pci_private.h"
> > >>>>  
> > >>>> +#ifdef __BIG_ENDIAN__
> > >>>> +#define ioread16_native		ioread16be
> > >>>> +#define ioread32_native		ioread32be
> > >>>> +#define iowrite16_native	iowrite16be
> > >>>> +#define iowrite32_native	iowrite32be
> > >>>> +#else
> > >>>> +#define ioread16_native		ioread16
> > >>>> +#define ioread32_native		ioread32
> > >>>> +#define iowrite16_native	iowrite16
> > >>>> +#define iowrite32_native	iowrite32
> > >>>> +#endif
> > >>>> +
> > >>>>  /*
> > >>>>   * Read or write from an __iomem region (MMIO or I/O port) with an excluded
> > >>>>   * range which is inaccessible.  The excluded range drops writes and fills
> > >>>> @@ -50,9 +62,9 @@ static ssize_t do_io_rw(void __iomem *io, char __user *buf,
> > >>>>  				if (copy_from_user(&val, buf, 4))
> > >>>>  					return -EFAULT;
> > >>>>  
> > >>>> -				iowrite32(le32_to_cpu(val), io + off);
> > >>>> +				iowrite32_native(val, io + off);
> > >>>>  			} else {
> > >>>> -				val = cpu_to_le32(ioread32(io + off));
> > >>>> +				val = ioread32_native(io + off);
> > >>>>  
> > >>>>  				if (copy_to_user(buf, &val, 4))
> > >>>>  					return -EFAULT;
> > >>>> @@ -66,9 +78,9 @@ static ssize_t do_io_rw(void __iomem *io, char __user *buf,
> > >>>>  				if (copy_from_user(&val, buf, 2))
> > >>>>  					return -EFAULT;
> > >>>>  
> > >>>> -				iowrite16(le16_to_cpu(val), io + off);
> > >>>> +				iowrite16_native(val, io + off);
> > >>>>  			} else {
> > >>>> -				val = cpu_to_le16(ioread16(io + off));
> > >>>> +				val = ioread16_native(io + off);
> > >>>>  
> > >>>>  				if (copy_to_user(buf, &val, 2))
> > >>>>  					return -EFAULT;
> > >>>
> > >>>
> > >>>
> > >>
> > >>
> > > 
> > > 
> > 
> > 
> 
> 
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

^ permalink raw reply

* Re: [PATCH] vfio: Fix endianness handling for emulated BARs
From: Benjamin Herrenschmidt @ 2014-06-20 23:16 UTC (permalink / raw)
  To: Alexey Kardashevskiy
  Cc: kvm, Nikunj A Dadhania, linux-kernel, Alexander Graf,
	Alex Williamson, linuxppc-dev
In-Reply-To: <53A441D3.8010602@ozlabs.ru>

On Sat, 2014-06-21 at 00:14 +1000, Alexey Kardashevskiy wrote:

> We can still use __raw_writel&co, would that be ok?

No unless you understand precisely what kind of memory barriers each
platform require for these.

Cheers,
Ben.

^ permalink raw reply

* [PATCH] arm64, ia64, ppc, s390, sh, tile, um, x86, mm: Remove default gate area
From: Andy Lutomirski @ 2014-06-21  0:09 UTC (permalink / raw)
  To: linux-arch
  Cc: linux-ia64, linux-sh, Catalin Marinas, Heiko Carstens, linux-mm,
	Paul Mackerras, H. Peter Anvin, linux-s390, Richard Weinberger,
	x86, Ingo Molnar, Fenghua Yu, user-mode-linux-devel, Will Deacon,
	Jeff Dike, Chris Metcalf, user-mode-linux-user, Thomas Gleixner,
	linux-arm-kernel, Tony Luck, linux-kernel, Andy Lutomirski,
	Martin Schwidefsky, linux390, linuxppc-dev

The core mm code will provide a default gate area based on
FIXADDR_USER_START and FIXADDR_USER_END if
!defined(__HAVE_ARCH_GATE_AREA) && defined(AT_SYSINFO_EHDR).

This default is only useful for ia64.  arm64, ppc, s390, sh, tile,
64-bit UML, and x86_32 have their own code just to disable it.  arm,
32-bit UML, and x86_64 have gate areas, but they have their own
implementations.

This gets rid of the default and moves the code into ia64.

This should save some code on architectures without a gate area: it's
now possible to inline the gate_area functions in the default case.

Signed-off-by: Andy Lutomirski <luto@amacapital.net>
---
 arch/arm64/include/asm/page.h      |  3 ---
 arch/arm64/kernel/vdso.c           | 19 -------------------
 arch/ia64/include/asm/page.h       |  2 ++
 arch/ia64/mm/init.c                | 26 ++++++++++++++++++++++++++
 arch/powerpc/include/asm/page.h    |  3 ---
 arch/powerpc/kernel/vdso.c         | 16 ----------------
 arch/s390/include/asm/page.h       |  2 --
 arch/s390/kernel/vdso.c            | 15 ---------------
 arch/sh/include/asm/page.h         |  5 -----
 arch/sh/kernel/vsyscall/vsyscall.c | 15 ---------------
 arch/tile/include/asm/page.h       |  6 ------
 arch/tile/kernel/vdso.c            | 15 ---------------
 arch/um/include/asm/page.h         |  5 +++++
 arch/x86/include/asm/page.h        |  1 -
 arch/x86/include/asm/page_64.h     |  2 ++
 arch/x86/um/asm/elf.h              |  1 -
 arch/x86/um/mem_64.c               | 15 ---------------
 arch/x86/vdso/vdso32-setup.c       | 19 +------------------
 include/linux/mm.h                 | 17 ++++++++++++-----
 mm/memory.c                        | 38 --------------------------------------
 mm/nommu.c                         |  5 -----
 21 files changed, 48 insertions(+), 182 deletions(-)

diff --git a/arch/arm64/include/asm/page.h b/arch/arm64/include/asm/page.h
index 46bf666..992710f 100644
--- a/arch/arm64/include/asm/page.h
+++ b/arch/arm64/include/asm/page.h
@@ -28,9 +28,6 @@
 #define PAGE_SIZE		(_AC(1,UL) << PAGE_SHIFT)
 #define PAGE_MASK		(~(PAGE_SIZE-1))
 
-/* We do define AT_SYSINFO_EHDR but don't use the gate mechanism */
-#define __HAVE_ARCH_GATE_AREA		1
-
 #ifndef __ASSEMBLY__
 
 #ifdef CONFIG_ARM64_64K_PAGES
diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c
index 50384fe..f630626 100644
--- a/arch/arm64/kernel/vdso.c
+++ b/arch/arm64/kernel/vdso.c
@@ -187,25 +187,6 @@ const char *arch_vma_name(struct vm_area_struct *vma)
 }
 
 /*
- * We define AT_SYSINFO_EHDR, so we need these function stubs to keep
- * Linux happy.
- */
-int in_gate_area_no_mm(unsigned long addr)
-{
-	return 0;
-}
-
-int in_gate_area(struct mm_struct *mm, unsigned long addr)
-{
-	return 0;
-}
-
-struct vm_area_struct *get_gate_vma(struct mm_struct *mm)
-{
-	return NULL;
-}
-
-/*
  * Update the vDSO data page to keep in sync with kernel timekeeping.
  */
 void update_vsyscall(struct timekeeper *tk)
diff --git a/arch/ia64/include/asm/page.h b/arch/ia64/include/asm/page.h
index f1e1b2e..1f1bf14 100644
--- a/arch/ia64/include/asm/page.h
+++ b/arch/ia64/include/asm/page.h
@@ -231,4 +231,6 @@ get_order (unsigned long size)
 #define PERCPU_ADDR		(-PERCPU_PAGE_SIZE)
 #define LOAD_OFFSET		(KERNEL_START - KERNEL_TR_PAGE_SIZE)
 
+#define __HAVE_ARCH_GATE_AREA	1
+
 #endif /* _ASM_IA64_PAGE_H */
diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c
index 25c3502..35efaa3 100644
--- a/arch/ia64/mm/init.c
+++ b/arch/ia64/mm/init.c
@@ -278,6 +278,32 @@ setup_gate (void)
 	ia64_patch_gate();
 }
 
+static struct vm_area_struct gate_vma;
+
+static int __init gate_vma_init(void)
+{
+	gate_vma.vm_mm = NULL;
+	gate_vma.vm_start = FIXADDR_USER_START;
+	gate_vma.vm_end = FIXADDR_USER_END;
+	gate_vma.vm_flags = VM_READ | VM_MAYREAD | VM_EXEC | VM_MAYEXEC;
+	gate_vma.vm_page_prot = __P101;
+
+	return 0;
+}
+__initcall(gate_vma_init);
+
+struct vm_area_struct *get_gate_vma(struct mm_struct *mm)
+{
+	return &gate_vma;
+}
+
+int in_gate_area_no_mm(unsigned long addr)
+{
+	if ((addr >= FIXADDR_USER_START) && (addr < FIXADDR_USER_END))
+		return 1;
+	return 0;
+}
+
 void ia64_mmu_init(void *my_cpu_data)
 {
 	unsigned long pta, impl_va_bits;
diff --git a/arch/powerpc/include/asm/page.h b/arch/powerpc/include/asm/page.h
index 32e4e21..26fe1ae 100644
--- a/arch/powerpc/include/asm/page.h
+++ b/arch/powerpc/include/asm/page.h
@@ -48,9 +48,6 @@ extern unsigned int HPAGE_SHIFT;
 #define HUGE_MAX_HSTATE		(MMU_PAGE_COUNT-1)
 #endif
 
-/* We do define AT_SYSINFO_EHDR but don't use the gate mechanism */
-#define __HAVE_ARCH_GATE_AREA		1
-
 /*
  * Subtle: (1 << PAGE_SHIFT) is an int, not an unsigned long. So if we
  * assign PAGE_MASK to a larger type it gets extended the way we want
diff --git a/arch/powerpc/kernel/vdso.c b/arch/powerpc/kernel/vdso.c
index ce74c33..f174351 100644
--- a/arch/powerpc/kernel/vdso.c
+++ b/arch/powerpc/kernel/vdso.c
@@ -840,19 +840,3 @@ static int __init vdso_init(void)
 	return 0;
 }
 arch_initcall(vdso_init);
-
-int in_gate_area_no_mm(unsigned long addr)
-{
-	return 0;
-}
-
-int in_gate_area(struct mm_struct *mm, unsigned long addr)
-{
-	return 0;
-}
-
-struct vm_area_struct *get_gate_vma(struct mm_struct *mm)
-{
-	return NULL;
-}
-
diff --git a/arch/s390/include/asm/page.h b/arch/s390/include/asm/page.h
index 114258e..7b2ac6e 100644
--- a/arch/s390/include/asm/page.h
+++ b/arch/s390/include/asm/page.h
@@ -162,6 +162,4 @@ static inline int devmem_is_allowed(unsigned long pfn)
 #include <asm-generic/memory_model.h>
 #include <asm-generic/getorder.h>
 
-#define __HAVE_ARCH_GATE_AREA 1
-
 #endif /* _S390_PAGE_H */
diff --git a/arch/s390/kernel/vdso.c b/arch/s390/kernel/vdso.c
index 6136490..0bbb7e0 100644
--- a/arch/s390/kernel/vdso.c
+++ b/arch/s390/kernel/vdso.c
@@ -316,18 +316,3 @@ static int __init vdso_init(void)
 	return 0;
 }
 early_initcall(vdso_init);
-
-int in_gate_area_no_mm(unsigned long addr)
-{
-	return 0;
-}
-
-int in_gate_area(struct mm_struct *mm, unsigned long addr)
-{
-	return 0;
-}
-
-struct vm_area_struct *get_gate_vma(struct mm_struct *mm)
-{
-	return NULL;
-}
diff --git a/arch/sh/include/asm/page.h b/arch/sh/include/asm/page.h
index 15d9703..fe20d14 100644
--- a/arch/sh/include/asm/page.h
+++ b/arch/sh/include/asm/page.h
@@ -186,11 +186,6 @@ typedef struct page *pgtable_t;
 #include <asm-generic/memory_model.h>
 #include <asm-generic/getorder.h>
 
-/* vDSO support */
-#ifdef CONFIG_VSYSCALL
-#define __HAVE_ARCH_GATE_AREA
-#endif
-
 /*
  * Some drivers need to perform DMA into kmalloc'ed buffers
  * and so we have to increase the kmalloc minalign for this.
diff --git a/arch/sh/kernel/vsyscall/vsyscall.c b/arch/sh/kernel/vsyscall/vsyscall.c
index 5ca5797..ea2aa13 100644
--- a/arch/sh/kernel/vsyscall/vsyscall.c
+++ b/arch/sh/kernel/vsyscall/vsyscall.c
@@ -92,18 +92,3 @@ const char *arch_vma_name(struct vm_area_struct *vma)
 
 	return NULL;
 }
-
-struct vm_area_struct *get_gate_vma(struct mm_struct *mm)
-{
-	return NULL;
-}
-
-int in_gate_area(struct mm_struct *mm, unsigned long address)
-{
-	return 0;
-}
-
-int in_gate_area_no_mm(unsigned long address)
-{
-	return 0;
-}
diff --git a/arch/tile/include/asm/page.h b/arch/tile/include/asm/page.h
index 6727680..a213a8d 100644
--- a/arch/tile/include/asm/page.h
+++ b/arch/tile/include/asm/page.h
@@ -39,12 +39,6 @@
 #define HPAGE_MASK	(~(HPAGE_SIZE - 1))
 
 /*
- * We do define AT_SYSINFO_EHDR to support vDSO,
- * but don't use the gate mechanism.
- */
-#define __HAVE_ARCH_GATE_AREA		1
-
-/*
  * If the Kconfig doesn't specify, set a maximum zone order that
  * is enough so that we can create huge pages from small pages given
  * the respective sizes of the two page types.  See <linux/mmzone.h>.
diff --git a/arch/tile/kernel/vdso.c b/arch/tile/kernel/vdso.c
index 1533af2..5bc51d7 100644
--- a/arch/tile/kernel/vdso.c
+++ b/arch/tile/kernel/vdso.c
@@ -121,21 +121,6 @@ const char *arch_vma_name(struct vm_area_struct *vma)
 	return NULL;
 }
 
-struct vm_area_struct *get_gate_vma(struct mm_struct *mm)
-{
-	return NULL;
-}
-
-int in_gate_area(struct mm_struct *mm, unsigned long address)
-{
-	return 0;
-}
-
-int in_gate_area_no_mm(unsigned long address)
-{
-	return 0;
-}
-
 int setup_vdso_pages(void)
 {
 	struct page **pagelist;
diff --git a/arch/um/include/asm/page.h b/arch/um/include/asm/page.h
index 5ff53d9..71c5d13 100644
--- a/arch/um/include/asm/page.h
+++ b/arch/um/include/asm/page.h
@@ -119,4 +119,9 @@ extern unsigned long uml_physmem;
 #include <asm-generic/getorder.h>
 
 #endif	/* __ASSEMBLY__ */
+
+#ifdef CONFIG_X86_32
+#define __HAVE_ARCH_GATE_AREA 1
+#endif
+
 #endif	/* __UM_PAGE_H */
diff --git a/arch/x86/include/asm/page.h b/arch/x86/include/asm/page.h
index 775873d..802dde3 100644
--- a/arch/x86/include/asm/page.h
+++ b/arch/x86/include/asm/page.h
@@ -70,7 +70,6 @@ extern bool __virt_addr_valid(unsigned long kaddr);
 #include <asm-generic/memory_model.h>
 #include <asm-generic/getorder.h>
 
-#define __HAVE_ARCH_GATE_AREA 1
 #define HAVE_ARCH_HUGETLB_UNMAPPED_AREA
 
 #endif	/* __KERNEL__ */
diff --git a/arch/x86/include/asm/page_64.h b/arch/x86/include/asm/page_64.h
index 0f1ddee..f408caf 100644
--- a/arch/x86/include/asm/page_64.h
+++ b/arch/x86/include/asm/page_64.h
@@ -39,4 +39,6 @@ void copy_page(void *to, void *from);
 
 #endif	/* !__ASSEMBLY__ */
 
+#define __HAVE_ARCH_GATE_AREA 1
+
 #endif /* _ASM_X86_PAGE_64_H */
diff --git a/arch/x86/um/asm/elf.h b/arch/x86/um/asm/elf.h
index 0feee2f..25a1022 100644
--- a/arch/x86/um/asm/elf.h
+++ b/arch/x86/um/asm/elf.h
@@ -216,6 +216,5 @@ extern long elf_aux_hwcap;
 #define ELF_HWCAP (elf_aux_hwcap)
 
 #define SET_PERSONALITY(ex) do ; while(0)
-#define __HAVE_ARCH_GATE_AREA 1
 
 #endif
diff --git a/arch/x86/um/mem_64.c b/arch/x86/um/mem_64.c
index c6492e7..f8fecad 100644
--- a/arch/x86/um/mem_64.c
+++ b/arch/x86/um/mem_64.c
@@ -9,18 +9,3 @@ const char *arch_vma_name(struct vm_area_struct *vma)
 
 	return NULL;
 }
-
-struct vm_area_struct *get_gate_vma(struct mm_struct *mm)
-{
-	return NULL;
-}
-
-int in_gate_area(struct mm_struct *mm, unsigned long addr)
-{
-	return 0;
-}
-
-int in_gate_area_no_mm(unsigned long addr)
-{
-	return 0;
-}
diff --git a/arch/x86/vdso/vdso32-setup.c b/arch/x86/vdso/vdso32-setup.c
index e4f7781..e904c27 100644
--- a/arch/x86/vdso/vdso32-setup.c
+++ b/arch/x86/vdso/vdso32-setup.c
@@ -115,23 +115,6 @@ static __init int ia32_binfmt_init(void)
 	return 0;
 }
 __initcall(ia32_binfmt_init);
-#endif
-
-#else  /* CONFIG_X86_32 */
-
-struct vm_area_struct *get_gate_vma(struct mm_struct *mm)
-{
-	return NULL;
-}
-
-int in_gate_area(struct mm_struct *mm, unsigned long addr)
-{
-	return 0;
-}
-
-int in_gate_area_no_mm(unsigned long addr)
-{
-	return 0;
-}
+#endif /* CONFIG_SYSCTL */
 
 #endif	/* CONFIG_X86_64 */
diff --git a/include/linux/mm.h b/include/linux/mm.h
index e03dd29..8981cc8 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -2014,13 +2014,20 @@ static inline bool kernel_page_present(struct page *page) { return true; }
 #endif /* CONFIG_HIBERNATION */
 #endif
 
+#ifdef __HAVE_ARCH_GATE_AREA
 extern struct vm_area_struct *get_gate_vma(struct mm_struct *mm);
-#ifdef	__HAVE_ARCH_GATE_AREA
-int in_gate_area_no_mm(unsigned long addr);
-int in_gate_area(struct mm_struct *mm, unsigned long addr);
+extern int in_gate_area_no_mm(unsigned long addr);
+extern int in_gate_area(struct mm_struct *mm, unsigned long addr);
 #else
-int in_gate_area_no_mm(unsigned long addr);
-#define in_gate_area(mm, addr) ({(void)mm; in_gate_area_no_mm(addr);})
+static inline struct vm_area_struct *get_gate_vma(struct mm_struct *mm)
+{
+	return NULL;
+}
+static inline int in_gate_area_no_mm(unsigned long addr) { return 0; }
+static inline int in_gate_area(struct mm_struct *mm, unsigned long addr)
+{
+	return 0;
+}
 #endif	/* __HAVE_ARCH_GATE_AREA */
 
 #ifdef CONFIG_SYSCTL
diff --git a/mm/memory.c b/mm/memory.c
index d67fd9f..099d234 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -3399,44 +3399,6 @@ int __pmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long address)
 }
 #endif /* __PAGETABLE_PMD_FOLDED */
 
-#if !defined(__HAVE_ARCH_GATE_AREA)
-
-#if defined(AT_SYSINFO_EHDR)
-static struct vm_area_struct gate_vma;
-
-static int __init gate_vma_init(void)
-{
-	gate_vma.vm_mm = NULL;
-	gate_vma.vm_start = FIXADDR_USER_START;
-	gate_vma.vm_end = FIXADDR_USER_END;
-	gate_vma.vm_flags = VM_READ | VM_MAYREAD | VM_EXEC | VM_MAYEXEC;
-	gate_vma.vm_page_prot = __P101;
-
-	return 0;
-}
-__initcall(gate_vma_init);
-#endif
-
-struct vm_area_struct *get_gate_vma(struct mm_struct *mm)
-{
-#ifdef AT_SYSINFO_EHDR
-	return &gate_vma;
-#else
-	return NULL;
-#endif
-}
-
-int in_gate_area_no_mm(unsigned long addr)
-{
-#ifdef AT_SYSINFO_EHDR
-	if ((addr >= FIXADDR_USER_START) && (addr < FIXADDR_USER_END))
-		return 1;
-#endif
-	return 0;
-}
-
-#endif	/* __HAVE_ARCH_GATE_AREA */
-
 static int __follow_pte(struct mm_struct *mm, unsigned long address,
 		pte_t **ptepp, spinlock_t **ptlp)
 {
diff --git a/mm/nommu.c b/mm/nommu.c
index b78e3a8..c4ca56b 100644
--- a/mm/nommu.c
+++ b/mm/nommu.c
@@ -1981,11 +1981,6 @@ error:
 	return -ENOMEM;
 }
 
-int in_gate_area_no_mm(unsigned long addr)
-{
-	return 0;
-}
-
 int filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
 	BUG();
-- 
1.9.3

^ permalink raw reply related

* [PATCH 1/2] pcmcia: Remove m8xx_pcmcia driver
From: Scott Wood @ 2014-06-21  1:02 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Scott Wood, Paul Bolle, linux-pcmcia

This driver doesn't build, and apparently has not built since
arch/ppc was removed in 2008 (when mk_int_int_mask was removed
from asm/irq.h, among other build errors).

A few weeks ago I asked whether anyone was actively maintaining
this code, and got no positive response:
http://patchwork.ozlabs.org/patch/352082/

So, let's remove it.

Signed-off-by: Scott Wood <scottwood@freescale.com>
Cc: Vitaly Bordug <vitb@kernel.crashing.org>
Cc: linux-pcmcia@lists.infradead.org
Cc: Paul Bolle <pebolle@tiscali.nl>
---
 arch/powerpc/include/asm/mpc8xx.h            |    2 -
 arch/powerpc/platforms/8xx/m8xx_setup.c      |    2 -
 arch/powerpc/platforms/8xx/mpc885ads_setup.c |   61 --
 drivers/pcmcia/Kconfig                       |   10 -
 drivers/pcmcia/Makefile                      |    1 -
 drivers/pcmcia/m8xx_pcmcia.c                 | 1168 --------------------------
 6 files changed, 1244 deletions(-)
 delete mode 100644 drivers/pcmcia/m8xx_pcmcia.c

diff --git a/arch/powerpc/include/asm/mpc8xx.h b/arch/powerpc/include/asm/mpc8xx.h
index 98f3c4f..8ab22e8 100644
--- a/arch/powerpc/include/asm/mpc8xx.h
+++ b/arch/powerpc/include/asm/mpc8xx.h
@@ -7,6 +7,4 @@
 #ifndef __CONFIG_8xx_DEFS
 #define __CONFIG_8xx_DEFS
 
-extern struct mpc8xx_pcmcia_ops m8xx_pcmcia_ops;
-
 #endif /* __CONFIG_8xx_DEFS */
diff --git a/arch/powerpc/platforms/8xx/m8xx_setup.c b/arch/powerpc/platforms/8xx/m8xx_setup.c
index 587a282..623bb43 100644
--- a/arch/powerpc/platforms/8xx/m8xx_setup.c
+++ b/arch/powerpc/platforms/8xx/m8xx_setup.c
@@ -28,8 +28,6 @@
 
 #include "mpc8xx.h"
 
-struct mpc8xx_pcmcia_ops m8xx_pcmcia_ops;
-
 extern int cpm_pic_init(void);
 extern int cpm_get_irq(void);
 
diff --git a/arch/powerpc/platforms/8xx/mpc885ads_setup.c b/arch/powerpc/platforms/8xx/mpc885ads_setup.c
index c126258..3d5e4e1 100644
--- a/arch/powerpc/platforms/8xx/mpc885ads_setup.c
+++ b/arch/powerpc/platforms/8xx/mpc885ads_setup.c
@@ -46,61 +46,6 @@
 
 static u32 __iomem *bcsr, *bcsr5;
 
-#ifdef CONFIG_PCMCIA_M8XX
-static void pcmcia_hw_setup(int slot, int enable)
-{
-	if (enable)
-		clrbits32(&bcsr[1], BCSR1_PCCEN);
-	else
-		setbits32(&bcsr[1], BCSR1_PCCEN);
-}
-
-static int pcmcia_set_voltage(int slot, int vcc, int vpp)
-{
-	u32 reg = 0;
-
-	switch (vcc) {
-	case 0:
-		break;
-	case 33:
-		reg |= BCSR1_PCCVCC0;
-		break;
-	case 50:
-		reg |= BCSR1_PCCVCC1;
-		break;
-	default:
-		return 1;
-	}
-
-	switch (vpp) {
-	case 0:
-		break;
-	case 33:
-	case 50:
-		if (vcc == vpp)
-			reg |= BCSR1_PCCVPP1;
-		else
-			return 1;
-		break;
-	case 120:
-		if ((vcc == 33) || (vcc == 50))
-			reg |= BCSR1_PCCVPP0;
-		else
-			return 1;
-	default:
-		return 1;
-	}
-
-	/* first, turn off all power */
-	clrbits32(&bcsr[1], 0x00610000);
-
-	/* enable new powersettings */
-	setbits32(&bcsr[1], reg);
-
-	return 0;
-}
-#endif
-
 struct cpm_pin {
 	int port, pin, flags;
 };
@@ -245,12 +190,6 @@ static void __init mpc885ads_setup_arch(void)
 		of_detach_node(np);
 		of_node_put(np);
 	}
-
-#ifdef CONFIG_PCMCIA_M8XX
-	/* Set up board specific hook-ups.*/
-	m8xx_pcmcia_ops.hw_ctrl = pcmcia_hw_setup;
-	m8xx_pcmcia_ops.voltage_set = pcmcia_set_voltage;
-#endif
 }
 
 static int __init mpc885ads_probe(void)
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig
index 0c657d6..087d7d7 100644
--- a/drivers/pcmcia/Kconfig
+++ b/drivers/pcmcia/Kconfig
@@ -144,16 +144,6 @@ config TCIC
 	  "Bridge" is the name used for the hardware inside your computer that
 	  PCMCIA cards are plugged into. If unsure, say N.
 
-config PCMCIA_M8XX
-	tristate "MPC8xx PCMCIA support"
-	depends on PCCARD && PPC && 8xx
-	select PCCARD_IODYN if PCMCIA != n
-	help
-	  Say Y here to include support for PowerPC 8xx series PCMCIA
-	  controller.
-
-	  This driver is also available as a module called m8xx_pcmcia.
-
 config PCMCIA_ALCHEMY_DEVBOARD
 	tristate "Alchemy Db/Pb1xxx PCMCIA socket services"
 	depends on MIPS_ALCHEMY && PCMCIA
diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile
index 7745b51..e62c26b 100644
--- a/drivers/pcmcia/Makefile
+++ b/drivers/pcmcia/Makefile
@@ -23,7 +23,6 @@ obj-$(CONFIG_PD6729)				+= pd6729.o
 obj-$(CONFIG_I82365)				+= i82365.o
 obj-$(CONFIG_I82092)				+= i82092.o
 obj-$(CONFIG_TCIC)				+= tcic.o
-obj-$(CONFIG_PCMCIA_M8XX)			+= m8xx_pcmcia.o
 obj-$(CONFIG_PCMCIA_SOC_COMMON)			+= soc_common.o
 obj-$(CONFIG_PCMCIA_SA11XX_BASE)		+= sa11xx_base.o
 obj-$(CONFIG_PCMCIA_SA1100)			+= sa1100_cs.o
diff --git a/drivers/pcmcia/m8xx_pcmcia.c b/drivers/pcmcia/m8xx_pcmcia.c
deleted file mode 100644
index 182034d..0000000
--- a/drivers/pcmcia/m8xx_pcmcia.c
+++ /dev/null
@@ -1,1168 +0,0 @@
-/*
- * m8xx_pcmcia.c - Linux PCMCIA socket driver for the mpc8xx series.
- *
- * (C) 1999-2000 Magnus Damm <damm@opensource.se>
- * (C) 2001-2002 Montavista Software, Inc.
- *     <mlocke@mvista.com>
- *
- * Support for two slots by Cyclades Corporation
- *     <oliver.kurth@cyclades.de>
- * Further fixes, v2.6 kernel port
- *     <marcelo.tosatti@cyclades.com>
- * 
- * Some fixes, additions (C) 2005-2007 Montavista Software, Inc.
- *     <vbordug@ru.mvista.com>
- *
- * "The ExCA standard specifies that socket controllers should provide
- * two IO and five memory windows per socket, which can be independently
- * configured and positioned in the host address space and mapped to
- * arbitrary segments of card address space. " - David A Hinds. 1999
- *
- * This controller does _not_ meet the ExCA standard.
- *
- * m8xx pcmcia controller brief info:
- * + 8 windows (attrib, mem, i/o)
- * + up to two slots (SLOT_A and SLOT_B)
- * + inputpins, outputpins, event and mask registers.
- * - no offset register. sigh.
- *
- * Because of the lacking offset register we must map the whole card.
- * We assign each memory window PCMCIA_MEM_WIN_SIZE address space.
- * Make sure there is (PCMCIA_MEM_WIN_SIZE * PCMCIA_MEM_WIN_NO
- * * PCMCIA_SOCKETS_NO) bytes at PCMCIA_MEM_WIN_BASE.
- * The i/o windows are dynamically allocated at PCMCIA_IO_WIN_BASE.
- * They are maximum 64KByte each...
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/string.h>
-
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/timer.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/fsl_devices.h>
-#include <linux/bitops.h>
-#include <linux/of_address.h>
-#include <linux/of_device.h>
-#include <linux/of_irq.h>
-#include <linux/of_platform.h>
-
-#include <asm/io.h>
-#include <asm/time.h>
-#include <asm/mpc8xx.h>
-#include <asm/8xx_immap.h>
-#include <asm/irq.h>
-#include <asm/fs_pd.h>
-
-#include <pcmcia/ss.h>
-
-#define pcmcia_info(args...) printk(KERN_INFO "m8xx_pcmcia: "args)
-#define pcmcia_error(args...) printk(KERN_ERR "m8xx_pcmcia: "args)
-
-static const char *version = "Version 0.06, Aug 2005";
-MODULE_LICENSE("Dual MPL/GPL");
-
-#if !defined(CONFIG_PCMCIA_SLOT_A) && !defined(CONFIG_PCMCIA_SLOT_B)
-
-/* The ADS board use SLOT_A */
-#ifdef CONFIG_ADS
-#define CONFIG_PCMCIA_SLOT_A
-#define CONFIG_BD_IS_MHZ
-#endif
-
-/* The FADS series are a mess */
-#ifdef CONFIG_FADS
-#if defined(CONFIG_MPC860T) || defined(CONFIG_MPC860) || defined(CONFIG_MPC821)
-#define CONFIG_PCMCIA_SLOT_A
-#else
-#define CONFIG_PCMCIA_SLOT_B
-#endif
-#endif
-
-#if defined(CONFIG_MPC885ADS)
-#define CONFIG_PCMCIA_SLOT_A
-#define PCMCIA_GLITCHY_CD
-#endif
-
-/* Cyclades ACS uses both slots */
-#ifdef CONFIG_PRxK
-#define CONFIG_PCMCIA_SLOT_A
-#define CONFIG_PCMCIA_SLOT_B
-#endif
-
-#endif				/* !defined(CONFIG_PCMCIA_SLOT_A) && !defined(CONFIG_PCMCIA_SLOT_B) */
-
-#if defined(CONFIG_PCMCIA_SLOT_A) && defined(CONFIG_PCMCIA_SLOT_B)
-
-#define PCMCIA_SOCKETS_NO 2
-/* We have only 8 windows, dualsocket support will be limited. */
-#define PCMCIA_MEM_WIN_NO 2
-#define PCMCIA_IO_WIN_NO  2
-#define PCMCIA_SLOT_MSG "SLOT_A and SLOT_B"
-
-#elif defined(CONFIG_PCMCIA_SLOT_A) || defined(CONFIG_PCMCIA_SLOT_B)
-
-#define PCMCIA_SOCKETS_NO 1
-/* full support for one slot */
-#define PCMCIA_MEM_WIN_NO 5
-#define PCMCIA_IO_WIN_NO  2
-
-/* define _slot_ to be able to optimize macros */
-
-#ifdef CONFIG_PCMCIA_SLOT_A
-#define _slot_ 0
-#define PCMCIA_SLOT_MSG "SLOT_A"
-#else
-#define _slot_ 1
-#define PCMCIA_SLOT_MSG "SLOT_B"
-#endif
-
-#else
-#error m8xx_pcmcia: Bad configuration!
-#endif
-
-/* ------------------------------------------------------------------------- */
-
-#define PCMCIA_MEM_WIN_BASE 0xe0000000	/* base address for memory window 0   */
-#define PCMCIA_MEM_WIN_SIZE 0x04000000	/* each memory window is 64 MByte     */
-#define PCMCIA_IO_WIN_BASE  _IO_BASE	/* base address for io window 0       */
-/* ------------------------------------------------------------------------- */
-
-static int pcmcia_schlvl;
-
-static DEFINE_SPINLOCK(events_lock);
-
-#define PCMCIA_SOCKET_KEY_5V 1
-#define PCMCIA_SOCKET_KEY_LV 2
-
-/* look up table for pgcrx registers */
-static u32 *m8xx_pgcrx[2];
-
-/*
- * This structure is used to address each window in the PCMCIA controller.
- *
- * Keep in mind that we assume that pcmcia_win[n+1] is mapped directly
- * after pcmcia_win[n]...
- */
-
-struct pcmcia_win {
-	u32 br;
-	u32 or;
-};
-
-/*
- * For some reason the hardware guys decided to make both slots share
- * some registers.
- *
- * Could someone invent object oriented hardware ?
- *
- * The macros are used to get the right bit from the registers.
- * SLOT_A : slot = 0
- * SLOT_B : slot = 1
- */
-
-#define M8XX_PCMCIA_VS1(slot)      (0x80000000 >> (slot << 4))
-#define M8XX_PCMCIA_VS2(slot)      (0x40000000 >> (slot << 4))
-#define M8XX_PCMCIA_VS_MASK(slot)  (0xc0000000 >> (slot << 4))
-#define M8XX_PCMCIA_VS_SHIFT(slot) (30 - (slot << 4))
-
-#define M8XX_PCMCIA_WP(slot)       (0x20000000 >> (slot << 4))
-#define M8XX_PCMCIA_CD2(slot)      (0x10000000 >> (slot << 4))
-#define M8XX_PCMCIA_CD1(slot)      (0x08000000 >> (slot << 4))
-#define M8XX_PCMCIA_BVD2(slot)     (0x04000000 >> (slot << 4))
-#define M8XX_PCMCIA_BVD1(slot)     (0x02000000 >> (slot << 4))
-#define M8XX_PCMCIA_RDY(slot)      (0x01000000 >> (slot << 4))
-#define M8XX_PCMCIA_RDY_L(slot)    (0x00800000 >> (slot << 4))
-#define M8XX_PCMCIA_RDY_H(slot)    (0x00400000 >> (slot << 4))
-#define M8XX_PCMCIA_RDY_R(slot)    (0x00200000 >> (slot << 4))
-#define M8XX_PCMCIA_RDY_F(slot)    (0x00100000 >> (slot << 4))
-#define M8XX_PCMCIA_MASK(slot)     (0xFFFF0000 >> (slot << 4))
-
-#define M8XX_PCMCIA_POR_VALID    0x00000001
-#define M8XX_PCMCIA_POR_WRPROT   0x00000002
-#define M8XX_PCMCIA_POR_ATTRMEM  0x00000010
-#define M8XX_PCMCIA_POR_IO       0x00000018
-#define M8XX_PCMCIA_POR_16BIT    0x00000040
-
-#define M8XX_PGCRX(slot)  m8xx_pgcrx[slot]
-
-#define M8XX_PGCRX_CXOE    0x00000080
-#define M8XX_PGCRX_CXRESET 0x00000040
-
-/* we keep one lookup table per socket to check flags */
-
-#define PCMCIA_EVENTS_MAX 5	/* 4 max at a time + termination */
-
-struct event_table {
-	u32 regbit;
-	u32 eventbit;
-};
-
-static const char driver_name[] = "m8xx-pcmcia";
-
-struct socket_info {
-	void (*handler) (void *info, u32 events);
-	void *info;
-
-	u32 slot;
-	pcmconf8xx_t *pcmcia;
-	u32 bus_freq;
-	int hwirq;
-
-	socket_state_t state;
-	struct pccard_mem_map mem_win[PCMCIA_MEM_WIN_NO];
-	struct pccard_io_map io_win[PCMCIA_IO_WIN_NO];
-	struct event_table events[PCMCIA_EVENTS_MAX];
-	struct pcmcia_socket socket;
-};
-
-static struct socket_info socket[PCMCIA_SOCKETS_NO];
-
-/*
- * Search this table to see if the windowsize is
- * supported...
- */
-
-#define M8XX_SIZES_NO 32
-
-static const u32 m8xx_size_to_gray[M8XX_SIZES_NO] = {
-	0x00000001, 0x00000002, 0x00000008, 0x00000004,
-	0x00000080, 0x00000040, 0x00000010, 0x00000020,
-	0x00008000, 0x00004000, 0x00001000, 0x00002000,
-	0x00000100, 0x00000200, 0x00000800, 0x00000400,
-
-	0x0fffffff, 0xffffffff, 0xffffffff, 0xffffffff,
-	0x01000000, 0x02000000, 0xffffffff, 0x04000000,
-	0x00010000, 0x00020000, 0x00080000, 0x00040000,
-	0x00800000, 0x00400000, 0x00100000, 0x00200000
-};
-
-/* ------------------------------------------------------------------------- */
-
-static irqreturn_t m8xx_interrupt(int irq, void *dev);
-
-#define PCMCIA_BMT_LIMIT (15*4)	/* Bus Monitor Timeout value */
-
-/* FADS Boards from Motorola                                               */
-
-#if defined(CONFIG_FADS)
-
-#define PCMCIA_BOARD_MSG "FADS"
-
-static int voltage_set(int slot, int vcc, int vpp)
-{
-	u32 reg = 0;
-
-	switch (vcc) {
-	case 0:
-		break;
-	case 33:
-		reg |= BCSR1_PCCVCC0;
-		break;
-	case 50:
-		reg |= BCSR1_PCCVCC1;
-		break;
-	default:
-		return 1;
-	}
-
-	switch (vpp) {
-	case 0:
-		break;
-	case 33:
-	case 50:
-		if (vcc == vpp)
-			reg |= BCSR1_PCCVPP1;
-		else
-			return 1;
-		break;
-	case 120:
-		if ((vcc == 33) || (vcc == 50))
-			reg |= BCSR1_PCCVPP0;
-		else
-			return 1;
-	default:
-		return 1;
-	}
-
-	/* first, turn off all power */
-	out_be32((u32 *) BCSR1,
-		 in_be32((u32 *) BCSR1) & ~(BCSR1_PCCVCC_MASK |
-					    BCSR1_PCCVPP_MASK));
-
-	/* enable new powersettings */
-	out_be32((u32 *) BCSR1, in_be32((u32 *) BCSR1) | reg);
-
-	return 0;
-}
-
-#define socket_get(_slot_) PCMCIA_SOCKET_KEY_5V
-
-static void hardware_enable(int slot)
-{
-	out_be32((u32 *) BCSR1, in_be32((u32 *) BCSR1) & ~BCSR1_PCCEN);
-}
-
-static void hardware_disable(int slot)
-{
-	out_be32((u32 *) BCSR1, in_be32((u32 *) BCSR1) | BCSR1_PCCEN);
-}
-
-#endif
-
-/* MPC885ADS Boards */
-
-#if defined(CONFIG_MPC885ADS)
-
-#define PCMCIA_BOARD_MSG "MPC885ADS"
-#define socket_get(_slot_) PCMCIA_SOCKET_KEY_5V
-
-static inline void hardware_enable(int slot)
-{
-	m8xx_pcmcia_ops.hw_ctrl(slot, 1);
-}
-
-static inline void hardware_disable(int slot)
-{
-	m8xx_pcmcia_ops.hw_ctrl(slot, 0);
-}
-
-static inline int voltage_set(int slot, int vcc, int vpp)
-{
-	return m8xx_pcmcia_ops.voltage_set(slot, vcc, vpp);
-}
-
-#endif
-
-#if defined(CONFIG_PRxK)
-#include <asm/cpld.h>
-extern volatile fpga_pc_regs *fpga_pc;
-
-#define PCMCIA_BOARD_MSG "MPC855T"
-
-static int voltage_set(int slot, int vcc, int vpp)
-{
-	u8 reg = 0;
-	u8 regread;
-	cpld_regs *ccpld = get_cpld();
-
-	switch (vcc) {
-	case 0:
-		break;
-	case 33:
-		reg |= PCMCIA_VCC_33;
-		break;
-	case 50:
-		reg |= PCMCIA_VCC_50;
-		break;
-	default:
-		return 1;
-	}
-
-	switch (vpp) {
-	case 0:
-		break;
-	case 33:
-	case 50:
-		if (vcc == vpp)
-			reg |= PCMCIA_VPP_VCC;
-		else
-			return 1;
-		break;
-	case 120:
-		if ((vcc == 33) || (vcc == 50))
-			reg |= PCMCIA_VPP_12;
-		else
-			return 1;
-	default:
-		return 1;
-	}
-
-	reg = reg >> (slot << 2);
-	regread = in_8(&ccpld->fpga_pc_ctl);
-	if (reg !=
-	    (regread & ((PCMCIA_VCC_MASK | PCMCIA_VPP_MASK) >> (slot << 2)))) {
-		/* enable new powersettings */
-		regread =
-		    regread & ~((PCMCIA_VCC_MASK | PCMCIA_VPP_MASK) >>
-				(slot << 2));
-		out_8(&ccpld->fpga_pc_ctl, reg | regread);
-		msleep(100);
-	}
-
-	return 0;
-}
-
-#define socket_get(_slot_) PCMCIA_SOCKET_KEY_LV
-#define hardware_enable(_slot_)	/* No hardware to enable */
-#define hardware_disable(_slot_)	/* No hardware to disable */
-
-#endif				/* CONFIG_PRxK */
-
-static u32 pending_events[PCMCIA_SOCKETS_NO];
-static DEFINE_SPINLOCK(pending_event_lock);
-
-static irqreturn_t m8xx_interrupt(int irq, void *dev)
-{
-	struct socket_info *s;
-	struct event_table *e;
-	unsigned int i, events, pscr, pipr, per;
-	pcmconf8xx_t *pcmcia = socket[0].pcmcia;
-
-	pr_debug("m8xx_pcmcia: Interrupt!\n");
-	/* get interrupt sources */
-
-	pscr = in_be32(&pcmcia->pcmc_pscr);
-	pipr = in_be32(&pcmcia->pcmc_pipr);
-	per = in_be32(&pcmcia->pcmc_per);
-
-	for (i = 0; i < PCMCIA_SOCKETS_NO; i++) {
-		s = &socket[i];
-		e = &s->events[0];
-		events = 0;
-
-		while (e->regbit) {
-			if (pscr & e->regbit)
-				events |= e->eventbit;
-
-			e++;
-		}
-
-		/*
-		 * report only if both card detect signals are the same
-		 * not too nice done,
-		 * we depend on that CD2 is the bit to the left of CD1...
-		 */
-		if (events & SS_DETECT)
-			if (((pipr & M8XX_PCMCIA_CD2(i)) >> 1) ^
-			    (pipr & M8XX_PCMCIA_CD1(i))) {
-				events &= ~SS_DETECT;
-			}
-#ifdef PCMCIA_GLITCHY_CD
-		/*
-		 * I've experienced CD problems with my ADS board.
-		 * We make an extra check to see if there was a
-		 * real change of Card detection.
-		 */
-
-		if ((events & SS_DETECT) &&
-		    ((pipr &
-		      (M8XX_PCMCIA_CD2(i) | M8XX_PCMCIA_CD1(i))) == 0) &&
-		    (s->state.Vcc | s->state.Vpp)) {
-			events &= ~SS_DETECT;
-			/*printk( "CD glitch workaround - CD = 0x%08x!\n",
-			   (pipr & (M8XX_PCMCIA_CD2(i)
-			   | M8XX_PCMCIA_CD1(i)))); */
-		}
-#endif
-
-		/* call the handler */
-
-		pr_debug("m8xx_pcmcia: slot %u: events = 0x%02x, pscr = 0x%08x, "
-			"pipr = 0x%08x\n", i, events, pscr, pipr);
-
-		if (events) {
-			spin_lock(&pending_event_lock);
-			pending_events[i] |= events;
-			spin_unlock(&pending_event_lock);
-			/*
-			 * Turn off RDY_L bits in the PER mask on
-			 * CD interrupt receival.
-			 *
-			 * They can generate bad interrupts on the
-			 * ACS4,8,16,32.   - marcelo
-			 */
-			per &= ~M8XX_PCMCIA_RDY_L(0);
-			per &= ~M8XX_PCMCIA_RDY_L(1);
-
-			out_be32(&pcmcia->pcmc_per, per);
-
-			if (events)
-				pcmcia_parse_events(&socket[i].socket, events);
-		}
-	}
-
-	/* clear the interrupt sources */
-	out_be32(&pcmcia->pcmc_pscr, pscr);
-
-	pr_debug("m8xx_pcmcia: Interrupt done.\n");
-
-	return IRQ_HANDLED;
-}
-
-static u32 m8xx_get_graycode(u32 size)
-{
-	u32 k;
-
-	for (k = 0; k < M8XX_SIZES_NO; k++)
-		if (m8xx_size_to_gray[k] == size)
-			break;
-
-	if ((k == M8XX_SIZES_NO) || (m8xx_size_to_gray[k] == -1))
-		k = -1;
-
-	return k;
-}
-
-static u32 m8xx_get_speed(u32 ns, u32 is_io, u32 bus_freq)
-{
-	u32 reg, clocks, psst, psl, psht;
-
-	if (!ns) {
-
-		/*
-		 * We get called with IO maps setup to 0ns
-		 * if not specified by the user.
-		 * They should be 255ns.
-		 */
-
-		if (is_io)
-			ns = 255;
-		else
-			ns = 100;	/* fast memory if 0 */
-	}
-
-	/*
-	 * In PSST, PSL, PSHT fields we tell the controller
-	 * timing parameters in CLKOUT clock cycles.
-	 * CLKOUT is the same as GCLK2_50.
-	 */
-
-/* how we want to adjust the timing - in percent */
-
-#define ADJ 180			/* 80 % longer accesstime - to be sure */
-
-	clocks = ((bus_freq / 1000) * ns) / 1000;
-	clocks = (clocks * ADJ) / (100 * 1000);
-	if (clocks >= PCMCIA_BMT_LIMIT) {
-		printk("Max access time limit reached\n");
-		clocks = PCMCIA_BMT_LIMIT - 1;
-	}
-
-	psst = clocks / 7;	/* setup time */
-	psht = clocks / 7;	/* hold time */
-	psl = (clocks * 5) / 7;	/* strobe length */
-
-	psst += clocks - (psst + psht + psl);
-
-	reg = psst << 12;
-	reg |= psl << 7;
-	reg |= psht << 16;
-
-	return reg;
-}
-
-static int m8xx_get_status(struct pcmcia_socket *sock, unsigned int *value)
-{
-	int lsock = container_of(sock, struct socket_info, socket)->slot;
-	struct socket_info *s = &socket[lsock];
-	unsigned int pipr, reg;
-	pcmconf8xx_t *pcmcia = s->pcmcia;
-
-	pipr = in_be32(&pcmcia->pcmc_pipr);
-
-	*value = ((pipr & (M8XX_PCMCIA_CD1(lsock)
-			   | M8XX_PCMCIA_CD2(lsock))) == 0) ? SS_DETECT : 0;
-	*value |= (pipr & M8XX_PCMCIA_WP(lsock)) ? SS_WRPROT : 0;
-
-	if (s->state.flags & SS_IOCARD)
-		*value |= (pipr & M8XX_PCMCIA_BVD1(lsock)) ? SS_STSCHG : 0;
-	else {
-		*value |= (pipr & M8XX_PCMCIA_RDY(lsock)) ? SS_READY : 0;
-		*value |= (pipr & M8XX_PCMCIA_BVD1(lsock)) ? SS_BATDEAD : 0;
-		*value |= (pipr & M8XX_PCMCIA_BVD2(lsock)) ? SS_BATWARN : 0;
-	}
-
-	if (s->state.Vcc | s->state.Vpp)
-		*value |= SS_POWERON;
-
-	/*
-	 * Voltage detection:
-	 * This driver only supports 16-Bit pc-cards.
-	 * Cardbus is not handled here.
-	 *
-	 * To determine what voltage to use we must read the VS1 and VS2 pin.
-	 * Depending on what socket type is present,
-	 * different combinations mean different things.
-	 *
-	 * Card Key  Socket Key   VS1   VS2   Card         Vcc for CIS parse
-	 *
-	 * 5V        5V, LV*      NC    NC    5V only       5V (if available)
-	 *
-	 * 5V        5V, LV*      GND   NC    5 or 3.3V     as low as possible
-	 *
-	 * 5V        5V, LV*      GND   GND   5, 3.3, x.xV  as low as possible
-	 *
-	 * LV*       5V            -     -    shall not fit into socket
-	 *
-	 * LV*       LV*          GND   NC    3.3V only     3.3V
-	 *
-	 * LV*       LV*          NC    GND   x.xV          x.xV (if avail.)
-	 *
-	 * LV*       LV*          GND   GND   3.3 or x.xV   as low as possible
-	 *
-	 * *LV means Low Voltage
-	 *
-	 *
-	 * That gives us the following table:
-	 *
-	 * Socket    VS1  VS2   Voltage
-	 *
-	 * 5V        NC   NC    5V
-	 * 5V        NC   GND   none (should not be possible)
-	 * 5V        GND  NC    >= 3.3V
-	 * 5V        GND  GND   >= x.xV
-	 *
-	 * LV        NC   NC    5V   (if available)
-	 * LV        NC   GND   x.xV (if available)
-	 * LV        GND  NC    3.3V
-	 * LV        GND  GND   >= x.xV
-	 *
-	 * So, how do I determine if I have a 5V or a LV
-	 * socket on my board?  Look at the socket!
-	 *
-	 *
-	 * Socket with 5V key:
-	 * ++--------------------------------------------+
-	 * ||                                            |
-	 * ||                                           ||
-	 * ||                                           ||
-	 * |                                             |
-	 * +---------------------------------------------+
-	 *
-	 * Socket with LV key:
-	 * ++--------------------------------------------+
-	 * ||                                            |
-	 * |                                            ||
-	 * |                                            ||
-	 * |                                             |
-	 * +---------------------------------------------+
-	 *
-	 *
-	 * With other words - LV only cards does not fit
-	 * into the 5V socket!
-	 */
-
-	/* read out VS1 and VS2 */
-
-	reg = (pipr & M8XX_PCMCIA_VS_MASK(lsock))
-	    >> M8XX_PCMCIA_VS_SHIFT(lsock);
-
-	if (socket_get(lsock) == PCMCIA_SOCKET_KEY_LV) {
-		switch (reg) {
-		case 1:
-			*value |= SS_3VCARD;
-			break;	/* GND, NC - 3.3V only */
-		case 2:
-			*value |= SS_XVCARD;
-			break;	/* NC. GND - x.xV only */
-		};
-	}
-
-	pr_debug("m8xx_pcmcia: GetStatus(%d) = %#2.2x\n", lsock, *value);
-	return 0;
-}
-
-static int m8xx_set_socket(struct pcmcia_socket *sock, socket_state_t * state)
-{
-	int lsock = container_of(sock, struct socket_info, socket)->slot;
-	struct socket_info *s = &socket[lsock];
-	struct event_table *e;
-	unsigned int reg;
-	unsigned long flags;
-	pcmconf8xx_t *pcmcia = socket[0].pcmcia;
-
-	pr_debug("m8xx_pcmcia: SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, "
-		"io_irq %d, csc_mask %#2.2x)\n", lsock, state->flags,
-		state->Vcc, state->Vpp, state->io_irq, state->csc_mask);
-
-	/* First, set voltage - bail out if invalid */
-	if (voltage_set(lsock, state->Vcc, state->Vpp))
-		return -EINVAL;
-
-	/* Take care of reset... */
-	if (state->flags & SS_RESET)
-		out_be32(M8XX_PGCRX(lsock), in_be32(M8XX_PGCRX(lsock)) | M8XX_PGCRX_CXRESET);	/* active high */
-	else
-		out_be32(M8XX_PGCRX(lsock),
-			 in_be32(M8XX_PGCRX(lsock)) & ~M8XX_PGCRX_CXRESET);
-
-	/* ... and output enable. */
-
-	/* The CxOE signal is connected to a 74541 on the ADS.
-	   I guess most other boards used the ADS as a reference.
-	   I tried to control the CxOE signal with SS_OUTPUT_ENA,
-	   but the reset signal seems connected via the 541.
-	   If the CxOE is left high are some signals tristated and
-	   no pullups are present -> the cards act weird.
-	   So right now the buffers are enabled if the power is on. */
-
-	if (state->Vcc || state->Vpp)
-		out_be32(M8XX_PGCRX(lsock), in_be32(M8XX_PGCRX(lsock)) & ~M8XX_PGCRX_CXOE);	/* active low */
-	else
-		out_be32(M8XX_PGCRX(lsock),
-			 in_be32(M8XX_PGCRX(lsock)) | M8XX_PGCRX_CXOE);
-
-	/*
-	 * We'd better turn off interrupts before
-	 * we mess with the events-table..
-	 */
-
-	spin_lock_irqsave(&events_lock, flags);
-
-	/*
-	 * Play around with the interrupt mask to be able to
-	 * give the events the generic pcmcia driver wants us to.
-	 */
-
-	e = &s->events[0];
-	reg = 0;
-
-	if (state->csc_mask & SS_DETECT) {
-		e->eventbit = SS_DETECT;
-		reg |= e->regbit = (M8XX_PCMCIA_CD2(lsock)
-				    | M8XX_PCMCIA_CD1(lsock));
-		e++;
-	}
-	if (state->flags & SS_IOCARD) {
-		/*
-		 * I/O card
-		 */
-		if (state->csc_mask & SS_STSCHG) {
-			e->eventbit = SS_STSCHG;
-			reg |= e->regbit = M8XX_PCMCIA_BVD1(lsock);
-			e++;
-		}
-		/*
-		 * If io_irq is non-zero we should enable irq.
-		 */
-		if (state->io_irq) {
-			out_be32(M8XX_PGCRX(lsock),
-				 in_be32(M8XX_PGCRX(lsock)) |
-				 mk_int_int_mask(s->hwirq) << 24);
-			/*
-			 * Strange thing here:
-			 * The manual does not tell us which interrupt
-			 * the sources generate.
-			 * Anyhow, I found out that RDY_L generates IREQLVL.
-			 *
-			 * We use level triggerd interrupts, and they don't
-			 * have to be cleared in PSCR in the interrupt handler.
-			 */
-			reg |= M8XX_PCMCIA_RDY_L(lsock);
-		} else
-			out_be32(M8XX_PGCRX(lsock),
-				 in_be32(M8XX_PGCRX(lsock)) & 0x00ffffff);
-	} else {
-		/*
-		 * Memory card
-		 */
-		if (state->csc_mask & SS_BATDEAD) {
-			e->eventbit = SS_BATDEAD;
-			reg |= e->regbit = M8XX_PCMCIA_BVD1(lsock);
-			e++;
-		}
-		if (state->csc_mask & SS_BATWARN) {
-			e->eventbit = SS_BATWARN;
-			reg |= e->regbit = M8XX_PCMCIA_BVD2(lsock);
-			e++;
-		}
-		/* What should I trigger on - low/high,raise,fall? */
-		if (state->csc_mask & SS_READY) {
-			e->eventbit = SS_READY;
-			reg |= e->regbit = 0;	//??
-			e++;
-		}
-	}
-
-	e->regbit = 0;		/* terminate list */
-
-	/*
-	 * Clear the status changed .
-	 * Port A and Port B share the same port.
-	 * Writing ones will clear the bits.
-	 */
-
-	out_be32(&pcmcia->pcmc_pscr, reg);
-
-	/*
-	 * Write the mask.
-	 * Port A and Port B share the same port.
-	 * Need for read-modify-write.
-	 * Ones will enable the interrupt.
-	 */
-
-	reg |=
-	    in_be32(&pcmcia->
-		    pcmc_per) & (M8XX_PCMCIA_MASK(0) | M8XX_PCMCIA_MASK(1));
-	out_be32(&pcmcia->pcmc_per, reg);
-
-	spin_unlock_irqrestore(&events_lock, flags);
-
-	/* copy the struct and modify the copy */
-
-	s->state = *state;
-
-	return 0;
-}
-
-static int m8xx_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *io)
-{
-	int lsock = container_of(sock, struct socket_info, socket)->slot;
-
-	struct socket_info *s = &socket[lsock];
-	struct pcmcia_win *w;
-	unsigned int reg, winnr;
-	pcmconf8xx_t *pcmcia = s->pcmcia;
-
-#define M8XX_SIZE (io->stop - io->start + 1)
-#define M8XX_BASE (PCMCIA_IO_WIN_BASE + io->start)
-
-	pr_debug("m8xx_pcmcia: SetIOMap(%d, %d, %#2.2x, %d ns, "
-		"%#4.4llx-%#4.4llx)\n", lsock, io->map, io->flags,
-		io->speed, (unsigned long long)io->start,
-		(unsigned long long)io->stop);
-
-	if ((io->map >= PCMCIA_IO_WIN_NO) || (io->start > 0xffff)
-	    || (io->stop > 0xffff) || (io->stop < io->start))
-		return -EINVAL;
-
-	if ((reg = m8xx_get_graycode(M8XX_SIZE)) == -1)
-		return -EINVAL;
-
-	if (io->flags & MAP_ACTIVE) {
-
-		pr_debug("m8xx_pcmcia: io->flags & MAP_ACTIVE\n");
-
-		winnr = (PCMCIA_MEM_WIN_NO * PCMCIA_SOCKETS_NO)
-		    + (lsock * PCMCIA_IO_WIN_NO) + io->map;
-
-		/* setup registers */
-
-		w = (void *)&pcmcia->pcmc_pbr0;
-		w += winnr;
-
-		out_be32(&w->or, 0);	/* turn off window first */
-		out_be32(&w->br, M8XX_BASE);
-
-		reg <<= 27;
-		reg |= M8XX_PCMCIA_POR_IO | (lsock << 2);
-
-		reg |= m8xx_get_speed(io->speed, 1, s->bus_freq);
-
-		if (io->flags & MAP_WRPROT)
-			reg |= M8XX_PCMCIA_POR_WRPROT;
-
-		/*if(io->flags & (MAP_16BIT | MAP_AUTOSZ)) */
-		if (io->flags & MAP_16BIT)
-			reg |= M8XX_PCMCIA_POR_16BIT;
-
-		if (io->flags & MAP_ACTIVE)
-			reg |= M8XX_PCMCIA_POR_VALID;
-
-		out_be32(&w->or, reg);
-
-		pr_debug("m8xx_pcmcia: Socket %u: Mapped io window %u at "
-			"%#8.8x, OR = %#8.8x.\n", lsock, io->map, w->br, w->or);
-	} else {
-		/* shutdown IO window */
-		winnr = (PCMCIA_MEM_WIN_NO * PCMCIA_SOCKETS_NO)
-		    + (lsock * PCMCIA_IO_WIN_NO) + io->map;
-
-		/* setup registers */
-
-		w = (void *)&pcmcia->pcmc_pbr0;
-		w += winnr;
-
-		out_be32(&w->or, 0);	/* turn off window */
-		out_be32(&w->br, 0);	/* turn off base address */
-
-		pr_debug("m8xx_pcmcia: Socket %u: Unmapped io window %u at "
-			"%#8.8x, OR = %#8.8x.\n", lsock, io->map, w->br, w->or);
-	}
-
-	/* copy the struct and modify the copy */
-	s->io_win[io->map] = *io;
-	s->io_win[io->map].flags &= (MAP_WRPROT | MAP_16BIT | MAP_ACTIVE);
-	pr_debug("m8xx_pcmcia: SetIOMap exit\n");
-
-	return 0;
-}
-
-static int m8xx_set_mem_map(struct pcmcia_socket *sock,
-			    struct pccard_mem_map *mem)
-{
-	int lsock = container_of(sock, struct socket_info, socket)->slot;
-	struct socket_info *s = &socket[lsock];
-	struct pcmcia_win *w;
-	struct pccard_mem_map *old;
-	unsigned int reg, winnr;
-	pcmconf8xx_t *pcmcia = s->pcmcia;
-
-	pr_debug("m8xx_pcmcia: SetMemMap(%d, %d, %#2.2x, %d ns, "
-		"%#5.5llx, %#5.5x)\n", lsock, mem->map, mem->flags,
-		mem->speed, (unsigned long long)mem->static_start,
-		mem->card_start);
-
-	if ((mem->map >= PCMCIA_MEM_WIN_NO)
-//          || ((mem->s) >= PCMCIA_MEM_WIN_SIZE)
-	    || (mem->card_start >= 0x04000000)
-	    || (mem->static_start & 0xfff)	/* 4KByte resolution */
-	    ||(mem->card_start & 0xfff))
-		return -EINVAL;
-
-	if ((reg = m8xx_get_graycode(PCMCIA_MEM_WIN_SIZE)) == -1) {
-		printk("Cannot set size to 0x%08x.\n", PCMCIA_MEM_WIN_SIZE);
-		return -EINVAL;
-	}
-	reg <<= 27;
-
-	winnr = (lsock * PCMCIA_MEM_WIN_NO) + mem->map;
-
-	/* Setup the window in the pcmcia controller */
-
-	w = (void *)&pcmcia->pcmc_pbr0;
-	w += winnr;
-
-	reg |= lsock << 2;
-
-	reg |= m8xx_get_speed(mem->speed, 0, s->bus_freq);
-
-	if (mem->flags & MAP_ATTRIB)
-		reg |= M8XX_PCMCIA_POR_ATTRMEM;
-
-	if (mem->flags & MAP_WRPROT)
-		reg |= M8XX_PCMCIA_POR_WRPROT;
-
-	if (mem->flags & MAP_16BIT)
-		reg |= M8XX_PCMCIA_POR_16BIT;
-
-	if (mem->flags & MAP_ACTIVE)
-		reg |= M8XX_PCMCIA_POR_VALID;
-
-	out_be32(&w->or, reg);
-
-	pr_debug("m8xx_pcmcia: Socket %u: Mapped memory window %u at %#8.8x, "
-		"OR = %#8.8x.\n", lsock, mem->map, w->br, w->or);
-
-	if (mem->flags & MAP_ACTIVE) {
-		/* get the new base address */
-		mem->static_start = PCMCIA_MEM_WIN_BASE +
-		    (PCMCIA_MEM_WIN_SIZE * winnr)
-		    + mem->card_start;
-	}
-
-	pr_debug("m8xx_pcmcia: SetMemMap(%d, %d, %#2.2x, %d ns, "
-		"%#5.5llx, %#5.5x)\n", lsock, mem->map, mem->flags,
-		mem->speed, (unsigned long long)mem->static_start,
-		mem->card_start);
-
-	/* copy the struct and modify the copy */
-
-	old = &s->mem_win[mem->map];
-
-	*old = *mem;
-	old->flags &= (MAP_ATTRIB | MAP_WRPROT | MAP_16BIT | MAP_ACTIVE);
-
-	return 0;
-}
-
-static int m8xx_sock_init(struct pcmcia_socket *sock)
-{
-	int i;
-	pccard_io_map io = { 0, 0, 0, 0, 1 };
-	pccard_mem_map mem = { 0, 0, 0, 0, 0, 0 };
-
-	pr_debug("m8xx_pcmcia: sock_init(%d)\n", s);
-
-	m8xx_set_socket(sock, &dead_socket);
-	for (i = 0; i < PCMCIA_IO_WIN_NO; i++) {
-		io.map = i;
-		m8xx_set_io_map(sock, &io);
-	}
-	for (i = 0; i < PCMCIA_MEM_WIN_NO; i++) {
-		mem.map = i;
-		m8xx_set_mem_map(sock, &mem);
-	}
-
-	return 0;
-
-}
-
-static int m8xx_sock_suspend(struct pcmcia_socket *sock)
-{
-	return m8xx_set_socket(sock, &dead_socket);
-}
-
-static struct pccard_operations m8xx_services = {
-	.init = m8xx_sock_init,
-	.suspend = m8xx_sock_suspend,
-	.get_status = m8xx_get_status,
-	.set_socket = m8xx_set_socket,
-	.set_io_map = m8xx_set_io_map,
-	.set_mem_map = m8xx_set_mem_map,
-};
-
-static int __init m8xx_probe(struct platform_device *ofdev)
-{
-	struct pcmcia_win *w;
-	unsigned int i, m, hwirq;
-	pcmconf8xx_t *pcmcia;
-	int status;
-	struct device_node *np = ofdev->dev.of_node;
-
-	pcmcia_info("%s\n", version);
-
-	pcmcia = of_iomap(np, 0);
-	if (pcmcia == NULL)
-		return -EINVAL;
-
-	pcmcia_schlvl = irq_of_parse_and_map(np, 0);
-	hwirq = irq_map[pcmcia_schlvl].hwirq;
-	if (pcmcia_schlvl < 0) {
-		iounmap(pcmcia);
-		return -EINVAL;
-	}
-
-	m8xx_pgcrx[0] = &pcmcia->pcmc_pgcra;
-	m8xx_pgcrx[1] = &pcmcia->pcmc_pgcrb;
-
-	pcmcia_info(PCMCIA_BOARD_MSG " using " PCMCIA_SLOT_MSG
-		    " with IRQ %u  (%d). \n", pcmcia_schlvl, hwirq);
-
-	/* Configure Status change interrupt */
-
-	if (request_irq(pcmcia_schlvl, m8xx_interrupt, IRQF_SHARED,
-			driver_name, socket)) {
-		pcmcia_error("Cannot allocate IRQ %u for SCHLVL!\n",
-			     pcmcia_schlvl);
-		iounmap(pcmcia);
-		return -1;
-	}
-
-	w = (void *)&pcmcia->pcmc_pbr0;
-
-	out_be32(&pcmcia->pcmc_pscr, M8XX_PCMCIA_MASK(0) | M8XX_PCMCIA_MASK(1));
-	clrbits32(&pcmcia->pcmc_per, M8XX_PCMCIA_MASK(0) | M8XX_PCMCIA_MASK(1));
-
-	/* connect interrupt and disable CxOE */
-
-	out_be32(M8XX_PGCRX(0),
-		 M8XX_PGCRX_CXOE | (mk_int_int_mask(hwirq) << 16));
-	out_be32(M8XX_PGCRX(1),
-		 M8XX_PGCRX_CXOE | (mk_int_int_mask(hwirq) << 16));
-
-	/* initialize the fixed memory windows */
-
-	for (i = 0; i < PCMCIA_SOCKETS_NO; i++) {
-		for (m = 0; m < PCMCIA_MEM_WIN_NO; m++) {
-			out_be32(&w->br, PCMCIA_MEM_WIN_BASE +
-				 (PCMCIA_MEM_WIN_SIZE
-				  * (m + i * PCMCIA_MEM_WIN_NO)));
-
-			out_be32(&w->or, 0);	/* set to not valid */
-
-			w++;
-		}
-	}
-
-	/* turn off voltage */
-	voltage_set(0, 0, 0);
-	voltage_set(1, 0, 0);
-
-	/* Enable external hardware */
-	hardware_enable(0);
-	hardware_enable(1);
-
-	for (i = 0; i < PCMCIA_SOCKETS_NO; i++) {
-		socket[i].slot = i;
-		socket[i].socket.owner = THIS_MODULE;
-		socket[i].socket.features =
-		    SS_CAP_PCCARD | SS_CAP_MEM_ALIGN | SS_CAP_STATIC_MAP;
-		socket[i].socket.irq_mask = 0x000;
-		socket[i].socket.map_size = 0x1000;
-		socket[i].socket.io_offset = 0;
-		socket[i].socket.pci_irq = pcmcia_schlvl;
-		socket[i].socket.ops = &m8xx_services;
-		socket[i].socket.resource_ops = &pccard_iodyn_ops;
-		socket[i].socket.cb_dev = NULL;
-		socket[i].socket.dev.parent = &ofdev->dev;
-		socket[i].pcmcia = pcmcia;
-		socket[i].bus_freq = ppc_proc_freq;
-		socket[i].hwirq = hwirq;
-
-	}
-
-	for (i = 0; i < PCMCIA_SOCKETS_NO; i++) {
-		status = pcmcia_register_socket(&socket[i].socket);
-		if (status < 0)
-			pcmcia_error("Socket register failed\n");
-	}
-
-	return 0;
-}
-
-static int m8xx_remove(struct platform_device *ofdev)
-{
-	u32 m, i;
-	struct pcmcia_win *w;
-	pcmconf8xx_t *pcmcia = socket[0].pcmcia;
-
-	for (i = 0; i < PCMCIA_SOCKETS_NO; i++) {
-		w = (void *)&pcmcia->pcmc_pbr0;
-
-		out_be32(&pcmcia->pcmc_pscr, M8XX_PCMCIA_MASK(i));
-		out_be32(&pcmcia->pcmc_per,
-			 in_be32(&pcmcia->pcmc_per) & ~M8XX_PCMCIA_MASK(i));
-
-		/* turn off interrupt and disable CxOE */
-		out_be32(M8XX_PGCRX(i), M8XX_PGCRX_CXOE);
-
-		/* turn off memory windows */
-		for (m = 0; m < PCMCIA_MEM_WIN_NO; m++) {
-			out_be32(&w->or, 0);	/* set to not valid */
-			w++;
-		}
-
-		/* turn off voltage */
-		voltage_set(i, 0, 0);
-
-		/* disable external hardware */
-		hardware_disable(i);
-	}
-	for (i = 0; i < PCMCIA_SOCKETS_NO; i++)
-		pcmcia_unregister_socket(&socket[i].socket);
-	iounmap(pcmcia);
-
-	free_irq(pcmcia_schlvl, NULL);
-
-	return 0;
-}
-
-static const struct of_device_id m8xx_pcmcia_match[] = {
-	{
-	 .type = "pcmcia",
-	 .compatible = "fsl,pq-pcmcia",
-	 },
-	{},
-};
-
-MODULE_DEVICE_TABLE(of, m8xx_pcmcia_match);
-
-static struct platform_driver m8xx_pcmcia_driver = {
-	.driver = {
-		.name = driver_name,
-		.owner = THIS_MODULE,
-		.of_match_table = m8xx_pcmcia_match,
-	},
-	.probe = m8xx_probe,
-	.remove = m8xx_remove,
-};
-
-module_platform_driver(m8xx_pcmcia_driver);
-- 
1.9.1

^ permalink raw reply related

* [PATCH 2/2] powerpc/8xx: Remove empty asm/mpc8xx.h
From: Scott Wood @ 2014-06-21  1:02 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Scott Wood, netdev
In-Reply-To: <1403312527-4453-1-git-send-email-scottwood@freescale.com>

m8xx_pcmcia_ops was the only thing in this file (other than a comment
that describes a usage that doesn't match the file's contents); now
that m8xx_pcmcia_ops is gone, remove the empty file.

Signed-off-by: Scott Wood <scottwood@freescale.com>
Cc: Pantelis Antoniou <pantelis.antoniou@gmail.com>
Cc: Vitaly Bordug <vitb@kernel.crashing.org>
Cc: netdev@vger.kernel.org
---
 arch/powerpc/include/asm/fs_pd.h                 |  1 -
 arch/powerpc/include/asm/mpc8xx.h                | 10 ----------
 arch/powerpc/platforms/8xx/m8xx_setup.c          |  1 -
 arch/powerpc/platforms/8xx/mpc885ads_setup.c     |  1 -
 arch/powerpc/platforms/8xx/tqm8xx_setup.c        |  1 -
 arch/powerpc/sysdev/micropatch.c                 |  1 -
 drivers/net/ethernet/freescale/fs_enet/mac-fec.c |  1 -
 drivers/net/ethernet/freescale/fs_enet/mac-scc.c |  1 -
 8 files changed, 17 deletions(-)
 delete mode 100644 arch/powerpc/include/asm/mpc8xx.h

diff --git a/arch/powerpc/include/asm/fs_pd.h b/arch/powerpc/include/asm/fs_pd.h
index 9361cd5..f79d6c7 100644
--- a/arch/powerpc/include/asm/fs_pd.h
+++ b/arch/powerpc/include/asm/fs_pd.h
@@ -28,7 +28,6 @@
 
 #ifdef CONFIG_8xx
 #include <asm/8xx_immap.h>
-#include <asm/mpc8xx.h>
 
 extern immap_t __iomem *mpc8xx_immr;
 
diff --git a/arch/powerpc/include/asm/mpc8xx.h b/arch/powerpc/include/asm/mpc8xx.h
deleted file mode 100644
index 8ab22e8..0000000
--- a/arch/powerpc/include/asm/mpc8xx.h
+++ /dev/null
@@ -1,10 +0,0 @@
-/* This is the single file included by all MPC8xx build options.
- * Since there are many different boards and no standard configuration,
- * we have a unique include file for each.  Rather than change every
- * file that has to include MPC8xx configuration, they all include
- * this one and the configuration switching is done here.
- */
-#ifndef __CONFIG_8xx_DEFS
-#define __CONFIG_8xx_DEFS
-
-#endif /* __CONFIG_8xx_DEFS */
diff --git a/arch/powerpc/platforms/8xx/m8xx_setup.c b/arch/powerpc/platforms/8xx/m8xx_setup.c
index 623bb43..d303774 100644
--- a/arch/powerpc/platforms/8xx/m8xx_setup.c
+++ b/arch/powerpc/platforms/8xx/m8xx_setup.c
@@ -18,7 +18,6 @@
 #include <linux/fsl_devices.h>
 
 #include <asm/io.h>
-#include <asm/mpc8xx.h>
 #include <asm/8xx_immap.h>
 #include <asm/prom.h>
 #include <asm/fs_pd.h>
diff --git a/arch/powerpc/platforms/8xx/mpc885ads_setup.c b/arch/powerpc/platforms/8xx/mpc885ads_setup.c
index 3d5e4e1..5921dcb 100644
--- a/arch/powerpc/platforms/8xx/mpc885ads_setup.c
+++ b/arch/powerpc/platforms/8xx/mpc885ads_setup.c
@@ -35,7 +35,6 @@
 #include <asm/page.h>
 #include <asm/processor.h>
 #include <asm/time.h>
-#include <asm/mpc8xx.h>
 #include <asm/8xx_immap.h>
 #include <asm/cpm1.h>
 #include <asm/fs_pd.h>
diff --git a/arch/powerpc/platforms/8xx/tqm8xx_setup.c b/arch/powerpc/platforms/8xx/tqm8xx_setup.c
index 251aba8..dda6078 100644
--- a/arch/powerpc/platforms/8xx/tqm8xx_setup.c
+++ b/arch/powerpc/platforms/8xx/tqm8xx_setup.c
@@ -37,7 +37,6 @@
 #include <asm/page.h>
 #include <asm/processor.h>
 #include <asm/time.h>
-#include <asm/mpc8xx.h>
 #include <asm/8xx_immap.h>
 #include <asm/cpm1.h>
 #include <asm/fs_pd.h>
diff --git a/arch/powerpc/sysdev/micropatch.c b/arch/powerpc/sysdev/micropatch.c
index c0bb76e..6727dc5 100644
--- a/arch/powerpc/sysdev/micropatch.c
+++ b/arch/powerpc/sysdev/micropatch.c
@@ -13,7 +13,6 @@
 #include <linux/mm.h>
 #include <linux/interrupt.h>
 #include <asm/irq.h>
-#include <asm/mpc8xx.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/8xx_immap.h>
diff --git a/drivers/net/ethernet/freescale/fs_enet/mac-fec.c b/drivers/net/ethernet/freescale/fs_enet/mac-fec.c
index fc54134..1eedfba 100644
--- a/drivers/net/ethernet/freescale/fs_enet/mac-fec.c
+++ b/drivers/net/ethernet/freescale/fs_enet/mac-fec.c
@@ -41,7 +41,6 @@
 #ifdef CONFIG_8xx
 #include <asm/8xx_immap.h>
 #include <asm/pgtable.h>
-#include <asm/mpc8xx.h>
 #include <asm/cpm1.h>
 #endif
 
diff --git a/drivers/net/ethernet/freescale/fs_enet/mac-scc.c b/drivers/net/ethernet/freescale/fs_enet/mac-scc.c
index b4bf02f..90b3b19 100644
--- a/drivers/net/ethernet/freescale/fs_enet/mac-scc.c
+++ b/drivers/net/ethernet/freescale/fs_enet/mac-scc.c
@@ -40,7 +40,6 @@
 #ifdef CONFIG_8xx
 #include <asm/8xx_immap.h>
 #include <asm/pgtable.h>
-#include <asm/mpc8xx.h>
 #include <asm/cpm1.h>
 #endif
 
-- 
1.9.1

^ permalink raw reply related

* Re: [PATCH 2/2] powerpc/8xx: Remove empty asm/mpc8xx.h
From: David Miller @ 2014-06-21  3:15 UTC (permalink / raw)
  To: scottwood; +Cc: netdev, linuxppc-dev
In-Reply-To: <1403312527-4453-2-git-send-email-scottwood@freescale.com>

From: Scott Wood <scottwood@freescale.com>
Date: Fri, 20 Jun 2014 20:02:07 -0500

> m8xx_pcmcia_ops was the only thing in this file (other than a comment
> that describes a usage that doesn't match the file's contents); now
> that m8xx_pcmcia_ops is gone, remove the empty file.
> 
> Signed-off-by: Scott Wood <scottwood@freescale.com>

For networking bits:

Acked-by: David S. Miller <davem@davemloft.net>

^ permalink raw reply

* Re: [RFC PATCH 1/7] mmc: sdhci: add quirk for broken 3.0V support
From: Vincent Yang @ 2014-06-21  4:29 UTC (permalink / raw)
  To: Anton Vorontsov
  Cc: Andy Green, patches, linux-mmc, chris, Vincent Yang, linuxppc-dev
In-Reply-To: <20140620202638.GA21349@teo>

Hi Anton,
Thanks a lot for your review.
I will update it in next version.


Best regards,
Vincent Yang

2014-06-21 4:26 GMT+08:00 Anton Vorontsov <anton@enomsg.org>:
> On Fri, Jun 20, 2014 at 05:35:22PM +0800, Vincent Yang wrote:
>> This patch defines a quirk for platforms unable
>> to enable 3.0V support.
>> It is a preparation and will be used by Fujitsu
>> SDHCI controller f_sdh30 driver.
>>
>> Signed-off-by: Vincent Yang <Vincent.Yang@tw.fujitsu.com>
>
> I don't think you need this patch. Instead, you can exclude 3V using the
> voltage-ranges = <> in the device tree.
>
> Thanks,
>
> Anton
>
>>  drivers/mmc/host/sdhci.c  | 3 +++
>>  include/linux/mmc/sdhci.h | 2 ++
>>  2 files changed, 5 insertions(+)
>>
>> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
>> index 47055f3..523075f 100644
>> --- a/drivers/mmc/host/sdhci.c
>> +++ b/drivers/mmc/host/sdhci.c
>> @@ -3069,6 +3069,9 @@ int sdhci_add_host(struct sdhci_host *host)
>>       }
>>  #endif /* CONFIG_REGULATOR */
>>
>> +     if (host->quirks2 & SDHCI_QUIRK2_NO_3_0_V)
>> +             caps[0] &= ~SDHCI_CAN_VDD_300;
>> +
>>       /*
>>        * According to SD Host Controller spec v3.00, if the Host System
>>        * can afford more than 150mA, Host Driver should set XPC to 1. Also
>> diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
>> index 08abe99..cac0958 100644
>> --- a/include/linux/mmc/sdhci.h
>> +++ b/include/linux/mmc/sdhci.h
>> @@ -98,6 +98,8 @@ struct sdhci_host {
>>  #define SDHCI_QUIRK2_BROKEN_HS200                    (1<<6)
>>  /* Controller does not support DDR50 */
>>  #define SDHCI_QUIRK2_BROKEN_DDR50                    (1<<7)
>> +/* The system physically doesn't support 3.0v, even if the host does */
>> +#define SDHCI_QUIRK2_NO_3_0_V                                (1<<8)
>>
>>       int irq;                /* Device IRQ */
>>       void __iomem *ioaddr;   /* Mapped address */
>> --
>> 1.9.0

^ permalink raw reply

* [PATCH 5/9] [arch/powerpc] replace obsolete strict_strto* calls
From: Daniel Walter @ 2014-06-21 12:05 UTC (permalink / raw)
  To: Benjamin Herrenschmidt, linux-kernel; +Cc: linuxppc-dev

Replace strict_strto calls with more appropriate kstrto calls

Signed-off-by: Daniel Walter <dwalter@google.com>
---
 arch/powerpc/kernel/setup_64.c            | 6 +++---
 arch/powerpc/kernel/vio.c                 | 2 +-
 arch/powerpc/platforms/pseries/dlpar.c    | 4 ++--
 arch/powerpc/platforms/pseries/mobility.c | 2 +-
 4 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index ee082d7..5257166 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -149,13 +149,13 @@ static void check_smt_enabled(void)
 		else if (!strcmp(smt_enabled_cmdline, "off"))
 			smt_enabled_at_boot = 0;
 		else {
-			long smt;
+			int smt;
 			int rc;
 
-			rc = strict_strtol(smt_enabled_cmdline, 10, &smt);
+			rc = kstrtoint(smt_enabled_cmdline, 10, &smt);
 			if (!rc)
 				smt_enabled_at_boot =
-					min(threads_per_core, (int)smt);
+					min(threads_per_core, smt);
 		}
 	} else {
 		dn = of_find_node_by_path("/options");
diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c
index 904c661..5bfdab9 100644
--- a/arch/powerpc/kernel/vio.c
+++ b/arch/powerpc/kernel/vio.c
@@ -977,7 +977,7 @@ static ssize_t viodev_cmo_desired_set(struct device *dev,
 	size_t new_desired;
 	int ret;
 
-	ret = strict_strtoul(buf, 10, &new_desired);
+	ret = kstrtoul(buf, 10, &new_desired);
 	if (ret)
 		return ret;
 
diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c
index 022b38e..abc6892 100644
--- a/arch/powerpc/platforms/pseries/dlpar.c
+++ b/arch/powerpc/platforms/pseries/dlpar.c
@@ -399,10 +399,10 @@ out:
 static ssize_t dlpar_cpu_probe(const char *buf, size_t count)
 {
 	struct device_node *dn, *parent;
-	unsigned long drc_index;
+	u32 drc_index;
 	int rc;
 
-	rc = strict_strtoul(buf, 0, &drc_index);
+	rc = kstrtou32(buf, 0, &drc_index);
 	if (rc)
 		return -EINVAL;
 
diff --git a/arch/powerpc/platforms/pseries/mobility.c b/arch/powerpc/platforms/pseries/mobility.c
index bde7eba..0694ac6 100644
--- a/arch/powerpc/platforms/pseries/mobility.c
+++ b/arch/powerpc/platforms/pseries/mobility.c
@@ -319,7 +319,7 @@ static ssize_t migrate_store(struct class *class, struct class_attribute *attr,
 	u64 streamid;
 	int rc;
 
-	rc = strict_strtoull(buf, 0, &streamid);
+	rc = kstrtou64(buf, 0, &streamid);
 	if (rc)
 		return rc;
 
-- 
2.0.0.526.g5318336

^ permalink raw reply related

* Re: [PATCH v3] powerpc/powernv: hwmon driver for power, fan rpm, voltage and temperature
From: Guenter Roeck @ 2014-06-21 17:15 UTC (permalink / raw)
  To: Neelesh Gupta, linuxppc-dev, jdelvare, lm-sensors; +Cc: sbhat
In-Reply-To: <20140618083250.20069.73848.stgit@localhost.localdomain>

On 06/18/2014 01:35 AM, Neelesh Gupta wrote:
> This patch adds basic kernel enablement for reading power values, fan

how about support instead of enablement ?

> speed rpm, voltage and temperature data on powernv platforms which will
> be exported to user space through sysfs interface.
>
> Test results:
> -------------
> [root@ltctul57a-p1 ~]# sensors
> ibmpowernv-isa-0000
> Adapter: ISA adapter
> fan1:        5660 RPM  (min =    0 RPM)
> fan2:        5273 RPM  (min =    0 RPM)
> fan3:        5625 RPM  (min =    0 RPM)
> fan4:        5283 RPM  (min =    0 RPM)
> fan5:        5625 RPM  (min =    0 RPM)
> fan6:        5242 RPM  (min =    0 RPM)
> fan7:        5636 RPM  (min =    0 RPM)
> fan8:        5273 RPM  (min =    0 RPM)
> fan9:        4984 RPM  (min =    0 RPM)
> fan10:       4984 RPM  (min =    0 RPM)
> fan11:       4984 RPM  (min =    0 RPM)
> fan12:       4984 RPM  (min =    0 RPM)
> temp1:        +24.0 C  (high =  +0.0 C)
> power1:      573.00 W
>
> [root@ltctul57a-p1 ~]#
> [root@ltctul57a-p1 ~]# ls /sys/devices/platform/
> alarmtimer  ibmpowernv.0  rtc-generic  serial8250  uevent
> [root@ltctul57a-p1 ~]# ls /sys/devices/platform/ibmpowernv.0/hwmon/hwmon0/
> device	     fan12_input  fan3_fault  fan5_min	  fan8_input  in4_fault
> fan10_fault  fan12_min	  fan3_input  fan6_fault  fan8_min    name
> fan10_input  fan1_fault   fan3_min    fan6_input  fan9_fault  power1_input
> fan10_min    fan1_input   fan4_fault  fan6_min	  fan9_input  subsystem
> fan11_fault  fan1_min	  fan4_input  fan7_fault  fan9_min    temp1_input
> fan11_input  fan2_fault   fan4_min    fan7_input  in1_fault   temp1_max
> fan11_min    fan2_input   fan5_fault  fan7_min	  in2_fault   uevent
> fan12_fault  fan2_min	  fan5_input  fan8_fault  in3_fault
> [root@ltctul57a-p1 ~]#
> [root@ltctul57a-p1 ~]# ls /sys/class/hwmon/hwmon0/
> device	     fan12_input  fan3_fault  fan5_min	  fan8_input  in4_fault
> fan10_fault  fan12_min	  fan3_input  fan6_fault  fan8_min    name
> fan10_input  fan1_fault   fan3_min    fan6_input  fan9_fault  power1_input
> fan10_min    fan1_input   fan4_fault  fan6_min	  fan9_input  subsystem
> fan11_fault  fan1_min	  fan4_input  fan7_fault  fan9_min    temp1_input
> fan11_input  fan2_fault   fan4_min    fan7_input  in1_fault   temp1_max
> fan11_min    fan2_input   fan5_fault  fan7_min	  in2_fault   uevent
> fan12_fault  fan2_min	  fan5_input  fan8_fault  in3_fault
> [root@ltctul57a-p1 ~]#
>
> Signed-off-by: Neelesh Gupta <neelegup@linux.vnet.ibm.com>
> ---
>
> Changes in V3
> =========
> - Fixed an endianness bug leading the driver to break on LE.
> - Fixed a bug that when one of the 'attribute_group' not populated, following
>    groups attributes were dropped.
> - Rewrite the get_sensor_index_attr() function to handle all the error scenarios
>    like 'sscanf' etc.
> - Fixed all the errors/warnings related to coding style/whitespace.
> - Added 'Documentation' files.
> - Addressed remaining review comments on V2.
>
> Changes in v2
> =============
> - Generic use of devm_* functions in hwmon like using devm_kzalloc() for dynamic
>    memory request, avoiding the need to explicit free of memory.
>    Adding 'struct attribute_group' as member of platform data structure to be
>    populated and then passed to devm_hwmon_device_register_with_groups().
>
>    Note: Having an array of pointers of 'attribute_group' and each group
>    corresponds to 'enum sensors' type. Not completely sure, if it's ideal or
>    could have just one group populated with attributes of sensor types?
>
> - 'ibmpowernv' is not hot-pluggable device so moving 'platform_driver' callback
>    function (probe) as part of __init code.
> - Fixed issues related to coding style.
> - Other general comments in v1.
>
>   .../devicetree/bindings/hwmon/ibmpowernv.txt       |   27 +
>   Documentation/hwmon/ibmpowernv                     |   41 ++
>   drivers/hwmon/Kconfig                              |   11 +
>   drivers/hwmon/Makefile                             |    1
>   drivers/hwmon/ibmpowernv.c                         |  366 ++++++++++++++++++++
>   5 files changed, 446 insertions(+)
>   create mode 100644 Documentation/devicetree/bindings/hwmon/ibmpowernv.txt
>   create mode 100644 Documentation/hwmon/ibmpowernv
>   create mode 100644 drivers/hwmon/ibmpowernv.c
>
> diff --git a/Documentation/devicetree/bindings/hwmon/ibmpowernv.txt b/Documentation/devicetree/bindings/hwmon/ibmpowernv.txt
> new file mode 100644
> index 0000000..e3bd1eb
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/hwmon/ibmpowernv.txt
> @@ -0,0 +1,27 @@
> +IBM POWERNV platform sensors
> +----------------------------
> +
> +Required node properties:
> +- compatible: must be one of
> +		"ibm,opal-sensor-cooling-fan"
> +		"ibm,opal-sensor-amb-temp"
> +		"ibm,opal-sensor-power-supply"
> +		"ibm,opal-sensor-power"
> +- sensor-id: an opaque id provided by the firmware to the kernel, identifies a
> +	     given sensor and its attribute data
> +
> +Example sensors node:
> +
> +cooling-fan#8-data {
> +	sensor-id = <0x7052107>;
> +	phandle = <0x10000028>;
> +	linux,phandle = <0x10000028>;
> +	compatible = "ibm,opal-sensor-cooling-fan";
> +};
> +
> +amb-temp#1-thrs {
> +	sensor-id = <0x5096000>;
> +	phandle = <0x10000017>;
> +	linux,phandle = <0x10000017>;
> +	compatible = "ibm,opal-sensor-amb-temp";
> +};
> diff --git a/Documentation/hwmon/ibmpowernv b/Documentation/hwmon/ibmpowernv
> new file mode 100644
> index 0000000..d9ce50e
> --- /dev/null
> +++ b/Documentation/hwmon/ibmpowernv
> @@ -0,0 +1,41 @@
> +Kernel Driver IBMPOWENV
> +=======================
> +
> +Supported systems:
> +  * Any recent IBM P servers based on POWERNV platform
> +
> +Author: Neelesh Gupta
> +
> +Description
> +-----------
> +
> +This driver implements reading the platform sensors data like temperature/fan/
> +voltage/power for 'POWERNV' platform.
> +
> +The driver uses the platform device infrastructure. It probes the device tree
> +for sensor devices during the __init phase and registers them with the 'hwmon'.
> +'hwmon' populates the 'sysfs' tree having attribute files, each for a given
> +sensor type and its attribute data.
> +
> +All the nodes in the DT appear under "/ibm,opal/sensors" and each valid node in
> +the DT maps to an attribute file in 'sysfs'. The node exports unique 'sensor-id'
> +which the driver uses to make an OPAL call to the firmware.
> +
> +Usage notes
> +-----------
> +The driver is built statically with the kernel by enabling the config
> +CONFIG_SENSORS_IBMPOWERNV. It can also be built as module 'ibmpowernv'.
> +
> +Sysfs attributes
> +----------------
> +
> +fanX_input		Measured RPM value.
> +fanX_min		Threshold RPM for alert generation.
> +fanX_fault		0: No fail condition
> +			1: Failing fan
> +tempX_input		Measured ambient temperature.
> +tempX_max		Threshold ambient temperature for alert generation.
> +inX_input		Measured power supply voltage
> +inX_fault		0: No fail condition.
> +			1: Failing power supply.
> +power1_input		System power consumption (milliWatts)

ABI says micro-watts. Code below agrees.

> diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
> index bc196f4..fc69112 100644
> --- a/drivers/hwmon/Kconfig
> +++ b/drivers/hwmon/Kconfig
> @@ -554,6 +554,17 @@ config SENSORS_IBMPEX
>   	  This driver can also be built as a module.  If so, the module
>   	  will be called ibmpex.
>
> +config SENSORS_IBMPOWERNV
> +	tristate "IBM POWERNV platform sensors"
> +	depends on PPC_POWERNV
> +	default y
> +	help
> +	  If you say yes here you get support for the temperature/fan/power
> +	  sensors on your platform.

on your PowerNV platform

> +
> +	  This driver can also be built as a module. If so, the module
> +	  will be called ibmpowernv.
> +
>   config SENSORS_IIO_HWMON
>   	tristate "Hwmon driver that uses channels specified via iio maps"
>   	depends on IIO
> diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
> index c48f987..199c401 100644
> --- a/drivers/hwmon/Makefile
> +++ b/drivers/hwmon/Makefile
> @@ -71,6 +71,7 @@ obj-$(CONFIG_SENSORS_ULTRA45)	+= ultra45_env.o
>   obj-$(CONFIG_SENSORS_I5K_AMB)	+= i5k_amb.o
>   obj-$(CONFIG_SENSORS_IBMAEM)	+= ibmaem.o
>   obj-$(CONFIG_SENSORS_IBMPEX)	+= ibmpex.o
> +obj-$(CONFIG_SENSORS_IBMPOWERNV)+= ibmpowernv.o
>   obj-$(CONFIG_SENSORS_IIO_HWMON) += iio_hwmon.o
>   obj-$(CONFIG_SENSORS_INA209)	+= ina209.o
>   obj-$(CONFIG_SENSORS_INA2XX)	+= ina2xx.o
> diff --git a/drivers/hwmon/ibmpowernv.c b/drivers/hwmon/ibmpowernv.c
> new file mode 100644
> index 0000000..45c7f4b
> --- /dev/null
> +++ b/drivers/hwmon/ibmpowernv.c
> @@ -0,0 +1,366 @@
> +/*
> + * IBM PowerNV platform sensors for temperature/fan/voltage/power
> + * Copyright (C) 2014 IBM
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.
> + */
> +
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/hwmon.h>
> +#include <linux/hwmon-sysfs.h>
> +#include <linux/of.h>
> +#include <linux/slab.h>
> +
> +#include <linux/platform_device.h>
> +#include <asm/opal.h>
> +#include <linux/err.h>
> +
> +#define DRVNAME		"ibmpowernv"
> +#define MAX_ATTR_LEN	32
> +
> +/* Sensor suffix name from DT */
> +#define DT_FAULT_ATTR_SUFFIX		"faulted"
> +#define DT_DATA_ATTR_SUFFIX		"data"
> +#define DT_THRESHOLD_ATTR_SUFFIX	"thrs"
> +
> +/*
> + * Enumerates all the types of sensors in the POWERNV platform and does index
> + * into 'struct sensor_group'
> + */
> +enum sensors {
> +	FAN,
> +	AMBIENT_TEMP,
> +	POWER_SUPPLY,
> +	POWER_INPUT,
> +	MAX_SENSOR_TYPE,
> +};
> +
> +static struct sensor_group {
> +	const char *name;
> +	const char *compatible;
> +	struct attribute_group group;
> +	u32 attr_count;
> +} sensor_groups[] = {
> +	{"fan", "ibm,opal-sensor-cooling-fan"},
> +	{"temp", "ibm,opal-sensor-amb-temp"},
> +	{"in", "ibm,opal-sensor-power-supply"},
> +	{"power", "ibm,opal-sensor-power"}
> +};
> +
> +struct sensor_data {
> +	u32 id; /* An opaque id of the firmware for each sensor */
> +	enum sensors type;
> +	char name[MAX_ATTR_LEN];
> +	struct device_attribute dev_attr;
> +};
> +
> +struct platform_data {
> +	const struct attribute_group *attr_groups[MAX_SENSOR_TYPE + 1];
> +	u32 sensors_count; /* Total count of sensors from each group */
> +};
> +
> +/* Platform device representing all the ibmpowernv sensors */
> +static struct platform_device *pdevice;
> +
> +static ssize_t show_sensor(struct device *dev, struct device_attribute *devattr,
> +			   char *buf)
> +{
> +	struct sensor_data *sdata = container_of(devattr, struct sensor_data,
> +						 dev_attr);
> +	ssize_t ret;
> +	u32 x;
> +
> +	ret = opal_get_sensor_data(sdata->id, &x);
> +	if (ret) {
> +		pr_err("%s: Failed to get opal sensor data\n", __func__);

Please use dev_err, and drop __func__. Also, do really need that error message ?
The caller already gets notified, so polluting the log with it isn't really
that helpful (if every driver in the kernel would do that, the log would be all
but useless).

> +		return ret;
> +	}
> +
> +	/* Convert temperature to milli-degrees */
> +	if (sdata->type == AMBIENT_TEMP)
> +		x *= 1000;
> +	/* Convert power to micro-watts */
> +	else if (sdata->type == POWER_INPUT)
> +		x *= 1000000;
> +
> +	return sprintf(buf, "%u\n", x);
> +}
> +
> +static int __init get_sensor_index_attr(const char *name, u32 *index,
> +					char *attr)
> +{
> +	char *hash_pos = strchr(name, '#');
> +	char *dash_pos;
> +	u32 copy_len;
> +	char buf[8];
> +
> +	memset(buf, 0, sizeof(buf));
> +
Consider using
	char buf[8] = { 0 };
to leave it up to the compiler how to initialize the field.

> +	if (!hash_pos)
> +		return -EINVAL;
> +
> +	dash_pos = strchr(hash_pos, '-');
> +	if (!dash_pos)
> +		return -EINVAL;
> +
> +	copy_len = dash_pos - hash_pos - 1;
> +	if (copy_len >= sizeof(buf))
> +		return -EINVAL;
> +
> +	strncpy(buf, hash_pos + 1, copy_len);
> +	if (sscanf(buf, "%d", index) != 1)
> +		return -EINVAL;
> +
checkpatch says:

WARNING: Prefer kstrto<type> to single variable sscanf
#347: FILE: drivers/hwmon/ibmpowernv.c:124:
+	if (sscanf(buf, "%d", index) != 1)
+		return -EINVAL;

> +	strncpy(attr, dash_pos + 1, MAX_ATTR_LEN);
> +
> +	return 0;
> +}
> +
> +/*
> + * This function translates the DT node name into the 'hwmon' attribute name.
> + * IBMPOWERNV device node appear like cooling-fan#2-data, amb-temp#1-thrs etc.
> + * which need to be mapped as fan2_input, temp1_max respectively before
> + * populating them inside hwmon device class..
> + */
> +static int __init create_hwmon_attr_name(enum sensors type,
> +					 const char *node_name,
> +					 char *hwmon_attr_name)
> +{
> +	char attr_suffix[MAX_ATTR_LEN];
> +	char *attr_name;
> +	u32 index;
> +	int err;
> +
> +	err = get_sensor_index_attr(node_name, &index, attr_suffix);
> +	if (err) {
> +		pr_info("%s: Sensor device node name is invalid, name: %s\n",
> +			__func__, node_name);

dev_info please, and drop __func__. Pass dev as parameter to the function.
Why _info anyway ? Isn't this an error ?

> +		return err;
> +	}
> +
> +	if (!strcmp(attr_suffix, DT_FAULT_ATTR_SUFFIX)) {
> +		attr_name = "fault";
> +	} else if (!strcmp(attr_suffix, DT_DATA_ATTR_SUFFIX)) {
> +		attr_name = "input";
> +	} else if (!strcmp(attr_suffix, DT_THRESHOLD_ATTR_SUFFIX)) {
> +		if (type == AMBIENT_TEMP)
> +			attr_name = "max";
> +		else if (type == FAN)
> +			attr_name = "min";
> +		else
> +			return -ENOENT;
> +	} else {
> +		return -ENOENT;
> +	}
> +
> +	snprintf(hwmon_attr_name, MAX_ATTR_LEN, "%s%d_%s",
> +		 sensor_groups[type].name, index, attr_name);
> +	return 0;
> +}
> +
> +static int __init populate_attr_groups(struct platform_device *pdev)
> +{
> +	struct platform_data *pdata = platform_get_drvdata(pdev);
> +	const struct attribute_group **pgroups = pdata->attr_groups;
> +	struct device_node *opal, *np;
> +	enum sensors type;
> +
> +	opal = of_find_node_by_path("/ibm,opal/sensors");
> +	if (!opal) {
> +		pr_err("%s: Opal 'sensors' node not found\n", __func__);

dev_err please, and drop __func__.

> +		return -ENODEV;
> +	}
> +
> +	for_each_child_of_node(opal, np) {
> +		if (np->name == NULL)
> +			continue;
> +
> +		for (type = 0; type < MAX_SENSOR_TYPE; type++)
> +			if (of_device_is_compatible(np,
> +					sensor_groups[type].compatible)) {
> +				sensor_groups[type].attr_count++;
> +				break;
> +			}
> +	}
> +
> +	of_node_put(opal);
> +
> +	for (type = 0; type < MAX_SENSOR_TYPE; type++) {
> +		sensor_groups[type].group.attrs = devm_kzalloc(&pdev->dev,
> +					sizeof(struct attribute *) *
> +					(sensor_groups[type].attr_count + 1),
> +					GFP_KERNEL);
> +		if (!sensor_groups[type].group.attrs)
> +			return -ENOMEM;
> +
> +		pgroups[type] = &sensor_groups[type].group;
> +		pdata->sensors_count += sensor_groups[type].attr_count;
> +		sensor_groups[type].attr_count = 0;
> +	}
> +
> +	return 0;
> +}
> +
> +/*
> + * Iterate through the device tree for each child of 'sensors' node, create
> + * a sysfs attribute file, the file is named by translating the DT node name
> + * to the name required by the higher 'hwmon' driver like fan1_input, temp1_max
> + * etc..
> + */
> +static int __init create_device_attrs(struct platform_device *pdev)
> +{
> +	struct platform_data *pdata = platform_get_drvdata(pdev);
> +	const struct attribute_group **pgroups = pdata->attr_groups;
> +	struct device_node *opal, *np;
> +	struct sensor_data *sdata;
> +	const __be32 *sensor_id;
> +	enum sensors type;
> +	u32 count = 0;
> +	int err = 0;
> +
> +	opal = of_find_node_by_path("/ibm,opal/sensors");
> +	if (!opal) {
> +		pr_err("%s: Opal 'sensors' node not found\n", __func__);

dev_err. Why are you checking this twice, anyway ?

> +		return -ENODEV;
> +	}
> +
> +	sdata = devm_kzalloc(&pdev->dev, (pdata->sensors_count) *
> +			     sizeof(*sdata), GFP_KERNEL);

( ) around pdata->sensors_count is unnecessary.

> +	if (!sdata) {
> +		err = -ENOMEM;
> +		goto exit_put_node;
> +	}
> +
> +	for_each_child_of_node(opal, np) {
> +		if (np->name == NULL)
> +			continue;
> +
> +		for (type = 0; type < MAX_SENSOR_TYPE; type++)
> +			if (of_device_is_compatible(np,
> +					sensor_groups[type].compatible))
> +				break;
> +
> +		if (type == MAX_SENSOR_TYPE)
> +			continue;
> +
> +		sensor_id = of_get_property(np, "sensor-id", NULL);
> +		if (!sensor_id) {
> +			pr_info("%s: 'sensor-id' property not present in %s\n",
> +				__func__, np->name);

dev_info

> +			continue;
> +		}
> +
> +		sdata[count].id = be32_to_cpup(sensor_id);
> +		sdata[count].type = type;
> +		err = create_hwmon_attr_name(type, np->name, sdata[count].name);
> +		if (err)
> +			goto exit_put_node;
> +
> +		sysfs_attr_init(&sdata[count].dev_attr.attr);
> +		sdata[count].dev_attr.attr.name = sdata[count].name;
> +		sdata[count].dev_attr.attr.mode = S_IRUGO;
> +		sdata[count].dev_attr.show = show_sensor;
> +
> +		pgroups[type]->attrs[sensor_groups[type].attr_count++] =
> +				&sdata[count++].dev_attr.attr;
> +	}
> +
> +exit_put_node:
> +	of_node_put(opal);
> +	return err;
> +}
> +
> +static int __init ibmpowernv_probe(struct platform_device *pdev)
> +{
> +	struct platform_data *pdata;
> +	struct device *hwmon_dev;
> +	int err;
> +
> +	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
> +	if (!pdata)
> +		return -ENOMEM;
> +
> +	platform_set_drvdata(pdev, pdata);
> +	pdata->sensors_count = 0;
> +	err = populate_attr_groups(pdev);
> +	if (err)
> +		return err;
> +
> +	/* Create sysfs attribute data for each sensor found in the DT */
> +	err = create_device_attrs(pdev);
> +	if (err)
> +		return err;
> +
> +	/* Finally, register with hwmon */
> +	hwmon_dev = devm_hwmon_device_register_with_groups(&pdev->dev, DRVNAME,
> +							   pdata,
> +							   pdata->attr_groups);
> +
> +	return PTR_ERR_OR_ZERO(hwmon_dev);
> +}
> +
> +static struct platform_driver ibmpowernv_driver = {
> +	.driver = {
> +		.owner = THIS_MODULE,
> +		.name = DRVNAME,
> +	},
> +};
> +
> +static int __init ibmpowernv_init(void)
> +{
> +	int err;
> +
> +	pdevice = platform_device_alloc(DRVNAME, 0);
> +	if (!pdevice) {
> +		pr_err("%s: Device allocation failed\n", __func__);

Please define something like

#define pr_fmt(fmt) DRVNAME ": " fmt

at the beginning of the driver (before the include files)
to get an automatic driver name prefix.
Then you can drop __func__ as it is redundant and doesn't provide
as much value as the name of the driver.

> +		err = -ENOMEM;
> +		goto exit;
> +	}
> +
> +	err = platform_device_add(pdevice);
> +	if (err) {
> +		pr_err("%s: Device addition failed (%d)\n", __func__, err);
> +		goto exit_device_put;
> +	}
> +
> +	err = platform_driver_probe(&ibmpowernv_driver, ibmpowernv_probe);
> +	if (err) {
> +		pr_err("%s: Platfrom driver probe failed\n", __func__);
> +		goto exit_device_del;
> +	}
> +
> +	return 0;
> +
> +exit_device_del:
> +	platform_device_del(pdevice);
> +exit_device_put:
> +	platform_device_put(pdevice);
> +exit:
> +	return err;
> +}
> +
> +static void __exit ibmpowernv_exit(void)
> +{
> +	platform_driver_unregister(&ibmpowernv_driver);
> +	platform_device_unregister(pdevice);
> +}
> +
> +MODULE_AUTHOR("Neelesh Gupta <neelegup@linux.vnet.ibm.com>");
> +MODULE_DESCRIPTION("IBM POWERNV platform sensors");
> +MODULE_LICENSE("GPL");
> +
> +module_init(ibmpowernv_init);
> +module_exit(ibmpowernv_exit);
>
>
>

^ permalink raw reply

* Re: [PATCH v2 1/2] flexcan: add err_irq handler for flexcan
From: Marc Kleine-Budde @ 2014-06-21 19:38 UTC (permalink / raw)
  To: Zhao Qiang, linuxppc-dev, linux-can, wg, B07421
In-Reply-To: <1403229664-33912-1-git-send-email-B45475@freescale.com>

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

On 06/20/2014 04:01 AM, Zhao Qiang wrote:
> when flexcan is not physically linked, command 'cantest' will
> trigger an err_irq, add err_irq handler for it.
> 
> Signed-off-by: Zhao Qiang <B45475@freescale.com>
> ---
> Changes for v2:
> 	- use a space instead of tab
> 	- use flexcan_poll_state instead of print
> 
>  drivers/net/can/flexcan.c | 31 ++++++++++++++++++++++++++++++-
>  1 file changed, 30 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c
> index f425ec2..7432ba4 100644
> --- a/drivers/net/can/flexcan.c
> +++ b/drivers/net/can/flexcan.c
> @@ -208,6 +208,7 @@ struct flexcan_priv {
>  	void __iomem *base;
>  	u32 reg_esr;
>  	u32 reg_ctrl_default;
> +	unsigned int err_irq;
>  
>  	struct clk *clk_ipg;
>  	struct clk *clk_per;
> @@ -744,6 +745,23 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
>  	return IRQ_HANDLED;
>  }
>  
> +static irqreturn_t flexcan_err_irq(int irq, void *dev_id)
> +{
> +	struct net_device *dev = dev_id;
> +	struct flexcan_priv *priv = netdev_priv(dev);
> +	struct flexcan_regs __iomem *regs = priv->base;
> +	u32 reg_ctrl, reg_esr;
> +
> +	reg_esr = flexcan_read(&regs->esr);
> +	reg_ctrl = flexcan_read(&regs->ctrl);
> +	if (reg_esr & FLEXCAN_ESR_TX_WRN) {

When is the err_irq triggered?

> +		flexcan_write(reg_esr & ~FLEXCAN_ESR_TX_WRN, &regs->esr);
> +		flexcan_write(reg_ctrl & ~FLEXCAN_CTRL_ERR_MSK, &regs->ctrl);
> +		flexcan_poll_state(dev, reg_esr);

poll_state() is does not work, if called from an IRQ
handler.....Depending when err_irq is triggered, is it worth to just
call the normal interrupt handler?

> +	}
> +	return IRQ_HANDLED;

Please return IRQ_HANDLED, only if there really was an interrupt.

> +}
> +
>  static void flexcan_set_bittiming(struct net_device *dev)
>  {
>  	const struct flexcan_priv *priv = netdev_priv(dev);
> @@ -944,6 +962,12 @@ static int flexcan_open(struct net_device *dev)
>  	if (err)
>  		goto out_close;
>  
> +	if (priv->err_irq)
> +		err = request_irq(priv->err_irq, flexcan_err_irq, IRQF_SHARED,
> +				  dev->name, dev);
> +	if (err)
> +		goto out_close;

In case of an error, you don't free() dev->irq.

> +
>  	/* start chip and queuing */
>  	err = flexcan_chip_start(dev);
>  	if (err)
> @@ -1099,7 +1123,7 @@ static int flexcan_probe(struct platform_device *pdev)
>  	struct resource *mem;
>  	struct clk *clk_ipg = NULL, *clk_per = NULL;
>  	void __iomem *base;
> -	int err, irq;
> +	int err, irq, err_irq;
>  	u32 clock_freq = 0;
>  
>  	if (pdev->dev.of_node)
> @@ -1126,6 +1150,10 @@ static int flexcan_probe(struct platform_device *pdev)
>  	if (irq <= 0)
>  		return -ENODEV;
>  
> +	err_irq = platform_get_irq(pdev, 1);
> +	if (err_irq <= 0)
> +		err_irq = 0;
> +
>  	base = devm_ioremap_resource(&pdev->dev, mem);
>  	if (IS_ERR(base))
>  		return PTR_ERR(base);
> @@ -1149,6 +1177,7 @@ static int flexcan_probe(struct platform_device *pdev)
>  	dev->flags |= IFF_ECHO;
>  
>  	priv = netdev_priv(dev);
> +	priv->err_irq = err_irq;
>  	priv->can.clock.freq = clock_freq;
>  	priv->can.bittiming_const = &flexcan_bittiming_const;
>  	priv->can.do_set_mode = flexcan_set_mode;
> 

Marc

-- 
Pengutronix e.K.                  | Marc Kleine-Budde           |
Industrial Linux Solutions        | Phone: +49-231-2826-924     |
Vertretung West/Dortmund          | Fax:   +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686  | http://www.pengutronix.de   |


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 242 bytes --]

^ permalink raw reply

* [PATCH] powerpc/kerenl: Enable EEH for IO accessors
From: Gavin Shan @ 2014-06-23  0:56 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Gavin Shan

In arch/powerpc/kernel/iomap.c, lots of IO reading accessors missed
to check EEH error as Ben pointed. The patch fixes it.

For the writing accessors, we change the called functions only for
making them look similar to the reading counterparts.

Suggested-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
 arch/powerpc/kernel/iomap.c | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/arch/powerpc/kernel/iomap.c b/arch/powerpc/kernel/iomap.c
index b82227e..12e48d5 100644
--- a/arch/powerpc/kernel/iomap.c
+++ b/arch/powerpc/kernel/iomap.c
@@ -23,7 +23,7 @@ unsigned int ioread16(void __iomem *addr)
 }
 unsigned int ioread16be(void __iomem *addr)
 {
-	return in_be16(addr);
+	return readw_be(addr);
 }
 unsigned int ioread32(void __iomem *addr)
 {
@@ -31,7 +31,7 @@ unsigned int ioread32(void __iomem *addr)
 }
 unsigned int ioread32be(void __iomem *addr)
 {
-	return in_be32(addr);
+	return readl_be(addr);
 }
 EXPORT_SYMBOL(ioread8);
 EXPORT_SYMBOL(ioread16);
@@ -49,7 +49,7 @@ void iowrite16(u16 val, void __iomem *addr)
 }
 void iowrite16be(u16 val, void __iomem *addr)
 {
-	out_be16(addr, val);
+	writew_be(val, addr);
 }
 void iowrite32(u32 val, void __iomem *addr)
 {
@@ -57,7 +57,7 @@ void iowrite32(u32 val, void __iomem *addr)
 }
 void iowrite32be(u32 val, void __iomem *addr)
 {
-	out_be32(addr, val);
+	writel_be(val, addr);
 }
 EXPORT_SYMBOL(iowrite8);
 EXPORT_SYMBOL(iowrite16);
@@ -75,15 +75,15 @@ EXPORT_SYMBOL(iowrite32be);
  */
 void ioread8_rep(void __iomem *addr, void *dst, unsigned long count)
 {
-	_insb((u8 __iomem *) addr, dst, count);
+	readsb(addr, dst, count);
 }
 void ioread16_rep(void __iomem *addr, void *dst, unsigned long count)
 {
-	_insw_ns((u16 __iomem *) addr, dst, count);
+	readsw(addr, dst, count);
 }
 void ioread32_rep(void __iomem *addr, void *dst, unsigned long count)
 {
-	_insl_ns((u32 __iomem *) addr, dst, count);
+	readsl(addr, dst, count);
 }
 EXPORT_SYMBOL(ioread8_rep);
 EXPORT_SYMBOL(ioread16_rep);
@@ -91,15 +91,15 @@ EXPORT_SYMBOL(ioread32_rep);
 
 void iowrite8_rep(void __iomem *addr, const void *src, unsigned long count)
 {
-	_outsb((u8 __iomem *) addr, src, count);
+	writesb(addr, src, count);
 }
 void iowrite16_rep(void __iomem *addr, const void *src, unsigned long count)
 {
-	_outsw_ns((u16 __iomem *) addr, src, count);
+	writesw(addr, src, count);
 }
 void iowrite32_rep(void __iomem *addr, const void *src, unsigned long count)
 {
-	_outsl_ns((u32 __iomem *) addr, src, count);
+	writesl(addr, src, count);
 }
 EXPORT_SYMBOL(iowrite8_rep);
 EXPORT_SYMBOL(iowrite16_rep);
-- 
1.8.3.2

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox