LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 4/7] sdhci: rename sdhci-esdhc-imx.c to sdhci-esdhc.c
From: Shawn Guo @ 2011-05-05 13:22 UTC (permalink / raw)
  To: linux-mmc
  Cc: Chris Ball, sameo, Arnd Bergmann, patches, Shawn Guo,
	devicetree-discuss, Saeed Bishara, Xiaobo Xie, kernel,
	Mike Rapoport, Olof Johansson, Anton Vorontsov, linuxppc-dev,
	Albert Herranz, linux-arm-kernel
In-Reply-To: <1304601778-13837-1-git-send-email-shawn.guo@linaro.org>

The patch renames the file to prepare for the consolidation
sdhci-of-esdhc and sdhci-esdhc-imx.

Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
 drivers/mmc/host/Makefile          |    2 +-
 drivers/mmc/host/sdhci-esdhc-imx.c |  381 ------------------------------------
 drivers/mmc/host/sdhci-esdhc.c     |  381 ++++++++++++++++++++++++++++++++++++
 3 files changed, 382 insertions(+), 382 deletions(-)
 delete mode 100644 drivers/mmc/host/sdhci-esdhc-imx.c
 create mode 100644 drivers/mmc/host/sdhci-esdhc.c

diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 01d38a1..186f0ed 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -45,7 +45,7 @@ obj-$(CONFIG_MMC_USHC)		+= ushc.o
 
 obj-$(CONFIG_MMC_SDHCI_PLTFM)		+= sdhci-pltfm.o
 obj-$(CONFIG_MMC_SDHCI_CNS3XXX)		+= sdhci-cns3xxx.o
