LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 8/8] spi_mpc8xxx: Add support for QE DMA mode and CPM1/CPM2 chips
From: Anton Vorontsov @ 2009-08-18 22:04 UTC (permalink / raw)
  To: David Brownell
  Cc: Greg Kroah-Hartman, linux-kernel, linuxppc-dev, spi-devel-general,
	Andrew Morton
In-Reply-To: <20090818220304.GA23640@oksana.dev.rtsoft.ru>

This patch adds QE buffer descriptors mode support for the
spi_mpc8xxx driver, and as a side effect we now support CPM1
and CPM2 SPI controllers.

That means that today we support almost all MPC SPI controllers:

- MPC834x-style controllers (support PIO mode only);
- CPM1 and CPM2 controllers (support DMA mode only);
- QE SPI controllers in CPU mode (PIO mode with shift quirks);
- QE SPI controllers in buffer descriptors (DMA) mode;

The only controller we don't currently support is a newer eSPI
(with a dedicated chip selects and a bit different registers map).

Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---
 drivers/spi/Kconfig       |    3 -
 drivers/spi/spi_mpc8xxx.c |  540 +++++++++++++++++++++++++++++++++++++++++----
 2 files changed, 500 insertions(+), 43 deletions(-)

diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 2c733c2..b22a4b4 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -146,9 +146,6 @@ config SPI_MPC8xxx
 	  This enables using the Freescale MPC8xxx SPI controllers in master
 	  mode.
 
-	  This driver uses a simple set of shift registers for data (opposed
-	  to the CPM based descriptor model).
-
 config SPI_OMAP_UWIRE
 	tristate "OMAP1 MicroWire"
 	depends on ARCH_OMAP1
diff --git a/drivers/spi/spi_mpc8xxx.c b/drivers/spi/spi_mpc8xxx.c
index 80374df..394b658 100644
--- a/drivers/spi/spi_mpc8xxx.c
+++ b/drivers/spi/spi_mpc8xxx.c
@@ -5,6 +5,10 @@
  *
  * Copyright (C) 2006 Polycom, Inc.
  *
+ * CPM SPI and QE buffer descriptors mode support:
+ * Copyright (c) 2009  MontaVista Software, Inc.
+ * Author: 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
@@ -27,6 +31,9 @@
 #include <linux/spi/spi_bitbang.h>
 #include <linux/platform_device.h>
 #include <linux/fsl_devices.h>
+#include <linux/dma-mapping.h>
+#include <linux/mm.h>
+#include <linux/mutex.h>
 #include <linux/of.h>
 #include <linux/of_platform.h>
 #include <linux/gpio.h>
@@ -34,8 +41,19 @@
 #include <linux/of_spi.h>
 
 #include <sysdev/fsl_soc.h>
+#include <asm/cpm.h>
+#include <asm/qe.h>
 #include <asm/irq.h>
 
+/* CPM1 and CPM2 are mutually exclusive. */
+#ifdef CONFIG_CPM1
+#include <asm/cpm1.h>
+#define CPM_SPI_CMD mk_cr_cmd(CPM_CR_CH_SPI, 0)
+#else
+#include <asm/cpm2.h>
+#define CPM_SPI_CMD mk_cr_cmd(CPM_CR_SPI_PAGE, CPM_CR_SPI_SBLOCK, 0, 0)
+#endif
+
 /* SPI Controller registers */
 struct mpc8xxx_spi_reg {
 	u8 res1[0x20];
@@ -47,6 +65,28 @@ struct mpc8xxx_spi_reg {
 	__be32 receive;
 };
 
+/* SPI Parameter RAM */
+struct spi_pram {
+	__be16	rbase;	/* Rx Buffer descriptor base address */
+	__be16	tbase;	/* Tx Buffer descriptor base address */
+	u8	rfcr;	/* Rx function code */
+	u8	tfcr;	/* Tx function code */
+	__be16	mrblr;	/* Max receive buffer length */
+	__be32	rstate;	/* Internal */
+	__be32	rdp;	/* Internal */
+	__be16	rbptr;	/* Internal */
+	__be16	rbc;	/* Internal */
+	__be32	rxtmp;	/* Internal */
+	__be32	tstate;	/* Internal */
+	__be32	tdp;	/* Internal */
+	__be16	tbptr;	/* Internal */
+	__be16	tbc;	/* Internal */
+	__be32	txtmp;	/* Internal */
+	__be32	res;	/* Tx temp. */
+	__be16  rpbase;	/* Relocation pointer (CPM1 only) */
+	__be16	res1;	/* Reserved */
+};
+
 /* SPI Controller mode register definitions */
 #define	SPMODE_LOOP		(1 << 30)
 #define	SPMODE_CI_INACTIVEHIGH	(1 << 29)
@@ -75,14 +115,40 @@ struct mpc8xxx_spi_reg {
 #define	SPIM_NE		0x00000200	/* Not empty */
 #define	SPIM_NF		0x00000100	/* Not full */
 
+#define	SPIE_TXB	0x00000200	/* Last char is written to tx fifo */
+#define	SPIE_RXB	0x00000100	/* Last char is written to rx buf */
+
+/* SPCOM register values */
+#define	SPCOM_STR	(1 << 23)	/* Start transmit */
+
+#define	SPI_PRAM_SIZE	0x100
+#define	SPI_MRBLR	((unsigned int)PAGE_SIZE)
+
 /* SPI Controller driver's private data. */
 struct mpc8xxx_spi {
+	struct device *dev;
 	struct mpc8xxx_spi_reg __iomem *base;
 
 	/* rx & tx bufs from the spi_transfer */
 	const void *tx;
 	void *rx;
 
+	int subblock;
+	struct spi_pram __iomem *pram;
+	struct cpm_buf_desc __iomem *tx_bd;
+	struct cpm_buf_desc __iomem *rx_bd;
+
+	struct spi_transfer *xfer_in_progress;
+
+	/* dma addresses for CPM transfers */
+	dma_addr_t tx_dma;
+	dma_addr_t rx_dma;
+	bool map_tx_dma;
+	bool map_rx_dma;
+
+	dma_addr_t dma_dummy_tx;
+	dma_addr_t dma_dummy_rx;
+
 	/* functions to deal with different sized buffers */
 	void (*get_rx) (u32 rx_data, struct mpc8xxx_spi *);
 	u32(*get_tx) (struct mpc8xxx_spi *);
@@ -98,6 +164,10 @@ struct mpc8xxx_spi {
 
 	unsigned int flags;
 #define SPI_QE_CPU_MODE		(1 << 0) /* QE CPU ("PIO") mode */
+#define SPI_CPM_MODE		(1 << 1) /* CPM/QE ("DMA") mode */
+#define SPI_CPM1		(1 << 2) /* SPI unit is in CPM1 block */
+#define SPI_CPM2		(1 << 3) /* SPI unit is in CPM2 block */
+#define SPI_QE			(1 << 4) /* SPI unit is in QE block */
 
 	struct workqueue_struct *workqueue;
 	struct work_struct work;
@@ -108,6 +178,10 @@ struct mpc8xxx_spi {
 	struct completion done;
 };
 
+static void *mpc8xxx_dummy_rx;
+static DEFINE_MUTEX(mpc8xxx_dummy_rx_lock);
+static int mpc8xxx_dummy_rx_refcnt;
+
 struct spi_mpc8xxx_cs {
 	/* functions to deal with different sized buffers */
 	void (*get_rx) (u32 rx_data, struct mpc8xxx_spi *);
@@ -173,6 +247,22 @@ static void mpc8xxx_spi_change_mode(struct spi_device *spi)
 	mpc8xxx_spi_write_reg(mode, cs->hw_mode & ~SPMODE_ENABLE);
 	mpc8xxx_spi_write_reg(mode, cs->hw_mode);
 
+	/* When in CPM mode, we need to reinit tx and rx. */
+	if (mspi->flags & SPI_CPM_MODE) {
+		if (mspi->flags & SPI_QE) {
+			qe_issue_cmd(QE_INIT_TX_RX, mspi->subblock,
+				     QE_CR_PROTOCOL_UNSPECIFIED, 0);
+		} else {
+			cpm_command(CPM_SPI_CMD, CPM_CR_INIT_TRX);
+			if (mspi->flags & SPI_CPM1) {
+				out_be16(&mspi->pram->rbptr,
+					 in_be16(&mspi->pram->rbase));
+				out_be16(&mspi->pram->tbptr,
+					 in_be16(&mspi->pram->tbase));
+			}
+		}
+	}
+
 	local_irq_restore(flags);
 }
 
@@ -298,19 +388,133 @@ int mpc8xxx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
 	return 0;
 }
 
-static int mpc8xxx_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
+static void mpc8xxx_spi_cpm_bufs_start(struct mpc8xxx_spi *mspi)
 {
-	struct mpc8xxx_spi *mpc8xxx_spi;
-	u32 word, len, bits_per_word;
+	struct cpm_buf_desc __iomem *tx_bd = mspi->tx_bd;
+	struct cpm_buf_desc __iomem *rx_bd = mspi->rx_bd;
+	unsigned int xfer_len = min(mspi->count, SPI_MRBLR);
+	unsigned int xfer_ofs;
 
-	mpc8xxx_spi = spi_master_get_devdata(spi->master);
+	xfer_ofs = mspi->xfer_in_progress->len - mspi->count;
+
+	out_be32(&rx_bd->cbd_bufaddr, mspi->rx_dma + xfer_ofs);
+	out_be16(&rx_bd->cbd_datlen, 0);
+	out_be16(&rx_bd->cbd_sc, BD_SC_EMPTY | BD_SC_INTRPT | BD_SC_WRAP);
+
+	out_be32(&tx_bd->cbd_bufaddr, mspi->tx_dma + xfer_ofs);
+	out_be16(&tx_bd->cbd_datlen, xfer_len);
+	out_be16(&tx_bd->cbd_sc, BD_SC_READY | BD_SC_INTRPT | BD_SC_WRAP |
+				 BD_SC_LAST);
+
+	/* start transfer */
+	mpc8xxx_spi_write_reg(&mspi->base->command, SPCOM_STR);
+}
+
+static int mpc8xxx_spi_cpm_bufs(struct mpc8xxx_spi *mspi,
+				struct spi_transfer *t, bool is_dma_mapped)
+{
+	struct device *dev = mspi->dev;
+
+	if (is_dma_mapped) {
+		mspi->map_tx_dma = 0;
+		mspi->map_rx_dma = 0;
+	} else {
+		mspi->map_tx_dma = 1;
+		mspi->map_rx_dma = 1;
+	}
+
+	if (!t->tx_buf) {
+		mspi->tx_dma = mspi->dma_dummy_tx;
+		mspi->map_tx_dma = 0;
+	}
+
+	if (!t->rx_buf) {
+		mspi->rx_dma = mspi->dma_dummy_rx;
+		mspi->map_rx_dma = 0;
+	}
+
+	if (mspi->map_tx_dma) {
+		void *nonconst_tx = (void *)mspi->tx; /* shut up gcc */
+
+		mspi->tx_dma = dma_map_single(dev, nonconst_tx, t->len,
+					      DMA_TO_DEVICE);
+		if (dma_mapping_error(dev, mspi->tx_dma)) {
+			dev_err(dev, "unable to map tx dma\n");
+			return -ENOMEM;
+		}
+	} else {
+		mspi->tx_dma = t->tx_dma;
+	}
+
+	if (mspi->map_rx_dma) {
+		mspi->rx_dma = dma_map_single(dev, mspi->rx, t->len,
+					      DMA_FROM_DEVICE);
+		if (dma_mapping_error(dev, mspi->rx_dma)) {
+			dev_err(dev, "unable to map rx dma\n");
+			goto err_rx_dma;
+		}
+	} else {
+		mspi->rx_dma = t->rx_dma;
+	}
+
+	/* enable rx ints */
+	mpc8xxx_spi_write_reg(&mspi->base->mask, SPIE_RXB);
+
+	mspi->xfer_in_progress = t;
+	mspi->count = t->len;
+
+	/* start CPM transfers */
+	mpc8xxx_spi_cpm_bufs_start(mspi);
+
+	return 0;
+
+err_rx_dma:
+	if (mspi->map_tx_dma)
+		dma_unmap_single(dev, mspi->tx_dma, t->len, DMA_TO_DEVICE);
+	return -ENOMEM;
+}
+
+static void mpc8xxx_spi_cpm_bufs_complete(struct mpc8xxx_spi *mspi)
+{
+	struct device *dev = mspi->dev;
+	struct spi_transfer *t = mspi->xfer_in_progress;
+
+	if (mspi->map_tx_dma)
+		dma_unmap_single(dev, mspi->tx_dma, t->len, DMA_TO_DEVICE);
+	if (mspi->map_tx_dma)
+		dma_unmap_single(dev, mspi->rx_dma, t->len, DMA_FROM_DEVICE);
+	mspi->xfer_in_progress = NULL;
+}
+
+static int mpc8xxx_spi_cpu_bufs(struct mpc8xxx_spi *mspi,
+				struct spi_transfer *t, unsigned int len)
+{
+	u32 word;
+
+	mspi->count = len;
+
+	/* enable rx ints */
+	mpc8xxx_spi_write_reg(&mspi->base->mask, SPIM_NE);
+
+	/* transmit word */
+	word = mspi->get_tx(mspi);
+	mpc8xxx_spi_write_reg(&mspi->base->transmit, word);
+
+	return 0;
+}
+
+static int mpc8xxx_spi_bufs(struct spi_device *spi, struct spi_transfer *t,
+			    bool is_dma_mapped)
+{
+	struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
+	unsigned int len = t->len;
+	u8 bits_per_word;
+	int ret;
 
-	mpc8xxx_spi->tx = t->tx_buf;
-	mpc8xxx_spi->rx = t->rx_buf;
 	bits_per_word = spi->bits_per_word;
 	if (t->bits_per_word)
 		bits_per_word = t->bits_per_word;
-	len = t->len;
+
 	if (bits_per_word > 8) {
 		/* invalid length? */
 		if (len & 1)
@@ -323,22 +527,27 @@ static int mpc8xxx_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
 			return -EINVAL;
 		len /= 2;
 	}
-	mpc8xxx_spi->count = len;
 
-	INIT_COMPLETION(mpc8xxx_spi->done);
+	mpc8xxx_spi->tx = t->tx_buf;
+	mpc8xxx_spi->rx = t->rx_buf;
 
-	/* enable rx ints */
-	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mask, SPIM_NE);
+	INIT_COMPLETION(mpc8xxx_spi->done);
 
-	/* transmit word */
-	word = mpc8xxx_spi->get_tx(mpc8xxx_spi);
-	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->transmit, word);
+	if (mpc8xxx_spi->flags & SPI_CPM_MODE)
+		ret = mpc8xxx_spi_cpm_bufs(mpc8xxx_spi, t, is_dma_mapped);
+	else
+		ret = mpc8xxx_spi_cpu_bufs(mpc8xxx_spi, t, len);
+	if (ret)
+		return ret;
 
 	wait_for_completion(&mpc8xxx_spi->done);
 
 	/* disable rx ints */
 	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mask, 0);
 
+	if (mpc8xxx_spi->flags & SPI_CPM_MODE)
+		mpc8xxx_spi_cpm_bufs_complete(mpc8xxx_spi);
+
 	return mpc8xxx_spi->count;
 }
 
