Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [FYI 2/4] mmci: add PrimeCell generic DMA to MMCI/PL180
From: Per Forlin @ 2011-01-12 18:19 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1294856383-14187-1-git-send-email-per.forlin@linaro.org>

From: Linus Walleij <linus.walleij@stericsson.com>

NOT to be mainlined, only sets the base for the double
buffer example implementation. The DMA implemenation for
MMCI is under development.

This extends the MMCI/PL180 driver with generic DMA engine support
using the PrimeCell DMA engine interface.
---
 drivers/mmc/host/mmci.c   |  264 +++++++++++++++++++++++++++++++++++++++++++--
 drivers/mmc/host/mmci.h   |   13 +++
 include/linux/amba/mmci.h |   16 +++
 3 files changed, 282 insertions(+), 11 deletions(-)

diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index aafede4..38fcbde 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -2,7 +2,7 @@
  *  linux/drivers/mmc/host/mmci.c - ARM PrimeCell MMCI PL180/1 driver
  *
  *  Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved.
- *  Copyright (C) 2010 ST-Ericsson AB.
+ *  Copyright (C) 2010 ST-Ericsson SA
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -24,8 +24,10 @@
 #include <linux/clk.h>
 #include <linux/scatterlist.h>
 #include <linux/gpio.h>
-#include <linux/amba/mmci.h>
 #include <linux/regulator/consumer.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/amba/mmci.h>
 
 #include <asm/div64.h>
 #include <asm/io.h>
@@ -41,11 +43,15 @@ static unsigned int fmax = 515633;
  * struct variant_data - MMCI variant-specific quirks
  * @clkreg: default value for MCICLOCK register
  * @clkreg_enable: enable value for MMCICLOCK register
+ * @dmareg_enable: enable value for MMCIDATACTRL register
  * @datalength_bits: number of bits in the MMCIDATALENGTH register
  * @fifosize: number of bytes that can be written when MMCI_TXFIFOEMPTY
  *	      is asserted (likewise for RX)
  * @fifohalfsize: number of bytes that can be written when MCI_TXFIFOHALFEMPTY
  *		  is asserted (likewise for RX)
+ * @txsize_threshold: Sets DMA burst size to minimal if transfer size is
+ *		less or equal to this threshold. This shall be specified in
+ *		number of bytes. Set 0 for no burst compensation
  * @broken_blockend: the MCI_DATABLOCKEND is broken on the hardware
  *		and will not work at all.
  * @sdio: variant supports SDIO
@@ -54,9 +60,11 @@ static unsigned int fmax = 515633;
 struct variant_data {
 	unsigned int		clkreg;
 	unsigned int		clkreg_enable;
+	unsigned int		dmareg_enable;
 	unsigned int		datalength_bits;
 	unsigned int		fifosize;
 	unsigned int		fifohalfsize;
+	unsigned int		txsize_threshold;
 	bool			broken_blockend;
 	bool			sdio;
 	bool			st_clkdiv;
@@ -80,8 +88,10 @@ static struct variant_data variant_u300 = {
 static struct variant_data variant_ux500 = {
 	.fifosize		= 30 * 4,
 	.fifohalfsize		= 8 * 4,
+	.txsize_threshold	= 16,
 	.clkreg			= MCI_CLK_ENABLE,
 	.clkreg_enable		= 1 << 14, /* HWFCEN */
+	.dmareg_enable		= 1 << 12, /* DMAREQCTRL */
 	.datalength_bits	= 24,
 	.broken_blockend	= true,
 	.sdio			= true,
@@ -193,6 +203,209 @@ static void mmci_init_sg(struct mmci_host *host, struct mmc_data *data)
 	sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags);
 }
 
+/*
+ * All the DMA operation mode stuff goes inside this ifdef.
+ * This assumes that you have a generic DMA device interface,
+ * no custom DMA interfaces are supported.
+ */
+#ifdef CONFIG_DMA_ENGINE
+static void __devinit mmci_setup_dma(struct mmci_host *host)
+{
+	struct mmci_platform_data *plat = host->plat;
+	dma_cap_mask_t mask;
+
+	if (!plat || !plat->dma_filter) {
+		dev_err(mmc_dev(host->mmc), "no DMA platform data!\n");
+		return;
+	}
+
+	/* Try to acquire a generic DMA engine slave channel */
+	dma_cap_zero(mask);
+	dma_cap_set(DMA_SLAVE, mask);
+	/*
+	 * If only an RX channel is specified, the driver will
+	 * attempt to use it bidirectionally, however if it is
+	 * is specified but cannot be located, DMA will be disabled.
+	 */
+	host->dma_rx_channel = dma_request_channel(mask,
+						plat->dma_filter,
+						plat->dma_rx_param);
+	/* E.g if no DMA hardware is present */
+	if (!host->dma_rx_channel) {
+		dev_err(mmc_dev(host->mmc), "no RX DMA channel!\n");
+		return;
+	}
+	if (plat->dma_tx_param) {
+		host->dma_tx_channel = dma_request_channel(mask,
+							   plat->dma_filter,
+							   plat->dma_tx_param);
+		if (!host->dma_tx_channel) {
+			dma_release_channel(host->dma_rx_channel);
+			host->dma_rx_channel = NULL;
+			return;
+		}
+	} else {
+		host->dma_tx_channel = host->dma_rx_channel;
+	}
+	host->dma_enable = true;
+	dev_info(mmc_dev(host->mmc), "use DMA channels DMA RX %s, DMA TX %s\n",
+		 dma_chan_name(host->dma_rx_channel),
+		 dma_chan_name(host->dma_tx_channel));
+}
+
+/*
+ * This is used in __devinit or __devexit so inline it
+ * so it can be discarded.
+ */
+static inline void mmci_disable_dma(struct mmci_host *host)
+{
+	if (host->dma_rx_channel)
+		dma_release_channel(host->dma_rx_channel);
+	if (host->dma_tx_channel)
+		dma_release_channel(host->dma_tx_channel);
+	host->dma_enable = false;
+}
+
+static void mmci_dma_data_end(struct mmci_host *host)
+{
+	struct mmc_data *data = host->data;
+
+	dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
+		     (data->flags & MMC_DATA_WRITE)
+		     ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+	host->dma_on_current_xfer = false;
+}
+
+static void mmci_dma_terminate(struct mmci_host *host)
+{
+	struct mmc_data *data = host->data;
+	struct dma_chan *chan;
+
+	dev_err(mmc_dev(host->mmc), "error during DMA transfer!\n");
+	if (data->flags & MMC_DATA_READ)
+		chan = host->dma_rx_channel;
+	else
+		chan = host->dma_tx_channel;
+	dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
+		     (data->flags & MMC_DATA_WRITE)
+		     ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+	chan->device->device_control(chan, DMA_TERMINATE_ALL, 0);
+}
+
+static int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl)
+{
+	struct variant_data *variant = host->variant;
+	struct dma_slave_config rx_conf = {
+		.src_addr = host->phybase + MMCIFIFO,
+		.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
+		.direction = DMA_FROM_DEVICE,
+		.src_maxburst = variant->fifohalfsize >> 2, /* # of words */
+	};
+	struct dma_slave_config tx_conf = {
+		.dst_addr = host->phybase + MMCIFIFO,
+		.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
+		.direction = DMA_TO_DEVICE,
+		.dst_maxburst = variant->fifohalfsize >> 2, /* # of words */
+	};
+	struct mmc_data *data = host->data;
+	enum dma_data_direction direction;
+	struct dma_chan *chan;
+	struct dma_async_tx_descriptor *desc;
+	struct scatterlist *sg;
+	dma_cookie_t cookie;
+	int i;
+
+	datactrl |= MCI_DPSM_DMAENABLE;
+	datactrl |= variant->dmareg_enable;
+
+	if (data->flags & MMC_DATA_READ) {
+		if (host->size <= variant->txsize_threshold)
+			rx_conf.src_maxburst = 1;
+
+		direction = DMA_FROM_DEVICE;
+		chan = host->dma_rx_channel;
+		chan->device->device_control(chan, DMA_SLAVE_CONFIG,
+					     (unsigned long) &rx_conf);
+	} else {
+		if (host->size <= variant->txsize_threshold)
+			tx_conf.dst_maxburst = 1;
+
+		direction = DMA_TO_DEVICE;
+		chan = host->dma_tx_channel;
+		chan->device->device_control(chan, DMA_SLAVE_CONFIG,
+					     (unsigned long) &tx_conf);
+	}
+
+	/* Check for weird stuff in the sg list */
+	for_each_sg(data->sg, sg, data->sg_len, i) {
+		dev_vdbg(mmc_dev(host->mmc), "MMCI SGlist %d dir %d: length: %08x\n",
+			 i, direction, sg->length);
+		if (sg->offset & 3 || sg->length & 3)
+			return -EINVAL;
+	}
+
+	dma_map_sg(mmc_dev(host->mmc), data->sg,
+		   data->sg_len, direction);
+
+	desc = chan->device->device_prep_slave_sg(chan,
+					data->sg, data->sg_len, direction,
+					DMA_CTRL_ACK);
+	if (!desc)
+		goto unmap_exit;
+
+	host->dma_desc = desc;
+	dev_vdbg(mmc_dev(host->mmc), "Submit MMCI DMA job, sglen %d "
+		 "blksz %04x blks %04x flags %08x\n",
+		 data->sg_len, data->blksz, data->blocks, data->flags);
+	cookie = desc->tx_submit(desc);
+
+	/* Here overloaded DMA controllers may fail */
+	if (dma_submit_error(cookie))
+		goto unmap_exit;
+
+	host->dma_on_current_xfer = true;
+	chan->device->device_issue_pending(chan);
+
+	/* Trigger the DMA transfer */
+	writel(datactrl, host->base + MMCIDATACTRL);
+	/*
+	 * Let the MMCI say when the data is ended and it's time
+	 * to fire next DMA request. When that happens, MMCI will
+	 * call mmci_data_end()
+	 */
+	writel(readl(host->base + MMCIMASK0) | MCI_DATAENDMASK,
+	       host->base + MMCIMASK0);
+	return 0;
+
+unmap_exit:
+	chan->device->device_control(chan, DMA_TERMINATE_ALL, 0);
+	dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, direction);
+	return -ENOMEM;
+}
+#else
+/* Blank functions if the DMA engine is not available */
+static inline void mmci_setup_dma(struct mmci_host *host)
+{
+}
+
+static inline void mmci_disable_dma(struct mmci_host *host)
+{
+}
+
+static inline void mmci_dma_data_end(struct mmci_host *host)
+{
+}
+
+static inline void mmci_dma_terminate(struct mmci_host *host)
+{
+}
+
+static inline int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl)
+{
+	return -ENOSYS;
+}
+#endif
+
 static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
 {
 	struct variant_data *variant = host->variant;
@@ -210,8 +423,6 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
 	host->last_blockend = false;
 	host->dataend = false;
 
-	mmci_init_sg(host, data);
-
 	clks = (unsigned long long)data->timeout_ns * host->cclk;
 	do_div(clks, 1000000000UL);
 
@@ -225,13 +436,32 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
 	BUG_ON(1 << blksz_bits != data->blksz);
 
 	datactrl = MCI_DPSM_ENABLE | blksz_bits << 4;
-	if (data->flags & MMC_DATA_READ) {
+
+	if (data->flags & MMC_DATA_READ)
 		datactrl |= MCI_DPSM_DIRECTION;
+
+	if (host->dma_enable) {
+		int ret;
+
+		/*
+		 * Attempt to use DMA operation mode, if this
+		 * should fail, fall back to PIO mode
+		 */
+		ret = mmci_dma_start_data(host, datactrl);
+		if (!ret)
+			return;
+	}
+
+	/* IRQ mode, map the SG list for CPU reading/writing */
+	mmci_init_sg(host, data);
+
+	if (data->flags & MMC_DATA_READ) {
 		irqmask1 = MCI_RXFIFOHALFFULLMASK;
 
 		/*
-		 * If we have less than a FIFOSIZE of bytes to transfer,
-		 * trigger a PIO interrupt as soon as any data is available.
+		 * If we have less than a FIFOSIZE of bytes to
+		 * transfer, trigger a PIO interrupt as soon as any
+		 * data is available.
 		 */
 		if (host->size < variant->fifosize)
 			irqmask1 |= MCI_RXDATAAVLBLMASK;
@@ -309,9 +539,12 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
 
 		/*
 		 * We hit an error condition.  Ensure that any data
-		 * partially written to a page is properly coherent.
+		 * partially written to a page is properly coherent,
+		 * unless we're using DMA.
 		 */
-		if (data->flags & MMC_DATA_READ) {
+		if (host->dma_on_current_xfer)
+			mmci_dma_terminate(host);
+		else if (data->flags & MMC_DATA_READ) {
 			struct sg_mapping_iter *sg_miter = &host->sg_miter;
 			unsigned long flags;
 
@@ -354,7 +587,7 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
 		 * flag is unreliable: since it can stay high between
 		 * IRQs it will corrupt the transfer counter.
 		 */
-		if (!variant->broken_blockend)
+		if (!variant->broken_blockend && !host->dma_on_current_xfer)
 			host->data_xfered += data->blksz;
 		if (host->data_xfered == data->blksz * data->blocks)
 			host->last_blockend = true;
@@ -370,6 +603,7 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
 	 */
 	if (host->dataend &&
 	    (host->last_blockend || variant->broken_blockend)) {
+		mmci_dma_data_end(host);
 		mmci_stop_data(host);
 
 		/* Reset these flags */
@@ -411,8 +645,11 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
 	}
 
 	if (!cmd->data || cmd->error) {
-		if (host->data)
+		if (host->data) {
+			if (host->dma_on_current_xfer)
+				mmci_dma_terminate(host);
 			mmci_stop_data(host);
+		}
 		mmci_request_end(host, cmd->mrq);
 	} else if (!(cmd->data->flags & MMC_DATA_READ)) {
 		mmci_start_data(host, cmd->data);
@@ -832,6 +1069,7 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
 		dev_dbg(mmc_dev(mmc), "eventual mclk rate: %u Hz\n",
 			host->mclk);
 	}
+	host->phybase = dev->res.start;
 	host->base = ioremap(dev->res.start, resource_size(&dev->res));
 	if (!host->base) {
 		ret = -ENOMEM;
@@ -942,6 +1180,8 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
 	    && host->gpio_cd_irq < 0)
 		mmc->caps |= MMC_CAP_NEEDS_POLL;
 
+	mmci_setup_dma(host);
+
 	ret = request_irq(dev->irq[0], mmci_irq, IRQF_SHARED, DRIVER_NAME " (cmd)", host);
 	if (ret)
 		goto unmap;
@@ -970,6 +1210,7 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
  irq0_free:
 	free_irq(dev->irq[0], host);
  unmap:
+	mmci_disable_dma(host);
 	if (host->gpio_wp != -ENOSYS)
 		gpio_free(host->gpio_wp);
  err_gpio_wp:
@@ -1008,6 +1249,7 @@ static int __devexit mmci_remove(struct amba_device *dev)
 		writel(0, host->base + MMCICOMMAND);
 		writel(0, host->base + MMCIDATACTRL);
 
+		mmci_disable_dma(host);
 		free_irq(dev->irq[0], host);
 		if (!host->singleirq)
 			free_irq(dev->irq[1], host);
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index 7ac8c4d..39b7ac7 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -148,8 +148,11 @@
 
 struct clk;
 struct variant_data;
+struct dma_chan;
+struct dma_async_tx_descriptor;
 
 struct mmci_host {
+	phys_addr_t		phybase;
 	void __iomem		*base;
 	struct mmc_request	*mrq;
 	struct mmc_command	*cmd;
@@ -183,6 +186,16 @@ struct mmci_host {
 	/* pio stuff */
 	struct sg_mapping_iter	sg_miter;
 	unsigned int		size;
+
 	struct regulator	*vcc;
+
+	/* DMA stuff */
+	bool			dma_enable;
+	bool			dma_on_current_xfer;
+#ifdef CONFIG_DMA_ENGINE
+	struct dma_chan		*dma_rx_channel;
+	struct dma_chan		*dma_tx_channel;
+	struct dma_async_tx_descriptor *dma_desc;
+#endif
 };
 
diff --git a/include/linux/amba/mmci.h b/include/linux/amba/mmci.h
index f4ee9ac..dbeba68 100644
--- a/include/linux/amba/mmci.h
+++ b/include/linux/amba/mmci.h
@@ -6,6 +6,8 @@
 
 #include <linux/mmc/host.h>
 
+/* Just some dummy forwarding */
+struct dma_chan;
 /**
  * struct mmci_platform_data - platform configuration for the MMCI
  * (also known as PL180) block.
@@ -27,6 +29,17 @@
  * @cd_invert: true if the gpio_cd pin value is active low
  * @capabilities: the capabilities of the block as implemented in
  * this platform, signify anything MMC_CAP_* from mmc/host.h
+ * @dma_filter: function used to select an apropriate RX and TX
+ * DMA channel to be used for DMA, if and only if you're deploying the
+ * generic DMA engine
+ * @dma_rx_param: parameter passed to the DMA allocation
+ * filter in order to select an apropriate RX channel. If
+ * there is a bidirectional RX+TX channel, then just specify
+ * this and leave dma_tx_param set to NULL
+ * @dma_tx_param: parameter passed to the DMA allocation
+ * filter in order to select an apropriate TX channel. If this
+ * is NULL the driver will attempt to use the RX channel as a
+ * bidirectional channel
  */
 struct mmci_platform_data {
 	unsigned int f_max;
@@ -38,6 +51,9 @@ struct mmci_platform_data {
 	int	gpio_cd;
 	bool	cd_invert;
 	unsigned long capabilities;
+	bool (*dma_filter)(struct dma_chan *chan, void *filter_param);
+	void *dma_rx_param;
+	void *dma_tx_param;
 };
 
 #endif
-- 
1.7.1

^ permalink raw reply related

* [FYI 3/4] MMCI: Corrections for DMA
From: Per Forlin @ 2011-01-12 18:19 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1294856383-14187-1-git-send-email-per.forlin@linaro.org>

From: Ulf Hansson <ulf.hansson@stericsson.com>

NOT to be mainlined, only sets the base for the double
buffer example implementation. The DMA implemenation for
MMCI is under development.

Make use of DMA_PREP_INTERRUPT to get a callback when DMA has
successfully completed the data transfer.

To entirely ending the transfer and request, both the DMA
callback and MCI_DATAEND must occur.
---
 drivers/mmc/host/mmci.c |  173 +++++++++++++++++++++++++++++++----------------
 1 files changed, 114 insertions(+), 59 deletions(-)

diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index 38fcbde..ab44f5f 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -203,6 +203,34 @@ static void mmci_init_sg(struct mmci_host *host, struct mmc_data *data)
 	sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags);
 }
 
+static void
+mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c)
+{
+	void __iomem *base = host->base;
+
+	dev_dbg(mmc_dev(host->mmc), "op %02x arg %08x flags %08x\n",
+	    cmd->opcode, cmd->arg, cmd->flags);
+
+	if (readl(base + MMCICOMMAND) & MCI_CPSM_ENABLE) {
+		writel(0, base + MMCICOMMAND);
+		udelay(1);
+	}
+
+	c |= cmd->opcode | MCI_CPSM_ENABLE;
+	if (cmd->flags & MMC_RSP_PRESENT) {
+		if (cmd->flags & MMC_RSP_136)
+			c |= MCI_CPSM_LONGRSP;
+		c |= MCI_CPSM_RESPONSE;
+	}
+	if (/*interrupt*/0)
+		c |= MCI_CPSM_INTERRUPT;
+
+	host->cmd = cmd;
+
+	writel(cmd->arg, base + MMCIARGUMENT);
+	writel(c, base + MMCICOMMAND);
+}
+
 /*
  * All the DMA operation mode stuff goes inside this ifdef.
  * This assumes that you have a generic DMA device interface,
@@ -290,6 +318,39 @@ static void mmci_dma_terminate(struct mmci_host *host)
 		     (data->flags & MMC_DATA_WRITE)
 		     ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
 	chan->device->device_control(chan, DMA_TERMINATE_ALL, 0);
+	host->dma_on_current_xfer = false;
+}
+
+static void mmci_dma_callback(void *arg)
+{
+	unsigned long flags;
+	struct mmci_host *host = arg;
+	struct mmc_data *data;
+
+	dev_vdbg(mmc_dev(host->mmc), "DMA transfer done!\n");
+
+	spin_lock_irqsave(&host->lock, flags);
+
+	mmci_dma_data_end(host);
+
+	/*
+	 * Make sure MMCI has received MCI_DATAEND before
+	 * ending the transfer and request.
+	 */
+	if (host->dataend) {
+		data = host->data;
+		mmci_stop_data(host);
+
+		host->data_xfered += data->blksz * data->blocks;
+		host->dataend = false;
+
+		if (!data->stop)
+			mmci_request_end(host, data->mrq);
+		else
+			mmci_start_command(host, data->stop, 0);
+	}
+
+	spin_unlock_irqrestore(&host->lock, flags);
 }
 
 static int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl)
@@ -314,6 +375,8 @@ static int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl)
 	struct scatterlist *sg;
 	dma_cookie_t cookie;
 	int i;
+	unsigned int irqmask0;
+	int sg_len;
 
 	datactrl |= MCI_DPSM_DMAENABLE;
 	datactrl |= variant->dmareg_enable;
@@ -344,15 +407,19 @@ static int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl)
 			return -EINVAL;
 	}
 
