LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH v2] drivers/ata: add support to Freescale 3.0Gbps SATA Controller
From: Arnd Bergmann @ 2007-10-15 11:45 UTC (permalink / raw)
  To: Kalra Ashish-B00888; +Cc: linuxppc-dev, jgarzik, linux-ide
In-Reply-To: <2A6F278C5B66C4459AF4013E77A40CD3FCBB59@zin33exm20.fsl.freescale.net>

On Monday 15 October 2007, Kalra Ashish-B00888 wrote:
> Thanks for your comments and feedback.
> 
> Actually, for PowerPC platforms iowrite32/ioread32 internally call
> writel/readl, which are again mapped to out_le32/in_le32,

This is correct on 6xx and e500 for now, but it's a little more
complicated than that in general:

iowriteXX/ioreadXX are either the simple readX/writeX wrappers
from arch/powerpc/kernel/iomap.c, or the more complex functions
from lib/iomap.c, depending on whether any of the active platforms
has set CONFIG_PPC_INDIRECT_IO.

writeX/readX can either map directly to out_leXX/in_leXX, or do
something more complicated, again depending on the platform.
In general, writeX/readX may need to consider PCI specific error
handling or synchronization requirements, while out_leXX/in_leXX
are low-level accessors that should only be used by device drivers
when they are used on directly connected (non-PCI) devices.

Since iowriteXX/ioreadXX is supposed to be the most generic
variant covering both PCI MMIO (writeX/readX) and PCI PIO
(outX/inX) transfers, it would make sense to extend them to
also do SOC MMIO (out_leXX/in_leXX/out_beXX/in_beXX) and
DCR (dcr_write/dcr_read) accesses in the future.

	Arnd <><

^ permalink raw reply

* RE: [PATCH v2] drivers/ata: add support to Freescale 3.0Gbps SATA Controller
From: Kalra Ashish-B00888 @ 2007-10-15 11:30 UTC (permalink / raw)
  To: Arnd Bergmann, linuxppc-dev; +Cc: linux-ide, jgarzik, Kalra Ashish-B00888
In-Reply-To: <200710121621.50649.arnd@arndb.de>

Hello Arnd,

Thanks for your comments and feedback.

Actually, for PowerPC platforms iowrite32/ioread32 internally call
writel/readl, which are again mapped to out_le32/in_le32,
therefore we will modify our code to use of_iomap() to combine
functionalities of both of_address_to_resource() & ioremap().

We will also incorporate your other suggestions and then resubmit the
patch.

Ashish

-----Original Message-----
From: Arnd Bergmann [mailto:arnd@arndb.de]=20
Sent: Friday, October 12, 2007 7:52 PM
To: linuxppc-dev@ozlabs.org
Cc: Li Yang-r58472; jgarzik@pobox.com; linux-ide@vger.kernel.org; Kalra
Ashish-B00888
Subject: Re: [PATCH v2] drivers/ata: add support to Freescale 3.0Gbps
SATA Controller

On Friday 12 October 2007, Li Yang wrote:
> This patch adds support for Freescale 3.0Gbps SATA Controller=20
> supporting Native Command Queueing(NCQ), device hotplug, and ATAPI. =20
> This controller can be found on MPC8315 and MPC8378.

Most of the driver looks really good, but here are a few things that
stick out:

> +static int sata_fsl_probe(struct of_device *ofdev,
> +			const struct of_device_id *match)
> +{
> +	int retval =3D 0;
> +	void __iomem *hcr_base =3D NULL;
> +	void __iomem *ssr_base =3D NULL;
> +	void __iomem *csr_base =3D NULL;
> +	struct sata_fsl_host_priv *host_priv =3D NULL;
> +	struct resource *r;
> +	int irq;
> +	struct ata_host *host;
> +
> +	struct ata_port_info pi =3D sata_fsl_port_info[0];
> +	const struct ata_port_info *ppi[] =3D { &pi, NULL };
> +
> +	dev_printk(KERN_INFO, &ofdev->dev,
> +		   "Sata FSL Platform/CSB Driver init\n");
> +
> +	r =3D kmalloc(sizeof(struct resource), GFP_KERNEL);
> +	retval =3D of_address_to_resource(ofdev->node, 0, r);
> +	if (retval)
> +		return -EINVAL;
> +
> +	DPRINTK("start i/o @0x%x\n", r->start);
> +
> +	hcr_base =3D ioremap(r->start, r->end - r->start + 1);
> +	if (!hcr_base)
> +		goto error_exit_with_cleanup;

Hmm, I think we should redefine of_iomap to do the right thing for you.
currently, it is the combination of of_address_to_resource and ioremap,
which you do as well, so your code can be simplified to do that.
However, ioremap is meant to be used with readl/writel or
in_le32/out_le32 and similar functions, not with ioread32/iowrite32
which you are using.

I had planned to do a patch to get that right for some time so you can
use of_iomap with ioread in all cases, but I guess you should start
using of_iomap even now.

> +
> +error_exit_with_cleanup:
> +
> +	if (hcr_base)
> +		iounmap(hcr_base);
> +	if (host_priv)
> +		kfree(host_priv);
> +
> +	return retval;
> +}

Once of_iomap start using devres, we would no longer need to iounmap
here.

> +static int sata_fsl_remove(struct of_device *ofdev) {
> +	struct ata_host *host =3D dev_get_drvdata(&ofdev->dev);
> +	struct sata_fsl_host_priv *host_priv =3D host->private_data;
> +
> +	dev_set_drvdata(&ofdev->dev, NULL);
> +
> +	iounmap(host_priv->hcr_base);
> +	kfree(host_priv);
> +
> +	return 0;
> +}

Should you also free the irq mapping here?

> --- /dev/null
> +++ b/drivers/ata/sata_fsl.h
> @@ -0,0 +1,92 @@
> +/*
> + * drivers/ata/sata_fsl.h
> + *
> + * Freescale 3.0Gbps SATA device driver

The header file is entirely pointless, since all definitions in here are
only used in a single file. Please merge the header into the
implementation.

> +static int sata_fsl_probe(struct of_device *ofdev,
> +			const struct of_device_id *match); static int=20
> +sata_fsl_remove(struct of_device *ofdev); static int=20
> +sata_fsl_scr_read(struct ata_port *, unsigned int, u32 *); static int

> +sata_fsl_scr_write(struct ata_port *, unsigned int, u32); static=20
> +unsigned int sata_fsl_qc_issue(struct ata_queued_cmd *); static=20
> +irqreturn_t sata_fsl_interrupt(int, void *); static void=20
> +sata_fsl_irq_clear(struct ata_port *); static int=20
> +sata_fsl_port_start(struct ata_port *); static void=20
> +sata_fsl_port_stop(struct ata_port *); static void=20
> +sata_fsl_tf_read(struct ata_port *, struct ata_taskfile *); static=20
> +void sata_fsl_qc_prep(struct ata_queued_cmd *); static u8=20
> +sata_fsl_check_status(struct ata_port *); static void=20
> +sata_fsl_freeze(struct ata_port *); static void sata_fsl_thaw(struct=20
> +ata_port *); static void sata_fsl_error_handler(struct ata_port *);=20
> +static void sata_fsl_post_internal_cmd(struct ata_queued_cmd *);
> +
> +static inline unsigned int sata_fsl_tag(unsigned int, void __iomem=20
> +*);

In particular, get rid of the forward declarations for static functions.
All functions in a simple driver should be ordered in a way that you
always reference only code that was previously defined. This helps avoid
accidental recursions and makes it easier to review.

	Arnd <><

^ permalink raw reply

* Re: mpc52xx bestcomm patches.
From: Matt Sealey @ 2007-10-15 11:30 UTC (permalink / raw)
  To: Kumar Gala; +Cc: linuxppc-dev, Paul Mackerras
In-Reply-To: <DDF4941D-02CA-49FA-999D-8BD08740902C@kernel.crashing.org>


Kumar Gala wrote:
>> The problem is that bestcomm is completely stalled on Sylvain.  He's
>> done good work, but he isn't able to put in the effort for the last
>> push to get it fixed and in.  But until that happens, nobody else will
>> step in to add patches on top of it to fix it up.
> 
> If Sylvain doesn't have the time can't someone else pick up what he's  
> done and fixup the issues with it?

I second that motion!

There are a few minor quibbles I have with Sylvain's implementation (it
seems to have ditched some perfectly sound ideas of the original API plus
additions made by bplan for using the device tree to resolve tasks, in
favour of making the API entirely driver-dependant, and Linux-dependant
(it trashes any existing device table) also it has a few "5200-specific"
features like disabling task prefetch (errata not present in 5200B onwards).

It needs some looking at. But, this can be merged in my opinion, we can
just throw it to the list right now, and take the niggles to the list
and have a discussion about it..

In the absense of one guy hammering at the code let's just get 20 people
to review it, right here, with a new submission..

-- 
Matt Sealey <matt@genesi-usa.com>
Genesi, Manager, Developer Relations

^ permalink raw reply

* RE: [PATCH] [POWERPC] ucc_geth: Fix build break introduced by commit 09f75cd7bf13720738e6a196cc0107ce9a5bd5a0
From: Li Yang-r58472 @ 2007-10-15 11:17 UTC (permalink / raw)
  To: Medve Emilian-EMMEDVE1, akpm, jgarzik, netdev, linuxppc-dev
In-Reply-To: <1192231588-17516-1-git-send-email-Emilian.Medve@Freescale.com>

> -----Original Message-----
> From: Medve Emilian-EMMEDVE1=20
> Sent: Saturday, October 13, 2007 7:26 AM
> To: akpm@linux-foundation.org; jgarzik@pobox.com; Li=20
> Yang-r58472; netdev@vger.kernel.org; linuxppc-dev@ozlabs.org
> Cc: Medve Emilian-EMMEDVE1
> Subject: [PATCH] [POWERPC] ucc_geth: Fix build break=20
> introduced by commit 09f75cd7bf13720738e6a196cc0107ce9a5bd5a0
>=20
>=20
>   CC      drivers/net/ucc_geth.o
> drivers/net/ucc_geth.c: In function 'ucc_geth_startup':
> drivers/net/ucc_geth.c:2614: warning: assignment makes=20
> integer from pointer without a cast
> drivers/net/ucc_geth.c:2651: warning: assignment makes=20
> integer from pointer without a cast
> drivers/net/ucc_geth.c: In function 'ucc_geth_rx':
> drivers/net/ucc_geth.c:3483: error: 'dev' undeclared (first=20
> use in this function)
> drivers/net/ucc_geth.c:3483: error: (Each undeclared=20
> identifier is reported only once
> drivers/net/ucc_geth.c:3483: error: for each function it appears in.)
> make[2]: *** [drivers/net/ucc_geth.o] Error 1

Thanks for the patch.  Here are some comments.

The patch fixes the dev undeclared compile error not the warnings.  So
they shouldn't be listed here.

>=20
> Signed-off-by: Emil Medve <Emilian.Medve@Freescale.com>
> ---
>=20
> Here is a convenient link for the culprit patch:=20
> http://git.kernel.org/?p=3Dlinux/kernel/git/jgarzik/netdev-2.6.g
> it;a=3Dcommit;h=3D09f75cd7bf13720738e6a196cc0107ce9a5bd5a0
>=20
> netdev-2.6> scripts/checkpatch.pl=20
> 0001-POWERPC-ucc_geth-Fix-build-break-introduced-by-co.patch
> Your patch has no obvious style problems and is ready for submission.
>=20
>  drivers/net/ucc_geth.c |   10 +++++-----
>  1 files changed, 5 insertions(+), 5 deletions(-)
>=20
> diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c=20
> index d00e7d4..c43d4d1 100644
> --- a/drivers/net/ucc_geth.c
> +++ b/drivers/net/ucc_geth.c
> @@ -63,7 +63,7 @@
>  #define UGETH_MSG_DEFAULT	(NETIF_MSG_IFUP << 1 ) - 1
> =20
>  void uec_set_ethtool_ops(struct net_device *netdev);
> -=09
> +
>  static DEFINE_SPINLOCK(ugeth_lock);
> =20
>  static struct {

There are quite a few references to the dev structure.  I would prefer
to add a new variable dev here.

- Leo

> @@ -3480,9 +3480,9 @@ static int ucc_geth_rx(struct=20
> ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit
>  				dev_kfree_skb_any(skb);
> =20
>  		=09
> ugeth->rx_skbuff[rxQ][ugeth->skb_currx[rxQ]] =3D NULL;
> -			dev->stats.rx_dropped++;
> +			ugeth->dev->stats.rx_dropped++;
>  		} else {
> -			dev->stats.rx_packets++;
> +			ugeth->dev->stats.rx_packets++;
>  			howmany++;
> =20
>  			/* Prep the skb for the packet */
> @@ -3491,7 +3491,7 @@ static int ucc_geth_rx(struct=20
> ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit
>  			/* Tell the skb what kind of packet this is */
>  			skb->protocol =3D eth_type_trans(skb, ugeth->dev);
> =20
> -			dev->stats.rx_bytes +=3D length;
> +			ugeth->dev->stats.rx_bytes +=3D length;
>  			/* Send the packet up the stack */
>  #ifdef CONFIG_UGETH_NAPI
>  			netif_receive_skb(skb);
> @@ -3506,7 +3506,7 @@ static int ucc_geth_rx(struct=20
> ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit
>  		if (!skb) {
>  			if (netif_msg_rx_err(ugeth))
>  				ugeth_warn("%s: No Rx Data=20
> Buffer", __FUNCTION__);
> -			dev->stats.rx_dropped++;
> +			ugeth->dev->stats.rx_dropped++;
>  			break;
>  		}
> =20
> --
> 1.5.3.GIT
>=20
>=20

^ permalink raw reply

* [PATCH take2] [POWERPC] i2c: adds support for i2c bus on 8xx
From: Jochen Friedrich @ 2007-10-15 11:10 UTC (permalink / raw)
  To: linuxppc-embedded@ozlabs.org, linux-kernel, i2c; +Cc: Carsten Juttner

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


Using the port of 2.4 code from Vitaly Bordug <vitb@kernel.crashing.org>
and the actual algorithm used by the i2c driver of the DBox code on
cvs.tuxboc.org from Tmbinc, Gillem (htoa@gmx.net). Renamed
i2c-algo-8xx.c to i2c-algo-cpm.c and i2c-rpx.c to i2c-8xx.c. Added
original i2c-rpx.c as i2c-8xx-ppc.c for pre-OF (arch ppc) devices.

Signed-off-by: Jochen Friedrich <jochen@scram.de>
---

This can be pulled from git://git.bocc.de/dbox2.git i2c

 arch/powerpc/boot/dts/mpc885ads.dts          |    9 +
 arch/powerpc/platforms/8xx/mpc885ads_setup.c |    6 +
 arch/powerpc/sysdev/fsl_soc.c                |   61 +++-
 drivers/i2c/algos/Kconfig                    |   12 +
 drivers/i2c/algos/Makefile                   |    1 +
 drivers/i2c/algos/i2c-algo-cpm.c             |  563 ++++++++++++++++++++++++++
 drivers/i2c/busses/Kconfig                   |   22 +
 drivers/i2c/busses/Makefile                  |    2 +
 drivers/i2c/busses/i2c-8xx-ppc.c             |  105 +++++
 drivers/i2c/busses/i2c-8xx.c                 |  170 ++++++++
 include/linux/i2c-algo-cpm.h                 |   34 ++
 11 files changed, 984 insertions(+), 1 deletions(-)
 create mode 100644 drivers/i2c/algos/i2c-algo-cpm.c
 create mode 100644 drivers/i2c/busses/i2c-8xx-ppc.c
 create mode 100644 drivers/i2c/busses/i2c-8xx.c
 create mode 100644 include/linux/i2c-algo-cpm.h

[-- Attachment #2: dbf0ac27a4f43181eb26453562bb701c7dbc2aa0.diff --]
[-- Type: text/x-patch, Size: 28844 bytes --]

diff --git a/arch/powerpc/boot/dts/mpc885ads.dts b/arch/powerpc/boot/dts/mpc885ads.dts
index 8848e63..a526c02 100644
--- a/arch/powerpc/boot/dts/mpc885ads.dts
+++ b/arch/powerpc/boot/dts/mpc885ads.dts
@@ -213,6 +213,15 @@
 				fsl,cpm-command = <0080>;
 				linux,network-index = <2>;
 			};
+
+			i2c@860 {
+				device_type = "i2c";
+				compatible = "fsl-i2c-cpm";
+				reg = <860 20 3c80 30>;
+				interrupts = <10>;
+				interrupt-parent = <&CPM_PIC>;
+				fsl,cpm-command = <0010>;
+			};
 		};
 	};
 
diff --git a/arch/powerpc/platforms/8xx/mpc885ads_setup.c b/arch/powerpc/platforms/8xx/mpc885ads_setup.c
index 2cf1b6a..350018b 100644
--- a/arch/powerpc/platforms/8xx/mpc885ads_setup.c
+++ b/arch/powerpc/platforms/8xx/mpc885ads_setup.c
@@ -175,6 +175,12 @@ static void __init init_ioports(void)
 
 	/* Set FEC1 and FEC2 to MII mode */
 	clrbits32(&mpc8xx_immr->im_cpm.cp_cptr, 0x00000180);
+
+#ifdef CONFIG_I2C_8XX
+	setbits32(&mpc8xx_immr->im_cpm.cp_pbpar, 0x00000030);
+	setbits32(&mpc8xx_immr->im_cpm.cp_pbdir, 0x00000030);
+	setbits16(&mpc8xx_immr->im_cpm.cp_pbodr, 0x0030);
+#endif
 }
 
 static void __init mpc885ads_setup_arch(void)
diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c
index 3ace747..e2c8bf8 100644
--- a/arch/powerpc/sysdev/fsl_soc.c
+++ b/arch/powerpc/sysdev/fsl_soc.c
@@ -28,6 +28,7 @@
 #include <linux/fsl_devices.h>
 #include <linux/fs_enet_pd.h>
 #include <linux/fs_uart_pd.h>
+#include <linux/of_platform.h>
 
 #include <asm/system.h>
 #include <asm/atomic.h>
@@ -397,7 +398,7 @@ static int __init fsl_i2c_of_init(void)
 	for (np = NULL, i = 0;
 	     (np = of_find_compatible_node(np, "i2c", "fsl-i2c")) != NULL;
 	     i++) {
-		struct resource r[2];
+		struct resource r[3];
 		struct fsl_i2c_platform_data i2c_data;
 		const unsigned char *flags = NULL;
 
@@ -1210,6 +1211,64 @@ err:
 
 arch_initcall(cpm_smc_uart_of_init);
 
+static const char *i2c_regs = "regs";
+static const char *i2c_pram = "pram";
+static const char *i2c_irq = "interrupt";
+
+static int __init fsl_i2c_cpm_of_init(void)
+{
+	struct device_node *np;
+	unsigned int i;
+	struct platform_device *i2c_dev;
+	int ret;
+
+	for (np = NULL, i = 0;
+	     (np = of_find_compatible_node(np, "i2c", "fsl-i2c-cpm")) != NULL;
+	     i++) {
+		struct resource r[3];
+		struct fsl_i2c_platform_data i2c_data;
+
+		memset(&r, 0, sizeof(r));
+		memset(&i2c_data, 0, sizeof(i2c_data));
+
+		ret = of_address_to_resource(np, 0, &r[0]);
+		if (ret)
+			goto err;
+		r[0].name = i2c_regs;
+
+		ret = of_address_to_resource(np, 1, &r[1]);
+		if (ret)
+			goto err;
+		r[1].name = i2c_pram;
+
+		r[2].start = r[2].end = irq_of_parse_and_map(np, 0);
+		r[2].flags = IORESOURCE_IRQ;
+		r[2].name = i2c_irq;
+
+		i2c_dev = platform_device_register_simple("fsl-i2c-cpm", i, &r[0], 3);
+		if (IS_ERR(i2c_dev)) {
+			ret = PTR_ERR(i2c_dev);
+			goto err;
+		}
+
+		ret =
+		    platform_device_add_data(i2c_dev, &i2c_data,
+					     sizeof(struct
+						    fsl_i2c_platform_data));
+		if (ret)
+			goto unreg;
+	}
+
+	return 0;
+
+unreg:
+	platform_device_unregister(i2c_dev);
+err:
+	return ret;
+}
+
+arch_initcall(fsl_i2c_cpm_of_init);
+
 #endif /* CONFIG_8xx */
 #endif /* CONFIG_PPC_CPM_NEW_BINDING */
 
diff --git a/drivers/i2c/algos/Kconfig b/drivers/i2c/algos/Kconfig
index 014dfa5..7a8200e 100644
--- a/drivers/i2c/algos/Kconfig
+++ b/drivers/i2c/algos/Kconfig
@@ -14,6 +14,18 @@ config I2C_ALGOBIT
 	  This support is also available as a module.  If so, the module 
 	  will be called i2c-algo-bit.
 
+config I2C_ALGOCPM
+	tristate "I2C MPC8xx CPM and MPC8260 CPM2 interfaces"
+	depends on ( 8xx || 8260 ) && I2C
+	help
+	  CPM I2C Algorithm, supports the CPM I2C interface for mpc8xx
+	  and mpc8260 CPUs. Say Y if you own a CPU of this class and wish
+	  to use the I2C interface and say Y to the specific driver for the
+	  particular CPU.
+
+	  This support is also available as a module.  If so, the module
+	  will be called i2c-algo-cpm.
+
 config I2C_ALGOPCF
 	tristate "I2C PCF 8584 interfaces"
 	help
diff --git a/drivers/i2c/algos/Makefile b/drivers/i2c/algos/Makefile
index cac1051..b5fe28c 100644
--- a/drivers/i2c/algos/Makefile
+++ b/drivers/i2c/algos/Makefile
@@ -6,6 +6,7 @@ obj-$(CONFIG_I2C_ALGOBIT)	+= i2c-algo-bit.o
 obj-$(CONFIG_I2C_ALGOPCF)	+= i2c-algo-pcf.o
 obj-$(CONFIG_I2C_ALGOPCA)	+= i2c-algo-pca.o
 obj-$(CONFIG_I2C_ALGO_SGI)	+= i2c-algo-sgi.o
+obj-$(CONFIG_I2C_ALGOCPM)	+= i2c-algo-cpm.o
 
 ifeq ($(CONFIG_I2C_DEBUG_ALGO),y)
 EXTRA_CFLAGS += -DDEBUG
diff --git a/drivers/i2c/algos/i2c-algo-cpm.c b/drivers/i2c/algos/i2c-algo-cpm.c
new file mode 100644
index 0000000..08552cb
--- /dev/null
+++ b/drivers/i2c/algos/i2c-algo-cpm.c
@@ -0,0 +1,563 @@
+/*
+ * i2c-algo-cpm.c i2x driver algorithms for MPC8XX CPM and MPC8260 CPM2
+ * Copyright (c) 1999 Dan Malek (dmalek@jlc.net).
+ *
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * moved into proper i2c interface; separated out platform specific
+ * parts into i2c-8xx.c
+ * Brad Parker (brad@heeltoe.com)
+ *
+ * Parts from dbox2_i2c.c (cvs.tuxbox.org)
+ * (C) 2000-2001 Tmbinc, Gillem (htoa@gmx.net)
+ *
+ * (C) 2007 Montavista Software, Inc.
+ * Vitaly Bordug <vitb@kernel.crashing.org>
+ *
+ * (C) 2007 Jochen Friedrich <jochen@scram.de>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-cpm.h>
+#include <linux/io.h>
+#include <linux/time.h>
+#include <linux/dma-mapping.h>
+#include <asm/mpc8xx.h>
+
+/* Try to define this if you have an older CPU (earlier than rev D4) */
+#undef	I2C_CHIP_ERRATA
+
+static int cpm_debug = 1;
+#ifdef DEBUG
+module_param(cpm_debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(cpm_debug, "debug level - 0 off; 1 normal");
+#endif
+
+static irqreturn_t cpm_iic_interrupt(int irq, void *dev_id)
+{
+	struct i2c_adapter *adap;
+	struct i2c_algo_cpm_data *cpm;
+	i2c8xx_t *i2c;
+	int i;
+
+	adap = (struct i2c_adapter *) dev_id;
+	cpm = adap->algo_data;
+	i2c = cpm->i2c;
+
+	/* Clear interrupt.
+	 */
+	i = in_8(&i2c->i2c_i2cer);
+	out_8(&i2c->i2c_i2cer, i);
+
+	if (cpm_debug)
+		dev_dbg(&adap->dev, "Interrupt: %x\n", i);
+
+	/* Get 'me going again.
+	 */
+	wake_up_interruptible(&cpm->iic_wait);
+
+	return IRQ_HANDLED;
+}
+
+static int cpm_iic_init(struct i2c_adapter *adap)
+{
+	struct i2c_algo_cpm_data *cpm = adap->algo_data;
+	iic_t *iip = cpm->iip;
+	i2c8xx_t *i2c = cpm->i2c;
+	unsigned char brg;
+	int ret, i;
+
+	if (cpm_debug)
+		dev_dbg(&adap->dev, "cpm_iic_init()\n");
+
+	ret = 0;
+	init_waitqueue_head(&cpm->iic_wait);
+	mutex_init(&cpm->iic_mutex);
+	/* Initialize the parameter ram.
+	 * We need to make sure many things are initialized to zero,
+	 * especially in the case of a microcode patch.
+	 */
+	out_be32(&iip->iic_rstate, 0);
+	out_be32(&iip->iic_rdp, 0);
+	out_be16(&iip->iic_rbptr, 0);
+	out_be16(&iip->iic_rbc, 0);
+	out_be32(&iip->iic_rxtmp, 0);
+	out_be32(&iip->iic_tstate, 0);
+	out_be32(&iip->iic_tdp, 0);
+	out_be16(&iip->iic_tbptr, 0);
+	out_be16(&iip->iic_tbc, 0);
+	out_be32(&iip->iic_txtmp, 0);
+
+	/* Set up the IIC parameters in the parameter ram.
+	 */
+	out_be16(&iip->iic_tbase, cpm->dp_addr);
+	out_be16(&iip->iic_rbase, cpm->dp_addr + sizeof(cbd_t) * CPM_MAXBD);
+
+	if (cpm_debug) {
+		dev_dbg(&adap->dev, "iip %p, dp_addr 0x%x\n", cpm->iip,
+			cpm->dp_addr);
+		dev_dbg(&adap->dev, "iic_tbase %d, iic_rbase %d\n",
+			in_be16(&iip->iic_tbase), in_be16(&iip->iic_rbase));
+	}
+
+	out_8(&iip->iic_tfcr, SMC_EB);
+	out_8(&iip->iic_rfcr, SMC_EB);
+
+	/* Set maximum receive size.
+	 */
+	out_be16(&iip->iic_mrblr, CPM_MAX_READ);
+
+	/* Initialize Tx/Rx parameters.
+	 */
+	if (cpm->reloc == 0) {
+		cpm8xx_t *cp = cpm->cp;
+		int res;
+
+		u16 v = mk_cr_cmd(CPM_CR_CH_I2C, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+
+		out_be16(&cp->cp_cpcr, v);
+		res = wait_event_timeout(cpm->iic_wait,
+					 !(in_be16(&cp->cp_cpcr) & CPM_CR_FLG),
+					 HZ * 10);
+		if (!res)
+			return -EIO;
+
+	} else {
+		iip->iic_rbptr = iip->iic_rbase;
+		iip->iic_tbptr = iip->iic_tbase;
+		iip->iic_rstate = 0;
+		iip->iic_tstate = 0;
+	}
+
+	/* Select an arbitrary address.  Just make sure it is unique.
+	 */
+	out_8(&i2c->i2c_i2add, 0xfe);
+
+	/* Make clock run at 60 kHz.
+	 */
+	/* brg = ppc_proc_freq / (32 * 2 * 60000) - 3; */
+	brg = 7;
+	out_8(&i2c->i2c_i2brg, brg);
+
+	out_8(&i2c->i2c_i2mod, 0x00);
+	out_8(&i2c->i2c_i2com, 0x01);	/* Master mode */
+
+	/* Disable interrupts.
+	 */
+	out_8(&i2c->i2c_i2cmr, 0);
+	out_8(&i2c->i2c_i2cer, 0xff);
+
+	/* Allocate TX and RX buffers */
+	for (i = 0; i < CPM_MAXBD; i++) {
+		cpm->rxbuf[i] = (unsigned char *)dma_alloc_coherent(
+			NULL, CPM_MAX_READ + 1, &cpm->rxdma[i], GFP_KERNEL);
+		if (!cpm->rxbuf[i]) {
+			ret = -ENOMEM;
+			goto out;
+		}
+		cpm->txbuf[i] = (unsigned char *)dma_alloc_coherent(
+			NULL, CPM_MAX_READ + 1, &cpm->txdma[i], GFP_KERNEL);
+		if (!cpm->txbuf[i]) {
+			ret = -ENOMEM;
+			goto out;
+		}
+	}
+
+	/* Install interrupt handler.
+	 */
+	if (request_irq(cpm->irq, cpm_iic_interrupt, 0, "8xx_i2c", adap)) {
+		ret = -EIO;
+		goto out;
+	}
+
+	return 0;
+out:
+	for (i = 0; i < CPM_MAXBD; i++) {
+		if (cpm->rxbuf[i]) dma_free_coherent(NULL, CPM_MAX_READ + 1,
+			cpm->rxbuf[i], cpm->rxdma[i]);
+		if (cpm->txbuf[i]) dma_free_coherent(NULL, CPM_MAX_READ + 1,
+			cpm->txbuf[i], cpm->txdma[i]);
+	}
+	return ret;
+}
+
+static int cpm_iic_shutdown(struct i2c_adapter *adap)
+{
+	struct i2c_algo_cpm_data *cpm = adap->algo_data;
+	int i;
+
+	i2c8xx_t *i2c = cpm->i2c;
+
+	/* Shut down IIC.
+	 */
+	out_8(&i2c->i2c_i2mod, in_8(&i2c->i2c_i2mod) | ~1);
+	out_8(&i2c->i2c_i2cmr, 0);
+	out_8(&i2c->i2c_i2cer, 0xff);
+
+	for (i = 0; i < CPM_MAXBD; i++) {
+		if (cpm->rxbuf[i]) dma_free_coherent(NULL, CPM_MAX_READ + 1,
+			cpm->rxbuf[i], cpm->rxdma[i]);
+		if (cpm->txbuf[i]) dma_free_coherent(NULL, CPM_MAX_READ + 1,
+			cpm->txbuf[i], cpm->txdma[i]);
+	}
+
+	free_irq(cpm->irq, adap);
+
+	return (0);
+}
+
+static void cpm_reset_iic_params(struct i2c_algo_cpm_data *cpm)
+{
+	iic_t *iip = cpm->iip;
+
+	out_be16(&iip->iic_tbase, cpm->dp_addr);
+	out_be16(&iip->iic_rbase, cpm->dp_addr + sizeof(cbd_t) * CPM_MAXBD);
+
+	out_8(&iip->iic_tfcr, SMC_EB);
+	out_8(&iip->iic_rfcr, SMC_EB);
+
+	out_be16(&iip->iic_mrblr, CPM_MAX_READ);
+
+	out_be32(&iip->iic_rstate, 0);
+	out_be32(&iip->iic_rdp, 0);
+	out_be16(&iip->iic_rbptr, in_be16(&iip->iic_rbase));
+	out_be16(&iip->iic_rbc, 0);
+	out_be32(&iip->iic_rxtmp, 0);
+	out_be32(&iip->iic_tstate, 0);
+	out_be32(&iip->iic_tdp, 0);
+	out_be16(&iip->iic_tbptr, in_be16(&iip->iic_tbase));
+	out_be16(&iip->iic_tbc, 0);
+	out_be32(&iip->iic_txtmp, 0);
+}
+
+#define BD_SC_NAK		((ushort)0x0004) /* NAK - did not respond */
+#define BD_SC_OV		((ushort)0x0002) /* OV - receive overrun */
+#define CPM_CR_CLOSE_RXBD	((ushort)0x0007)
+
+static void force_close(struct i2c_adapter *adap)
+{
+	struct i2c_algo_cpm_data *cpm = adap->algo_data;
+	i2c8xx_t *i2c = cpm->i2c;
+	if (cpm->reloc == 0) {	/* micro code disabled */
+		cpm8xx_t *cp = cpm->cp;
+		u16 v =
+		    mk_cr_cmd(CPM_CR_CH_I2C, CPM_CR_CLOSE_RXBD) | CPM_CR_FLG;
+
+		if (cpm_debug)
+			printk(KERN_INFO "force_close()\n");
+
+		out_be16(&cp->cp_cpcr, v);
+		wait_event_timeout(cpm->iic_wait,
+				   !(in_be16(&cp->cp_cpcr) & CPM_CR_FLG),
+				   HZ * 5);
+	}
+	out_8(&i2c->i2c_i2cmr, 0x00);	/* Disable all interrupts */
+	out_8(&i2c->i2c_i2cer, 0xff);
+}
+
+static void cpm_parse_message(struct i2c_adapter *adap, struct i2c_msg *pmsg,
+	int num, int tx, int rx)
+{
+	cbd_t *tbdf, *rbdf;
+	u_char addr;
+	u_char *tb;
+	u_char *rb;
+	struct i2c_algo_cpm_data *cpm = adap->algo_data;
+	iic_t *iip = cpm->iip;
+	int i, dscan;
+
+	tbdf = (cbd_t *) cpm_dpram_addr(in_be16(&iip->iic_tbase));
+	rbdf = (cbd_t *) cpm_dpram_addr(in_be16(&iip->iic_rbase));
+
+	/* This chip can't do zero lenth writes. However, the i2c core uses
+	   them to scan for devices. The best we can do is to convert them
+	   into 1 byte reads */
+
+	dscan = ((pmsg->len == 0) && (num == 1));
+
+	addr = pmsg->addr << 1;
+	if ((pmsg->flags & I2C_M_RD) || dscan)
+		addr |= 1;
+
+	tb = cpm->txbuf[tx];
+	rb = cpm->rxbuf[rx];
+
+	/* Align read buffer */
+	rb = (u_char *) (((uint) rb + 1) & ~1);
+
+	if ((pmsg->flags & I2C_M_RD) || dscan) {
+		/* To read, we need an empty buffer of the proper length.
+		 * All that is used is the first byte for address, the remainder
+		 * is just used for timing (and doesn't really have to exist).
+		 */
+		tb[0] = addr;		/* Device address byte w/rw flag */
+
+		if (cpm_debug)
+			dev_dbg(&adap->dev, "cpm_iic_read(abyte=0x%x)\n", addr);
+		tbdf[tx].cbd_bufaddr = cpm->txdma[tx];
+		if (dscan)
+			tbdf[tx].cbd_datlen = 2;
+		else
+			tbdf[tx].cbd_datlen = pmsg->len + 1;
+		tbdf[tx].cbd_sc = 0;
+		if (!(pmsg->flags & I2C_M_NOSTART))
+			tbdf[tx].cbd_sc |= BD_IIC_START;
+		if (tx + 1 == num)
+			tbdf[tx].cbd_sc |= BD_SC_LAST | BD_SC_WRAP;
+
+		rbdf[rx].cbd_datlen = 0;
+		rbdf[rx].cbd_bufaddr = ((cpm->rxdma[rx] + 1) & ~1);
+		rbdf[rx].cbd_sc = BD_SC_EMPTY | BD_SC_INTRPT;
+		if (rx + 1 == CPM_MAXBD)
+			tbdf[rx].cbd_sc |= BD_SC_WRAP;
+
+		tbdf[tx].cbd_sc |= BD_SC_READY;
+	} else {
+		tb[0] = addr;		/* Device address byte w/rw flag */
+		for (i = 0; i < pmsg->len; i++)
+			tb[i+1] = pmsg->buf[i];
+
+		if (cpm_debug)
+			dev_dbg(&adap->dev, "cpm_iic_write(abyte=0x%x)\n",
+				addr);
+		tbdf[tx].cbd_bufaddr = cpm->txdma[tx];
+		tbdf[tx].cbd_datlen = pmsg->len + 1;
+		tbdf[tx].cbd_sc = 0;
+		if (!(pmsg->flags & I2C_M_NOSTART))
+			tbdf[tx].cbd_sc |= BD_IIC_START;
+		if (tx + 1 == num)
+			tbdf[tx].cbd_sc |= BD_SC_LAST | BD_SC_WRAP;
+		tbdf[tx].cbd_sc |= BD_SC_READY | BD_SC_INTRPT;
+		dev_dbg(&adap->dev, "tx sc %d %04x\n",
+			tx, tbdf[tx].cbd_sc);
+	}
+}
+
+static int cpm_check_message(struct i2c_adapter *adap, struct i2c_msg *pmsg,
+	int tx, int rx)
+{
+	cbd_t *tbdf, *rbdf;
+	u_char *tb;
+	u_char *rb;
+	struct i2c_algo_cpm_data *cpm = adap->algo_data;
+	iic_t *iip = cpm->iip;
+	int i;
+
+	tbdf = (cbd_t *) cpm_dpram_addr(in_be16(&iip->iic_tbase));
+	rbdf = (cbd_t *) cpm_dpram_addr(in_be16(&iip->iic_rbase));
+
+	tb = cpm->txbuf[tx];
+	rb = cpm->rxbuf[rx];
+
+	/* Align read buffer */
+	rb = (u_char *) (((uint) rb + 1) & ~1);
+
+	if (pmsg->flags & I2C_M_RD) {
+		if (cpm_debug)
+			dev_dbg(&adap->dev, "rx sc %04x, rx sc %04x\n",
+				tbdf[tx].cbd_sc, rbdf[rx].cbd_sc);
+		if (tbdf[tx].cbd_sc & BD_SC_NAK) {
+			if (cpm_debug)
+				dev_dbg(&adap->dev, "IIC read; no ack\n");
+			if (pmsg->flags & I2C_M_IGNORE_NAK)
+				return 0;
+			else
+				return -EREMOTEIO;
+		}
+		if (rbdf[rx].cbd_sc & BD_SC_EMPTY) {
+			if (cpm_debug) {
+				dev_dbg(&adap->dev,
+					"IIC read; complete but rbuf empty\n");
+			}
+			return -EREMOTEIO;
+		}
+		if (rbdf[rx].cbd_sc & BD_SC_OV) {
+			if (cpm_debug)
+				dev_dbg(&adap->dev, "IIC read; Overrun\n");
+			return -EREMOTEIO;
+		}
+		for (i = 0; i < pmsg->len; i++)
+			pmsg->buf[i] = rb[i];
+	} else {
+		if (cpm_debug)
+			dev_dbg(&adap->dev, "tx sc %d %04x\n",
+				tx, tbdf[tx].cbd_sc);
+		if (tbdf[tx].cbd_sc & BD_SC_NAK) {
+			if (cpm_debug)
+				dev_dbg(&adap->dev, "IIC write; no ack\n");
+			if (pmsg->flags & I2C_M_IGNORE_NAK)
+				return 0;
+			else
+				return -EIO;
+		}
+	}
+	return 0;
+}
+
+static int cpm_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+	struct i2c_algo_cpm_data *cpm = adap->algo_data;
+	i2c8xx_t *i2c = cpm->i2c;
+	iic_t *iip = cpm->iip;
+	struct i2c_msg *pmsg, *rmsg;
+	int ret, i;
+	int tptr;
+	int rptr;
+	cbd_t *tbdf, *rbdf;
+
+	if (num > CPM_MAXBD)
+		return -EREMOTEIO;
+
+	/* Check if we have any oversized READ requests */
+	for (i = 0; i < num; i++) {
+		pmsg = &msgs[i];
+		if (pmsg->len >= CPM_MAX_READ)
+			return -EREMOTEIO;
+	}
+
+	mutex_lock(&cpm->iic_mutex);
+
+	/* check for and use a microcode relocation patch */
+	if (cpm->reloc)
+		cpm_reset_iic_params(cpm);
+
+	/* Reset to use first buffer */
+	out_be16(&iip->iic_rbptr, in_be16(&iip->iic_rbase));
+	out_be16(&iip->iic_tbptr, in_be16(&iip->iic_tbase));
+
+	tbdf = (cbd_t *) cpm_dpram_addr(in_be16(&iip->iic_tbase));
+	rbdf = (cbd_t *) cpm_dpram_addr(in_be16(&iip->iic_rbase));
+
+	tptr = 0;
+	rptr = 0;
+
+	while (tptr < num) {
+		pmsg = &msgs[tptr];
+		if (cpm_debug)
+			dev_dbg(&adap->dev, "i2c-algo-cpm.o: "
+				"R: %d T: %d\n",
+				rptr, tptr);
+
+		cpm_parse_message(adap, pmsg, num, tptr, rptr);
+		if (pmsg->flags & I2C_M_RD)
+			rptr++;
+		tptr++;
+	}
+	/* Start transfer now */
+	/* Chip bug, set enable here */
+	out_8(&i2c->i2c_i2cmr, 0x13);	/* Enable some interupts */
+	out_8(&i2c->i2c_i2cer, 0xff);
+	out_8(&i2c->i2c_i2mod, in_8(&i2c->i2c_i2mod) | 1);	/* Enable */
+	/* Begin transmission */
+	out_8(&i2c->i2c_i2com, in_8(&i2c->i2c_i2com) | 0x80);
+
+	tptr = 0;
+	rptr = 0;
+
+	while (tptr < num) {
+		/* Check for outstanding messages */
+		dev_dbg(&adap->dev, "test ready.\n");
+		if (!(tbdf[tptr].cbd_sc & BD_SC_READY)) {
+			dev_dbg(&adap->dev, "ready.\n");
+			rmsg = &msgs[tptr];
+			ret = cpm_check_message(adap, rmsg, tptr, rptr);
+			tptr++;
+			if (rmsg->flags & I2C_M_RD)
+				rptr++;
+			if (ret) {
+				force_close(adap);
+				mutex_unlock(&cpm->iic_mutex);
+				return -EREMOTEIO;
+			}
+		} else {
+			dev_dbg(&adap->dev, "not ready.\n");
+			ret = wait_event_interruptible_timeout(cpm->iic_wait,
+				!(tbdf[tptr].cbd_sc & BD_SC_READY), 1 * HZ);
+			if (ret == 0) {
+				force_close(adap);
+				if (cpm_debug)
+					dev_dbg(&adap->dev,
+						"IIC read: timeout!\n");
+				mutex_unlock(&cpm->iic_mutex);
+				return -EREMOTEIO;
+			}
+		}
+	}
+#ifdef I2C_CHIP_ERRATA
+	/* Chip errata, clear enable. This is not needed on rev D4 CPUs.
+	   Disabling I2C too early may cause too short stop condition */
+	udelay(4);
+	out_8(&i2c->i2c_i2mod, in_8(&i2c->i2c_i2mod) | ~1);
+#endif
+	mutex_unlock(&cpm->iic_mutex);
+	return (num);
+}
+
+static u32 cpm_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+/* -----exported algorithm data: -------------------------------------	*/
+
+static struct i2c_algorithm cpm_algo = {
+	.master_xfer = cpm_xfer,
+	.functionality = cpm_func,
+};
+
+/*
+ * registering functions to load algorithms at runtime
+ */
+int i2c_cpm_add_bus(struct i2c_adapter *adap)
+{
+	int res;
+
+	if (cpm_debug)
+		dev_dbg(&adap->dev,
+			"i2c-algo-cpm.o: hw routines for %s registered.\n",
+			adap->name);
+
+	/* register new adapter to i2c module... */
+
+	adap->algo = &cpm_algo;
+
+	res = cpm_iic_init(adap);
+
+	if (res)
+		return res;
+
+	return i2c_add_adapter(adap);
+}
+EXPORT_SYMBOL(i2c_cpm_add_bus);
+
+int i2c_cpm_del_bus(struct i2c_adapter *adap)
+{
+	i2c_del_adapter(adap);
+
+	return cpm_iic_shutdown(adap);
+}
+EXPORT_SYMBOL(i2c_cpm_del_bus);
+
+MODULE_AUTHOR("Brad Parker <brad@heeltoe.com>");
+MODULE_DESCRIPTION("I2C-Bus CPM algorithm");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index de95c75..705997b 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -4,6 +4,28 @@
 
 menu "I2C Hardware Bus support"
 
+config I2C_8XX_PPC
+	tristate "MPC8xx CPM oldstyle (no OF)"
+	depends on 8xx && I2C && !OF
+	select I2C_ALGOCPM
+	help
+	  This supports the use of the I2C interface on Freescale MPC8xx
+	  processors.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-8xx-ppc.
+
+config I2C_8XX
+	tristate "MPC8xx CPM with Open Firmware"
+	depends on 8xx && I2C && OF
+	select I2C_ALGOCPM
+	help
+	  This supports the use of the I2C interface on Freescale MPC8xx
+	  processors.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-8xx.
+
 config I2C_ALI1535
 	tristate "ALI 1535"
 	depends on PCI
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 81d43c2..f2feb4b 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -2,6 +2,8 @@
 # Makefile for the i2c bus drivers.
 #
 
+obj-$(CONFIG_I2C_8XX_PPC)	+= i2c-8xx-ppc.o
+obj-$(CONFIG_I2C_8XX)		+= i2c-8xx.o
 obj-$(CONFIG_I2C_ALI1535)	+= i2c-ali1535.o
 obj-$(CONFIG_I2C_ALI1563)	+= i2c-ali1563.o
 obj-$(CONFIG_I2C_ALI15X3)	+= i2c-ali15x3.o
diff --git a/drivers/i2c/busses/i2c-8xx-ppc.c b/drivers/i2c/busses/i2c-8xx-ppc.c
new file mode 100644
index 0000000..88b1642
--- /dev/null
+++ b/drivers/i2c/busses/i2c-8xx-ppc.c
@@ -0,0 +1,105 @@
+/*
+ * Embedded Planet RPX Lite MPC8xx CPM I2C interface.
+ * Copyright (c) 1999 Dan Malek (dmalek@jlc.net).
+ *
+ * moved into proper i2c interface;
+ * Brad Parker (brad@heeltoe.com)
+ *
+ * RPX lite specific parts of the i2c interface
+ * Update:  There actually isn't anything RPXLite-specific about this module.
+ * This should work for most any 8xx board.  The console messages have been
+ * changed to eliminate RPXLite references.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/stddef.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-cpm.h>
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <asm/mpc8xx.h>
+#include <asm/commproc.h>
+
+static int
+m8xx_iic_init(struct i2c_algo_cpm_data *data)
+{
+	cpm8xx_t *cp;
+	immap_t *immap;
+
+	immap = (immap_t *)IMAP_ADDR;	/* and to internal registers */
+	/* Get pointer to Communication Processor */
+	cp = (cpm8xx_t *)&immap->im_cpm;
+
+	data->iip = (iic_t *)&cp->cp_dparam[PROFF_IIC];
+
+	/* Check for and use a microcode relocation patch.
+	*/
+	data->reloc = in_be16(&data->iip->iic_rpbase);
+	if (data->reloc)
+		data->iip = (iic_t *)&cp->cp_dpmem[data->reloc];
+
+	data->i2c = (i2c8xx_t *)&(immap->im_i2c);
+	data->cp = cp;
+
+	/* Initialize Port B IIC pins.
+	*/
+	setbits32(&cp->cp_pbpar, 0x00000030);
+	setbits32(&cp->cp_pbdir, 0x00000030);
+	setbits16(&cp->cp_pbodr, 0x0030);
+
+	/* Allocate space for transmit and receive buffer
+	 * descriptors in the DP ram.
+	 */
+	data->dp_addr = cpm_dpalloc(sizeof(cbd_t) * 2 * CPM_MAXBD, 8);
+	if (!data->dp_addr)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static struct i2c_algo_cpm_data m8xx_data = {
+	.irq = CPM_IRQ_OFFSET + CPMVEC_I2C,
+};
+
+static struct i2c_adapter m8xx_ops = {
+	.owner		= THIS_MODULE,
+	.name		= "i2c-8xx-ppc",
+	.id		= I2C_HW_MPC8XX_EPON,
+	.algo_data	= &m8xx_data,
+	.dev.parent	= &platform_bus,
+	.class		= I2C_CLASS_HWMON,
+};
+
+int __init i2c_8xx_init(void)
+{
+	int ret;
+
+	printk(KERN_INFO "i2c-8xx-ppc: i2c MPC8xx driver\n");
+
+	/* reset hardware to sane state */
+	ret = m8xx_iic_init(&m8xx_data);
+	if (ret)
+		return ret;
+
+	if (i2c_cpm_add_bus(&m8xx_ops) < 0) {
+		printk(KERN_ERR "i2c-8xx-ppc: Unable to register with I2C\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+void __exit i2c_8xx_exit(void)
+{
+	i2c_cpm_del_bus(&m8xx_ops);
+}
+
+module_init(i2c_8xx_init);
+module_exit(i2c_8xx_exit);
+
+MODULE_AUTHOR("Dan Malek <dmalek@jlc.net>");
+MODULE_DESCRIPTION("I2C-Bus adapter routines for MPC8xx boards");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-8xx.c b/drivers/i2c/busses/i2c-8xx.c
new file mode 100644
index 0000000..c38b52e
--- /dev/null
+++ b/drivers/i2c/busses/i2c-8xx.c
@@ -0,0 +1,170 @@
+/*
+ * Embedded Planet RPX Lite MPC8xx CPM I2C interface.
+ * Copyright (c) 1999 Dan Malek (dmalek@jlc.net).
+ *
+ * moved into proper i2c interface;
+ * Brad Parker (brad@heeltoe.com)
+ *
+ * (C) 2007 Montavista Software, Inc.
+ * Vitaly Bordug <vitb@kernel.crashing.org>
+ *
+ * RPX lite specific parts of the i2c interface
+ * Update:  There actually isn't anything RPXLite-specific about this module.
+ * This should work for most any 8xx board.  The console messages have been
+ * changed to eliminate RPXLite references.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/stddef.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-cpm.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <asm/mpc8xx.h>
+#include <asm/commproc.h>
+#include <asm/fs_pd.h>
+
+
+struct m8xx_i2c {
+	char *base;
+	struct of_device *ofdev;
+	struct i2c_adapter adap;
+	struct i2c_algo_cpm_data *algo_8xx;
+};
+
+static struct i2c_algo_cpm_data m8xx_data;
+
+static const struct i2c_adapter m8xx_ops = {
+	.owner		= THIS_MODULE,
+	.name		= "i2c-8xx",
+	.id		= I2C_HW_MPC8XX_EPON,
+	.algo_data	= &m8xx_data,
+	.dev.parent	= &platform_bus,
+	.class		= I2C_CLASS_HWMON,
+};
+
+static int m8xx_iic_init(struct m8xx_i2c *i2c)
+{
+	cpm8xx_t *cp;
+	struct resource r;
+	struct i2c_algo_cpm_data *data = i2c->algo_8xx;
+	struct of_device *ofdev = i2c->ofdev;
+	struct device_node *np = ofdev->node;
+
+	/* Pointer to Communication Processor
+	 */
+	cp = (cpm8xx_t *)immr_map(im_cpm);
+	data->cp = cp;
+
+	data->irq = irq_of_parse_and_map(np, 0);
+	if (data->irq < 0)
+		return -EINVAL;
+
+	if (of_address_to_resource(np, 1, &r))
+		return -EINVAL;
+
+	data->iip = ioremap(r.start, r.end - r.start + 1);
+	if (data->iip == NULL)
+		return -EINVAL;
+
+	/* Check for and use a microcode relocation patch.
+	 */
+	data->reloc = data->iip->iic_rpbase;
+	if (data->reloc)
+		data->iip = (iic_t *)&cp->cp_dpmem[data->iip->iic_rpbase];
+
+	if (of_address_to_resource(np, 0, &r))
+		return -EINVAL;
+
+	data->i2c = ioremap(r.start, r.end - r.start + 1);
+	if (data->i2c == NULL)
+		return -EINVAL;
+
+	/* Allocate space for two transmit and two receive buffer
+	 * descriptors in the DP ram.
+	 */
+	data->dp_addr = cpm_dpalloc(sizeof(cbd_t) * 4, 8);
+	if (!data->dp_addr)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static int i2c_8xx_probe(struct of_device *ofdev,
+			 const struct of_device_id *match)
+{
+	int result;
+	struct m8xx_i2c *i2c;
+
+	i2c = kzalloc(sizeof(*i2c), GFP_KERNEL);
+	if (!i2c)
+		return -ENOMEM;
+
+	i2c->ofdev = ofdev;
+	i2c->algo_8xx = &m8xx_data;
+
+	m8xx_iic_init(i2c);
+
+	dev_set_drvdata(&ofdev->dev, i2c);
+
+	i2c->adap = m8xx_ops;
+	i2c_set_adapdata(&i2c->adap, i2c);
+	i2c->adap.dev.parent = &ofdev->dev;
+
+	result = i2c_cpm_add_bus(&i2c->adap);
+	if (result < 0) {
+		printk(KERN_ERR "i2c-8xx: Unable to register with I2C\n");
+		kfree(i2c);
+	}
+
+	return result;
+}
+
+static int i2c_8xx_remove(struct of_device *ofdev)
+{
+	struct m8xx_i2c *i2c = dev_get_drvdata(&ofdev->dev);
+
+	i2c_cpm_del_bus(&i2c->adap);
+	dev_set_drvdata(&ofdev->dev, NULL);
+
+	kfree(i2c);
+	return 0;
+}
+
+static struct of_device_id i2c_8xx_match[] = {
+	{
+		.type = "i2c",
+		.compatible = "fsl,i2c-cpm",
+	},
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, i2c_8xx_match);
+
+static struct of_platform_driver i2c_8xx_driver = {
+	.name		= "fsl-i2c-cpm",
+	.match_table	= i2c_8xx_match,
+	.probe		= i2c_8xx_probe,
+	.remove		= i2c_8xx_remove,
+};
+
+static int __init i2c_8xx_init(void)
+{
+	return of_register_platform_driver(&i2c_8xx_driver);
+}
+
+static void __exit i2c_8xx_exit(void)
+{
+	of_unregister_platform_driver(&i2c_8xx_driver);
+}
+
+module_init(i2c_8xx_init);
+module_exit(i2c_8xx_exit);
+
+MODULE_AUTHOR("Dan Malek <dmalek@jlc.net>");
+MODULE_DESCRIPTION("I2C-Bus adapter routines for MPC8xx boards");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/i2c-algo-cpm.h b/include/linux/i2c-algo-cpm.h
new file mode 100644
index 0000000..2192b7d
--- /dev/null
+++ b/include/linux/i2c-algo-cpm.h
@@ -0,0 +1,34 @@
+/* ------------------------------------------------------------------------- */
+/* i2c-algo-cpm.h i2c driver algorithms for MPX8XX CPM or MPC8250 CPM2       */
+/* ------------------------------------------------------------------------- */
+
+#ifndef I2C_ALGO_CPM_H
+#define I2C_ALGO_CPM_H
+
+#include <linux/i2c.h>
+#include <asm/8xx_immap.h>
+#include <asm/commproc.h>
+
+#define CPM_MAX_READ    513
+#define CPM_MAXBD       4
+
+struct i2c_algo_cpm_data {
+	uint dp_addr;
+	int reloc;
+	int irq;
+	i2c8xx_t *i2c;
+	iic_t *iip;
+	cpm8xx_t *cp;
+	wait_queue_head_t iic_wait;
+	struct mutex iic_mutex; /* Protects I2C CPM */
+	u_char *txbuf[CPM_MAXBD];
+	u_char *rxbuf[CPM_MAXBD];
+	u32 txdma[CPM_MAXBD];
+	u32 rxdma[CPM_MAXBD];
+};
+
+extern int i2c_cpm_add_bus(struct i2c_adapter *);
+extern int i2c_cpm_del_bus(struct i2c_adapter *);
+
+#endif /* I2C_ALGO_CPM_H */
+


^ permalink raw reply related

* [BUG] Linux 2.6.23.1 - Open Firmware exception handler invoked
From: Kamalesh Babulal @ 2007-10-15 11:08 UTC (permalink / raw)
  To: linux-kernel; +Cc: linuxppc-dev, Greg Kroah-Hartman, stable
In-Reply-To: <20071012170140.GA18498@kroah.com>

Hi,

The Open Firmware exception handler is begin invoked, on power5 lpar.

boot: 2.6.23.1
Please wait, loading kernel...
Allocated 03500000 bytes for kernel @ 01c00000
   Elf64 kernel loaded...
Loading ramdisk...
ramdisk loaded 0020d000 @ 06b00000
DEFAULT CATCH!, exception-handler=fff00300 
at   %SRR0: c00000000202705c   %SRR1: 8000000000003002 
Open Firmware exception handler entered from non-OF code

Client's Fix Pt Regs:
 00 0223100003080000 00000000018bfac0 0000000004bbeaf8 00000000018bfb48
 04 00000000018bfc90 0000000000c39a48 0000000000000000 5c3a03080000a0fa
 08 0000000000000001 0000000000000000 05910000194c0223 000000005cae0000
 0c 0000000003f1eaf8 0000000000000000 0000000000000000 0000000000000000
 10 0000000000000000 0000000000c39a48 0000000000000000 00000000018bfc90
 14 0000000000c00000 000000000020d000 0000000000000000 0000000008b00000
 18 0000000000280004 00000000018bff04 0000000000000001 0000000000000000
 1c 0000000008b00000 0000000000c39a48 c000000004d1e530 0000000008b00000
Special Regs:
    %IV: 00000300     %CR: 44000028    %XER: 00000000  %DSISR: 08000000 
  %SRR0: c00000000202705c   %SRR1: 8000000000003002 
    %LR: c000000002027428    %CTR: c0000000020273f0 
   %DAR: 05910000194c02eb 
Virtual PID = 0 
PFW: Unable to send error log!
 ofdbg
0 > 

# cat /proc/cpuinfo 
processor       : 0
cpu             : POWER5+ (gs)
clock           : 1498.500000MHz
revision        : 2.0 (pvr 003b 0200)

processor       : 1
cpu             : POWER5+ (gs)
clock           : 1498.500000MHz
revision        : 2.0 (pvr 003b 0200)

timebase        : 187199000
platform        : pSeries
machine         : CHRP IBM,9133-55A
-- 
Thanks & Regards,
Kamalesh Babulal,
Linux Technology Center,
IBM, ISTL.

^ permalink raw reply

* Re: [PATCH v3 4/4] FEC mpc52xx: phy part of the driver\
From: Domen Puncer @ 2007-10-15 10:56 UTC (permalink / raw)
  To: Grant Likely; +Cc: linuxppc-dev, jgarzik, netdev
In-Reply-To: <fa686aa40710141505w1787e7e1g6116185001561a4d@mail.gmail.com>

On 14/10/07 16:05 -0600, Grant Likely wrote:
> On 10/14/07, Domen Puncer <domen.puncer@telargo.com> wrote:
> > PHY part of the driver for mpc5200(b) ethernet.
> 
> Assuming I understand correctly, this comment is not correct and this
> patch just adds an MDIO bus driver.  PHY drivers are in phylib and
> data transfer is setup via the core driver, correct?

Right.

> 
> It is conceivable that the PHY is connected to an alternate MDIO bus,
> or the MDIO bus is used for a PHY connected to an external Ethernet
> controller.
> 
> Speaking of which, is it possible to use this MDIO bus without the
> core FEC being initialized?

IIRC fec doesn't need any initialization for MDIO bus registers to work.

> 
> > +static struct of_device_id fec_mdio_match[] = {
> > +       {
> > +               .type = "mdio",
> > +               .compatible = "mpc5200b-fec-phy",
> 
> This is not a phy; it's an MDIO bus.  Also, shouldn't this be
> "mpc5200-..." instead of "mpc5200b-..."?

Didn't know if it's ok for mpc5200, guess it is?

> 
> > +       },
> > +       {},
> > +};
> > +
> > +struct of_platform_driver mpc52xx_fec_mdio_driver = {
> > +       .name = "mpc5200b-fec-phy",
> > +       .probe = fec_mdio_probe,
> > +       .remove = fec_mdio_remove,
> > +       .match_table = fec_mdio_match,
> 
> Inconsistent naming.  Please use the same prefix on all global/static
> symbols (ie. use "mpc52xx_mdio_" instead of the mix of
> "mpc52xx_fec_mdio_", "fec_mdio_", etc.)  I also thing that "fec_mdio_"
> is too generic because there are a number of different incompatible
> FEC devices.

OK.

> 
> > +};
> > +
> > +/* let fec driver call it, since this has to be registered before it */
> > +EXPORT_SYMBOL_GPL(mpc52xx_fec_mdio_driver);
> 
> Why not have a module_init()/module_exit() in this file?  I don't
> think the FEC driver calls this driver's functions directly anymore,
> and it's still dependent on the of_platform bus probe order anyway.

It was one way of making sure mdio driver is registered before fec.
(and of_platform bus probe order won't work for modules)
Nicer alternatives?

> 
> As an added bonus, it makes your Makefile much simpler.
> 
> > +
> > +
> > +MODULE_LICENSE("Dual BSD/GPL");
> > Index: linux.git/drivers/net/fec_mpc52xx/Makefile
> > ===================================================================
> > --- linux.git.orig/drivers/net/fec_mpc52xx/Makefile
> > +++ linux.git/drivers/net/fec_mpc52xx/Makefile
> > @@ -1,2 +1,7 @@
> >  obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx.o
> >  fec_mpc52xx-objs := fec.o
> > +
> > +ifeq ($(CONFIG_FEC_MPC52xx_MDIO),y)
> > +       obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx_phy.o
> > +       fec_mpc52xx_phy-objs := fec_phy.o
> > +endif
> > Index: linux.git/drivers/net/fec_mpc52xx/Kconfig
> > ===================================================================
> > --- linux.git.orig/drivers/net/fec_mpc52xx/Kconfig
> > +++ linux.git/drivers/net/fec_mpc52xx/Kconfig
> > @@ -11,5 +11,18 @@ config FEC_MPC52xx
> >         ---help---
> >           This option enables support for the MPC5200's on-chip
> >           Fast Ethernet Controller
> > +         If compiled as module, it will be called 'fec_mpc52xx.ko'.
> 
> Drop this line and make the help text the same format as the other eth
> drivers in drivers/net.

How exactly is it different now?
And most of them have the "Module will be called xxx" line.

> 
> > +
> > +config FEC_MPC52xx_MDIO
> > +       bool "FEC MII PHY driver"
> > +       depends on FEC_MPC52xx
> > +       default y
> > +       ---help---
> > +         The MPC5200's FEC can connect to the Ethernet either with
> > +         an external MII PHY chip or 10 Mbps 7-wire interface
> > +         (Motorola? industry standard).
> > +         If your board uses an external PHY, enable this.
> 
> Not strictly true.  This enables talking to a PHY using the internal
> MDIO controller.  PHY register access could just as easily be accessed
> via an alternate interface.

Not just that is also selects which mode will it use.
If you don't enable this, fec will be set up as 7-wire
( 696                 rcntrl |= FEC_RCNTRL_MII_MODE;)


> 
> > +         If not sure, enable.
> > +         If compiled as module, it will be called 'fec_mpc52xx_phy.ko'.
> 
> Drop the module name comment.
> 
> Cheers,
> g.
> 
> -- 
> Grant Likely, B.Sc., P.Eng.
> Secret Lab Technologies Ltd.
> grant.likely@secretlab.ca
> (403) 399-0195

-- 
Domen Puncer | Research & Development
.............................................................................................
Telargo d.o.o. | Zagrebška cesta 20 | 2000 Maribor | Slovenia
.............................................................................................
www.telargo.com

^ permalink raw reply

* [PATCH] PS3 system bus add_uevent_var() fallout
From: Geert Uytterhoeven @ 2007-10-15  9:51 UTC (permalink / raw)
  To: Linus Torvalds, Andrew Morton, Paul Mackerras
  Cc: Linux/PPC Development, Linux Kernel Development

[-- Attachment #1: Type: TEXT/PLAIN, Size: 1238 bytes --]

PS3 system bus add_uevent_var() fallout: kill unused variables

Signed-off-by: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
---
 arch/powerpc/platforms/ps3/system-bus.c |    1 -
 1 files changed, 1 deletion(-)

--- a/arch/powerpc/platforms/ps3/system-bus.c
+++ b/arch/powerpc/platforms/ps3/system-bus.c
@@ -440,7 +440,6 @@ static void ps3_system_bus_shutdown(stru
 static int ps3_system_bus_uevent(struct device *_dev, struct kobj_uevent_env *env)
 {
 	struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
-	int i = 0, length = 0;
 
 	if (add_uevent_var(env, "MODALIAS=ps3:%d", dev->match_id))
 		return -ENOMEM;

With kind regards,
 
Geert Uytterhoeven
Software Architect

Sony Network and Software Technology Center Europe
The Corporate Village · Da Vincilaan 7-D1 · B-1935 Zaventem · Belgium
 
Phone:    +32 (0)2 700 8453	
Fax:      +32 (0)2 700 8622	
E-mail:   Geert.Uytterhoeven@sonycom.com	
Internet: http://www.sony-europe.com/
 	
Sony Network and Software Technology Center Europe	
A division of Sony Service Centre (Europe) N.V.	
Registered office: Technologielaan 7 · B-1840 Londerzeel · Belgium	
VAT BE 0413.825.160 · RPR Brussels	
Fortis Bank Zaventem · Swift GEBABEBB08A · IBAN BE39001382358619

^ permalink raw reply

* [PATCH 5/5] Remove msic_dcr_read() in axon_msi.c
From: Michael Ellerman @ 2007-10-15  9:34 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev, jgarzik
In-Reply-To: <33ee227bae85a8d7ccde69a717cff47000888354.1192440801.git.michael@ellerman.id.au>

msic_dcr_read() doesn't really do anything useful, just replace it with
direct calls to dcr_read().

Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
 arch/powerpc/platforms/cell/axon_msi.c |    9 ++-------
 1 files changed, 2 insertions(+), 7 deletions(-)

diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c
index aca1500..095988f 100644
--- a/arch/powerpc/platforms/cell/axon_msi.c
+++ b/arch/powerpc/platforms/cell/axon_msi.c
@@ -80,18 +80,13 @@ static void msic_dcr_write(struct axon_msic *msic, unsigned int dcr_n, u32 val)
 	dcr_write(msic->dcr_host, dcr_n, val);
 }
 
-static u32 msic_dcr_read(struct axon_msic *msic, unsigned int dcr_n)
-{
-	return dcr_read(msic->dcr_host, dcr_n);
-}
-
 static void axon_msi_cascade(unsigned int irq, struct irq_desc *desc)
 {
 	struct axon_msic *msic = get_irq_data(irq);
 	u32 write_offset, msi;
 	int idx;
 
-	write_offset = msic_dcr_read(msic, MSIC_WRITE_OFFSET_REG);
+	write_offset = dcr_read(msic->dcr_host, MSIC_WRITE_OFFSET_REG);
 	pr_debug("axon_msi: original write_offset 0x%x\n", write_offset);
 
 	/* write_offset doesn't wrap properly, so we have to mask it */
@@ -306,7 +301,7 @@ static int axon_msi_notify_reboot(struct notifier_block *nb,
 	list_for_each_entry(msic, &axon_msic_list, list) {
 		pr_debug("axon_msi: disabling %s\n",
 			  msic->irq_host->of_node->full_name);
-		tmp  = msic_dcr_read(msic, MSIC_CTRL_REG);
+		tmp  = dcr_read(msic->dcr_host, MSIC_CTRL_REG);
 		tmp &= ~MSIC_CTRL_ENABLE & ~MSIC_CTRL_IRQ_ENABLE;
 		msic_dcr_write(msic, MSIC_CTRL_REG, tmp);
 	}
-- 
1.5.1.3.g7a33b

^ permalink raw reply related

* [PATCH 4/5] Use dcr_host_t.base in dcr_unmap()
From: Michael Ellerman @ 2007-10-15  9:34 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev, jgarzik
In-Reply-To: <33ee227bae85a8d7ccde69a717cff47000888354.1192440801.git.michael@ellerman.id.au>

With the base stored in dcr_host_t, there's no need for callers to pass
the dcr_n into dcr_unmap(). In fact this removes the possibility of them
passing the incorrect value, which would then be iounmap()'ed.

Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
 arch/powerpc/sysdev/dcr.c        |    4 ++--
 drivers/net/ibm_newemac/mal.c    |    2 +-
 include/asm-powerpc/dcr-mmio.h   |    2 +-
 include/asm-powerpc/dcr-native.h |    2 +-
 4 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/arch/powerpc/sysdev/dcr.c b/arch/powerpc/sysdev/dcr.c
index ab11c0b..427027c 100644
--- a/arch/powerpc/sysdev/dcr.c
+++ b/arch/powerpc/sysdev/dcr.c
@@ -126,13 +126,13 @@ dcr_host_t dcr_map(struct device_node *dev, unsigned int dcr_n,
 }
 EXPORT_SYMBOL_GPL(dcr_map);
 
-void dcr_unmap(dcr_host_t host, unsigned int dcr_n, unsigned int dcr_c)
+void dcr_unmap(dcr_host_t host, unsigned int dcr_c)
 {
 	dcr_host_t h = host;
 
 	if (h.token == NULL)
 		return;
-	h.token += dcr_n * h.stride;
+	h.token += host.base * h.stride;
 	iounmap(h.token);
 	h.token = NULL;
 }
diff --git a/drivers/net/ibm_newemac/mal.c b/drivers/net/ibm_newemac/mal.c
index 748a869..39f4cb6 100644
--- a/drivers/net/ibm_newemac/mal.c
+++ b/drivers/net/ibm_newemac/mal.c
@@ -627,7 +627,7 @@ static int __devinit mal_probe(struct of_device *ofdev,
  fail2:
 	dma_free_coherent(&ofdev->dev, bd_size, mal->bd_virt, mal->bd_dma);
  fail_unmap:
-	dcr_unmap(mal->dcr_host, dcr_base, 0x100);
+	dcr_unmap(mal->dcr_host, 0x100);
  fail:
 	kfree(mal);
 
diff --git a/include/asm-powerpc/dcr-mmio.h b/include/asm-powerpc/dcr-mmio.h
index a7d9eaf..08532ff 100644
--- a/include/asm-powerpc/dcr-mmio.h
+++ b/include/asm-powerpc/dcr-mmio.h
@@ -33,7 +33,7 @@ typedef struct {
 
 extern dcr_host_t dcr_map(struct device_node *dev, unsigned int dcr_n,
 			  unsigned int dcr_c);
-extern void dcr_unmap(dcr_host_t host, unsigned int dcr_n, unsigned int dcr_c);
+extern void dcr_unmap(dcr_host_t host, unsigned int dcr_c);
 
 static inline u32 dcr_read(dcr_host_t host, unsigned int dcr_n)
 {
diff --git a/include/asm-powerpc/dcr-native.h b/include/asm-powerpc/dcr-native.h
index 3bc780f..8dbb1ab 100644
--- a/include/asm-powerpc/dcr-native.h
+++ b/include/asm-powerpc/dcr-native.h
@@ -29,7 +29,7 @@ typedef struct {
 #define DCR_MAP_OK(host)	(1)
 
 #define dcr_map(dev, dcr_n, dcr_c)	((dcr_host_t){ .base = (dcr_n) })
-#define dcr_unmap(host, dcr_n, dcr_c)	do {} while (0)
+#define dcr_unmap(host, dcr_c)		do {} while (0)
 #define dcr_read(host, dcr_n)		mfdcr(dcr_n + host.base)
 #define dcr_write(host, dcr_n, value)	mtdcr(dcr_n + host.base, value)
 
-- 
1.5.1.3.g7a33b

^ permalink raw reply related

* [PATCH 3/5] Add dcr_host_t.base in dcr_read()/dcr_write()
From: Michael Ellerman @ 2007-10-15  9:34 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev, jgarzik
In-Reply-To: <33ee227bae85a8d7ccde69a717cff47000888354.1192440801.git.michael@ellerman.id.au>

Now that all users of dcr_read()/dcr_write() add the dcr_host_t.base, we
can save them the trouble and do it in dcr_read()/dcr_write().

As some background to why we just went through all this jiggery-pokery,
benh sayeth:

 Initially the goal of the dcr_read/dcr_write routines was to operate like
 mfdcr/mtdcr which take absolute DCR numbers. The reason is that on 4xx
 hardware, indirect DCR access is a pain (goes through a table of
 instructions) and it's useful to have the compiler resolve an absolute DCR
 inline.

 We decided that wasn't worth the API bastardisation since most places
 where absolute DCR values are used are low level 4xx-only code which may
 as well continue using mfdcr/mtdcr, while the new API is designed for
 device "instances" that can exist on 4xx and Axon type platforms and may
 be located at variable DCR offsets.

Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
 arch/powerpc/platforms/cell/axon_msi.c |    4 ++--
 arch/powerpc/sysdev/mpic.c             |    4 ++--
 drivers/net/ibm_emac/ibm_emac_mal.h    |    4 ++--
 drivers/net/ibm_newemac/mal.h          |    4 ++--
 include/asm-powerpc/dcr-mmio.h         |    4 ++--
 include/asm-powerpc/dcr-native.h       |    4 ++--
 6 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c
index 1245b2f..aca1500 100644
--- a/arch/powerpc/platforms/cell/axon_msi.c
+++ b/arch/powerpc/platforms/cell/axon_msi.c
@@ -77,12 +77,12 @@ static void msic_dcr_write(struct axon_msic *msic, unsigned int dcr_n, u32 val)
 {
 	pr_debug("axon_msi: dcr_write(0x%x, 0x%x)\n", val, dcr_n);
 
-	dcr_write(msic->dcr_host, msic->dcr_host.base + dcr_n, val);
+	dcr_write(msic->dcr_host, dcr_n, val);
 }
 
 static u32 msic_dcr_read(struct axon_msic *msic, unsigned int dcr_n)
 {
-	return dcr_read(msic->dcr_host, msic->dcr_host.base + dcr_n);
+	return dcr_read(msic->dcr_host, dcr_n);
 }
 
 static void axon_msi_cascade(unsigned int irq, struct irq_desc *desc)
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index 893e654..e479388 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -156,7 +156,7 @@ static inline u32 _mpic_read(enum mpic_reg_type type,
 	switch(type) {
 #ifdef CONFIG_PPC_DCR
 	case mpic_access_dcr:
-		return dcr_read(rb->dhost, rb->dhost.base + reg);
+		return dcr_read(rb->dhost, reg);
 #endif
 	case mpic_access_mmio_be:
 		return in_be32(rb->base + (reg >> 2));
@@ -173,7 +173,7 @@ static inline void _mpic_write(enum mpic_reg_type type,
 	switch(type) {
 #ifdef CONFIG_PPC_DCR
 	case mpic_access_dcr:
-		return dcr_write(rb->dhost, rb->dhost.base + reg, value);
+		return dcr_write(rb->dhost, reg, value);
 #endif
 	case mpic_access_mmio_be:
 		return out_be32(rb->base + (reg >> 2), value);
diff --git a/drivers/net/ibm_emac/ibm_emac_mal.h b/drivers/net/ibm_emac/ibm_emac_mal.h
index aa76d3f..b8adbe6 100644
--- a/drivers/net/ibm_emac/ibm_emac_mal.h
+++ b/drivers/net/ibm_emac/ibm_emac_mal.h
@@ -208,12 +208,12 @@ struct ibm_ocp_mal {
 
 static inline u32 get_mal_dcrn(struct ibm_ocp_mal *mal, int reg)
 {
-	return dcr_read(mal->dcrhost, mal->dcrhost.base + reg);
+	return dcr_read(mal->dcrhost, reg);
 }
 
 static inline void set_mal_dcrn(struct ibm_ocp_mal *mal, int reg, u32 val)
 {
-	dcr_write(mal->dcrhost, mal->dcrhost.base + reg, val);
+	dcr_write(mal->dcrhost, reg, val);
 }
 
 /* Register MAL devices */
diff --git a/drivers/net/ibm_newemac/mal.h b/drivers/net/ibm_newemac/mal.h
index 6daa98e..784edb8 100644
--- a/drivers/net/ibm_newemac/mal.h
+++ b/drivers/net/ibm_newemac/mal.h
@@ -212,12 +212,12 @@ struct mal_instance {
 
 static inline u32 get_mal_dcrn(struct mal_instance *mal, int reg)
 {
-	return dcr_read(mal->dcr_host, mal->dcr_host.base + reg);
+	return dcr_read(mal->dcr_host, reg);
 }
 
 static inline void set_mal_dcrn(struct mal_instance *mal, int reg, u32 val)
 {
-	dcr_write(mal->dcr_host, mal->dcr_host.base + reg, val);
+	dcr_write(mal->dcr_host, reg, val);
 }
 
 /* Register MAL devices */
diff --git a/include/asm-powerpc/dcr-mmio.h b/include/asm-powerpc/dcr-mmio.h
index 6b82c3b..a7d9eaf 100644
--- a/include/asm-powerpc/dcr-mmio.h
+++ b/include/asm-powerpc/dcr-mmio.h
@@ -37,12 +37,12 @@ extern void dcr_unmap(dcr_host_t host, unsigned int dcr_n, unsigned int dcr_c);
 
 static inline u32 dcr_read(dcr_host_t host, unsigned int dcr_n)
 {
-	return in_be32(host.token + dcr_n * host.stride);
+	return in_be32(host.token + ((host.base + dcr_n) * host.stride));
 }
 
 static inline void dcr_write(dcr_host_t host, unsigned int dcr_n, u32 value)
 {
-	out_be32(host.token + dcr_n * host.stride, value);
+	out_be32(host.token + ((host.base + dcr_n) * host.stride), value);
 }
 
 extern u64 of_translate_dcr_address(struct device_node *dev,
diff --git a/include/asm-powerpc/dcr-native.h b/include/asm-powerpc/dcr-native.h
index f41058c..3bc780f 100644
--- a/include/asm-powerpc/dcr-native.h
+++ b/include/asm-powerpc/dcr-native.h
@@ -30,8 +30,8 @@ typedef struct {
 
 #define dcr_map(dev, dcr_n, dcr_c)	((dcr_host_t){ .base = (dcr_n) })
 #define dcr_unmap(host, dcr_n, dcr_c)	do {} while (0)
-#define dcr_read(host, dcr_n)		mfdcr(dcr_n)
-#define dcr_write(host, dcr_n, value)	mtdcr(dcr_n, value)
+#define dcr_read(host, dcr_n)		mfdcr(dcr_n + host.base)
+#define dcr_write(host, dcr_n, value)	mtdcr(dcr_n + host.base, value)
 
 /* Device Control Registers */
 void __mtdcr(int reg, unsigned int val);
-- 
1.5.1.3.g7a33b

^ permalink raw reply related

* [PATCH 2/5] Use dcr_host_t.base in ibm_emac_mal
From: Michael Ellerman @ 2007-10-15  9:34 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev, jgarzik
In-Reply-To: <33ee227bae85a8d7ccde69a717cff47000888354.1192440801.git.michael@ellerman.id.au>

This requires us to do a sort-of fake dcr_map(), so that base is set
properly. This will be fixed/removed when the device-tree-aware emac driver
is merged.

Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
 drivers/net/ibm_emac/ibm_emac_mal.c |    5 ++++-
 drivers/net/ibm_emac/ibm_emac_mal.h |    5 ++---
 2 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/net/ibm_emac/ibm_emac_mal.c b/drivers/net/ibm_emac/ibm_emac_mal.c
index 4e49e8c..dcd8826 100644
--- a/drivers/net/ibm_emac/ibm_emac_mal.c
+++ b/drivers/net/ibm_emac/ibm_emac_mal.c
@@ -413,7 +413,10 @@ static int __init mal_probe(struct ocp_device *ocpdev)
 		       ocpdev->def->index);
 		return -ENOMEM;
 	}
-	mal->dcrbase = maldata->dcr_base;
+
+	/* XXX This only works for native dcr for now */
+	mal->dcrhost = dcr_map(NULL, maldata->dcr_base, 0);
+
 	mal->def = ocpdev->def;
 
 	INIT_LIST_HEAD(&mal->poll_list);
diff --git a/drivers/net/ibm_emac/ibm_emac_mal.h b/drivers/net/ibm_emac/ibm_emac_mal.h
index 8f54d62..aa76d3f 100644
--- a/drivers/net/ibm_emac/ibm_emac_mal.h
+++ b/drivers/net/ibm_emac/ibm_emac_mal.h
@@ -191,7 +191,6 @@ struct mal_commac {
 };
 
 struct ibm_ocp_mal {
-	int			dcrbase;
 	dcr_host_t		dcrhost;
 
 	struct list_head	poll_list;
@@ -209,12 +208,12 @@ struct ibm_ocp_mal {
 
 static inline u32 get_mal_dcrn(struct ibm_ocp_mal *mal, int reg)
 {
-	return dcr_read(mal->dcrhost, mal->dcrbase + reg);
+	return dcr_read(mal->dcrhost, mal->dcrhost.base + reg);
 }
 
 static inline void set_mal_dcrn(struct ibm_ocp_mal *mal, int reg, u32 val)
 {
-	dcr_write(mal->dcrhost, mal->dcrbase + reg, val);
+	dcr_write(mal->dcrhost, mal->dcrhost.base + reg, val);
 }
 
 /* Register MAL devices */
-- 
1.5.1.3.g7a33b

^ permalink raw reply related

* [PATCH 1/5] Update ibm_newemac to use dcr_host_t.base
From: Michael Ellerman @ 2007-10-15  9:34 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev, jgarzik

Now that dcr_host_t contains the base address, we can use that in the
ibm_newemac code, rather than storing it separately.

Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
 drivers/net/ibm_newemac/mal.c |    9 +++++----
 drivers/net/ibm_newemac/mal.h |    5 ++---
 2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/net/ibm_newemac/mal.c b/drivers/net/ibm_newemac/mal.c
index 5885411..748a869 100644
--- a/drivers/net/ibm_newemac/mal.c
+++ b/drivers/net/ibm_newemac/mal.c
@@ -461,6 +461,7 @@ static int __devinit mal_probe(struct of_device *ofdev,
 	struct mal_instance *mal;
 	int err = 0, i, bd_size;
 	int index = mal_count++;
+	unsigned int dcr_base;
 	const u32 *prop;
 	u32 cfg;
 
@@ -497,14 +498,14 @@ static int __devinit mal_probe(struct of_device *ofdev,
 	}
 	mal->num_rx_chans = prop[0];
 
-	mal->dcr_base = dcr_resource_start(ofdev->node, 0);
-	if (mal->dcr_base == 0) {
+	dcr_base = dcr_resource_start(ofdev->node, 0);
+	if (dcr_base == 0) {
 		printk(KERN_ERR
 		       "mal%d: can't find DCR resource!\n", index);
 		err = -ENODEV;
 		goto fail;
 	}
-        mal->dcr_host = dcr_map(ofdev->node, mal->dcr_base, 0x100);
+	mal->dcr_host = dcr_map(ofdev->node, dcr_base, 0x100);
 	if (!DCR_MAP_OK(mal->dcr_host)) {
 		printk(KERN_ERR
 		       "mal%d: failed to map DCRs !\n", index);
@@ -626,7 +627,7 @@ static int __devinit mal_probe(struct of_device *ofdev,
  fail2:
 	dma_free_coherent(&ofdev->dev, bd_size, mal->bd_virt, mal->bd_dma);
  fail_unmap:
-	dcr_unmap(mal->dcr_host, mal->dcr_base, 0x100);
+	dcr_unmap(mal->dcr_host, dcr_base, 0x100);
  fail:
 	kfree(mal);
 
diff --git a/drivers/net/ibm_newemac/mal.h b/drivers/net/ibm_newemac/mal.h
index cb1a16d..6daa98e 100644
--- a/drivers/net/ibm_newemac/mal.h
+++ b/drivers/net/ibm_newemac/mal.h
@@ -185,7 +185,6 @@ struct mal_commac {
 
 struct mal_instance {
 	int			version;
-	int			dcr_base;
 	dcr_host_t		dcr_host;
 
 	int			num_tx_chans;	/* Number of TX channels */
@@ -213,12 +212,12 @@ struct mal_instance {
 
 static inline u32 get_mal_dcrn(struct mal_instance *mal, int reg)
 {
-	return dcr_read(mal->dcr_host, mal->dcr_base + reg);
+	return dcr_read(mal->dcr_host, mal->dcr_host.base + reg);
 }
 
 static inline void set_mal_dcrn(struct mal_instance *mal, int reg, u32 val)
 {
-	dcr_write(mal->dcr_host, mal->dcr_base + reg, val);
+	dcr_write(mal->dcr_host, mal->dcr_host.base + reg, val);
 }
 
 /* Register MAL devices */
-- 
1.5.1.3.g7a33b

^ permalink raw reply related

* Re: [RFC/PATCH 2/2] powerpc: irqtrace support to 64-bit powerpc
From: Benjamin Herrenschmidt @ 2007-10-15  9:25 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linuxppc-dev
In-Reply-To: <1192437681.3349.12.camel@johannes.berg>


> 
> > --- linux-work.orig/include/asm-powerpc/irqflags.h	2007-10-15 17:10:12.000000000 +1000
> > +++ linux-work/include/asm-powerpc/irqflags.h	2007-10-15 17:11:09.000000000 +1000
>  
> >  /*
> > - * Do the CPU's IRQ-state tracing from assembly code. We call a
> > - * C function, so save all the C-clobbered registers:
> > + * Most of the CPU's IRQ-state tracing is done from assembly code; we
> > + * have to call a C function so call a wrapper that saves all the
> > + * C-clobbered registers.
> >   */
> 
> That comment is now wrong, it should probably be removed.

Ah yes, it's stale, I'll get rid of it. Thanks.

Ben.

^ permalink raw reply

* Re: [RFC/PATCH 2/2] powerpc: irqtrace support to 64-bit powerpc
From: Johannes Berg @ 2007-10-15  8:41 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev
In-Reply-To: <20071015072826.2D541DDE16@ozlabs.org>

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

On Mon, 2007-10-15 at 17:28 +1000, Benjamin Herrenschmidt wrote:
> This adds the low level irq tracing hooks to the powerpc architecture
> needed to enable full lockdep functionality
> 
> Some rework from Johannes initial version, removing the asm trampoline that
> isn't needed (thus improving perfs) and fixing a couple of bugs such as
> incorrect initial preempt_count on the softirq alternate stack.

Cool. I always wanted to look into seeing if I could remove that but
never got around to it. Thanks!


> --- linux-work.orig/include/asm-powerpc/irqflags.h	2007-10-15 17:10:12.000000000 +1000
> +++ linux-work/include/asm-powerpc/irqflags.h	2007-10-15 17:11:09.000000000 +1000
 
>  /*
> - * Do the CPU's IRQ-state tracing from assembly code. We call a
> - * C function, so save all the C-clobbered registers:
> + * Most of the CPU's IRQ-state tracing is done from assembly code; we
> + * have to call a C function so call a wrapper that saves all the
> + * C-clobbered registers.
>   */

That comment is now wrong, it should probably be removed.

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 828 bytes --]

^ permalink raw reply

* Re: [PATCH] Rework hrtimer_nanosleep to make sys_compat_nanosleep easier
From: Arnd Bergmann @ 2007-10-15  7:28 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Thomas Gleixner, mingo, Anton Blanchard, linux-kernel
In-Reply-To: <20071015063833.GA15396@kryten>

On Monday 15 October 2007, Anton Blanchard wrote:
> Pull the copy_to_user out of hrtimer_nanosleep and into the callers
> (common_nsleep, sys_nanosleep) in preparation for converting
> compat_sys_nanosleep to use hrtimers.

Looks good, except for two micro-optimization:

> Signed-off-by: Anton Blanchard <anton@samba.org>

Acked-by: Arnd Bergmann <arnd@arndb.de>

> @@ -1361,7 +1356,14 @@ sys_nanosleep(struct timespec __user *rqtp, struct=
 timespec __user *rmtp)
> =A0=A0=A0=A0=A0=A0=A0=A0if (!timespec_valid(&tu))
> =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0return -EINVAL;
> =A0
> -=A0=A0=A0=A0=A0=A0=A0return hrtimer_nanosleep(&tu, rmtp, HRTIMER_MODE_RE=
L, CLOCK_MONOTONIC);
> +=A0=A0=A0=A0=A0=A0=A0ret =3D hrtimer_nanosleep(&tu, &rmt, HRTIMER_MODE_R=
EL, CLOCK_MONOTONIC);
> +
> +=A0=A0=A0=A0=A0=A0=A0if (ret && rmtp) {
> +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0if (copy_to_user(rmtp, &rmt=
, sizeof(*rmtp)))
> +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0ret=
urn -EFAULT;
> +=A0=A0=A0=A0=A0=A0=A0}
> +
> +=A0=A0=A0=A0=A0=A0=A0return ret;
> =A0}
> =A0

If it's common to call sys_nanosleep with a NULL rmtp argument, we could sa=
ve a
few cycles using=20

	return hrtimer_nanosleep(&tu, rmtp ? &rmp : NULL, HRTIMER_MODE_REL,
								 CLOCK_MONOTONIC);

> diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c
> index 57efe04..cce8c75 100644
> --- a/kernel/posix-timers.c
> +++ b/kernel/posix-timers.c
> @@ -980,9 +980,19 @@ sys_clock_getres(const clockid_t which_clock, struct=
 timespec __user *tp)
> =A0static int common_nsleep(const clockid_t which_clock, int flags,
> =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 =
struct timespec *tsave, struct timespec __user *rmtp)
> =A0{
> -=A0=A0=A0=A0=A0=A0=A0return hrtimer_nanosleep(tsave, rmtp, flags & TIMER=
_ABSTIME ?
> +=A0=A0=A0=A0=A0=A0=A0struct timespec rmt;
> +=A0=A0=A0=A0=A0=A0=A0int ret;
> +
> +=A0=A0=A0=A0=A0=A0=A0ret =3D hrtimer_nanosleep(tsave, &rmt, flags & TIME=
R_ABSTIME ?
> =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=
=A0=A0=A0=A0=A0=A0=A0=A0 HRTIMER_MODE_ABS : HRTIMER_MODE_REL,
> =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=
=A0=A0=A0=A0=A0=A0=A0=A0 which_clock);
> +
> +=A0=A0=A0=A0=A0=A0=A0if (ret && rmtp) {
> +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0if (copy_to_user(rmtp, &rmt=
, sizeof(*rmtp)))
> +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0ret=
urn -EFAULT;
> +=A0=A0=A0=A0=A0=A0=A0}
> +
> +=A0=A0=A0=A0=A0=A0=A0return ret;
> =A0}

I think it would be better here to propagate the move to a kernel *rmtp
down to sys_clock_nanosleep so we get the same optimization in
compat_sys_clock_nanosleep. That should probably also be a separate
patch. I can do one if you don't do it first.

	Arnd <><

^ permalink raw reply

* [RFC/PATCH 2/2] powerpc: irqtrace support to 64-bit powerpc
From: Benjamin Herrenschmidt @ 2007-10-15  7:28 UTC (permalink / raw)
  To: linuxppc-dev
In-Reply-To: <1192433296.924212.737979117370.qpush@grosgo>

This adds the low level irq tracing hooks to the powerpc architecture
needed to enable full lockdep functionality

Some rework from Johannes initial version, removing the asm trampoline that
isn't needed (thus improving perfs) and fixing a couple of bugs such as
incorrect initial preempt_count on the softirq alternate stack.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

---

 arch/powerpc/Kconfig            |    9 +++++
 arch/powerpc/kernel/entry_64.S  |   27 +++++++++++++++
 arch/powerpc/kernel/head_64.S   |   68 +++++++++++++++++++++++++++++-----------
 arch/powerpc/kernel/irq.c       |   17 ++++++++--
 arch/powerpc/kernel/ppc_ksyms.c |    4 --
 arch/powerpc/kernel/setup_64.c  |    6 +++
 include/asm-powerpc/exception.h |    7 ++--
 include/asm-powerpc/hw_irq.h    |   13 ++++---
 include/asm-powerpc/irqflags.h  |   23 ++++++-------
 include/asm-powerpc/rwsem.h     |   34 +++++++++++++++-----
 include/asm-powerpc/spinlock.h  |    1 
 11 files changed, 155 insertions(+), 54 deletions(-)

Index: linux-work/arch/powerpc/Kconfig
===================================================================
--- linux-work.orig/arch/powerpc/Kconfig	2007-10-15 17:10:11.000000000 +1000
+++ linux-work/arch/powerpc/Kconfig	2007-10-15 17:11:09.000000000 +1000
@@ -50,6 +50,15 @@ config STACKTRACE_SUPPORT
 	bool
 	default y
 
+config TRACE_IRQFLAGS_SUPPORT
+	bool
+	depends on PPC64
+	default y
+
+config LOCKDEP_SUPPORT
+	bool
+	default y
+
 config RWSEM_GENERIC_SPINLOCK
 	bool
 
Index: linux-work/arch/powerpc/kernel/irq.c
===================================================================
--- linux-work.orig/arch/powerpc/kernel/irq.c	2007-10-15 17:10:11.000000000 +1000
+++ linux-work/arch/powerpc/kernel/irq.c	2007-10-15 17:11:09.000000000 +1000
@@ -114,7 +114,7 @@ static inline void set_soft_enabled(unsi
 	: : "r" (enable), "i" (offsetof(struct paca_struct, soft_enabled)));
 }
 
-void local_irq_restore(unsigned long en)
+void raw_local_irq_restore(unsigned long en)
 {
 	/*
 	 * get_paca()->soft_enabled = en;
@@ -175,6 +175,7 @@ void local_irq_restore(unsigned long en)
 
 	__hard_irq_enable();
 }
+EXPORT_SYMBOL(raw_local_irq_restore);
 #endif /* CONFIG_PPC64 */
 
 int show_interrupts(struct seq_file *p, void *v)
@@ -311,8 +312,20 @@ void do_IRQ(struct pt_regs *regs)
 				handler = &__do_IRQ;
 			irqtp->task = curtp->task;
 			irqtp->flags = 0;
+
+			/* Copy the softirq bits in preempt_count so that the
+			 * softirq checks work in the hardirq context.
+			 */
+			irqtp->preempt_count =
+				(irqtp->preempt_count & ~SOFTIRQ_MASK) |
+				(curtp->preempt_count & SOFTIRQ_MASK);
+
 			call_handle_irq(irq, desc, irqtp, handler);
 			irqtp->task = NULL;
+
+			/* Set any flag that may have been set on the
+			 * alternate stack
+			 */
 			if (irqtp->flags)
 				set_bits(irqtp->flags, &curtp->flags);
 		} else
@@ -358,7 +371,7 @@ void irq_ctx_init(void)
 		memset((void *)softirq_ctx[i], 0, THREAD_SIZE);
 		tp = softirq_ctx[i];
 		tp->cpu = i;
-		tp->preempt_count = SOFTIRQ_OFFSET;
+		tp->preempt_count = 0;
 
 		memset((void *)hardirq_ctx[i], 0, THREAD_SIZE);
 		tp = hardirq_ctx[i];
Index: linux-work/arch/powerpc/kernel/ppc_ksyms.c
===================================================================
--- linux-work.orig/arch/powerpc/kernel/ppc_ksyms.c	2007-10-15 17:10:11.000000000 +1000
+++ linux-work/arch/powerpc/kernel/ppc_ksyms.c	2007-10-15 17:11:09.000000000 +1000
@@ -49,10 +49,6 @@
 #include <asm/commproc.h>
 #endif
 
-#ifdef CONFIG_PPC64
-EXPORT_SYMBOL(local_irq_restore);
-#endif
-
 #ifdef CONFIG_PPC32
 extern void transfer_to_handler(void);
 extern void do_IRQ(struct pt_regs *regs);
Index: linux-work/include/asm-powerpc/hw_irq.h
===================================================================
--- linux-work.orig/include/asm-powerpc/hw_irq.h	2007-10-15 17:10:12.000000000 +1000
+++ linux-work/include/asm-powerpc/hw_irq.h	2007-10-15 17:11:09.000000000 +1000
@@ -27,7 +27,7 @@ static inline unsigned long local_get_fl
 	return flags;
 }
 
-static inline unsigned long local_irq_disable(void)
+static inline unsigned long raw_local_irq_disable(void)
 {
 	unsigned long flags, zero;
 
@@ -39,14 +39,15 @@ static inline unsigned long local_irq_di
 	return flags;
 }
 
-extern void local_irq_restore(unsigned long);
+extern void raw_local_irq_restore(unsigned long);
 extern void iseries_handle_interrupts(void);
 
-#define local_irq_enable()	local_irq_restore(1)
-#define local_save_flags(flags)	((flags) = local_get_flags())
-#define local_irq_save(flags)	((flags) = local_irq_disable())
+#define raw_local_irq_enable()		raw_local_irq_restore(1)
+#define raw_local_save_flags(flags)	((flags) = local_get_flags())
+#define raw_local_irq_save(flags)	((flags) = raw_local_irq_disable())
 
-#define irqs_disabled()		(local_get_flags() == 0)
+#define raw_irqs_disabled()		(local_get_flags() == 0)
+#define raw_irqs_disabled_flags(flags)	((flags) == 0)
 
 #define __hard_irq_enable()	__mtmsrd(mfmsr() | MSR_EE, 1)
 #define __hard_irq_disable()	__mtmsrd(mfmsr() & ~MSR_EE, 1)
Index: linux-work/include/asm-powerpc/irqflags.h
===================================================================
--- linux-work.orig/include/asm-powerpc/irqflags.h	2007-10-15 17:10:12.000000000 +1000
+++ linux-work/include/asm-powerpc/irqflags.h	2007-10-15 17:11:09.000000000 +1000
@@ -2,30 +2,29 @@
  * include/asm-powerpc/irqflags.h
  *
  * IRQ flags handling
- *
- * This file gets included from lowlevel asm headers too, to provide
- * wrapped versions of the local_irq_*() APIs, based on the
- * raw_local_irq_*() macros from the lowlevel headers.
  */
 #ifndef _ASM_IRQFLAGS_H
 #define _ASM_IRQFLAGS_H
 
+#ifndef __ASSEMBLY__
 /*
  * Get definitions for raw_local_save_flags(x), etc.
  */
 #include <asm-powerpc/hw_irq.h>
 
+#else
+#ifdef CONFIG_TRACE_IRQFLAGS
 /*
- * Do the CPU's IRQ-state tracing from assembly code. We call a
- * C function, so save all the C-clobbered registers:
+ * Most of the CPU's IRQ-state tracing is done from assembly code; we
+ * have to call a C function so call a wrapper that saves all the
+ * C-clobbered registers.
  */
-#ifdef CONFIG_TRACE_IRQFLAGS
-
-#error No support on PowerPC yet for CONFIG_TRACE_IRQFLAGS
-
+#define TRACE_ENABLE_INTS	bl .trace_hardirqs_on
+#define TRACE_DISABLE_INTS	bl .trace_hardirqs_off
 #else
-# define TRACE_IRQS_ON
-# define TRACE_IRQS_OFF
+#define TRACE_ENABLE_INTS
+#define TRACE_DISABLE_INTS
+#endif
 #endif
 
 #endif
Index: linux-work/include/asm-powerpc/rwsem.h
===================================================================
--- linux-work.orig/include/asm-powerpc/rwsem.h	2007-10-15 17:10:12.000000000 +1000
+++ linux-work/include/asm-powerpc/rwsem.h	2007-10-15 17:11:09.000000000 +1000
@@ -32,11 +32,21 @@ struct rw_semaphore {
 #define RWSEM_ACTIVE_WRITE_BIAS		(RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
 	spinlock_t		wait_lock;
 	struct list_head	wait_list;
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+	struct lockdep_map	dep_map;
+#endif
 };
 
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+# define __RWSEM_DEP_MAP_INIT(lockname) , .dep_map = { .name = #lockname }
+#else
+# define __RWSEM_DEP_MAP_INIT(lockname)
+#endif
+
 #define __RWSEM_INITIALIZER(name) \
 	{ RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, \
-	  LIST_HEAD_INIT((name).wait_list) }
+	  LIST_HEAD_INIT((name).wait_list) \
+	  __RWSEM_DEP_MAP_INIT(name) }
 
 #define DECLARE_RWSEM(name)		\
 	struct rw_semaphore name = __RWSEM_INITIALIZER(name)
@@ -46,12 +56,15 @@ extern struct rw_semaphore *rwsem_down_w
 extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem);
 extern struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem);
 
-static inline void init_rwsem(struct rw_semaphore *sem)
-{
-	sem->count = RWSEM_UNLOCKED_VALUE;
-	spin_lock_init(&sem->wait_lock);
-	INIT_LIST_HEAD(&sem->wait_list);
-}
+extern void __init_rwsem(struct rw_semaphore *sem, const char *name,
+			 struct lock_class_key *key);
+
+#define init_rwsem(sem)					\
+	do {						\
+		static struct lock_class_key __key;	\
+							\
+		__init_rwsem((sem), #sem, &__key);	\
+	} while (0)
 
 /*
  * lock for reading
@@ -78,7 +91,7 @@ static inline int __down_read_trylock(st
 /*
  * lock for writing
  */
-static inline void __down_write(struct rw_semaphore *sem)
+static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
 {
 	int tmp;
 
@@ -88,6 +101,11 @@ static inline void __down_write(struct r
 		rwsem_down_write_failed(sem);
 }
 
+static inline void __down_write(struct rw_semaphore *sem)
+{
+	__down_write_nested(sem, 0);
+}
+
 static inline int __down_write_trylock(struct rw_semaphore *sem)
 {
 	int tmp;
Index: linux-work/include/asm-powerpc/spinlock.h
===================================================================
--- linux-work.orig/include/asm-powerpc/spinlock.h	2007-10-15 17:10:12.000000000 +1000
+++ linux-work/include/asm-powerpc/spinlock.h	2007-10-15 17:11:09.000000000 +1000
@@ -19,6 +19,7 @@
  *
  * (the type definitions are in asm/spinlock_types.h)
  */
+#include <linux/irqflags.h>
 #ifdef CONFIG_PPC64
 #include <asm/paca.h>
 #include <asm/hvcall.h>
Index: linux-work/include/asm-powerpc/exception.h
===================================================================
--- linux-work.orig/include/asm-powerpc/exception.h	2007-10-15 17:10:12.000000000 +1000
+++ linux-work/include/asm-powerpc/exception.h	2007-10-15 17:11:09.000000000 +1000
@@ -232,14 +232,15 @@ BEGIN_FW_FTR_SECTION;				\
 	mfmsr	r10;				\
 	ori	r10,r10,MSR_EE;			\
 	mtmsrd	r10,1;				\
-END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
+END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES);	\
+	TRACE_DISABLE_INTS
 
 #else
 #define DISABLE_INTS				\
 	li	r11,0;				\
 	stb	r11,PACASOFTIRQEN(r13);		\
-	stb	r11,PACAHARDIRQEN(r13)
-
+	stb	r11,PACAHARDIRQEN(r13);		\
+	TRACE_DISABLE_INTS
 #endif /* CONFIG_PPC_ISERIES */
 
 #define ENABLE_INTS				\
Index: linux-work/arch/powerpc/kernel/head_64.S
===================================================================
--- linux-work.orig/arch/powerpc/kernel/head_64.S	2007-10-15 17:10:11.000000000 +1000
+++ linux-work/arch/powerpc/kernel/head_64.S	2007-10-15 17:11:09.000000000 +1000
@@ -36,8 +36,7 @@
 #include <asm/firmware.h>
 #include <asm/page_64.h>
 #include <asm/exception.h>
-
-#define DO_SOFT_DISABLE
+#include <asm/irqflags.h>
 
 /*
  * We layout physical memory as follows:
@@ -450,24 +449,35 @@ bad_stack:
  */
 fast_exc_return_irq:			/* restores irq state too */
 	ld	r3,SOFTE(r1)
-	ld	r12,_MSR(r1)
+#ifdef CONFIG_TRACE_IRQFLAGS
+	cmpdi	r3,0
+	bne	1f
 	stb	r3,PACASOFTIRQEN(r13)	/* restore paca->soft_enabled */
+	bl	.trace_hardirqs_off
+	b	2f
+1:
+	bl	.trace_hardirqs_on
+	li	r3,1
+#endif /* CONFIG_TRACE_IRQFLAGS */
+	stb	r3,PACASOFTIRQEN(r13)	/* restore paca->soft_enabled */
+2:
+	ld	r12,_MSR(r1)
 	rldicl	r4,r12,49,63		/* get MSR_EE to LSB */
 	stb	r4,PACAHARDIRQEN(r13)	/* restore paca->hard_enabled */
-	b	1f
+	b	3f
 
 	.globl	fast_exception_return
 fast_exception_return:
 	ld	r12,_MSR(r1)
-1:	ld	r11,_NIP(r1)
+3:	ld	r11,_NIP(r1)
 	andi.	r3,r12,MSR_RI		/* check if RI is set */
 	beq-	unrecov_fer
 
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
 	andi.	r3,r12,MSR_PR
-	beq	2f
+	beq	4f
 	ACCOUNT_CPU_USER_EXIT(r3, r4)
-2:
+4:
 #endif
 
 	ld	r3,_CCR(r1)
@@ -820,6 +830,25 @@ BEGIN_FTR_SECTION
 END_FTR_SECTION_IFCLR(CPU_FTR_SLB)
 
 	/*
+	 * On iSeries, we soft-disable interrupts here, then
+	 * hard-enable interrupts so that the hash_page code can spin on
+	 * the hash_table_lock without problems on a shared processor.
+	 */
+	DISABLE_INTS
+
+	/*
+	 * Currently, trace_hardirqs_off() will be called by DISABLE_INTS
+	 * and will clobber volatile registers when irq tracing is enabled
+	 * so we need to reload them. It may be possible to be smarter here
+	 * and move the irq tracing elsewhere but let's keep it simple for
+	 * now
+	 */
+#ifdef CONFIG_TRACE_IRQFLAGS
+	ld	r3,_DAR(r1)
+	ld	r4,_DSISR(r1)
+	ld	r5,_TRAP(r1)
+#endif /* CONFIG_TRACE_IRQFLAGS */
+	/*
 	 * We need to set the _PAGE_USER bit if MSR_PR is set or if we are
 	 * accessing a userspace segment (even from the kernel). We assume
 	 * kernel addresses always have the high bit set.
@@ -832,13 +861,6 @@ END_FTR_SECTION_IFCLR(CPU_FTR_SLB)
 	rlwimi	r4,r5,22+2,31-2,31-2	/* Set _PAGE_EXEC if trap is 0x400 */
 
 	/*
-	 * On iSeries, we soft-disable interrupts here, then
-	 * hard-enable interrupts so that the hash_page code can spin on
-	 * the hash_table_lock without problems on a shared processor.
-	 */
-	DISABLE_INTS
-
-	/*
 	 * r3 contains the faulting address
 	 * r4 contains the required access permissions
 	 * r5 contains the trap number
@@ -848,7 +870,6 @@ END_FTR_SECTION_IFCLR(CPU_FTR_SLB)
 	bl	.hash_page		/* build HPTE if possible */
 	cmpdi	r3,0			/* see if hash_page succeeded */
 
-#ifdef DO_SOFT_DISABLE
 BEGIN_FW_FTR_SECTION
 	/*
 	 * If we had interrupts soft-enabled at the point where the
@@ -860,7 +881,7 @@ BEGIN_FW_FTR_SECTION
 	 */
 	beq	13f
 END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
-#endif
+
 BEGIN_FW_FTR_SECTION
 	/*
 	 * Here we have interrupts hard-disabled, so it is sufficient
@@ -874,11 +895,22 @@ END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISER
 
 	/*
 	 * hash_page couldn't handle it, set soft interrupt enable back
-	 * to what it was before the trap.  Note that .local_irq_restore
+	 * to what it was before the trap.  Note that .raw_local_irq_restore
 	 * handles any interrupts pending at this point.
 	 */
 	ld	r3,SOFTE(r1)
-	bl	.local_irq_restore
+#ifdef CONFIG_TRACE_IRQFLAGS
+	cmpdi	r3,0
+	bne	14f
+	bl	.raw_local_irq_restore
+	bl	.trace_hardirqs_off
+	b	15f
+14:
+	bl	.trace_hardirqs_on
+	li	r3,1
+#endif /* CONFIG_TRACE_IRQFLAGS */
+	bl	.raw_local_irq_restore
+15:
 	b	11f
 
 /* Here we have a page fault that hash_page can't handle. */
Index: linux-work/arch/powerpc/kernel/setup_64.c
===================================================================
--- linux-work.orig/arch/powerpc/kernel/setup_64.c	2007-10-15 17:10:11.000000000 +1000
+++ linux-work/arch/powerpc/kernel/setup_64.c	2007-10-15 17:11:09.000000000 +1000
@@ -33,6 +33,7 @@
 #include <linux/serial_8250.h>
 #include <linux/bootmem.h>
 #include <linux/pci.h>
+#include <linux/lockdep.h>
 #include <asm/io.h>
 #include <asm/kdump.h>
 #include <asm/prom.h>
@@ -359,6 +360,11 @@ void __init setup_system(void)
 			  &__start___fw_ftr_fixup, &__stop___fw_ftr_fixup);
 
 	/*
+	 * start lockdep
+	 */
+	lockdep_init();
+
+	/*
 	 * Unflatten the device-tree passed by prom_init or kexec
 	 */
 	unflatten_device_tree();
Index: linux-work/arch/powerpc/kernel/entry_64.S
===================================================================
--- linux-work.orig/arch/powerpc/kernel/entry_64.S	2007-10-15 17:10:11.000000000 +1000
+++ linux-work/arch/powerpc/kernel/entry_64.S	2007-10-15 17:13:28.000000000 +1000
@@ -29,6 +29,7 @@
 #include <asm/cputable.h>
 #include <asm/firmware.h>
 #include <asm/bug.h>
+#include <asm/irqflags.h>
 
 /*
  * System calls.
@@ -88,6 +89,13 @@ system_call_common:
 	addi	r9,r1,STACK_FRAME_OVERHEAD
 	ld	r11,exception_marker@toc(r2)
 	std	r11,-16(r9)		/* "regshere" marker */
+#ifdef CONFIG_TRACE_IRQFLAGS
+	bl	.trace_hardirqs_on
+	REST_GPR(0,r1)
+	REST_4GPRS(3,r1)
+	REST_2GPRS(7,r1)
+	addi	r9,r1,STACK_FRAME_OVERHEAD
+#endif /* CONFIG_TRACE_IRQFLAGS */
 	li	r10,1
 	stb	r10,PACASOFTIRQEN(r13)
 	stb	r10,PACAHARDIRQEN(r13)
@@ -500,14 +508,27 @@ BEGIN_FW_FTR_SECTION
 	stb	r3,PACASOFTIRQEN(r13)	/* ensure we are soft-disabled */
 	ori	r10,r10,MSR_EE
 	mtmsrd	r10			/* hard-enable again */
+#ifdef CONFIG_TRACE_IRQFLAGS
+	bl	.trace_hardirqs_off
+#endif
 	addi	r3,r1,STACK_FRAME_OVERHEAD
 	bl	.do_IRQ
 	b	.ret_from_except_lite		/* loop back and handle more */
 4:
 END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
 #endif
+#ifdef CONFIG_TRACE_IRQFLAGS
+	cmpdi	r5,0
+	bne	5f
 	stb	r5,PACASOFTIRQEN(r13)
-
+	bl	.trace_hardirqs_off
+	b	6f
+5:
+	bl	.trace_hardirqs_on
+	li	r5,1
+#endif
+	stb	r5,PACASOFTIRQEN(r13)
+6:
 	/* extract EE bit and use it to restore paca->hard_enabled */
 	ld	r3,_MSR(r1)
 	rldicl	r4,r3,49,63		/* r0 = (r3 >> 15) & 1 */
@@ -574,6 +595,10 @@ do_work:
 	bne	restore
 	/* here we are preempting the current task */
 1:
+#ifdef CONFIG_TRACE_IRQFLAGS
+	bl	.trace_hardirqs_on
+	mfmsr	r10		/* Get current interrupt state */
+#endif /* CONFIG_TRACE_IRQFLAGS */
 	li	r0,1
 	stb	r0,PACASOFTIRQEN(r13)
 	stb	r0,PACAHARDIRQEN(r13)

^ permalink raw reply

* [RFC/PATCH 1/2] powerpc: lockdep stacktrace support
From: Benjamin Herrenschmidt @ 2007-10-15  7:28 UTC (permalink / raw)
  To: linuxppc-dev
In-Reply-To: <1192433296.924212.737979117370.qpush@grosgo>

From: Christoph Hellwig <hch@lst.de>

I recently tried to work on lockdep for powerpc.  I have preliminary
version of the stacktrace code, but had to give up on trace irqflags
support because I'm not that knowledgeable on lowlevel ppc details.

Maybe someone more faimilar with the code wants to give it another try?

My stacktrace code is below:

Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

---
 arch/powerpc/Kconfig             |    4 +++
 arch/powerpc/kernel/Makefile     |    1 
 arch/powerpc/kernel/stacktrace.c |   52 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 57 insertions(+)

Index: linux-work/arch/powerpc/Kconfig
===================================================================
--- linux-work.orig/arch/powerpc/Kconfig	2007-10-15 11:19:35.000000000 +1000
+++ linux-work/arch/powerpc/Kconfig	2007-10-15 14:04:05.000000000 +1000
@@ -46,6 +46,10 @@ config IRQ_PER_CPU
 	bool
 	default y
 
+config STACKTRACE_SUPPORT
+	bool
+	default y
+
 config RWSEM_GENERIC_SPINLOCK
 	bool
 
Index: linux-work/arch/powerpc/kernel/Makefile
===================================================================
--- linux-work.orig/arch/powerpc/kernel/Makefile	2007-10-15 11:19:35.000000000 +1000
+++ linux-work/arch/powerpc/kernel/Makefile	2007-10-15 14:04:05.000000000 +1000
@@ -65,6 +65,7 @@ obj-$(CONFIG_BOOTX_TEXT)	+= btext.o
 obj-$(CONFIG_SMP)		+= smp.o
 obj-$(CONFIG_KPROBES)		+= kprobes.o
 obj-$(CONFIG_PPC_UDBG_16550)	+= legacy_serial.o udbg_16550.o
+obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
 
 pci64-$(CONFIG_PPC64)		+= pci_dn.o isa-bridge.o
 obj-$(CONFIG_PCI)		+= pci_$(CONFIG_WORD_SIZE).o $(pci64-y) \
Index: linux-work/arch/powerpc/kernel/stacktrace.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-work/arch/powerpc/kernel/stacktrace.c	2007-10-15 14:04:05.000000000 +1000
@@ -0,0 +1,52 @@
+
+#include <linux/sched.h>
+#include <linux/stacktrace.h>
+
+
+#ifdef CONFIG_PPC64
+#define MIN_STACK_FRAME 112     /* same as STACK_FRAME_OVERHEAD, in fact */
+#define FRAME_LR_SAVE   2
+#define INT_FRAME_SIZE  (sizeof(struct pt_regs) + STACK_FRAME_OVERHEAD + 288)
+#define REGS_MARKER     0x7265677368657265ul
+#define FRAME_MARKER    12
+#else
+#define MIN_STACK_FRAME 16
+#define FRAME_LR_SAVE   1
+#define INT_FRAME_SIZE  (sizeof(struct pt_regs) + STACK_FRAME_OVERHEAD)
+#define REGS_MARKER     0x72656773ul
+#define FRAME_MARKER    2
+#endif
+
+
+/*
+ * Save stack-backtrace addresses into a stack_trace buffer.
+ * If all_contexts is set, all contexts (hardirq, softirq and process)
+ * are saved. If not set then only the current context is saved.
+ */
+void save_stack_trace(struct stack_trace *trace)
+{
+	unsigned long sp;
+
+	asm("mr %0,1" : "=r" (sp));
+
+	for (;;) {
+		unsigned long *stack = (unsigned long *) sp;
+		unsigned long newsp, ip;
+
+		if (!validate_sp(sp, current, MIN_STACK_FRAME))
+			return;
+
+		newsp = stack[0];
+		ip = stack[FRAME_LR_SAVE];
+
+		if (!trace->skip)
+			trace->entries[trace->nr_entries++] = ip;
+		else
+			trace->skip--;
+
+		if (trace->nr_entries >= trace->max_entries)
+			return;
+
+		sp = newsp;
+	}
+}

^ permalink raw reply

* [RFC/PATCH 0/2] powerpc: 64 bits irqtrace / lockdep support
From: Benjamin Herrenschmidt @ 2007-10-15  7:28 UTC (permalink / raw)
  To: linuxppc-dev

This is 2 patches, one from Christoph Hellwig that adds the backtrace support,
and one from Johannes Berg modified by me that adds the irq tracing support.

This successfully boots a POWER5 pSeries machine. I'm going to run some more
tests in the upcoming few days, so this is not an official submission (and it's
too late for .24 merge window anyway) but it's looking good so far.

Then, I -might- give a go at a 32 bits version but no promises there :-)

^ permalink raw reply

* [PATCH] Hook compat_sys_nanosleep up to high res timer code
From: Anton Blanchard @ 2007-10-15  6:43 UTC (permalink / raw)
  To: Thomas Gleixner; +Cc: linuxppc-dev, mingo, linux-kernel, Arnd Bergmann
In-Reply-To: <20071015063833.GA15396@kryten>

 
Now we have high res timers on ppc64 I thought Id test them. It turns
out compat_sys_nanosleep hasnt been converted to the hrtimer code and so
is limited to HZ resolution.

The follow patch converts compat_sys_nanosleep to use high res timers.

Signed-off-by: Anton Blanchard <anton@samba.org>
---

diff --git a/kernel/compat.c b/kernel/compat.c
index 3bae374..729f63d 100644
--- a/kernel/compat.c
+++ b/kernel/compat.c
@@ -40,62 +40,26 @@ int put_compat_timespec(const struct timespec *ts, struct compat_timespec __user
 			__put_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0;
 }
 
-static long compat_nanosleep_restart(struct restart_block *restart)
-{
-	unsigned long expire = restart->arg0, now = jiffies;
-	struct compat_timespec __user *rmtp;
-
-	/* Did it expire while we handled signals? */
-	if (!time_after(expire, now))
-		return 0;
-
-	expire = schedule_timeout_interruptible(expire - now);
-	if (expire == 0)
-		return 0;
-
-	rmtp = (struct compat_timespec __user *)restart->arg1;
-	if (rmtp) {
-		struct compat_timespec ct;
-		struct timespec t;
-
-		jiffies_to_timespec(expire, &t);
-		ct.tv_sec = t.tv_sec;
-		ct.tv_nsec = t.tv_nsec;
-		if (copy_to_user(rmtp, &ct, sizeof(ct)))
-			return -EFAULT;
-	}
-	/* The 'restart' block is already filled in */
-	return -ERESTART_RESTARTBLOCK;
-}
-
 asmlinkage long compat_sys_nanosleep(struct compat_timespec __user *rqtp,
-		struct compat_timespec __user *rmtp)
+				     struct compat_timespec __user *rmtp)
 {
-	struct timespec t;
-	struct restart_block *restart;
-	unsigned long expire;
+	struct timespec tu, rmt;
+	long ret;
 
-	if (get_compat_timespec(&t, rqtp))
+	if (get_compat_timespec(&tu, rqtp))
 		return -EFAULT;
 
-	if ((t.tv_nsec >= 1000000000L) || (t.tv_nsec < 0) || (t.tv_sec < 0))
+	if (!timespec_valid(&tu))
 		return -EINVAL;
 
-	expire = timespec_to_jiffies(&t) + (t.tv_sec || t.tv_nsec);
-	expire = schedule_timeout_interruptible(expire);
-	if (expire == 0)
-		return 0;
+	ret = hrtimer_nanosleep(&tu, &rmt, HRTIMER_MODE_REL, CLOCK_MONOTONIC);
 
-	if (rmtp) {
-		jiffies_to_timespec(expire, &t);
-		if (put_compat_timespec(&t, rmtp))
+	if (ret && rmtp) {
+		if (put_compat_timespec(&rmt, rmtp))
 			return -EFAULT;
 	}
-	restart = &current_thread_info()->restart_block;
-	restart->fn = compat_nanosleep_restart;
-	restart->arg0 = jiffies + expire;
-	restart->arg1 = (unsigned long) rmtp;
-	return -ERESTART_RESTARTBLOCK;
+
+	return ret;
 }
 
 static inline long get_compat_itimerval(struct itimerval *o,

^ permalink raw reply related

* [PATCH] Rework hrtimer_nanosleep to make sys_compat_nanosleep easier
From: Anton Blanchard @ 2007-10-15  6:38 UTC (permalink / raw)
  To: Thomas Gleixner; +Cc: linuxppc-dev, mingo, linux-kernel, Arnd Bergmann
In-Reply-To: <alpine.LFD.0.9999.0710150804290.22612@localhost.localdomain>


Hi Thomas,

Thanks for the review, updates to follow.

Anton

--

Pull the copy_to_user out of hrtimer_nanosleep and into the callers
(common_nsleep, sys_nanosleep) in preparation for converting
compat_sys_nanosleep to use hrtimers.

Signed-off-by: Anton Blanchard <anton@samba.org>
---

diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h
index 540799b..7a9398e 100644
--- a/include/linux/hrtimer.h
+++ b/include/linux/hrtimer.h
@@ -300,7 +300,7 @@ hrtimer_forward(struct hrtimer *timer, ktime_t now, ktime_t interval);
 
 /* Precise sleep: */
 extern long hrtimer_nanosleep(struct timespec *rqtp,
-			      struct timespec __user *rmtp,
+			      struct timespec *rmtp,
 			      const enum hrtimer_mode mode,
 			      const clockid_t clockid);
 extern long hrtimer_nanosleep_restart(struct restart_block *restart_block);
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index dc8a445..129fead 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -1286,8 +1286,7 @@ static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mod
 long __sched hrtimer_nanosleep_restart(struct restart_block *restart)
 {
 	struct hrtimer_sleeper t;
-	struct timespec __user *rmtp;
-	struct timespec tu;
+	struct timespec *rmtp;
 	ktime_t time;
 
 	restart->fn = do_no_restart_syscall;
@@ -1298,14 +1297,12 @@ long __sched hrtimer_nanosleep_restart(struct restart_block *restart)
 	if (do_nanosleep(&t, HRTIMER_MODE_ABS))
 		return 0;
 
-	rmtp = (struct timespec __user *) restart->arg1;
+	rmtp = (struct timespec *)restart->arg1;
 	if (rmtp) {
 		time = ktime_sub(t.timer.expires, t.timer.base->get_time());
 		if (time.tv64 <= 0)
 			return 0;
-		tu = ktime_to_timespec(time);
-		if (copy_to_user(rmtp, &tu, sizeof(tu)))
-			return -EFAULT;
+		*rmtp = ktime_to_timespec(time);
 	}
 
 	restart->fn = hrtimer_nanosleep_restart;
@@ -1314,12 +1311,11 @@ long __sched hrtimer_nanosleep_restart(struct restart_block *restart)
 	return -ERESTART_RESTARTBLOCK;
 }
 
-long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp,
+long hrtimer_nanosleep(struct timespec *rqtp, struct timespec *rmtp,
 		       const enum hrtimer_mode mode, const clockid_t clockid)
 {
 	struct restart_block *restart;
 	struct hrtimer_sleeper t;
-	struct timespec tu;
 	ktime_t rem;
 
 	hrtimer_init(&t.timer, clockid, mode);
@@ -1335,9 +1331,7 @@ long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp,
 		rem = ktime_sub(t.timer.expires, t.timer.base->get_time());
 		if (rem.tv64 <= 0)
 			return 0;
-		tu = ktime_to_timespec(rem);
-		if (copy_to_user(rmtp, &tu, sizeof(tu)))
-			return -EFAULT;
+		*rmtp = ktime_to_timespec(rem);
 	}
 
 	restart = &current_thread_info()->restart_block;
@@ -1353,7 +1347,8 @@ long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp,
 asmlinkage long
 sys_nanosleep(struct timespec __user *rqtp, struct timespec __user *rmtp)
 {
-	struct timespec tu;
+	struct timespec tu, rmt;
+	int ret;
 
 	if (copy_from_user(&tu, rqtp, sizeof(tu)))
 		return -EFAULT;
@@ -1361,7 +1356,14 @@ sys_nanosleep(struct timespec __user *rqtp, struct timespec __user *rmtp)
 	if (!timespec_valid(&tu))
 		return -EINVAL;
 
-	return hrtimer_nanosleep(&tu, rmtp, HRTIMER_MODE_REL, CLOCK_MONOTONIC);
+	ret = hrtimer_nanosleep(&tu, &rmt, HRTIMER_MODE_REL, CLOCK_MONOTONIC);
+
+	if (ret && rmtp) {
+		if (copy_to_user(rmtp, &rmt, sizeof(*rmtp)))
+			return -EFAULT;
+	}
+
+	return ret;
 }
 
 /*
diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c
index 57efe04..cce8c75 100644
--- a/kernel/posix-timers.c
+++ b/kernel/posix-timers.c
@@ -980,9 +980,19 @@ sys_clock_getres(const clockid_t which_clock, struct timespec __user *tp)
 static int common_nsleep(const clockid_t which_clock, int flags,
 			 struct timespec *tsave, struct timespec __user *rmtp)
 {
-	return hrtimer_nanosleep(tsave, rmtp, flags & TIMER_ABSTIME ?
+	struct timespec rmt;
+	int ret;
+
+	ret = hrtimer_nanosleep(tsave, &rmt, flags & TIMER_ABSTIME ?
 				 HRTIMER_MODE_ABS : HRTIMER_MODE_REL,
 				 which_clock);
+
+	if (ret && rmtp) {
+		if (copy_to_user(rmtp, &rmt, sizeof(*rmtp)))
+			return -EFAULT;
+	}
+
+	return ret;
 }
 
 asmlinkage long

^ permalink raw reply related

* Re: [PATCH v2 4/7] bestcomm: core bestcomm support for Freescale MPC5200
From: Sven Luther @ 2007-10-15  6:12 UTC (permalink / raw)
  To: Grant Likely; +Cc: linuxppc-dev, paulus, domen.puncer
In-Reply-To: <fa686aa40710141423o69666b16pa7ce6851fa407d5e@mail.gmail.com>

On Sun, Oct 14, 2007 at 03:23:21PM -0600, Grant Likely wrote:
> On 10/14/07, Sven Luther <sven@powerlinux.fr> wrote:
> > On Sun, Oct 14, 2007 at 02:22:16PM -0600, Grant Likely wrote:
> > > On 10/14/07, Sven Luther <sven@powerlinux.fr> wrote:
> > > > On Sat, Oct 13, 2007 at 10:42:05PM -0600, Grant Likely wrote:
> > > > > From: Sylvain Munaut <tnt@246tNt.com>
> > > > >
> > > > > This patch adds support for the core of the BestComm API
> > > > > for the Freescale MPC5200(b). The BestComm engine is a
> > > > > microcode-controlled / tasks-based DMA used by several
> > > > > of the onchip devices.
> > > > >
> > > > > Setting up the tasks / memory allocation and all common
> > > > > low level functions are handled by this patch.
> > > > > The specifics details of each tasks and their microcode
> > > > > are split-out in separate patches.
> > > > >
> > > > > This is not the official API, but a much cleaner one.
> > > > > (hopefully)
> > > > >
> > > > > Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
> > > > > Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
> > > >
> > > > Hi Grant, ...
> > > >
> > > > I am unsure if this is a regression with regard to Sylvain's patch, or
> > > > somethign else, but it is no more possible to build bestcomm modular :
> > >
> > > Hmmm, interesting.  I'll try that out here this afternoon.
> >
> > Notice that domen said it was working, so it could have been a
> > mismanipulation on my part, or some problem with the debian patches.
> >
> > The older patchset with 2.6.23-rc6 worked fine though, and making the
> > main bestcomm module builtin solved the error messages. I did not spot
> > anything obvious when looking at the code.
> 
> Yes, it is a regression.  There had been a change to the Makefile.
> I've reverted it and it works fine now.  I'll repost v3 shortly.

Ok, thanks.

Friendly,

Sven Luther

^ permalink raw reply

* Re: [PATCH] Hook compat_sys_nanosleep up to high res timer code
From: Thomas Gleixner @ 2007-10-15  6:11 UTC (permalink / raw)
  To: Anton Blanchard; +Cc: linuxppc-dev, mingo, linux-kernel, Arnd Bergmann
In-Reply-To: <20071014231616.GA24519@kryten>

On Sun, 14 Oct 2007, Anton Blanchard wrote:
> Hi Arnd,
>  
> > The code looks correct, but I think it would be nicer to change 
> > hrtimer_nanosleep to take a kernel pointer and have all three
> > callers (common_nsleep, sys_nanosleep and compat_sys_nanosleep)
> > do the copy_to_user/put_compat_timespec in the caller.
> 
> Good idea, I had considered that but thought a larger cleanup might run
> afoul of the merge rules :)

Looks good, except ....
 
> --- a/kernel/compat.c
> +++ b/kernel/compat.c
> @@ -40,62 +40,26 @@ int put_compat_timespec(const struct timespec *ts, struct compat_timespec __user
>  			__put_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0;
>  }

Can you put this into a separate patch please ?
  
> --- a/kernel/hrtimer.c
> +++ b/kernel/hrtimer.c
>  	restart = &current_thread_info()->restart_block;
> @@ -1353,7 +1347,8 @@ long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp,
>  asmlinkage long
>  sys_nanosleep(struct timespec __user *rqtp, struct timespec __user *rmtp)
>  {
> -	struct timespec tu;
> +	struct timespec tu, rmt;
> +	int ret;
>  
>  	if (copy_from_user(&tu, rqtp, sizeof(tu)))
>  		return -EFAULT;
> @@ -1361,7 +1356,14 @@ sys_nanosleep(struct timespec __user *rqtp, struct timespec __user *rmtp)
>  	if (!timespec_valid(&tu))
>  		return -EINVAL;
>  
> -	return hrtimer_nanosleep(&tu, rmtp, HRTIMER_MODE_REL, CLOCK_MONOTONIC);
> +	ret = hrtimer_nanosleep(&tu, &rmt, HRTIMER_MODE_REL, CLOCK_MONOTONIC);
> +
> +	if (ret) {

Can you check for rmtp as well ? rmtp is optional and can be NULL

> +		if (copy_to_user(rmtp, &rmt, sizeof(*rmtp)))
> +			return -EFAULT;
> +	}
> +
> +	return ret;
>  }
>  
>  /*
> diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c
> index 7a15afb..fc7dac2 100644
> --- a/kernel/posix-timers.c
> +++ b/kernel/posix-timers.c
> @@ -980,9 +980,19 @@ sys_clock_getres(const clockid_t which_clock, struct timespec __user *tp)
>  static int common_nsleep(const clockid_t which_clock, int flags,
>  			 struct timespec *tsave, struct timespec __user *rmtp)
>  {
> -	return hrtimer_nanosleep(tsave, rmtp, flags & TIMER_ABSTIME ?
> +	struct timespec rmt;
> +	int ret;
> +
> +	ret = hrtimer_nanosleep(tsave, &rmt, flags & TIMER_ABSTIME ?
>  				 HRTIMER_MODE_ABS : HRTIMER_MODE_REL,
>  				 which_clock);
> +
> +	if (ret) {

Ditto.

> +		if (copy_to_user(rmtp, &rmt, sizeof(*rmtp)))
> +			return -EFAULT;
> +	}
> +
> +	return ret;
>  }

Thanks,

	tglx

^ permalink raw reply

* Re: [PATCH] powerpc: Add 1TB workaround for PA6T
From: Michael Neuling @ 2007-10-15  5:25 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: Olof Johansson, linuxppc-dev
In-Reply-To: <18194.62797.632192.458851@cargo.ozlabs.ibm.com>

In message <18194.62797.632192.458851@cargo.ozlabs.ibm.com> you wrote:
> Olof Johansson writes:
> 
> > @@ -367,7 +368,7 @@ extern void do_feature_fixups(unsigned long value, void
 *fixup_start,
> >  #define CPU_FTRS_PA6T (CPU_FTR_USE_TB | \
> >  	    CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | \
> >  	    CPU_FTR_ALTIVEC_COMP | CPU_FTR_CI_LARGE_PAGE | \
> > -	    CPU_FTR_PURR | CPU_FTR_REAL_LE)
> > +	    CPU_FTR_PURR | CPU_FTR_REAL_LE | CPU_FTR_NO_SLBIE_B)
> >  #define CPU_FTRS_COMPATIBLE	(CPU_FTR_USE_TB | \
> >  	    CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2)
> >  
> > @@ -375,7 +376,8 @@ extern void do_feature_fixups(unsigned long value, void
 *fixup_start,
> >  #define CPU_FTRS_POSSIBLE	\
> >  	    (CPU_FTRS_POWER3 | CPU_FTRS_RS64 | CPU_FTRS_POWER4 |	\
> >  	    CPU_FTRS_PPC970 | CPU_FTRS_POWER5 | CPU_FTRS_POWER6 |	\
> > -	    CPU_FTRS_CELL | CPU_FTRS_PA6T | CPU_FTR_1T_SEGMENT)
> > +	    CPU_FTRS_CELL | CPU_FTRS_PA6T | CPU_FTR_1T_SEGMENT |	\
> > +	    CPU_FTR_NO_SLBIE_B)
> >  #else
> >  enum {
> >  	CPU_FTRS_POSSIBLE =
> 
> I don't think the second hunk there is necessary, since
> CPU_FTRS_POSSIBLE will already get CPU_FTR_NO_SLBIE_B via
> CPU_FTRS_PA6T.

On that, should we put CPU_FTR_1T_SEGMENT in CPU_FTR_POWER6 and
CPU_FTR_PA6T?  Then we can remove it from CPU_FTRS_POSSIBLE also.  

Mikey

^ permalink raw reply

* Re: [PATCH 2/2] clk for mpc52xx: use psc_mclk's in spi driver
From: Domen Puncer @ 2007-10-15  5:16 UTC (permalink / raw)
  To: Grant Likely; +Cc: david-b, linuxppc-dev
In-Reply-To: <fa686aa40710141542w552eacet7ba13e8e251e2285@mail.gmail.com>

On 14/10/07 16:42 -0600, Grant Likely wrote:
> On 10/14/07, Domen Puncer <domen.puncer@telargo.com> wrote:
> > Use clocks subsystem in spi driver.
> 
> I don't understand the advantage of this approach.  Is the current code broken?

Actually the calculations are broken. But ok, fix doesn't need to be like this.

And it wasn't my idea to use clk.h :-)
http://patchwork.ozlabs.org/linuxppc-embedded/patch?id=11186

> 
> I agree that abstraction is good; but in this case it seems these two
> patches add a lot of code for a very simple calculation.  Also, there
> is exactly 2 chips that use these devices, the mpc5200 and the
> mpc5200b, and they are both wired up in exactly the same way.  I'm
> inclined to believe that splitting of reading of the CDM into a
> separate driver (or at least using the clk infrastructure) is over the
> edge of diminishing returns.  However, I could be convinced that
> having a utility function for setting the PSC clock rate is a useful
> thing, but until arch/ppc goes away, you should support it in both
> arch/ppc and arch/powerpc.
> 
> Cheers,
> g.
> 
> -- 
> Grant Likely, B.Sc., P.Eng.
> Secret Lab Technologies Ltd.
> grant.likely@secretlab.ca
> (403) 399-0195

-- 
Domen Puncer | Research & Development
.............................................................................................
Telargo d.o.o. | Zagrebška cesta 20 | 2000 Maribor | Slovenia
.............................................................................................
www.telargo.com

^ 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