@@ -369,7 +578,7 @@ static void mpc8xxx_spi_do_one_msg(struct spi_message *m)
 		}
 		cs_change = t->cs_change;
 		if (t->len)
-			status = mpc8xxx_spi_bufs(spi, t);
+			status = mpc8xxx_spi_bufs(spi, t, m->is_dma_mapped);
 		if (status) {
 			status = -EMSGSIZE;
 			break;
@@ -458,45 +667,80 @@ static int mpc8xxx_spi_setup(struct spi_device *spi)
 	return 0;
 }
 
-static irqreturn_t mpc8xxx_spi_irq(s32 irq, void *context_data)
+static void mpc8xxx_spi_cpm_irq(struct mpc8xxx_spi *mspi, u32 events)
 {
-	struct mpc8xxx_spi *mpc8xxx_spi = context_data;
-	u32 event;
-	irqreturn_t ret = IRQ_NONE;
+	u16 len;
 
-	/* Get interrupt events(tx/rx) */
-	event = mpc8xxx_spi_read_reg(&mpc8xxx_spi->base->event);
+	dev_dbg(mspi->dev, "%s: bd datlen %d, count %d\n", __func__,
+		in_be16(&mspi->rx_bd->cbd_datlen), mspi->count);
 
-	/* We need handle RX first */
-	if (event & SPIE_NE) {
-		u32 rx_data = mpc8xxx_spi_read_reg(&mpc8xxx_spi->base->receive);
+	len = in_be16(&mspi->rx_bd->cbd_datlen);
+	if (len > mspi->count) {
+		WARN_ON(1);
+		len = mspi->count;
+	}
 
-		if (mpc8xxx_spi->rx)
-			mpc8xxx_spi->get_rx(rx_data, mpc8xxx_spi);
+	/* Clear the events */
+	mpc8xxx_spi_write_reg(&mspi->base->event, events);
 
-		ret = IRQ_HANDLED;
+	mspi->count -= len;
+	if (mspi->count)
+		mpc8xxx_spi_cpm_bufs_start(mspi);
+	else
+		complete(&mspi->done);
+}
+
+static void mpc8xxx_spi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events)
+{
+	/* We need handle RX first */
+	if (events & SPIE_NE) {
+		u32 rx_data = mpc8xxx_spi_read_reg(&mspi->base->receive);
+
+		if (mspi->rx)
+			mspi->get_rx(rx_data, mspi);
 	}
 
-	if ((event & SPIE_NF) == 0)
+	if ((events & SPIE_NF) == 0)
 		/* spin until TX is done */
-		while (((event =
-			 mpc8xxx_spi_read_reg(&mpc8xxx_spi->base->event)) &
+		while (((events =
+			mpc8xxx_spi_read_reg(&mspi->base->event)) &
 						SPIE_NF) == 0)
 			cpu_relax();
 
-	mpc8xxx_spi->count -= 1;
-	if (mpc8xxx_spi->count) {
-		u32 word = mpc8xxx_spi->get_tx(mpc8xxx_spi);
-		mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->transmit, word);
+	/* Clear the events */
+	mpc8xxx_spi_write_reg(&mspi->base->event, events);
+
+	mspi->count -= 1;
+	if (mspi->count) {
+		u32 word = mspi->get_tx(mspi);
+
+		mpc8xxx_spi_write_reg(&mspi->base->transmit, word);
 	} else {
-		complete(&mpc8xxx_spi->done);
+		complete(&mspi->done);
 	}
+}
 
-	/* Clear the events */
-	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->event, event);
+static irqreturn_t mpc8xxx_spi_irq(s32 irq, void *context_data)
+{
+	struct mpc8xxx_spi *mspi = context_data;
+	irqreturn_t ret = IRQ_NONE;
+	u32 events;
+
+	/* Get interrupt events(tx/rx) */
+	events = mpc8xxx_spi_read_reg(&mspi->base->event);
+	if (events)
+		ret = IRQ_HANDLED;
+
+	dev_dbg(mspi->dev, "%s: events %x\n", __func__, events);
+
+	if (mspi->flags & SPI_CPM_MODE)
+		mpc8xxx_spi_cpm_irq(mspi, events);
+	else
+		mpc8xxx_spi_cpu_irq(mspi, events);
 
 	return ret;
 }
+
 static int mpc8xxx_spi_transfer(struct spi_device *spi,
 				struct spi_message *m)
 {
@@ -520,10 +764,212 @@ static void mpc8xxx_spi_cleanup(struct spi_device *spi)
 	kfree(spi->controller_state);
 }
 
+static void *mpc8xxx_spi_alloc_dummy_rx(void)
+{
+	mutex_lock(&mpc8xxx_dummy_rx_lock);
+
+	if (!mpc8xxx_dummy_rx)
+		mpc8xxx_dummy_rx = kmalloc(SPI_MRBLR, GFP_KERNEL);
+	if (mpc8xxx_dummy_rx)
+		mpc8xxx_dummy_rx_refcnt++;
+
+	mutex_unlock(&mpc8xxx_dummy_rx_lock);
+
+	return mpc8xxx_dummy_rx;
+}
+
+static void mpc8xxx_spi_free_dummy_rx(void)
+{
+	mutex_lock(&mpc8xxx_dummy_rx_lock);
+
+	switch (mpc8xxx_dummy_rx_refcnt) {
+	case 0:
+		WARN_ON(1);
+		break;
+	case 1:
+		kfree(mpc8xxx_dummy_rx);
+		mpc8xxx_dummy_rx = NULL;
+		/* fall through */
+	default:
+		mpc8xxx_dummy_rx_refcnt--;
+		break;
+	}
+
+	mutex_unlock(&mpc8xxx_dummy_rx_lock);
+}
+
+static unsigned long mpc8xxx_spi_cpm_get_pram(struct mpc8xxx_spi *mspi)
+{
+	struct device *dev = mspi->dev;
+	struct device_node *np = dev_archdata_get_node(&dev->archdata);
+	const u32 *iprop;
+	int size;
+	unsigned long spi_base_ofs;
+	unsigned long pram_ofs = -ENOMEM;
+
+	/* Can't use of_address_to_resource(), QE muram isn't at 0. */
+	iprop = of_get_property(np, "reg", &size);
+
+	/* QE with a fixed pram location? */
+	if (mspi->flags & SPI_QE && iprop && size == sizeof(*iprop) * 4)
+		return cpm_muram_alloc_fixed(iprop[2], SPI_PRAM_SIZE);
+
+	/* QE but with a dynamic pram location? */
+	if (mspi->flags & SPI_QE) {
+		pram_ofs = cpm_muram_alloc(SPI_PRAM_SIZE, 64);
+		qe_issue_cmd(QE_ASSIGN_PAGE_TO_DEVICE, mspi->subblock,
+				QE_CR_PROTOCOL_UNSPECIFIED, pram_ofs);
+		return pram_ofs;
+	}
+
+	/* CPM1 and CPM2 pram must be at a fixed addr. */
+	if (!iprop || size != sizeof(*iprop) * 4)
+		return -ENOMEM;
+
+	spi_base_ofs = cpm_muram_alloc_fixed(iprop[2], 2);
+	if (IS_ERR_VALUE(spi_base_ofs))
+		return -ENOMEM;
+
+	if (mspi->flags & SPI_CPM2) {
+		pram_ofs = cpm_muram_alloc(SPI_PRAM_SIZE, 64);
+		if (!IS_ERR_VALUE(pram_ofs)) {
+			u16 __iomem *spi_base = cpm_muram_addr(spi_base_ofs);
+
+			out_be16(spi_base, pram_ofs);
+		}
+	} else {
+		struct spi_pram __iomem *pram = cpm_muram_addr(spi_base_ofs);
+		u16 rpbase = in_be16(&pram->rpbase);
+
+		/* Microcode relocation patch applied? */
+		if (rpbase)
+			pram_ofs = rpbase;
+		else
+			return spi_base_ofs;
+	}
+
+	cpm_muram_free(spi_base_ofs);
+	return pram_ofs;
+}
+
+static int mpc8xxx_spi_cpm_init(struct mpc8xxx_spi *mspi)
+{
+	struct device *dev = mspi->dev;
+	struct device_node *np = dev_archdata_get_node(&dev->archdata);
+	const u32 *iprop;
+	int size;
+	unsigned long pram_ofs;
+	unsigned long bds_ofs;
+
+	if (!(mspi->flags & SPI_CPM_MODE))
+		return 0;
+
+	if (!mpc8xxx_spi_alloc_dummy_rx())
+		return -ENOMEM;
+
+	if (mspi->flags & SPI_QE) {
+		iprop = of_get_property(np, "cell-index", &size);
+		if (iprop && size == sizeof(*iprop))
+			mspi->subblock = *iprop;
+
+		switch (mspi->subblock) {
+		default:
+			dev_warn(dev, "cell-index unspecified, assuming SPI1");
+			/* fall through */
+		case 0:
+			mspi->subblock = QE_CR_SUBBLOCK_SPI1;
+			break;
+		case 1:
+			mspi->subblock = QE_CR_SUBBLOCK_SPI2;
+			break;
+		}
+	}
+
+	pram_ofs = mpc8xxx_spi_cpm_get_pram(mspi);
+	if (IS_ERR_VALUE(pram_ofs)) {
+		dev_err(dev, "can't allocate spi parameter ram\n");
+		goto err_pram;
+	}
+
+	bds_ofs = cpm_muram_alloc(sizeof(*mspi->tx_bd) +
+				  sizeof(*mspi->rx_bd), 8);
+	if (IS_ERR_VALUE(bds_ofs)) {
+		dev_err(dev, "can't allocate bds\n");
+		goto err_bds;
+	}
+
+	mspi->dma_dummy_tx = dma_map_single(dev, empty_zero_page, PAGE_SIZE,
+					    DMA_TO_DEVICE);
+	if (dma_mapping_error(dev, mspi->dma_dummy_tx)) {
+		dev_err(dev, "unable to map dummy tx buffer\n");
+		goto err_dummy_tx;
+	}
+
+	mspi->dma_dummy_rx = dma_map_single(dev, mpc8xxx_dummy_rx, SPI_MRBLR,
+					    DMA_FROM_DEVICE);
+	if (dma_mapping_error(dev, mspi->dma_dummy_rx)) {
+		dev_err(dev, "unable to map dummy rx buffer\n");
+		goto err_dummy_rx;
+	}
+
+	mspi->pram = cpm_muram_addr(pram_ofs);
+
+	mspi->tx_bd = cpm_muram_addr(bds_ofs);
+	mspi->rx_bd = cpm_muram_addr(bds_ofs + sizeof(*mspi->tx_bd));
+
+	/* Initialize parameter ram. */
+	out_be16(&mspi->pram->tbase, cpm_muram_offset(mspi->tx_bd));
+	out_be16(&mspi->pram->rbase, cpm_muram_offset(mspi->rx_bd));
+	out_8(&mspi->pram->tfcr, CPMFCR_EB | CPMFCR_GBL);
+	out_8(&mspi->pram->rfcr, CPMFCR_EB | CPMFCR_GBL);
+	out_be16(&mspi->pram->mrblr, SPI_MRBLR);
+	out_be32(&mspi->pram->rstate, 0);
+	out_be32(&mspi->pram->rdp, 0);
+	out_be16(&mspi->pram->rbptr, 0);
+	out_be16(&mspi->pram->rbc, 0);
+	out_be32(&mspi->pram->rxtmp, 0);
+	out_be32(&mspi->pram->tstate, 0);
+	out_be32(&mspi->pram->tdp, 0);
+	out_be16(&mspi->pram->tbptr, 0);
+	out_be16(&mspi->pram->tbc, 0);
+	out_be32(&mspi->pram->txtmp, 0);
+
+	return 0;
+
+err_dummy_rx:
+	dma_unmap_single(dev, mspi->dma_dummy_tx, PAGE_SIZE, DMA_TO_DEVICE);
+err_dummy_tx:
+	cpm_muram_free(bds_ofs);
+err_bds:
+	cpm_muram_free(pram_ofs);
+err_pram:
+	mpc8xxx_spi_free_dummy_rx();
+	return -ENOMEM;
+}
+
+static void mpc8xxx_spi_cpm_free(struct mpc8xxx_spi *mspi)
+{
+	struct device *dev = mspi->dev;
+
+	dma_unmap_single(dev, mspi->dma_dummy_rx, SPI_MRBLR, DMA_FROM_DEVICE);
+	dma_unmap_single(dev, mspi->dma_dummy_tx, PAGE_SIZE, DMA_TO_DEVICE);
+	cpm_muram_free(cpm_muram_offset(mspi->tx_bd));
+	cpm_muram_free(cpm_muram_offset(mspi->pram));
+	mpc8xxx_spi_free_dummy_rx();
+}
+
 static const char *mpc8xxx_spi_strmode(unsigned int flags)
 {
-	if (flags & SPI_QE_CPU_MODE)
+	if (flags & SPI_QE_CPU_MODE) {
 		return "QE CPU";
+	} else if (flags & SPI_CPM_MODE) {
+		if (flags & SPI_QE)
+			return "QE";
+		else if (flags & SPI_CPM2)
+			return "CPM2";
+		else
+			return "CPM1";
+	}
 	return "CPU";
 }
 
@@ -553,11 +999,16 @@ mpc8xxx_spi_probe(struct device *dev, struct resource *mem, unsigned int irq)
 	master->cleanup = mpc8xxx_spi_cleanup;
 
 	mpc8xxx_spi = spi_master_get_devdata(master);
+	mpc8xxx_spi->dev = dev;
 	mpc8xxx_spi->get_rx = mpc8xxx_spi_rx_buf_u8;
 	mpc8xxx_spi->get_tx = mpc8xxx_spi_tx_buf_u8;
 	mpc8xxx_spi->flags = pdata->flags;
 	mpc8xxx_spi->spibrg = pdata->sysclk;
 
+	ret = mpc8xxx_spi_cpm_init(mpc8xxx_spi);
+	if (ret)
+		goto err_cpm_init;
+
 	mpc8xxx_spi->rx_shift = 0;
 	mpc8xxx_spi->tx_shift = 0;
 	if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) {
@@ -570,7 +1021,7 @@ mpc8xxx_spi_probe(struct device *dev, struct resource *mem, unsigned int irq)
 	mpc8xxx_spi->base = ioremap(mem->start, mem->end - mem->start + 1);
 	if (mpc8xxx_spi->base == NULL) {
 		ret = -ENOMEM;
-		goto put_master;
+		goto err_ioremap;
 	}
 
 	mpc8xxx_spi->irq = irq;
@@ -624,7 +1075,9 @@ free_irq:
 	free_irq(mpc8xxx_spi->irq, mpc8xxx_spi);
 unmap_io:
 	iounmap(mpc8xxx_spi->base);
-put_master:
+err_ioremap:
+	mpc8xxx_spi_cpm_free(mpc8xxx_spi);
+err_cpm_init:
 	spi_master_put(master);
 err:
 	return ERR_PTR(ret);
@@ -644,6 +1097,7 @@ static int __devexit mpc8xxx_spi_remove(struct device *dev)
 
 	free_irq(mpc8xxx_spi->irq, mpc8xxx_spi);
 	iounmap(mpc8xxx_spi->base);
+	mpc8xxx_spi_cpm_free(mpc8xxx_spi);
 
 	return 0;
 }