-	dma_map_sg(mmc_dev(host->mmc), data->sg,
-		   data->sg_len, direction);
+	sg_len = dma_map_sg(mmc_dev(host->mmc), data->sg,
+				data->sg_len, direction);
+	if (!sg_len)
+		goto map_err;
 
 	desc = chan->device->device_prep_slave_sg(chan,
-					data->sg, data->sg_len, direction,
-					DMA_CTRL_ACK);
+					data->sg, sg_len, direction,
+					DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
 	if (!desc)
 		goto unmap_exit;
 
+	desc->callback = mmci_dma_callback;
+	desc->callback_param = host;
 	host->dma_desc = desc;
 	dev_vdbg(mmc_dev(host->mmc), "Submit MMCI DMA job, sglen %d "
 		 "blksz %04x blks %04x flags %08x\n",
@@ -366,20 +433,25 @@ static int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl)
 	host->dma_on_current_xfer = true;
 	chan->device->device_issue_pending(chan);
 
-	/* Trigger the DMA transfer */
-	writel(datactrl, host->base + MMCIDATACTRL);
 	/*
-	 * Let the MMCI say when the data is ended and it's time
-	 * to fire next DMA request. When that happens, MMCI will
-	 * call mmci_data_end()
+	 * MMCI monitors both MCI_DATAEND and the DMA callback.
+	 * Both events must occur before the transfer is considered
+	 * to be completed. MCI_DATABLOCKEND is not used in DMA mode.
 	 */
-	writel(readl(host->base + MMCIMASK0) | MCI_DATAENDMASK,
-	       host->base + MMCIMASK0);
+	host->last_blockend = true;
+	irqmask0 = readl(host->base + MMCIMASK0);
+	irqmask0 |= MCI_DATAENDMASK;
+	irqmask0 &= ~MCI_DATABLOCKENDMASK;
+	writel(irqmask0, host->base + MMCIMASK0);
+
+	/* Trigger the DMA transfer */
+	writel(datactrl, host->base + MMCIDATACTRL);
 	return 0;
 
 unmap_exit:
-	chan->device->device_control(chan, DMA_TERMINATE_ALL, 0);
 	dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, direction);
+map_err:
+	chan->device->device_control(chan, DMA_TERMINATE_ALL, 0);
 	return -ENOMEM;
 }
 #else
@@ -478,43 +550,20 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
 		if (mmc_card_sdio(host->mmc->card))
 			datactrl |= MCI_ST_DPSM_SDIOEN;
 
-	writel(datactrl, base + MMCIDATACTRL);
+	/* Setup IRQ */
 	irqmask0 = readl(base + MMCIMASK0);
-	if (variant->broken_blockend)
+	if (variant->broken_blockend) {
+		host->last_blockend = true;
 		irqmask0 &= ~MCI_DATABLOCKENDMASK;
-	else
+	} else {
 		irqmask0 |= MCI_DATABLOCKENDMASK;
+	}
 	irqmask0 &= ~MCI_DATAENDMASK;
 	writel(irqmask0, base + MMCIMASK0);
 	mmci_set_mask1(host, irqmask1);