-obj-$(CONFIG_MMC_SDHCI_ESDHC_IMX)	+= sdhci-esdhc-imx.o
+obj-$(CONFIG_MMC_SDHCI_ESDHC_IMX)	+= sdhci-esdhc.o
 obj-$(CONFIG_MMC_SDHCI_DOVE)		+= sdhci-dove.o
 obj-$(CONFIG_MMC_SDHCI_TEGRA)		+= sdhci-tegra.o
 obj-$(CONFIG_MMC_SDHCI_OF_ESDHC)	+= sdhci-of-esdhc.o
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
deleted file mode 100644
index 8da57d4..0000000
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ /dev/null
@@ -1,381 +0,0 @@
-/*
- * Freescale eSDHC i.MX controller driver for the platform bus.
- *
- * derived from the OF-version.
- *
- * Copyright (c) 2010 Pengutronix e.K.
- *   Author: Wolfram Sang <w.sang@pengutronix.de>
- *
- * 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.
- */
-
-#include <linux/io.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/gpio.h>
-#include <linux/slab.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/sdhci-pltfm.h>
-#include <linux/mmc/mmc.h>
-#include <linux/mmc/sdio.h>
-#include <mach/hardware.h>
-#include <mach/esdhc.h>
-#include "sdhci.h"
-#include "sdhci-pltfm.h"
-#include "sdhci-esdhc.h"
-
-/* VENDOR SPEC register */
-#define SDHCI_VENDOR_SPEC		0xC0
-#define  SDHCI_VENDOR_SPEC_SDIO_QUIRK	0x00000002
-
-#define ESDHC_FLAG_GPIO_FOR_CD_WP	(1 << 0)
-/*
- * The CMDTYPE of the CMD register (offset 0xE) should be set to
- * "11" when the STOP CMD12 is issued on imx53 to abort one
- * open ended multi-blk IO. Otherwise the TC INT wouldn't
- * be generated.
- * In exact block transfer, the controller doesn't complete the
- * operations automatically as required at the end of the
- * transfer and remains on hold if the abort command is not sent.
- * As a result, the TC flag is not asserted and SW  received timeout
- * exeception. Bit1 of Vendor Spec registor is used to fix it.
- */
-#define ESDHC_FLAG_MULTIBLK_NO_INT	(1 << 1)
-
-struct pltfm_imx_data {
-	int flags;
-	u32 scratchpad;
-};
-
-static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, int reg)
-{
-	void __iomem *base = host->ioaddr + (reg & ~0x3);
-	u32 shift = (reg & 0x3) * 8;
-
-	writel(((readl(base) & ~(mask << shift)) | (val << shift)), base);
-}
-
-static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
-{
-	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
-	struct pltfm_imx_data *imx_data = pltfm_host->priv;
-
-	/* fake CARD_PRESENT flag on mx25/35 */
-	u32 val = readl(host->ioaddr + reg);
-
-	if (unlikely((reg == SDHCI_PRESENT_STATE)
-			&& (imx_data->flags & ESDHC_FLAG_GPIO_FOR_CD_WP))) {
-		struct esdhc_platform_data *boarddata =
-				host->mmc->parent->platform_data;
-
-		if (boarddata && gpio_is_valid(boarddata->cd_gpio)
-				&& gpio_get_value(boarddata->cd_gpio))
-			/* no card, if a valid gpio says so... */
-			val &= SDHCI_CARD_PRESENT;
-		else
-			/* ... in all other cases assume card is present */
-			val |= SDHCI_CARD_PRESENT;
-	}
-
-	return val;
-}
-
-static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg)
-{
-	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
-	struct pltfm_imx_data *imx_data = pltfm_host->priv;
-
-	if (unlikely((reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE)
-			&& (imx_data->flags & ESDHC_FLAG_GPIO_FOR_CD_WP)))
-		/*
-		 * these interrupts won't work with a custom card_detect gpio
-		 * (only applied to mx25/35)
-		 */
-		val &= ~(SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT);
-
-	if (unlikely((imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT)
-				&& (reg == SDHCI_INT_STATUS)
-				&& (val & SDHCI_INT_DATA_END))) {
-			u32 v;
-			v = readl(host->ioaddr + SDHCI_VENDOR_SPEC);
-			v &= ~SDHCI_VENDOR_SPEC_SDIO_QUIRK;
-			writel(v, host->ioaddr + SDHCI_VENDOR_SPEC);
-	}
-
-	writel(val, host->ioaddr + reg);
-}
-
-static u16 esdhc_readw_le(struct sdhci_host *host, int reg)
-{
-	if (unlikely(reg == SDHCI_HOST_VERSION))
-		reg ^= 2;
-
-	return readw(host->ioaddr + reg);
-}
-
-static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
-{
-	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
-	struct pltfm_imx_data *imx_data = pltfm_host->priv;
-
-	switch (reg) {
-	case SDHCI_TRANSFER_MODE:
-		/*
-		 * Postpone this write, we must do it together with a
-		 * command write that is down below.
-		 */
-		if ((imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT)
-				&& (host->cmd->opcode == SD_IO_RW_EXTENDED)
-				&& (host->cmd->data->blocks > 1)
-				&& (host->cmd->data->flags & MMC_DATA_READ)) {
-			u32 v;
-			v = readl(host->ioaddr + SDHCI_VENDOR_SPEC);
-			v |= SDHCI_VENDOR_SPEC_SDIO_QUIRK;
-			writel(v, host->ioaddr + SDHCI_VENDOR_SPEC);
-		}
-		imx_data->scratchpad = val;
-		return;
-	case SDHCI_COMMAND:
-		if ((host->cmd->opcode == MMC_STOP_TRANSMISSION)
-			&& (imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT))
-			val |= SDHCI_CMD_ABORTCMD;
-		writel(val << 16 | imx_data->scratchpad,
-			host->ioaddr + SDHCI_TRANSFER_MODE);
-		return;
-	case SDHCI_BLOCK_SIZE:
-		val &= ~SDHCI_MAKE_BLKSZ(0x7, 0);
-		break;
-	}
-	esdhc_clrset_le(host, 0xffff, val, reg);
-}
-
-static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg)
-{
-	u32 new_val;
-
-	switch (reg) {
-	case SDHCI_POWER_CONTROL:
-		/*
-		 * FSL put some DMA bits here
-		 * If your board has a regulator, code should be here
-		 */
-		return;
-	case SDHCI_HOST_CONTROL:
-		/* FSL messed up here, so we can just keep those two */
-		new_val = val & (SDHCI_CTRL_LED | SDHCI_CTRL_4BITBUS);
-		/* ensure the endianess */
-		new_val |= ESDHC_HOST_CONTROL_LE;
-		/* DMA mode bits are shifted */
-		new_val |= (val & SDHCI_CTRL_DMA_MASK) << 5;
-
-		esdhc_clrset_le(host, 0xffff, new_val, reg);
-		return;
-	}
-	esdhc_clrset_le(host, 0xff, val, reg);
-}
-
-static unsigned int esdhc_pltfm_get_max_clock(struct sdhci_host *host)
-{
-	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
-
-	return clk_get_rate(pltfm_host->clk);
-}
-
-static unsigned int esdhc_pltfm_get_min_clock(struct sdhci_host *host)
-{
-	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
-
-	return clk_get_rate(pltfm_host->clk) / 256 / 16;
-}
-
-static struct sdhci_ops sdhci_esdhc_ops = {
-	.read_l = esdhc_readl_le,
-	.read_w = esdhc_readw_le,
-	.write_l = esdhc_writel_le,
-	.write_w = esdhc_writew_le,
-	.write_b = esdhc_writeb_le,
-	.set_clock = esdhc_set_clock,
-	.get_max_clock = esdhc_pltfm_get_max_clock,
-	.get_min_clock = esdhc_pltfm_get_min_clock,
-};
-
-static struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
-	.quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_ADMA
-			| SDHCI_QUIRK_BROKEN_CARD_DETECTION,
-	/* ADMA has issues. Might be fixable */
-	.ops = &sdhci_esdhc_ops,
-};
-
-static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host)
-{
-	struct esdhc_platform_data *boarddata = host->mmc->parent->platform_data;
-
-	if (boarddata && gpio_is_valid(boarddata->wp_gpio))
-		return gpio_get_value(boarddata->wp_gpio);
-	else
-		return -ENOSYS;
-}
-
-static irqreturn_t cd_irq(int irq, void *data)
-{
-	struct sdhci_host *sdhost = (struct sdhci_host *)data;
-
-	tasklet_schedule(&sdhost->card_tasklet);
-	return IRQ_HANDLED;
-};
-
-static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
-{
-	struct sdhci_pltfm_host *pltfm_host;
-	struct sdhci_host *host;
-	struct esdhc_platform_data *boarddata;
-	struct clk *clk;
-	int err;
-	struct pltfm_imx_data *imx_data;
-
-	host = sdhci_pltfm_init(pdev, &sdhci_esdhc_imx_pdata);
-	if (IS_ERR(host))
-		return PTR_ERR(host);
-
-	pltfm_host = sdhci_priv(host);
-
-	imx_data = kzalloc(sizeof(struct pltfm_imx_data), GFP_KERNEL);
-	if (!imx_data)
-		return -ENOMEM;
-	pltfm_host->priv = imx_data;
-
-	clk = clk_get(mmc_dev(host->mmc), NULL);
-	if (IS_ERR(clk)) {
-		dev_err(mmc_dev(host->mmc), "clk err\n");
-		err = PTR_ERR(clk);
-		goto err_clk_get;
-	}
-	clk_enable(clk);
-	pltfm_host->clk = clk;
-
-	if (!cpu_is_mx25())
-		host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
-
-	if (cpu_is_mx25() || cpu_is_mx35()) {
-		/* Fix errata ENGcm07207 present on i.MX25 and i.MX35 */
-		host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK;
-		/* write_protect can't be routed to controller, use gpio */
-		sdhci_esdhc_ops.get_ro = esdhc_pltfm_get_ro;
-	}
-
-	if (!(cpu_is_mx25() || cpu_is_mx35() || cpu_is_mx51()))
-		imx_data->flags |= ESDHC_FLAG_MULTIBLK_NO_INT;
-
-	boarddata = host->mmc->parent->platform_data;
-	if (boarddata) {
-		err = gpio_request_one(boarddata->wp_gpio, GPIOF_IN, "ESDHC_WP");
-		if (err) {
-			dev_warn(mmc_dev(host->mmc),
-				"no write-protect pin available!\n");
-			boarddata->wp_gpio = err;
-		}
-
-		err = gpio_request_one(boarddata->cd_gpio, GPIOF_IN, "ESDHC_CD");
-		if (err) {
-			dev_warn(mmc_dev(host->mmc),
-				"no card-detect pin available!\n");
-			goto no_card_detect_pin;
-		}
-
-		/* i.MX5x has issues to be researched */
-		if (!cpu_is_mx25() && !cpu_is_mx35())
-			goto not_supported;
-
-		err = request_irq(gpio_to_irq(boarddata->cd_gpio), cd_irq,
-				 IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
-				 mmc_hostname(host->mmc), host);
-		if (err) {
-			dev_warn(mmc_dev(host->mmc), "request irq error\n");
-			goto no_card_detect_irq;
-		}
-
-		imx_data->flags |= ESDHC_FLAG_GPIO_FOR_CD_WP;
-		/* Now we have a working card_detect again */
-		host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION;
-	}
-
-	err = sdhci_add_host(host);
-	if (err)
-		goto err_add_host;
-
-	return 0;
-
- no_card_detect_irq:
-	gpio_free(boarddata->cd_gpio);
- no_card_detect_pin:
-	boarddata->cd_gpio = err;
- not_supported:
-	kfree(imx_data);
- err_add_host:
-	clk_disable(pltfm_host->clk);
-	clk_put(pltfm_host->clk);
- err_clk_get:
-	sdhci_pltfm_free(pdev);
-	return err;
-}
-
-static int __devexit sdhci_esdhc_imx_remove(struct platform_device *pdev)
-{
-	struct sdhci_host *host = platform_get_drvdata(pdev);
-	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
-	struct esdhc_platform_data *boarddata = host->mmc->parent->platform_data;
-	struct pltfm_imx_data *imx_data = pltfm_host->priv;
-	int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
-
-	sdhci_remove_host(host, dead);
-
-	if (boarddata && gpio_is_valid(boarddata->wp_gpio))
-		gpio_free(boarddata->wp_gpio);
-
-	if (boarddata && gpio_is_valid(boarddata->cd_gpio)) {
-		gpio_free(boarddata->cd_gpio);
-
-		if (!(host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION))
-			free_irq(gpio_to_irq(boarddata->cd_gpio), host);
-	}
-
-	clk_disable(pltfm_host->clk);
-	clk_put(pltfm_host->clk);
-	kfree(imx_data);
-
-	sdhci_pltfm_free(pdev);
-
-	return 0;
-}
-
-static struct platform_driver sdhci_esdhc_imx_driver = {
-	.driver		= {
-		.name	= "sdhci-esdhc-imx",
-		.owner	= THIS_MODULE,
-	},
-	.probe		= sdhci_esdhc_imx_probe,
-	.remove		= __devexit_p(sdhci_esdhc_imx_remove),
-#ifdef CONFIG_PM
-	.suspend	= sdhci_pltfm_suspend,
-	.resume		= sdhci_pltfm_resume,
-#endif
-};
- 
-static int __init sdhci_esdhc_imx_init(void)
-{
-	return platform_driver_register(&sdhci_esdhc_imx_driver);
-}
-module_init(sdhci_esdhc_imx_init);
-
-static void __exit sdhci_esdhc_imx_exit(void)
-{
-	platform_driver_unregister(&sdhci_esdhc_imx_driver);
-}
-module_exit(sdhci_esdhc_imx_exit);
-
-MODULE_DESCRIPTION("SDHCI driver for Freescale i.MX eSDHC");
-MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/mmc/host/sdhci-esdhc.c b/drivers/mmc/host/sdhci-esdhc.c
new file mode 100644
index 0000000..8da57d4
--- /dev/null
+++ b/drivers/mmc/host/sdhci-esdhc.c
@@ -0,0 +1,381 @@
+/*
+ * Freescale eSDHC i.MX controller driver for the platform bus.
+ *
+ * derived from the OF-version.
+ *
+ * Copyright (c) 2010 Pengutronix e.K.
+ *   Author: Wolfram Sang <w.sang@pengutronix.de>
+ *
+ * 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.
+ */
+
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/sdhci-pltfm.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/sdio.h>
+#include <mach/hardware.h>
+#include <mach/esdhc.h>
+#include "sdhci.h"
+#include "sdhci-pltfm.h"
+#include "sdhci-esdhc.h"
+
+/* VENDOR SPEC register */
+#define SDHCI_VENDOR_SPEC		0xC0
+#define  SDHCI_VENDOR_SPEC_SDIO_QUIRK	0x00000002
+
+#define ESDHC_FLAG_GPIO_FOR_CD_WP	(1 << 0)
+/*
+ * The CMDTYPE of the CMD register (offset 0xE) should be set to
+ * "11" when the STOP CMD12 is issued on imx53 to abort one
+ * open ended multi-blk IO. Otherwise the TC INT wouldn't
+ * be generated.
+ * In exact block transfer, the controller doesn't complete the
+ * operations automatically as required at the end of the
+ * transfer and remains on hold if the abort command is not sent.
+ * As a result, the TC flag is not asserted and SW  received timeout
+ * exeception. Bit1 of Vendor Spec registor is used to fix it.
+ */
+#define ESDHC_FLAG_MULTIBLK_NO_INT	(1 << 1)
+
+struct pltfm_imx_data {
+	int flags;
+	u32 scratchpad;
+};
+
+static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, int reg)
+{
+	void __iomem *base = host->ioaddr + (reg & ~0x3);
+	u32 shift = (reg & 0x3) * 8;
+
+	writel(((readl(base) & ~(mask << shift)) | (val << shift)), base);
+}
+
+static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
+{
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct pltfm_imx_data *imx_data = pltfm_host->priv;
+
+	/* fake CARD_PRESENT flag on mx25/35 */
+	u32 val = readl(host->ioaddr + reg);
+
+	if (unlikely((reg == SDHCI_PRESENT_STATE)
+			&& (imx_data->flags & ESDHC_FLAG_GPIO_FOR_CD_WP))) {
+		struct esdhc_platform_data *boarddata =
+				host->mmc->parent->platform_data;
+
+		if (boarddata && gpio_is_valid(boarddata->cd_gpio)
+				&& gpio_get_value(boarddata->cd_gpio))
+			/* no card, if a valid gpio says so... */
+			val &= SDHCI_CARD_PRESENT;
+		else
+			/* ... in all other cases assume card is present */
+			val |= SDHCI_CARD_PRESENT;
+	}
+
+	return val;
+}
+
+static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg)
+{
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct pltfm_imx_data *imx_data = pltfm_host->priv;
+
+	if (unlikely((reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE)
+			&& (imx_data->flags & ESDHC_FLAG_GPIO_FOR_CD_WP)))
+		/*
+		 * these interrupts won't work with a custom card_detect gpio
+		 * (only applied to mx25/35)
+		 */
+		val &= ~(SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT);
+
+	if (unlikely((imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT)
+				&& (reg == SDHCI_INT_STATUS)
+				&& (val & SDHCI_INT_DATA_END))) {
+			u32 v;
+			v = readl(host->ioaddr + SDHCI_VENDOR_SPEC);
+			v &= ~SDHCI_VENDOR_SPEC_SDIO_QUIRK;
+			writel(v, host->ioaddr + SDHCI_VENDOR_SPEC);
+	}
+
+	writel(val, host->ioaddr + reg);
+}
+
+static u16 esdhc_readw_le(struct sdhci_host *host, int reg)
+{
+	if (unlikely(reg == SDHCI_HOST_VERSION))
+		reg ^= 2;
+
+	return readw(host->ioaddr + reg);
+}
+
+static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
+{
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct pltfm_imx_data *imx_data = pltfm_host->priv;
+
+	switch (reg) {
+	case SDHCI_TRANSFER_MODE:
+		/*
+		 * Postpone this write, we must do it together with a
+		 * command write that is down below.
+		 */
+		if ((imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT)
+				&& (host->cmd->opcode == SD_IO_RW_EXTENDED)
+				&& (host->cmd->data->blocks > 1)
+				&& (host->cmd->data->flags & MMC_DATA_READ)) {
+			u32 v;
+			v = readl(host->ioaddr + SDHCI_VENDOR_SPEC);
+			v |= SDHCI_VENDOR_SPEC_SDIO_QUIRK;
+			writel(v, host->ioaddr + SDHCI_VENDOR_SPEC);
+		}
+		imx_data->scratchpad = val;
+		return;
+	case SDHCI_COMMAND:
+		if ((host->cmd->opcode == MMC_STOP_TRANSMISSION)
+			&& (imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT))
+			val |= SDHCI_CMD_ABORTCMD;
+		writel(val << 16 | imx_data->scratchpad,
+			host->ioaddr + SDHCI_TRANSFER_MODE);
+		return;
+	case SDHCI_BLOCK_SIZE:
+		val &= ~SDHCI_MAKE_BLKSZ(0x7, 0);
+		break;
+	}
+	esdhc_clrset_le(host, 0xffff, val, reg);
+}
+
+static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg)
+{
+	u32 new_val;
+
+	switch (reg) {
+	case SDHCI_POWER_CONTROL:
+		/*
+		 * FSL put some DMA bits here
+		 * If your board has a regulator, code should be here
+		 */
+		return;
+	case SDHCI_HOST_CONTROL:
+		/* FSL messed up here, so we can just keep those two */
+		new_val = val & (SDHCI_CTRL_LED | SDHCI_CTRL_4BITBUS);
+		/* ensure the endianess */
+		new_val |= ESDHC_HOST_CONTROL_LE;
+		/* DMA mode bits are shifted */
+		new_val |= (val & SDHCI_CTRL_DMA_MASK) << 5;
+
+		esdhc_clrset_le(host, 0xffff, new_val, reg);
+		return;
+	}
+	esdhc_clrset_le(host, 0xff, val, reg);
+}
+
+static unsigned int esdhc_pltfm_get_max_clock(struct sdhci_host *host)
+{
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+
+	return clk_get_rate(pltfm_host->clk);
+}
+
+static unsigned int esdhc_pltfm_get_min_clock(struct sdhci_host *host)
+{
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+
+	return clk_get_rate(pltfm_host->clk) / 256 / 16;
+}
+
+static struct sdhci_ops sdhci_esdhc_ops = {
+	.read_l = esdhc_readl_le,
+	.read_w = esdhc_readw_le,
+	.write_l = esdhc_writel_le,
+	.write_w = esdhc_writew_le,
+	.write_b = esdhc_writeb_le,
+	.set_clock = esdhc_set_clock,
+	.get_max_clock = esdhc_pltfm_get_max_clock,
+	.get_min_clock = esdhc_pltfm_get_min_clock,
+};
+
+static struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
+	.quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_ADMA
+			| SDHCI_QUIRK_BROKEN_CARD_DETECTION,
+	/* ADMA has issues. Might be fixable */
+	.ops = &sdhci_esdhc_ops,
+};
+
+static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host)
+{
+	struct esdhc_platform_data *boarddata = host->mmc->parent->platform_data;
+
+	if (boarddata && gpio_is_valid(boarddata->wp_gpio))
+		return gpio_get_value(boarddata->wp_gpio);
+	else
+		return -ENOSYS;
+}
+
+static irqreturn_t cd_irq(int irq, void *data)
+{
+	struct sdhci_host *sdhost = (struct sdhci_host *)data;
+
+	tasklet_schedule(&sdhost->card_tasklet);
+	return IRQ_HANDLED;
+};
+
+static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
+{
+	struct sdhci_pltfm_host *pltfm_host;
+	struct sdhci_host *host;
+	struct esdhc_platform_data *boarddata;
+	struct clk *clk;
+	int err;
+	struct pltfm_imx_data *imx_data;
+
+	host = sdhci_pltfm_init(pdev, &sdhci_esdhc_imx_pdata);
+	if (IS_ERR(host))
+		return PTR_ERR(host);
+
+	pltfm_host = sdhci_priv(host);
+
+	imx_data = kzalloc(sizeof(struct pltfm_imx_data), GFP_KERNEL);
+	if (!imx_data)
+		return -ENOMEM;
+	pltfm_host->priv = imx_data;
+
+	clk = clk_get(mmc_dev(host->mmc), NULL);
+	if (IS_ERR(clk)) {
+		dev_err(mmc_dev(host->mmc), "clk err\n");
+		err = PTR_ERR(clk);
+		goto err_clk_get;
+	}
+	clk_enable(clk);
+	pltfm_host->clk = clk;
+
+	if (!cpu_is_mx25())
+		host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
+
+	if (cpu_is_mx25() || cpu_is_mx35()) {
+		/* Fix errata ENGcm07207 present on i.MX25 and i.MX35 */
+		host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK;
+		/* write_protect can't be routed to controller, use gpio */
+		sdhci_esdhc_ops.get_ro = esdhc_pltfm_get_ro;
+	}
+
+	if (!(cpu_is_mx25() || cpu_is_mx35() || cpu_is_mx51()))
+		imx_data->flags |= ESDHC_FLAG_MULTIBLK_NO_INT;
+
+	boarddata = host->mmc->parent->platform_data;
+	if (boarddata) {
+		err = gpio_request_one(boarddata->wp_gpio, GPIOF_IN, "ESDHC_WP");
+		if (err) {
+			dev_warn(mmc_dev(host->mmc),
+				"no write-protect pin available!\n");
+			boarddata->wp_gpio = err;
+		}
+
+		err = gpio_request_one(boarddata->cd_gpio, GPIOF_IN, "ESDHC_CD");
+		if (err) {
+			dev_warn(mmc_dev(host->mmc),
+				"no card-detect pin available!\n");
+			goto no_card_detect_pin;
+		}
+
+		/* i.MX5x has issues to be researched */
+		if (!cpu_is_mx25() && !cpu_is_mx35())
+			goto not_supported;
+
+		err = request_irq(gpio_to_irq(boarddata->cd_gpio), cd_irq,
+				 IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+				 mmc_hostname(host->mmc), host);
+		if (err) {
+			dev_warn(mmc_dev(host->mmc), "request irq error\n");
+			goto no_card_detect_irq;
+		}
+
+		imx_data->flags |= ESDHC_FLAG_GPIO_FOR_CD_WP;
+		/* Now we have a working card_detect again */
+		host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION;
+	}
+
+	err = sdhci_add_host(host);
+	if (err)
+		goto err_add_host;
+
+	return 0;
+
+ no_card_detect_irq:
+	gpio_free(boarddata->cd_gpio);
+ no_card_detect_pin:
+	boarddata->cd_gpio = err;
+ not_supported:
+	kfree(imx_data);
+ err_add_host:
+	clk_disable(pltfm_host->clk);
+	clk_put(pltfm_host->clk);
+ err_clk_get:
+	sdhci_pltfm_free(pdev);
+	return err;
+}
+
+static int __devexit sdhci_esdhc_imx_remove(struct platform_device *pdev)
+{
+	struct sdhci_host *host = platform_get_drvdata(pdev);
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct esdhc_platform_data *boarddata = host->mmc->parent->platform_data;
+	struct pltfm_imx_data *imx_data = pltfm_host->priv;
+	int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
+
+	sdhci_remove_host(host, dead);
+
+	if (boarddata && gpio_is_valid(boarddata->wp_gpio))
+		gpio_free(boarddata->wp_gpio);
+
+	if (boarddata && gpio_is_valid(boarddata->cd_gpio)) {
+		gpio_free(boarddata->cd_gpio);
+
+		if (!(host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION))
+			free_irq(gpio_to_irq(boarddata->cd_gpio), host);
+	}
+
+	clk_disable(pltfm_host->clk);
+	clk_put(pltfm_host->clk);
+	kfree(imx_data);
+
+	sdhci_pltfm_free(pdev);
+
+	return 0;
+}
+
+static struct platform_driver sdhci_esdhc_imx_driver = {
+	.driver		= {
+		.name	= "sdhci-esdhc-imx",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= sdhci_esdhc_imx_probe,
+	.remove		= __devexit_p(sdhci_esdhc_imx_remove),
+#ifdef CONFIG_PM
+	.suspend	= sdhci_pltfm_suspend,
+	.resume		= sdhci_pltfm_resume,
+#endif
+};
+ 
+static int __init sdhci_esdhc_imx_init(void)
+{
+	return platform_driver_register(&sdhci_esdhc_imx_driver);
+}
+module_init(sdhci_esdhc_imx_init);
+
+static void __exit sdhci_esdhc_imx_exit(void)
+{
+	platform_driver_unregister(&sdhci_esdhc_imx_driver);
+}
+module_exit(sdhci_esdhc_imx_exit);
+
+MODULE_DESCRIPTION("SDHCI driver for Freescale i.MX eSDHC");
+MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>");
+MODULE_LICENSE("GPL v2");
-- 
1.7.4.1

^ permalink raw reply related

* [PATCH v2 3/7] mmc: sdhci: make sdhci-of device drivers self registered
From: Shawn Guo @ 2011-05-05 13:22 UTC (permalink / raw)
  To: linux-mmc
  Cc: Chris Ball, sameo, Arnd Bergmann, patches, Shawn Guo,
	devicetree-discuss, Saeed Bishara, Xiaobo Xie, kernel,
	Mike Rapoport, Olof Johansson, Anton Vorontsov, linuxppc-dev,
	Albert Herranz, linux-arm-kernel
In-Reply-To: <1304601778-13837-1-git-send-email-shawn.guo@linaro.org>

The patch turns the sdhci-of-core common stuff into helper functions
added into sdhci-pltfm.c, and makes sdhci-of device drviers self
registered using the same pair of .probe and .remove used by
sdhci-pltfm device drivers.

As a result, sdhci-of-core.c and sdhci-of.h can be eliminated with
those common things merged into sdhci-pltfm.c and sdhci-pltfm.h
respectively.

Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
 drivers/mmc/host/Kconfig          |   15 +--
 drivers/mmc/host/Makefile         |    7 +-
 drivers/mmc/host/sdhci-of-core.c  |  250 -------------------------------------
 drivers/mmc/host/sdhci-of-esdhc.c |   53 ++++++++-
 drivers/mmc/host/sdhci-of-hlwd.c  |   50 +++++++-
 drivers/mmc/host/sdhci-of.h       |   33 -----
 drivers/mmc/host/sdhci-pltfm.c    |  104 +++++++++++++++-
 drivers/mmc/host/sdhci-pltfm.h    |   12 ++
 8 files changed, 220 insertions(+), 304 deletions(-)
 delete mode 100644 drivers/mmc/host/sdhci-of-core.c
 delete mode 100644 drivers/mmc/host/sdhci-of.h

diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 799e935..fdd20ad 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -81,19 +81,11 @@ config MMC_RICOH_MMC
 
 	  If unsure, say Y.
 
-config MMC_SDHCI_OF
-	tristate "SDHCI support on OpenFirmware platforms"
-	depends on MMC_SDHCI && OF
-	help
-	  This selects the OF support for Secure Digital Host Controller
-	  Interfaces.
-
-	  If unsure, say N.
-
 config MMC_SDHCI_OF_ESDHC
 	bool "SDHCI OF support for the Freescale eSDHC controller"
-	depends on MMC_SDHCI_OF
+	depends on MMC_SDHCI
 	depends on PPC_OF
+	select MMC_SDHCI_PLTFM
 	select MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
 	help
 	  This selects the Freescale eSDHC controller support.
@@ -102,8 +94,9 @@ config MMC_SDHCI_OF_ESDHC
 
 config MMC_SDHCI_OF_HLWD
 	bool "SDHCI OF support for the Nintendo Wii SDHCI controllers"
-	depends on MMC_SDHCI_OF
+	depends on MMC_SDHCI
 	depends on PPC_OF
+	select MMC_SDHCI_PLTFM
 	select MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
 	help
 	  This selects the Secure Digital Host Controller Interface (SDHCI)
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 95fddb8..01d38a1 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -48,11 +48,8 @@ obj-$(CONFIG_MMC_SDHCI_CNS3XXX)		+= sdhci-cns3xxx.o
 obj-$(CONFIG_MMC_SDHCI_ESDHC_IMX)	+= sdhci-esdhc-imx.o
 obj-$(CONFIG_MMC_SDHCI_DOVE)		+= sdhci-dove.o
 obj-$(CONFIG_MMC_SDHCI_TEGRA)		+= sdhci-tegra.o
-
-obj-$(CONFIG_MMC_SDHCI_OF)	+= sdhci-of.o
-sdhci-of-y				:= sdhci-of-core.o
-sdhci-of-$(CONFIG_MMC_SDHCI_OF_ESDHC)	+= sdhci-of-esdhc.o
-sdhci-of-$(CONFIG_MMC_SDHCI_OF_HLWD)	+= sdhci-of-hlwd.o
+obj-$(CONFIG_MMC_SDHCI_OF_ESDHC)	+= sdhci-of-esdhc.o
+obj-$(CONFIG_MMC_SDHCI_OF_HLWD)		+= sdhci-of-hlwd.o
 
 ifeq ($(CONFIG_CB710_DEBUG),y)
 	CFLAGS-cb710-mmc	+= -DDEBUG
diff --git a/drivers/mmc/host/sdhci-of-core.c b/drivers/mmc/host/sdhci-of-core.c
deleted file mode 100644
index 6b2de9e..0000000
--- a/drivers/mmc/host/sdhci-of-core.c
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * OpenFirmware bindings for Secure Digital Host Controller Interface.
- *
- * Copyright (c) 2007 Freescale Semiconductor, Inc.
- * Copyright (c) 2009 MontaVista Software, Inc.
- *
- * Authors: Xiaobo Xie <X.Xie@freescale.com>
- *	    Anton Vorontsov <avorontsov@ru.mvista.com>
- *
- * 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.
- */
-
-#include <linux/err.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/of.h>
-#include <linux/of_platform.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <linux/mmc/host.h>
-#ifdef CONFIG_PPC
-#include <asm/machdep.h>
-#endif
-#include "sdhci-of.h"
-#include "sdhci.h"
-
-#ifdef CONFIG_MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
-
-/*
- * These accessors are designed for big endian hosts doing I/O to
- * little endian controllers incorporating a 32-bit hardware byte swapper.
- */
-
-u32 sdhci_be32bs_readl(struct sdhci_host *host, int reg)
-{
-	return in_be32(host->ioaddr + reg);
-}
-
-u16 sdhci_be32bs_readw(struct sdhci_host *host, int reg)
-{
-	return in_be16(host->ioaddr + (reg ^ 0x2));
-}
-
-u8 sdhci_be32bs_readb(struct sdhci_host *host, int reg)
-{
-	return in_8(host->ioaddr + (reg ^ 0x3));
-}
-
-void sdhci_be32bs_writel(struct sdhci_host *host, u32 val, int reg)
-{
-	out_be32(host->ioaddr + reg, val);
-}
-
-void sdhci_be32bs_writew(struct sdhci_host *host, u16 val, int reg)
-{
-	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
-	int base = reg & ~0x3;
-	int shift = (reg & 0x2) * 8;
-
-	switch (reg) {
-	case SDHCI_TRANSFER_MODE:
-		/*
-		 * Postpone this write, we must do it together with a
-		 * command write that is down below.
-		 */
-		pltfm_host->xfer_mode_shadow = val;
-		return;
-	case SDHCI_COMMAND:
-		sdhci_be32bs_writel(host, val << 16 | pltfm_host->xfer_mode_shadow,
-				    SDHCI_TRANSFER_MODE);
-		return;
-	}
-	clrsetbits_be32(host->ioaddr + base, 0xffff << shift, val << shift);
-}
-
-void sdhci_be32bs_writeb(struct sdhci_host *host, u8 val, int reg)
-{
-	int base = reg & ~0x3;
-	int shift = (reg & 0x3) * 8;
-
-	clrsetbits_be32(host->ioaddr + base , 0xff << shift, val << shift);
-}
-#endif /* CONFIG_MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER */
-
-#ifdef CONFIG_PM
-
-static int sdhci_of_suspend(struct platform_device *ofdev, pm_message_t state)
-{
-	struct sdhci_host *host = dev_get_drvdata(&ofdev->dev);
-
-	return mmc_suspend_host(host->mmc);
-}
-
-static int sdhci_of_resume(struct platform_device *ofdev)
-{
-	struct sdhci_host *host = dev_get_drvdata(&ofdev->dev);
-
-	return mmc_resume_host(host->mmc);
-}
-
-#else
-
-#define sdhci_of_suspend NULL
-#define sdhci_of_resume NULL
-
-#endif
-
-static bool __devinit sdhci_of_wp_inverted(struct device_node *np)
-{
-	if (of_get_property(np, "sdhci,wp-inverted", NULL))
-		return true;
-
-	/* Old device trees don't have the wp-inverted property. */
-#ifdef CONFIG_PPC
-	return machine_is(mpc837x_rdb) || machine_is(mpc837x_mds);
-#else
-	return false;
-#endif
-}
-
-static int __devinit sdhci_of_probe(struct platform_device *ofdev)
-{
-	struct device_node *np = ofdev->dev.of_node;
-	struct sdhci_pltfm_data *pdata;
-	struct sdhci_host *host;
-	struct sdhci_of_host *of_host;
-	const __be32 *clk;
-	int size;
-	int ret;
-
-	if (!ofdev->dev.of_match)
-		return -EINVAL;
-	pdata = ofdev->dev.of_match->data;
-
-	if (!of_device_is_available(np))
-		return -ENODEV;
-
-	host = sdhci_alloc_host(&ofdev->dev, sizeof(*pltfm_host));
-	if (IS_ERR(host))
-		return -ENOMEM;
-
-	pltfm_host = sdhci_priv(host);
-	dev_set_drvdata(&ofdev->dev, host);
-
-	host->ioaddr = of_iomap(np, 0);
-	if (!host->ioaddr) {
-		ret = -ENOMEM;
-		goto err_addr_map;
-	}
-
-	host->irq = irq_of_parse_and_map(np, 0);
-	if (!host->irq) {
-		ret = -EINVAL;
-		goto err_no_irq;
-	}
-
-	host->hw_name = dev_name(&ofdev->dev);
-	if (pdata) {
-		host->quirks = pdata->quirks;
-		host->ops = &pdata->ops;
-	}
-
-	if (of_get_property(np, "sdhci,auto-cmd12", NULL))
-		host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12;
-
-
-	if (of_get_property(np, "sdhci,1-bit-only", NULL))
-		host->quirks |= SDHCI_QUIRK_FORCE_1_BIT_DATA;
-
-	if (sdhci_of_wp_inverted(np))
-		host->quirks |= SDHCI_QUIRK_INVERTED_WRITE_PROTECT;
-
-	clk = of_get_property(np, "clock-frequency", &size);
-	if (clk && size == sizeof(*clk) && *clk)
-		pltfm_host->clock = be32_to_cpup(clk);
-
-	ret = sdhci_add_host(host);
-	if (ret)
-		goto err_add_host;
-
-	return 0;
-
-err_add_host:
-	irq_dispose_mapping(host->irq);
-err_no_irq:
-	iounmap(host->ioaddr);
-err_addr_map:
-	sdhci_free_host(host);
-	return ret;
-}
-
-static int __devexit sdhci_of_remove(struct platform_device *ofdev)
-{
-	struct sdhci_host *host = dev_get_drvdata(&ofdev->dev);
-
-	sdhci_remove_host(host, 0);
-	sdhci_free_host(host);
-	irq_dispose_mapping(host->irq);
-	iounmap(host->ioaddr);
-	return 0;
-}
-
-static const struct of_device_id sdhci_of_match[] = {
-#ifdef CONFIG_MMC_SDHCI_OF_ESDHC
-	{ .compatible = "fsl,mpc8379-esdhc", .data = &sdhci_esdhc_pdata, },
-	{ .compatible = "fsl,mpc8536-esdhc", .data = &sdhci_esdhc_pdata, },
-	{ .compatible = "fsl,esdhc", .data = &sdhci_esdhc_pdata, },
-#endif
-#ifdef CONFIG_MMC_SDHCI_OF_HLWD
-	{ .compatible = "nintendo,hollywood-sdhci", .data = &sdhci_hlwd_pdata, },
-#endif
-	{ .compatible = "generic-sdhci", },
-	{},
-};
-MODULE_DEVICE_TABLE(of, sdhci_of_match);
-
-static struct platform_driver sdhci_of_driver = {
-	.driver = {
-		.name = "sdhci-of",
-		.owner = THIS_MODULE,
-		.of_match_table = sdhci_of_match,
-	},
-	.probe = sdhci_of_probe,
-	.remove = __devexit_p(sdhci_of_remove),
-	.suspend = sdhci_of_suspend,
-	.resume	= sdhci_of_resume,
-};
-
-static int __init sdhci_of_init(void)
-{
-	return platform_driver_register(&sdhci_of_driver);
-}
-module_init(sdhci_of_init);
-
-static void __exit sdhci_of_exit(void)
-{
-	platform_driver_unregister(&sdhci_of_driver);
-}
-module_exit(sdhci_of_exit);
-
-MODULE_DESCRIPTION("Secure Digital Host Controller Interface OF driver");
-MODULE_AUTHOR("Xiaobo Xie <X.Xie@freescale.com>, "
-	      "Anton Vorontsov <avorontsov@ru.mvista.com>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index 492bcd7..2db6a45 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -16,7 +16,7 @@
 #include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/mmc/host.h>
-#include "sdhci-of.h"
+#include "sdhci-pltfm.h"
 #include "sdhci.h"
 #include "sdhci-esdhc.h"
 
@@ -85,9 +85,58 @@ static struct sdhci_ops sdhci_esdhc_ops = {
 	.get_min_clock = esdhc_of_get_min_clock,
 };
 
-struct sdhci_pltfm_data sdhci_esdhc_pdata = {
+static struct sdhci_pltfm_data sdhci_esdhc_pdata = {
 	/* card detection could be handled via GPIO */
 	.quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_CARD_DETECTION
 		| SDHCI_QUIRK_NO_CARD_NO_RESET,
 	.ops = &sdhci_esdhc_ops,
 };
+
+static int __devinit sdhci_esdhc_probe(struct platform_device *pdev)
+{
+	return sdhci_pltfm_register(pdev, &sdhci_esdhc_pdata);
+}
+
+static int __devexit sdhci_esdhc_remove(struct platform_device *pdev)
+{
+	return sdhci_pltfm_unregister(pdev);
+}
+
+static const struct of_device_id sdhci_esdhc_of_match[] = {
+	{ .compatible = "fsl,mpc8379-esdhc" },
+	{ .compatible = "fsl,mpc8536-esdhc" },
+	{ .compatible = "fsl,esdhc" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, sdhci_esdhc_of_match);
+
+static struct platform_driver sdhci_esdhc_driver = {
+	.driver = {
+		.name = "sdhci-esdhc",
+		.owner = THIS_MODULE,
+		.of_match_table = sdhci_esdhc_of_match,
+	},
+	.probe = sdhci_esdhc_probe,
+	.remove = __devexit_p(sdhci_esdhc_remove),
+#ifdef CONFIG_PM
+	.suspend = sdhci_pltfm_suspend,
+	.resume = sdhci_pltfm_resume,
+#endif
+};
+
+static int __init sdhci_esdhc_init(void)
+{
+	return platform_driver_register(&sdhci_esdhc_driver);
+}
+module_init(sdhci_esdhc_init);
+
+static void __exit sdhci_esdhc_exit(void)
+{
+	platform_driver_unregister(&sdhci_esdhc_driver);
+}
+module_exit(sdhci_esdhc_exit);
+
+MODULE_DESCRIPTION("SDHCI OF driver for Freescale MPC eSDHC");
+MODULE_AUTHOR("Xiaobo Xie <X.Xie@freescale.com>, "
+	      "Anton Vorontsov <avorontsov@ru.mvista.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mmc/host/sdhci-of-hlwd.c b/drivers/mmc/host/sdhci-of-hlwd.c
index 380e896..faedfce 100644
--- a/drivers/mmc/host/sdhci-of-hlwd.c
+++ b/drivers/mmc/host/sdhci-of-hlwd.c
@@ -21,7 +21,7 @@
 
 #include <linux/delay.h>
 #include <linux/mmc/host.h>
-#include "sdhci-of.h"
+#include "sdhci-pltfm.h"
 #include "sdhci.h"
 
 /*
@@ -60,8 +60,54 @@ static struct sdhci_ops sdhci_hlwd_ops = {
 	.write_b = sdhci_hlwd_writeb,
 };
 
-struct sdhci_pltfm_data sdhci_hlwd_pdata = {
+static struct sdhci_pltfm_data sdhci_hlwd_pdata = {
 	.quirks = SDHCI_QUIRK_32BIT_DMA_ADDR |
 		  SDHCI_QUIRK_32BIT_DMA_SIZE,
 	.ops = &sdhci_hlwd_ops,
 };
+
+static int __devinit sdhci_hlwd_probe(struct platform_device *pdev)
+{
+	return sdhci_pltfm_register(pdev, &sdhci_hlwd_pdata);
+}
+
+static int __devexit sdhci_hlwd_remove(struct platform_device *pdev)
+{
+	return sdhci_pltfm_unregister(pdev);
+}
+
+static const struct of_device_id sdhci_hlwd_of_match[] = {
+	{ .compatible = "nintendo,hollywood-sdhci" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, sdhci_hlwd_of_match);
+
+static struct platform_driver sdhci_hlwd_driver = {
+	.driver = {
+		.name = "sdhci-hlwd",
+		.owner = THIS_MODULE,
+		.of_match_table = sdhci_hlwd_of_match,
+	},
+	.probe = sdhci_hlwd_probe,
+	.remove = __devexit_p(sdhci_hlwd_remove),
+#ifdef CONFIG_PM
+	.suspend = sdhci_pltfm_suspend,
+	.resume = sdhci_pltfm_resume,
+#endif
+};
+
+static int __init sdhci_hlwd_init(void)
+{
+	return platform_driver_register(&sdhci_hlwd_driver);
+}
+module_init(sdhci_hlwd_init);
+
+static void __exit sdhci_hlwd_exit(void)
+{
+	platform_driver_unregister(&sdhci_hlwd_driver);
+}
+module_exit(sdhci_hlwd_exit);
+
+MODULE_DESCRIPTION("Nintendo Wii SDHCI OF driver");
+MODULE_AUTHOR("The GameCube Linux Team, Albert Herranz");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mmc/host/sdhci-of.h b/drivers/mmc/host/sdhci-of.h
deleted file mode 100644
index 5bdb5e7..0000000
--- a/drivers/mmc/host/sdhci-of.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * OpenFirmware bindings for Secure Digital Host Controller Interface.
- *
- * Copyright (c) 2007 Freescale Semiconductor, Inc.
- * Copyright (c) 2009 MontaVista Software, Inc.
- *
- * Authors: Xiaobo Xie <X.Xie@freescale.com>
- *	    Anton Vorontsov <avorontsov@ru.mvista.com>
- *
- * 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.
- */
-
-#ifndef __SDHCI_OF_H
-#define __SDHCI_OF_H
-
-#include <linux/types.h>
-#include "sdhci.h"
-#include "sdhci-pltfm.h"
-
-extern u32 sdhci_be32bs_readl(struct sdhci_host *host, int reg);
-extern u16 sdhci_be32bs_readw(struct sdhci_host *host, int reg);
-extern u8 sdhci_be32bs_readb(struct sdhci_host *host, int reg);
-extern void sdhci_be32bs_writel(struct sdhci_host *host, u32 val, int reg);
-extern void sdhci_be32bs_writew(struct sdhci_host *host, u16 val, int reg);
-extern void sdhci_be32bs_writeb(struct sdhci_host *host, u8 val, int reg);
-
-extern struct sdhci_pltfm_data sdhci_esdhc_pdata;
-extern struct sdhci_pltfm_data sdhci_hlwd_pdata;
-
-#endif /* __SDHCI_OF_H */
diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c
index 8ccf256..4b22db2 100644
--- a/drivers/mmc/host/sdhci-pltfm.c
+++ b/drivers/mmc/host/sdhci-pltfm.c
@@ -23,13 +23,113 @@
  */
 
 #include <linux/err.h>
-
+#include <linux/of.h>
+#ifdef CONFIG_PPC
+#include <asm/machdep.h>
+#endif
 #include "sdhci.h"
 #include "sdhci-pltfm.h"
 
 static struct sdhci_ops sdhci_pltfm_ops = {
 };
 
+#ifdef CONFIG_MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
+/*
+ * These accessors are designed for big endian hosts doing I/O to
+ * little endian controllers incorporating a 32-bit hardware byte swapper.
+ */
+u32 sdhci_be32bs_readl(struct sdhci_host *host, int reg)
+{
+	return in_be32(host->ioaddr + reg);
+}
+
+u16 sdhci_be32bs_readw(struct sdhci_host *host, int reg)
+{
+	return in_be16(host->ioaddr + (reg ^ 0x2));
+}
+
+u8 sdhci_be32bs_readb(struct sdhci_host *host, int reg)
+{
+	return in_8(host->ioaddr + (reg ^ 0x3));
+}
+
+void sdhci_be32bs_writel(struct sdhci_host *host, u32 val, int reg)
+{
+	out_be32(host->ioaddr + reg, val);
+}
+
+void sdhci_be32bs_writew(struct sdhci_host *host, u16 val, int reg)
+{
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	int base = reg & ~0x3;
+	int shift = (reg & 0x2) * 8;
+
+	switch (reg) {
+	case SDHCI_TRANSFER_MODE:
+		/*
+		 * Postpone this write, we must do it together with a
+		 * command write that is down below.
+		 */
+		pltfm_host->xfer_mode_shadow = val;
+		return;
+	case SDHCI_COMMAND:
+		sdhci_be32bs_writel(host, val << 16 | pltfm_host->xfer_mode_shadow,
+				    SDHCI_TRANSFER_MODE);
+		return;
+	}
+	clrsetbits_be32(host->ioaddr + base, 0xffff << shift, val << shift);
+}
+
+void sdhci_be32bs_writeb(struct sdhci_host *host, u8 val, int reg)
+{
+	int base = reg & ~0x3;
+	int shift = (reg & 0x3) * 8;
+
+	clrsetbits_be32(host->ioaddr + base , 0xff << shift, val << shift);
+}
+#endif /* CONFIG_MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER */
+
+#ifdef CONFIG_OF
+static bool sdhci_of_wp_inverted(struct device_node *np)
+{
+	if (of_get_property(np, "sdhci,wp-inverted", NULL))
+		return true;
+
+	/* Old device trees don't have the wp-inverted property. */
+#ifdef CONFIG_PPC
+	return machine_is(mpc837x_rdb) || machine_is(mpc837x_mds);
+#else
+	return false;
+#endif
+}
+
+void sdhci_get_of_property(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct sdhci_host *host = platform_get_drvdata(pdev);
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	const __be32 *clk;
+	int size;
+
+	if (of_device_is_available(np)) {
+		if (of_get_property(np, "sdhci,auto-cmd12", NULL))
+			host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12;
+
+		if (of_get_property(np, "sdhci,1-bit-only", NULL))
+			host->quirks |= SDHCI_QUIRK_FORCE_1_BIT_DATA;
+
+		if (sdhci_of_wp_inverted(np))
+			host->quirks |= SDHCI_QUIRK_INVERTED_WRITE_PROTECT;
+
+		clk = of_get_property(np, "clock-frequency", &size);
+		if (clk && size == sizeof(*clk) && *clk)
+			pltfm_host->clock = be32_to_cpup(clk);
+	}
+}
+#else
+void sdhci_get_of_property(struct platform_device *pdev) {}
+#endif
+
 struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev,
 				    struct sdhci_pltfm_data *pdata)
 {
@@ -117,6 +217,8 @@ int sdhci_pltfm_register(struct platform_device *pdev,
 	if (IS_ERR(host))
 		return PTR_ERR(host);
 
+	sdhci_get_of_property(pdev);
+
 	ret = sdhci_add_host(host);
 	if (ret)
 		sdhci_pltfm_free(pdev);
diff --git a/drivers/mmc/host/sdhci-pltfm.h b/drivers/mmc/host/sdhci-pltfm.h
index 3cac450..fe27b83 100644
--- a/drivers/mmc/host/sdhci-pltfm.h
+++ b/drivers/mmc/host/sdhci-pltfm.h
@@ -15,6 +15,7 @@
 #include <linux/types.h>
 #include <linux/platform_device.h>
 #include <linux/mmc/sdhci-pltfm.h>
+#include <linux/mmc/sdhci.h>
 
 struct sdhci_pltfm_host {
 	struct clk *clk;
@@ -25,6 +26,17 @@ struct sdhci_pltfm_host {
 	u16 xfer_mode_shadow;
 };
 
+#ifdef CONFIG_MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
+extern u32 sdhci_be32bs_readl(struct sdhci_host *host, int reg);
+extern u16 sdhci_be32bs_readw(struct sdhci_host *host, int reg);
+extern u8 sdhci_be32bs_readb(struct sdhci_host *host, int reg);
+extern void sdhci_be32bs_writel(struct sdhci_host *host, u32 val, int reg);
+extern void sdhci_be32bs_writew(struct sdhci_host *host, u16 val, int reg);
+extern void sdhci_be32bs_writeb(struct sdhci_host *host, u8 val, int reg);
+#endif
+
+extern void sdhci_get_of_property(struct platform_device *pdev);
+
 extern struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev,
 					   struct sdhci_pltfm_data *pdata);
 extern void sdhci_pltfm_free(struct platform_device *pdev);
-- 
1.7.4.1

^ permalink raw reply related

* [PATCH v2 2/7] mmc: sdhci: eliminate sdhci_of_host and sdhci_of_data
From: Shawn Guo @ 2011-05-05 13:22 UTC (permalink / raw)
  To: linux-mmc
  Cc: Chris Ball, sameo, Arnd Bergmann, patches, Shawn Guo,
	devicetree-discuss, Saeed Bishara, Xiaobo Xie, kernel,
	Mike Rapoport, Olof Johansson, Anton Vorontsov, linuxppc-dev,
	Albert Herranz, linux-arm-kernel
In-Reply-To: <1304601778-13837-1-git-send-email-shawn.guo@linaro.org>

The patch migrates the use of sdhci_of_host and sdhci_of_data to
sdhci_pltfm_host and sdhci_pltfm_data, so that the former pair can
be eliminated.

Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
Reviewed-by: Grant Likely <grant.likely@secretlab.ca>
---
 drivers/mmc/host/sdhci-of-core.c  |   30 +++++++++++++++---------------
 drivers/mmc/host/sdhci-of-esdhc.c |   36 +++++++++++++++++++-----------------
 drivers/mmc/host/sdhci-of-hlwd.c  |   20 +++++++++++---------
 drivers/mmc/host/sdhci-of.h       |   15 +++------------
 drivers/mmc/host/sdhci-pltfm.h    |    4 ++++
 5 files changed, 52 insertions(+), 53 deletions(-)

diff --git a/drivers/mmc/host/sdhci-of-core.c b/drivers/mmc/host/sdhci-of-core.c
index f9b611f..6b2de9e 100644
--- a/drivers/mmc/host/sdhci-of-core.c
+++ b/drivers/mmc/host/sdhci-of-core.c
@@ -59,7 +59,7 @@ void sdhci_be32bs_writel(struct sdhci_host *host, u32 val, int reg)
 
 void sdhci_be32bs_writew(struct sdhci_host *host, u16 val, int reg)
 {
-	struct sdhci_of_host *of_host = sdhci_priv(host);
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
 	int base = reg & ~0x3;
 	int shift = (reg & 0x2) * 8;
 
@@ -69,10 +69,10 @@ void sdhci_be32bs_writew(struct sdhci_host *host, u16 val, int reg)
 		 * Postpone this write, we must do it together with a
 		 * command write that is down below.
 		 */
-		of_host->xfer_mode_shadow = val;
+		pltfm_host->xfer_mode_shadow = val;
 		return;
 	case SDHCI_COMMAND:
-		sdhci_be32bs_writel(host, val << 16 | of_host->xfer_mode_shadow,
+		sdhci_be32bs_writel(host, val << 16 | pltfm_host->xfer_mode_shadow,
 				    SDHCI_TRANSFER_MODE);
 		return;
 	}
@@ -127,7 +127,7 @@ static bool __devinit sdhci_of_wp_inverted(struct device_node *np)
 static int __devinit sdhci_of_probe(struct platform_device *ofdev)
 {
 	struct device_node *np = ofdev->dev.of_node;
-	struct sdhci_of_data *sdhci_of_data;
+	struct sdhci_pltfm_data *pdata;
 	struct sdhci_host *host;
 	struct sdhci_of_host *of_host;
 	const __be32 *clk;
@@ -136,16 +136,16 @@ static int __devinit sdhci_of_probe(struct platform_device *ofdev)
 
 	if (!ofdev->dev.of_match)
 		return -EINVAL;
-	sdhci_of_data = ofdev->dev.of_match->data;
+	pdata = ofdev->dev.of_match->data;
 
 	if (!of_device_is_available(np))
 		return -ENODEV;
 
-	host = sdhci_alloc_host(&ofdev->dev, sizeof(*of_host));
+	host = sdhci_alloc_host(&ofdev->dev, sizeof(*pltfm_host));
 	if (IS_ERR(host))
 		return -ENOMEM;
 
-	of_host = sdhci_priv(host);
+	pltfm_host = sdhci_priv(host);
 	dev_set_drvdata(&ofdev->dev, host);
 
 	host->ioaddr = of_iomap(np, 0);
@@ -161,9 +161,9 @@ static int __devinit sdhci_of_probe(struct platform_device *ofdev)
 	}
 
 	host->hw_name = dev_name(&ofdev->dev);
-	if (sdhci_of_data) {
-		host->quirks = sdhci_of_data->quirks;
-		host->ops = &sdhci_of_data->ops;
+	if (pdata) {
+		host->quirks = pdata->quirks;
+		host->ops = &pdata->ops;
 	}
 
 	if (of_get_property(np, "sdhci,auto-cmd12", NULL))
@@ -178,7 +178,7 @@ static int __devinit sdhci_of_probe(struct platform_device *ofdev)
 
 	clk = of_get_property(np, "clock-frequency", &size);
 	if (clk && size == sizeof(*clk) && *clk)
-		of_host->clock = be32_to_cpup(clk);
+		pltfm_host->clock = be32_to_cpup(clk);
 
 	ret = sdhci_add_host(host);
 	if (ret)
@@ -208,12 +208,12 @@ static int __devexit sdhci_of_remove(struct platform_device *ofdev)
 
 static const struct of_device_id sdhci_of_match[] = {
 #ifdef CONFIG_MMC_SDHCI_OF_ESDHC
-	{ .compatible = "fsl,mpc8379-esdhc", .data = &sdhci_esdhc, },
-	{ .compatible = "fsl,mpc8536-esdhc", .data = &sdhci_esdhc, },
-	{ .compatible = "fsl,esdhc", .data = &sdhci_esdhc, },
+	{ .compatible = "fsl,mpc8379-esdhc", .data = &sdhci_esdhc_pdata, },
+	{ .compatible = "fsl,mpc8536-esdhc", .data = &sdhci_esdhc_pdata, },
+	{ .compatible = "fsl,esdhc", .data = &sdhci_esdhc_pdata, },
 #endif
 #ifdef CONFIG_MMC_SDHCI_OF_HLWD
-	{ .compatible = "nintendo,hollywood-sdhci", .data = &sdhci_hlwd, },
+	{ .compatible = "nintendo,hollywood-sdhci", .data = &sdhci_hlwd_pdata, },
 #endif
 	{ .compatible = "generic-sdhci", },
 	{},
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index ba40d6d..492bcd7 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -60,32 +60,34 @@ static int esdhc_of_enable_dma(struct sdhci_host *host)
 
 static unsigned int esdhc_of_get_max_clock(struct sdhci_host *host)
 {
-	struct sdhci_of_host *of_host = sdhci_priv(host);
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
 
-	return of_host->clock;
+	return pltfm_host->clock;
 }
 
 static unsigned int esdhc_of_get_min_clock(struct sdhci_host *host)
 {
-	struct sdhci_of_host *of_host = sdhci_priv(host);
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
 
-	return of_host->clock / 256 / 16;
+	return pltfm_host->clock / 256 / 16;
 }
 
-struct sdhci_of_data sdhci_esdhc = {
+static struct sdhci_ops sdhci_esdhc_ops = {
+	.read_l = sdhci_be32bs_readl,
+	.read_w = esdhc_readw,
+	.read_b = sdhci_be32bs_readb,
+	.write_l = sdhci_be32bs_writel,
+	.write_w = esdhc_writew,
+	.write_b = esdhc_writeb,
+	.set_clock = esdhc_set_clock,
+	.enable_dma = esdhc_of_enable_dma,
+	.get_max_clock = esdhc_of_get_max_clock,
+	.get_min_clock = esdhc_of_get_min_clock,
+};
+
+struct sdhci_pltfm_data sdhci_esdhc_pdata = {
 	/* card detection could be handled via GPIO */
 	.quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_CARD_DETECTION
 		| SDHCI_QUIRK_NO_CARD_NO_RESET,
-	.ops = {
-		.read_l = sdhci_be32bs_readl,
-		.read_w = esdhc_readw,
-		.read_b = sdhci_be32bs_readb,
-		.write_l = sdhci_be32bs_writel,
-		.write_w = esdhc_writew,
-		.write_b = esdhc_writeb,
-		.set_clock = esdhc_set_clock,
-		.enable_dma = esdhc_of_enable_dma,
-		.get_max_clock = esdhc_of_get_max_clock,
-		.get_min_clock = esdhc_of_get_min_clock,
-	},
+	.ops = &sdhci_esdhc_ops,
 };
diff --git a/drivers/mmc/host/sdhci-of-hlwd.c b/drivers/mmc/host/sdhci-of-hlwd.c
index 68ddb75..380e896 100644
--- a/drivers/mmc/host/sdhci-of-hlwd.c
+++ b/drivers/mmc/host/sdhci-of-hlwd.c
@@ -51,15 +51,17 @@ static void sdhci_hlwd_writeb(struct sdhci_host *host, u8 val, int reg)
 	udelay(SDHCI_HLWD_WRITE_DELAY);
 }
 
-struct sdhci_of_data sdhci_hlwd = {
+static struct sdhci_ops sdhci_hlwd_ops = {
+	.read_l = sdhci_be32bs_readl,
+	.read_w = sdhci_be32bs_readw,
+	.read_b = sdhci_be32bs_readb,
+	.write_l = sdhci_hlwd_writel,
+	.write_w = sdhci_hlwd_writew,
+	.write_b = sdhci_hlwd_writeb,
+};
+
+struct sdhci_pltfm_data sdhci_hlwd_pdata = {
 	.quirks = SDHCI_QUIRK_32BIT_DMA_ADDR |
 		  SDHCI_QUIRK_32BIT_DMA_SIZE,
-	.ops = {
-		.read_l = sdhci_be32bs_readl,
-		.read_w = sdhci_be32bs_readw,
-		.read_b = sdhci_be32bs_readb,
-		.write_l = sdhci_hlwd_writel,
-		.write_w = sdhci_hlwd_writew,
-		.write_b = sdhci_hlwd_writeb,
-	},
+	.ops = &sdhci_hlwd_ops,
 };
diff --git a/drivers/mmc/host/sdhci-of.h b/drivers/mmc/host/sdhci-of.h
index ad09ad9..5bdb5e7 100644
--- a/drivers/mmc/host/sdhci-of.h
+++ b/drivers/mmc/host/sdhci-of.h
@@ -18,16 +18,7 @@
 
 #include <linux/types.h>
 #include "sdhci.h"
-
-struct sdhci_of_data {
-	unsigned int quirks;
-	struct sdhci_ops ops;
-};
-
-struct sdhci_of_host {
-	unsigned int clock;
-	u16 xfer_mode_shadow;
-};
+#include "sdhci-pltfm.h"
 
 extern u32 sdhci_be32bs_readl(struct sdhci_host *host, int reg);
 extern u16 sdhci_be32bs_readw(struct sdhci_host *host, int reg);
@@ -36,7 +27,7 @@ extern void sdhci_be32bs_writel(struct sdhci_host *host, u32 val, int reg);
 extern void sdhci_be32bs_writew(struct sdhci_host *host, u16 val, int reg);
 extern void sdhci_be32bs_writeb(struct sdhci_host *host, u8 val, int reg);
 
-extern struct sdhci_of_data sdhci_esdhc;
-extern struct sdhci_of_data sdhci_hlwd;
+extern struct sdhci_pltfm_data sdhci_esdhc_pdata;
+extern struct sdhci_pltfm_data sdhci_hlwd_pdata;
 
 #endif /* __SDHCI_OF_H */
diff --git a/drivers/mmc/host/sdhci-pltfm.h b/drivers/mmc/host/sdhci-pltfm.h
index ff4b7eb..3cac450 100644
--- a/drivers/mmc/host/sdhci-pltfm.h
+++ b/drivers/mmc/host/sdhci-pltfm.h
@@ -19,6 +19,10 @@
 struct sdhci_pltfm_host {
 	struct clk *clk;
 	void *priv; /* to handle quirks across io-accessor calls */
+
+	/* migrate from sdhci_of_host */
+	unsigned int clock;
+	u16 xfer_mode_shadow;
 };
 
 extern struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev,
-- 
1.7.4.1

^ permalink raw reply related

* [PATCH v2 1/7] mmc: sdhci: make sdhci-pltfm device drivers self registered
From: Shawn Guo @ 2011-05-05 13:22 UTC (permalink / raw)
  To: linux-mmc
  Cc: Chris Ball, sameo, Arnd Bergmann, patches, Shawn Guo,
	devicetree-discuss, Saeed Bishara, Xiaobo Xie, kernel,
	Mike Rapoport, Olof Johansson, Anton Vorontsov, linuxppc-dev,
	Albert Herranz, linux-arm-kernel
In-Reply-To: <1304601778-13837-1-git-send-email-shawn.guo@linaro.org>

The patch turns the common stuff in sdhci-pltfm.c into functions, and
add device drivers their own .probe and .remove which in turn call
into the common functions, so that those sdhci-pltfm device drivers
register itself and keep all device specific things away from common
sdhci-pltfm file.

Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Reviewed-by: Grant Likely <grant.likely@secretlab.ca>
---
 drivers/mmc/host/Kconfig           |   32 ++++----
 drivers/mmc/host/Makefile          |   11 +--
 drivers/mmc/host/sdhci-cns3xxx.c   |   42 +++++++++-
 drivers/mmc/host/sdhci-dove.c      |   42 +++++++++-
 drivers/mmc/host/sdhci-esdhc-imx.c |  112 ++++++++++++++++++-------
 drivers/mmc/host/sdhci-pltfm.c     |  157 +++++++++---------------------------
 drivers/mmc/host/sdhci-pltfm.h     |   17 +++-
 drivers/mmc/host/sdhci-tegra.c     |  118 +++++++++++++++++++--------
 include/linux/mmc/sdhci-pltfm.h    |    6 --
 9 files changed, 317 insertions(+), 220 deletions(-)

diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index b981715..799e935 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -113,28 +113,27 @@ config MMC_SDHCI_OF_HLWD
 	  If unsure, say N.
 
 config MMC_SDHCI_PLTFM
-	tristate "SDHCI support on the platform specific bus"
+	bool
 	depends on MMC_SDHCI
 	help
-	  This selects the platform specific bus support for Secure Digital Host
-	  Controller Interface.
-
-	  If you have a controller with this interface, say Y or M here.
-
-	  If unsure, say N.
+	  This selects the platform common function support for Secure Digital
+	  Host Controller Interface.
 
 config MMC_SDHCI_CNS3XXX
-	bool "SDHCI support on the Cavium Networks CNS3xxx SoC"
+	tristate "SDHCI support on the Cavium Networks CNS3xxx SoC"
 	depends on ARCH_CNS3XXX
-	depends on MMC_SDHCI_PLTFM
+	depends on MMC_SDHCI
+	select MMC_SDHCI_PLTFM
 	help
 	  This selects the SDHCI support for CNS3xxx System-on-Chip devices.
 
 	  If unsure, say N.
 
 config MMC_SDHCI_ESDHC_IMX
-	bool "SDHCI platform support for the Freescale eSDHC i.MX controller"
-	depends on MMC_SDHCI_PLTFM && (ARCH_MX25 || ARCH_MX35 || ARCH_MX5)
+	tristate "SDHCI platform support for the Freescale eSDHC i.MX controller"
+	depends on ARCH_MX25 || ARCH_MX35 || ARCH_MX5
+	depends on MMC_SDHCI
+	select MMC_SDHCI_PLTFM
 	select MMC_SDHCI_IO_ACCESSORS
 	help
 	  This selects the Freescale eSDHC controller support on the platform
@@ -143,9 +142,10 @@ config MMC_SDHCI_ESDHC_IMX
 	  If unsure, say N.
 
 config MMC_SDHCI_DOVE
-	bool "SDHCI support on Marvell's Dove SoC"
+	tristate "SDHCI support on Marvell's Dove SoC"
 	depends on ARCH_DOVE
-	depends on MMC_SDHCI_PLTFM
+	depends on MMC_SDHCI
+	select MMC_SDHCI_PLTFM
 	select MMC_SDHCI_IO_ACCESSORS
 	help
 	  This selects the Secure Digital Host Controller Interface in
@@ -154,8 +154,10 @@ config MMC_SDHCI_DOVE
 	  If unsure, say N.
 
 config MMC_SDHCI_TEGRA
-	bool "SDHCI platform support for the Tegra SD/MMC Controller"
-	depends on MMC_SDHCI_PLTFM && ARCH_TEGRA
+	tristate "SDHCI platform support for the Tegra SD/MMC Controller"
+	depends on ARCH_TEGRA
+	depends on MMC_SDHCI
+	select MMC_SDHCI_PLTFM
 	select MMC_SDHCI_IO_ACCESSORS
 	help
 	  This selects the Tegra SD/MMC controller. If you have a Tegra
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 4f1df0a..95fddb8 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -43,12 +43,11 @@ obj-$(CONFIG_MMC_SH_MMCIF)	+= sh_mmcif.o
 obj-$(CONFIG_MMC_JZ4740)	+= jz4740_mmc.o
 obj-$(CONFIG_MMC_USHC)		+= ushc.o
 
-obj-$(CONFIG_MMC_SDHCI_PLTFM)			+= sdhci-platform.o
-sdhci-platform-y				:= sdhci-pltfm.o
-sdhci-platform-$(CONFIG_MMC_SDHCI_CNS3XXX)	+= sdhci-cns3xxx.o
-sdhci-platform-$(CONFIG_MMC_SDHCI_ESDHC_IMX)	+= sdhci-esdhc-imx.o
-sdhci-platform-$(CONFIG_MMC_SDHCI_DOVE)		+= sdhci-dove.o
-sdhci-platform-$(CONFIG_MMC_SDHCI_TEGRA)	+= sdhci-tegra.o
+obj-$(CONFIG_MMC_SDHCI_PLTFM)		+= sdhci-pltfm.o
+obj-$(CONFIG_MMC_SDHCI_CNS3XXX)		+= sdhci-cns3xxx.o
+obj-$(CONFIG_MMC_SDHCI_ESDHC_IMX)	+= sdhci-esdhc-imx.o
+obj-$(CONFIG_MMC_SDHCI_DOVE)		+= sdhci-dove.o
+obj-$(CONFIG_MMC_SDHCI_TEGRA)		+= sdhci-tegra.o
 
 obj-$(CONFIG_MMC_SDHCI_OF)	+= sdhci-of.o
 sdhci-of-y				:= sdhci-of-core.o
diff --git a/drivers/mmc/host/sdhci-cns3xxx.c b/drivers/mmc/host/sdhci-cns3xxx.c
index 9ebd1d7..ac4b26f 100644
--- a/drivers/mmc/host/sdhci-cns3xxx.c
+++ b/drivers/mmc/host/sdhci-cns3xxx.c
@@ -86,7 +86,7 @@ static struct sdhci_ops sdhci_cns3xxx_ops = {
 	.set_clock	= sdhci_cns3xxx_set_clock,
 };
 
-struct sdhci_pltfm_data sdhci_cns3xxx_pdata = {
+static struct sdhci_pltfm_data sdhci_cns3xxx_pdata = {
 	.ops = &sdhci_cns3xxx_ops,
 	.quirks = SDHCI_QUIRK_BROKEN_DMA |
 		  SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
@@ -95,3 +95,43 @@ struct sdhci_pltfm_data sdhci_cns3xxx_pdata = {
 		  SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
 		  SDHCI_QUIRK_NONSTANDARD_CLOCK,
 };
+
+static int __devinit sdhci_cns3xxx_probe(struct platform_device *pdev)
+{
+	return sdhci_pltfm_register(pdev, &sdhci_cns3xxx_pdata);
+}
+
+static int __devexit sdhci_cns3xxx_remove(struct platform_device *pdev)
+{
+	return sdhci_pltfm_unregister(pdev);
+}
+
+static struct platform_driver sdhci_cns3xxx_driver = {
+	.driver		= {
+		.name	= "sdhci-cns3xxx",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= sdhci_cns3xxx_probe,
+	.remove		= __devexit_p(sdhci_cns3xxx_remove),
+#ifdef CONFIG_PM
+	.suspend	= sdhci_pltfm_suspend,
+	.resume		= sdhci_pltfm_resume,
+#endif
+};
+
+static int __init sdhci_cns3xxx_init(void)
+{
+	return platform_driver_register(&sdhci_cns3xxx_driver);
+}
+module_init(sdhci_cns3xxx_init);
+
+static void __exit sdhci_cns3xxx_exit(void)
+{
+	platform_driver_unregister(&sdhci_cns3xxx_driver);
+}
+module_exit(sdhci_cns3xxx_exit);
+
+MODULE_DESCRIPTION("SDHCI driver for CNS3xxx");
+MODULE_AUTHOR("Scott Shu, "
+	      "Anton Vorontsov <avorontsov@mvista.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mmc/host/sdhci-dove.c b/drivers/mmc/host/sdhci-dove.c
index 2aeef4f..49aa533 100644
--- a/drivers/mmc/host/sdhci-dove.c
+++ b/drivers/mmc/host/sdhci-dove.c
@@ -61,10 +61,50 @@ static struct sdhci_ops sdhci_dove_ops = {
 	.read_l	= sdhci_dove_readl,
 };
 
-struct sdhci_pltfm_data sdhci_dove_pdata = {
+static struct sdhci_pltfm_data sdhci_dove_pdata = {
 	.ops	= &sdhci_dove_ops,
 	.quirks	= SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER |
 		  SDHCI_QUIRK_NO_BUSY_IRQ |
 		  SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
 		  SDHCI_QUIRK_FORCE_DMA,
 };
+
+static int __devinit sdhci_dove_probe(struct platform_device *pdev)
+{
+	return sdhci_pltfm_register(pdev, &sdhci_dove_pdata);
+}
+
+static int __devexit sdhci_dove_remove(struct platform_device *pdev)
+{
+	return sdhci_pltfm_unregister(pdev);
+}
+
+static struct platform_driver sdhci_dove_driver = {
+	.driver		= {
+		.name	= "sdhci-dove",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= sdhci_dove_probe,
+	.remove		= __devexit_p(sdhci_dove_remove),
+#ifdef CONFIG_PM
+	.suspend	= sdhci_pltfm_suspend,
+	.resume		= sdhci_pltfm_resume,
+#endif
+};
+
+static int __init sdhci_dove_init(void)
+{
+	return platform_driver_register(&sdhci_dove_driver);
+}
+module_init(sdhci_dove_init);
+
+static void __exit sdhci_dove_exit(void)
+{
+	platform_driver_unregister(&sdhci_dove_driver);
+}
+module_exit(sdhci_dove_exit);
+
+MODULE_DESCRIPTION("SDHCI driver for Dove");
+MODULE_AUTHOR("Saeed Bishara <saeed@marvell.com>, "
+	      "Mike Rapoport <mike@compulab.co.il>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index a19967d..8da57d4 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -191,16 +191,6 @@ static unsigned int esdhc_pltfm_get_min_clock(struct sdhci_host *host)
 	return clk_get_rate(pltfm_host->clk) / 256 / 16;
 }
 
-static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host)
-{
-	struct esdhc_platform_data *boarddata = host->mmc->parent->platform_data;
-
-	if (boarddata && gpio_is_valid(boarddata->wp_gpio))
-		return gpio_get_value(boarddata->wp_gpio);
-	else
-		return -ENOSYS;
-}
-
 static struct sdhci_ops sdhci_esdhc_ops = {
 	.read_l = esdhc_readl_le,
 	.read_w = esdhc_readw_le,
@@ -212,6 +202,23 @@ static struct sdhci_ops sdhci_esdhc_ops = {
 	.get_min_clock = esdhc_pltfm_get_min_clock,
 };
 
+static struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
+	.quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_ADMA
+			| SDHCI_QUIRK_BROKEN_CARD_DETECTION,
+	/* ADMA has issues. Might be fixable */
+	.ops = &sdhci_esdhc_ops,
+};
+
+static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host)
+{
+	struct esdhc_platform_data *boarddata = host->mmc->parent->platform_data;
+
+	if (boarddata && gpio_is_valid(boarddata->wp_gpio))
+		return gpio_get_value(boarddata->wp_gpio);
+	else
+		return -ENOSYS;
+}
+
 static irqreturn_t cd_irq(int irq, void *data)
 {
 	struct sdhci_host *sdhost = (struct sdhci_host *)data;
@@ -220,30 +227,35 @@ static irqreturn_t cd_irq(int irq, void *data)
 	return IRQ_HANDLED;
 };
 
-static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pdata)
+static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
 {
-	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
-	struct esdhc_platform_data *boarddata = host->mmc->parent->platform_data;
+	struct sdhci_pltfm_host *pltfm_host;
+	struct sdhci_host *host;
+	struct esdhc_platform_data *boarddata;
 	struct clk *clk;
 	int err;
 	struct pltfm_imx_data *imx_data;
 
+	host = sdhci_pltfm_init(pdev, &sdhci_esdhc_imx_pdata);
+	if (IS_ERR(host))
+		return PTR_ERR(host);
+
+	pltfm_host = sdhci_priv(host);
+
+	imx_data = kzalloc(sizeof(struct pltfm_imx_data), GFP_KERNEL);
+	if (!imx_data)
+		return -ENOMEM;
+	pltfm_host->priv = imx_data;
+
 	clk = clk_get(mmc_dev(host->mmc), NULL);
 	if (IS_ERR(clk)) {
 		dev_err(mmc_dev(host->mmc), "clk err\n");
-		return PTR_ERR(clk);
+		err = PTR_ERR(clk);
+		goto err_clk_get;
 	}
 	clk_enable(clk);
 	pltfm_host->clk = clk;
 
-	imx_data = kzalloc(sizeof(struct pltfm_imx_data), GFP_KERNEL);
-	if (!imx_data) {
-		clk_disable(pltfm_host->clk);
-		clk_put(pltfm_host->clk);
-		return -ENOMEM;
-	}
-	pltfm_host->priv = imx_data;
-
 	if (!cpu_is_mx25())
 		host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
 
@@ -257,6 +269,7 @@ static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pd
 	if (!(cpu_is_mx25() || cpu_is_mx35() || cpu_is_mx51()))
 		imx_data->flags |= ESDHC_FLAG_MULTIBLK_NO_INT;
 
+	boarddata = host->mmc->parent->platform_data;
 	if (boarddata) {
 		err = gpio_request_one(boarddata->wp_gpio, GPIOF_IN, "ESDHC_WP");
 		if (err) {
@@ -289,6 +302,10 @@ static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pd
 		host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION;
 	}
 
+	err = sdhci_add_host(host);
+	if (err)
+		goto err_add_host;
+
 	return 0;
 
  no_card_detect_irq:
@@ -297,14 +314,23 @@ static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pd
 	boarddata->cd_gpio = err;
  not_supported:
 	kfree(imx_data);
-	return 0;
+ err_add_host:
+	clk_disable(pltfm_host->clk);
+	clk_put(pltfm_host->clk);
+ err_clk_get:
+	sdhci_pltfm_free(pdev);
+	return err;
 }
 
-static void esdhc_pltfm_exit(struct sdhci_host *host)
+static int __devexit sdhci_esdhc_imx_remove(struct platform_device *pdev)
 {
+	struct sdhci_host *host = platform_get_drvdata(pdev);
 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
 	struct esdhc_platform_data *boarddata = host->mmc->parent->platform_data;
 	struct pltfm_imx_data *imx_data = pltfm_host->priv;
+	int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
+
+	sdhci_remove_host(host, dead);
 
 	if (boarddata && gpio_is_valid(boarddata->wp_gpio))
 		gpio_free(boarddata->wp_gpio);
@@ -319,13 +345,37 @@ static void esdhc_pltfm_exit(struct sdhci_host *host)
 	clk_disable(pltfm_host->clk);
 	clk_put(pltfm_host->clk);
 	kfree(imx_data);
+
+	sdhci_pltfm_free(pdev);
+
+	return 0;
 }
 
-struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
-	.quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_ADMA
-			| SDHCI_QUIRK_BROKEN_CARD_DETECTION,
-	/* ADMA has issues. Might be fixable */
-	.ops = &sdhci_esdhc_ops,
-	.init = esdhc_pltfm_init,
-	.exit = esdhc_pltfm_exit,
+static struct platform_driver sdhci_esdhc_imx_driver = {
+	.driver		= {
+		.name	= "sdhci-esdhc-imx",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= sdhci_esdhc_imx_probe,
+	.remove		= __devexit_p(sdhci_esdhc_imx_remove),
+#ifdef CONFIG_PM
+	.suspend	= sdhci_pltfm_suspend,
+	.resume		= sdhci_pltfm_resume,
+#endif
 };
+ 
+static int __init sdhci_esdhc_imx_init(void)
+{
+	return platform_driver_register(&sdhci_esdhc_imx_driver);
+}
+module_init(sdhci_esdhc_imx_init);
+
+static void __exit sdhci_esdhc_imx_exit(void)
+{
+	platform_driver_unregister(&sdhci_esdhc_imx_driver);
+}
+module_exit(sdhci_esdhc_imx_exit);
+
+MODULE_DESCRIPTION("SDHCI driver for Freescale i.MX eSDHC");
+MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c
index dbab040..8ccf256 100644
--- a/drivers/mmc/host/sdhci-pltfm.c
+++ b/drivers/mmc/host/sdhci-pltfm.c
@@ -22,48 +22,22 @@
  * Inspired by sdhci-pci.c, by Pierre Ossman
  */
 
-#include <linux/delay.h>
-#include <linux/highmem.h>
-#include <linux/mod_devicetable.h>
-#include <linux/platform_device.h>
-
-#include <linux/mmc/host.h>
-
-#include <linux/io.h>
-#include <linux/mmc/sdhci-pltfm.h>
+#include <linux/err.h>
 
 #include "sdhci.h"
 #include "sdhci-pltfm.h"
 
-/*****************************************************************************\
- *                                                                           *
- * SDHCI core callbacks                                                      *
- *                                                                           *
-\*****************************************************************************/
-
 static struct sdhci_ops sdhci_pltfm_ops = {
 };
 
-/*****************************************************************************\
- *                                                                           *
- * Device probing/removal                                                    *
- *                                                                           *
-\*****************************************************************************/
-
-static int __devinit sdhci_pltfm_probe(struct platform_device *pdev)
+struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev,
+				    struct sdhci_pltfm_data *pdata)
 {
-	const struct platform_device_id *platid = platform_get_device_id(pdev);
-	struct sdhci_pltfm_data *pdata;
 	struct sdhci_host *host;
 	struct sdhci_pltfm_host *pltfm_host;
 	struct resource *iomem;
 	int ret;
 
-	if (platid && platid->driver_data)
-		pdata = (void *)platid->driver_data;
-	else
-		pdata = pdev->dev.platform_data;
-
 	iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!iomem) {
 		ret = -ENOMEM;
@@ -71,8 +45,7 @@ static int __devinit sdhci_pltfm_probe(struct platform_device *pdev)
 	}
 
 	if (resource_size(iomem) < 0x100)
-		dev_err(&pdev->dev, "Invalid iomem size. You may "
-			"experience problems.\n");
+		dev_err(&pdev->dev, "Invalid iomem size!\n");
 
 	/* Some PCI-based MFD need the parent here */
 	if (pdev->dev.parent != &platform_bus)
@@ -87,7 +60,7 @@ static int __devinit sdhci_pltfm_probe(struct platform_device *pdev)
 
 	pltfm_host = sdhci_priv(host);
 
-	host->hw_name = "platform";
+	host->hw_name = dev_name(&pdev->dev);
 	if (pdata && pdata->ops)
 		host->ops = pdata->ops;
 	else
@@ -110,126 +83,70 @@ static int __devinit sdhci_pltfm_probe(struct platform_device *pdev)
 		goto err_remap;
 	}
 
-	if (pdata && pdata->init) {
-		ret = pdata->init(host, pdata);
-		if (ret)
-			goto err_plat_init;
-	}
-
-	ret = sdhci_add_host(host);
-	if (ret)
-		goto err_add_host;
-
 	platform_set_drvdata(pdev, host);
 
-	return 0;
+	return host;
 
-err_add_host:
-	if (pdata && pdata->exit)
-		pdata->exit(host);
-err_plat_init:
-	iounmap(host->ioaddr);
 err_remap:
 	release_mem_region(iomem->start, resource_size(iomem));
 err_request:
 	sdhci_free_host(host);
 err:
-	printk(KERN_ERR"Probing of sdhci-pltfm failed: %d\n", ret);
-	return ret;
+	dev_err(&pdev->dev, "%s failed %d\n", __func__, ret);
+	return ERR_PTR(ret);
 }
 
-static int __devexit sdhci_pltfm_remove(struct platform_device *pdev)
+void sdhci_pltfm_free(struct platform_device *pdev)
 {
-	struct sdhci_pltfm_data *pdata = pdev->dev.platform_data;
 	struct sdhci_host *host = platform_get_drvdata(pdev);
 	struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	int dead;
-	u32 scratch;
-
-	dead = 0;
-	scratch = readl(host->ioaddr + SDHCI_INT_STATUS);
-	if (scratch == (u32)-1)
-		dead = 1;
 
-	sdhci_remove_host(host, dead);
-	if (pdata && pdata->exit)
-		pdata->exit(host);
 	iounmap(host->ioaddr);
 	release_mem_region(iomem->start, resource_size(iomem));
 	sdhci_free_host(host);
 	platform_set_drvdata(pdev, NULL);
+}
 
-	return 0;
+int sdhci_pltfm_register(struct platform_device *pdev,
+			 struct sdhci_pltfm_data *pdata)
+{
+	struct sdhci_host *host;
+	int ret = 0;
+
+	host = sdhci_pltfm_init(pdev, pdata);
+	if (IS_ERR(host))
+		return PTR_ERR(host);
+
+	ret = sdhci_add_host(host);
+	if (ret)
+		sdhci_pltfm_free(pdev);
+
+	return ret;
 }
 
-static const struct platform_device_id sdhci_pltfm_ids[] = {
-	{ "sdhci", },
-#ifdef CONFIG_MMC_SDHCI_CNS3XXX
-	{ "sdhci-cns3xxx", (kernel_ulong_t)&sdhci_cns3xxx_pdata },
-#endif
-#ifdef CONFIG_MMC_SDHCI_ESDHC_IMX
-	{ "sdhci-esdhc-imx", (kernel_ulong_t)&sdhci_esdhc_imx_pdata },
-#endif
-#ifdef CONFIG_MMC_SDHCI_DOVE
-	{ "sdhci-dove", (kernel_ulong_t)&sdhci_dove_pdata },
-#endif
-#ifdef CONFIG_MMC_SDHCI_TEGRA
-	{ "sdhci-tegra", (kernel_ulong_t)&sdhci_tegra_pdata },
-#endif
-	{ },
-};
-MODULE_DEVICE_TABLE(platform, sdhci_pltfm_ids);
+int sdhci_pltfm_unregister(struct platform_device *pdev)
+{
+	struct sdhci_host *host = platform_get_drvdata(pdev);
+	int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
+
+	sdhci_remove_host(host, dead);
+	sdhci_pltfm_free(pdev);
+
+	return 0;
+}
 
 #ifdef CONFIG_PM
-static int sdhci_pltfm_suspend(struct platform_device *dev, pm_message_t state)
+int sdhci_pltfm_suspend(struct platform_device *dev, pm_message_t state)
 {
 	struct sdhci_host *host = platform_get_drvdata(dev);
 
 	return sdhci_suspend_host(host, state);
 }
 
-static int sdhci_pltfm_resume(struct platform_device *dev)
+int sdhci_pltfm_resume(struct platform_device *dev)
 {
 	struct sdhci_host *host = platform_get_drvdata(dev);
 
 	return sdhci_resume_host(host);
 }
-#else
-#define sdhci_pltfm_suspend	NULL
-#define sdhci_pltfm_resume	NULL
 #endif	/* CONFIG_PM */
-
-static struct platform_driver sdhci_pltfm_driver = {
-	.driver = {
-		.name	= "sdhci",
-		.owner	= THIS_MODULE,
-	},
-	.probe		= sdhci_pltfm_probe,
-	.remove		= __devexit_p(sdhci_pltfm_remove),
-	.id_table	= sdhci_pltfm_ids,
-	.suspend	= sdhci_pltfm_suspend,
-	.resume		= sdhci_pltfm_resume,
-};
-
-/*****************************************************************************\
- *                                                                           *
- * Driver init/exit                                                          *
- *                                                                           *
-\*****************************************************************************/
-
-static int __init sdhci_drv_init(void)
-{
-	return platform_driver_register(&sdhci_pltfm_driver);
-}
-
-static void __exit sdhci_drv_exit(void)
-{
-	platform_driver_unregister(&sdhci_pltfm_driver);
-}
-
-module_init(sdhci_drv_init);
-module_exit(sdhci_drv_exit);
-
-MODULE_DESCRIPTION("Secure Digital Host Controller Interface platform driver");
-MODULE_AUTHOR("Mocean Laboratories <info@mocean-labs.com>");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/mmc/host/sdhci-pltfm.h b/drivers/mmc/host/sdhci-pltfm.h
index 2b37016..ff4b7eb 100644
--- a/drivers/mmc/host/sdhci-pltfm.h
+++ b/drivers/mmc/host/sdhci-pltfm.h
@@ -13,6 +13,7 @@
 
 #include <linux/clk.h>
 #include <linux/types.h>
+#include <linux/platform_device.h>
 #include <linux/mmc/sdhci-pltfm.h>
 
 struct sdhci_pltfm_host {
@@ -20,9 +21,17 @@ struct sdhci_pltfm_host {
 	void *priv; /* to handle quirks across io-accessor calls */
 };
 
-extern struct sdhci_pltfm_data sdhci_cns3xxx_pdata;
-extern struct sdhci_pltfm_data sdhci_esdhc_imx_pdata;
-extern struct sdhci_pltfm_data sdhci_dove_pdata;
-extern struct sdhci_pltfm_data sdhci_tegra_pdata;
+extern struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev,
+					   struct sdhci_pltfm_data *pdata);
+extern void sdhci_pltfm_free(struct platform_device *pdev);
+
+extern int sdhci_pltfm_register(struct platform_device *pdev,
+				struct sdhci_pltfm_data *pdata);
+extern int sdhci_pltfm_unregister(struct platform_device *pdev);
+
+#ifdef CONFIG_PM
+extern int sdhci_pltfm_suspend(struct platform_device *dev, pm_message_t state);
+extern int sdhci_pltfm_resume(struct platform_device *dev);
+#endif
 
 #endif /* _DRIVERS_MMC_SDHCI_PLTFM_H */
diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c
index 343c97e..95fce3d 100644
--- a/drivers/mmc/host/sdhci-tegra.c
+++ b/drivers/mmc/host/sdhci-tegra.c
@@ -116,20 +116,42 @@ static int tegra_sdhci_8bit(struct sdhci_host *host, int bus_width)
 	return 0;
 }
 
+static struct sdhci_ops tegra_sdhci_ops = {
+	.get_ro     = tegra_sdhci_get_ro,
+	.read_l     = tegra_sdhci_readl,
+	.read_w     = tegra_sdhci_readw,
+	.write_l    = tegra_sdhci_writel,
+	.platform_8bit_width = tegra_sdhci_8bit,
+};
+
+static struct sdhci_pltfm_data sdhci_tegra_pdata = {
+	.quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
+		  SDHCI_QUIRK_SINGLE_POWER_WRITE |
+		  SDHCI_QUIRK_NO_HISPD_BIT |
+		  SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC,
+	.ops  = &tegra_sdhci_ops,
+};
 
-static int tegra_sdhci_pltfm_init(struct sdhci_host *host,
-				  struct sdhci_pltfm_data *pdata)
+static int __devinit sdhci_tegra_probe(struct platform_device *pdev)
 {
-	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
-	struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc));
+	struct sdhci_pltfm_host *pltfm_host;
 	struct tegra_sdhci_platform_data *plat;
+	struct sdhci_host *host;
 	struct clk *clk;
 	int rc;
 
+	host = sdhci_pltfm_init(pdev, &sdhci_tegra_pdata);
+	if (IS_ERR(host))
+		return PTR_ERR(host);
+
+	pltfm_host = sdhci_priv(host);
+
 	plat = pdev->dev.platform_data;
+
 	if (plat == NULL) {
 		dev_err(mmc_dev(host->mmc), "missing platform data\n");
-		return -ENXIO;
+		rc = -ENXIO;
+		goto err_no_plat;
 	}
 
 	if (gpio_is_valid(plat->power_gpio)) {
@@ -137,7 +159,7 @@ static int tegra_sdhci_pltfm_init(struct sdhci_host *host,
 		if (rc) {
 			dev_err(mmc_dev(host->mmc),
 				"failed to allocate power gpio\n");
-			goto out;
+			goto err_power_req;
 		}
 		tegra_gpio_enable(plat->power_gpio);
 		gpio_direction_output(plat->power_gpio, 1);
@@ -148,7 +170,7 @@ static int tegra_sdhci_pltfm_init(struct sdhci_host *host,
 		if (rc) {
 			dev_err(mmc_dev(host->mmc),
 				"failed to allocate cd gpio\n");
-			goto out_power;
+			goto err_cd_req;
 		}
 		tegra_gpio_enable(plat->cd_gpio);
 		gpio_direction_input(plat->cd_gpio);
@@ -159,7 +181,7 @@ static int tegra_sdhci_pltfm_init(struct sdhci_host *host,
 
 		if (rc)	{
 			dev_err(mmc_dev(host->mmc), "request irq error\n");
-			goto out_cd;
+			goto err_cd_irq_req;
 		}
 
 	}
@@ -169,7 +191,7 @@ static int tegra_sdhci_pltfm_init(struct sdhci_host *host,
 		if (rc) {
 			dev_err(mmc_dev(host->mmc),
 				"failed to allocate wp gpio\n");
-			goto out_irq;
+			goto err_wp_req;
 		}
 		tegra_gpio_enable(plat->wp_gpio);
 		gpio_direction_input(plat->wp_gpio);
@@ -179,7 +201,7 @@ static int tegra_sdhci_pltfm_init(struct sdhci_host *host,
 	if (IS_ERR(clk)) {
 		dev_err(mmc_dev(host->mmc), "clk err\n");
 		rc = PTR_ERR(clk);
-		goto out_wp;
+		goto err_clk_get;
 	}
 	clk_enable(clk);
 	pltfm_host->clk = clk;
@@ -189,38 +211,47 @@ static int tegra_sdhci_pltfm_init(struct sdhci_host *host,
 	if (plat->is_8bit)
 		host->mmc->caps |= MMC_CAP_8_BIT_DATA;
 
+	rc = sdhci_add_host(host);
+	if (rc)
+		goto err_add_host;
+
 	return 0;
 
-out_wp:
+err_add_host:
+	clk_disable(pltfm_host->clk);
+	clk_put(pltfm_host->clk);
+err_clk_get:
 	if (gpio_is_valid(plat->wp_gpio)) {
 		tegra_gpio_disable(plat->wp_gpio);
 		gpio_free(plat->wp_gpio);
 	}
-
-out_irq:
+err_wp_req:
 	if (gpio_is_valid(plat->cd_gpio))
 		free_irq(gpio_to_irq(plat->cd_gpio), host);
-out_cd:
+err_cd_irq_req:
 	if (gpio_is_valid(plat->cd_gpio)) {
 		tegra_gpio_disable(plat->cd_gpio);
 		gpio_free(plat->cd_gpio);
 	}
-
-out_power:
+err_cd_req:
 	if (gpio_is_valid(plat->power_gpio)) {
 		tegra_gpio_disable(plat->power_gpio);
 		gpio_free(plat->power_gpio);
 	}
-
-out:
+err_power_req:
+err_no_plat:
+	sdhci_pltfm_free(pdev);
 	return rc;
 }
 
-static void tegra_sdhci_pltfm_exit(struct sdhci_host *host)
+static int __devexit sdhci_tegra_remove(struct platform_device *pdev)
 {
+	struct sdhci_host *host = platform_get_drvdata(pdev);
 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
-	struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc));
-	struct tegra_sdhci_platform_data *plat;
+ 	struct tegra_sdhci_platform_data *plat;
+	int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
+
+	sdhci_remove_host(host, dead);
 
 	plat = pdev->dev.platform_data;
 
@@ -242,22 +273,37 @@ static void tegra_sdhci_pltfm_exit(struct sdhci_host *host)
 
 	clk_disable(pltfm_host->clk);
 	clk_put(pltfm_host->clk);
+
+	sdhci_pltfm_free(pdev);
+
+	return 0;
 }
 
-static struct sdhci_ops tegra_sdhci_ops = {
-	.get_ro     = tegra_sdhci_get_ro,
-	.read_l     = tegra_sdhci_readl,
-	.read_w     = tegra_sdhci_readw,
-	.write_l    = tegra_sdhci_writel,
-	.platform_8bit_width = tegra_sdhci_8bit,
+static struct platform_driver sdhci_tegra_driver = {
+	.driver		= {
+		.name	= "sdhci-tegra",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= sdhci_tegra_probe,
+	.remove		= __devexit_p(sdhci_tegra_remove),
+#ifdef CONFIG_PM
+	.suspend	= sdhci_pltfm_suspend,
+	.resume		= sdhci_pltfm_resume,
+#endif
 };
 
-struct sdhci_pltfm_data sdhci_tegra_pdata = {
-	.quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
-		  SDHCI_QUIRK_SINGLE_POWER_WRITE |
-		  SDHCI_QUIRK_NO_HISPD_BIT |
-		  SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC,
-	.ops  = &tegra_sdhci_ops,
-	.init = tegra_sdhci_pltfm_init,
-	.exit = tegra_sdhci_pltfm_exit,
-};
+static int __init sdhci_tegra_init(void)
+{
+	return platform_driver_register(&sdhci_tegra_driver);
+}
+module_init(sdhci_tegra_init);
+ 
+static void __exit sdhci_tegra_exit(void)
+{
+	platform_driver_unregister(&sdhci_tegra_driver);
+}
+module_exit(sdhci_tegra_exit);
+
+MODULE_DESCRIPTION("SDHCI driver for Tegra");
+MODULE_AUTHOR(" Google, Inc.");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/mmc/sdhci-pltfm.h b/include/linux/mmc/sdhci-pltfm.h
index 548d59d..f1c2ac3 100644
--- a/include/linux/mmc/sdhci-pltfm.h
+++ b/include/linux/mmc/sdhci-pltfm.h
@@ -15,21 +15,15 @@
 #define _SDHCI_PLTFM_H
 
 struct sdhci_ops;
-struct sdhci_host;
 
 /**
  * struct sdhci_pltfm_data - SDHCI platform-specific information & hooks
  * @ops: optional pointer to the platform-provided SDHCI ops
  * @quirks: optional SDHCI quirks
- * @init: optional hook that is called during device probe, before the
- *        driver tries to access any SDHCI registers
- * @exit: optional hook that is called during device removal
  */
 struct sdhci_pltfm_data {
 	struct sdhci_ops *ops;
 	unsigned int quirks;
-	int (*init)(struct sdhci_host *host, struct sdhci_pltfm_data *pdata);
-	void (*exit)(struct sdhci_host *host);
 };
 
 #endif /* _SDHCI_PLTFM_H */
-- 
1.7.4.1

^ permalink raw reply related

* [PATCH v2 0/7] Consolidate sdhci pltfm & OF drivers and get them self registered
From: Shawn Guo @ 2011-05-05 13:22 UTC (permalink / raw)
  To: linux-mmc
  Cc: Chris Ball, sameo, Arnd Bergmann, patches, devicetree-discuss,
	Saeed Bishara, Xiaobo Xie, kernel, Mike Rapoport, Olof Johansson,
	Anton Vorontsov, linuxppc-dev, Albert Herranz, linux-arm-kernel

Here are what the patch set does.

* Remove .probe and .remove hooks from sdhci-pltfm.c and make it be
  a pure common helper function providers.
* Add .probe and .remove hooks for sdhci pltfm drivers sdhci-cns3xxx,
  sdhci-dove, sdhci-tegra, and sdhci-esdhc-imx to make them self
  registered with calling helper functions created above.
* Migrate the use of sdhci_of_host and sdhci_of_data to
  sdhci_pltfm_host and sdhci_pltfm_data, so that OF version host and
  data structure works can be saved, and pltfm version works for both
  cases.
* Add OF common helper stuff into sdhci-pltfm.c, and make OF version
  sdhci drivers sdhci-of-esdhc and sdhci-of-hlwd become self
  registered as well, so that sdhci-of-core.c and sdhci-of.h can be
  removed.
* Consolidate the OF and pltfm esdhc drivers into one with sharing
  the same pair of .probe and .remove hooks.
* Eliminate include/linux/mmc/sdhci-pltfm.h with moving stuff into
  drivers/mmc/host/sdhci-pltfm.h.

And the benefits we gain from the changes are:

* Get the sdhci device driver follow the Linux trend that driver
  makes the registration by its own.
* sdhci-pltfm.c becomes simple and clean as it only has common helper
  stuff there now.
* All sdhci device specific things are going back its own driver.
* The dt and non-dt drivers are consolidated to use the same pair of
  .probe and .remove hooks.
* SDHCI driver for Freescale eSDHC controller found on both MPCxxx
  and i.MX platforms is consolidated to use the same one .probe
  function.

It was only tested on i.mx51 babbage board, all other targets were
build tested.  Tested-by, Reviwed-by, and Acked-by are much
appreciated.

I attempt to get patch #1 ~ #6 go through Chris' tree, while the #7
through Sascha's tree.

Regards,
Shawn

Changes since v1:
 * Rebase on cjb's mmc-next tree
 * Introduce helper function pair sdhci_pltfm_register and
   sdhci_pltfm_unregister
 * Eliminate variable 'scratch' in .remove hook to make the code
   look simple
 * Return ERR_PTR in sdhci_pltfm_init and use IS_ERR/PTR_ERR to check
   return value in .probe hooks
 * Correct MODULE_AUTHOR statement
 * Split esdhc conlidation patch to ease reviewing

Shawn Guo (7):
      mmc: sdhci: make sdhci-pltfm device drivers self registered
      mmc: sdhci: eliminate sdhci_of_host and sdhci_of_data
      mmc: sdhci: make sdhci-of device drivers self registered
      sdhci: rename sdhci-esdhc-imx.c to sdhci-esdhc.c
      mmc: sdhci: consolidate sdhci-of-esdhc and sdhci-esdhc-imx
      mmc: sdhci: merge two sdhci-pltfm.h into one
      ARM: mxc: remove esdhc.h and use the public one

 .../plat-mxc/devices/platform-sdhci-esdhc-imx.c    |    1 -
 arch/arm/plat-mxc/include/mach/devices-common.h    |    2 +-
 drivers/mmc/host/Kconfig                           |   77 ++--
 drivers/mmc/host/Makefile                          |   17 +-
 drivers/mmc/host/sdhci-cns3xxx.c                   |   43 ++-
 drivers/mmc/host/sdhci-dove.c                      |   42 ++-
 drivers/mmc/host/sdhci-esdhc-imx.c                 |  331 -----------
 drivers/mmc/host/sdhci-esdhc.c                     |  580 ++++++++++++++++++++
 drivers/mmc/host/sdhci-esdhc.h                     |   81 ---
 drivers/mmc/host/sdhci-of-core.c                   |  250 ---------
 drivers/mmc/host/sdhci-of-esdhc.c                  |   91 ---
 drivers/mmc/host/sdhci-of-hlwd.c                   |   66 ++-
 drivers/mmc/host/sdhci-of.h                        |   42 --
 drivers/mmc/host/sdhci-pltfm.c                     |  259 +++++----
 drivers/mmc/host/sdhci-pltfm.h                     |   39 ++-
 drivers/mmc/host/sdhci-tegra.c                     |  118 +++--
 include/linux/mmc/esdhc.h                          |   27 +
 include/linux/mmc/sdhci-pltfm.h                    |   35 --
 18 files changed, 1048 insertions(+), 1053 deletions(-)

^ permalink raw reply

* Re: [RFC][PATCH] powerpc: respect how command line nr_cpus is set
From: Kumar Gala @ 2011-05-05 11:38 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev
In-Reply-To: <1304562302.2513.418.camel@pasglop>


On May 4, 2011, at 9:25 PM, Benjamin Herrenschmidt wrote:

> On Wed, 2011-05-04 at 15:17 -0500, Kumar Gala wrote:
>> We should utilize nr_cpus as the max # of CPUs that we can have =
present
>> instead of NR_CPUS.  This way we actually respect how nr_cpus is set =
on
>> the command line rather than ignoring it.
>>=20
>> Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
>> ---
>> I think this is what we should be doing, but would like someone else =
to take
>> a look.
>=20
> The main question I have is should max_cpus absolutely limit the =
number
> of possible CPUs or should it limit the number that get automatically
> onlined at boot, potentially letting us bring the rest online later on =
?
>=20
> Cheers,
> Ben.

=46rom Documentation/kernel-parameters.txt:

        nr_cpus=3D        [SMP] Maximum number of processors that an SMP =
kernel
                        could support.  nr_cpus=3Dn : n >=3D 1 limits =
the kernel to
                        supporting 'n' processors. Later in runtime you =
can not
                        use hotplug cpu feature to put more cpu back to =
online.
                        just like you compile the kernel NR_CPUS=3Dn

Which makes me think we should have max_cpus be an absolute limit.

- k=

^ permalink raw reply

* Re: [PATCH 0/6] General device tree irq domain infrastructure
From: Thomas Gleixner @ 2011-05-05  8:37 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: Michal Simek, Sebastian Andrzej Siewior, x86, linux-kernel,
	Ralf Baechle, hpa, Dirk Brandewie, linuxppc-dev,
	devicetree-discuss
In-Reply-To: <1304555953.2513.390.camel@pasglop>

On Thu, 5 May 2011, Benjamin Herrenschmidt wrote:
> > As for the mapping, I agree that the functionality is generally
> > useful, I'm just not fond of the current implementation.  I think it
> > is more complex than it needs to be and I'm not excited about bring it
> > over to the other architectures as-is.
>
> Nobody cares about the current implementation. What is important is
> indeed the functionality. The basic thing I think everybody agrees is
> that you need to extend the irq_desc (or data, whatever tglx prefers)
> with two bits of information: Some identifier of the domain and some
> identifier of the interrupt number within that domain.

irq_data because that's what is handed into the callbacks and you
probably want to have the HW number there.
 
> In addition, PIC code will need a way to perform efficient reverse
> mapping. You may decide that for simple IRQ controllers that handle a
> small linear range of interrupts, it's kosher to simply reserve a linear
> range of descriptors and use a simple offset, I'm find with that now
> that we no longer live in a world constrained by NR_IRQ.
> 
> But the need for the radix tree remains for things that have massively
> large potential HW numbers such as we have on powerpc.
> 
> > For the majority of fixed hw interrupt controllers it is overkill.
> > There is no need for a map table when all the irq descs (<=32 of them)
> > get allocated when the irq controller is instantiated and the mapping
> > consists of 'virq = hw_irq + virq_base'.  For instance, with the arm
> > irq controllers, it's be more than sufficient to use irq_alloc_descs
> > to obtain a range of irq numbers and then a simple of_irq_domain
> > registration to handle the parsing.
> 
> That's true if and only if you make NR_IRQ a non issue and if you accept
> the general wastage due to unused interrupts.
> 
> The main problem has always been that hard limit which made me chose a
> more efficient mechanisms. Take a mac with 2 cascaded MPICs with 256
> sources each which are mostly never used. I would need an NR_IRQs of 512
> with your scheme (plus 16 because I do want to continue avoiding the
> "ISA" numbers), which is a waste of space, even with SPARSE_IRQ.
> 
> Now I hope eventually NR_IRQ will go away and we'll have a more
> efficient mechanism to allocate descriptors and so it will become less
> of an issue.

Well, NR_IRQS in the sparse case is irrelevant already and I'm looking
into a way to remove the !SPARSE code completely.

One thing we can do to avoid allocating 512 irq descriptors for the
MAC case is to reserve the space and only allocate the descriptors you
really need to be operational.

> > For the cases where an interrupt controller isn't able to alloc all
> > the irq descs at once, like for MSI, then yes the LINEAR and RADIX
> > mappings are important.  What bothers me though is the way irq_host
> > needs to use unions and the ->revmap_type value to implement multiple
> > behaviours into a single type.  That's the sort of thing that can be
> > broken out into a library and instantiated only by the interrupt
> > controllers that actually need it.
> 
> But that's what it is really. You'll notice that on the fast path the
> interrupt controller code calls directly into the "right" type of revmap
> routine. You may want to refactor things a bit if you want, but the
> union served me well simply because I didnt have to bother doing lots of
> different alloc_bootmem back then. Nowadays, kmalloc is available much
> earlier so it might have become a non issue too.
> 
> >   Similarly, it bothers me that that
> > radix mapping makes up a significant portion of the code, yet it has
> > only one user. 
> 
> "significant" ? Seriously ? Like 3 function calls ? It's nothing. We use
> an existing radix tree facility, and the amount of code in our irq.c is
> actually very small.
> 
> Originally it was living in xics in fact, but I moved it out
> specifically because I wanted a common interface to remapping, so for
> example, I can expose the linux -> hw mapping in debugfs generically,
> among others.

And there is another reverse mapping implementation in the superH
code.

> >  I'd be happier if each kind of mapping had its own
> > structure that embedded a generic irq_host/irq_domain with mapping
> > specific ops populated to manipulate it.
> 
> Whatever, that's just plumbing, I don't care either way, that doesn't
> change the fact that the concept of domain doesn't have much to do with
> OF :-)
> 
> > Regardless, the immediate priority is to implement a mapper that will
> > work for all architectures (or at least everything but powerpc and
> > sparc).
> 
> I oppose the implementation of a new mapper that doesn't include
> powerpc, that would be stupid. Either re-use ours or implement a new one
> that encompass our needs. I can't talk for sparc but I wouldn't be
> surprised if David thought about the same lines.
> 
> >   x86 has already implemented a skeleton irq_domain because
> > there wasn't any common code for it to use.  ARM also needs the
> > functionality immediately, and I don't want to see yet another
> > arch-specific implementation.  I'd like to get the framework in place
> > now, and grafting in mapping features as follow on patches.  That way
> > the new DT users aren't blocked while waiting for us to hammer down
> > the features that the other architectures don't need yet.
> 
> But the mapping code exist already. It returns a device-node as the
> interrupt controller. What you then need is to establish the
> relationship between that device-node and a domain in linux, and have
> code to decode the content of the interrupts property.
> 
> So you need the concept of domain first, generic, and -then- you can
> start adding a way to bind it to OF.

Ack.
 
Thanks,

	tglx

^ permalink raw reply

* linux-next: build failure after merge of the final tree (powerpc tree related)
From: Stephen Rothwell @ 2011-05-05  3:41 UTC (permalink / raw)
  To: Benjamin Herrenschmidt, Paul Mackerras, linuxppc-dev
  Cc: Michael Ellerman, Tseng-Hui (Frank) Lin, Sonny Rao, linux-kernel,
	linux-next, Anton Blanchard

Hi all,

After merging the final tree, today's linux-next build (powerpc
allyesconfig) failed like this:

arch/powerpc/mm/mmu_context_hash64.c: In function 'init_new_context':
arch/powerpc/mm/mmu_context_hash64.c:282: error: 'NO_CONTEXT' undeclared (first use in this function)

Presumably caused by commit 851d2e2fe8db ("powerpc: Add Initiate
Coprocessor Store Word (icswx) support") interacting with commit
5e8e7b404ac9 ("powerpc/mm: Standardise on MMU_NO_CONTEXT").

I added the below patch for today.
-- 
Cheers,
Stephen Rothwell                    sfr@canb.auug.org.au

From: Stephen Rothwell <sfr@canb.auug.org.au>
Date: Thu, 5 May 2011 13:32:02 +1000
Subject: [PATCH] powerpc: fix up mismerge in mmu_context_hash64.c

NO_CONTEXT was changed to MMU_NO_CONTEXT.

Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
---
 arch/powerpc/mm/mmu_context_hash64.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/arch/powerpc/mm/mmu_context_hash64.c b/arch/powerpc/mm/mmu_context_hash64.c
index c517815..3bafc3d 100644
--- a/arch/powerpc/mm/mmu_context_hash64.c
+++ b/arch/powerpc/mm/mmu_context_hash64.c
@@ -279,7 +279,7 @@ int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
 	if (!mm->context.cop_lockp) {
 		__destroy_context(index);
 		subpage_prot_free(mm);
-		mm->context.id = NO_CONTEXT;
+		mm->context.id = MMU_NO_CONTEXT;
 		return -ENOMEM;
 	}
 	spin_lock_init(mm->context.cop_lockp);
-- 
1.7.4.4

^ permalink raw reply related

* Re: [RFC][PATCH] powerpc: respect how command line nr_cpus is set
From: Benjamin Herrenschmidt @ 2011-05-05  2:25 UTC (permalink / raw)
  To: Kumar Gala; +Cc: linuxppc-dev
In-Reply-To: <1304540257-19831-1-git-send-email-galak@kernel.crashing.org>

On Wed, 2011-05-04 at 15:17 -0500, Kumar Gala wrote:
> We should utilize nr_cpus as the max # of CPUs that we can have present
> instead of NR_CPUS.  This way we actually respect how nr_cpus is set on
> the command line rather than ignoring it.
> 
> Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
> ---
> I think this is what we should be doing, but would like someone else to take
> a look.

The main question I have is should max_cpus absolutely limit the number
of possible CPUs or should it limit the number that get automatically
onlined at boot, potentially letting us bring the rest online later on ?

Cheers,
Ben.

> - k
> 
>  arch/powerpc/kernel/setup-common.c |   10 +++++-----
>  1 files changed, 5 insertions(+), 5 deletions(-)
> 
> diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c
> index 21f30cb..fedf813 100644
> --- a/arch/powerpc/kernel/setup-common.c
> +++ b/arch/powerpc/kernel/setup-common.c
> @@ -424,7 +424,7 @@ void __init smp_setup_cpu_maps(void)
>  
>  	DBG("smp_setup_cpu_maps()\n");
>  
> -	while ((dn = of_find_node_by_type(dn, "cpu")) && cpu < NR_CPUS) {
> +	while ((dn = of_find_node_by_type(dn, "cpu")) && cpu < nr_cpu_ids) {
>  		const int *intserv;
>  		int j, len;
>  
> @@ -443,7 +443,7 @@ void __init smp_setup_cpu_maps(void)
>  				intserv = &cpu;	/* assume logical == phys */
>  		}
>  
> -		for (j = 0; j < nthreads && cpu < NR_CPUS; j++) {
> +		for (j = 0; j < nthreads && cpu < nr_cpu_ids; j++) {
>  			DBG("    thread %d -> cpu %d (hard id %d)\n",
>  			    j, cpu, intserv[j]);
>  			set_cpu_present(cpu, true);
> @@ -483,12 +483,12 @@ void __init smp_setup_cpu_maps(void)
>  		if (cpu_has_feature(CPU_FTR_SMT))
>  			maxcpus *= nthreads;
>  
> -		if (maxcpus > NR_CPUS) {
> +		if (maxcpus > nr_cpu_ids) {
>  			printk(KERN_WARNING
>  			       "Partition configured for %d cpus, "
>  			       "operating system maximum is %d.\n",
> -			       maxcpus, NR_CPUS);
> -			maxcpus = NR_CPUS;
> +			       maxcpus, nr_cpu_ids);
> +			maxcpus = nr_cpu_ids;
>  		} else
>  			printk(KERN_INFO "Partition configured for %d cpus.\n",
>  			       maxcpus);

^ permalink raw reply

* Re: [PATCH 4/6] dt: generalize irq_of_create_mapping()
From: Benjamin Herrenschmidt @ 2011-05-05  0:43 UTC (permalink / raw)
  To: Grant Likely
  Cc: Michal Simek, Sebastian Andrzej Siewior, x86, linux-kernel,
	Ralf Baechle, hpa, Dirk Brandewie, Thomas Gleixner, linuxppc-dev,
	devicetree-discuss
In-Reply-To: <20110504160502.GC3317@ponder.secretlab.ca>

On Wed, 2011-05-04 at 10:05 -0600, Grant Likely wrote:
> > I think you are going the wrong way around.
> > 
> > First thing first, is to make the irq domain / mapping API generic
> > without the OF bits.
> > 
> > IE. move the IRQ domain generically, get rid of irq_map by putting
> the
> > domain ptr & hw numbers in the irq desc/data etc...
> > 
> > Then you can move over the OF specific bits which are optional and
> > orthogonal to a large extent.
> 
> As discussed in my other reply, I disagree.  There isn't an immediate
> need for the mapping interface in common code.  It would be useful,
> sure, for some interrupt controllers, but for many of them
> irq_alloc_descs() and an irq_base value is all the functionality that
> is needed, and irq_host doesn't gain anything.

No but the concept of domain is a pre-requisite. Even if it's an opaque
data structure. And I don't want to have it be some "of" specific thing.

> The OF translation on the other hand is needed immediately by several
> architectures and are very much non-optional in that regard.

But it relies on having an underlying mapping. I don't see how you can
do one without the other, even if your mapping in effect is just an
offset.

And it is -not- related to OF.

Whether you obtain that your interrupt you are interested it is
interrupt 5 of your PIC "foo" via the device-tree or any other way (an
arch quirk for example), you need the mechanism to associate them
together, whether it's a simple offset as you propose (I'm ok with that
for simple things, I just didn't think it was the right approach for
powerpc but it's perfectly valid as an option generically) or a more
complex radix-tree style mapping.

Thus sort out the mapping interfaces first. _Then_ layout the
device-tree bits on top.

The basic parsing for the DT is already there. It will return a parent
node and a __be32* pointer.

Cheers,
Ben.

^ permalink raw reply

* Re: [PATCH 2/6] powerpc: make irq_{alloc, free}_virt private and remove count argument
From: Benjamin Herrenschmidt @ 2011-05-05  0:39 UTC (permalink / raw)
  To: Grant Likely
  Cc: Michal Simek, Sebastian Andrzej Siewior, x86, linux-kernel,
	Ralf Baechle, hpa, Dirk Brandewie, Thomas Gleixner, linuxppc-dev,
	devicetree-discuss
In-Reply-To: <20110504155905.GB3317@ponder.secretlab.ca>

On Wed, 2011-05-04 at 09:59 -0600, Grant Likely wrote:
> 
> Heh, I wondered about that, but there hasn't been any users for at
> least 5 years (as evidenced by commit e12514650b, "Fix loop logic in
> irq_alloc_virt()") so it was looking pretty dead, and it made the
> patch to switch to using irq_alloc_desc*() quite a bit simpler if it
> was removed.  :-)
> 
> I'm not particularly attached to this patch, so I can drop it from the
> series. 

Well, Willy recently added support for the MSI block allocation so ...

Cheers,
Ben.

^ permalink raw reply

* Re: [PATCH 0/6] General device tree irq domain infrastructure
From: Benjamin Herrenschmidt @ 2011-05-05  0:39 UTC (permalink / raw)
  To: Grant Likely
  Cc: Michal Simek, Sebastian Andrzej Siewior, x86, linux-kernel,
	Ralf Baechle, hpa, Dirk Brandewie, Thomas Gleixner, linuxppc-dev,
	devicetree-discuss
In-Reply-To: <20110504155227.GA3317@ponder.secretlab.ca>


> I completely agree that irq domains are a generically useful feature
> for architectures, and it should be made available.  I also completely
> agree that it is orthogonal to device tree translations, which in a
> large part is why I've structured this series and the new code the
> way I have.
> 
> In this series I'm specifically addressing device tree translation,
> which is the one bit that is DT specific, and is important regardless
> of the backend translation mechanism.  In fact, the more I looked at
> it, the more it seems that the DT api really is orthogonal to the
> backend irq mapping and I don't think that the way irq_host ties them
> together is necessarily the best way to do it.  Many of the interrupt
> controllers which need to gain dt irq parsing have already been
> converted to using the irq_alloc_desc*() apis and have all the mapping
> mechanism they need, but lack a method of exposing it for DT
> translation.

But irq_alloc_desc() is purely about allocating the linux side irq
descriptors. Nothing to do with HW numbers here.

You still need a mapping mechanism, regardless of the device-tree, to
map those linux number to your HW numbers.

This is simple and eventually even 1:1 on things like x86, but the
minute you start having cascaded IRQ controllers, multiple IRQ domains,
and/or very large HW numbers that encode node IDs etc... this falls
appart.

And this is still completely orthogonal to the device-tree. 

Mapping is the important functionality. Whatever the actual allocator is
is indeed irrelevant.

> As for the mapping, I agree that the functionality is generally
> useful, I'm just not fond of the current implementation.  I think it
> is more complex than it needs to be and I'm not excited about bring it
> over to the other architectures as-is.

Nobody cares about the current implementation. What is important is
indeed the functionality. The basic thing I think everybody agrees is
that you need to extend the irq_desc (or data, whatever tglx prefers)
with two bits of information: Some identifier of the domain and some
identifier of the interrupt number within that domain.

In addition, PIC code will need a way to perform efficient reverse
mapping. You may decide that for simple IRQ controllers that handle a
small linear range of interrupts, it's kosher to simply reserve a linear
range of descriptors and use a simple offset, I'm find with that now
that we no longer live in a world constrained by NR_IRQ.

But the need for the radix tree remains for things that have massively
large potential HW numbers such as we have on powerpc.

> For the majority of fixed hw interrupt controllers it is overkill.
> There is no need for a map table when all the irq descs (<=32 of them)
> get allocated when the irq controller is instantiated and the mapping
> consists of 'virq = hw_irq + virq_base'.  For instance, with the arm
> irq controllers, it's be more than sufficient to use irq_alloc_descs
> to obtain a range of irq numbers and then a simple of_irq_domain
> registration to handle the parsing.

That's true if and only if you make NR_IRQ a non issue and if you accept
the general wastage due to unused interrupts.

The main problem has always been that hard limit which made me chose a
more efficient mechanisms. Take a mac with 2 cascaded MPICs with 256
sources each which are mostly never used. I would need an NR_IRQs of 512
with your scheme (plus 16 because I do want to continue avoiding the
"ISA" numbers), which is a waste of space, even with SPARSE_IRQ.

Now I hope eventually NR_IRQ will go away and we'll have a more
efficient mechanism to allocate descriptors and so it will become less
of an issue.

> For the cases where an interrupt controller isn't able to alloc all
> the irq descs at once, like for MSI, then yes the LINEAR and RADIX
> mappings are important.  What bothers me though is the way irq_host
> needs to use unions and the ->revmap_type value to implement multiple
> behaviours into a single type.  That's the sort of thing that can be
> broken out into a library and instantiated only by the interrupt
> controllers that actually need it.

But that's what it is really. You'll notice that on the fast path the
interrupt controller code calls directly into the "right" type of revmap
routine. You may want to refactor things a bit if you want, but the
union served me well simply because I didnt have to bother doing lots of
different alloc_bootmem back then. Nowadays, kmalloc is available much
earlier so it might have become a non issue too.

>   Similarly, it bothers me that that
> radix mapping makes up a significant portion of the code, yet it has
> only one user. 

"significant" ? Seriously ? Like 3 function calls ? It's nothing. We use
an existing radix tree facility, and the amount of code in our irq.c is
actually very small.

Originally it was living in xics in fact, but I moved it out
specifically because I wanted a common interface to remapping, so for
example, I can expose the linux -> hw mapping in debugfs generically,
among others.

>  I'd be happier if each kind of mapping had its own
> structure that embedded a generic irq_host/irq_domain with mapping
> specific ops populated to manipulate it.

Whatever, that's just plumbing, I don't care either way, that doesn't
change the fact that the concept of domain doesn't have much to do with
OF :-)

> Regardless, the immediate priority is to implement a mapper that will
> work for all architectures (or at least everything but powerpc and
> sparc).

I oppose the implementation of a new mapper that doesn't include
powerpc, that would be stupid. Either re-use ours or implement a new one
that encompass our needs. I can't talk for sparc but I wouldn't be
surprised if David thought about the same lines.

>   x86 has already implemented a skeleton irq_domain because
> there wasn't any common code for it to use.  ARM also needs the
> functionality immediately, and I don't want to see yet another
> arch-specific implementation.  I'd like to get the framework in place
> now, and grafting in mapping features as follow on patches.  That way
> the new DT users aren't blocked while waiting for us to hammer down
> the features that the other architectures don't need yet.

But the mapping code exist already. It returns a device-node as the
interrupt controller. What you then need is to establish the
relationship between that device-node and a domain in linux, and have
code to decode the content of the interrupts property.

So you need the concept of domain first, generic, and -then- you can
start adding a way to bind it to OF.

> What I /could/ have done I suppose was called it 'struct irq_domain'
> as you suggest, and allowed each translation mechanism to define its
> own match/map pair of routines, with device tree being the only one
> actually implemented at this point.  Yes, I understand that the
> core code treats the controller pointer as an anonymous cookie, but
> the api is still very device tree centric, and I'm not convinced that
> the assumption that all firmware irq representations will be an array
> of u32 values is going to hold up.

How so ?

>   I'd rather state upfront that the
> device tree translation really is device tree and let translations for
> other representation have the option of defining their own API.
> 
> However, that is not a strong objection, and if Thomas agrees with you
> then I'm okay with renaming of_irq_domain to irq_domain and moving it
> to kernel/irq/irqdomain.c.  The mapping functionality I think should
> stay out for now until we come to agreement on how it should look, and
> I'll fix up any users if the API needs to change at a later date.

But I think the mapping functionality is what needs to be sorted first.

Cheers
Ben.

> g.
> 
> 
> 
> > 
> > > PowerPC and x86 have been converted to use of_irq_domain.  MIPS and
> > > Microblaze have it enabled, but nothing actually registers domains
> > > yet, so a workaround is in place to preserve the current behaviour
> > > until it is fixed.
> > > 
> > > I'd really like to get patches 1-4 merged into 2.6.40.  Please test.
> > > I'm also running through build testing here, and when it's complete
> > > I'll push it out to a 'devicetree/irq-domain' branch on
> > > git://git.secretlab.ca/git/linux-2.6
> > > 
> > > It needs testing.  I've booted it on a powerpc board here without any
> > > apparent regressions, but that isn't a very big sample.  I've also
> > > build tested on everything I think is affected.
> > > 
> > > I'd also like to get it into linux-next.  Ben, if things checkout okay
> > > over the next few days, would you be okay with me adding it to
> > > linux-next, say around Wednesday next week?  As for merging, I think
> > > this should probably go via your powerpc tree since the that's where
> > > the bulk of the changes are, but I'm open to other suggestions).
> > > 
> > > Patches 5 & 6 are follow-on cleanup work to powerpc, but patch 6 is
> > > RFC only since there is a locking problem that I haven't fixed yet.
> > > 
> > > Cheers,
> > > g.
> > > 
> > > ---
> > > 
> > > Grant Likely (6):
> > >       powerpc: stop exporting irq_map
> > >       powerpc: make irq_{alloc,free}_virt private and remove count argument
> > >       powerpc: Make struct irq_host semi-private by moving into irqhost.h
> > >       dt: generalize of_irq_parse_and_map()
> > >       powerpc: move irq_alloc_descs_at() call into irq_alloc_virt()
> > >       powerpc: use irq_alloc_desc() to manage irq allocations
> > > 
> > > 
> > >  arch/microblaze/kernel/irq.c                     |    7 -
> > >  arch/microblaze/kernel/setup.c                   |    2 
> > >  arch/mips/kernel/prom.c                          |   14 -
> > >  arch/powerpc/include/asm/irq.h                   |   88 +------
> > >  arch/powerpc/include/asm/irqhost.h               |   27 ++
> > >  arch/powerpc/kernel/irq.c                        |  260 ++++++++++++----------
> > >  arch/powerpc/platforms/512x/mpc5121_ads_cpld.c   |    5 
> > >  arch/powerpc/platforms/52xx/media5200.c          |    5 
> > >  arch/powerpc/platforms/52xx/mpc52xx_gpt.c        |    1 
> > >  arch/powerpc/platforms/52xx/mpc52xx_pic.c        |   80 +------
> > >  arch/powerpc/platforms/82xx/pq2ads-pci-pic.c     |    5 
> > >  arch/powerpc/platforms/85xx/socrates_fpga_pic.c  |   26 +-
> > >  arch/powerpc/platforms/86xx/gef_pic.c            |   10 -
> > >  arch/powerpc/platforms/8xx/m8xx_setup.c          |    2 
> > >  arch/powerpc/platforms/cell/axon_msi.c           |   15 +
> > >  arch/powerpc/platforms/cell/spider-pic.c         |   19 +-
> > >  arch/powerpc/platforms/embedded6xx/flipper-pic.c |    9 -
> > >  arch/powerpc/platforms/embedded6xx/hlwd-pic.c    |    9 -
> > >  arch/powerpc/platforms/embedded6xx/wii.c         |    6 -
> > >  arch/powerpc/platforms/iseries/irq.c             |   10 -
> > >  arch/powerpc/platforms/powermac/pic.c            |   12 +
> > >  arch/powerpc/platforms/pseries/ras.c             |    4 
> > >  arch/powerpc/platforms/pseries/xics.c            |   14 +
> > >  arch/powerpc/sysdev/cpm1.c                       |    8 -
> > >  arch/powerpc/sysdev/cpm2_pic.c                   |   10 -
> > >  arch/powerpc/sysdev/fsl_msi.c                    |    3 
> > >  arch/powerpc/sysdev/i8259.c                      |    3 
> > >  arch/powerpc/sysdev/ipic.c                       |   19 +-
> > >  arch/powerpc/sysdev/mpc8xx_pic.c                 |   10 -
> > >  arch/powerpc/sysdev/mpc8xxx_gpio.c               |   13 +
> > >  arch/powerpc/sysdev/mpic.c                       |   33 +--
> > >  arch/powerpc/sysdev/mpic_msi.c                   |    3 
> > >  arch/powerpc/sysdev/mpic_pasemi_msi.c            |    5 
> > >  arch/powerpc/sysdev/mv64x60_pic.c                |   14 +
> > >  arch/powerpc/sysdev/qe_lib/qe_ic.c               |    9 -
> > >  arch/powerpc/sysdev/uic.c                        |   13 +
> > >  arch/powerpc/sysdev/xilinx_intc.c                |    9 -
> > >  arch/x86/include/asm/irq_controller.h            |   12 -
> > >  arch/x86/include/asm/prom.h                      |    1 
> > >  arch/x86/kernel/devicetree.c                     |   77 +------
> > >  drivers/of/irq.c                                 |  118 ++++++++++
> > >  include/linux/of_irq.h                           |   31 +++
> > >  42 files changed, 504 insertions(+), 517 deletions(-)
> > >  create mode 100644 arch/powerpc/include/asm/irqhost.h
> > >  delete mode 100644 arch/x86/include/asm/irq_controller.h
> > 
> > 
> --
> 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

* [PATCH 3/3] [repost] powerpc/eeh: Display eeh error location for bus and device
From: Richard A Lary @ 2011-05-04 22:57 UTC (permalink / raw)
  To: linuxppc-dev, Benjamin Herrenschmidt, antonb

From: Richard A Lary <rlary@linux.vnet.ibm.com>

  For adapters which have devices under a PCIe switch/bridge it is informative
  to display information for both the PCIe switch/bridge and the device on
  which the bus error was detected.

  rebased to powerpc-next

Signed-off-by: Richard A Lary <rlary@linux.vnet.ibm.com>
---
---
  arch/powerpc/platforms/pseries/eeh_driver.c |   22 	13 +	9 -	0 !
  1 file changed, 13 insertions(+), 9 deletions(-)

Index: b/arch/powerpc/platforms/pseries/eeh_driver.c
===================================================================
--- a/arch/powerpc/platforms/pseries/eeh_driver.c
+++ b/arch/powerpc/platforms/pseries/eeh_driver.c
@@ -328,7 +328,7 @@ struct pci_dn * handle_eeh_events (struc
  	struct pci_bus *frozen_bus;
  	int rc = 0;
  	enum pci_ers_result result = PCI_ERS_RESULT_NONE;
-	const char *location, *pci_str, *drv_str;
+	const char *location, *pci_str, *drv_str, *bus_pci_str, *bus_drv_str;

  	frozen_dn = find_device_pe(event->dn);
  	if (!frozen_dn) {
@@ -364,13 +364,8 @@ struct pci_dn * handle_eeh_events (struc
  	frozen_pdn = PCI_DN(frozen_dn);
  	frozen_pdn->eeh_freeze_count++;

-	if (frozen_pdn->pcidev) {
-		pci_str = pci_name (frozen_pdn->pcidev);
-		drv_str = pcid_name (frozen_pdn->pcidev);
-	} else {
-		pci_str = eeh_pci_name(event->dev);
-		drv_str = pcid_name (event->dev);
-	}
+	pci_str = eeh_pci_name(event->dev);
+	drv_str = pcid_name(event->dev);
  	
  	if (frozen_pdn->eeh_freeze_count > EEH_MAX_ALLOWED_FREEZES)
  		goto excess_failures;
@@ -378,8 +373,17 @@ struct pci_dn * handle_eeh_events (struc
  	printk(KERN_WARNING
  	   "EEH: This PCI device has failed %d times in the last hour:\n",
  		frozen_pdn->eeh_freeze_count);
+
+	if (frozen_pdn->pcidev) {
+		bus_pci_str = pci_name(frozen_pdn->pcidev);
+		bus_drv_str = pcid_name(frozen_pdn->pcidev);
+		printk(KERN_WARNING
+			"EEH: Bus location=%s driver=%s pci addr=%s\n",
+			location, bus_drv_str, bus_pci_str);
+	}
+
  	printk(KERN_WARNING
-		"EEH: location=%s driver=%s pci addr=%s\n",
+		"EEH: Device location=%s driver=%s pci addr=%s\n",
  		location, drv_str, pci_str);

  	/* Walk the various device drivers attached to this slot through

^ permalink raw reply

* [PATCH] powerpc: ensure dtl buffers do not cross 4k boundary
From: Nishanth Aravamudan @ 2011-05-04 22:54 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev, Paul Mackerras, Anton Blanchard

Future releases of fimrware will enforce a requirement that DTL buffers
do not cross a 4k boundary. Commit
127493d5dc73589cbe00ea5ec8357cc2a4c0d82a satisfies this requirement for
CONFIG_VIRT_CPU_ACCOUNTING=y kernels, but if !CONFIG_VIRT_CPU_ACCOUNTING
&& CONFIG_DTL=y, the current code will fail at dtl registration time.
Fix this by making the kmem cache from
127493d5dc73589cbe00ea5ec8357cc2a4c0d82a visible outside of setup.c and
using the same cache in both dtl.c and setup.c. This requires a bit of
reorganization to ensure ordering of the kmem cache and buffer
allocations.

Note: Since firmware now limits the size of the buffer, I made
dtl_buf_entries read-only in debugfs.

Tested with upcoming firmware with the 4 combinations of
CONFIG_VIRT_CPU_ACCOUNTING and CONFIG_DTL.

Signed-off-by: Nishanth Aravamudan <nacc@us.ibm.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Anton Blanchard <anton@samba.org>
Cc: linuxppc-dev@lists.ozlabs.org

---
Paul, why should `cat /sys/kernel/debug/powerpc/dtl/cpu-0` return
EINVAL? I understand why it does from the code as the page size (4k or
64k) is not evenly divisble by 48 bytes, but is that EINVAL just to
avoid dealing with short reads?

 arch/powerpc/include/asm/lppaca.h      |    2 ++
 arch/powerpc/platforms/pseries/dtl.c   |   20 +++++++++++---------
 arch/powerpc/platforms/pseries/setup.c |   31 ++++++++++++++++++++++---------
 3 files changed, 35 insertions(+), 18 deletions(-)

diff --git a/arch/powerpc/include/asm/lppaca.h b/arch/powerpc/include/asm/lppaca.h
index a077adc..e0298d2 100644
--- a/arch/powerpc/include/asm/lppaca.h
+++ b/arch/powerpc/include/asm/lppaca.h
@@ -210,6 +210,8 @@ struct dtl_entry {
 #define DISPATCH_LOG_BYTES	4096	/* bytes per cpu */
 #define N_DISPATCH_LOG		(DISPATCH_LOG_BYTES / sizeof(struct dtl_entry))
 
+extern struct kmem_cache *dtl_cache;
+
 /*
  * When CONFIG_VIRT_CPU_ACCOUNTING = y, the cpu accounting code controls
  * reading from the dispatch trace log.  If other code wants to consume
diff --git a/arch/powerpc/platforms/pseries/dtl.c b/arch/powerpc/platforms/pseries/dtl.c
index c371bc0..e919007 100644
--- a/arch/powerpc/platforms/pseries/dtl.c
+++ b/arch/powerpc/platforms/pseries/dtl.c
@@ -52,10 +52,10 @@ static u8 dtl_event_mask = 0x7;
 
 
 /*
- * Size of per-cpu log buffers. Default is just under 16 pages worth.
+ * Size of per-cpu log buffers. Firmware requires that the buffer does
+ * not cross a 4k boundary.
  */
-static int dtl_buf_entries = (16 * 85);
-
+static int dtl_buf_entries = N_DISPATCH_LOG;
 
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
 struct dtl_ring {
@@ -151,7 +151,7 @@ static int dtl_start(struct dtl *dtl)
 
 	/* Register our dtl buffer with the hypervisor. The HV expects the
 	 * buffer size to be passed in the second word of the buffer */
-	((u32 *)dtl->buf)[1] = dtl->buf_entries * sizeof(struct dtl_entry);
+	((u32 *)dtl->buf)[1] = DISPATCH_LOG_BYTES;
 
 	hwcpu = get_hard_smp_processor_id(dtl->cpu);
 	addr = __pa(dtl->buf);
@@ -196,13 +196,15 @@ static int dtl_enable(struct dtl *dtl)
 	long int rc;
 	struct dtl_entry *buf = NULL;
 
+	if (!dtl_cache)
+		return -ENOMEM;
+
 	/* only allow one reader */
 	if (dtl->buf)
 		return -EBUSY;
 
 	n_entries = dtl_buf_entries;
-	buf = kmalloc_node(n_entries * sizeof(struct dtl_entry),
-			GFP_KERNEL, cpu_to_node(dtl->cpu));
+	buf = kmem_cache_alloc_node(dtl_cache, GFP_KERNEL, cpu_to_node(dtl->cpu));
 	if (!buf) {
 		printk(KERN_WARNING "%s: buffer alloc failed for cpu %d\n",
 				__func__, dtl->cpu);
@@ -223,7 +225,7 @@ static int dtl_enable(struct dtl *dtl)
 	spin_unlock(&dtl->lock);
 
 	if (rc)
-		kfree(buf);
+		kmem_cache_free(dtl_cache, buf);
 	return rc;
 }
 
@@ -231,7 +233,7 @@ static void dtl_disable(struct dtl *dtl)
 {
 	spin_lock(&dtl->lock);
 	dtl_stop(dtl);
-	kfree(dtl->buf);
+	kmem_cache_free(dtl_cache, dtl->buf);
 	dtl->buf = NULL;
 	dtl->buf_entries = 0;
 	spin_unlock(&dtl->lock);
@@ -365,7 +367,7 @@ static int dtl_init(void)
 
 	event_mask_file = debugfs_create_x8("dtl_event_mask", 0600,
 				dtl_dir, &dtl_event_mask);
-	buf_entries_file = debugfs_create_u32("dtl_buf_entries", 0600,
+	buf_entries_file = debugfs_create_u32("dtl_buf_entries", 0400,
 				dtl_dir, &dtl_buf_entries);
 
 	if (!event_mask_file || !buf_entries_file) {
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
index 6c42cfd..b6ecd04 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -276,6 +276,8 @@ static struct notifier_block pci_dn_reconfig_nb = {
 	.notifier_call = pci_dn_reconfig_notifier,
 };
 
+struct kmem_cache *dtl_cache;
+
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
 /*
  * Allocate space for the dispatch trace log for all possible cpus
@@ -287,18 +289,12 @@ static int alloc_dispatch_logs(void)
 	int cpu, ret;
 	struct paca_struct *pp;
 	struct dtl_entry *dtl;
-	struct kmem_cache *dtl_cache;
 
 	if (!firmware_has_feature(FW_FEATURE_SPLPAR))
 		return 0;
 
-	dtl_cache = kmem_cache_create("dtl", DISPATCH_LOG_BYTES,
-						DISPATCH_LOG_BYTES, 0, NULL);
-	if (!dtl_cache) {
-		pr_warn("Failed to create dispatch trace log buffer cache\n");
-		pr_warn("Stolen time statistics will be unreliable\n");
+	if (!dtl_cache)
 		return 0;
-	}
 
 	for_each_possible_cpu(cpu) {
 		pp = &paca[cpu];
@@ -332,10 +328,27 @@ static int alloc_dispatch_logs(void)
 
 	return 0;
 }
-
-early_initcall(alloc_dispatch_logs);
+#else /* !CONFIG_VIRT_CPU_ACCOUNTING */
+static inline int alloc_dispatch_logs(void)
+{
+	return 0;
+}
 #endif /* CONFIG_VIRT_CPU_ACCOUNTING */
 
+static int alloc_dispatch_log_kmem_cache(void)
+{
+	dtl_cache = kmem_cache_create("dtl", DISPATCH_LOG_BYTES,
+						DISPATCH_LOG_BYTES, 0, NULL);
+	if (!dtl_cache) {
+		pr_warn("Failed to create dispatch trace log buffer cache\n");
+		pr_warn("Stolen time statistics will be unreliable\n");
+		return 0;
+	}
+
+	return alloc_dispatch_logs();
+}
+early_initcall(alloc_dispatch_log_kmem_cache);
+
 static void __init pSeries_setup_arch(void)
 {
 	/* Discover PIC type and setup ppc_md accordingly */
-- 
1.7.4.1

^ permalink raw reply related

* [RFC][PATCH] powerpc: respect how command line nr_cpus is set
From: Kumar Gala @ 2011-05-04 20:17 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev

We should utilize nr_cpus as the max # of CPUs that we can have present
instead of NR_CPUS.  This way we actually respect how nr_cpus is set on
the command line rather than ignoring it.

Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
---
I think this is what we should be doing, but would like someone else to take
a look.

- k

 arch/powerpc/kernel/setup-common.c |   10 +++++-----
 1 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c
index 21f30cb..fedf813 100644
--- a/arch/powerpc/kernel/setup-common.c
+++ b/arch/powerpc/kernel/setup-common.c
@@ -424,7 +424,7 @@ void __init smp_setup_cpu_maps(void)
 
 	DBG("smp_setup_cpu_maps()\n");
 
-	while ((dn = of_find_node_by_type(dn, "cpu")) && cpu < NR_CPUS) {
+	while ((dn = of_find_node_by_type(dn, "cpu")) && cpu < nr_cpu_ids) {
 		const int *intserv;
 		int j, len;
 
@@ -443,7 +443,7 @@ void __init smp_setup_cpu_maps(void)
 				intserv = &cpu;	/* assume logical == phys */
 		}
 
-		for (j = 0; j < nthreads && cpu < NR_CPUS; j++) {
+		for (j = 0; j < nthreads && cpu < nr_cpu_ids; j++) {
 			DBG("    thread %d -> cpu %d (hard id %d)\n",
 			    j, cpu, intserv[j]);
 			set_cpu_present(cpu, true);
@@ -483,12 +483,12 @@ void __init smp_setup_cpu_maps(void)
 		if (cpu_has_feature(CPU_FTR_SMT))
 			maxcpus *= nthreads;
 
-		if (maxcpus > NR_CPUS) {
+		if (maxcpus > nr_cpu_ids) {
 			printk(KERN_WARNING
 			       "Partition configured for %d cpus, "
 			       "operating system maximum is %d.\n",
-			       maxcpus, NR_CPUS);
-			maxcpus = NR_CPUS;
+			       maxcpus, nr_cpu_ids);
+			maxcpus = nr_cpu_ids;
 		} else
 			printk(KERN_INFO "Partition configured for %d cpus.\n",
 			       maxcpus);
-- 
1.7.3.4

^ permalink raw reply related

* Re: [PATCH] atomic: add *_dec_not_zero
From: Matt Turner @ 2011-05-04 18:13 UTC (permalink / raw)
  To: Sven Eckelmann
  Cc: linux-arch, linux-mips, linux-m32r, linux-ia64, linux-parisc,
	linux-cris-kernel, linux-s390, linux-sh, x86, linux-kernel,
	Chris Metcalf, David Howells, linux-m68k, linux-am33-list,
	linux-alpha, sparclinux, uclinux-dist-devel, linuxppc-dev,
	linux-arm-kernel
In-Reply-To: <1304458235-28473-1-git-send-email-sven@narfation.org>

On Tue, May 3, 2011 at 5:30 PM, Sven Eckelmann <sven@narfation.org> wrote:
> diff --git a/arch/alpha/include/asm/atomic.h b/arch/alpha/include/asm/ato=
mic.h
> index e756d04..7e9434e 100644
> --- a/arch/alpha/include/asm/atomic.h
> +++ b/arch/alpha/include/asm/atomic.h
> @@ -200,6 +200,7 @@ static __inline__ int atomic_add_unless(atomic_t *v, =
int a, int u)
> =A0}
>
> =A0#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
> +#define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0)
>
> =A0/**
> =A0* atomic64_add_unless - add unless the number is a given value
> @@ -226,6 +227,7 @@ static __inline__ int atomic64_add_unless(atomic64_t =
*v, long a, long u)
> =A0}
>
> =A0#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
> +#define atomic64_dec_not_zero(v) atomic64_add_unless((v), -1, 0)
>
> =A0#define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0)
> =A0#define atomic64_add_negative(a, v) (atomic64_add_return((a), (v)) < 0=
)
> diff --git a/arch/alpha/include/asm/local.h b/arch/alpha/include/asm/loca=
l.h
> index b9e3e33..09fb327 100644
> --- a/arch/alpha/include/asm/local.h
> +++ b/arch/alpha/include/asm/local.h
> @@ -79,6 +79,7 @@ static __inline__ long local_sub_return(long i, local_t=
 * l)
> =A0 =A0 =A0 =A0c !=3D (u); =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 \
> =A0})
> =A0#define local_inc_not_zero(l) local_add_unless((l), 1, 0)
> +#define local_dec_not_zero(l) local_add_unless((l), -1, 0)
>
> =A0#define local_add_negative(a, l) (local_add_return((a), (l)) < 0)
>

Acked-by: Matt Turner <mattst88@gmail.com> [alpha]

^ permalink raw reply

* Re: [PATCH] atomic: add *_dec_not_zero
From: Will Deacon @ 2011-05-04 17:27 UTC (permalink / raw)
  To: Sven Eckelmann
  Cc: linux-arch, linux-mips, linux-m68k, linux-m32r, linux-ia64,
	linux-cris-kernel, linux-parisc, linux-s390, linux-sh,
	linux-kernel, Chris Metcalf, David Howells, linux-am33-list,
	linux-alpha, sparclinux, uclinux-dist-devel, x86, linuxppc-dev,
	linux-arm-kernel
In-Reply-To: <1304458235-28473-1-git-send-email-sven@narfation.org>

On Tue, 2011-05-03 at 22:30 +0100, Sven Eckelmann wrote:
> Introduce an *_dec_not_zero operation.  Make this a special case of
> *_add_unless because batman-adv uses atomic_dec_not_zero in different
> places like re-broadcast queue or aggregation queue management. There
> are other non-final patches which may also want to use this macro.
> 
For the ARM changes:

Acked-by: Will Deacon <will.deacon@arm.com>

Cheers,

Will

^ permalink raw reply

* Re: [PATCH 4/6] dt: generalize irq_of_create_mapping()
From: Grant Likely @ 2011-05-04 16:05 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: Michal Simek, Sebastian Andrzej Siewior, x86, linux-kernel,
	Ralf Baechle, hpa, Dirk Brandewie, Thomas Gleixner, linuxppc-dev,
	devicetree-discuss
In-Reply-To: <1304387422.2513.301.camel@pasglop>

On Tue, May 03, 2011 at 11:50:22AM +1000, Benjamin Herrenschmidt wrote:
> On Thu, 2011-04-28 at 14:02 -0600, Grant Likely wrote:
> > This patch creates a common implementation of irq_of_create_mapping()
> > and factors out the interrupt domain translation code from powerpc to
> > make it available for all architectures.
> 
> I think you are going the wrong way around.
> 
> First thing first, is to make the irq domain / mapping API generic
> without the OF bits.
> 
> IE. move the IRQ domain generically, get rid of irq_map by putting the
> domain ptr & hw numbers in the irq desc/data etc...
> 
> Then you can move over the OF specific bits which are optional and
> orthogonal to a large extent.

As discussed in my other reply, I disagree.  There isn't an immediate
need for the mapping interface in common code.  It would be useful,
sure, for some interrupt controllers, but for many of them
irq_alloc_descs() and an irq_base value is all the functionality that
is needed, and irq_host doesn't gain anything.

The OF translation on the other hand is needed immediately by several
architectures and are very much non-optional in that regard.

g.

^ permalink raw reply

* Re: [PATCH 2/6] powerpc: make irq_{alloc, free}_virt private and remove count argument
From: Grant Likely @ 2011-05-04 15:59 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: Michal Simek, Sebastian Andrzej Siewior, x86, linux-kernel,
	Ralf Baechle, hpa, Dirk Brandewie, Thomas Gleixner, linuxppc-dev,
	devicetree-discuss
In-Reply-To: <1304387267.2513.298.camel@pasglop>

On Tue, May 03, 2011 at 11:47:47AM +1000, Benjamin Herrenschmidt wrote:
> On Thu, 2011-04-28 at 14:01 -0600, Grant Likely wrote:
> > irq_alloc_virt() and irq_free_virt() aren't called anywhere but from
> > arch/powerpc/kernel/irq.c, and they are only ever called with count=1.
> > This patch removes the prototypes from the header file, removes the
> > count arguments, and cuts out the dead code.
> > 
> > Also removes obsolete references to irq_early_init()
> 
> Nack.
> 
> The count was intended to be able to allocate blocks of interrupts. This
> was not used so far because we didn't support MSI blocks (for non-X
> MSIs) but that is coming, and unfortunately, the API that was designed
> for that is crap and requires contiguous IRQ numbers on the linux side
> as well as on the device side (well device side is a HW requirement but
> we could have been smarter on the Linux side).
> 
> So the ability to allocate blocks will be needed. In fact it's not clear
> yet whether we'll also need them to be naturally aligned powers of two
> or not at this stage. It depends how the bloody API is going to be used
> by drivers.

Heh, I wondered about that, but there hasn't been any users for at
least 5 years (as evidenced by commit e12514650b, "Fix loop logic in
irq_alloc_virt()") so it was looking pretty dead, and it made the
patch to switch to using irq_alloc_desc*() quite a bit simpler if it
was removed.  :-)

I'm not particularly attached to this patch, so I can drop it from the
series.

g.

^ permalink raw reply

* Re: [PATCH 0/6] General device tree irq domain infrastructure
From: Grant Likely @ 2011-05-04 15:52 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: Michal Simek, Sebastian Andrzej Siewior, x86, linux-kernel,
	Ralf Baechle, hpa, Dirk Brandewie, Thomas Gleixner, linuxppc-dev,
	devicetree-discuss
In-Reply-To: <1304386999.2513.293.camel@pasglop>

On Tue, May 03, 2011 at 11:43:19AM +1000, Benjamin Herrenschmidt wrote:
> On Thu, 2011-04-28 at 14:01 -0600, Grant Likely wrote:
> > A lot of this series ends up being fixups to powerpc code; but the 4th
> > patch is of importance to every architecture using CONFIG_OF (except
> > SPARC, which has its own solution).
> > 
> > This series (finally!) factors out device tree irq domain decoding
> > from arch/powerpc and makes it generic for all architectures.  The
> > infrastructure is quite simple.  Any interrupt controller can embed
> > the of_irq_domain structure and register it with the core code.  After
> > that, device nodes referencing interrupts on that device tree node
> > will trigger a call to the domain's map function.
> 
> This leads to an immediate reaction from me : why "of_irq_domain" ?
> 
> The concept of interrupt domains is completely orthogonal to "OF" and
> whether you use the device-tree or not.
> 
> Having a remapping mechanism allowing to deal with multiple interrupt
> domains without playing stupid numbering tricks is generally useful for
> architectures, regardless of their adoption of the device-tree.
> 
> The irq domain has one and -only one- op that is related to OF which
> allows to map a device node to a domain, but that's 'optional' and only
> use if you use the OF resolving process. The whole mechanism can be (and
> is under some circumstances on ppc) without a device-tree relationship.
> 
> We instanciate IRQs within domains manually in some cases, either
> because we lack proper DT informations or bcs the IRQs come from the
> firmware or as "created" out of the blue (device-tree). A domain pointer
> (or NULL for the default domain) is all is needed.
> 
> Thus I object to tying this infrastructure generically to "OF" even if
> it's just a mater of naming of the domain structure and location of the
> code in the kernel tree.
> 
> It should basically all go into kernel/irq/domains.c or something like
> that.

I completely agree that irq domains are a generically useful feature
for architectures, and it should be made available.  I also completely
agree that it is orthogonal to device tree translations, which in a
large part is why I've structured this series and the new code the
way I have.

In this series I'm specifically addressing device tree translation,
which is the one bit that is DT specific, and is important regardless
of the backend translation mechanism.  In fact, the more I looked at
it, the more it seems that the DT api really is orthogonal to the
backend irq mapping and I don't think that the way irq_host ties them
together is necessarily the best way to do it.  Many of the interrupt
controllers which need to gain dt irq parsing have already been
converted to using the irq_alloc_desc*() apis and have all the mapping
mechanism they need, but lack a method of exposing it for DT
translation.

As for the mapping, I agree that the functionality is generally
useful, I'm just not fond of the current implementation.  I think it
is more complex than it needs to be and I'm not excited about bring it
over to the other architectures as-is.

For the majority of fixed hw interrupt controllers it is overkill.
There is no need for a map table when all the irq descs (<=32 of them)
get allocated when the irq controller is instantiated and the mapping
consists of 'virq = hw_irq + virq_base'.  For instance, with the arm
irq controllers, it's be more than sufficient to use irq_alloc_descs
to obtain a range of irq numbers and then a simple of_irq_domain
registration to handle the parsing.

For the cases where an interrupt controller isn't able to alloc all
the irq descs at once, like for MSI, then yes the LINEAR and RADIX
mappings are important.  What bothers me though is the way irq_host
needs to use unions and the ->revmap_type value to implement multiple
behaviours into a single type.  That's the sort of thing that can be
broken out into a library and instantiated only by the interrupt
controllers that actually need it.  Similarly, it bothers me that that
radix mapping makes up a significant portion of the code, yet it has
only one user.  I'd be happier if each kind of mapping had its own
structure that embedded a generic irq_host/irq_domain with mapping
specific ops populated to manipulate it.

Regardless, the immediate priority is to implement a mapper that will
work for all architectures (or at least everything but powerpc and
sparc).  x86 has already implemented a skeleton irq_domain because
there wasn't any common code for it to use.  ARM also needs the
functionality immediately, and I don't want to see yet another
arch-specific implementation.  I'd like to get the framework in place
now, and grafting in mapping features as follow on patches.  That way
the new DT users aren't blocked while waiting for us to hammer down
the features that the other architectures don't need yet.

What I /could/ have done I suppose was called it 'struct irq_domain'
as you suggest, and allowed each translation mechanism to define its
own match/map pair of routines, with device tree being the only one
actually implemented at this point.  Yes, I understand that the
core code treats the controller pointer as an anonymous cookie, but
the api is still very device tree centric, and I'm not convinced that
the assumption that all firmware irq representations will be an array
of u32 values is going to hold up.  I'd rather state upfront that the
device tree translation really is device tree and let translations for
other representation have the option of defining their own API.

However, that is not a strong objection, and if Thomas agrees with you
then I'm okay with renaming of_irq_domain to irq_domain and moving it
to kernel/irq/irqdomain.c.  The mapping functionality I think should
stay out for now until we come to agreement on how it should look, and
I'll fix up any users if the API needs to change at a later date.

g.



> 
> > PowerPC and x86 have been converted to use of_irq_domain.  MIPS and
> > Microblaze have it enabled, but nothing actually registers domains
> > yet, so a workaround is in place to preserve the current behaviour
> > until it is fixed.
> > 
> > I'd really like to get patches 1-4 merged into 2.6.40.  Please test.
> > I'm also running through build testing here, and when it's complete
> > I'll push it out to a 'devicetree/irq-domain' branch on
> > git://git.secretlab.ca/git/linux-2.6
> > 
> > It needs testing.  I've booted it on a powerpc board here without any
> > apparent regressions, but that isn't a very big sample.  I've also
> > build tested on everything I think is affected.
> > 
> > I'd also like to get it into linux-next.  Ben, if things checkout okay
> > over the next few days, would you be okay with me adding it to
> > linux-next, say around Wednesday next week?  As for merging, I think
> > this should probably go via your powerpc tree since the that's where
> > the bulk of the changes are, but I'm open to other suggestions).
> > 
> > Patches 5 & 6 are follow-on cleanup work to powerpc, but patch 6 is
> > RFC only since there is a locking problem that I haven't fixed yet.
> > 
> > Cheers,
> > g.
> > 
> > ---
> > 
> > Grant Likely (6):
> >       powerpc: stop exporting irq_map
> >       powerpc: make irq_{alloc,free}_virt private and remove count argument
> >       powerpc: Make struct irq_host semi-private by moving into irqhost.h
> >       dt: generalize of_irq_parse_and_map()
> >       powerpc: move irq_alloc_descs_at() call into irq_alloc_virt()
> >       powerpc: use irq_alloc_desc() to manage irq allocations
> > 
> > 
> >  arch/microblaze/kernel/irq.c                     |    7 -
> >  arch/microblaze/kernel/setup.c                   |    2 
> >  arch/mips/kernel/prom.c                          |   14 -
> >  arch/powerpc/include/asm/irq.h                   |   88 +------
> >  arch/powerpc/include/asm/irqhost.h               |   27 ++
> >  arch/powerpc/kernel/irq.c                        |  260 ++++++++++++----------
> >  arch/powerpc/platforms/512x/mpc5121_ads_cpld.c   |    5 
> >  arch/powerpc/platforms/52xx/media5200.c          |    5 
> >  arch/powerpc/platforms/52xx/mpc52xx_gpt.c        |    1 
> >  arch/powerpc/platforms/52xx/mpc52xx_pic.c        |   80 +------
> >  arch/powerpc/platforms/82xx/pq2ads-pci-pic.c     |    5 
> >  arch/powerpc/platforms/85xx/socrates_fpga_pic.c  |   26 +-
> >  arch/powerpc/platforms/86xx/gef_pic.c            |   10 -
> >  arch/powerpc/platforms/8xx/m8xx_setup.c          |    2 
> >  arch/powerpc/platforms/cell/axon_msi.c           |   15 +
> >  arch/powerpc/platforms/cell/spider-pic.c         |   19 +-
> >  arch/powerpc/platforms/embedded6xx/flipper-pic.c |    9 -
> >  arch/powerpc/platforms/embedded6xx/hlwd-pic.c    |    9 -
> >  arch/powerpc/platforms/embedded6xx/wii.c         |    6 -
> >  arch/powerpc/platforms/iseries/irq.c             |   10 -
> >  arch/powerpc/platforms/powermac/pic.c            |   12 +
> >  arch/powerpc/platforms/pseries/ras.c             |    4 
> >  arch/powerpc/platforms/pseries/xics.c            |   14 +
> >  arch/powerpc/sysdev/cpm1.c                       |    8 -
> >  arch/powerpc/sysdev/cpm2_pic.c                   |   10 -
> >  arch/powerpc/sysdev/fsl_msi.c                    |    3 
> >  arch/powerpc/sysdev/i8259.c                      |    3 
> >  arch/powerpc/sysdev/ipic.c                       |   19 +-
> >  arch/powerpc/sysdev/mpc8xx_pic.c                 |   10 -
> >  arch/powerpc/sysdev/mpc8xxx_gpio.c               |   13 +
> >  arch/powerpc/sysdev/mpic.c                       |   33 +--
> >  arch/powerpc/sysdev/mpic_msi.c                   |    3 
> >  arch/powerpc/sysdev/mpic_pasemi_msi.c            |    5 
> >  arch/powerpc/sysdev/mv64x60_pic.c                |   14 +
> >  arch/powerpc/sysdev/qe_lib/qe_ic.c               |    9 -
> >  arch/powerpc/sysdev/uic.c                        |   13 +
> >  arch/powerpc/sysdev/xilinx_intc.c                |    9 -
> >  arch/x86/include/asm/irq_controller.h            |   12 -
> >  arch/x86/include/asm/prom.h                      |    1 
> >  arch/x86/kernel/devicetree.c                     |   77 +------
> >  drivers/of/irq.c                                 |  118 ++++++++++
> >  include/linux/of_irq.h                           |   31 +++
> >  42 files changed, 504 insertions(+), 517 deletions(-)
> >  create mode 100644 arch/powerpc/include/asm/irqhost.h
> >  delete mode 100644 arch/x86/include/asm/irq_controller.h
> 
> 

^ permalink raw reply

* Re: [PATCH] atomic: add *_dec_not_zero
From: James Bottomley @ 2011-05-04 15:04 UTC (permalink / raw)
  To: Mike Frysinger
  Cc: linux-arch, linux-mips, linux-m32r, linux-ia64, linux-parisc,
	linux-cris-kernel, linux-s390, linux-sh, x86, linux-kernel,
	Chris Metcalf, David Howells, linux-m68k, linux-am33-list,
	linux-arm-kernel, linux-alpha, sparclinux, uclinux-dist-devel,
	linuxppc-dev, Sven Eckelmann
In-Reply-To: <BANLkTiminpyJ_opxhqG0E0gBOrF490b+tQ@mail.gmail.com>

On Wed, 2011-05-04 at 00:44 -0400, Mike Frysinger wrote:
> On Tue, May 3, 2011 at 17:30, Sven Eckelmann wrote:
> > Introduce an *_dec_not_zero operation.  Make this a special case of
> > *_add_unless because batman-adv uses atomic_dec_not_zero in different
> > places like re-broadcast queue or aggregation queue management. There
> > are other non-final patches which may also want to use this macro.
> >
> > Cc: uclinux-dist-devel@blackfin.uclinux.org
> >
> > --- a/arch/blackfin/include/asm/atomic.h
> > +++ b/arch/blackfin/include/asm/atomic.h
> > @@ -103,6 +103,7 @@ static inline int atomic_test_mask(int mask, atomic_t *v)
> >        c != (u);                                               \
> >  })
> >  #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
> > +#define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0)
> >
> >  /*
> >  * atomic_inc_and_test - increment and test
> 
> no opinion on the actual idea, but for the Blackfin pieces:
> Acked-by: Mike Frysinger <vapier@gentoo.org>

This goes for parisc as well.

Acked-by: James Bottomley <James.Bottomley@HansenPartnership.com>

James

^ permalink raw reply

* [PATCH] powerpc/mpc8610_hpcd: Do not use "/" in interrupt names
From: Geert Uytterhoeven @ 2011-05-04 14:29 UTC (permalink / raw)
  To: Benjamin Herrenschmidt, Anton Vorontsov, Kumar Gala
  Cc: Linux/PPC Development, Linux Kernel Development

It may trigger a warning in fs/proc/generic.c:__xlate_proc_name() when
trying to add an entry for the interrupt handler to sysfs.

Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
---
 arch/powerpc/platforms/86xx/mpc8610_hpcd.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c
index 018cc67..efadd3b 100644
--- a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c
+++ b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c
@@ -66,7 +66,7 @@ static void __init mpc8610_suspend_init(void)
 		return;
 	}
 
-	ret = request_irq(irq, mpc8610_sw9_irq, 0, "sw9/wakeup", NULL);
+	ret = request_irq(irq, mpc8610_sw9_irq, 0, "sw9:wakeup", NULL);
 	if (ret) {
 		pr_err("%s: can't request pixis event IRQ: %d\n",
 		       __func__, ret);
-- 
1.7.0.4

Gr{oetje,eeting}s,

						Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
							    -- Linus Torvalds

^ permalink raw reply related

* [PATCH] fsl/usb: Unused endpoint failure for USB gadget
From: Ramneek Mehresh @ 2011-05-04 14:11 UTC (permalink / raw)
  To: linuxppc-dev, linuxppc-release
  Cc: Suchit Lepcha, dbrownell, gregkh, Ramneek Mehresh

Though USB controller works without this most of the time, an issue was faced
where USB was configured as printer device and it was dropping first
packet(64 bytes) in full speed mode due to DATA PID mismatch.
The problem gets resolved once unused endpoints are configured as bulk.
As per P1020 RM (Table17-31, bits 19-18, bits 3-2) "When only one endpoint
(RX or TX, but not both) of an endpoint pair is used, the unused endpoint
should be configured as a bulk type endpoint." So according to the RM,
this patch is initializing TX and RX endpoints as bulk type

Signed-off-by: Suchit Lepcha <Suchit.Lepcha@freescale.com>
Signed-off-by: Ramneek Mehresh <ramneek.mehresh@freescale.com>
---
Applies on git://git.am.freescale.net/mirrors/linux-2.6.git
(branch master)

 drivers/usb/gadget/fsl_udc_core.c |   27 +++++++++++++++++++++------
 1 files changed, 21 insertions(+), 6 deletions(-)

diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c
index 07499c1..bac8ca9 100644
--- a/drivers/usb/gadget/fsl_udc_core.c
+++ b/drivers/usb/gadget/fsl_udc_core.c
@@ -1,5 +1,6 @@
 /*
- * Copyright (C) 2004-2007 Freescale Semicondutor, Inc. All rights reserved.
+ * Copyright (C) 2004-2007,2011 Freescale Semiconductor, Inc.
+ * All rights reserved.
  *
  * Author: Li Yang <leoli@freescale.com>
  *         Jiang Bo <tanya.jiang@freescale.com>
@@ -177,7 +178,8 @@ static void nuke(struct fsl_ep *ep, int status)
 
 static int dr_controller_setup(struct fsl_udc *udc)
 {
-	unsigned int tmp, portctrl;
+	unsigned int tmp, portctrl, ep_num;
+	unsigned int max_no_of_ep;
 #ifndef CONFIG_ARCH_MXC
 	unsigned int ctrl;
 #endif
@@ -242,6 +244,14 @@ static int dr_controller_setup(struct fsl_udc *udc)
 		udc->ep_qh, (int)tmp,
 		fsl_readl(&dr_regs->endpointlistaddr));
 
+	max_no_of_ep = (0x0000001F & fsl_readl(&dr_regs->dccparams));
+	for (ep_num = 1; ep_num < max_no_of_ep; ep_num++) {
+		tmp = fsl_readl(&dr_regs->endptctrl[ep_num]);
+		tmp &= ~(EPCTRL_TX_TYPE | EPCTRL_RX_TYPE);
+		tmp |= (EPCTRL_EP_TYPE_BULK << EPCTRL_TX_EP_TYPE_SHIFT)
+		| (EPCTRL_EP_TYPE_BULK << EPCTRL_RX_EP_TYPE_SHIFT);
+		fsl_writel(tmp, &dr_regs->endptctrl[ep_num]);
+	}
 	/* Config control enable i/o output, cpu endian register */
 #ifndef CONFIG_ARCH_MXC
 	ctrl = __raw_readl(&usb_sys_regs->control);
@@ -318,12 +328,14 @@ static void dr_ep_setup(unsigned char ep_num, unsigned char dir,
 		if (ep_num)
 			tmp_epctrl |= EPCTRL_TX_DATA_TOGGLE_RST;
 		tmp_epctrl |= EPCTRL_TX_ENABLE;
+		tmp_epctrl &= ~EPCTRL_TX_TYPE;
 		tmp_epctrl |= ((unsigned int)(ep_type)
 				<< EPCTRL_TX_EP_TYPE_SHIFT);
 	} else {
 		if (ep_num)
 			tmp_epctrl |= EPCTRL_RX_DATA_TOGGLE_RST;
 		tmp_epctrl |= EPCTRL_RX_ENABLE;
+		tmp_epctrl &= ~EPCTRL_RX_TYPE;
 		tmp_epctrl |= ((unsigned int)(ep_type)
 				<< EPCTRL_RX_EP_TYPE_SHIFT);
 	}
@@ -546,10 +558,13 @@ static int fsl_ep_disable(struct usb_ep *_ep)
 	/* disable ep on controller */
 	ep_num = ep_index(ep);
 	epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]);
-	if (ep_is_in(ep))
-		epctrl &= ~EPCTRL_TX_ENABLE;
-	else
-		epctrl &= ~EPCTRL_RX_ENABLE;
+	if (ep_is_in(ep)) {
+		epctrl &= ~(EPCTRL_TX_ENABLE | EPCTRL_TX_TYPE);
+		epctrl |= EPCTRL_EP_TYPE_BULK << EPCTRL_TX_EP_TYPE_SHIFT;
+	} else {
+		epctrl &= ~(EPCTRL_RX_ENABLE | EPCTRL_TX_TYPE);
+		epctrl |= EPCTRL_EP_TYPE_BULK << EPCTRL_RX_EP_TYPE_SHIFT;
+	}
 	fsl_writel(epctrl, &dr_regs->endptctrl[ep_num]);
 
 	udc = (struct fsl_udc *)ep->udc;
-- 
1.6.1

^ permalink raw reply related

* [PATCH] powerpc/qoriq: Add default mode for P1020RDB USB
From: Ramneek Mehresh @ 2011-05-04 13:26 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: paulus, Ramneek Mehresh

Add P1020 USB controller default value for "dr_mode" property

Signed-off-by: Ramneek Mehresh <ramneek.mehresh@freescale.com>
---
Applies on git://git.am.freescale.net/mirrors/linux-2.6.git
(branch master)
 arch/powerpc/boot/dts/p1020rdb.dts |   10 ++++------
 1 files changed, 4 insertions(+), 6 deletions(-)

diff --git a/arch/powerpc/boot/dts/p1020rdb.dts b/arch/powerpc/boot/dts/p1020rdb.dts
index e0668f8..c630b51 100644
--- a/arch/powerpc/boot/dts/p1020rdb.dts
+++ b/arch/powerpc/boot/dts/p1020rdb.dts
@@ -473,13 +473,11 @@
 			interrupt-parent = <&mpic>;
 			interrupts = <28 0x2>;
 			phy_type = "ulpi";
+			dr_mode = "host";
 		};
 
-		/* USB2 is shared with localbus, so it must be disabled
-		   by default. We can't put 'status = "disabled";' here
-		   since U-Boot doesn't clear the status property when
-		   it enables USB2. OTOH, U-Boot does create a new node
-		   when there isn't any. So, just comment it out.
+		/* USB2 is shared with localbus. It is used
+		   only in case of SPI and SD boot*/
 		usb@23000 {
 			#address-cells = <1>;
 			#size-cells = <0>;
@@ -488,8 +486,8 @@
 			interrupt-parent = <&mpic>;
 			interrupts = <46 0x2>;
 			phy_type = "ulpi";
+			dr_mode = "host";
 		};
-		*/
 
 		sdhci@2e000 {
 			compatible = "fsl,p1020-esdhc", "fsl,esdhc";
-- 
1.6.1

^ permalink raw reply related

* Re: [PATCH] atomic: add *_dec_not_zero
From: Geert Uytterhoeven @ 2011-05-04 12:17 UTC (permalink / raw)
  To: Sven Eckelmann
  Cc: linux-arch, linux-mips, linux-m32r, linux-ia64, linux-parisc,
	linux-cris-kernel, linux-s390, linux-sh, x86, linux-kernel,
	Chris Metcalf, David Howells, linux-m68k, linux-am33-list,
	linux-alpha, sparclinux, uclinux-dist-devel, linuxppc-dev,
	linux-arm-kernel
In-Reply-To: <1304458235-28473-1-git-send-email-sven@narfation.org>

On Tue, May 3, 2011 at 23:30, Sven Eckelmann <sven@narfation.org> wrote:
> Introduce an *_dec_not_zero operation. =C2=A0Make this a special case of
> *_add_unless because batman-adv uses atomic_dec_not_zero in different
> places like re-broadcast queue or aggregation queue management. There
> are other non-final patches which may also want to use this macro.

> =C2=A0arch/m68k/include/asm/atomic.h =C2=A0 =C2=A0 | =C2=A0 =C2=A01 +

Acked-by: Geert Uytterhoeven <geert@linux-m68k.org>

Gr{oetje,eeting}s,

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k=
.org

In personal conversations with technical people, I call myself a hacker. Bu=
t
when I'm talking to journalists I just say "programmer" or something like t=
hat.
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0=C2=A0 =C2=A0=C2=A0 -- Linus Torvalds

^ permalink raw reply


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