@@ -806,6 +1260,12 @@ static int __devinit of_mpc8xxx_spi_probe(struct of_device *ofdev,
 	prop = of_get_property(np, "mode", NULL);
 	if (prop && !strcmp(prop, "cpu-qe"))
 		pdata->flags = SPI_QE_CPU_MODE;
+	else if (prop && !strcmp(prop, "qe"))
+		pdata->flags = SPI_CPM_MODE | SPI_QE;
+	else if (of_device_is_compatible(np, "fsl,cpm2-spi"))
+		pdata->flags = SPI_CPM_MODE | SPI_CPM2;
+	else if (of_device_is_compatible(np, "fsl,cpm1-spi"))
+		pdata->flags = SPI_CPM_MODE | SPI_CPM1;
 
 	ret = of_mpc8xxx_spi_get_chipselects(dev);
 	if (ret)
-- 
1.6.3.3

^ permalink raw reply related

* spin_is_locked() broken for uniprocessor?
From: Kumar Gala @ 2009-08-18 22:09 UTC (permalink / raw)
  To: Linux-Kernel List; +Cc: Thomas Gleixner, linuxppc-dev list

I just want to validate that what I'm seeing (for UP, non-debug  
features):

spin_is_locked() is defined as:

include/linux/spinlock.h:#define spin_is_locked(lock)    
__raw_spin_is_locked(&(lock)->raw_lock)