-}
-
-static void
-mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c)
-{
-	void __iomem *base = host->base;
-
-	dev_dbg(mmc_dev(host->mmc), "op %02x arg %08x flags %08x\n",
-	    cmd->opcode, cmd->arg, cmd->flags);
-
-	if (readl(base + MMCICOMMAND) & MCI_CPSM_ENABLE) {
-		writel(0, base + MMCICOMMAND);
-		udelay(1);
-	}
 
-	c |= cmd->opcode | MCI_CPSM_ENABLE;
-	if (cmd->flags & MMC_RSP_PRESENT) {
-		if (cmd->flags & MMC_RSP_136)
-			c |= MCI_CPSM_LONGRSP;
-		c |= MCI_CPSM_RESPONSE;
-	}
-	if (/*interrupt*/0)
-		c |= MCI_CPSM_INTERRUPT;
-
-	host->cmd = cmd;
-
-	writel(cmd->arg, base + MMCIARGUMENT);
-	writel(c, base + MMCICOMMAND);
+	/* Start the data transfer */
+	writel(datactrl, base + MMCIDATACTRL);
 }
 
 static void
@@ -601,26 +650,29 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
 	 * on others we must sync with the blockend signal since they can
 	 * appear out-of-order.
 	 */
-	if (host->dataend &&
-	    (host->last_blockend || variant->broken_blockend)) {
-		mmci_dma_data_end(host);
-		mmci_stop_data(host);
-
-		/* Reset these flags */
+	if (host->dataend && host->last_blockend) {
 		host->last_blockend = false;
-		host->dataend = false;
 
 		/*
-		 * Variants with broken blockend flags need to handle the
-		 * end of the entire transfer here.
+		 * Make sure there is no dma transfer running before
+		 * ending the transfer and the request.
 		 */
-		if (variant->broken_blockend && !data->error)
+		if (!host->dma_on_current_xfer) {
 			host->data_xfered += data->blksz * data->blocks;
+			mmci_stop_data(host);
+			host->dataend = false;
 
-		if (!data->stop) {
-			mmci_request_end(host, data->mrq);
-		} else {
-			mmci_start_command(host, data->stop, 0);
+			/*
+			 * Variants with broken blockend flags need to handle
+			 * the end of the entire transfer here.
+			 */
+			if (variant->broken_blockend && !data->error)
+				host->data_xfered += data->blksz * data->blocks;
+
+			if (!data->stop)
+				mmci_request_end(host, data->mrq);
+			else
+				mmci_start_command(host, data->stop, 0);
 		}
 	}
 }
@@ -1130,10 +1182,13 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
 	mmc->max_req_size = (1 << variant->datalength_bits) - 1;
 
 	/*
-	 * Set the maximum segment size.  Since we aren't doing DMA
-	 * (yet) we are only limited by the data length register.
+	 * Set the maximum segment size. Right now DMA sets the
+	 * limit and not the data length register. Thus until the DMA
+	 * driver not handles this, the segment size is limited by DMA.
+	 * DMA limit: src_addr_width x (64 KB -1). src_addr_width
+	 * can be 1.
 	 */
-	mmc->max_seg_size = mmc->max_req_size;
+	mmc->max_seg_size = 65535;
 
 	/*
 	 * Block size can be up to 2048 bytes, but must be a power of two.
-- 
1.7.1

^ permalink raw reply related

* [FYI 4/4] ARM: mmci: add support for double buffering
From: Per Forlin @ 2011-01-12 18:19 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1294856383-14187-1-git-send-email-per.forlin@linaro.org>

This is an example of how to utilize the double buffer
support in the mmc framework. This patch is not intended
nor ready for mainline.

Implement pre_req() and post_reg() hooks. pre_req()
runs dma_map_sg and prepares the dma descriptor and
post_req calls dma_unmap_sg.

Signed-off-by: Per Forlin <per.forlin@linaro.org>
---
 drivers/mmc/host/mmci.c |  164 ++++++++++++++++++++++++++++++++++++-----------
 drivers/mmc/host/mmci.h |    4 +
 2 files changed, 130 insertions(+), 38 deletions(-)

diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index ab44f5f..7f0b12a 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -276,6 +276,7 @@ static void __devinit mmci_setup_dma(struct mmci_host *host)
 		host->dma_tx_channel = host->dma_rx_channel;
 	}
 	host->dma_enable = true;
+
 	dev_info(mmc_dev(host->mmc), "use DMA channels DMA RX %s, DMA TX %s\n",
 		 dma_chan_name(host->dma_rx_channel),
 		 dma_chan_name(host->dma_tx_channel));
@@ -296,11 +297,6 @@ static inline void mmci_disable_dma(struct mmci_host *host)
 
 static void mmci_dma_data_end(struct mmci_host *host)
 {
-	struct mmc_data *data = host->data;
-
-	dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
-		     (data->flags & MMC_DATA_WRITE)
-		     ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
 	host->dma_on_current_xfer = false;
 }
 
@@ -353,7 +349,9 @@ static void mmci_dma_callback(void *arg)
 	spin_unlock_irqrestore(&host->lock, flags);
 }
 
-static int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl)
+static struct dma_async_tx_descriptor *mmci_dma_cfg(struct mmc_data *data,
+						    struct mmci_host *host,
+						    struct dma_chan **chan_dma)
 {
 	struct variant_data *variant = host->variant;
 	struct dma_slave_config rx_conf = {
@@ -368,19 +366,13 @@ static int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl)
 		.direction = DMA_TO_DEVICE,
 		.dst_maxburst = variant->fifohalfsize >> 2, /* # of words */
 	};
-	struct mmc_data *data = host->data;
 	enum dma_data_direction direction;
 	struct dma_chan *chan;
 	struct dma_async_tx_descriptor *desc;
 	struct scatterlist *sg;
-	dma_cookie_t cookie;
 	int i;
-	unsigned int irqmask0;
 	int sg_len;
 
-	datactrl |= MCI_DPSM_DMAENABLE;
-	datactrl |= variant->dmareg_enable;
-
 	if (data->flags & MMC_DATA_READ) {
 		if (host->size <= variant->txsize_threshold)
 			rx_conf.src_maxburst = 1;
@@ -404,11 +396,12 @@ static int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl)
 		dev_vdbg(mmc_dev(host->mmc), "MMCI SGlist %d dir %d: length: %08x\n",
 			 i, direction, sg->length);
 		if (sg->offset & 3 || sg->length & 3)
-			return -EINVAL;
+			return NULL;
 	}
 
 	sg_len = dma_map_sg(mmc_dev(host->mmc), data->sg,
-				data->sg_len, direction);
+			    data->sg_len, direction);
+
 	if (!sg_len)
 		goto map_err;
 
@@ -420,7 +413,42 @@ static int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl)
 
 	desc->callback = mmci_dma_callback;
 	desc->callback_param = host;
-	host->dma_desc = desc;
+
+	*chan_dma = chan;
+	return desc;
+unmap_exit:
+	dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, direction);
+map_err:
+	*chan_dma = NULL;
+	return NULL;
+}
+
+static void mmci_dma_prepare(struct mmc_data *data, struct mmci_host *host)
+{
+
+	if (data != host->data_next)
+		host->dma_desc = mmci_dma_cfg(data, host, &host->cur_chan);
+	else {
+		host->dma_desc = host->dma_desc_next;
+		host->cur_chan = host->next_chan;
+
+		host->dma_desc_next = NULL;
+		host->data_next = NULL;
+		host->next_chan = NULL;
+	}
+
+	BUG_ON(!host->dma_desc);
+	BUG_ON(!host->cur_chan);
+}
+
+static int mmci_dma_start_data(struct mmci_host *host)
+{
+	struct mmc_data *data = host->data;
+	struct dma_async_tx_descriptor *desc = host->dma_desc;
+	struct dma_chan *chan = host->cur_chan;
+	dma_cookie_t cookie;
+	enum dma_data_direction direction;
+
 	dev_vdbg(mmc_dev(host->mmc), "Submit MMCI DMA job, sglen %d "
 		 "blksz %04x blks %04x flags %08x\n",
 		 data->sg_len, data->blksz, data->blocks, data->flags);
@@ -433,6 +461,24 @@ static int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl)
 	host->dma_on_current_xfer = true;
 	chan->device->device_issue_pending(chan);
 
+	return 0;
+unmap_exit:
+	if (data->flags & MMC_DATA_READ)
+		direction = DMA_FROM_DEVICE;
+
+	dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, direction);
+	chan->device->device_control(chan, DMA_TERMINATE_ALL, 0);
+
+	return -ENOMEM;
+}
+
+static int mmci_dma_start_fifo(struct mmci_host *host, unsigned int datactrl)
+{
+	unsigned int irqmask0;
+
+	datactrl |= MCI_DPSM_DMAENABLE;
+	datactrl |= host->variant->dmareg_enable;
+
 	/*
 	 * MMCI monitors both MCI_DATAEND and the DMA callback.
 	 * Both events must occur before the transfer is considered
@@ -447,12 +493,45 @@ static int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl)
 	/* Trigger the DMA transfer */
 	writel(datactrl, host->base + MMCIDATACTRL);
 	return 0;
+}
+
+static void mmci_post_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+	struct mmci_host *host = mmc_priv(mmc);
+	struct mmc_data *data = mrq->data;
+
+	if (host->dma_enable)
+		dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
+			     (data->flags & MMC_DATA_WRITE)
+			     ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+}
+
+static void mmci_pre_request(struct mmc_host *mmc, struct mmc_request *mrq,
+			     bool host_is_idle)
+{
+	struct mmci_host *host = mmc_priv(mmc);
+	struct mmc_data *data = mrq->data;
+
+	if (host->dma_enable && !host_is_idle) {
+		struct dma_async_tx_descriptor *desc;
+		struct dma_chan *chan;
+
+		desc = mmci_dma_cfg(data, host, &chan);
+		if (desc == NULL)
+			goto no_next;
+
+		host->dma_desc_next = desc;
+		host->data_next = data;
+		host->next_chan = chan;
+	}
+
+	return;
+
+ no_next:
+	host->dma_desc_next = NULL;
+	host->data_next = NULL;
+	host->next_chan = NULL;
 
-unmap_exit:
-	dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, direction);
-map_err:
-	chan->device->device_control(chan, DMA_TERMINATE_ALL, 0);
-	return -ENOMEM;
 }
 #else
 /* Blank functions if the DMA engine is not available */
@@ -472,10 +551,23 @@ static inline void mmci_dma_terminate(struct mmci_host *host)
 {
 }
 
-static inline int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl)
+static inline int mmci_dma_start_data(struct mmci_host *host)
 {
 	return -ENOSYS;
 }
+
+static inline int mmci_dma_start_fifo(struct mmci_host *host,
+				      unsigned int datactrl)
+{
+	return -ENOSYS;
+}
+
+static void mmci_dma_prepare(struct mmc_data *data, struct mmci_host *host)
+{
+}
+
+#define mmci_post_request NULL
+#define mmci_pre_request NULL
 #endif
 
 static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
@@ -519,7 +611,7 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
 		 * Attempt to use DMA operation mode, if this
 		 * should fail, fall back to PIO mode
 		 */
-		ret = mmci_dma_start_data(host, datactrl);
+		ret = mmci_dma_start_fifo(host, datactrl);
 		if (!ret)
 			return;
 	}
@@ -662,13 +754,6 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
 			mmci_stop_data(host);
 			host->dataend = false;
 
-			/*
-			 * Variants with broken blockend flags need to handle
-			 * the end of the entire transfer here.
-			 */
-			if (variant->broken_blockend && !data->error)
-				host->data_xfered += data->blksz * data->blocks;
-
 			if (!data->stop)
 				mmci_request_end(host, data->mrq);
 			else
@@ -705,6 +790,8 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
 		mmci_request_end(host, cmd->mrq);
 	} else if (!(cmd->data->flags & MMC_DATA_READ)) {
 		mmci_start_data(host, cmd->data);
+		if (host->dma_enable)
+			mmci_dma_start_data(host);
 	}
 }
 