for UP that should get us:

include/linux/spinlock_up.h:#define __raw_spin_is_locked(lock)  ((void) 
(lock), 0)

which implies to me that spin_is_locked() will always return false.   
Is this expected behavior.

- k

^ permalink raw reply

* [PATCH] USB: fsl_qe_udc: Add fsl,mpc8323-qe-usb compatible entry
From: Anton Vorontsov @ 2009-08-18 22:23 UTC (permalink / raw)
  To: Greg Kroah-Hartman, David Brownell; +Cc: Scott Wood, linuxppc-dev, linux-usb

Current bindings specify that "fsl,mpc8323-qe-usb" compatible entry
should be used as a base match for QE UDCs, so update the driver to
comply with the bindings.

Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---

On Thu, Apr 02, 2009 at 02:17:11PM -0500, Scott Wood wrote:
> Anton Vorontsov wrote:
> >On Thu, Apr 02, 2009 at 01:42:37PM -0500, Timur Tabi wrote:
> >>Anton Vorontsov wrote:
> >>
> >>>Oh, I was wrong. fsl_qe_udc driver uses mpc8360 compatible for
> >>>matching, so you can't remove it. :-/
> >>Ugh, that's a bug in the driver then.
> >
> >Yes, but that depends on what chip was the first one? MPC8323 or
> >MPC8360?
> 
> Actually, it depends on which one we picked in the devtree binding
> (assuming they're compatible both ways), which appears to be
> mpc8323.

A bit delayed, but here is a patch to fix the issue.

 drivers/usb/gadget/fsl_qe_udc.c |    4 ++++
 1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/drivers/usb/gadget/fsl_qe_udc.c b/drivers/usb/gadget/fsl_qe_udc.c
index d701bf4..7881f12 100644
--- a/drivers/usb/gadget/fsl_qe_udc.c
+++ b/drivers/usb/gadget/fsl_qe_udc.c
@@ -2751,6 +2751,10 @@ static int __devexit qe_udc_remove(struct of_device *ofdev)
 /*-------------------------------------------------------------------------*/
 static struct of_device_id __devinitdata qe_udc_match[] = {
 	{
+		.compatible = "fsl,mpc8323-qe-usb",
+		.data = (void *)PORT_QE,
+	},
+	{
 		.compatible = "fsl,mpc8360-qe-usb",
 		.data = (void *)PORT_QE,
 	},
-- 
1.6.3.3

^ permalink raw reply related

* Re: spin_is_locked() broken for uniprocessor?
From: Thomas Gleixner @ 2009-08-18 22:24 UTC (permalink / raw)
  To: Kumar Gala
  Cc: Peter Zijlstra, Linux-Kernel List, Steven Rostedt,
	linuxppc-dev list, Ingo Molnar
In-Reply-To: <DE9C9034-D2CE-4D21-93D9-A10FE2580920@kernel.crashing.org>

On Tue, 18 Aug 2009, Kumar Gala wrote:
> I just want to validate that what I'm seeing (for UP, non-debug features):
> 
> spin_is_locked() is defined as:
> 
> include/linux/spinlock.h:#define spin_is_locked(lock)
> __raw_spin_is_locked(&(lock)->raw_lock)
> 
> for UP that should get us:
> 
> include/linux/spinlock_up.h:#define __raw_spin_is_locked(lock)  ((void)(lock),
> 0)
> 
> which implies to me that spin_is_locked() will always return false.  Is this
> expected behavior.

That's wrong. spin_is_locked should always return true on UP.

Thanks,

	tglx

^ permalink raw reply

* Re: [PATCH 4/8] powerpc/qe&cpm: Implement static inline stubs for non-QE/CPM builds
From: Greg KH @ 2009-08-18 22:27 UTC (permalink / raw)
  To: Anton Vorontsov
  Cc: David Brownell, linux-kernel, linuxppc-dev, spi-devel-general,
	Andrew Morton
In-Reply-To: <20090818220418.GD25090@oksana.dev.rtsoft.ru>

On Wed, Aug 19, 2009 at 02:04:18AM +0400, Anton Vorontsov wrote:
> This is needed to avoid ugly #ifdefs in drivers. Also update fsl_qe_udc
> driver so that now it doesn't define its own versions that cause build
> breakage when the generic stubs are used.
> 
> Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>

As you're just deleting code, I'll ack that :)

	Acked-by: Greg Kroah-Hartman <gregkh@suse.de>

Hopefully you have tested building this thing...

thanks,

greg k-h

^ permalink raw reply

* Re: [PATCH v2] qe_lib: Set gpio data before changing the direction to output
From: Timur Tabi @ 2009-08-18 22:33 UTC (permalink / raw)
  To: avorontsov; +Cc: linuxppc-dev, Michael Barkowski
In-Reply-To: <20090818213355.GA20966@oksana.dev.rtsoft.ru>

Anton Vorontsov wrote:
> On Tue, Aug 18, 2009 at 05:20:44PM -0400, Michael Barkowski wrote:
>> This avoids having a short glitch if the desired initial value is not
>> the same as what was previously in the data register.
>>
>> Signed-off-by: Michael Barkowski <michaelbarkowski@ruggedcom.com>
> 
> Acked-by: Anton Vorontsov <avorontsov@ru.mvista.com>

I don't have the time to test this patch, so I abstain from acking. :-)  If Anton likes it, that's good enough for me.

-- 
Timur Tabi
Linux kernel developer at Freescale

^ permalink raw reply

* Re: [PATCH/RFC] powerpc/mm: Cleanup handling of execute permission
From: Benjamin Herrenschmidt @ 2009-08-18 22:33 UTC (permalink / raw)
  To: Josh Boyer; +Cc: linuxppc-dev list, Kumar Gala
In-Reply-To: <20090818205621.GB2530@zod.rchland.ibm.com>

On Tue, 2009-08-18 at 16:56 -0400, Josh Boyer wrote:
> On Fri, Aug 14, 2009 at 05:39:42PM -0500, Becky Bruce wrote:
> > Ben,
> >
> > This breaks the boot on 8572.  I don't know why yet (and I'm probably  
> > not going to figure it out before I go home, because, frankly, it's late 
> > on a Friday afternoon and I need a glass of wine or, perhaps, a beer).
> >
> > Kumar and I will poke into this more and let you know what we find out - 
> > in the meantime, if you have any brilliant flashes, pony up!
> 
> I tested this on a 440EPx NFS rootfs boot too.  It doesn't cause init itself
> to crap out with a SIGILL like Becky's board, but it does do weird things
> and cause a SIGILL elsewhere during my boot.
> 
> Reverting this patch from your testing branch allows things to work just fine.

Becky found my thinko, I'll send a new patch later today.

Cheers,
Ben.

^ permalink raw reply

* [PATCH] spinlock: __raw_spin_is_locked() should return true for UP
From: Kumar Gala @ 2009-08-18 22:42 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: peterz, linux-kernel, rostedt, linuxppc-dev, mingo, tglx

For some reason __raw_spin_is_locked() has been returning false for the
uni-processor, non-CONFIG_DEBUG_SPINLOCK.  The UP + CONFIG_DEBUG_SPINLOCK
handles this correctly.

Found this by enabling CONFIG_DEBUG_VM on PPC and hitting always hitting
a BUG_ON that was testing to make sure the pte_lock was held.

Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
---

Linus, a fix for 2.6.31

 include/linux/spinlock_up.h |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/include/linux/spinlock_up.h b/include/linux/spinlock_up.h
index d4841ed..2b372e0 100644
--- a/include/linux/spinlock_up.h
+++ b/include/linux/spinlock_up.h
@@ -57,7 +57,7 @@ static inline void __raw_spin_unlock(raw_spinlock_t *lock)
 #define __raw_write_unlock(lock)	do { (void)(lock); } while (0)
 
 #else /* DEBUG_SPINLOCK */
-#define __raw_spin_is_locked(lock)	((void)(lock), 0)
+#define __raw_spin_is_locked(lock)	((void)(lock), 1)
 /* for sched.c and kernel_lock.c: */
 # define __raw_spin_lock(lock)		do { (void)(lock); } while (0)
 # define __raw_spin_lock_flags(lock, flags)	do { (void)(lock); } while (0)
-- 
1.6.0.6

^ permalink raw reply related

* Re: [PATCH v2] qe_lib: Set gpio data before changing the direction to output
From: Anton Vorontsov @ 2009-08-18 22:56 UTC (permalink / raw)
  To: Timur Tabi; +Cc: linuxppc-dev, Michael Barkowski
In-Reply-To: <4A8B2C1C.3060403@freescale.com>

On Tue, Aug 18, 2009 at 05:33:00PM -0500, Timur Tabi wrote:
> Anton Vorontsov wrote:
> > On Tue, Aug 18, 2009 at 05:20:44PM -0400, Michael Barkowski wrote:
> >> This avoids having a short glitch if the desired initial value is not
> >> the same as what was previously in the data register.
> >>
> >> Signed-off-by: Michael Barkowski <michaelbarkowski@ruggedcom.com>
> > 
> > Acked-by: Anton Vorontsov <avorontsov@ru.mvista.com>
> 
> I don't have the time to test this patch, so I abstain from acking. :-)
> If Anton likes it, that's good enough for me.

You made me doubt for a moment. :-) Thanks for the suspiciousness.

What happens if a pin was previously configured as input? Does our
write to the data register survive? For MPC8xxx GPIO controllers
it does. And randomly taken QE spec says:

  A write to CPDAT is latched, and if the corresponding CPDIR
  bits have configured the port pin as an output, the latched
  value is driven onto the respective pin. However, if the
  corresponding CPDIR bits have configured the port pin as an
  input, the latched value is prevented from reaching the pin.

I guess we're safe, but Michael, could you actually test it
(if not already)?

Thanks!

-- 
Anton Vorontsov
email: cbouatmailru@gmail.com
irc://irc.freenode.net/bd2

^ permalink raw reply

* RE: Jumbo Frames, sil24 SATA driver, and kswapd0 page allocation failures
From: Jonathan Haws @ 2009-08-18 22:56 UTC (permalink / raw)
  To: Chris Friesen; +Cc: linuxppc-dev@lists.ozlabs.org
In-Reply-To: <4A83442B.6080305@nortel.com>

> If the hardware supports it, the best way to deal with it is to set
> up
> the driver so that it only ever deals in single pages. =20

I am working on fixing the driver to support NETIF_F_SG and have changed ho=
w it receives packets to follow how the e1000 driver does it.

Here is where I am at:

When I get the first part of the frame, I allocate an skb for the packet.  =
I call dev->page =3D alloc_page(GFP_ATOMIC) to allocate a page for the 4080=
 bytes coming from the MAL.

I then setup a DMA mapping for that page to get the data out of the MAL (th=
e original code simply used dma_map_single, but I need a page).

Once the DMA map has been setup and data transferred, I call skb_fill_page_=
desc() to put the data into the skb.  I then wrote a function called emac_c=
onsume_page, which unmaps the DMA mapping, frees the page, and updates the =
lengths in the skb.

The relevant source code is at the end of this email.

My problem is this:

When I run this code, it appears to create the fragmented packet just fine,=
 but when it passes it up the stack, the kernel spits out these bugs, one a=
fter another:

BUG: Bad page state in process swapper  pfn:0ee9b
page:c051f360 flags:(null) count:-3 mapcount:0 mapping:(null) index:766
Call Trace:
[c032bc30] [c0006ef0] show_stack+0x44/0x16c (unreliable)
[c032bc70] [c006c438] bad_page+0x94/0x130
[c032bc90] [c006d4a0] get_page_from_freelist+0x458/0x4d4
[c032bd20] [c006d5f4] __alloc_pages_nodemask+0xd8/0x4f8
[c032bda0] [c01a1174] emac_poll_rx+0x300/0x9c8
[c032bdf0] [c019cb64] mal_poll+0xa8/0x1ec
[c032be20] [c01cf218] net_rx_action+0x9c/0x1b4
[c032be50] [c0039678] __do_softirq+0xc4/0x148
[c032be90] [c0004d18] do_softirq+0x78/0x80
[c032bea0] [c0039264] irq_exit+0x64/0x7c
[c032beb0] [c0005210] do_IRQ+0x9c/0xb4
[c032bed0] [c000fa7c] ret_from_except+0x0/0x18
[c032bf90] [c000808c] cpu_idle+0xdc/0xec
[c032bfb0] [c00028fc] rest_init+0x70/0x84
[c032bfc0] [c02e0864] start_kernel+0x240/0x2c4
[c032bff0] [c0002254] start_here+0x44/0xb0
BUG: Bad page state in process swapper  pfn:0ee8c
page:c051f180 flags:(null) count:-3 mapcount:0 mapping:(null) index:757
Call Trace:
[c032bc30] [c0006ef0] show_stack+0x44/0x16c (unreliable)
[c032bc70] [c006c438] bad_page+0x94/0x130
[c032bc90] [c006d4a0] get_page_from_freelist+0x458/0x4d4
[c032bd20] [c006d5f4] __alloc_pages_nodemask+0xd8/0x4f8
[c032bda0] [c01a1174] emac_poll_rx+0x300/0x9c8
[c032bdf0] [c019cb64] mal_poll+0xa8/0x1ec
[c032be20] [c01cf218] net_rx_action+0x9c/0x1b4
[c032be50] [c0039678] __do_softirq+0xc4/0x148
[c032be90] [c0004d18] do_softirq+0x78/0x80
[c032bea0] [c0039264] irq_exit+0x64/0x7c
[c032beb0] [c0005210] do_IRQ+0x9c/0xb4
[c032bed0] [c000fa7c] ret_from_except+0x0/0x18
[c032bf90] [c000808c] cpu_idle+0xdc/0xec
[c032bfb0] [c00028fc] rest_init+0x70/0x84
[c032bfc0] [c02e0864] start_kernel+0x240/0x2c4
[c032bff0] [c0002254] start_here+0x44/0xb0

I know that I am missing something when it comes to allocating the pages fo=
r the fragments, but when I compare my methodology to the e1000 driver, the=
y appear to be functionally the same?

Any ideas?  I can send the entire source file for the driver if needs be.

Thanks!

Jonathan


Here is the source:

static int emac_poll_rx(void *param, int budget)
{

... /* Other code is here */

push_packet:
	skb->dev =3D dev->ndev;
	skb->protocol =3D eth_type_trans(skb, dev->ndev);
	emac_rx_csum(dev, skb, ctrl);

	if (unlikely(netif_receive_skb(skb) =3D=3D NET_RX_DROP))
		++dev->estats.rx_dropped_stack;
next:
	++dev->stats.rx_packets;
skip:
	dev->stats.rx_bytes +=3D len;
	slot =3D (slot + 1) % NUM_RX_BUFF;
	--budget;
	++received;
	continue;
sg:
if (ctrl & MAL_RX_CTRL_FIRST) {
	BUG_ON(dev->rx_sg_skb);
	if (unlikely(emac_alloc_rx_skb2(dev, slot, GFP_ATOMIC))) {
		DBG(dev, "rx OOM %d (%d) (%d)" NL, slot, dev->rx_skb_size, len);
		++dev->estats.rx_dropped_oom;
		emac_recycle_rx_skb(dev, slot, 0);
	} else {
		dev->rx_sg_skb =3D skb;
		skb_fill_page_desc(dev->rx_sg_skb, 0, dev->page, 0, len);
		emac_consume_page(dev, len, slot);
		dev->rx_sg_skb->len +=3D ETH_HLEN;
	}
} else if (!emac_rx_sg_append(dev, slot) && (ctrl & MAL_RX_CTRL_LAST)) {
	skb =3D dev->rx_sg_skb;
	dev->rx_sg_skb =3D NULL;

	ctrl &=3D EMAC_BAD_RX_MASK;
	if (unlikely(ctrl && ctrl !=3D EMAC_RX_TAH_BAD_CSUM)) {
		emac_parse_rx_error(dev, ctrl);
		++dev->estats.rx_dropped_error;
		dev_kfree_skb(skb);
		len =3D 0;
	} else
		goto push_packet;
}

... /* Other code is here */
} /* end of emac_poll_rx */

static inline int emac_alloc_rx_skb2(struct emac_instance *dev, int slot,
				    gfp_t flags)
{
	struct sk_buff *skb =3D alloc_skb(242, flags);
	if (unlikely(!skb))
		return -ENOMEM;


	dev->rx_skb[slot] =3D skb;
	dev->rx_desc[slot].data_len =3D 0;

	dev->page =3D alloc_page(flags);
	DBG(dev, "emac_alloc_skb2: page %x" NL, dev->page);
	if(unlikely(!dev->page))
	{
		return -1;
	}
	dev->rx_desc[slot].data_ptr =3D dma_map_page(&dev->ofdev->dev, dev->page, =
0, 4096, DMA_FROM_DEVICE);

	wmb();
	dev->rx_desc[slot].ctrl =3D MAL_RX_CTRL_EMPTY |
	    (slot =3D=3D (NUM_RX_BUFF - 1) ? MAL_RX_CTRL_WRAP : 0);

	return 0;
} /* end of emac_alloc_rx_skb2 */

static inline void emac_consume_page(struct emac_instance* dev, int length,=
 int slot)
{
	dma_unmap_page(&dev->ofdev->dev, dev->rx_desc[slot].data_ptr, 4096, DMA_FR=
OM_DEVICE);
	wmb();
	__free_page(dev->page);
	dev->page =3D NULL;
	dev->rx_sg_skb->len +=3D length;
	dev->rx_sg_skb->data_len +=3D length;
	dev->rx_sg_skb->truesize +=3D length;
}

static inline int emac_rx_sg_append(struct emac_instance *dev, int slot)
{
	if (likely(dev->rx_sg_skb !=3D NULL)) {
		int len =3D dev->rx_desc[slot].data_len;
		int tot_len =3D dev->rx_sg_skb->len + len;

		if (unlikely(tot_len + 2 > dev->max_mtu)) {
			++dev->estats.rx_dropped_mtu;
			dev_kfree_skb(dev->rx_sg_skb);
			dev->rx_sg_skb =3D NULL;
		} else {
			dev->page =3D alloc_page(GFP_ATOMIC);
			if(unlikely(!dev->page))
			{
				return -ENOMEM;
			}
			dev->rx_desc[slot].data_ptr =3D dma_map_page(&dev->ofdev->dev, dev->page=
, 0, 4096, DMA_FROM_DEVICE);
			dev->rx_desc[slot].data_len =3D 0;
			wmb();
			dev->rx_desc[slot].ctrl =3D MAL_RX_CTRL_EMPTY | (slot =3D=3D (NUM_RX_BUF=
F - 1) ? MAL_RX_CTRL_WRAP : 0);
			skb_fill_page_desc(dev->rx_sg_skb, skb_shinfo(dev->rx_sg_skb)->nr_frags,=
 dev->page, 0, len);
			emac_consume_page(dev, len, slot);
			return 0;
		}
	}
	emac_recycle_rx_skb(dev, slot, 0);
	return -1;
} /* end of emac_rx_sg_append */