@@ -944,6 +1031,13 @@ static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
 
 	mmci_start_command(host, mrq->cmd, 0);
 
+	if (host->dma_enable && mrq->data) {
+		mmci_dma_prepare(mrq->data, host);
+
+		if (mrq->data->flags & MMC_DATA_READ)
+			mmci_dma_start_data(host);
+	}
+
 	spin_unlock_irqrestore(&host->lock, flags);
 }
 
@@ -1053,6 +1147,8 @@ static irqreturn_t mmci_cd_irq(int irq, void *dev_id)
 
 static const struct mmc_host_ops mmci_ops = {
 	.request	= mmci_request,
+	.pre_req	= mmci_pre_request,
+	.post_req	= mmci_post_request,
 	.set_ios	= mmci_set_ios,
 	.get_ro		= mmci_get_ro,
 	.get_cd		= mmci_get_cd,
@@ -1180,15 +1276,7 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
 	 * single request.
 	 */
 	mmc->max_req_size = (1 << variant->datalength_bits) - 1;
-
-	/*
-	 * Set the maximum segment size. Right now DMA sets the
-	 * limit and not the data length register. Thus until the DMA
-	 * driver not handles this, the segment size is limited by DMA.
-	 * DMA limit: src_addr_width x (64 KB -1). src_addr_width
-	 * can be 1.
-	 */
-	mmc->max_seg_size = 65535;
+	mmc->max_seg_size = mmc->max_req_size;
 
 	/*
 	 * Block size can be up to 2048 bytes, but must be a power of two.
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index 39b7ac7..828ab5a 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -196,6 +196,10 @@ struct mmci_host {
 	struct dma_chan		*dma_rx_channel;
 	struct dma_chan		*dma_tx_channel;
 	struct dma_async_tx_descriptor *dma_desc;
+	struct dma_async_tx_descriptor *dma_desc_next;
+	struct mmc_data		*data_next;
+	struct dma_chan		*cur_chan;
+	struct dma_chan		*next_chan;
 #endif
 };
 
-- 
1.7.1

^ permalink raw reply related

* [PATCH 0/5] mmc: add double buffering for mmc block requests
From: Per Forlin @ 2011-01-12 18:24 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1294856043-13447-1-git-send-email-per.forlin@linaro.org>

I mistyped the linaro email in this patch series.

Sorry for the mess
/Per

On 12 January 2011 19:13, Per Forlin <per.forlin@linaro.org> wrote:
> Add support to prepare one MMC request while another is active on
> the host. This is done by making the issue_rw_rq() asynchronous.
> The increase in throughput is proportional to the time it takes to
> prepare a request and how fast the memory is. The faster the MMC/SD is
> the more significant the prepare request time becomes. Measurements on U5500
> and U8500 on eMMC shows significant performance gain for DMA on MMC for large
> reads. In the PIO case there is some gain in performance for large reads too.
> There seems to be no or small performance gain for write, don't have a good
> explanation for this yet.
>
> There are two optional hooks pre_req() and post_req() that the host driver
> may implement in order to improve double buffering. In the DMA case pre_req()
> may do dma_map_sg() and prepare the dma descriptor and post_req runs the
> dma_unmap_sg.
>
> The mmci host driver implementation for double buffering is not intended
> nor ready for mainline yet. It is only an example of how to implement
> pre_req() and post_req(). The reason for this is that the basic DMA support
> for MMCI is not complete yet. The mmci patches are sent in a separate patch
> series "[FYI 0/4] arm: mmci: example implementation of double buffering".
>
> Issues/Questions for issue_rw_rq() in block.c:
> * Is it safe to claim the host for the first MMC request and wait to release
> ?it until the MMC queue is empty again? Or must the host be claimed and
> ?released for every request?
> * Is it possible to predict the result from __blk_end_request().
> ?If there are no errors for a completed MMC request and the
> ?blk_rq_bytes(req) == data.bytes_xfered, will it be guaranteed that
> ?__blk_end_request will return 0?
>
> Here follows the IOZone results for u8500 v1.1 on eMMC.
> The numbers for DMA are a bit to good here due to the fact that the
> CPU speed is decreased compared to u8500 v2. This makes the cache handling
> even more significant.
>
> Command line used: ./iozone -az -i0 -i1 -i2 -s 50m -I -f /iozone.tmp -e -R -+u
>
> Relative diff: VANILLA-MMC-PIO -> 2BUF-MMC-PIO
> cpu load is abs diff
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?random ?random
> ? ? ? ?KB ? ? ?reclen ?write ? rewrite read ? ?reread ?read ? ?write
> ? ? ? ?51200 ? 4 ? ? ? +0% ? ? +0% ? ? +0% ? ? +0% ? ? +0% ? ? +0%
> ? ? ? ?cpu: ? ? ? ? ? ?+0.1 ? ?-0.1 ? ?-0.5 ? ?-0.3 ? ?-0.1 ? ?-0.0
>
> ? ? ? ?51200 ? 8 ? ? ? +0% ? ? +0% ? ? +6% ? ? +6% ? ? +8% ? ? +0%
> ? ? ? ?cpu: ? ? ? ? ? ?+0.1 ? ?-0.1 ? ?-0.3 ? ?-0.4 ? ?-0.8 ? ?+0.0
>
> ? ? ? ?51200 ? 16 ? ? ?+0% ? ? -2% ? ? +0% ? ? +0% ? ? -3% ? ? +0%
> ? ? ? ?cpu: ? ? ? ? ? ?+0.0 ? ?-0.2 ? ?+0.0 ? ?+0.0 ? ?-0.2 ? ?+0.0
>
> ? ? ? ?51200 ? 32 ? ? ?+0% ? ? +1% ? ? +0% ? ? +0% ? ? +0% ? ? +0%
> ? ? ? ?cpu: ? ? ? ? ? ?+0.1 ? ?+0.0 ? ?-0.3 ? ?+0.0 ? ?+0.0 ? ?+0.0
>
> ? ? ? ?51200 ? 64 ? ? ?+0% ? ? +0% ? ? +0% ? ? +0% ? ? +0% ? ? +0%
> ? ? ? ?cpu: ? ? ? ? ? ?+0.1 ? ?+0.0 ? ?+0.0 ? ?+0.0 ? ?+0.0 ? ?+0.0
>
> ? ? ? ?51200 ? 128 ? ? +0% ? ? +1% ? ? +1% ? ? +1% ? ? +1% ? ? +0%
> ? ? ? ?cpu: ? ? ? ? ? ?+0.0 ? ?+0.2 ? ?+0.1 ? ?-0.3 ? ?+0.4 ? ?+0.0
>
> ? ? ? ?51200 ? 256 ? ? +0% ? ? +0% ? ? +1% ? ? +1% ? ? +1% ? ? +0%
> ? ? ? ?cpu: ? ? ? ? ? ?+0.0 ? ?-0.0 ? ?+0.1 ? ?+0.1 ? ?+0.1 ? ?+0.0
>
> ? ? ? ?51200 ? 512 ? ? +0% ? ? +1% ? ? +2% ? ? +2% ? ? +2% ? ? +0%
> ? ? ? ?cpu: ? ? ? ? ? ?+0.1 ? ?+0.0 ? ?+0.2 ? ?+0.2 ? ?+0.2 ? ?+0.1
>
> ? ? ? ?51200 ? 1024 ? ?+0% ? ? +2% ? ? +2% ? ? +2% ? ? +3% ? ? +0%
> ? ? ? ?cpu: ? ? ? ? ? ?+0.2 ? ?+0.1 ? ?+0.2 ? ?+0.5 ? ?-0.8 ? ?+0.0
>
> ? ? ? ?51200 ? 2048 ? ?+0% ? ? +2% ? ? +3% ? ? +3% ? ? +3% ? ? +0%
> ? ? ? ?cpu: ? ? ? ? ? ?+0.0 ? ?-0.2 ? ?+0.4 ? ?+0.8 ? ?-0.5 ? ?+0.2
>
> ? ? ? ?51200 ? 4096 ? ?+0% ? ? +1% ? ? +3% ? ? +3% ? ? +3% ? ? +1%
> ? ? ? ?cpu: ? ? ? ? ? ?+0.2 ? ?+0.1 ? ?+0.9 ? ?+0.9 ? ?+0.5 ? ?+0.1
>
> ? ? ? ?51200 ? 8192 ? ?+1% ? ? +0% ? ? +3% ? ? +3% ? ? +3% ? ? +1%
> ? ? ? ?cpu: ? ? ? ? ? ?+0.2 ? ?+0.2 ? ?+1.3 ? ?+1.3 ? ?+1.0 ? ?+0.0
>
> ? ? ? ?51200 ? 16384 ? +0% ? ? +1% ? ? +3% ? ? +3% ? ? +3% ? ? +1%
> ? ? ? ?cpu: ? ? ? ? ? ?+0.2 ? ?+0.1 ? ?+1.0 ? ?+1.3 ? ?+1.0 ? ?+0.5
>
> Relative diff: VANILLA-MMC-DMA -> 2BUF-MMC-MMCI-DMA
> cpu load is abs diff
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?random ?random
> ? ? ? ?KB ? ? ?reclen ?write ? rewrite read ? ?reread ?read ? ?write
> ? ? ? ?51200 ? 4 ? ? ? +0% ? ? -3% ? ? +6% ? ? +5% ? ? +5% ? ? +0%
> ? ? ? ?cpu: ? ? ? ? ? ?+0.0 ? ?-0.2 ? ?-0.6 ? ?-0.1 ? ?+0.3 ? ?+0.0
>
> ? ? ? ?51200 ? 8 ? ? ? +0% ? ? +0% ? ? +7% ? ? +7% ? ? +7% ? ? +0%
> ? ? ? ?cpu: ? ? ? ? ? ?+0.0 ? ?+0.1 ? ?+0.8 ? ?+0.6 ? ?+0.9 ? ?+0.0
>
> ? ? ? ?51200 ? 16 ? ? ?+0% ? ? +0% ? ? +7% ? ? +7% ? ? +8% ? ? +0%
> ? ? ? ?cpu: ? ? ? ? ? ?+0.0 ? ?-0.0 ? ?+0.7 ? ?+0.7 ? ?+0.8 ? ?+0.0
>
> ? ? ? ?51200 ? 32 ? ? ?+0% ? ? +0% ? ? +8% ? ? +8% ? ? +9% ? ? +0%
> ? ? ? ?cpu: ? ? ? ? ? ?+0.0 ? ?+0.1 ? ?+0.7 ? ?+0.7 ? ?+0.3 ? ?+0.0
>
> ? ? ? ?51200 ? 64 ? ? ?+0% ? ? +1% ? ? +9% ? ? +9% ? ? +9% ? ? +0%
> ? ? ? ?cpu: ? ? ? ? ? ?+0.0 ? ?+0.0 ? ?+0.8 ? ?+0.7 ? ?+0.8 ? ?+0.0
>
> ? ? ? ?51200 ? 128 ? ? +1% ? ? +0% ? ? +13% ? ?+13% ? ?+14% ? ?+0%
> ? ? ? ?cpu: ? ? ? ? ? ?+0.2 ? ?+0.0 ? ?+1.0 ? ?+1.0 ? ?+1.1 ? ?+0.0
>
> ? ? ? ?51200 ? 256 ? ? +1% ? ? +2% ? ? +8% ? ? +8% ? ? +11% ? ?+0%
> ? ? ? ?cpu: ? ? ? ? ? ?+0.0 ? ?+0.3 ? ?+0.0 ? ?+0.7 ? ?+1.5 ? ?+0.0
>
> ? ? ? ?51200 ? 512 ? ? +1% ? ? +2% ? ? +16% ? ?+16% ? ?+17% ? ?+0%
> ? ? ? ?cpu: ? ? ? ? ? ?+0.2 ? ?+0.2 ? ?+2.2 ? ?+2.1 ? ?+2.2 ? ?+0.1
>
> ? ? ? ?51200 ? 1024 ? ?+1% ? ? +2% ? ? +20% ? ?+20% ? ?+20% ? ?+1%
> ? ? ? ?cpu: ? ? ? ? ? ?+0.2 ? ?+0.1 ? ?+2.6 ? ?+1.9 ? ?+2.6 ? ?+0.0
>
> ? ? ? ?51200 ? 2048 ? ?+0% ? ? +2% ? ? +22% ? ?+22% ? ?+21% ? ?+0%
> ? ? ? ?cpu: ? ? ? ? ? ?+0.0 ? ?+0.3 ? ?+2.3 ? ?+2.9 ? ?+2.1 ? ?-0.0
>
> ? ? ? ?51200 ? 4096 ? ?+1% ? ? +2% ? ? +23% ? ?+23% ? ?+23% ? ?+1%
> ? ? ? ?cpu: ? ? ? ? ? ?+0.2 ? ?+0.1 ? ?+2.0 ? ?+3.2 ? ?+3.1 ? ?+0.0
>
> ? ? ? ?51200 ? 8192 ? ?+1% ? ? +5% ? ? +24% ? ?+24% ? ?+24% ? ?+1%
> ? ? ? ?cpu: ? ? ? ? ? ?+1.4 ? ?-0.0 ? ?+4.2 ? ?+3.0 ? ?+2.8 ? ?+0.1
>
> ? ? ? ?51200 ? 16384 ? +1% ? ? +3% ? ? +24% ? ?+24% ? ?+24% ? ?+2%
> ? ? ? ?cpu: ? ? ? ? ? ?+0.0 ? ?+0.3 ? ?+3.4 ? ?+3.8 ? ?+3.7 ? ?+0.1
>
> Here follows the IOZone results for u5500 on eMMC.
> These numbers for DMA are more as expected.
>
> Command line used: ./iozone -az -i0 -i1 -i2 -s 50m -I -f /iozone.tmp -e -R -+u
>
> Relative diff: VANILLA-MMC-DMA -> 2BUF-MMC-MMCI-DMA
> cpu load is abs diff
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?random ?random
> ? ? ? ?KB ? ? ?reclen ?write ? rewrite read ? ?reread ?read ? ?write
> ? ? ? ?51200 ? 128 ? ? +1% ? ? +1% ? ? +10% ? ?+9% ? ? +10% ? ?+0%
> ? ? ? ?cpu: ? ? ? ? ? ?+0.1 ? ?+0.0 ? ?+1.3 ? ?+0.1 ? ?+0.8 ? ?+0.1
>
> ? ? ? ?51200 ? 256 ? ? +2% ? ? +2% ? ? +7% ? ? +7% ? ? +9% ? ? +0%
> ? ? ? ?cpu: ? ? ? ? ? ?+0.1 ? ?+0.4 ? ?+0.5 ? ?+0.6 ? ?+0.7 ? ?+0.0
>
> ? ? ? ?51200 ? 512 ? ? +2% ? ? +2% ? ? +12% ? ?+12% ? ?+12% ? ?+1%
> ? ? ? ?cpu: ? ? ? ? ? ?+0.4 ? ?+0.6 ? ?+1.8 ? ?+2.4 ? ?+2.4 ? ?+0.2
>
> ? ? ? ?51200 ? 1024 ? ?+2% ? ? +3% ? ? +14% ? ?+14% ? ?+14% ? ?+0%
> ? ? ? ?cpu: ? ? ? ? ? ?+0.3 ? ?+0.1 ? ?+2.1 ? ?+1.4 ? ?+1.4 ? ?+0.2
>
> ? ? ? ?51200 ? 2048 ? ?+3% ? ? +3% ? ? +16% ? ?+16% ? ?+16% ? ?+1%
> ? ? ? ?cpu: ? ? ? ? ? ?+0.2 ? ?+0.2 ? ?+2.5 ? ?+1.8 ? ?+2.4 ? ?-0.2
>
> ? ? ? ?51200 ? 4096 ? ?+3% ? ? +3% ? ? +17% ? ?+17% ? ?+18% ? ?+3%
> ? ? ? ?cpu: ? ? ? ? ? ?+0.1 ? ?-0.1 ? ?+2.7 ? ?+2.0 ? ?+2.7 ? ?-0.1
>
> ? ? ? ?51200 ? 8192 ? ?+3% ? ? +3% ? ? +18% ? ?+18% ? ?+18% ? ?+3%
> ? ? ? ?cpu: ? ? ? ? ? ?-0.1 ? ?+0.2 ? ?+3.0 ? ?+2.3 ? ?+2.2 ? ?+0.2
>
> ? ? ? ?51200 ? 16384 ? +3% ? ? +3% ? ? +18% ? ?+18% ? ?+18% ? ?+4%
> ? ? ? ?cpu: ? ? ? ? ? ?+0.2 ? ?+0.2 ? ?+2.8 ? ?+3.5 ? ?+2.4 ? ?-0.0
>
> Per Forlin (5):
> ?mmc: add member in mmc queue struct to hold request data
> ?mmc: Add a block request prepare function
> ?mmc: Add a second mmc queue request member
> ?mmc: Store the mmc block request struct in mmc queue
> ?mmc: Add double buffering for mmc block requests
>
> ?drivers/mmc/card/block.c | ?337 ++++++++++++++++++++++++++++++----------------
> ?drivers/mmc/card/queue.c | ?171 +++++++++++++++---------
> ?drivers/mmc/card/queue.h | ? 31 +++-
> ?drivers/mmc/core/core.c ?| ? 77 +++++++++--
> ?include/linux/mmc/core.h | ? ?7 +-
> ?include/linux/mmc/host.h | ? ?8 +
> ?6 files changed, 432 insertions(+), 199 deletions(-)
>
>

^ permalink raw reply

* ARM: relocation out of range (when loading a module)
From: Nicolas Pitre @ 2011-01-12 18:28 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <AANLkTimAFp7ORrJLw2d8-i5pK0MZGTyAN5kmRR37ky1v@mail.gmail.com>

On Wed, 12 Jan 2011, Dave Martin wrote:

> In general, do we expect always to be able to avoid the situation
> where branches in the kernel may need to cover too large a range ...
> and is there any strategy for working aroung it?

Normally we try to keep the code close together.  And at least for the 
.text section, the linker is able to insert indirect branch veneers when 
the range is too large.  But in the case of modules, it's the in-kernel 
code that perform the final symbol relocation.

> If we have problems branching from the modules area into vmlinux, we
> could possibly build modules with -fPIC : this would remove the
> restriction on branch range, though there would also be some
> performance impact for the modules...

If we really needed to do such thing, that would be even better to 
simply have the kernel create those indirect veneers dynamically.  And 
in fact, Russell had that working and he posted the corresponding patch 
many years ago, but the module placement was made so that the indirect 
branches were unnecessary.

Even now, it's probably a better idea to rework the section layout and 
preserve the ability to perform direct branches into the kernel from 
modules as much as possible.


Nicolas

^ permalink raw reply

* ARM: relocation out of range (when loading a module)
From: Russell King - ARM Linux @ 2011-01-12 18:42 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <alpine.LFD.2.00.1101121314470.25498@xanadu.home>

On Wed, Jan 12, 2011 at 01:28:23PM -0500, Nicolas Pitre wrote:
> If we really needed to do such thing, that would be even better to 
> simply have the kernel create those indirect veneers dynamically.  And 
> in fact, Russell had that working and he posted the corresponding patch 
> many years ago, but the module placement was made so that the indirect 
> branches were unnecessary.

Actually, it's something we used to do in 2.2 days when modules were
prepared and linked in userspace before being uploaded into kernel
space.  This allowed the module to be inteligently linked - so the
indirect branches were created only when they were necessary.

When the new kernel-based module linker happened, this presented a
chicken and egg problem with that approach, which give us a choice:
either place the module within range of the kernel text and guarantee
that the kernel text is reachable, or _always_ indirect every module
branch through a jump table even if it was reachable from where the
module was placed.

The decision was made to go with the former, so the latter never got
implemented.

Then came along the embedded initrd/initramfs idea which rather buggered
the scheme when large initramfs are embedded into the image.

As the overall feeling at the time was "don't use large initrds" it's
something I've never really cared about - and I'm still of the opinion
that 16MB of compressed initrd/initramfs is rather silly.

^ permalink raw reply

* [PATCHv8 00/12] Contiguous Memory Allocator
From: Marek Szyprowski @ 2011-01-12 18:49 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20101223134432.GJ3636@n2100.arm.linux.org.uk>

Hello,

I'm sorry for the delay. Just got back from my holidays and getting thought
the mails.

On Thursday, December 23, 2010 2:45 PM Russell King - ARM Linux wrote:

> On Thu, Dec 23, 2010 at 02:09:44PM +0100, Marek Szyprowski wrote:
> > Hello,
> >
> > On Thursday, December 23, 2010 1:19 PM Russell King - ARM Linux wrote:
> >
> > > On Thu, Dec 23, 2010 at 11:58:08AM +0100, Marek Szyprowski wrote:
> > > > Actually this contiguous memory allocator is a better replacement for
> > > > alloc_pages() which is used by dma_alloc_coherent(). It is a generic
> > > > framework that is not tied only to ARM architecture.
> > >
> > > ... which is open to abuse.  What I'm trying to find out is - if it
> > > can't be used for DMA, what is it to be used for?
> > >
> > > Or are we inventing an everything-but-ARM framework?
> >
> > We are trying to get something that really works and SOLVES some of the
> > problems with real devices that require contiguous memory for DMA.
> 
> So, here you've confirmed that it's for DMA.

Right, otherwise it wouldn't really make much sense. Note that our proposal
already works for non-arm platforms. 

> > > > > In other words, do we _actually_ have a use for this which doesn't
> > > > > involve doing something like allocating 32MB of memory from it,
> > > > > remapping it so that it's DMA coherent, and then performing DMA
> > > > > on the resulting buffer?
> > > >
> > > > This is an arm specific problem, also related to dma_alloc_coherent()
> > > > allocator. To be 100% conformant with ARM specification we would
> > > > probably need to unmap all pages used by the dma_coherent allocator
> > > > from the LOW MEM area. This is doable, but completely not related
> > > > to the CMA and this patch series.
> > >
> > > You've already been told why we can't unmap pages from the kernel
> > > direct mapping.
> >
> > It requires some amount of work but I see no reason why we shouldn't be
> > able to unmap that pages to stay 100% conformant with ARM spec.
> 
> I have considered - and tried - to do that with the dma_alloc_coherent()
> spec, but it is NOT POSSIBLE to do so - too many factors stand in the
> way of making it work, such as the need bring the system to a complete
> halt to modify all the L1 page tables and broadcast the TLB operations
> to invalidate the old mappings.  None of that can be done from all the
> contexts under which dma_alloc_coherent() is called from.

I understand that this requires a lot of work, but I still think this might
be possible to get it working with some additional constraints.

I understand that modifying L1 page tables is definitely not a proper way of
handling this. It simply costs too much. But what if we consider that the DMA
memory can be only allocated from a specific range of the system memory?
Assuming that this range of memory is known during the boot time, it CAN be
mapped with two-level of tables in MMU. First level mapping will stay the
same all the time for all processes, but it would be possible to unmap the
pages required for DMA from the second level mapping what will be visible
from all the processes at once.

Is there any reason why such solution won't work?

Best regards
--
Marek Szyprowski
Samsung Poland R&D Center

^ permalink raw reply

* ARM: relocation out of range (when loading a module)
From: Nicolas Pitre @ 2011-01-12 18:55 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20110112184258.GH11039@n2100.arm.linux.org.uk>

On Wed, 12 Jan 2011, Russell King - ARM Linux wrote:

> Then came along the embedded initrd/initramfs idea which rather buggered
> the scheme when large initramfs are embedded into the image.
> 
> As the overall feeling at the time was "don't use large initrds" it's
> something I've never really cared about - and I'm still of the opinion
> that 16MB of compressed initrd/initramfs is rather silly.

It is... but we have more than 32MB of RAM total now, and people are 
running standard distributions on ARM these days, such as Fedora or 
Ubuntu, including their corresponding initrd that may contain lots of 
modules, splashscreen data, etc.  So it might be a good idea to think 
about fixing this limitation before it comes back again.


Nicolas

^ permalink raw reply

* [PATCHv8 00/12] Contiguous Memory Allocator
From: Nicolas Pitre @ 2011-01-12 19:04 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <001c01cbb289$864391f0$92cab5d0$%szyprowski@samsung.com>

On Wed, 12 Jan 2011, Marek Szyprowski wrote:

> I understand that modifying L1 page tables is definitely not a proper way of
> handling this. It simply costs too much. But what if we consider that the DMA
> memory can be only allocated from a specific range of the system memory?
> Assuming that this range of memory is known during the boot time, it CAN be
> mapped with two-level of tables in MMU. First level mapping will stay the
> same all the time for all processes, but it would be possible to unmap the
> pages required for DMA from the second level mapping what will be visible
> from all the processes at once.

How much memory are we talking about?  What is the typical figure?

> Is there any reason why such solution won't work?

It could work indeed.

One similar solution that is already in place is to use highmem for that 
reclaimable DMA memory.  It is easy to ensure affected highmem pages are 
not mapped in kernel space.  And you can decide at boot time how many 
highmem pages you want even if the system has less that 1GB of RAM.


Nicolas

^ permalink raw reply

* [PATCH v2] arm: Defer vetting of atags to setup.c
From: Russell King - ARM Linux @ 2011-01-12 19:56 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20110112180257.6824.33147.stgit@localhost6.localdomain6>

The patch looks good to me, except for one small concerning point, which
I should've thought about earlier - sorry.

One of the things that __vet_atags does is to make sure that the data
pointed to by 'r2' is actually an atag list.

Historically, we haven't required boot loaders to set r2 to anything -
it used not to be defined to mean anything at all.  So with older boot
loaders, this could be pointing at anything - it all depends what the
boot loader code last did, and how the compiler optimized that code.

So, the __vet_atags asm tries dereferencing the values there after
checking that it's word aligned.  We hope that we won't hit a read-
sensitive device in doing so.  If we find a valid ATAG_CORE then we
allow the pointer.  If we don't find those magic words, then we zero.

For boot loaders which always pass valid r2 values, moving this code
after the MMU makes no difference.  For older boot loaders, it may be
that __phys_to_virt(r2) ends up pointing at unmapped memory, which will
cause a MMU abort - and as the vectors haven't been setup, that could
hang the kernel.

So I think this has to stay in assembly code to make sure it works as
required - to detect old boot loaders passing random values in r2 and
allow the old method (atag address in machine_desc struct) to work.

On Wed, Jan 12, 2011 at 11:03:07AM -0700, Grant Likely wrote:
> Since the debug macros no longer depend on atag data, the vetting can
> be deferred to setup_arch() in setup.c which simplifies the code
> somewhat.
> 
> This patch removes __vet_atags() from head.S and moves it setup_arch().
> I've tried to preserve the existing behaviour in this patch so the
> extra atags vetting is only using when CONFIG_MMU is selected.
> 
> v2: Move removal of __machine_type_lookup to a separate patch.
> 
> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
> ---
>  arch/arm/kernel/head-common.S |   51 +++++++----------------------------------
>  arch/arm/kernel/head.S        |    1 -
>  arch/arm/kernel/setup.c       |   16 +++++++++++++
>  3 files changed, 25 insertions(+), 43 deletions(-)
> 
> diff --git a/arch/arm/kernel/head-common.S b/arch/arm/kernel/head-common.S
> index c84b57d..8bb1829 100644
> --- a/arch/arm/kernel/head-common.S
> +++ b/arch/arm/kernel/head-common.S
> @@ -11,50 +11,8 @@
>   *
>   */
>  
> -#define ATAG_CORE 0x54410001
> -#define ATAG_CORE_SIZE ((2*4 + 3*4) >> 2)
> -#define ATAG_CORE_SIZE_EMPTY ((2*4) >> 2)
> -
> -/*
> - * Exception handling.  Something went wrong and we can't proceed.  We
> - * ought to tell the user, but since we don't have any guarantee that
> - * we're even running on the right architecture, we do virtually nothing.
> - *
> - * If CONFIG_DEBUG_LL is set we try to print out something about the error
> - * and hope for the best (useful if bootloader fails to pass a proper
> - * machine ID for example).
> - */
>  	__HEAD
>  
> -/* Determine validity of the r2 atags pointer.  The heuristic requires
> - * that the pointer be aligned, in the first 16k of physical RAM and
> - * that the ATAG_CORE marker is first and present.  Future revisions
> - * of this function may be more lenient with the physical address and
> - * may also be able to move the ATAGS block if necessary.
> - *
> - * Returns:
> - *  r2 either valid atags pointer, or zero
> - *  r5, r6 corrupted
> - */
> -__vet_atags:
> -	tst	r2, #0x3			@ aligned?
> -	bne	1f
> -
> -	ldr	r5, [r2, #0]			@ is first tag ATAG_CORE?
> -	cmp	r5, #ATAG_CORE_SIZE
> -	cmpne	r5, #ATAG_CORE_SIZE_EMPTY
> -	bne	1f
> -	ldr	r5, [r2, #4]
> -	ldr	r6, =ATAG_CORE
> -	cmp	r5, r6
> -	bne	1f
> -
> -	mov	pc, lr				@ atag pointer is ok
> -
> -1:	mov	r2, #0
> -	mov	pc, lr
> -ENDPROC(__vet_atags)
> -
>  /*
>   * The following fragment of code is executed with the MMU on in MMU mode,
>   * and uses absolute addresses; this is not position independent.
> @@ -158,6 +116,15 @@ __lookup_processor_type_data:
>  	.long	__proc_info_end
>  	.size	__lookup_processor_type_data, . - __lookup_processor_type_data
>  
> +/*
> + * Exception handling.  Something went wrong and we can't proceed.  We
> + * ought to tell the user, but since we don't have any guarantee that
> + * we're even running on the right architecture, we do virtually nothing.
> + *
> + * If CONFIG_DEBUG_LL is set we try to print out something about the error
> + * and hope for the best (useful if bootloader fails to pass a proper
> + * machine ID for example).
> + */
>  __error_p:
>  #ifdef CONFIG_DEBUG_LL
>  	adr	r0, str_p1
> diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
> index 19f3909..4b0cf4a 100644
> --- a/arch/arm/kernel/head.S
> +++ b/arch/arm/kernel/head.S
> @@ -92,7 +92,6 @@ ENTRY(stext)
>  	 * r1 = machine no, r2 = atags,
>  	 * r9 = cpuid, r10 = procinfo
>  	 */
> -	bl	__vet_atags
>  #ifdef CONFIG_SMP_ON_UP
>  	bl	__fixup_smp
>  #endif
> diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
> index 77266a8..47cf110 100644
> --- a/arch/arm/kernel/setup.c
> +++ b/arch/arm/kernel/setup.c
> @@ -851,6 +851,22 @@ void __init setup_arch(char **cmdline_p)
>  	if (mdesc->soft_reboot)
>  		reboot_setup("s");
>  
> +#if defined(CONFIG_MMU)
> +	/*
> +	 * Determine validity of the atags pointer.  The heuristic requires
> +	 * that the pointer be aligned, and that the ATAG_CORE marker is
> +	 * first and present.
> +	 */
> +	if (__atags_pointer & 0x3)
> +		__atags_pointer = 0;
> +	if (__atags_pointer) {
> +		struct tag *t = phys_to_virt(__atags_pointer);
> +		if ((t->hdr.size != tag_size(tag_core)) &&
> +		    (t->hdr.size != sizeof(struct tag_header)) &&
> +		    (t->hdr.tag != ATAG_CORE))
> +			__atags_pointer = 0;
> +	}
> +#endif
>  	if (__atags_pointer)
>  		tags = phys_to_virt(__atags_pointer);
>  	else if (mdesc->boot_params)
> 

^ permalink raw reply

* BUG: spinlock recursion (sys_chdir, user_path_at, do_path_lookup ...)
From: Ramirez Luna, Omar @ 2011-01-12 20:59 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

I picked this mail from google so I might be missing some recipients.

On Wed, 12 Jan 2011, Russell King - ARM Linux wrote:
> On Wed, Jan 12, 2011 at 12:35:08PM +0000, Russell King - ARM Linux wrote:
> > ARM doesn't implement save_stack_trace_regs() nor save_stack_trace_bp()
> > so if the compiler referenced these, you'd have a kernel which doesn't
> > link.  The only places that this symbol appears is:
> >
> > arch/x86/kernel/stacktrace.c:void save_stack_trace_regs(struct stack_trace *trac
> > arch/x86/mm/kmemcheck/error.c:  save_stack_trace_regs(&e->trace, regs);
> > include/linux/stacktrace.h:extern void save_stack_trace_regs(struct stack_trace
> >
> > So, if this is where your bisect decided was the problem, your bisect
> > was faulty.
>
> BTW, a useful thing to do after a bisect is to return to the point in
> the history where you first noticed the regression (so Linus' tip,
> your tip, or whatever).  Then try reverting the commit which git bisect
> _thinks_ is the cause of your problem and re-test that.
>
> If the problem is fixed, you have greater confidence that the commit is
> the problem.

Reverting this commit (9c0729dc8062bed96189bd14ac6d4920f3958743 )
didn't improve in my case.

> If it made no difference, then you know that something else (maybe in
> combination) is causing the problem.

I tried to narrow it down using the dump and another thread mentioning
recent changes from "Nick" (might be Nick Piggin).

Reverting: fs: rcu-walk aware d_revalidate method
commit: 34286d6662308d82aed891852d04c7c3a2649b16

Seems to get rid of the bug, hopefully it will give more information
to someone more experienced with this code (than me).

Regards,

Omar

^ permalink raw reply

* BUG: spinlock recursion (sys_chdir, user_path_at, do_path_lookup ...)
From: Uwe Kleine-König @ 2011-01-12 21:02 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <AANLkTimb3i4BiuXvnCdhXn-xnN==NjVg8MDLsDkuFwLC@mail.gmail.com>

Hello Omar,

On Wed, Jan 12, 2011 at 02:59:39PM -0600, Ramirez Luna, Omar wrote:
> I picked this mail from google so I might be missing some recipients.
> 
> On Wed, 12 Jan 2011, Russell King - ARM Linux wrote:
> > On Wed, Jan 12, 2011 at 12:35:08PM +0000, Russell King - ARM Linux wrote:
> > > ARM doesn't implement save_stack_trace_regs() nor save_stack_trace_bp()
> > > so if the compiler referenced these, you'd have a kernel which doesn't
> > > link.  The only places that this symbol appears is:
> > >
> > > arch/x86/kernel/stacktrace.c:void save_stack_trace_regs(struct stack_trace *trac
> > > arch/x86/mm/kmemcheck/error.c:  save_stack_trace_regs(&e->trace, regs);
> > > include/linux/stacktrace.h:extern void save_stack_trace_regs(struct stack_trace
> > >
> > > So, if this is where your bisect decided was the problem, your bisect
> > > was faulty.
> >
> > BTW, a useful thing to do after a bisect is to return to the point in
> > the history where you first noticed the regression (so Linus' tip,
> > your tip, or whatever).  Then try reverting the commit which git bisect
> > _thinks_ is the cause of your problem and re-test that.
> >
> > If the problem is fixed, you have greater confidence that the commit is
> > the problem.
> 
> Reverting this commit (9c0729dc8062bed96189bd14ac6d4920f3958743 )
> didn't improve in my case.
Yeah, my bisect was screwed because I somehow changed .config in the
middle ...

You're on ARM, too?

> > If it made no difference, then you know that something else (maybe in
> > combination) is causing the problem.
> 
> I tried to narrow it down using the dump and another thread mentioning
> recent changes from "Nick" (might be Nick Piggin).
> 
> Reverting: fs: rcu-walk aware d_revalidate method
> commit: 34286d6662308d82aed891852d04c7c3a2649b16
I found that one, too, in the meantime.  Currently debugging that with
tglx on irc.

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-K?nig            |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

^ permalink raw reply

* BUG: spinlock recursion (sys_chdir, user_path_at, do_path_lookup ...)
From: Ramirez Luna, Omar @ 2011-01-12 21:16 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20110112210241.GM24920@pengutronix.de>

Hi Uwe,

2011/1/12 Uwe Kleine-K?nig <u.kleine-koenig@pengutronix.de>:
> You're on ARM, too?

Yes, ARMv7 (zoom2).

>> > If it made no difference, then you know that something else (maybe in
>> > combination) is causing the problem.
>>
>> I tried to narrow it down using the dump and another thread mentioning
>> recent changes from "Nick" (might be Nick Piggin).
>>
>> Reverting: fs: rcu-walk aware d_revalidate method
>> commit: 34286d6662308d82aed891852d04c7c3a2649b16
> I found that one, too, in the meantime. ?Currently debugging that with
> tglx on irc.

OK, let me know if I can help.

Regards,

Omar

^ permalink raw reply

* Bug: loops_per_jiffy based udelay() mostly shorter than requested
From: Linus Torvalds @ 2011-01-12 21:19 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20110109170829.GA14252@flint.arm.linux.org.uk>

On Sun, Jan 9, 2011 at 9:08 AM, Russell King <rmk@arm.linux.org.uk> wrote:
>
> Any suggestions or thoughts, or should we not care too much if udelay()
> produces slightly shorter than desired delays? ?Or am I doing something
> horribly wrong in the ARM code?

Judging by the numbers you quote, I would definitely put this in the
"don't care too much".

If it's about 1% off, it's all fine. If somebody picked a delay value
that is so sensitive to small errors in the delay that they notice
that - or even notice something like 5% - then they have picked too
short of a delay.

udelay() was never really meant to be some kind of precision
instrument. Especially with CPU's running at different frequencies,
we've historically had some rather wild fluctuation. The traditional
busy loop ends up being affected not just by interrupts, but also by
things like cache alignment (we used to inline it), and then later the
TSC-based one obviously depended on TSC's being stable (which they
weren't for a while).

So historically, we've seen udelay() being _really_ off (ie 50% off
etc), I wouldn't worry about things in the 1% range.

                       Linus

^ permalink raw reply

* [PATCH v2 3/3] ARM: twd_smp: add clock api support
From: Rob Herring @ 2011-01-12 21:28 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20101221134515.GB1556@n2100.arm.linux.org.uk>

Russell,

On 12/21/2010 07:45 AM, Russell King - ARM Linux wrote:
> On Sat, Oct 02, 2010 at 09:34:46AM -0500, Rob Herring wrote:
>> From: Rob Herring<rob.herring@smooth-stone.com>
>>
>> The private timer freq is currently dynamically detected
>> using jiffies count to determine the rate. This method adds
>> a delay to boot-up, so use the clock api instead to get the
>> clock rate.
> More or less the same comments go for this as well as the timer-sp code.

I've implemented your requested changes for timer-sp code. The problem 
with doing the same thing with smp_twd timer is I don't know what the 
frequency of the timer is on various platforms or an understanding of 
what their clock trees look like to do a proper implementation of the 
clocks. I could make calling twd_timer_init mandatory and replace direct 
setting of twd_base, but it would still fall back to calculating the 
rate if no clock found. These are the current users:

mach-omap2/timer-gp.c
mach-realview/realview_eb.c
mach-realview/realview_pb11mp.c
mach-realview/realview_pbx.c
mach-s5pv310/time.c
mach-shmobile/smp-sh73a0.c
mach-tegra/timer.c
mach-ux500/cpu.c
mach-vexpress/ct-ca9x4.c

Rob

^ permalink raw reply

* mmaping a fixed address fails on ARM
From: Bryan Wu @ 2011-01-12 21:58 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Russell,

Andre posted a mmap testcase [1] and a bug report [2] for Ubuntu
kernel on OMAP4 system, since he is porting some applications from x86
to ARM. He testcase works fine on x86, but always fail on ARM. I've
tested it on OMAP3/OMAP4/i.MX51.

Basically what he want to do is get a mapping on a specific virtual
address. But AFAIK, mmap doesn't make sure we can get the mapping
address as we want. On x86, it works fine. So if this fails, the
application can't run on ARM.

The implementation of arch_get_unmapped_area() is different from ARM
and x86, that might makes mmap behavior different between ARM and x86.
Andre said 2.6.28-versatile. I'm not sure whether it is a regression.

[1]: http://launchpadlibrarian.net/61588086/main.c
[2]: https://bugs.launchpad.net/ubuntu/+source/linux-ti-omap4/+bug/697004

Thanks,
-- 
Bryan Wu <bryan.wu@canonical.com>
Kernel Developer ? ?+86.138-1617-6545 Mobile
Ubuntu Kernel Team
Canonical Ltd. ? ? ?www.canonical.com
Ubuntu - Linux for human beings | www.ubuntu.com

^ permalink raw reply

* mmaping a fixed address fails on ARM
From: Bryan Wu @ 2011-01-12 22:05 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <AANLkTin0jjxLTWzkLHnJ+sGQz=jdDDL94R9o1gh-rO9P@mail.gmail.com>

Let me add Andre here

Thanks,
-Bryan

On Thu, Jan 13, 2011 at 5:58 AM, Bryan Wu <bryan.wu@canonical.com> wrote:
> Hi Russell,
>
> Andre posted a mmap testcase [1] and a bug report [2] for Ubuntu
> kernel on OMAP4 system, since he is porting some applications from x86
> to ARM. He testcase works fine on x86, but always fail on ARM. I've
> tested it on OMAP3/OMAP4/i.MX51.
>
> Basically what he want to do is get a mapping on a specific virtual
> address. But AFAIK, mmap doesn't make sure we can get the mapping
> address as we want. On x86, it works fine. So if this fails, the
> application can't run on ARM.
>
> The implementation of arch_get_unmapped_area() is different from ARM
> and x86, that might makes mmap behavior different between ARM and x86.
> Andre said 2.6.28-versatile. I'm not sure whether it is a regression.
>
> [1]: http://launchpadlibrarian.net/61588086/main.c
> [2]: https://bugs.launchpad.net/ubuntu/+source/linux-ti-omap4/+bug/697004
>
> Thanks,
> --
> Bryan Wu <bryan.wu@canonical.com>
> Kernel Developer ? ?+86.138-1617-6545 Mobile
> Ubuntu Kernel Team
> Canonical Ltd. ? ? ?www.canonical.com
> Ubuntu - Linux for human beings | www.ubuntu.com
>

^ permalink raw reply

* Bug: loops_per_jiffy based udelay() mostly shorter than requested
From: Russell King - ARM Linux @ 2011-01-12 22:23 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <AANLkTik5BmZAOFdYVGAjuoHftQ3qh1oTCEr5MpkCiDVz@mail.gmail.com>

On Wed, Jan 12, 2011 at 01:19:49PM -0800, Linus Torvalds wrote:
> On Sun, Jan 9, 2011 at 9:08 AM, Russell King <rmk@arm.linux.org.uk> wrote:
> >
> > Any suggestions or thoughts, or should we not care too much if udelay()
> > produces slightly shorter than desired delays? ?Or am I doing something
> > horribly wrong in the ARM code?
> 
> Judging by the numbers you quote, I would definitely put this in the
> "don't care too much".

Thanks - that's my thoughts too.  I think I'm still going to push out
the rounding patch for the sake of correctness even though it's down
in the noise.

^ permalink raw reply

* [PATCH 5/5 v2] ARM: pxa: Fix recursive call of pxa_(un)mask_low_gpio()
From: Marek Vasut @ 2011-01-12 22:29 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <AANLkTikOUHOC2nrfKpcO=rE=CbdthvU0JxbCtOc1piSK@mail.gmail.com>

On Wednesday 12 January 2011 00:16:50 Eric Miao wrote:
> The original intention is to re-use pxa_{mask,unmask}_irq(), will
> the change below looks better? The move of irq_base() is to avoid
> the error of function not declared.
> 
> diff --git a/arch/arm/mach-pxa/irq.c b/arch/arm/mach-pxa/irq.c
> index a7deff5..6107253 100644
> --- a/arch/arm/mach-pxa/irq.c
> +++ b/arch/arm/mach-pxa/irq.c
> @@ -53,6 +53,17 @@ static inline int cpu_has_ipr(void)
>  	return !cpu_is_pxa25x();
>  }
> 
> +static inline void __iomem *irq_base(int i)
> +{
> +	static unsigned long phys_base[] = {
> +		0x40d00000,
> +		0x40d0009c,
> +		0x40d00130,
> +	};
> +
> +	return (void __iomem *)io_p2v(phys_base[i]);
> +}
> +
>  static void pxa_mask_irq(unsigned int irq)
>  {
>  	void __iomem *base = get_irq_chip_data(irq);
> @@ -108,25 +119,11 @@ static void pxa_ack_low_gpio(unsigned int irq)
>  	GEDR0 = (1 << (irq - IRQ_GPIO0));
>  }
> 
> -static void pxa_mask_low_gpio(unsigned int irq)
> -{
> -	struct irq_desc *desc = irq_to_desc(irq);
> -
> -	desc->chip->mask(irq);
> -}
> -
> -static void pxa_unmask_low_gpio(unsigned int irq)
> -{
> -	struct irq_desc *desc = irq_to_desc(irq);
> -
> -	desc->chip->unmask(irq);
> -}
> -
>  static struct irq_chip pxa_low_gpio_chip = {
>  	.name		= "GPIO-l",
>  	.ack		= pxa_ack_low_gpio,
> -	.mask		= pxa_mask_low_gpio,
> -	.unmask		= pxa_unmask_low_gpio,
> +	.mask		= pxa_mask_irq,
> +	.unmask		= pxa_unmask_irq,
>  	.set_type	= pxa_set_low_gpio_type,
>  };
> 
> @@ -141,6 +138,7 @@ static void __init pxa_init_low_gpio_irq(set_wake_t fn)
> 
>  	for (irq = IRQ_GPIO0; irq <= IRQ_GPIO1; irq++) {
>  		set_irq_chip(irq, &pxa_low_gpio_chip);
> +		set_irq_chip_data(irq, irq_base(0));
>  		set_irq_handler(irq, handle_edge_irq);
>  		set_irq_flags(irq, IRQF_VALID);
>  	}
> @@ -148,17 +146,6 @@ static void __init pxa_init_low_gpio_irq(set_wake_t
> fn) pxa_low_gpio_chip.set_wake = fn;
>  }
> 
> -static inline void __iomem *irq_base(int i)
> -{
> -	static unsigned long phys_base[] = {
> -		0x40d00000,
> -		0x40d0009c,
> -		0x40d00130,
> -	};
> -
> -	return (void __iomem *)io_p2v(phys_base[i]);
> -}
> -
>  void __init pxa_init_irq(int irq_nr, set_wake_t fn)
>  {
>  	int irq, i, n;

Way better indeed

Acked-by: Marek Vasut <marek.vasut@gmail.com>

> 
> On Mon, Jan 10, 2011 at 4:53 PM, Marek Vasut <marek.vasut@gmail.com> wrote:
> > Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
> > ---
> > v2: Remove dead code as proposed by Sergei
> > 
> >  arch/arm/mach-pxa/irq.c |    8 ++------
> >  1 files changed, 2 insertions(+), 6 deletions(-)
> > 
> > diff --git a/arch/arm/mach-pxa/irq.c b/arch/arm/mach-pxa/irq.c
> > index a7deff5..76e69cf 100644
> > --- a/arch/arm/mach-pxa/irq.c
> > +++ b/arch/arm/mach-pxa/irq.c
> > @@ -110,16 +110,12 @@ static void pxa_ack_low_gpio(unsigned int irq)
> > 
> >  static void pxa_mask_low_gpio(unsigned int irq)
> >  {
> > -       struct irq_desc *desc = irq_to_desc(irq);
> > -
> > -       desc->chip->mask(irq);
> > +       pxa_mask_irq(irq);
> >  }
> > 
> >  static void pxa_unmask_low_gpio(unsigned int irq)
> >  {
> > -       struct irq_desc *desc = irq_to_desc(irq);
> > -
> > -       desc->chip->unmask(irq);
> > +       pxa_unmask_irq(irq);
> >  }
> > 
> >  static struct irq_chip pxa_low_gpio_chip = {
> > --
> > 1.7.2.3

^ permalink raw reply

* [PATCH 5/5 v2] ARM: pxa: Fix recursive call of pxa_(un)mask_low_gpio()
From: Marek Vasut @ 2011-01-12 22:30 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <AANLkTikOUHOC2nrfKpcO=rE=CbdthvU0JxbCtOc1piSK@mail.gmail.com>

On Wednesday 12 January 2011 00:16:50 Eric Miao wrote:
> The original intention is to re-use pxa_{mask,unmask}_irq(), will
> the change below looks better? The move of irq_base() is to avoid
> the error of function not declared.

Here's your :

Tested-by: Marek Vasut <marek.vasut@gmail.com>

Tested on Zipit Z2
> 
> diff --git a/arch/arm/mach-pxa/irq.c b/arch/arm/mach-pxa/irq.c
> index a7deff5..6107253 100644
> --- a/arch/arm/mach-pxa/irq.c
> +++ b/arch/arm/mach-pxa/irq.c
> @@ -53,6 +53,17 @@ static inline int cpu_has_ipr(void)
>  	return !cpu_is_pxa25x();
>  }
> 
> +static inline void __iomem *irq_base(int i)
> +{
> +	static unsigned long phys_base[] = {
> +		0x40d00000,
> +		0x40d0009c,
> +		0x40d00130,
> +	};
> +
> +	return (void __iomem *)io_p2v(phys_base[i]);
> +}
> +
>  static void pxa_mask_irq(unsigned int irq)
>  {
>  	void __iomem *base = get_irq_chip_data(irq);
> @@ -108,25 +119,11 @@ static void pxa_ack_low_gpio(unsigned int irq)
>  	GEDR0 = (1 << (irq - IRQ_GPIO0));
>  }
> 
> -static void pxa_mask_low_gpio(unsigned int irq)
> -{
> -	struct irq_desc *desc = irq_to_desc(irq);
> -
> -	desc->chip->mask(irq);
> -}
> -
> -static void pxa_unmask_low_gpio(unsigned int irq)
> -{
> -	struct irq_desc *desc = irq_to_desc(irq);
> -
> -	desc->chip->unmask(irq);
> -}
> -
>  static struct irq_chip pxa_low_gpio_chip = {
>  	.name		= "GPIO-l",
>  	.ack		= pxa_ack_low_gpio,
> -	.mask		= pxa_mask_low_gpio,
> -	.unmask		= pxa_unmask_low_gpio,
> +	.mask		= pxa_mask_irq,
> +	.unmask		= pxa_unmask_irq,
>  	.set_type	= pxa_set_low_gpio_type,
>  };
> 
> @@ -141,6 +138,7 @@ static void __init pxa_init_low_gpio_irq(set_wake_t fn)
> 
>  	for (irq = IRQ_GPIO0; irq <= IRQ_GPIO1; irq++) {
>  		set_irq_chip(irq, &pxa_low_gpio_chip);
> +		set_irq_chip_data(irq, irq_base(0));
>  		set_irq_handler(irq, handle_edge_irq);
>  		set_irq_flags(irq, IRQF_VALID);
>  	}
> @@ -148,17 +146,6 @@ static void __init pxa_init_low_gpio_irq(set_wake_t
> fn) pxa_low_gpio_chip.set_wake = fn;
>  }
> 
> -static inline void __iomem *irq_base(int i)
> -{
> -	static unsigned long phys_base[] = {
> -		0x40d00000,
> -		0x40d0009c,
> -		0x40d00130,
> -	};
> -
> -	return (void __iomem *)io_p2v(phys_base[i]);
> -}
> -
>  void __init pxa_init_irq(int irq_nr, set_wake_t fn)
>  {
>  	int irq, i, n;
> 
> On Mon, Jan 10, 2011 at 4:53 PM, Marek Vasut <marek.vasut@gmail.com> wrote:
> > Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
> > ---
> > v2: Remove dead code as proposed by Sergei
> > 
> >  arch/arm/mach-pxa/irq.c |    8 ++------
> >  1 files changed, 2 insertions(+), 6 deletions(-)
> > 
> > diff --git a/arch/arm/mach-pxa/irq.c b/arch/arm/mach-pxa/irq.c
> > index a7deff5..76e69cf 100644
> > --- a/arch/arm/mach-pxa/irq.c
> > +++ b/arch/arm/mach-pxa/irq.c
> > @@ -110,16 +110,12 @@ static void pxa_ack_low_gpio(unsigned int irq)
> > 
> >  static void pxa_mask_low_gpio(unsigned int irq)
> >  {
> > -       struct irq_desc *desc = irq_to_desc(irq);
> > -
> > -       desc->chip->mask(irq);
> > +       pxa_mask_irq(irq);
> >  }
> > 
> >  static void pxa_unmask_low_gpio(unsigned int irq)
> >  {
> > -       struct irq_desc *desc = irq_to_desc(irq);
> > -
> > -       desc->chip->unmask(irq);
> > +       pxa_unmask_irq(irq);
> >  }
> > 
> >  static struct irq_chip pxa_low_gpio_chip = {
> > --
> > 1.7.2.3

^ permalink raw reply

* [PATCH/RFC 0/3] ARM: S5P: Add a common platform setup code for MIPI CSIS/DSIM
From: Kukjin Kim @ 2011-01-12 22:34 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <4D2D92F9.3000902@gmail.com>

Sylwester Nawrocki wrote:
> 
> On 01/04/2011 04:09 PM, Sylwester Nawrocki wrote:
> > Hello,
> >
> > the following patch series adds the common platform code for configuration
> > of the MIPI CSIS and MIPI DSIM PHYs on S5PV210 and S5PV310 SoCs.
> > The spinlock is used to avoid races while the common PHY control register
> > is accessed from within MIPI DSIM and MIPI CSIS drivers.
> > The common PHY enable bit is cleared only when both CSIS and DSIM devices
> > are not in use.
> >
> >
> > The patch series contains:
> >
> > [PATCH/RFC 1/3] ARM: S5P: Add a platform callback for MIPI CSIS PHY control
> > [PATCH/RFC 2/3] ARM: S5PV310: Add a platform helper for MIPI DSIM/CSIS
> setup
> > [PATCH/RFC 3/3] ARM: S5PV210: Add a platform helper for MIPI DSIM/CSIS
> setup
> >
> 
> Any comments on this one?
> 
Hi,

It's 38 merge window now. So I want to wait until after this merge window.

Thanks.

Best regards,
Kgene.
--
Kukjin Kim <kgene.kim@samsung.com>, Senior Engineer,
SW Solution Development Team, Samsung Electronics Co., Ltd.

^ permalink raw reply

* [PATCH] ARM: use memblock memory regions for "System RAM" I/O resources
From: Dima Zavin @ 2011-01-12 22:35 UTC (permalink / raw)
  To: linux-arm-kernel

Do not use memory bank info to request the "system ram" resources as
they do not track holes created by memblock_remove inside
machine's reserve callback. If the removed memory is passed as
platform_device's ioresource, then drivers that call
request_mem_region would fail due to a conflict with the incorrectly
configured system ram resource.

Instead, iterate through the regions of memblock.memory and add
those as "System RAM" resources.

Signed-off-by: Dima Zavin <dima@android.com>
---
 arch/arm/kernel/setup.c |   10 ++++------
 1 files changed, 4 insertions(+), 6 deletions(-)

diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 336f14e..c3aa394 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -520,6 +520,7 @@ setup_ramdisk(int doload, int prompt, int image_start, unsigned int rd_sz)
 static void __init
 request_standard_resources(struct meminfo *mi, struct machine_desc *mdesc)
 {
+	struct memblock_type *mem = &memblock.memory;
 	struct resource *res;
 	int i;
 
@@ -528,14 +529,11 @@ request_standard_resources(struct meminfo *mi, struct machine_desc *mdesc)
 	kernel_data.start   = virt_to_phys(_sdata);
 	kernel_data.end     = virt_to_phys(_end - 1);
 
-	for (i = 0; i < mi->nr_banks; i++) {
-		if (mi->bank[i].size == 0)
-			continue;
-
+	for (i = 0; i < mem->cnt; i++) {
 		res = alloc_bootmem_low(sizeof(*res));
 		res->name  = "System RAM";
-		res->start = mi->bank[i].start;
-		res->end   = mi->bank[i].start + mi->bank[i].size - 1;
+		res->start = mem->regions[i].base;
+		res->end   = mem->regions[i].base + mem->regions[i].size - 1;
 		res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
 
 		request_resource(&iomem_resource, res);
-- 
1.7.3.1

^ permalink raw reply related

* BUG: spinlock recursion (sys_chdir, user_path_at, do_path_lookup ...)
From: Thomas Gleixner @ 2011-01-12 22:52 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20110112210241.GM24920@pengutronix.de>

On Wed, 12 Jan 2011, Uwe Kleine-K?nig wrote:
> > Reverting: fs: rcu-walk aware d_revalidate method
> > commit: 34286d6662308d82aed891852d04c7c3a2649b16
> I found that one, too, in the meantime.  Currently debugging that with
> tglx on irc.

The last finding is that parent and dentry in
nameidata_dentry_drop_rcu() are the same, which explains the lock
recursion nicely. 

@nick: Anything you want us to add to the debugging ?

@peterz: Why does lockdep ignore the lock recursion in that
	 spin_lock_nested() call?

Thanks,

	tglx

^ permalink raw reply

* [PATCH 1/2] mach-mmp: MMP2 Drive Strength FAST using wrong value
From: Eric Miao @ 2011-01-12 23:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <DE4BADCB-9705-427A-B80E-BB45B8678ACB@marvell.com>

On Fri, Jan 7, 2011 at 1:26 PM, Philip Rakity <prakity@marvell.com> wrote:
>
> Drive strength for MMP2 is a 2 bit value but because of the mapping in
> plat-pxa/mfp.h needs to be shifted up one bit to handle real
> location in mfp registers. ?(MMP2 and PXA910 drive strength start
> at bit 11 while PXA168 starts at bit 10).
>
> Values 0, 1, 2, and 3 effectively need to be
> 0, 2, 4, and 6 to fit into register. ?8 does not work.
>
> Signed-off-by: Philip Rakity <prakity@marvell.com>
> Tested-by: John Watlington <wad@laptop.org>

Applied.

> ---
> ?arch/arm/mach-mmp/include/mach/mfp-mmp2.h | ? ?2 +-
> ?1 files changed, 1 insertions(+), 1 deletions(-)
>
> diff --git a/arch/arm/mach-mmp/include/mach/mfp-mmp2.h b/arch/arm/mach-mmp/include/mach/mfp-mmp2.h
> index 117e303..4ad3862 100644
> --- a/arch/arm/mach-mmp/include/mach/mfp-mmp2.h
> +++ b/arch/arm/mach-mmp/include/mach/mfp-mmp2.h
> @@ -6,7 +6,7 @@
> ?#define MFP_DRIVE_VERY_SLOW ? ?(0x0 << 13)
> ?#define MFP_DRIVE_SLOW ? ? ? ? (0x2 << 13)
> ?#define MFP_DRIVE_MEDIUM ? ? ? (0x4 << 13)
> -#define MFP_DRIVE_FAST ? ? ? ? (0x8 << 13)
> +#define MFP_DRIVE_FAST ? ? ? ? (0x6 << 13)
>
> ?/* GPIO */
> ?#define GPIO0_GPIO ? ? MFP_CFG(GPIO0, AF0)
> --
> 1.7.0.4
>
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>

^ permalink raw reply

* [PATCH] ARM: use memblock memory regions for "System RAM" I/O resources
From: Russell King - ARM Linux @ 2011-01-12 23:11 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1294871757-11391-1-git-send-email-dima@android.com>

On Wed, Jan 12, 2011 at 02:35:57PM -0800, Dima Zavin wrote:
> Do not use memory bank info to request the "system ram" resources as
> they do not track holes created by memblock_remove inside
> machine's reserve callback. If the removed memory is passed as
> platform_device's ioresource, then drivers that call
> request_mem_region would fail due to a conflict with the incorrectly
> configured system ram resource.
> 
> Instead, iterate through the regions of memblock.memory and add
> those as "System RAM" resources.
> 
> Signed-off-by: Dima Zavin <dima@android.com>
> ---
>  arch/arm/kernel/setup.c |   10 ++++------
>  1 files changed, 4 insertions(+), 6 deletions(-)
> 
> diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
> index 336f14e..c3aa394 100644
> --- a/arch/arm/kernel/setup.c
> +++ b/arch/arm/kernel/setup.c
> @@ -520,6 +520,7 @@ setup_ramdisk(int doload, int prompt, int image_start, unsigned int rd_sz)
>  static void __init
>  request_standard_resources(struct meminfo *mi, struct machine_desc *mdesc)

Doesn't this means we can get rid of the 'mi' argument?

^ 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