^ permalink raw reply

* Re: [PATCH] spinlock: __raw_spin_is_locked() should return true for UP
From: Linus Torvalds @ 2009-08-18 23:20 UTC (permalink / raw)
  To: Kumar Gala; +Cc: peterz, linux-kernel, rostedt, linuxppc-dev, mingo, tglx
In-Reply-To: <1250635343-32546-1-git-send-email-galak@kernel.crashing.org>



On Tue, 18 Aug 2009, Kumar Gala wrote:
>
> For some reason __raw_spin_is_locked() has been returning false for the
> uni-processor, non-CONFIG_DEBUG_SPINLOCK.  The UP + CONFIG_DEBUG_SPINLOCK
> handles this correctly.
> 
> Found this by enabling CONFIG_DEBUG_VM on PPC and hitting always hitting
> a BUG_ON that was testing to make sure the pte_lock was held.
> 
> Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
> ---
> 
> Linus, a fix for 2.6.31

This really isn't all that clear.

The thing is, some people may assert that a lock is held, but others could 
easily be looping until it's not held using something like

	while (spin_is_locked(lock))
		cpu_relax();

so it's hard to tell whether it should return true or false in the case 
where spin-locking simply doesn't exist.

		Linus

^ permalink raw reply

* [PATCH 1/3] powerpc/82xx: Fix BCSR bits for MPC8272ADS boards
From: Anton Vorontsov @ 2009-08-18 23:28 UTC (permalink / raw)
  To: Kumar Gala; +Cc: linuxppc-dev

mpc8272_ads.c is using BCSR bits definitions from pq2ads.h, but
according to User's Guide the bits are wrong for MPC8272ADS boards
(I guess definitions from pq2ads should only be used for PQ2FADS
boards).

So, let's introduce our own definitions for MPC8272ADS, and don't
include pq2ads.h.

Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---
 arch/powerpc/platforms/82xx/mpc8272_ads.c |    8 +++++++-
 1 files changed, 7 insertions(+), 1 deletions(-)

diff --git a/arch/powerpc/platforms/82xx/mpc8272_ads.c b/arch/powerpc/platforms/82xx/mpc8272_ads.c
index 8054c68..67e2184 100644
--- a/arch/powerpc/platforms/82xx/mpc8272_ads.c
+++ b/arch/powerpc/platforms/82xx/mpc8272_ads.c
@@ -29,7 +29,6 @@
 #include <sysdev/fsl_soc.h>
 #include <sysdev/cpm2_pic.h>
 
-#include "pq2ads.h"
 #include "pq2.h"
 
 static void __init mpc8272_ads_pic_init(void)
@@ -144,6 +143,13 @@ static void __init mpc8272_ads_setup_arch(void)
 		return;
 	}
 
+#define BCSR1_FETHIEN		0x08000000
+#define BCSR1_FETH_RST		0x04000000
+#define BCSR1_RS232_EN1		0x02000000
+#define BCSR1_RS232_EN2		0x01000000
+#define BCSR3_FETHIEN2		0x10000000
+#define BCSR3_FETH2_RST		0x08000000
+
 	clrbits32(&bcsr[1], BCSR1_RS232_EN1 | BCSR1_RS232_EN2 | BCSR1_FETHIEN);
 	setbits32(&bcsr[1], BCSR1_FETH_RST);
 
-- 
1.6.3.3

^ permalink raw reply related

* [PATCH 2/3] powerpc/82xx: Add CPM USB Gadget support for MPC8272ADS boards
From: Anton Vorontsov @ 2009-08-18 23:28 UTC (permalink / raw)
  To: Kumar Gala; +Cc: linuxppc-dev

- Add usb node;
- Configure pins and clocks;
- Enable USB function in BCSR.

The support was successfully tested using serial and ethernet gadget
drivers.

Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---
 arch/powerpc/boot/dts/mpc8272ads.dts      |    8 ++++++++
 arch/powerpc/platforms/82xx/mpc8272_ads.c |   14 ++++++++++++++
 2 files changed, 22 insertions(+), 0 deletions(-)

diff --git a/arch/powerpc/boot/dts/mpc8272ads.dts b/arch/powerpc/boot/dts/mpc8272ads.dts
index 60f3327..e802ebd 100644
--- a/arch/powerpc/boot/dts/mpc8272ads.dts
+++ b/arch/powerpc/boot/dts/mpc8272ads.dts
@@ -173,6 +173,14 @@
 				fsl,cpm-command = <0xce00000>;
 			};
 
+			usb@11b60 {
+				compatible = "fsl,mpc8272-cpm-usb";
+				reg = <0x11b60 0x40 0x8b00 0x100>;
+				interrupts = <11 8>;
+				interrupt-parent = <&PIC>;
+				mode = "peripheral";
+			};
+
 			mdio@10d40 {
 				device_type = "mdio";
 				compatible = "fsl,mpc8272ads-mdio-bitbang",
diff --git a/arch/powerpc/platforms/82xx/mpc8272_ads.c b/arch/powerpc/platforms/82xx/mpc8272_ads.c
index 67e2184..30394b4 100644
--- a/arch/powerpc/platforms/82xx/mpc8272_ads.c
+++ b/arch/powerpc/platforms/82xx/mpc8272_ads.c
@@ -99,6 +99,15 @@ static struct cpm_pin mpc8272_ads_pins[] = {
 	/* I2C */
 	{3, 14, CPM_PIN_INPUT | CPM_PIN_SECONDARY | CPM_PIN_OPENDRAIN},
 	{3, 15, CPM_PIN_INPUT | CPM_PIN_SECONDARY | CPM_PIN_OPENDRAIN},
+
+	/* USB */
+	{2, 10, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
+	{2, 11, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
+	{2, 20, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
+	{2, 24, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
+	{3, 23, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
+	{3, 24, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
+	{3, 25, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
 };
 
 static void __init init_ioports(void)
@@ -112,6 +121,8 @@ static void __init init_ioports(void)
 
 	cpm2_clk_setup(CPM_CLK_SCC1, CPM_BRG1, CPM_CLK_RX);
 	cpm2_clk_setup(CPM_CLK_SCC1, CPM_BRG1, CPM_CLK_TX);
+	cpm2_clk_setup(CPM_CLK_SCC3, CPM_CLK8, CPM_CLK_RX);
+	cpm2_clk_setup(CPM_CLK_SCC3, CPM_CLK8, CPM_CLK_TX);
 	cpm2_clk_setup(CPM_CLK_SCC4, CPM_BRG4, CPM_CLK_RX);
 	cpm2_clk_setup(CPM_CLK_SCC4, CPM_BRG4, CPM_CLK_TX);
 	cpm2_clk_setup(CPM_CLK_FCC1, CPM_CLK11, CPM_CLK_RX);
@@ -147,6 +158,7 @@ static void __init mpc8272_ads_setup_arch(void)
 #define BCSR1_FETH_RST		0x04000000
 #define BCSR1_RS232_EN1		0x02000000
 #define BCSR1_RS232_EN2		0x01000000
+#define BCSR3_USB_nEN		0x80000000
 #define BCSR3_FETHIEN2		0x10000000
 #define BCSR3_FETH2_RST		0x08000000
 
@@ -156,6 +168,8 @@ static void __init mpc8272_ads_setup_arch(void)
 	clrbits32(&bcsr[3], BCSR3_FETHIEN2);
 	setbits32(&bcsr[3], BCSR3_FETH2_RST);
 
+	clrbits32(&bcsr[3], BCSR3_USB_nEN);
+
 	iounmap(bcsr);
 
 	init_ioports();
-- 
1.6.3.3

^ permalink raw reply related

* [PATCH 3/3] powerpc/85xx: Add QE USB support for MPC8569E-MDS boards
From: Anton Vorontsov @ 2009-08-18 23:28 UTC (permalink / raw)
  To: Kumar Gala; +Cc: linuxppc-dev

- Add gpio-controller node for BCSR17, it is used to control USB
  speed and VBUS;
- Add timer node for QE GTM, needed for USB host;
- Add usb node itself;
- Add some probing code for BCSR GPIOs.

NOTE: QE USB doesn't work on prototype boards, but should work on
      pilot boards if specs and schematics are correct, though we
      don't have the pilot boards to actually test it.

Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---
 arch/powerpc/boot/dts/mpc8569mds.dts      |   45 +++++++++++++++++++++++++++++
 arch/powerpc/platforms/85xx/mpc85xx_mds.c |    4 ++
 2 files changed, 49 insertions(+), 0 deletions(-)

diff --git a/arch/powerpc/boot/dts/mpc8569mds.dts b/arch/powerpc/boot/dts/mpc8569mds.dts
index a680165..880f896 100644
--- a/arch/powerpc/boot/dts/mpc8569mds.dts
+++ b/arch/powerpc/boot/dts/mpc8569mds.dts
@@ -99,8 +99,18 @@
 		};
 
 		bcsr@1,0 {
+			#address-cells = <1>;
+			#size-cells = <1>;
 			compatible = "fsl,mpc8569mds-bcsr";
 			reg = <1 0 0x8000>;
+			ranges = <0 1 0 0x8000>;
+
+			bcsr17: gpio-controller@11 {
+				#gpio-cells = <2>;
+				compatible = "fsl,mpc8569mds-bcsr-gpio";
+				reg = <0x11 0x1>;
+				gpio-controller;
+			};
 		};
 
 		nand@3,0 {
@@ -315,6 +325,14 @@
 				gpio-controller;
 			};
 
+			qe_pio_f: gpio-controller@a0 {
+				#gpio-cells = <2>;
+				compatible = "fsl,mpc8569-qe-pario-bank",
+					     "fsl,mpc8323-qe-pario-bank";
+				reg = <0xa0 0x18>;
+				gpio-controller;
+			};
+
 			pio1: ucc_pin@01 {
 				pio-map = <
 			/* port  pin  dir  open_drain  assignment  has_irq */
@@ -419,6 +437,16 @@
 			interrupt-parent = <&mpic>;
 		};
 
+		timer@440 {
+			compatible = "fsl,mpc8569-qe-gtm",
+				     "fsl,qe-gtm", "fsl,gtm";
+			reg = <0x440 0x40>;
+			interrupts = <12 13 14 15>;
+			interrupt-parent = <&qeic>;
+			/* Filled in by U-Boot */
+			clock-frequency = <0>;
+		};
+
 		spi@4c0 {
 			#address-cells = <1>;
 			#size-cells = <0>;
@@ -446,6 +474,23 @@
 			mode = "cpu";
 		};
 
+		usb@6c0 {
+			compatible = "fsl,mpc8569-qe-usb",
+				     "fsl,mpc8323-qe-usb";
+			reg = <0x6c0 0x40 0x8b00 0x100>;
+			interrupts = <11>;
+			interrupt-parent = <&qeic>;
+			fsl,fullspeed-clock = "clk5";
+			fsl,lowspeed-clock = "brg10";
+			gpios = <&qe_pio_f 3 0   /* USBOE */
+				 &qe_pio_f 4 0   /* USBTP */
+				 &qe_pio_f 5 0   /* USBTN */
+				 &qe_pio_f 6 0   /* USBRP */
+				 &qe_pio_f 8 0   /* USBRN */
+				 &bcsr17   6 0   /* SPEED */
+				 &bcsr17   5 1>; /* POWER */
+		};
+
 		enet0: ucc@2000 {
 			device_type = "network";
 			compatible = "ucc_geth";
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c
index 60ed9c0..173d459 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c
@@ -47,6 +47,7 @@
 #include <asm/udbg.h>
 #include <sysdev/fsl_soc.h>
 #include <sysdev/fsl_pci.h>
+#include <sysdev/simple_gpio.h>
 #include <asm/qe.h>
 #include <asm/qe_ic.h>
 #include <asm/mpic.h>
@@ -291,6 +292,9 @@ static struct of_device_id mpc85xx_ids[] = {
 
 static int __init mpc85xx_publish_devices(void)
 {
+	if (machine_is(mpc8569_mds))
+		simple_gpiochip_init("fsl,mpc8569mds-bcsr-gpio");
+
 	/* Publish the QE devices */
 	of_platform_bus_probe(NULL, mpc85xx_ids, NULL);
 
-- 
1.6.3.3

^ permalink raw reply related

* Re: [PATCH] spinlock: __raw_spin_is_locked() should return true for UP
From: Steven Rostedt @ 2009-08-18 23:36 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: peterz, linux-kernel, linuxppc-dev, mingo, tglx
In-Reply-To: <alpine.LFD.2.01.0908181618420.3158@localhost.localdomain>


On Tue, 18 Aug 2009, Linus Torvalds wrote:

> 
> 
> On Tue, 18 Aug 2009, Kumar Gala wrote:
> >
> > For some reason __raw_spin_is_locked() has been returning false for the
> > uni-processor, non-CONFIG_DEBUG_SPINLOCK.  The UP + CONFIG_DEBUG_SPINLOCK
> > handles this correctly.
> > 
> > Found this by enabling CONFIG_DEBUG_VM on PPC and hitting always hitting
> > a BUG_ON that was testing to make sure the pte_lock was held.
> > 
> > Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
> > ---
> > 
> > Linus, a fix for 2.6.31
> 
> This really isn't all that clear.
> 
> The thing is, some people may assert that a lock is held, but others could 
> easily be looping until it's not held using something like
> 
> 	while (spin_is_locked(lock))
> 		cpu_relax();

Wouldn't something like that be really racey? And anyone doing such a 
thing had better have that code within an #ifdef CONFIG_SMP.

> 
> so it's hard to tell whether it should return true or false in the case 
> where spin-locking simply doesn't exist.

Actually, I did have a case where I would use it and would expect a return 
of 0. That was in the experimental printk code to see if it was safe to 
wakeup the klogd. I once had a check of the current cpu runqueue lock is 
locked, and if it was, not to wake up klogd. I'm sure there's other cases 
like this as well.

Thinking about it, UP probably should have spin_is_locked always return 
false, but if you want to make sure you are not in a critical section 
with the lock not held, then use assert_spin_locked, which on UP should be 
a nop.

-- Steve

^ permalink raw reply

* [PATCH v2] powerpc/85xx: Add eSDHC support for MPC8536DS boards
From: Anton Vorontsov @ 2009-08-18 23:38 UTC (permalink / raw)
  To: Kumar Gala
  Cc: Ben Dooks, linux-kernel, sdhci-devel, linuxppc-dev, Andrew Morton,
	Pierre Ossman, David Vrabel
In-Reply-To: <A17F24A0-87E0-4FFA-9C14-DF57D8A9D015@kernel.crashing.org>

This patch simply adds sdhci node to the device tree.

We specify clock-frequency manually, so that eSDHC will work without
upgrading U-Boot. Though, that'll only work for default setup (1500
MHz) on new board revisions. For non-default setups, it's recommended
to upgrade U-Boot, since it will fixup clock-frequency automatically.

Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---

On Tue, Aug 11, 2009 at 08:48:32AM -0500, Kumar Gala wrote:
> On Aug 7, 2009, at 2:58 PM, Anton Vorontsov wrote:
> >This patch simply adds sdhci node to the device tree.
> >
> >We specify clock-frequency manually, so that eSDHC will work without
> >upgrading U-Boot. Though, that'll only work for default setup (1500
> >MHz) on new board revisions. For non-default setups, it's recommended
> >to upgrade U-Boot, since it will fixup clock-frequency automatically.
> >
> >Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
> >---
> >arch/powerpc/boot/dts/mpc8536ds.dts |    8 ++++++++
> >1 files changed, 8 insertions(+), 0 deletions(-)
> 
> Can you update the mpc8536ds_36b.dts as well (its in my next branch)

Sure thing.

 arch/powerpc/boot/dts/mpc8536ds.dts     |    8 ++++++++
 arch/powerpc/boot/dts/mpc8536ds_36b.dts |    8 ++++++++
 2 files changed, 16 insertions(+), 0 deletions(-)

diff --git a/arch/powerpc/boot/dts/mpc8536ds.dts b/arch/powerpc/boot/dts/mpc8536ds.dts
index 22caf69..815cebb 100644
--- a/arch/powerpc/boot/dts/mpc8536ds.dts
+++ b/arch/powerpc/boot/dts/mpc8536ds.dts
@@ -250,6 +250,14 @@
 			phy_type = "ulpi";
 		};
 
+		sdhci@2e000 {
+			compatible = "fsl,mpc8536-esdhc", "fsl,esdhc";
+			reg = <0x2e000 0x1000>;
+			interrupts = <72 0x2>;
+			interrupt-parent = <&mpic>;
+			clock-frequency = <250000000>;
+		};
+
 		serial0: serial@4500 {
 			cell-index = <0>;
 			device_type = "serial";
diff --git a/arch/powerpc/boot/dts/mpc8536ds_36b.dts b/arch/powerpc/boot/dts/mpc8536ds_36b.dts
index 113ed8b..d95b260 100644
--- a/arch/powerpc/boot/dts/mpc8536ds_36b.dts
+++ b/arch/powerpc/boot/dts/mpc8536ds_36b.dts
@@ -250,6 +250,14 @@
 			phy_type = "ulpi";
 		};
 
+		sdhci@2e000 {
+			compatible = "fsl,mpc8536-esdhc", "fsl,esdhc";
+			reg = <0x2e000 0x1000>;
+			interrupts = <72 0x2>;
+			interrupt-parent = <&mpic>;
+			clock-frequency = <250000000>;
+		};
+
 		serial0: serial@4500 {
 			cell-index = <0>;
 			device_type = "serial";
-- 
1.6.3.3

^ permalink raw reply related

* Re: [PATCH 4/8] powerpc/qe&cpm: Implement static inline stubs for non-QE/CPM builds
From: Anton Vorontsov @ 2009-08-18 23:47 UTC (permalink / raw)
  To: Greg KH
  Cc: David Brownell, linux-kernel, linuxppc-dev, spi-devel-general,
	Andrew Morton
In-Reply-To: <20090818222747.GB4354@suse.de>

On Tue, Aug 18, 2009 at 03:27:47PM -0700, Greg KH wrote:
> On Wed, Aug 19, 2009 at 02:04:18AM +0400, Anton Vorontsov wrote:
> > This is needed to avoid ugly #ifdefs in drivers. Also update fsl_qe_udc
> > driver so that now it doesn't define its own versions that cause build
> > breakage when the generic stubs are used.
> > 
> > Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
> 
> As you're just deleting code, I'll ack that :)
> 
> 	Acked-by: Greg Kroah-Hartman <gregkh@suse.de>
> 
> Hopefully you have tested building this thing...

Yep, thanks!

-- 
Anton Vorontsov
email: cbouatmailru@gmail.com
irc://irc.freenode.net/bd2

^ permalink raw reply

* Re: [PATCH] spinlock: __raw_spin_is_locked() should return true for UP
From: Linus Torvalds @ 2009-08-18 23:52 UTC (permalink / raw)
  To: Steven Rostedt; +Cc: peterz, linux-kernel, linuxppc-dev, mingo, tglx
In-Reply-To: <alpine.DEB.2.00.0908181931180.28398@gandalf.stny.rr.com>



On Tue, 18 Aug 2009, Steven Rostedt wrote:
>
> > The thing is, some people may assert that a lock is held, but others could 
> > easily be looping until it's not held using something like
> > 
> > 	while (spin_is_locked(lock))
> > 		cpu_relax();
> 
> Wouldn't something like that be really racey? And anyone doing such a 
> thing had better have that code within an #ifdef CONFIG_SMP.

Sure, it's hopefully inside a #ifdef CONFIG_SMP.

And no, it's not necessarily racy. Sure, it's race in itself if that's all 
you are doing, but I could imagine writing that kind of code if I knew 
some lock was likely held, and I wanted to avoid doing a "try_lock()" 
until it got released.

The point is, "spin_is_locked()" is simply not a well-defined operation in 
this case. It could go either way.

And for the original case, we actually have a function for that:

	assert_spin_locked(x)

which goes away on UP. Exactly because

	BUG_ON(!spin_is_locked(x))

is not a good thing to do!

> > so it's hard to tell whether it should return true or false in the case 
> > where spin-locking simply doesn't exist.
> 
> Actually, I did have a case where I would use it and would expect a return 
> of 0. That was in the experimental printk code to see if it was safe to 
> wakeup the klogd. I once had a check of the current cpu runqueue lock is 
> locked, and if it was, not to wake up klogd. I'm sure there's other cases 
> like this as well.

Yeah, "spin_is_locked()" can be useful for those kinds of things. A 
heuristic for whether we should do something based on whether some other 
CPU holds it (or we migth have recursion).

Exactly like it can be useful for doing the BUG_ON thing. But in both 
cases it's a bit iffy.

> Thinking about it, UP probably should have spin_is_locked always return 
> false, but if you want to make sure you are not in a critical section 
> with the lock not held, then use assert_spin_locked, which on UP should be 
> a nop.

That's what we do. That said, I also think we should generally try to 
avoid the kind of code that depends on spin_is_locked always returning 
false, for the same reason we should try to avoid any code that depends on 
it always returning true. 

		Linus

^ permalink raw reply

* Re: [PATCH] spinlock: __raw_spin_is_locked() should return true for UP
From: Steven Rostedt @ 2009-08-19  0:07 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: peterz, linux-kernel, linuxppc-dev, mingo, tglx
In-Reply-To: <alpine.LFD.2.01.0908181640120.3158@localhost.localdomain>

On Tue, 18 Aug 2009, Linus Torvalds wrote:
> 
> > Thinking about it, UP probably should have spin_is_locked always return 
> > false, but if you want to make sure you are not in a critical section 
> > with the lock not held, then use assert_spin_locked, which on UP should be 
> > a nop.
> 
> That's what we do. That said, I also think we should generally try to 
> avoid the kind of code that depends on spin_is_locked always returning 
> false, for the same reason we should try to avoid any code that depends on 
> it always returning true. 

Perhaps we can deprecate spin_is_locked and replace it with 
"expect_spin_locked" and "expect_spin_unlocked" which on SMP would return 
true and false respectively if the lock was locked. But both would always 
return true on UP.

Or do some thing similar, that would remove the ambiguity on UP.

-- Steve

^ permalink raw reply

* Re: [PATCH] spinlock: __raw_spin_is_locked() should return true for UP
From: Kumar Gala @ 2009-08-19  1:17 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: peterz, linux-kernel, linuxppc-dev, mingo, Linus Torvalds, tglx
In-Reply-To: <alpine.DEB.2.00.0908182003430.18648@gandalf.stny.rr.com>


On Aug 18, 2009, at 7:07 PM, Steven Rostedt wrote:

> On Tue, 18 Aug 2009, Linus Torvalds wrote:
>>
>>> Thinking about it, UP probably should have spin_is_locked always  
>>> return
>>> false, but if you want to make sure you are not in a critical  
>>> section
>>> with the lock not held, then use assert_spin_locked, which on UP  
>>> should be
>>> a nop.
>>
>> That's what we do. That said, I also think we should generally try to
>> avoid the kind of code that depends on spin_is_locked always  
>> returning
>> false, for the same reason we should try to avoid any code that  
>> depends on
>> it always returning true.
>
> Perhaps we can deprecate spin_is_locked and replace it with
> "expect_spin_locked" and "expect_spin_unlocked" which on SMP would  
> return
> true and false respectively if the lock was locked. But both would  
> always
> return true on UP.
>
> Or do some thing similar, that would remove the ambiguity on UP.

I agree its a little too easy to abuse spin_is_locked.  However we  
should be consistent between spin_is_locked on UP between with and  
without CONFIG_DEBUG_SPINLOCK enabled.  How much of this do we want to  
try and address in .31?

The PPC test really should be using assert_spin_locked and I'll send a  
patch to Ben for that.

- k

^ permalink raw reply

* [PATCH] powerpc/mm: Fix assert_pte_locked to work properly on uniprocessor
From: Kumar Gala @ 2009-08-19  1:21 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev

Since the pte_lockptr is a spinlock it gets optimized away on
uniprocessor builds so using spin_is_locked is not correct.  We can use
assert_spin_locked instead and get the proper behavior between UP and
SMP builds.

Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
---
 arch/powerpc/mm/pgtable.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/arch/powerpc/mm/pgtable.c b/arch/powerpc/mm/pgtable.c
index 627767d..4b9a27d 100644
--- a/arch/powerpc/mm/pgtable.c
+++ b/arch/powerpc/mm/pgtable.c
@@ -242,7 +242,7 @@ void assert_pte_locked(struct mm_struct *mm, unsigned long addr)
 	BUG_ON(pud_none(*pud));
 	pmd = pmd_offset(pud, addr);
 	BUG_ON(!pmd_present(*pmd));
-	BUG_ON(!spin_is_locked(pte_lockptr(mm, pmd)));
+	assert_spin_locked(pte_lockptr(mm, pmd));
 }
 #endif /* CONFIG_DEBUG_VM */
 
-- 
1.6.0.6

^ permalink raw reply related

* Re: [PATCH v2] powerpc/85xx: Add eSDHC support for MPC8536DS boards
From: Kumar Gala @ 2009-08-19  1:24 UTC (permalink / raw)
  To: avorontsov
  Cc: Ben Dooks, linux-kernel, sdhci-devel, linuxppc-dev, Andrew Morton,
	Pierre Ossman, David Vrabel
In-Reply-To: <20090818233818.GA29042@oksana.dev.rtsoft.ru>


On Aug 18, 2009, at 6:38 PM, Anton Vorontsov wrote:

> This patch simply adds sdhci node to the device tree.
>
> We specify clock-frequency manually, so that eSDHC will work without
> upgrading U-Boot. Though, that'll only work for default setup (1500
> MHz) on new board revisions. For non-default setups, it's recommended
> to upgrade U-Boot, since it will fixup clock-frequency automatically.
>
> Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>

out of interest the 85xx eSDHC don't need the sdhci,wp-inverted  
property?

- k

^ permalink raw reply

* Re: powerpc/405ex: Support cuImage for PPC405EX
From: tiejun.chen @ 2009-08-19  1:45 UTC (permalink / raw)
  To: Josh Boyer; +Cc: linuxppc-dev
In-Reply-To: <20090818132835.GA2530@zod.rchland.ibm.com>

Josh Boyer wrote:
> On Tue, Aug 18, 2009 at 10:28:02AM +0800, Tiejun Chen wrote:
>> Summary: powerpc/405ex: Support cuImage for PPC405EX
>> Reviewers: Benjmain and linux-ppc
>> ----------------------------------------------------
>> These patch series are used to support cuImage on the kilauea board based on PPC405ex.
>>
>> Tested on the amcc kilauea board:
> 
> Hm.  The U-Boot version that ships on the AMCC Kilauea board is FDT aware, so
> cuImage shouldn't be needed at all.  I'm slightly confused why we need this.

That the newer u-boot can aware extra on Kilauea is really as you said. But I
think I/we need to consider some other requirements for 405EX, such as only
using one image for convenient on embedded system, and u-boot don't pass dtb for
kernel since it will be isolated with one customer software layer.

And actually to support old U-boot compatibility is original *goal* of
implementing cuImage in kernel as we know. Right?

As Documentation/powerpc/bootwrapper.txt I think the kernel should support more
image variant to satisfy different requirement. Sometimes that is also beyond we
can discuss here.

> Are you using it for some other board derived from 405EX that doesn't have
> an FDT aware U-Boot?
> 

Yes, this is really another factor. Anyway thinks your comments.

Best Reards
Tiejun

> josh
> 

^ permalink raw reply

* Re: [PATCH v2] powerpc/85xx: Add eSDHC support for MPC8536DS boards
From: Anton Vorontsov @ 2009-08-19  1:51 UTC (permalink / raw)
  To: Kumar Gala
  Cc: Ben Dooks, linux-kernel, sdhci-devel, linuxppc-dev, Andrew Morton,
	Pierre Ossman, David Vrabel
In-Reply-To: <F58A75CD-73CC-4F75-AF51-2BCC0B828E84@kernel.crashing.org>

On Tue, Aug 18, 2009 at 08:24:17PM -0500, Kumar Gala wrote:
> 
> On Aug 18, 2009, at 6:38 PM, Anton Vorontsov wrote:
> 
> >This patch simply adds sdhci node to the device tree.
> >
> >We specify clock-frequency manually, so that eSDHC will work without
> >upgrading U-Boot. Though, that'll only work for default setup (1500
> >MHz) on new board revisions. For non-default setups, it's recommended
> >to upgrade U-Boot, since it will fixup clock-frequency automatically.
> >
> >Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
> 
> out of interest the 85xx eSDHC don't need the sdhci,wp-inverted
> property?

Yes, eSDHC controllers in MPC85xx report normal state in its
registers.

But the funny thing is that the switch itself is inverted,
so to enable writing, on MPC8569E-MDS and MPC8536DS boards
we have to place card's write protect tab into "lock" position.

Unfortunately we can't fix that in software since controller
doesn't permit write operations if it detects write-protected
state. On the bright side, IIRC MPC8536DS revision history
says that WP line level is fixed via BCSR upgrade. Not sure
if it is possible to fix it for MPC8569E-MDS.

-- 
Anton Vorontsov
email: cbouatmailru@gmail.com
irc://irc.freenode.net/bd2

^ permalink raw reply

* Re: [PATCH] spinlock: __raw_spin_is_locked() should return true for UP
From: Linus Torvalds @ 2009-08-19  2:40 UTC (permalink / raw)
  To: Kumar Gala
  Cc: peterz, linux-kernel, Steven Rostedt, linuxppc-dev, mingo, tglx
In-Reply-To: <BB2762BC-C760-4D4C-BDCF-76EFD3E1B18D@kernel.crashing.org>



On Tue, 18 Aug 2009, Kumar Gala wrote:
> 
> I agree its a little too easy to abuse spin_is_locked.  However we should be
> consistent between spin_is_locked on UP between with and without
> CONFIG_DEBUG_SPINLOCK enabled.

No we shouldn't.

With CONFIG_DEBUG_SPINLOCK, you have an actual lock variable for debugging 
purposes, so spin_is_locked() can clearly return a _valid_ answer, and 
should do so.

Without DEBUG_SPINLOCK, there isn't any answer to return.

So there's no way we can or should be consistent. In one case an answer 
exists, in another one the answer is meaningless and doesn't exist.

> How much of this do we want to try and address in .31?

Absolutely nothing.

> The PPC test really should be using assert_spin_locked and I'll send a patch
> to Ben for that.

Yes, that's the correct fix.

		Linus

^ 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