LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] swsusp: introduce register_nosave_region_late
From: Johannes Berg @ 2007-05-08  9:23 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: Rafael J. Wysocki, linuxppc-dev list

This patch introduces a new register_nosave_region_late function that
can be called from initcalls when register_nosave_region can no longer
be used because it uses bootmem.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Acked-by: Rafael J. Wysocki <rjw@sisk.pl>

---
Paul, I see you merged the suspend to disk for G5 patches, but this one
is required for it to build. Rafael said that we should merge it with
the user, since our code is the only user right now I take it that means
it should go through the powerpc tree.

 include/linux/suspend.h |   11 ++++++++++-
 kernel/power/snapshot.c |   12 +++++++++---
 2 files changed, 19 insertions(+), 4 deletions(-)

--- linux-2.6-git.orig/include/linux/suspend.h	2007-05-03 15:20:29.081123904 +0200
+++ linux-2.6-git/include/linux/suspend.h	2007-05-03 15:23:03.819123904 +0200
@@ -52,7 +52,15 @@ struct hibernation_ops {
 
 #if defined(CONFIG_PM) && defined(CONFIG_SOFTWARE_SUSPEND)
 /* kernel/power/snapshot.c */
-extern void __init register_nosave_region(unsigned long, unsigned long);
+extern void __register_nosave_region(unsigned long b, unsigned long e, int km);
+static inline void register_nosave_region(unsigned long b, unsigned long e)
+{
+	__register_nosave_region(b, e, 0);
+}
+static inline void register_nosave_region_late(unsigned long b, unsigned long e)
+{
+	__register_nosave_region(b, e, 1);
+}
 extern int swsusp_page_is_forbidden(struct page *);
 extern void swsusp_set_page_free(struct page *);
 extern void swsusp_unset_page_free(struct page *);
@@ -70,6 +78,7 @@ void hibernation_set_ops(struct hibernat
 extern int hibernate(void);
 #else
 static inline void register_nosave_region(unsigned long b, unsigned long e) {}
+static inline void register_nosave_region_late(unsigned long b, unsigned long e) {}
 static inline int swsusp_page_is_forbidden(struct page *p) { return 0; }
 static inline void swsusp_set_page_free(struct page *p) {}
 static inline void swsusp_unset_page_free(struct page *p) {}
--- linux-2.6-git.orig/kernel/power/snapshot.c	2007-05-03 15:20:01.842123904 +0200
+++ linux-2.6-git/kernel/power/snapshot.c	2007-05-03 15:22:19.138123904 +0200
@@ -608,7 +608,8 @@ static LIST_HEAD(nosave_regions);
  */
 
 void __init
-register_nosave_region(unsigned long start_pfn, unsigned long end_pfn)
+__register_nosave_region(unsigned long start_pfn, unsigned long end_pfn,
+			 int use_kmalloc)
 {
 	struct nosave_region *region;
 
@@ -624,8 +625,13 @@ register_nosave_region(unsigned long sta
 			goto Report;
 		}
 	}
-	/* This allocation cannot fail */
-	region = alloc_bootmem_low(sizeof(struct nosave_region));
+	if (use_kmalloc) {
+		/* during init, this shouldn't fail */
+		region = kmalloc(sizeof(struct nosave_region), GFP_KERNEL);
+		BUG_ON(!region);
+	} else
+		/* This allocation cannot fail */
+		region = alloc_bootmem_low(sizeof(struct nosave_region));
 	region->start_pfn = start_pfn;
 	region->end_pfn = end_pfn;
 	list_add_tail(&region->list, &nosave_regions);

^ permalink raw reply

* Re: [PATCH 7/7] MPIC U3/U4 MSI backend
From: Johannes Berg @ 2007-05-08  9:04 UTC (permalink / raw)
  To: Michael Ellerman; +Cc: linuxppc-dev, Paul Mackerras
In-Reply-To: <1178614502.18162.34.camel@johannes.berg>

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

On Tue, 2007-05-08 at 10:55 +0200, Johannes Berg wrote:

> How badly will this clash with my patch that implements suspend/resume
> for mpic, and will I need to do more suspend/resume for this?

Oh. I see that my patch is in there already. Will we have to implement
suspend/resume for the MSI case?

johannes

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

^ permalink raw reply

* Re: [PATCH 7/7] MPIC U3/U4 MSI backend
From: Johannes Berg @ 2007-05-08  8:55 UTC (permalink / raw)
  To: Michael Ellerman; +Cc: linuxppc-dev, Paul Mackerras
In-Reply-To: <20070508025843.0D93ADDEFD@ozlabs.org>

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

On Tue, 2007-05-08 at 12:58 +1000, Michael Ellerman wrote:
> MPIC U3/U4 MSI backend. Based on code from Segher, heavily hacked by me.
> This only deals with MSI on U3/U4 MPICs, aka. CPC 9x5.
> 
> If we find a U3/U4 then we enable this backend, ie. take over the ppc_md
> MSI hooks. We might need more elaborate logic in future to decide which
> backend is enabled.
> 
> We need our own irq_chip so that we can do MSI masking/unmasking on
> the device itself. We also need to mask explicitly on shutdown to make
> sure we don't get bitten by lazy-disable semantics.

How badly will this clash with my patch that implements suspend/resume
for mpic, and will I need to do more suspend/resume for this?

johannes

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

^ permalink raw reply

* Re: [PATCH 1/2] [POWERPC] 8xx: mpc885ads pcmcia support
From: Vitaly Bordug @ 2007-05-08  7:23 UTC (permalink / raw)
  To: Olof Johansson; +Cc: linuxppc-dev, linux-pcmcia, linux-kernel
In-Reply-To: <20070507135609.GA8513@lixom.net>

On Mon, 7 May 2007 08:56:09 -0500
Olof Johansson wrote:

> Hi,
> 
> Some minor nitpicks below. Overall it looks good.
> 
> 
> -Olof
> 
> On Sun, May 06, 2007 at 05:26:33AM +0400, Vitaly Bordug wrote:
> > @@ -322,6 +334,70 @@ void init_smc_ioports(struct
> > fs_uart_platform_info *data) }
> >  }
> >  
> > +#ifdef CONFIG_PCMCIA_M8XX
> > +static void pcmcia_hw_setup(int slot, int enable)
> > +{
> > +	unsigned *bcsr_io;
> > +
> > +	bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
> > +	if (enable)
> > +		clrbits32(bcsr_io, BCSR1_PCCEN);
> > +	else
> > +		setbits32(bcsr_io, BCSR1_PCCEN);
> > +
> > +	iounmap(bcsr_io);
> > +}
> 
> If you move this (and next) function up, you don't have to do the
> prototypes in the beginning of the file. One less #ifdef that way.
> 
ok.
> > +
> > +static int pcmcia_set_voltage(int slot, int vcc, int vpp)
> > +{
> > +	u32 reg = 0;
> > +	unsigned *bcsr_io;
> > +
> > +	bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
> > +
> > +	switch(vcc) {
> > +	case 0:
> > +		break;
> > +	case 33:
> > +		reg |= BCSR1_PCCVCC0;
> > +		break;
> > +	case 50:
> > +		reg |= BCSR1_PCCVCC1;
> > +		break;
> > +	default:
> > +		return 1;
> > +	}
> > +
> > +	switch(vpp) {
> > +	case 0:
> > +       	break;
> > +	case 33:
> > +	case 50:
> > +       	if(vcc == vpp)
> > +			reg |= BCSR1_PCCVPP1;
> > +		else
> > +			return 1;
> > +		break;
> > +	case 120:
> > +	if ((vcc == 33) || (vcc == 50))
> > +		reg |= BCSR1_PCCVPP0;
> > +	else
> > +		return 1;
> > +	default:
> > +		return 1;
> > +	}
> > +
> > +	/* first, turn off all power */
> > +	clrbits32(bcsr_io, 0x00610000);
> > +
> > +	/* enable new powersettings */
> > +	setbits32(bcsr_io, reg);
> > +
> > +	iounmap(bcsr_io);
> > +	return 0;
> > +}
> > +#endif
> > +
> >  int platform_device_skip(const char *model, int id)
> >  {
> >  #ifdef CONFIG_MPC8xx_SECOND_ETH_SCC3
> > diff --git a/arch/powerpc/sysdev/fsl_soc.c
> > b/arch/powerpc/sysdev/fsl_soc.c index 8a123c7..880e45f 100644
> > --- a/arch/powerpc/sysdev/fsl_soc.c
> > +++ b/arch/powerpc/sysdev/fsl_soc.c
> > @@ -1028,6 +1028,19 @@ err:
> >  
> >  arch_initcall(fs_enet_of_init);
> >  
> > +static int __init fsl_pcmcia_of_init(void)
> > +{
> > +	struct device_node *np = NULL;
> > +	/*
> > +	 * Register all the devices which type is "pcmcia"
> > +	 */
> > +	while ((np = of_find_compatible_node(np, 
> > +			"pcmcia", "fsl,pq-pcmcia")) != NULL)
> > +			    of_platform_device_create(np,
> > "m8xx-pcmcia", NULL);
> 
> Do you really need this now that you have the device table in the
> driver?
> 
Want to keep this one for now... 

> > +	return 0;
> > +}
> > +
> > +arch_initcall(fsl_pcmcia_of_init);
> >  
> >  static const char *smc_regs = "regs";
> >  static const char *smc_pram = "pram";
> > diff --git a/arch/powerpc/sysdev/mpc8xx_pic.h
> > b/arch/powerpc/sysdev/mpc8xx_pic.h index afa2ee6..07be061 100644
> > --- a/arch/powerpc/sysdev/mpc8xx_pic.h
> > +++ b/arch/powerpc/sysdev/mpc8xx_pic.h
> > @@ -4,7 +4,7 @@
> >  #include <linux/irq.h>
> >  #include <linux/interrupt.h>
> >  
> > -extern struct hw_interrupt_type mpc8xx_pic;
> > +/*extern struct hw_interrupt_type mpc8xx_pic;*/
> 
> Take it out or leave it in, but don't comment it out, please
> 
ok
> >  
> >  int mpc8xx_pic_init(void);
> >  unsigned int mpc8xx_get_irq(void);
> > diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig
> > index 35f8864..c3fd55d 100644
> > --- a/drivers/pcmcia/Kconfig
> > +++ b/drivers/pcmcia/Kconfig
> > @@ -183,6 +183,7 @@ config PCMCIA_M8XX
> >          tristate "MPC8xx PCMCIA support"
> >          depends on PCMCIA && PPC && 8xx 
> >          select PCCARD_IODYN
> > +	select PCCARD_NONSTATIC
> 
> I was going to say "whitespace!", but seems like this added line is
> the only one that's actually using tabs. :-) (Yes, I saw 2/2 that
> fixes this).
> 
> >          help
> >          Say Y here to include support for PowerPC 8xx series PCMCIA
> >          controller.


-- 
Sincerely, Vitaly

^ permalink raw reply

* [PATCH] [POWERPC] i2c: adds support for i2c bus on 8xx
From: Vitaly Bordug @ 2007-05-08  6:31 UTC (permalink / raw)
  To: Jean Delvare; +Cc: linuxppc-dev, linux-kernel


Utilized devicetree to store I2C data, ported i2c-algo-8xx.c from 2.4
approach(which remains nearly intact), refined i2c-rpx.c. I2C functionality
has been validated on mpc885ads with EEPROM access.

Interface has been reworked to of_device as well as other feedback
addressed. Repeated start ability is missing from the implementation.

Signed-off-by: Vitaly Bordug <vitb@kernel.crashing.org>

---

 arch/powerpc/platforms/8xx/mpc885ads_setup.c |   15 +
 arch/powerpc/sysdev/fsl_soc.c                |   15 +
 drivers/i2c/algos/Kconfig                    |    2 
 drivers/i2c/algos/Makefile                   |    1 
 drivers/i2c/algos/i2c-algo-8xx.c             |  520 ++++++++++++++++++++++++++
 drivers/i2c/busses/Kconfig                   |    2 
 drivers/i2c/busses/i2c-rpx.c                 |  143 +++++--
 include/linux/i2c-algo-8xx.h                 |   29 +
 8 files changed, 683 insertions(+), 44 deletions(-)

diff --git a/arch/powerpc/platforms/8xx/mpc885ads_setup.c b/arch/powerpc/platforms/8xx/mpc885ads_setup.c
index a57b577..40d12a2 100644
--- a/arch/powerpc/platforms/8xx/mpc885ads_setup.c
+++ b/arch/powerpc/platforms/8xx/mpc885ads_setup.c
@@ -51,6 +51,17 @@ static void init_smc1_uart_ioports(struct fs_uart_platform_info* fpi);
 static void init_smc2_uart_ioports(struct fs_uart_platform_info* fpi);
 static void init_scc3_ioports(struct fs_platform_info* ptr);
 
+#ifdef CONFIG_I2C_RPXLITE
+static void init_i2c_ioports()
+{
+	cpm8xx_t *cp = (cpm8xx_t *)immr_map(im_cpm);
+
+	setbits32(&cp->cp_pbpar, 0x00000030);
+	setbits32(&cp->cp_pbdir, 0x00000030);
+	setbits16(&cp->cp_pbodr, 0x0030);
+}
+#endif
+
 void __init mpc885ads_board_setup(void)
 {
 	cpm8xx_t *cp;
@@ -115,6 +126,10 @@ void __init mpc885ads_board_setup(void)
 	immr_unmap(io_port);
 
 #endif
+
+#ifdef CONFIG_I2C_RPXLITE
+	init_i2c_ioports();
+#endif
 }
 
 
diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c
index 8a123c7..be60db7 100644
--- a/arch/powerpc/sysdev/fsl_soc.c
+++ b/arch/powerpc/sysdev/fsl_soc.c
@@ -33,6 +33,7 @@
 #include <asm/irq.h>
 #include <asm/time.h>
 #include <asm/prom.h>
+#include <asm/of_platform.h>
 #include <sysdev/fsl_soc.h>
 #include <mm/mmu_decl.h>
 #include <asm/cpm2.h>
@@ -1102,4 +1103,18 @@ err:
 
 arch_initcall(cpm_smc_uart_of_init);
 
+static int __init fsl_i2c_cpm_of_init(void)
+{
+	struct device_node *np = NULL;
+	/*
+	 * Register all the devices which type is "i2c-cpm"
+	 */
+	while ((np = of_find_compatible_node(np, "i2c", "fsl,i2c-cpm")) != NULL)
+		of_platform_device_create(np, "fsl-i2c-cpm", NULL);
+	return 0;
+}
+
+arch_initcall(fsl_i2c_cpm_of_init);
+
+
 #endif /* CONFIG_8xx */
diff --git a/drivers/i2c/algos/Kconfig b/drivers/i2c/algos/Kconfig
index af02034..11e37ff 100644
--- a/drivers/i2c/algos/Kconfig
+++ b/drivers/i2c/algos/Kconfig
@@ -41,6 +41,8 @@ config I2C_ALGOPCA
 config I2C_ALGO8XX
 	tristate "MPC8xx CPM I2C interface"
 	depends on 8xx && I2C
+	help
+	  8xx I2C Algorithm,supports the CPM I2C interface for mpc8xx CPUs.
 
 config I2C_ALGO_SGI
 	tristate "I2C SGI interfaces"
diff --git a/drivers/i2c/algos/Makefile b/drivers/i2c/algos/Makefile
index cac1051..1bd3b37 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_ALGO8XX)	+= i2c-algo-8xx.o
 
 ifeq ($(CONFIG_I2C_DEBUG_ALGO),y)
 EXTRA_CFLAGS += -DDEBUG
diff --git a/drivers/i2c/algos/i2c-algo-8xx.c b/drivers/i2c/algos/i2c-algo-8xx.c
new file mode 100644
index 0000000..01ffcee
--- /dev/null
+++ b/drivers/i2c/algos/i2c-algo-8xx.c
@@ -0,0 +1,520 @@
+/*
+ * i2c-algo-8xx.c i2x driver algorithms for MPC8XX CPM
+ * 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-rpx.c
+ * Brad Parker (brad@heeltoe.com)
+ * 
+ * (C) 2007 Montavista Software, Inc.
+ * Vitaly Bordug <vitb@kernel.crashing.org>
+ */
+
+#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-8xx.h>
+#include <asm/io.h>
+#include <asm/cacheflush.h>
+#include <asm/time.h>
+#include <asm/mpc8xx.h>
+
+/* Try to define this if you have an older CPU (earlier than rev D4) */
+#undef	I2C_CHIP_ERRATA
+
+static wait_queue_head_t iic_wait;
+static ushort r_tbase, r_rbase;
+
+static int cpm_debug;
+
+static irqreturn_t cpm_iic_interrupt(int irq, void *dev_id)
+{
+	i2c8xx_t *i2c = (i2c8xx_t *) dev_id;
+
+#if 0
+	/* Chip errata, clear enable. This is not needed on rev D4 CPUs */
+	/* This should probably be removed and replaced by I2C_CHIP_ERRATA stuff */
+	/* Someone with a buggy CPU needs to confirm that */
+	out_8(&i2c->i2c_i2mod, in_8(&i2c->i2c_i2mod) | ~1);
+#endif
+	/* Clear interrupt.
+	 */
+	out_8(&i2c->i2c_i2cer, 0xff);
+
+	/* Get 'me going again.
+	 */
+	wake_up_interruptible(&iic_wait);
+
+	return IRQ_HANDLED;
+}
+
+static int cpm_iic_init(struct i2c_adapter *adap)
+{
+	struct i2c_algo_8xx_data *cpm = adap->algo_data;
+	iic_t *iip = cpm->iip;
+	i2c8xx_t *i2c = cpm->i2c;
+	unsigned char brg;
+
+	if (cpm_debug)
+		dev_dbg(adap->dev, "cpm_iic_init()\n");
+
+	init_waitqueue_head(&iic_wait);
+
+	/* Initialize the parameter ram.
+	 * We need to make sure many things are initialized to zero,
+	 * especially in the case of a microcode patch.
+	 */
+	iip->iic_rstate = 0;
+	iip->iic_rdp = 0;
+	iip->iic_rbptr = 0;
+	iip->iic_rbc = 0;
+	iip->iic_rxtmp = 0;
+	iip->iic_tstate = 0;
+	iip->iic_tdp = 0;
+	iip->iic_tbptr = 0;
+	iip->iic_tbc = 0;
+	iip->iic_txtmp = 0;
+
+	/* Set up the IIC parameters in the parameter ram.
+	 */
+	iip->iic_tbase = r_tbase = cpm->dp_addr;
+	iip->iic_rbase = r_rbase = cpm->dp_addr + sizeof(cbd_t) * 2;
+
+	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, r_tbase %d\n", iip->iic_tbase,
+			r_tbase);
+	}
+
+	iip->iic_tfcr = SMC_EB;
+	iip->iic_rfcr = SMC_EB;
+
+	/* Set maximum receive size.
+	 */
+	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(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;
+	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);
+
+	/* Install interrupt handler.
+	 */
+	request_irq(cpm->irq, cpm_iic_interrupt, 0, "8xx_i2c", i2c);
+
+	return 0;
+}
+
+static int cpm_iic_shutdown(struct i2c_algo_8xx_data *cpm)
+{
+	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);
+
+	return (0);
+}
+
+static void cpm_reset_iic_params(iic_t * iip)
+{
+	iip->iic_tbase = r_tbase;
+	iip->iic_rbase = r_rbase;
+
+	iip->iic_tfcr = SMC_EB;
+	iip->iic_rfcr = SMC_EB;
+
+	iip->iic_mrblr = CPM_MAX_READ;
+
+	iip->iic_rstate = 0;
+	iip->iic_rdp = 0;
+	iip->iic_rbptr = iip->iic_rbase;
+	iip->iic_rbc = 0;
+	iip->iic_rxtmp = 0;
+	iip->iic_tstate = 0;
+	iip->iic_tdp = 0;
+	iip->iic_tbptr = iip->iic_tbase;
+	iip->iic_tbc = 0;
+	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_8xx_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("force_close()\n");
+
+		out_be16(&cp->cp_cpcr, v);
+		wait_event_timeout(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);
+}
+
+/* Read from IIC...
+ * abyte = address byte, with r/w flag already set
+ */
+static int
+cpm_iic_read(struct i2c_adapter *adap, u_char abyte, char *buf, int count)
+{
+	struct i2c_algo_8xx_data *cpm = adap->algo_data;
+	iic_t *iip = cpm->iip;
+	i2c8xx_t *i2c = cpm->i2c;
+	cbd_t *tbdf, *rbdf;
+	u_char *tb;
+	int res = 0;
+
+	if (count >= CPM_MAX_READ)
+		return -EINVAL;
+
+	/* check for and use a microcode relocation patch */
+	if (cpm->reloc) {
+		cpm_reset_iic_params(iip);
+	}
+
+	tbdf = (cbd_t *) cpm_dpram_addr(iip->iic_tbase);
+	rbdf = (cbd_t *) cpm_dpram_addr(iip->iic_rbase);
+
+	/* 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 = cpm->temp;
+	tb = (u_char *) (((uint) tb + 15) & ~15);
+	tb[0] = abyte;		/* Device address byte w/rw flag */
+
+	flush_dcache_range((unsigned long)tb, (unsigned long)(tb + 1));
+
+	if (cpm_debug)
+		dev_dbg(adap->dev, "cpm_iic_read(abyte=0x%x)\n", abyte);
+
+	tbdf->cbd_bufaddr = __pa(tb);
+	tbdf->cbd_datlen = count + 1;
+	tbdf->cbd_sc = BD_SC_READY | BD_SC_LAST | BD_SC_WRAP | BD_IIC_START;
+
+	iip->iic_mrblr = count + 1;	/* prevent excessive read, +1
+					   is needed otherwise will the
+					   RXB interrupt come too early */
+
+	/* flush will invalidate too. */
+	flush_dcache_range((unsigned long)buf, (unsigned long)(buf + count));
+
+	rbdf->cbd_datlen = 0;
+	rbdf->cbd_bufaddr = __pa(buf);
+	rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP | BD_SC_INTRPT;
+
+	/* 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 */
+	out_8(&i2c->i2c_i2com, in_8(&i2c->i2c_i2com) | 0x80);	/* Begin transmission */
+
+	/* Wait for IIC transfer */
+	res = wait_event_interruptible_timeout(iic_wait, 0, 1 * HZ);
+
+	if (res < 0) {
+		force_close(adap);
+		if (cpm_debug)
+			dev_dbg(adap->dev, "IIC read: timeout!\n");
+		return -EIO;
+	}
+#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
+	if (cpm_debug) {
+		dev_dbg(adap->dev, "tx sc %04x, rx sc %04x\n",
+			tbdf->cbd_sc, rbdf->cbd_sc);
+	}
+
+	if (tbdf->cbd_sc & BD_SC_READY) {
+		dev_dbg(adap->dev, "IIC read; complete but tbuf ready\n");
+		force_close(adap);
+		dev_dbg(adap->dev, "tx sc %04x, rx sc %04x\n",
+			tbdf->cbd_sc, rbdf->cbd_sc);
+	}
+
+	if (tbdf->cbd_sc & BD_SC_NAK) {
+		if (cpm_debug)
+			dev_dbg(adap->dev, "IIC read; no ack\n");
+		return -EREMOTEIO;
+	}
+
+	if (rbdf->cbd_sc & BD_SC_EMPTY) {
+		/* force_close(adap); */
+		if (cpm_debug) {
+			dev_dbg(adap->dev,
+				"IIC read; complete but rbuf empty\n");
+			dev_dbg(adap->dev, "tx sc %04x, rx sc %04x\n",
+				tbdf->cbd_sc, rbdf->cbd_sc);
+		}
+		return -EREMOTEIO;
+	}
+
+	if (rbdf->cbd_sc & BD_SC_OV) {
+		if (cpm_debug)
+			dev_dbg(adap->dev, "IIC read; Overrun\n");
+		return -EREMOTEIO;
+	}
+
+	if (cpm_debug)
+		dev_dbg(adap->dev, "read %d bytes\n", rbdf->cbd_datlen);
+
+	if (rbdf->cbd_datlen < count) {
+		if (cpm_debug)
+			dev_dbg(adap->dev,
+				"IIC read; short, wanted %d got %d\n", count,
+				rbdf->cbd_datlen);
+		return 0;
+	}
+
+	return count;
+}
+
+/* Write to IIC...
+ * addr = address byte, with r/w flag already set
+ */
+static int
+cpm_iic_write(struct i2c_adapter *adap, u_char abyte, char *buf, int count)
+{
+	struct i2c_algo_8xx_data *cpm = adap->algo_data;
+	iic_t *iip = cpm->iip;
+	i2c8xx_t *i2c = cpm->i2c;
+	cbd_t *tbdf;
+	u_char *tb;
+	int res = 0;
+
+	/* check for and use a microcode relocation patch */
+	if (cpm->reloc) {
+		cpm_reset_iic_params(iip);
+	}
+	tb = cpm->temp;
+	tb = (u_char *) (((uint) tb + 15) & ~15);
+	*tb = abyte;		/* Device address byte w/rw flag */
+
+	flush_dcache_range((unsigned long)tb, (unsigned long)(tb + 1));
+	flush_dcache_range((unsigned long)buf, (unsigned long)(buf + count));
+
+	if (cpm_debug)
+		dev_dbg(adap->dev, "cpm_iic_write(abyte=0x%x)\n", abyte);
+
+	/* set up 2 descriptors */
+
+	tbdf = (cbd_t *) cpm_dpram_addr(iip->iic_tbase);
+
+	tbdf[0].cbd_bufaddr = __pa(tb);
+	tbdf[0].cbd_datlen = 1;
+	tbdf[0].cbd_sc = BD_SC_READY | BD_IIC_START;
+
+	tbdf[1].cbd_bufaddr = __pa(buf);
+	tbdf[1].cbd_datlen = count;
+	tbdf[1].cbd_sc = BD_SC_READY | BD_SC_INTRPT | BD_SC_LAST | BD_SC_WRAP;
+
+	/* 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 */
+	out_8(&i2c->i2c_i2com, in_8(&i2c->i2c_i2com) | 0x80);	/* Begin transmission */
+
+	/* Wait for IIC transfer */
+	res = wait_event_interruptible_timeout(iic_wait, 0, 1 * HZ);
+
+	if (res < 0) {
+		force_close(adap);
+		if (cpm_debug)
+			dev_dbg(adap->dev, "IIC write: timeout!\n");
+		return -EIO;
+	}
+#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
+	if (cpm_debug) {
+		dev_dbg(adap->dev, "tx0 sc %04x, tx1 sc %04x\n",
+			tbdf[0].cbd_sc, tbdf[1].cbd_sc);
+	}
+
+	if (tbdf->cbd_sc & BD_SC_NAK) {
+		if (cpm_debug)
+			dev_dbg(adap->dev, "IIC write; no ack\n");
+		return 0;
+	}
+
+	if (tbdf->cbd_sc & BD_SC_READY) {
+		if (cpm_debug)
+			dev_dbg(adap->dev,
+				"IIC write; complete but tbuf ready\n");
+		return 0;
+	}
+
+	return count;
+}
+
+static int cpm_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+	struct i2c_msg *pmsg;
+	int i, ret;
+	u_char addr;
+
+	for (i = 0; i < num; i++) {
+		pmsg = &msgs[i];
+
+		if (cpm_debug)
+			dev_dbg(adap->dev, "i2c-algo-8xx.o: "
+				"#%d addr=0x%x flags=0x%x len=%d\n buf=%lx\n",
+				i, pmsg->addr, pmsg->flags, pmsg->len,
+				(unsigned long)pmsg->buf);
+
+		addr = pmsg->addr << 1;
+		if (pmsg->flags & I2C_M_RD)
+			addr |= 1;
+		if (pmsg->flags & I2C_M_REV_DIR_ADDR)
+			addr ^= 1;
+
+		if (pmsg->flags & I2C_M_RD) {
+			/* read bytes into buffer */
+			ret = cpm_iic_read(adap, addr, pmsg->buf, pmsg->len);
+			if (cpm_debug)
+				dev_dbg(adap->dev,
+					"i2c-algo-8xx.o: read %d bytes\n", ret);
+			if (ret < pmsg->len) {
+				return (ret < 0) ? ret : -EREMOTEIO;
+			}
+		} else {
+			/* write bytes from buffer */
+			ret = cpm_iic_write(adap, addr, pmsg->buf, pmsg->len);
+			if (cpm_debug)
+				dev_dbg(adap->dev, "i2c-algo-8xx.o: wrote %d\n",
+					ret);
+			if (ret < pmsg->len) {
+				return (ret < 0) ? ret : -EREMOTEIO;
+			}
+		}
+	}
+	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_8xx_add_bus(struct i2c_adapter *adap)
+{
+	int res;
+
+	if (cpm_debug)
+		dev_dbg(adap->dev,
+			"i2c-algo-8xx.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);
+}
+
+int i2c_8xx_del_bus(struct i2c_adapter *adap)
+{
+	struct i2c_algo_8xx_data *cpm = adap->algo_data;
+
+	i2c_del_adapter(adap);
+
+	return cpm_iic_shutdown(cpm);
+}
+
+EXPORT_SYMBOL(i2c_8xx_add_bus);
+EXPORT_SYMBOL(i2c_8xx_del_bus);
+
+MODULE_AUTHOR("Brad Parker <brad@heeltoe.com>");
+MODULE_DESCRIPTION("I2C-Bus MPC8XX algorithm");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index ece31d2..df29fb5 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -365,7 +365,7 @@ config I2C_PROSAVAGE
 
 config I2C_RPXLITE
 	tristate "Embedded Planet RPX Lite/Classic support"
-	depends on (RPXLITE || RPXCLASSIC) && I2C
+	depends on (RPXLITE || RPXCLASSIC || MPC86XADS || MPC885ADS) && I2C
 	select I2C_ALGO8XX
 
 config I2C_S3C2410
diff --git a/drivers/i2c/busses/i2c-rpx.c b/drivers/i2c/busses/i2c-rpx.c
index 8764df0..97cbd2c 100644
--- a/drivers/i2c/busses/i2c-rpx.c
+++ b/drivers/i2c/busses/i2c-rpx.c
@@ -5,6 +5,9 @@
  * 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 
@@ -14,88 +17,142 @@
 #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-8xx.h>
+#include <asm/of_device.h>
+#include <asm/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_8xx_data *algo_8xx;
+};
 
+static struct i2c_algo_8xx_data rpx_data;
 
-static void
-rpx_iic_init(struct i2c_algo_8xx_data *data)
+static const struct i2c_adapter rpx_ops = {
+	.owner		= THIS_MODULE,
+	.name		= "i2c-rpx",
+	.id		= I2C_HW_MPC8XX_EPON,
+	.algo_data	= &rpx_data,
+};
+
+static int rpx_iic_init(struct m8xx_i2c *i2c)
 {
 	volatile cpm8xx_t *cp;
-	volatile immap_t *immap;
+	struct resource r;
+	struct i2c_algo_8xx_data *data = i2c->algo_8xx;
+	struct of_device *ofdev = i2c->ofdev;
+	struct device_node *np = ofdev->node;
+
+	/* Pointer to Communication Processor 
+	 */
+	cp = data->cp = (cpm8xx_t *)immr_map(im_cpm);
 
-	cp = cpmp;	/* Get pointer to Communication Processor */
-	immap = (immap_t *)IMAP_ADDR;	/* and to internal registers */
+	data->irq = irq_of_parse_and_map(np, 0);
+  	if (data->irq < 0)
+		return -EINVAL;
 
-	data->iip = (iic_t *)&cp->cp_dparam[PROFF_IIC];
+	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.
-	*/
+	 */
 	if ((data->reloc = data->iip->iic_rpbase))
 		data->iip = (iic_t *)&cp->cp_dpmem[data->iip->iic_rpbase];
 		
-	data->i2c = (i2c8xx_t *)&(immap->im_i2c);
-	data->cp = cp;
+	if (of_address_to_resource(np, 0, &r))
+		return -EINVAL;
 
-	/* Initialize Port B IIC pins.
-	*/
-	cp->cp_pbpar |= 0x00000030;
-	cp->cp_pbdir |= 0x00000030;
-	cp->cp_pbodr |= 0x00000030;
+	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);
-		
-	/* ptr to i2c area */
-	data->i2c = (i2c8xx_t *)&(((immap_t *)IMAP_ADDR)->im_i2c);
 }
 
-static int rpx_install_isr(int irq, void (*func)(void *), void *data)
+static int i2c_rpx_probe(struct of_device* ofdev, const struct of_device_id *match)
 {
-	/* install interrupt handler */
-	cpm_install_handler(irq, func, data);
+	int result;
+	struct m8xx_i2c *i2c;
 
-	return 0;
-}
+	if (!(i2c = kzalloc(sizeof(*i2c), GFP_KERNEL))) {
+		return -ENOMEM;
+	}
+	i2c->ofdev = ofdev;
+	i2c->algo_8xx = &rpx_data;
 
-static struct i2c_algo_8xx_data rpx_data = {
-	.setisr = rpx_install_isr
-};
+	rpx_iic_init(i2c);
 
-static struct i2c_adapter rpx_ops = {
-	.owner		= THIS_MODULE,
-	.name		= "m8xx",
-	.id		= I2C_HW_MPC8XX_EPON,
-	.algo_data	= &rpx_data,
-};
-
-int __init i2c_rpx_init(void)
-{
-	printk(KERN_INFO "i2c-rpx: i2c MPC8xx driver\n");
+	dev_set_drvdata(&ofdev->dev, i2c);
 
-	/* reset hardware to sane state */
-	rpx_iic_init(&rpx_data);
+	i2c->adap = rpx_ops;
+	i2c_set_adapdata(&i2c->adap, i2c);
+	i2c->adap.dev.parent = &ofdev->dev;
 
-	if (i2c_8xx_add_bus(&rpx_ops) < 0) {
+	if ((result = i2c_8xx_add_bus(&i2c->adap) < 0)) {
 		printk(KERN_ERR "i2c-rpx: Unable to register with I2C\n");
-		return -ENODEV;
+		kfree(i2c);
 	}
 
+	return result;
+}
+
+static int i2c_rpx_remove(struct of_device* ofdev)
+{
+	struct m8xx_i2c *i2c = dev_get_drvdata(&ofdev->dev);
+
+	i2c_8xx_del_bus(&i2c->adap);
+	dev_set_drvdata(&ofdev->dev, NULL);
+
+	kfree(i2c);
 	return 0;
 }
 
-void __exit i2c_rpx_exit(void)
+static struct of_device_id i2c_rpx_match[] = {
+	{
+		.type = "i2c",
+		.compatible = "fsl,i2c-cpm",
+	},
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, i2c_rpx_match);
+
+static struct of_platform_driver i2c_rpx_driver = {
+	.name		= "fsl-i2c-cpm",
+	.match_table	= i2c_rpx_match,
+	.probe		= i2c_rpx_probe,
+	.remove		= i2c_rpx_remove,
+};
+
+static int __init i2c_rpx_init(void)
 {
-	i2c_8xx_del_bus(&rpx_ops);
+	return of_register_platform_driver(&i2c_rpx_driver);
 }
 
-MODULE_AUTHOR("Dan Malek <dmalek@jlc.net>");
-MODULE_DESCRIPTION("I2C-Bus adapter routines for MPC8xx boards");
+static void __exit i2c_rpx_exit(void)
+{
+	of_unregister_platform_driver(&i2c_rpx_driver);
+}
 
 module_init(i2c_rpx_init);
 module_exit(i2c_rpx_exit);
+
+MODULE_AUTHOR("Dan Malek <dmalek@jlc.net>");
+MODULE_DESCRIPTION("I2C-Bus adapter routines for MPC8xx boards");
diff --git a/include/linux/i2c-algo-8xx.h b/include/linux/i2c-algo-8xx.h
new file mode 100644
index 0000000..c63a739
--- /dev/null
+++ b/include/linux/i2c-algo-8xx.h
@@ -0,0 +1,29 @@
+/* ------------------------------------------------------------------------- */
+/* i2c-algo-8xx.h i2c driver algorithms for MPX8XX CPM			     */
+/* ------------------------------------------------------------------------- */
+
+#ifndef I2C_ALGO_8XX_H
+#define I2C_ALGO_8XX_H
+
+#include <linux/i2c.h>
+#include <asm/8xx_immap.h>
+#include <asm/commproc.h>
+
+#define CPM_MAX_READ    513
+
+struct i2c_algo_8xx_data {
+	uint dp_addr;
+	int reloc;
+	int irq;
+	i2c8xx_t *i2c;
+	iic_t *iip;
+	cpm8xx_t *cp;
+
+	u_char temp[CPM_MAX_READ];
+};
+
+extern int i2c_8xx_add_bus(struct i2c_adapter *);
+extern int i2c_8xx_del_bus(struct i2c_adapter *);
+
+#endif /* I2C_ALGO_8XX_H */
+

^ permalink raw reply related

* [PATCH 5/5] powerpc: Don't use SLAB/SLUB for PTE pages
From: Benjamin Herrenschmidt @ 2007-05-08  6:27 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Hugh Dickins, Paul Mackerras
In-Reply-To: <1178605646.637780.625211974455.qpush@grosgo>

From: Hugh Dickins <hugh@veritas.com>

The SLUB allocator relies on struct page fields first_page and slab,
overwritten by ptl when SPLIT_PTLOCK: so the SLUB allocator cannot then
be used for the lowest level of pagetable pages.  This was obstructing
SLUB on PowerPC, which uses kmem_caches for its pagetables.  So convert
its pte level to use normal gfp pages (whereas pmd, pud and 64k-page pgd
want partpages, so continue to use kmem_caches for pmd, pud and pgd).

Signed-off-by: Hugh Dickins <hugh@veritas.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---

 arch/powerpc/mm/init_64.c     |   17 ++++++-----------
 include/asm-powerpc/pgalloc.h |   34 ++++++++++++++++------------------
 2 files changed, 22 insertions(+), 29 deletions(-)

Index: linux-cell/arch/powerpc/mm/init_64.c
===================================================================
--- linux-cell.orig/arch/powerpc/mm/init_64.c	2007-05-08 11:46:50.000000000 +1000
+++ linux-cell/arch/powerpc/mm/init_64.c	2007-05-08 15:45:46.000000000 +1000
@@ -146,21 +146,16 @@ static void zero_ctor(void *addr, struct
 	memset(addr, 0, kmem_cache_size(cache));
 }
 
-#ifdef CONFIG_PPC_64K_PAGES
-static const unsigned int pgtable_cache_size[3] = {
-	PTE_TABLE_SIZE, PMD_TABLE_SIZE, PGD_TABLE_SIZE
-};
-static const char *pgtable_cache_name[ARRAY_SIZE(pgtable_cache_size)] = {
-	"pte_pmd_cache", "pmd_cache", "pgd_cache",
-};
-#else
 static const unsigned int pgtable_cache_size[2] = {
-	PTE_TABLE_SIZE, PMD_TABLE_SIZE
+	PGD_TABLE_SIZE, PMD_TABLE_SIZE
 };
 static const char *pgtable_cache_name[ARRAY_SIZE(pgtable_cache_size)] = {
-	"pgd_pte_cache", "pud_pmd_cache",
-};
+#ifdef CONFIG_PPC_64K_PAGES
+	"pgd_cache", "pmd_cache",
+#else
+	"pgd_cache", "pud_pmd_cache",
 #endif /* CONFIG_PPC_64K_PAGES */
+};
 
 #ifdef CONFIG_HUGETLB_PAGE
 /* Hugepages need one extra cache, initialized in hugetlbpage.c.  We
Index: linux-cell/include/asm-powerpc/pgalloc.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/pgalloc.h	2007-04-27 14:13:24.000000000 +1000
+++ linux-cell/include/asm-powerpc/pgalloc.h	2007-05-08 16:01:00.000000000 +1000
@@ -13,18 +13,11 @@
 
 extern struct kmem_cache *pgtable_cache[];
 
-#ifdef CONFIG_PPC_64K_PAGES
-#define PTE_CACHE_NUM	0
-#define PMD_CACHE_NUM	1
-#define PGD_CACHE_NUM	2
-#define HUGEPTE_CACHE_NUM 3
-#else
-#define PTE_CACHE_NUM	0
-#define PMD_CACHE_NUM	1
-#define PUD_CACHE_NUM	1
-#define PGD_CACHE_NUM	0
-#define HUGEPTE_CACHE_NUM 2
-#endif
+#define PGD_CACHE_NUM		0
+#define PUD_CACHE_NUM		1
+#define PMD_CACHE_NUM		1
+#define HUGEPTE_CACHE_NUM	2
+#define PTE_NONCACHE_NUM	3  /* from GFP rather than kmem_cache */
 
 /*
  * This program is free software; you can redistribute it and/or
@@ -97,8 +90,10 @@ static inline void pmd_free(pmd_t *pmd)
 static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
 					  unsigned long address)
 {
-	return kmem_cache_alloc(pgtable_cache[PTE_CACHE_NUM],
-				GFP_KERNEL|__GFP_REPEAT);
+	pte_t *ptepage = (pte_t *)__get_free_page(GFP_KERNEL | __GFP_REPEAT);
+	if (ptepage)
+		clear_page(ptepage);
+	return ptepage;
 }
 
 static inline struct page *pte_alloc_one(struct mm_struct *mm,
@@ -109,12 +104,12 @@ static inline struct page *pte_alloc_one
 		
 static inline void pte_free_kernel(pte_t *pte)
 {
-	kmem_cache_free(pgtable_cache[PTE_CACHE_NUM], pte);
+	free_page((unsigned long)pte);
 }
 
 static inline void pte_free(struct page *ptepage)
 {
-	pte_free_kernel(page_address(ptepage));
+	__free_page(ptepage);
 }
 
 #define PGF_CACHENUM_MASK	0x3
@@ -136,14 +131,17 @@ static inline void pgtable_free(pgtable_
 	void *p = (void *)(pgf.val & ~PGF_CACHENUM_MASK);
 	int cachenum = pgf.val & PGF_CACHENUM_MASK;
 
-	kmem_cache_free(pgtable_cache[cachenum], p);
+	if (cachenum == PTE_NONCACHE_NUM)
+		free_page((unsigned long)p);
+	else
+		kmem_cache_free(pgtable_cache[cachenum], p);
 }
 
 extern void pgtable_free_tlb(struct mmu_gather *tlb, pgtable_free_t pgf);
 
 #define __pte_free_tlb(tlb, ptepage)	\
 	pgtable_free_tlb(tlb, pgtable_free_cache(page_address(ptepage), \
-		PTE_CACHE_NUM, PTE_TABLE_SIZE-1))
+		PTE_NONCACHE_NUM, PTE_TABLE_SIZE-1))
 #define __pmd_free_tlb(tlb, pmd) 	\
 	pgtable_free_tlb(tlb, pgtable_free_cache(pmd, \
 		PMD_CACHE_NUM, PMD_TABLE_SIZE-1))

^ permalink raw reply

* [PATCH 4/5] powerpc: spufs support for 64K LS mappings on 4K kernels
From: Benjamin Herrenschmidt @ 2007-05-08  6:27 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Hugh Dickins, Paul Mackerras
In-Reply-To: <1178605646.637780.625211974455.qpush@grosgo>

This patch adds an option to spufs when the kernel is configured for
4K page to give it the ability to use 64K pages for SPE local store
mappings.

Currently, we are optimistic and try order 4 allocations when creting
contexts. If that fails, the code will fallback to 4K automatically.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

 arch/powerpc/platforms/cell/Kconfig             |   15 +
 arch/powerpc/platforms/cell/spufs/Makefile      |    2 
 arch/powerpc/platforms/cell/spufs/context.c     |    4 
 arch/powerpc/platforms/cell/spufs/file.c        |   78 ++++++++--
 arch/powerpc/platforms/cell/spufs/lscsa_alloc.c |  181 ++++++++++++++++++++++++
 arch/powerpc/platforms/cell/spufs/switch.c      |   28 +--
 include/asm-powerpc/spu_csa.h                   |   10 +
 7 files changed, 282 insertions(+), 36 deletions(-)

Index: linux-cell/arch/powerpc/platforms/cell/Kconfig
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/cell/Kconfig	2007-05-08 15:27:02.000000000 +1000
+++ linux-cell/arch/powerpc/platforms/cell/Kconfig	2007-05-08 15:29:26.000000000 +1000
@@ -35,6 +35,21 @@ config SPU_FS
 	  Units on machines implementing the Broadband Processor
 	  Architecture.
 
+config SPU_FS_64K_LS
+	bool "Use 64K pages to map SPE local  store"
+	# we depend on PPC_MM_SLICES for now rather than selecting
+	# it because we depend on hugetlbfs hooks being present. We
+	# will fix that when the generic code has been improved to
+	# not require hijacking hugetlbfs hooks.
+	depends on SPU_FS && PPC_MM_SLICES && !PPC_64K_PAGES
+	default y
+	select PPC_HAS_HASH_64K
+	help
+	  This option causes SPE local stores to be mapped in process
+	  address spaces using 64K pages while the rest of the kernel
+	  uses 4K pages. This can improve performances of applications
+	  using multiple SPEs by lowering the TLB pressure on them.
+
 config SPU_BASE
 	bool
 	default n
Index: linux-cell/arch/powerpc/platforms/cell/spufs/context.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/cell/spufs/context.c	2007-05-08 15:27:02.000000000 +1000
+++ linux-cell/arch/powerpc/platforms/cell/spufs/context.c	2007-05-08 15:29:26.000000000 +1000
@@ -36,10 +36,8 @@ struct spu_context *alloc_spu_context(st
 	/* Binding to physical processor deferred
 	 * until spu_activate().
 	 */
-	spu_init_csa(&ctx->csa);
-	if (!ctx->csa.lscsa) {
+	if (spu_init_csa(&ctx->csa))
 		goto out_free;
-	}
 	spin_lock_init(&ctx->mmio_lock);
 	spin_lock_init(&ctx->mapping_lock);
 	kref_init(&ctx->kref);
Index: linux-cell/arch/powerpc/platforms/cell/spufs/switch.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/cell/spufs/switch.c	2007-05-08 15:27:02.000000000 +1000
+++ linux-cell/arch/powerpc/platforms/cell/spufs/switch.c	2007-05-08 15:29:26.000000000 +1000
@@ -2189,40 +2189,30 @@ static void init_priv2(struct spu_state 
  * as it is by far the largest of the context save regions,
  * and may need to be pinned or otherwise specially aligned.
  */
-void spu_init_csa(struct spu_state *csa)
+int spu_init_csa(struct spu_state *csa)
 {
-	struct spu_lscsa *lscsa;
-	unsigned char *p;
+	int rc;
 
 	if (!csa)
-		return;
+		return -EINVAL;
 	memset(csa, 0, sizeof(struct spu_state));
 
-	lscsa = vmalloc(sizeof(struct spu_lscsa));
-	if (!lscsa)
-		return;
+	rc = spu_alloc_lscsa(csa);
+	if (rc)
+		return rc;
 
-	memset(lscsa, 0, sizeof(struct spu_lscsa));
-	csa->lscsa = lscsa;
 	spin_lock_init(&csa->register_lock);
 
-	/* Set LS pages reserved to allow for user-space mapping. */
-	for (p = lscsa->ls; p < lscsa->ls + LS_SIZE; p += PAGE_SIZE)
-		SetPageReserved(vmalloc_to_page(p));
-
 	init_prob(csa);
 	init_priv1(csa);
 	init_priv2(csa);
+
+	return 0;
 }
 EXPORT_SYMBOL_GPL(spu_init_csa);
 
 void spu_fini_csa(struct spu_state *csa)
 {
-	/* Clear reserved bit before vfree. */
-	unsigned char *p;
-	for (p = csa->lscsa->ls; p < csa->lscsa->ls + LS_SIZE; p += PAGE_SIZE)
-		ClearPageReserved(vmalloc_to_page(p));
-
-	vfree(csa->lscsa);
+	spu_free_lscsa(csa);
 }
 EXPORT_SYMBOL_GPL(spu_fini_csa);
Index: linux-cell/include/asm-powerpc/spu_csa.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/spu_csa.h	2007-05-08 15:27:02.000000000 +1000
+++ linux-cell/include/asm-powerpc/spu_csa.h	2007-05-08 15:29:26.000000000 +1000
@@ -235,6 +235,12 @@ struct spu_priv2_collapsed {
  */
 struct spu_state {
 	struct spu_lscsa *lscsa;
+#ifdef CONFIG_SPU_FS_64K_LS
+	int		use_big_pages;
+	/* One struct page per 64k page */
+#define SPU_LSCSA_NUM_BIG_PAGES	(sizeof(struct spu_lscsa) / 0x10000)
+	struct page	*lscsa_pages[SPU_LSCSA_NUM_BIG_PAGES];
+#endif
 	struct spu_problem_collapsed prob;
 	struct spu_priv1_collapsed priv1;
 	struct spu_priv2_collapsed priv2;
@@ -247,12 +253,14 @@ struct spu_state {
 	spinlock_t register_lock;
 };
 
-extern void spu_init_csa(struct spu_state *csa);
+extern int spu_init_csa(struct spu_state *csa);
 extern void spu_fini_csa(struct spu_state *csa);
 extern int spu_save(struct spu_state *prev, struct spu *spu);
 extern int spu_restore(struct spu_state *new, struct spu *spu);
 extern int spu_switch(struct spu_state *prev, struct spu_state *new,
 		      struct spu *spu);
+extern int spu_alloc_lscsa(struct spu_state *csa);
+extern void spu_free_lscsa(struct spu_state *csa);
 
 #endif /* !__SPU__ */
 #endif /* __KERNEL__ */
Index: linux-cell/arch/powerpc/platforms/cell/spufs/Makefile
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/cell/spufs/Makefile	2007-05-08 15:27:02.000000000 +1000
+++ linux-cell/arch/powerpc/platforms/cell/spufs/Makefile	2007-05-08 15:29:26.000000000 +1000
@@ -1,4 +1,4 @@
-obj-y += switch.o fault.o
+obj-y += switch.o fault.o lscsa_alloc.o
 
 obj-$(CONFIG_SPU_FS) += spufs.o
 spufs-y += inode.o file.o context.o syscalls.o coredump.o
Index: linux-cell/arch/powerpc/platforms/cell/spufs/lscsa_alloc.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-cell/arch/powerpc/platforms/cell/spufs/lscsa_alloc.c	2007-05-08 15:29:26.000000000 +1000
@@ -0,0 +1,181 @@
+/*
+ * SPU local store allocation routines
+ *
+ * Copyright 2007 Benjamin Herrenschmidt, IBM Corp.
+ *
+ * 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, 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.
+ */
+
+#undef DEBUG
+
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+
+#include <asm/spu.h>
+#include <asm/spu_csa.h>
+#include <asm/mmu.h>
+
+static int spu_alloc_lscsa_std(struct spu_state *csa)
+{
+	struct spu_lscsa *lscsa;
+	unsigned char *p;
+
+	lscsa = vmalloc(sizeof(struct spu_lscsa));
+	if (!lscsa)
+		return -ENOMEM;
+	memset(lscsa, 0, sizeof(struct spu_lscsa));
+	csa->lscsa = lscsa;
+
+	/* Set LS pages reserved to allow for user-space mapping. */
+	for (p = lscsa->ls; p < lscsa->ls + LS_SIZE; p += PAGE_SIZE)
+		SetPageReserved(vmalloc_to_page(p));
+
+	return 0;
+}
+
+static void spu_free_lscsa_std(struct spu_state *csa)
+{
+	/* Clear reserved bit before vfree. */
+	unsigned char *p;
+
+	if (csa->lscsa == NULL)
+		return;
+
+	for (p = csa->lscsa->ls; p < csa->lscsa->ls + LS_SIZE; p += PAGE_SIZE)
+		ClearPageReserved(vmalloc_to_page(p));
+
+	vfree(csa->lscsa);
+}
+
+#ifdef CONFIG_SPU_FS_64K_LS
+
+#define SPU_64K_PAGE_SHIFT	16
+#define SPU_64K_PAGE_ORDER	(SPU_64K_PAGE_SHIFT - PAGE_SHIFT)
+#define SPU_64K_PAGE_COUNT	(1ul << SPU_64K_PAGE_ORDER)
+
+int spu_alloc_lscsa(struct spu_state *csa)
+{
+	struct page	**pgarray;
+	unsigned char	*p;
+	int		i, j, n_4k;
+
+	/* Check availability of 64K pages */
+	if (mmu_psize_defs[MMU_PAGE_64K].shift == 0)
+		goto fail;
+
+	csa->use_big_pages = 1;
+
+	pr_debug("spu_alloc_lscsa(csa=0x%p), trying to allocate 64K pages\n",
+		 csa);
+
+	/* First try to allocate our 64K pages. We need 5 of them
+	 * with the current implementation. In the future, we should try
+	 * to separate the lscsa with the actual local store image, thus
+	 * allowing us to require only 4 64K pages per context
+	 */
+	for (i = 0; i < SPU_LSCSA_NUM_BIG_PAGES; i++) {
+		/* XXX This is likely to fail, we should use a special pool
+		 *     similiar to what hugetlbfs does.
+		 */
+		csa->lscsa_pages[i] = alloc_pages(GFP_KERNEL,
+						  SPU_64K_PAGE_ORDER);
+		if (csa->lscsa_pages[i] == NULL)
+			goto fail;
+	}
+
+	pr_debug(" success ! creating vmap...\n");
+
+	/* Now we need to create a vmalloc mapping of these for the kernel
+	 * and SPU context switch code to use. Currently, we stick to a
+	 * normal kernel vmalloc mapping, which in our case will be 4K
+	 */
+	n_4k = SPU_64K_PAGE_COUNT * SPU_LSCSA_NUM_BIG_PAGES;
+	pgarray = kmalloc(sizeof(struct page *) * n_4k, GFP_KERNEL);
+	if (pgarray == NULL)
+		goto fail;
+	for (i = 0; i < SPU_LSCSA_NUM_BIG_PAGES; i++)
+		for (j = 0; j < SPU_64K_PAGE_COUNT; j++)
+			/* We assume all the struct page's are contiguous
+			 * which should be hopefully the case for an order 4
+			 * allocation..
+			 */
+			pgarray[i * SPU_64K_PAGE_COUNT + j] =
+				csa->lscsa_pages[i] + j;
+	csa->lscsa = vmap(pgarray, n_4k, VM_USERMAP, PAGE_KERNEL);
+	kfree(pgarray);
+	if (csa->lscsa == NULL)
+		goto fail;
+
+	memset(csa->lscsa, 0, sizeof(struct spu_lscsa));
+
+	/* Set LS pages reserved to allow for user-space mapping.
+	 *
+	 * XXX isn't that a bit obsolete ? I think we should just
+	 * make sure the page count is high enough. Anyway, won't harm
+	 * for now
+	 */
+	for (p = csa->lscsa->ls; p < csa->lscsa->ls + LS_SIZE; p += PAGE_SIZE)
+		SetPageReserved(vmalloc_to_page(p));
+
+	pr_debug(" all good !\n");
+
+	return 0;
+fail:
+	pr_debug("spufs: failed to allocate lscsa 64K pages, falling back\n");
+	spu_free_lscsa(csa);
+	return spu_alloc_lscsa_std(csa);
+}
+
+void spu_free_lscsa(struct spu_state *csa)
+{
+	unsigned char *p;
+	int i;
+
+	if (!csa->use_big_pages) {
+		spu_free_lscsa_std(csa);
+		return;
+	}
+	csa->use_big_pages = 0;
+
+	if (csa->lscsa == NULL)
+		goto free_pages;
+
+	for (p = csa->lscsa->ls; p < csa->lscsa->ls + LS_SIZE; p += PAGE_SIZE)
+		ClearPageReserved(vmalloc_to_page(p));
+
+	vunmap(csa->lscsa);
+	csa->lscsa = NULL;
+
+ free_pages:
+
+	for (i = 0; i < SPU_LSCSA_NUM_BIG_PAGES; i++)
+		if (csa->lscsa_pages[i])
+			__free_pages(csa->lscsa_pages[i], SPU_64K_PAGE_ORDER);
+}
+
+#else /* CONFIG_SPU_FS_64K_LS */
+
+int spu_alloc_lscsa(struct spu_state *csa)
+{
+	return spu_alloc_lscsa_std(csa);
+}
+
+void spu_free_lscsa(struct spu_state *csa)
+{
+	spu_free_lscsa_std(csa);
+}
+
+#endif /* !defined(CONFIG_SPU_FS_64K_LS) */
Index: linux-cell/arch/powerpc/platforms/cell/spufs/file.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/cell/spufs/file.c	2007-05-08 15:27:02.000000000 +1000
+++ linux-cell/arch/powerpc/platforms/cell/spufs/file.c	2007-05-08 15:29:26.000000000 +1000
@@ -118,14 +118,32 @@ spufs_mem_write(struct file *file, const
 static unsigned long spufs_mem_mmap_nopfn(struct vm_area_struct *vma,
 					  unsigned long address)
 {
-	struct spu_context *ctx = vma->vm_file->private_data;
-	unsigned long pfn, offset = address - vma->vm_start;
-
-	offset += vma->vm_pgoff << PAGE_SHIFT;
+	struct spu_context *ctx	= vma->vm_file->private_data;
+	unsigned long pfn, offset, addr0 = address;
+#ifdef CONFIG_SPU_FS_64K_LS
+	struct spu_state *csa = &ctx->csa;
+	int psize;
+
+	/* Check what page size we are using */
+	psize = get_slice_psize(vma->vm_mm, address);
+
+	/* Some sanity checking */
+	BUG_ON(csa->use_big_pages != (psize == MMU_PAGE_64K));
+
+	/* Wow, 64K, cool, we need to align the address though */
+	if (csa->use_big_pages) {
+		BUG_ON(vma->vm_start & 0xffff);
+		address &= ~0xfffful;
+	}
+#endif /* CONFIG_SPU_FS_64K_LS */
 
+	offset = (address - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT);
 	if (offset >= LS_SIZE)
 		return NOPFN_SIGBUS;
 
+	pr_debug("spufs_mem_mmap_nopfn address=0x%lx -> 0x%lx, offset=0x%lx\n",
+		 addr0, address, offset);
+
 	spu_acquire(ctx);
 
 	if (ctx->state == SPU_STATE_SAVED) {
@@ -149,9 +167,24 @@ static struct vm_operations_struct spufs
 	.nopfn = spufs_mem_mmap_nopfn,
 };
 
-static int
-spufs_mem_mmap(struct file *file, struct vm_area_struct *vma)
+static int spufs_mem_mmap(struct file *file, struct vm_area_struct *vma)
 {
+#ifdef CONFIG_SPU_FS_64K_LS
+	struct spu_context	*ctx = file->private_data;
+	struct spu_state	*csa = &ctx->csa;
+
+	/* Sanity check VMA alignment */
+	if (csa->use_big_pages) {
+		pr_debug("spufs_mem_mmap 64K, start=0x%lx, end=0x%lx,"
+			 " pgoff=0x%lx\n", vma->vm_start, vma->vm_end,
+			 vma->vm_pgoff);
+		if (vma->vm_start & 0xffff)
+			return -EINVAL;
+		if (vma->vm_pgoff & 0xf)
+			return -EINVAL;
+	}
+#endif /* CONFIG_SPU_FS_64K_LS */
+
 	if (!(vma->vm_flags & VM_SHARED))
 		return -EINVAL;
 
@@ -163,13 +196,34 @@ spufs_mem_mmap(struct file *file, struct
 	return 0;
 }
 
+#ifdef CONFIG_SPU_FS_64K_LS
+unsigned long spufs_get_unmapped_area(struct file *file, unsigned long addr,
+				      unsigned long len, unsigned long pgoff,
+				      unsigned long flags)
+{
+	struct spu_context	*ctx = file->private_data;
+	struct spu_state	*csa = &ctx->csa;
+
+	/* If not using big pages, fallback to normal MM g_u_a */
+	if (!csa->use_big_pages)
+		return current->mm->get_unmapped_area(file, addr, len,
+						      pgoff, flags);
+
+	/* Else, try to obtain a 64K pages slice */
+	return slice_get_unmapped_area(addr, len, flags,
+				       MMU_PAGE_64K, 1, 0);
+}
+#endif /* CONFIG_SPU_FS_64K_LS */
+
 static const struct file_operations spufs_mem_fops = {
-	.open	 = spufs_mem_open,
-	.release = spufs_mem_release,
-	.read    = spufs_mem_read,
-	.write   = spufs_mem_write,
-	.llseek  = generic_file_llseek,
-	.mmap    = spufs_mem_mmap,
+	.open	 		= spufs_mem_open,
+	.read   		= spufs_mem_read,
+	.write   		= spufs_mem_write,
+	.llseek  		= generic_file_llseek,
+	.mmap    		= spufs_mem_mmap,
+#ifdef CONFIG_SPU_FS_64K_LS
+	.get_unmapped_area	= spufs_get_unmapped_area,
+#endif
 };
 
 static unsigned long spufs_ps_nopfn(struct vm_area_struct *vma,

^ permalink raw reply

* [PATCH 3/5] powerpc: Add ability to 4K kernel to hash in 64K pages
From: Benjamin Herrenschmidt @ 2007-05-08  6:27 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Hugh Dickins, Paul Mackerras
In-Reply-To: <1178605646.637780.625211974455.qpush@grosgo>

This patch adds the ability for a kernel compiled with 4K page size
to have special slices containing 64K pages and hash the right type
of hash PTEs.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

 arch/powerpc/Kconfig              |    6 +++++
 arch/powerpc/mm/hash_low_64.S     |    5 +++-
 arch/powerpc/mm/hash_utils_64.c   |   39 ++++++++++++++++++++++++++------------
 arch/powerpc/mm/tlb_64.c          |   12 ++++++++---
 include/asm-powerpc/pgtable-4k.h  |    6 ++++-
 include/asm-powerpc/pgtable-64k.h |    7 +++++-
 6 files changed, 57 insertions(+), 18 deletions(-)

Index: linux-cell/arch/powerpc/mm/hash_low_64.S
===================================================================
--- linux-cell.orig/arch/powerpc/mm/hash_low_64.S	2007-05-08 15:27:03.000000000 +1000
+++ linux-cell/arch/powerpc/mm/hash_low_64.S	2007-05-08 15:29:21.000000000 +1000
@@ -615,6 +615,9 @@ htab_pte_insert_failure:
 	li	r3,-1
 	b	htab_bail
 
+#endif /* CONFIG_PPC_64K_PAGES */
+
+#ifdef CONFIG_PPC_HAS_HASH_64K
 
 /*****************************************************************************
  *                                                                           *
@@ -870,7 +873,7 @@ ht64_pte_insert_failure:
 	b	ht64_bail
 
 
-#endif /* CONFIG_PPC_64K_PAGES */
+#endif /* CONFIG_PPC_HAS_HASH_64K */
 
 
 /*****************************************************************************
Index: linux-cell/include/asm-powerpc/pgtable-64k.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/pgtable-64k.h	2007-05-08 15:27:03.000000000 +1000
+++ linux-cell/include/asm-powerpc/pgtable-64k.h	2007-05-08 15:29:21.000000000 +1000
@@ -36,6 +36,11 @@
 #define _PAGE_HPTE_SUB0	0x08000000 /* combo only: first sub page */
 #define _PAGE_COMBO	0x10000000 /* this is a combo 4k page */
 #define _PAGE_4K_PFN	0x20000000 /* PFN is for a single 4k page */
+
+/* Note the full page bits must be in the same location as for normal
+ * 4k pages as the same asssembly will be used to insert 64K pages
+ * wether the kernel has CONFIG_PPC_64K_PAGES or not
+ */
 #define _PAGE_F_SECOND  0x00008000 /* full page: hidx bits */
 #define _PAGE_F_GIX     0x00007000 /* full page: hidx bits */
 
@@ -91,7 +96,7 @@
 
 #define pte_iterate_hashed_end() } while(0); } } while(0)
 
-#define pte_pagesize_index(pte)	\
+#define pte_pagesize_index(mm, addr, pte)	\
 	(((pte) & _PAGE_COMBO)? MMU_PAGE_4K: MMU_PAGE_64K)
 
 #define remap_4k_pfn(vma, addr, pfn, prot)				\
Index: linux-cell/arch/powerpc/Kconfig
===================================================================
--- linux-cell.orig/arch/powerpc/Kconfig	2007-05-08 15:27:52.000000000 +1000
+++ linux-cell/arch/powerpc/Kconfig	2007-05-08 15:29:21.000000000 +1000
@@ -532,9 +532,15 @@ config NODES_SPAN_OTHER_NODES
 	def_bool y
 	depends on NEED_MULTIPLE_NODES
 
+config PPC_HAS_HASH_64K
+	bool
+	depends on PPC64
+	default n
+
 config PPC_64K_PAGES
 	bool "64k page size"
 	depends on PPC64
+	select PPC_HAS_HASH_64K
 	help
 	  This option changes the kernel logical page size to 64k. On machines
 	  without processor support for 64k pages, the kernel will simulate
Index: linux-cell/arch/powerpc/mm/hash_utils_64.c
===================================================================
--- linux-cell.orig/arch/powerpc/mm/hash_utils_64.c	2007-05-08 15:28:34.000000000 +1000
+++ linux-cell/arch/powerpc/mm/hash_utils_64.c	2007-05-08 15:29:21.000000000 +1000
@@ -420,7 +420,7 @@ static void __init htab_finish_init(void
 	extern unsigned int *htab_call_hpte_remove;
 	extern unsigned int *htab_call_hpte_updatepp;
 
-#ifdef CONFIG_PPC_64K_PAGES
+#ifdef CONFIG_PPC_HAS_HASH_64K
 	extern unsigned int *ht64_call_hpte_insert1;
 	extern unsigned int *ht64_call_hpte_insert2;
 	extern unsigned int *ht64_call_hpte_remove;
@@ -648,7 +648,11 @@ int hash_page(unsigned long ea, unsigned
 			return 1;
 		}
 		vsid = get_vsid(mm->context.id, ea);
+#ifdef CONFIG_PPC_MM_SLICES
+		psize = get_slice_psize(mm, ea);
+#else
 		psize = mm->context.user_psize;
+#endif
 		break;
 	case VMALLOC_REGION_ID:
 		mm = &init_mm;
@@ -678,13 +682,21 @@ int hash_page(unsigned long ea, unsigned
 
 #ifdef CONFIG_HUGETLB_PAGE
 	/* Handle hugepage regions */
-	if (HPAGE_SHIFT &&
-	    unlikely(get_slice_psize(mm, ea) == mmu_huge_psize)) {
+	if (HPAGE_SHIFT && psize == mmu_huge_psize) {
 		DBG_LOW(" -> huge page !\n");
 		return hash_huge_page(mm, access, ea, vsid, local, trap);
 	}
 #endif /* CONFIG_HUGETLB_PAGE */
 
+#ifndef CONFIG_PPC_64K_PAGES
+	/* If we use 4K pages and our psize is not 4K, then we are hitting
+	 * a special driver mapping, we need to align the address before
+	 * we fetch the PTE
+	 */
+	if (psize != MMU_PAGE_4K)
+		ea &= ~((1ul << mmu_psize_defs[psize].shift) - 1);
+#endif /* CONFIG_PPC_64K_PAGES */
+
 	/* Get PTE and page size from page tables */
 	ptep = find_linux_pte(pgdir, ea);
 	if (ptep == NULL || !pte_present(*ptep)) {
@@ -707,9 +719,7 @@ int hash_page(unsigned long ea, unsigned
 	}
 
 	/* Do actual hashing */
-#ifndef CONFIG_PPC_64K_PAGES
-	rc = __hash_page_4K(ea, access, vsid, ptep, trap, local);
-#else
+#ifdef CONFIG_PPC_64K_PAGES
 	/* If _PAGE_4K_PFN is set, make sure this is a 4k segment */
 	if (pte_val(*ptep) & _PAGE_4K_PFN) {
 		demote_segment_4k(mm, ea);
@@ -751,12 +761,14 @@ int hash_page(unsigned long ea, unsigned
 			mmu_psize_defs[mmu_vmalloc_psize].sllp;
 		slb_flush_and_rebolt();
 	}
+#endif /* CONFIG_PPC_64K_PAGES */
 
+#ifdef CONFIG_PPC_HAS_HASH_64K
 	if (psize == MMU_PAGE_64K)
 		rc = __hash_page_64K(ea, access, vsid, ptep, trap, local);
 	else
+#endif /* CONFIG_PPC_HAS_HASH_64K */
 		rc = __hash_page_4K(ea, access, vsid, ptep, trap, local);
-#endif /* CONFIG_PPC_64K_PAGES */
 
 #ifndef CONFIG_PPC_64K_PAGES
 	DBG_LOW(" o-pte: %016lx\n", pte_val(*ptep));
@@ -812,19 +824,22 @@ void hash_preload(struct mm_struct *mm, 
 	/* Get VSID */
 	vsid = get_vsid(mm->context.id, ea);
 
-	/* Hash it in */
+	/* Hash doesn't like irqs */
 	local_irq_save(flags);
+
+	/* Is that local to this CPU ? */
 	mask = cpumask_of_cpu(smp_processor_id());
 	if (cpus_equal(mm->cpu_vm_mask, mask))
 		local = 1;
-#ifndef CONFIG_PPC_64K_PAGES
-	__hash_page_4K(ea, access, vsid, ptep, trap, local);
-#else
+
+	/* Hash it in */
+#ifdef CONFIG_PPC_HAS_HASH_64K
 	if (mm->context.user_psize == MMU_PAGE_64K)
 		__hash_page_64K(ea, access, vsid, ptep, trap, local);
 	else
-		__hash_page_4K(ea, access, vsid, ptep, trap, local);
 #endif /* CONFIG_PPC_64K_PAGES */
+		__hash_page_4K(ea, access, vsid, ptep, trap, local);
+
 	local_irq_restore(flags);
 }
 
Index: linux-cell/arch/powerpc/mm/tlb_64.c
===================================================================
--- linux-cell.orig/arch/powerpc/mm/tlb_64.c	2007-05-08 15:27:03.000000000 +1000
+++ linux-cell/arch/powerpc/mm/tlb_64.c	2007-05-08 15:29:21.000000000 +1000
@@ -143,16 +143,22 @@ void hpte_need_flush(struct mm_struct *m
 	 */
 	addr &= PAGE_MASK;
 
-	/* Get page size (maybe move back to caller) */
+	/* Get page size (maybe move back to caller).
+	 *
+	 * NOTE: when using special 64K mappings in 4K environment like
+	 * for SPEs, we obtain the page size from the slice, which thus
+	 * must still exist (and thus the VMA not reused) at the time
+	 * of this call
+	 */
 	if (huge) {
 #ifdef CONFIG_HUGETLB_PAGE
 		psize = mmu_huge_psize;
 #else
 		BUG();
-		psize = pte_pagesize_index(pte); /* shutup gcc */
+		psize = pte_pagesize_index(mm, addr, pte); /* shutup gcc */
 #endif
 	} else
-		psize = pte_pagesize_index(pte);
+		psize = pte_pagesize_index(mm, addr, pte);
 
 	/* Build full vaddr */
 	if (!is_kernel_addr(addr)) {
Index: linux-cell/include/asm-powerpc/pgtable-4k.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/pgtable-4k.h	2007-05-08 15:27:03.000000000 +1000
+++ linux-cell/include/asm-powerpc/pgtable-4k.h	2007-05-08 15:29:21.000000000 +1000
@@ -78,7 +78,11 @@
 
 #define pte_iterate_hashed_end() } while(0)
 
-#define pte_pagesize_index(pte)	MMU_PAGE_4K
+#ifdef CONFIG_PPC_HAS_HASH_64K
+#define pte_pagesize_index(mm, addr, pte)	get_slice_psize(mm, addr)
+#else
+#define pte_pagesize_index(mm, addr, pte)	MMU_PAGE_4K
+#endif
 
 /*
  * 4-level page tables related bits

^ permalink raw reply

* [PATCH 2/5] powerpc: Introduce address space "slices"
From: Benjamin Herrenschmidt @ 2007-05-08  6:27 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Hugh Dickins, Paul Mackerras
In-Reply-To: <1178605646.637780.625211974455.qpush@grosgo>

The basic issue is to be able to do what hugetlbfs does but with
different page sizes for some other special filesystems, more
specifically, my need is:

 - Huge pages

 - SPE local store mappings using 64K pages on a 4K base page size
kernel on Cell

 - Some special 4K segments in 64K pages kernels for mapping a dodgy
specie of powerpc specific infiniband hardware that requires 4K MMU
mappings for various reasons I won't explain here.

The main issues are:

 - To maintain/keep track of the page size per "segments" (as we can
only have one page size per segment on powerpc, which are 256MB
divisions of the address space).

 - To make sure special mappings stay within their alloted
"segments" (including MAP_FIXED crap)

 - To make sure everybody else doesn't mmap/brk/grow_stack into a
"segment" that is used for a special mapping

Some of the necessary mecanisms to handle that were present in the
hugetlbfs code, but mostly in ways not suitable for anything else.

The patch relies on some changes to the generic get_unmapped_area()
that just got merged. It still hijacks hugetlb callbacks here or
there as the generic code hasn't been entirely cleaned up yet but
that shouldn't be a problem. 

So what is a slice ? Well, I re-used the mecanism used formerly by our
hugetlbfs implementation which divides the address space in
"meta-segments" which I called "slices". The division is done using
256MB slices below 4G, and 1T slices above. Thus the address space is
divided currently into 16 "low" slices and 16 "high" slices. (Special
case: high slice 0 is the area between 4G and 1T).

Doing so simplifies significantly the tracking of segments and avoid
having to keep track of all the 256MB segments in the address space.

While I used the "concepts" of hugetlbfs, I mostly re-implemented
everything in a more generic way and "ported" hugetlbfs to it. 

slices can have an associated page size, which is encoded in the mmu
context and used by the SLB miss handler to set the segment sizes. The
hash code currently doesn't care, it has a specific check for hugepages,
though I might add a mecanism to provide per-slice hash mapping
functions in the future.

The slice code provide a pair of "generic" get_unmapped_area() (bottomup
and topdown) functions that should work with any slice size. There is
some trickyness here so I would appreciate people to have a look at the
implementation of these and let me know if I got something wrong.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

 arch/powerpc/Kconfig                   |    5 
 arch/powerpc/kernel/asm-offsets.c      |   16 
 arch/powerpc/mm/Makefile               |    1 
 arch/powerpc/mm/hash_utils_64.c        |   20 -
 arch/powerpc/mm/hugetlbpage.c          |  548 ----------------------------
 arch/powerpc/mm/mmu_context_64.c       |   10 
 arch/powerpc/mm/slb.c                  |   11 
 arch/powerpc/mm/slb_low.S              |   54 +-
 arch/powerpc/mm/slice.c                |  633 +++++++++++++++++++++++++++++++++
 arch/powerpc/platforms/cell/spu_base.c |    9 
 include/asm-powerpc/mmu-hash64.h       |   11 
 include/asm-powerpc/paca.h             |    2 
 include/asm-powerpc/page_64.h          |   88 ++--
 13 files changed, 771 insertions(+), 637 deletions(-)

Index: linux-cell/arch/powerpc/Kconfig
===================================================================
--- linux-cell.orig/arch/powerpc/Kconfig	2007-05-08 15:27:05.000000000 +1000
+++ linux-cell/arch/powerpc/Kconfig	2007-05-08 15:27:52.000000000 +1000
@@ -338,6 +338,11 @@ config PPC_STD_MMU_32
 	def_bool y
 	depends on PPC_STD_MMU && PPC32
 
+config PPC_MM_SLICES
+	bool
+	default y if HUGETLB_PAGE
+	default n
+
 config VIRT_CPU_ACCOUNTING
 	bool "Deterministic task and CPU time accounting"
 	depends on PPC64
Index: linux-cell/include/asm-powerpc/paca.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/paca.h	2007-05-08 15:27:05.000000000 +1000
+++ linux-cell/include/asm-powerpc/paca.h	2007-05-08 15:27:52.000000000 +1000
@@ -83,8 +83,8 @@ struct paca_struct {
 
 	mm_context_t context;
 	u16 vmalloc_sllp;
-	u16 slb_cache[SLB_CACHE_ENTRIES];
 	u16 slb_cache_ptr;
+	u16 slb_cache[SLB_CACHE_ENTRIES];
 
 	/*
 	 * then miscellaneous read-write fields
Index: linux-cell/include/asm-powerpc/page_64.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/page_64.h	2007-05-08 15:27:05.000000000 +1000
+++ linux-cell/include/asm-powerpc/page_64.h	2007-05-08 15:27:52.000000000 +1000
@@ -88,57 +88,55 @@ extern unsigned int HPAGE_SHIFT;
 
 #endif /* __ASSEMBLY__ */
 
-#ifdef CONFIG_HUGETLB_PAGE
+#ifdef CONFIG_PPC_MM_SLICES
 
-#define HTLB_AREA_SHIFT		40
-#define HTLB_AREA_SIZE		(1UL << HTLB_AREA_SHIFT)
-#define GET_HTLB_AREA(x)	((x) >> HTLB_AREA_SHIFT)
-
-#define LOW_ESID_MASK(addr, len)    \
-	(((1U << (GET_ESID(min((addr)+(len)-1, 0x100000000UL))+1)) \
-	  - (1U << GET_ESID(min((addr), 0x100000000UL)))) & 0xffff)
-#define HTLB_AREA_MASK(addr, len)   (((1U << (GET_HTLB_AREA(addr+len-1)+1)) \
-		                      - (1U << GET_HTLB_AREA(addr))) & 0xffff)
+#define SLICE_LOW_SHIFT		28
+#define SLICE_HIGH_SHIFT	40
 
-#define ARCH_HAS_HUGEPAGE_ONLY_RANGE
-#define ARCH_HAS_HUGETLB_FREE_PGD_RANGE
-#define ARCH_HAS_PREPARE_HUGEPAGE_RANGE
-#define ARCH_HAS_SETCLEAR_HUGE_PTE
+#define SLICE_LOW_TOP		(0x100000000ul)
+#define SLICE_NUM_LOW		(SLICE_LOW_TOP >> SLICE_LOW_SHIFT)
+#define SLICE_NUM_HIGH		(PGTABLE_RANGE >> SLICE_HIGH_SHIFT)
 
-#define touches_hugepage_low_range(mm, addr, len) \
-	(((addr) < 0x100000000UL) \
-	 && (LOW_ESID_MASK((addr), (len)) & (mm)->context.low_htlb_areas))
-#define touches_hugepage_high_range(mm, addr, len) \
-	((((addr) + (len)) > 0x100000000UL) \
-	  && (HTLB_AREA_MASK((addr), (len)) & (mm)->context.high_htlb_areas))
-
-#define __within_hugepage_low_range(addr, len, segmask) \
-	( (((addr)+(len)) <= 0x100000000UL) \
-	  && ((LOW_ESID_MASK((addr), (len)) | (segmask)) == (segmask)))
-#define within_hugepage_low_range(addr, len) \
-	__within_hugepage_low_range((addr), (len), \
-				    current->mm->context.low_htlb_areas)
-#define __within_hugepage_high_range(addr, len, zonemask) \
-	( ((addr) >= 0x100000000UL) \
-	  && ((HTLB_AREA_MASK((addr), (len)) | (zonemask)) == (zonemask)))
-#define within_hugepage_high_range(addr, len) \
-	__within_hugepage_high_range((addr), (len), \
-				    current->mm->context.high_htlb_areas)
-
-#define is_hugepage_only_range(mm, addr, len) \
-	(touches_hugepage_high_range((mm), (addr), (len)) || \
-	  touches_hugepage_low_range((mm), (addr), (len)))
-#define HAVE_ARCH_HUGETLB_UNMAPPED_AREA
+#define GET_LOW_SLICE_INDEX(addr)	((addr) >> SLICE_LOW_SHIFT)
+#define GET_HIGH_SLICE_INDEX(addr)	((addr) >> SLICE_HIGH_SHIFT)
 
-#define in_hugepage_area(context, addr) \
-	(cpu_has_feature(CPU_FTR_16M_PAGE) && \
-	 ( ( (addr) >= 0x100000000UL) \
-	   ? ((1 << GET_HTLB_AREA(addr)) & (context).high_htlb_areas) \
-	   : ((1 << GET_ESID(addr)) & (context).low_htlb_areas) ) )
+#ifndef __ASSEMBLY__
 
-#else /* !CONFIG_HUGETLB_PAGE */
+struct slice_mask {
+	u16 low_slices;
+	u16 high_slices;
+};
 
-#define in_hugepage_area(mm, addr)	0
+struct mm_struct;
+
+extern unsigned long slice_get_unmapped_area(unsigned long addr,
+					     unsigned long len,
+					     unsigned long flags,
+					     unsigned int psize,
+					     int topdown,
+					     int use_cache);
+
+extern unsigned int get_slice_psize(struct mm_struct *mm,
+				    unsigned long addr);
+
+extern void slice_init_context(struct mm_struct *mm, unsigned int psize);
+extern void slice_set_user_psize(struct mm_struct *mm, unsigned int psize);
+
+#define ARCH_HAS_HUGEPAGE_ONLY_RANGE
+extern int is_hugepage_only_range(struct mm_struct *m,
+				  unsigned long addr,
+				  unsigned long len);
+
+#endif /* __ASSEMBLY__ */
+#else
+#define slice_init()
+#endif /* CONFIG_PPC_MM_SLICES */
+
+#ifdef CONFIG_HUGETLB_PAGE
+
+#define ARCH_HAS_HUGETLB_FREE_PGD_RANGE
+#define ARCH_HAS_SETCLEAR_HUGE_PTE
+#define HAVE_ARCH_HUGETLB_UNMAPPED_AREA
 
 #endif /* !CONFIG_HUGETLB_PAGE */
 
Index: linux-cell/arch/powerpc/mm/Makefile
===================================================================
--- linux-cell.orig/arch/powerpc/mm/Makefile	2007-05-08 15:27:05.000000000 +1000
+++ linux-cell/arch/powerpc/mm/Makefile	2007-05-08 15:27:52.000000000 +1000
@@ -18,4 +18,5 @@ obj-$(CONFIG_40x)		+= 4xx_mmu.o
 obj-$(CONFIG_44x)		+= 44x_mmu.o
 obj-$(CONFIG_FSL_BOOKE)		+= fsl_booke_mmu.o
 obj-$(CONFIG_NEED_MULTIPLE_NODES) += numa.o
+obj-$(CONFIG_PPC_MM_SLICES)	+= slice.o
 obj-$(CONFIG_HUGETLB_PAGE)	+= hugetlbpage.o
Index: linux-cell/arch/powerpc/mm/slice.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-cell/arch/powerpc/mm/slice.c	2007-05-08 15:27:52.000000000 +1000
@@ -0,0 +1,633 @@
+/*
+ * address space "slices" (meta-segments) support
+ *
+ * Copyright (C) 2007 Benjamin Herrenschmidt, IBM Corporation.
+ *
+ * Based on hugetlb implementation
+ *
+ * Copyright (C) 2003 David Gibson, IBM Corporation.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#undef DEBUG
+
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/err.h>
+#include <linux/spinlock.h>
+#include <linux/module.h>
+#include <asm/mman.h>
+#include <asm/mmu.h>
+#include <asm/spu.h>
+
+static spinlock_t slice_convert_lock = SPIN_LOCK_UNLOCKED;
+
+
+#ifdef DEBUG
+int _slice_debug = 1;
+
+static void slice_print_mask(const char *label, struct slice_mask mask)
+{
+	char	*p, buf[16 + 3 + 16 + 1];
+	int	i;
+
+	if (!_slice_debug)
+		return;
+	p = buf;
+	for (i = 0; i < SLICE_NUM_LOW; i++)
+		*(p++) = (mask.low_slices & (1 << i)) ? '1' : '0';
+	*(p++) = ' ';
+	*(p++) = '-';
+	*(p++) = ' ';
+	for (i = 0; i < SLICE_NUM_HIGH; i++)
+		*(p++) = (mask.high_slices & (1 << i)) ? '1' : '0';
+	*(p++) = 0;
+
+	printk(KERN_DEBUG "%s:%s\n", label, buf);
+}
+
+#define slice_dbg(fmt...) do { if (_slice_debug) pr_debug(fmt); } while(0)
+
+#else
+
+static void slice_print_mask(const char *label, struct slice_mask mask) {}
+#define slice_dbg(fmt...)
+
+#endif
+
+static struct slice_mask slice_range_to_mask(unsigned long start,
+					     unsigned long len)
+{
+	unsigned long end = start + len - 1;
+	struct slice_mask ret = { 0, 0 };
+
+	if (start < SLICE_LOW_TOP) {
+		unsigned long mend = min(end, SLICE_LOW_TOP);
+		unsigned long mstart = min(start, SLICE_LOW_TOP);
+
+		ret.low_slices = (1u << (GET_LOW_SLICE_INDEX(mend) + 1))
+			- (1u << GET_LOW_SLICE_INDEX(mstart));
+	}
+
+	if ((start + len) > SLICE_LOW_TOP)
+		ret.high_slices = (1u << (GET_HIGH_SLICE_INDEX(end) + 1))
+			- (1u << GET_HIGH_SLICE_INDEX(start));
+
+	return ret;
+}
+
+static int slice_area_is_free(struct mm_struct *mm, unsigned long addr,
+			      unsigned long len)
+{
+	struct vm_area_struct *vma;
+
+	if ((mm->task_size - len) < addr)
+		return 0;
+	vma = find_vma(mm, addr);
+	return (!vma || (addr + len) <= vma->vm_start);
+}
+
+static int slice_low_has_vma(struct mm_struct *mm, unsigned long slice)
+{
+	return !slice_area_is_free(mm, slice << SLICE_LOW_SHIFT,
+				   1ul << SLICE_LOW_SHIFT);
+}
+
+static int slice_high_has_vma(struct mm_struct *mm, unsigned long slice)
+{
+	unsigned long start = slice << SLICE_HIGH_SHIFT;
+	unsigned long end = start + (1ul << SLICE_HIGH_SHIFT);
+
+	/* Hack, so that each addresses is controlled by exactly one
+	 * of the high or low area bitmaps, the first high area starts
+	 * at 4GB, not 0 */
+	if (start == 0)
+		start = SLICE_LOW_TOP;
+
+	return !slice_area_is_free(mm, start, end - start);
+}
+
+static struct slice_mask slice_mask_for_free(struct mm_struct *mm)
+{
+	struct slice_mask ret = { 0, 0 };
+	unsigned long i;
+
+	for (i = 0; i < SLICE_NUM_LOW; i++)
+		if (!slice_low_has_vma(mm, i))
+			ret.low_slices |= 1u << i;
+
+	if (mm->task_size <= SLICE_LOW_TOP)
+		return ret;
+
+	for (i = 0; i < SLICE_NUM_HIGH; i++)
+		if (!slice_high_has_vma(mm, i))
+			ret.high_slices |= 1u << i;
+
+	return ret;
+}
+
+static struct slice_mask slice_mask_for_size(struct mm_struct *mm, int psize)
+{
+	struct slice_mask ret = { 0, 0 };
+	unsigned long i;
+	u64 psizes;
+
+	psizes = mm->context.low_slices_psize;
+	for (i = 0; i < SLICE_NUM_LOW; i++)
+		if (((psizes >> (i * 4)) & 0xf) == psize)
+			ret.low_slices |= 1u << i;
+
+	psizes = mm->context.high_slices_psize;
+	for (i = 0; i < SLICE_NUM_HIGH; i++)
+		if (((psizes >> (i * 4)) & 0xf) == psize)
+			ret.high_slices |= 1u << i;
+
+	return ret;
+}
+
+static int slice_check_fit(struct slice_mask mask, struct slice_mask available)
+{
+	return (mask.low_slices & available.low_slices) == mask.low_slices &&
+		(mask.high_slices & available.high_slices) == mask.high_slices;
+}
+
+static void slice_flush_segments(void *parm)
+{
+	struct mm_struct *mm = parm;
+	unsigned long flags;
+
+	if (mm != current->active_mm)
+		return;
+
+	/* update the paca copy of the context struct */
+	get_paca()->context = current->active_mm->context;
+
+	local_irq_save(flags);
+	slb_flush_and_rebolt();
+	local_irq_restore(flags);
+}
+
+static void slice_convert(struct mm_struct *mm, struct slice_mask mask, int psize)
+{
+	/* Write the new slice psize bits */
+	u64 lpsizes, hpsizes;
+	unsigned long i, flags;
+
+	slice_dbg("slice_convert(mm=%p, psize=%d)\n", mm, psize);
+	slice_print_mask(" mask", mask);
+
+	/* We need to use a spinlock here to protect against
+	 * concurrent 64k -> 4k demotion ...
+	 */
+	spin_lock_irqsave(&slice_convert_lock, flags);
+
+	lpsizes = mm->context.low_slices_psize;
+	for (i = 0; i < SLICE_NUM_LOW; i++)
+		if (mask.low_slices & (1u << i))
+			lpsizes = (lpsizes & ~(0xful << (i * 4))) |
+				(((unsigned long)psize) << (i * 4));
+
+	hpsizes = mm->context.high_slices_psize;
+	for (i = 0; i < SLICE_NUM_HIGH; i++)
+		if (mask.high_slices & (1u << i))
+			hpsizes = (hpsizes & ~(0xful << (i * 4))) |
+				(((unsigned long)psize) << (i * 4));
+
+	mm->context.low_slices_psize = lpsizes;
+	mm->context.high_slices_psize = hpsizes;
+
+	slice_dbg(" lsps=%lx, hsps=%lx\n",
+		  mm->context.low_slices_psize,
+		  mm->context.high_slices_psize);
+
+	spin_unlock_irqrestore(&slice_convert_lock, flags);
+	mb();
+
+	/* XXX this is sub-optimal but will do for now */
+	on_each_cpu(slice_flush_segments, mm, 0, 1);
+#ifdef CONFIG_SPU_BASE
+	spu_flush_all_slbs(mm);
+#endif
+}
+
+static unsigned long slice_find_area_bottomup(struct mm_struct *mm,
+					      unsigned long len,
+					      struct slice_mask available,
+					      int psize, int use_cache)
+{
+	struct vm_area_struct *vma;
+	unsigned long start_addr, addr;
+	struct slice_mask mask;
+	int pshift = max_t(int, mmu_psize_defs[psize].shift, PAGE_SHIFT);
+
+	if (use_cache) {
+		if (len <= mm->cached_hole_size) {
+			start_addr = addr = TASK_UNMAPPED_BASE;
+			mm->cached_hole_size = 0;
+		} else
+			start_addr = addr = mm->free_area_cache;
+	} else
+		start_addr = addr = TASK_UNMAPPED_BASE;
+
+full_search:
+	for (;;) {
+		addr = _ALIGN_UP(addr, 1ul << pshift);
+		if ((TASK_SIZE - len) < addr)
+			break;
+		vma = find_vma(mm, addr);
+		BUG_ON(vma && (addr >= vma->vm_end));
+
+		mask = slice_range_to_mask(addr, len);
+		if (!slice_check_fit(mask, available)) {
+			if (addr < SLICE_LOW_TOP)
+				addr = _ALIGN_UP(addr + 1,  1ul << SLICE_LOW_SHIFT);
+			else
+				addr = _ALIGN_UP(addr + 1,  1ul << SLICE_HIGH_SHIFT);
+			continue;
+		}
+		if (!vma || addr + len <= vma->vm_start) {
+			/*
+			 * Remember the place where we stopped the search:
+			 */
+			if (use_cache)
+				mm->free_area_cache = addr + len;
+			return addr;
+		}
+		if (use_cache && (addr + mm->cached_hole_size) < vma->vm_start)
+		        mm->cached_hole_size = vma->vm_start - addr;
+		addr = vma->vm_end;
+	}
+
+	/* Make sure we didn't miss any holes */
+	if (use_cache && start_addr != TASK_UNMAPPED_BASE) {
+		start_addr = addr = TASK_UNMAPPED_BASE;
+		mm->cached_hole_size = 0;
+		goto full_search;
+	}
+	return -ENOMEM;
+}
+
+static unsigned long slice_find_area_topdown(struct mm_struct *mm,
+					     unsigned long len,
+					     struct slice_mask available,
+					     int psize, int use_cache)
+{
+	struct vm_area_struct *vma;
+	unsigned long addr;
+	struct slice_mask mask;
+	int pshift = max_t(int, mmu_psize_defs[psize].shift, PAGE_SHIFT);
+
+	/* check if free_area_cache is useful for us */
+	if (use_cache) {
+		if (len <= mm->cached_hole_size) {
+			mm->cached_hole_size = 0;
+			mm->free_area_cache = mm->mmap_base;
+		}
+
+		/* either no address requested or can't fit in requested
+		 * address hole
+		 */
+		addr = mm->free_area_cache;
+
+		/* make sure it can fit in the remaining address space */
+		if (addr > len) {
+			addr = _ALIGN_DOWN(addr - len, 1ul << pshift);
+			mask = slice_range_to_mask(addr, len);
+			if (slice_check_fit(mask, available) &&
+			    slice_area_is_free(mm, addr, len))
+					/* remember the address as a hint for
+					 * next time
+					 */
+					return (mm->free_area_cache = addr);
+		}
+	}
+
+	addr = mm->mmap_base;
+	while (addr > len) {
+		/* Go down by chunk size */
+		addr = _ALIGN_DOWN(addr - len, 1ul << pshift);
+
+		/* Check for hit with different page size */
+		mask = slice_range_to_mask(addr, len);
+		if (!slice_check_fit(mask, available)) {
+			if (addr < SLICE_LOW_TOP)
+				addr = _ALIGN_DOWN(addr, 1ul << SLICE_LOW_SHIFT);
+			else if (addr < (1ul << SLICE_HIGH_SHIFT))
+				addr = SLICE_LOW_TOP;
+			else
+				addr = _ALIGN_DOWN(addr, 1ul << SLICE_HIGH_SHIFT);
+			continue;
+		}
+
+		/*
+		 * Lookup failure means no vma is above this address,
+		 * else if new region fits below vma->vm_start,
+		 * return with success:
+		 */
+		vma = find_vma(mm, addr);
+		if (!vma || (addr + len) <= vma->vm_start) {
+			/* remember the address as a hint for next time */
+			if (use_cache)
+				mm->free_area_cache = addr;
+			return addr;
+		}
+
+ 		/* remember the largest hole we saw so far */
+ 		if (use_cache && (addr + mm->cached_hole_size) < vma->vm_start)
+ 		        mm->cached_hole_size = vma->vm_start - addr;
+
+		/* try just below the current vma->vm_start */
+		addr = vma->vm_start;
+	}
+
+	/*
+	 * A failed mmap() very likely causes application failure,
+	 * so fall back to the bottom-up function here. This scenario
+	 * can happen with large stack limits and large mmap()
+	 * allocations.
+	 */
+	addr = slice_find_area_bottomup(mm, len, available, psize, 0);
+
+	/*
+	 * Restore the topdown base:
+	 */
+	if (use_cache) {
+		mm->free_area_cache = mm->mmap_base;
+		mm->cached_hole_size = ~0UL;
+	}
+
+	return addr;
+}
+
+
+static unsigned long slice_find_area(struct mm_struct *mm, unsigned long len,
+				     struct slice_mask mask, int psize,
+				     int topdown, int use_cache)
+{
+	if (topdown)
+		return slice_find_area_topdown(mm, len, mask, psize, use_cache);
+	else
+		return slice_find_area_bottomup(mm, len, mask, psize, use_cache);
+}
+
+unsigned long slice_get_unmapped_area(unsigned long addr, unsigned long len,
+				      unsigned long flags, unsigned int psize,
+				      int topdown, int use_cache)
+{
+	struct slice_mask mask;
+	struct slice_mask good_mask;
+	struct slice_mask potential_mask = {0,0} /* silence stupid warning */;
+	int pmask_set = 0;
+	int fixed = (flags & MAP_FIXED);
+	int pshift = max_t(int, mmu_psize_defs[psize].shift, PAGE_SHIFT);
+	struct mm_struct *mm = current->mm;
+
+	/* Sanity checks */
+	BUG_ON(mm->task_size == 0);
+
+	slice_dbg("slice_get_unmapped_area(mm=%p, psize=%d...\n", mm, psize);
+	slice_dbg(" addr=%lx, len=%lx, flags=%lx, topdown=%d, use_cache=%d\n",
+		  addr, len, flags, topdown, use_cache);
+
+	if (len > mm->task_size)
+		return -ENOMEM;
+	if (fixed && (addr & ((1ul << pshift) - 1)))
+		return -EINVAL;
+	if (fixed && addr > (mm->task_size - len))
+		return -EINVAL;
+
+	/* If hint, make sure it matches our alignment restrictions */
+	if (!fixed && addr) {
+		addr = _ALIGN_UP(addr, 1ul << pshift);
+		slice_dbg(" aligned addr=%lx\n", addr);
+	}
+
+	/* First makeup a "good" mask of slices that have the right size
+	 * already
+	 */
+	good_mask = slice_mask_for_size(mm, psize);
+	slice_print_mask(" good_mask", good_mask);
+
+	/* First check hint if it's valid or if we have MAP_FIXED */
+	if ((addr != 0 || fixed) && (mm->task_size - len) >= addr) {
+
+		/* Don't bother with hint if it overlaps a VMA */
+		if (!fixed && !slice_area_is_free(mm, addr, len))
+			goto search;
+
+		/* Build a mask for the requested range */
+		mask = slice_range_to_mask(addr, len);
+		slice_print_mask(" mask", mask);
+
+		/* Check if we fit in the good mask. If we do, we just return,
+		 * nothing else to do
+		 */
+		if (slice_check_fit(mask, good_mask)) {
+			slice_dbg(" fits good !\n");
+			return addr;
+		}
+
+		/* We don't fit in the good mask, check what other slices are
+		 * empty and thus can be converted
+		 */
+		potential_mask = slice_mask_for_free(mm);
+		potential_mask.low_slices |= good_mask.low_slices;
+		potential_mask.high_slices |= good_mask.high_slices;
+		pmask_set = 1;
+		slice_print_mask(" potential", potential_mask);
+		if (slice_check_fit(mask, potential_mask)) {
+			slice_dbg(" fits potential !\n");
+			goto convert;
+		}
+	}
+
+	/* If we have MAP_FIXED and failed the above step, then error out */
+	if (fixed)
+		return -EBUSY;
+
+ search:
+	slice_dbg(" search...\n");
+
+	/* Now let's see if we can find something in the existing slices
+	 * for that size
+	 */
+	addr = slice_find_area(mm, len, good_mask, psize, topdown, use_cache);
+	if (addr != -ENOMEM) {
+		/* Found within the good mask, we don't have to setup,
+		 * we thus return directly
+		 */
+		slice_dbg(" found area at 0x%lx\n", addr);
+		return addr;
+	}
+
+	/* Won't fit, check what can be converted */
+	if (!pmask_set) {
+		potential_mask = slice_mask_for_free(mm);
+		potential_mask.low_slices |= good_mask.low_slices;
+		potential_mask.high_slices |= good_mask.high_slices;
+		pmask_set = 1;
+		slice_print_mask(" potential", potential_mask);
+	}
+
+	/* Now let's see if we can find something in the existing slices
+	 * for that size
+	 */
+	addr = slice_find_area(mm, len, potential_mask, psize, topdown,
+			       use_cache);
+	if (addr == -ENOMEM)
+		return -ENOMEM;
+
+	mask = slice_range_to_mask(addr, len);
+	slice_dbg(" found potential area at 0x%lx\n", addr);
+	slice_print_mask(" mask", mask);
+
+ convert:
+	slice_convert(mm, mask, psize);
+	return addr;
+
+}
+EXPORT_SYMBOL_GPL(slice_get_unmapped_area);
+
+unsigned long arch_get_unmapped_area(struct file *filp,
+				     unsigned long addr,
+				     unsigned long len,
+				     unsigned long pgoff,
+				     unsigned long flags)
+{
+	return slice_get_unmapped_area(addr, len, flags,
+				       current->mm->context.user_psize,
+				       0, 1);
+}
+
+unsigned long arch_get_unmapped_area_topdown(struct file *filp,
+					     const unsigned long addr0,
+					     const unsigned long len,
+					     const unsigned long pgoff,
+					     const unsigned long flags)
+{
+	return slice_get_unmapped_area(addr0, len, flags,
+				       current->mm->context.user_psize,
+				       1, 1);
+}
+
+unsigned int get_slice_psize(struct mm_struct *mm, unsigned long addr)
+{
+	u64 psizes;
+	int index;
+
+	if (addr < SLICE_LOW_TOP) {
+		psizes = mm->context.low_slices_psize;
+		index = GET_LOW_SLICE_INDEX(addr);
+	} else {
+		psizes = mm->context.high_slices_psize;
+		index = GET_HIGH_SLICE_INDEX(addr);
+	}
+
+	return (psizes >> (index * 4)) & 0xf;
+}
+EXPORT_SYMBOL_GPL(get_slice_psize);
+
+/*
+ * This is called by hash_page when it needs to do a lazy conversion of
+ * an address space from real 64K pages to combo 4K pages (typically
+ * when hitting a non cacheable mapping on a processor or hypervisor
+ * that won't allow them for 64K pages).
+ *
+ * This is also called in init_new_context() to change back the user
+ * psize from whatever the parent context had it set to
+ *
+ * This function will only change the content of the {low,high)_slice_psize
+ * masks, it will not flush SLBs as this shall be handled lazily by the
+ * caller.
+ */
+void slice_set_user_psize(struct mm_struct *mm, unsigned int psize)
+{
+	unsigned long flags, lpsizes, hpsizes;
+	unsigned int old_psize;
+	int i;
+
+	slice_dbg("slice_set_user_psize(mm=%p, psize=%d)\n", mm, psize);
+
+	spin_lock_irqsave(&slice_convert_lock, flags);
+
+	old_psize = mm->context.user_psize;
+	slice_dbg(" old_psize=%d\n", old_psize);
+	if (old_psize == psize)
+		goto bail;
+
+	mm->context.user_psize = psize;
+	wmb();
+
+	lpsizes = mm->context.low_slices_psize;
+	for (i = 0; i < SLICE_NUM_LOW; i++)
+		if (((lpsizes >> (i * 4)) & 0xf) == old_psize)
+			lpsizes = (lpsizes & ~(0xful << (i * 4))) |
+				(((unsigned long)psize) << (i * 4));
+
+	hpsizes = mm->context.high_slices_psize;
+	for (i = 0; i < SLICE_NUM_HIGH; i++)
+		if (((hpsizes >> (i * 4)) & 0xf) == old_psize)
+			hpsizes = (hpsizes & ~(0xful << (i * 4))) |
+				(((unsigned long)psize) << (i * 4));
+
+	mm->context.low_slices_psize = lpsizes;
+	mm->context.high_slices_psize = hpsizes;
+
+	slice_dbg(" lsps=%lx, hsps=%lx\n",
+		  mm->context.low_slices_psize,
+		  mm->context.high_slices_psize);
+
+ bail:
+	spin_unlock_irqrestore(&slice_convert_lock, flags);
+}
+
+/*
+ * is_hugepage_only_range() is used by generic code to verify wether
+ * a normal mmap mapping (non hugetlbfs) is valid on a given area.
+ *
+ * until the generic code provides a more generic hook and/or starts
+ * calling arch get_unmapped_area for MAP_FIXED (which our implementation
+ * here knows how to deal with), we hijack it to keep standard mappings
+ * away from us.
+ *
+ * because of that generic code limitation, MAP_FIXED mapping cannot
+ * "convert" back a slice with no VMAs to the standard page size, only
+ * get_unmapped_area() can. It would be possible to fix it here but I
+ * prefer working on fixing the generic code instead.
+ *
+ * WARNING: This will not work if hugetlbfs isn't enabled since the
+ * generic code will redefine that function as 0 in that. This is ok
+ * for now as we only use slices with hugetlbfs enabled. This should
+ * be fixed as the generic code gets fixed.
+ */
+int is_hugepage_only_range(struct mm_struct *mm, unsigned long addr,
+			   unsigned long len)
+{
+	struct slice_mask mask, available;
+
+	mask = slice_range_to_mask(addr, len);
+	available = slice_mask_for_size(mm, mm->context.user_psize);
+
+#if 0 /* too verbose */
+	slice_dbg("is_hugepage_only_range(mm=%p, addr=%lx, len=%lx)\n",
+		 mm, addr, len);
+	slice_print_mask(" mask", mask);
+	slice_print_mask(" available", available);
+#endif
+	return !slice_check_fit(mask, available);
+}
+
Index: linux-cell/arch/powerpc/kernel/asm-offsets.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/asm-offsets.c	2007-05-08 15:27:05.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/asm-offsets.c	2007-05-08 15:27:52.000000000 +1000
@@ -122,12 +122,18 @@ int main(void)
 	DEFINE(PACASLBCACHE, offsetof(struct paca_struct, slb_cache));
 	DEFINE(PACASLBCACHEPTR, offsetof(struct paca_struct, slb_cache_ptr));
 	DEFINE(PACACONTEXTID, offsetof(struct paca_struct, context.id));
-	DEFINE(PACACONTEXTSLLP, offsetof(struct paca_struct, context.sllp));
 	DEFINE(PACAVMALLOCSLLP, offsetof(struct paca_struct, vmalloc_sllp));
-#ifdef CONFIG_HUGETLB_PAGE
-	DEFINE(PACALOWHTLBAREAS, offsetof(struct paca_struct, context.low_htlb_areas));
-	DEFINE(PACAHIGHHTLBAREAS, offsetof(struct paca_struct, context.high_htlb_areas));
-#endif /* CONFIG_HUGETLB_PAGE */
+#ifdef CONFIG_PPC_MM_SLICES
+	DEFINE(PACALOWSLICESPSIZE, offsetof(struct paca_struct,
+					    context.low_slices_psize));
+	DEFINE(PACAHIGHSLICEPSIZE, offsetof(struct paca_struct,
+					    context.high_slices_psize));
+	DEFINE(MMUPSIZEDEFSIZE, sizeof(struct mmu_psize_def));
+	DEFINE(MMUPSIZESLLP, offsetof(struct mmu_psize_def, sllp));
+#else
+	DEFINE(PACACONTEXTSLLP, offsetof(struct paca_struct, context.sllp));
+
+#endif /* CONFIG_PPC_MM_SLICES */
 	DEFINE(PACA_EXGEN, offsetof(struct paca_struct, exgen));
 	DEFINE(PACA_EXMC, offsetof(struct paca_struct, exmc));
 	DEFINE(PACA_EXSLB, offsetof(struct paca_struct, exslb));
Index: linux-cell/arch/powerpc/mm/hugetlbpage.c
===================================================================
--- linux-cell.orig/arch/powerpc/mm/hugetlbpage.c	2007-05-08 15:27:05.000000000 +1000
+++ linux-cell/arch/powerpc/mm/hugetlbpage.c	2007-05-08 15:27:52.000000000 +1000
@@ -92,7 +92,7 @@ pte_t *huge_pte_offset(struct mm_struct 
 	pgd_t *pg;
 	pud_t *pu;
 
-	BUG_ON(! in_hugepage_area(mm->context, addr));
+	BUG_ON(get_slice_psize(mm, addr) != mmu_huge_psize);
 
 	addr &= HPAGE_MASK;
 
@@ -120,7 +120,7 @@ pte_t *huge_pte_alloc(struct mm_struct *
 	pud_t *pu;
 	hugepd_t *hpdp = NULL;
 
-	BUG_ON(! in_hugepage_area(mm->context, addr));
+	BUG_ON(get_slice_psize(mm, addr) != mmu_huge_psize);
 
 	addr &= HPAGE_MASK;
 
@@ -303,7 +303,7 @@ void hugetlb_free_pgd_range(struct mmu_g
 	start = addr;
 	pgd = pgd_offset((*tlb)->mm, addr);
 	do {
-		BUG_ON(! in_hugepage_area((*tlb)->mm->context, addr));
+		BUG_ON(get_slice_psize((*tlb)->mm, addr) != mmu_huge_psize);
 		next = pgd_addr_end(addr, end);
 		if (pgd_none_or_clear_bad(pgd))
 			continue;
@@ -332,203 +332,13 @@ pte_t huge_ptep_get_and_clear(struct mm_
 	return __pte(old);
 }
 
-struct slb_flush_info {
-	struct mm_struct *mm;
-	u16 newareas;
-};
-
-static void flush_low_segments(void *parm)
-{
-	struct slb_flush_info *fi = parm;
-	unsigned long i;
-
-	BUILD_BUG_ON((sizeof(fi->newareas)*8) != NUM_LOW_AREAS);
-
-	if (current->active_mm != fi->mm)
-		return;
-
-	/* Only need to do anything if this CPU is working in the same
-	 * mm as the one which has changed */
-
-	/* update the paca copy of the context struct */
-	get_paca()->context = current->active_mm->context;
-
-	asm volatile("isync" : : : "memory");
-	for (i = 0; i < NUM_LOW_AREAS; i++) {
-		if (! (fi->newareas & (1U << i)))
-			continue;
-		asm volatile("slbie %0"
-			     : : "r" ((i << SID_SHIFT) | SLBIE_C));
-	}
-	asm volatile("isync" : : : "memory");
-}
-
-static void flush_high_segments(void *parm)
-{
-	struct slb_flush_info *fi = parm;
-	unsigned long i, j;
-
-
-	BUILD_BUG_ON((sizeof(fi->newareas)*8) != NUM_HIGH_AREAS);
-
-	if (current->active_mm != fi->mm)
-		return;
-
-	/* Only need to do anything if this CPU is working in the same
-	 * mm as the one which has changed */
-
-	/* update the paca copy of the context struct */
-	get_paca()->context = current->active_mm->context;
-
-	asm volatile("isync" : : : "memory");
-	for (i = 0; i < NUM_HIGH_AREAS; i++) {
-		if (! (fi->newareas & (1U << i)))
-			continue;
-		for (j = 0; j < (1UL << (HTLB_AREA_SHIFT-SID_SHIFT)); j++)
-			asm volatile("slbie %0"
-				     :: "r" (((i << HTLB_AREA_SHIFT)
-					      + (j << SID_SHIFT)) | SLBIE_C));
-	}
-	asm volatile("isync" : : : "memory");
-}
-
-static int prepare_low_area_for_htlb(struct mm_struct *mm, unsigned long area)
-{
-	unsigned long start = area << SID_SHIFT;
-	unsigned long end = (area+1) << SID_SHIFT;
-	struct vm_area_struct *vma;
-
-	BUG_ON(area >= NUM_LOW_AREAS);
-
-	/* Check no VMAs are in the region */
-	vma = find_vma(mm, start);
-	if (vma && (vma->vm_start < end))
-		return -EBUSY;
-
-	return 0;
-}
-
-static int prepare_high_area_for_htlb(struct mm_struct *mm, unsigned long area)
-{
-	unsigned long start = area << HTLB_AREA_SHIFT;
-	unsigned long end = (area+1) << HTLB_AREA_SHIFT;
-	struct vm_area_struct *vma;
-
-	BUG_ON(area >= NUM_HIGH_AREAS);
-
-	/* Hack, so that each addresses is controlled by exactly one
-	 * of the high or low area bitmaps, the first high area starts
-	 * at 4GB, not 0 */
-	if (start == 0)
-		start = 0x100000000UL;
-
-	/* Check no VMAs are in the region */
-	vma = find_vma(mm, start);
-	if (vma && (vma->vm_start < end))
-		return -EBUSY;
-
-	return 0;
-}
-
-static int open_low_hpage_areas(struct mm_struct *mm, u16 newareas)
-{
-	unsigned long i;
-	struct slb_flush_info fi;
-
-	BUILD_BUG_ON((sizeof(newareas)*8) != NUM_LOW_AREAS);
-	BUILD_BUG_ON((sizeof(mm->context.low_htlb_areas)*8) != NUM_LOW_AREAS);
-
-	newareas &= ~(mm->context.low_htlb_areas);
-	if (! newareas)
-		return 0; /* The segments we want are already open */
-
-	for (i = 0; i < NUM_LOW_AREAS; i++)
-		if ((1 << i) & newareas)
-			if (prepare_low_area_for_htlb(mm, i) != 0)
-				return -EBUSY;
-
-	mm->context.low_htlb_areas |= newareas;
-
-	/* the context change must make it to memory before the flush,
-	 * so that further SLB misses do the right thing. */
-	mb();
-
-	fi.mm = mm;
-	fi.newareas = newareas;
-	on_each_cpu(flush_low_segments, &fi, 0, 1);
-
-	return 0;
-}
-
-static int open_high_hpage_areas(struct mm_struct *mm, u16 newareas)
-{
-	struct slb_flush_info fi;
-	unsigned long i;
-
-	BUILD_BUG_ON((sizeof(newareas)*8) != NUM_HIGH_AREAS);
-	BUILD_BUG_ON((sizeof(mm->context.high_htlb_areas)*8)
-		     != NUM_HIGH_AREAS);
-
-	newareas &= ~(mm->context.high_htlb_areas);
-	if (! newareas)
-		return 0; /* The areas we want are already open */
-
-	for (i = 0; i < NUM_HIGH_AREAS; i++)
-		if ((1 << i) & newareas)
-			if (prepare_high_area_for_htlb(mm, i) != 0)
-				return -EBUSY;
-
-	mm->context.high_htlb_areas |= newareas;
-
-	/* the context change must make it to memory before the flush,
-	 * so that further SLB misses do the right thing. */
-	mb();
-
-	fi.mm = mm;
-	fi.newareas = newareas;
-	on_each_cpu(flush_high_segments, &fi, 0, 1);
-
-	return 0;
-}
-
-int prepare_hugepage_range(unsigned long addr, unsigned long len, pgoff_t pgoff)
-{
-	int err = 0;
-
-	if (pgoff & (~HPAGE_MASK >> PAGE_SHIFT))
-		return -EINVAL;
-	if (len & ~HPAGE_MASK)
-		return -EINVAL;
-	if (addr & ~HPAGE_MASK)
-		return -EINVAL;
-
-	if (addr < 0x100000000UL)
-		err = open_low_hpage_areas(current->mm,
-					  LOW_ESID_MASK(addr, len));
-	if ((addr + len) > 0x100000000UL)
-		err = open_high_hpage_areas(current->mm,
-					    HTLB_AREA_MASK(addr, len));
-#ifdef CONFIG_SPE_BASE
-	spu_flush_all_slbs(current->mm);
-#endif
-	if (err) {
-		printk(KERN_DEBUG "prepare_hugepage_range(%lx, %lx)"
-		       " failed (lowmask: 0x%04hx, highmask: 0x%04hx)\n",
-		       addr, len,
-		       LOW_ESID_MASK(addr, len), HTLB_AREA_MASK(addr, len));
-		return err;
-	}
-
-	return 0;
-}
-
 struct page *
 follow_huge_addr(struct mm_struct *mm, unsigned long address, int write)
 {
 	pte_t *ptep;
 	struct page *page;
 
-	if (! in_hugepage_area(mm->context, address))
+	if (get_slice_psize(mm, address) != mmu_huge_psize)
 		return ERR_PTR(-EINVAL);
 
 	ptep = huge_pte_offset(mm, address);
@@ -552,359 +362,13 @@ follow_huge_pmd(struct mm_struct *mm, un
 	return NULL;
 }
 
-/* Because we have an exclusive hugepage region which lies within the
- * normal user address space, we have to take special measures to make
- * non-huge mmap()s evade the hugepage reserved regions. */
-unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
-				     unsigned long len, unsigned long pgoff,
-				     unsigned long flags)
-{
-	struct mm_struct *mm = current->mm;
-	struct vm_area_struct *vma;
-	unsigned long start_addr;
-
-	if (len > TASK_SIZE)
-		return -ENOMEM;
-
-	/* handle fixed mapping: prevent overlap with huge pages */
-	if (flags & MAP_FIXED) {
-		if (is_hugepage_only_range(mm, addr, len))
-			return -EINVAL;
-		return addr;
-	}
-
-	if (addr) {
-		addr = PAGE_ALIGN(addr);
-		vma = find_vma(mm, addr);
-		if (((TASK_SIZE - len) >= addr)
-		    && (!vma || (addr+len) <= vma->vm_start)
-		    && !is_hugepage_only_range(mm, addr,len))
-			return addr;
-	}
-	if (len > mm->cached_hole_size) {
-	        start_addr = addr = mm->free_area_cache;
-	} else {
-	        start_addr = addr = TASK_UNMAPPED_BASE;
-	        mm->cached_hole_size = 0;
-	}
-
-full_search:
-	vma = find_vma(mm, addr);
-	while (TASK_SIZE - len >= addr) {
-		BUG_ON(vma && (addr >= vma->vm_end));
-
-		if (touches_hugepage_low_range(mm, addr, len)) {
-			addr = ALIGN(addr+1, 1<<SID_SHIFT);
-			vma = find_vma(mm, addr);
-			continue;
-		}
-		if (touches_hugepage_high_range(mm, addr, len)) {
-			addr = ALIGN(addr+1, 1UL<<HTLB_AREA_SHIFT);
-			vma = find_vma(mm, addr);
-			continue;
-		}
-		if (!vma || addr + len <= vma->vm_start) {
-			/*
-			 * Remember the place where we stopped the search:
-			 */
-			mm->free_area_cache = addr + len;
-			return addr;
-		}
-		if (addr + mm->cached_hole_size < vma->vm_start)
-		        mm->cached_hole_size = vma->vm_start - addr;
-		addr = vma->vm_end;
-		vma = vma->vm_next;
-	}
-
-	/* Make sure we didn't miss any holes */
-	if (start_addr != TASK_UNMAPPED_BASE) {
-		start_addr = addr = TASK_UNMAPPED_BASE;
-		mm->cached_hole_size = 0;
-		goto full_search;
-	}
-	return -ENOMEM;
-}
-
-/*
- * This mmap-allocator allocates new areas top-down from below the
- * stack's low limit (the base):
- *
- * Because we have an exclusive hugepage region which lies within the
- * normal user address space, we have to take special measures to make
- * non-huge mmap()s evade the hugepage reserved regions.
- */
-unsigned long
-arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
-			  const unsigned long len, const unsigned long pgoff,
-			  const unsigned long flags)
-{
-	struct vm_area_struct *vma, *prev_vma;
-	struct mm_struct *mm = current->mm;
-	unsigned long base = mm->mmap_base, addr = addr0;
-	unsigned long largest_hole = mm->cached_hole_size;
-	int first_time = 1;
-
-	/* requested length too big for entire address space */
-	if (len > TASK_SIZE)
-		return -ENOMEM;
-
-	/* handle fixed mapping: prevent overlap with huge pages */
-	if (flags & MAP_FIXED) {
-		if (is_hugepage_only_range(mm, addr, len))
-			return -EINVAL;
-		return addr;
-	}
-
-	/* dont allow allocations above current base */
-	if (mm->free_area_cache > base)
-		mm->free_area_cache = base;
-
-	/* requesting a specific address */
-	if (addr) {
-		addr = PAGE_ALIGN(addr);
-		vma = find_vma(mm, addr);
-		if (TASK_SIZE - len >= addr &&
-				(!vma || addr + len <= vma->vm_start)
-				&& !is_hugepage_only_range(mm, addr,len))
-			return addr;
-	}
-
-	if (len <= largest_hole) {
-	        largest_hole = 0;
-		mm->free_area_cache = base;
-	}
-try_again:
-	/* make sure it can fit in the remaining address space */
-	if (mm->free_area_cache < len)
-		goto fail;
-
-	/* either no address requested or cant fit in requested address hole */
-	addr = (mm->free_area_cache - len) & PAGE_MASK;
-	do {
-hugepage_recheck:
-		if (touches_hugepage_low_range(mm, addr, len)) {
-			addr = (addr & ((~0) << SID_SHIFT)) - len;
-			goto hugepage_recheck;
-		} else if (touches_hugepage_high_range(mm, addr, len)) {
-			addr = (addr & ((~0UL) << HTLB_AREA_SHIFT)) - len;
-			goto hugepage_recheck;
-		}
-
-		/*
-		 * Lookup failure means no vma is above this address,
-		 * i.e. return with success:
-		 */
- 	 	if (!(vma = find_vma_prev(mm, addr, &prev_vma)))
-			return addr;
-
-		/*
-		 * new region fits between prev_vma->vm_end and
-		 * vma->vm_start, use it:
-		 */
-		if (addr+len <= vma->vm_start &&
-		          (!prev_vma || (addr >= prev_vma->vm_end))) {
-			/* remember the address as a hint for next time */
-		        mm->cached_hole_size = largest_hole;
-		        return (mm->free_area_cache = addr);
-		} else {
-			/* pull free_area_cache down to the first hole */
-		        if (mm->free_area_cache == vma->vm_end) {
-				mm->free_area_cache = vma->vm_start;
-				mm->cached_hole_size = largest_hole;
-			}
-		}
-
-		/* remember the largest hole we saw so far */
-		if (addr + largest_hole < vma->vm_start)
-		        largest_hole = vma->vm_start - addr;
-
-		/* try just below the current vma->vm_start */
-		addr = vma->vm_start-len;
-	} while (len <= vma->vm_start);
-
-fail:
-	/*
-	 * if hint left us with no space for the requested
-	 * mapping then try again:
-	 */
-	if (first_time) {
-		mm->free_area_cache = base;
-		largest_hole = 0;
-		first_time = 0;
-		goto try_again;
-	}
-	/*
-	 * A failed mmap() very likely causes application failure,
-	 * so fall back to the bottom-up function here. This scenario
-	 * can happen with large stack limits and large mmap()
-	 * allocations.
-	 */
-	mm->free_area_cache = TASK_UNMAPPED_BASE;
-	mm->cached_hole_size = ~0UL;
-	addr = arch_get_unmapped_area(filp, addr0, len, pgoff, flags);
-	/*
-	 * Restore the topdown base:
-	 */
-	mm->free_area_cache = base;
-	mm->cached_hole_size = ~0UL;
-
-	return addr;
-}
-
-static int htlb_check_hinted_area(unsigned long addr, unsigned long len)
-{
-	struct vm_area_struct *vma;
-
-	vma = find_vma(current->mm, addr);
-	if (TASK_SIZE - len >= addr &&
-	    (!vma || ((addr + len) <= vma->vm_start)))
-		return 0;
-
-	return -ENOMEM;
-}
-
-static unsigned long htlb_get_low_area(unsigned long len, u16 segmask)
-{
-	unsigned long addr = 0;
-	struct vm_area_struct *vma;
-
-	vma = find_vma(current->mm, addr);
-	while (addr + len <= 0x100000000UL) {
-		BUG_ON(vma && (addr >= vma->vm_end)); /* invariant */
-
-		if (! __within_hugepage_low_range(addr, len, segmask)) {
-			addr = ALIGN(addr+1, 1<<SID_SHIFT);
-			vma = find_vma(current->mm, addr);
-			continue;
-		}
-
-		if (!vma || (addr + len) <= vma->vm_start)
-			return addr;
-		addr = ALIGN(vma->vm_end, HPAGE_SIZE);
-		/* Depending on segmask this might not be a confirmed
-		 * hugepage region, so the ALIGN could have skipped
-		 * some VMAs */
-		vma = find_vma(current->mm, addr);
-	}
-
-	return -ENOMEM;
-}
-
-static unsigned long htlb_get_high_area(unsigned long len, u16 areamask)
-{
-	unsigned long addr = 0x100000000UL;
-	struct vm_area_struct *vma;
-
-	vma = find_vma(current->mm, addr);
-	while (addr + len <= TASK_SIZE_USER64) {
-		BUG_ON(vma && (addr >= vma->vm_end)); /* invariant */
-
-		if (! __within_hugepage_high_range(addr, len, areamask)) {
-			addr = ALIGN(addr+1, 1UL<<HTLB_AREA_SHIFT);
-			vma = find_vma(current->mm, addr);
-			continue;
-		}
-
-		if (!vma || (addr + len) <= vma->vm_start)
-			return addr;
-		addr = ALIGN(vma->vm_end, HPAGE_SIZE);
-		/* Depending on segmask this might not be a confirmed
-		 * hugepage region, so the ALIGN could have skipped
-		 * some VMAs */
-		vma = find_vma(current->mm, addr);
-	}
-
-	return -ENOMEM;
-}
 
 unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
 					unsigned long len, unsigned long pgoff,
 					unsigned long flags)
 {
-	int lastshift;
-	u16 areamask, curareas;
-
-	if (HPAGE_SHIFT == 0)
-		return -EINVAL;
-	if (len & ~HPAGE_MASK)
-		return -EINVAL;
-	if (len > TASK_SIZE)
-		return -ENOMEM;
-
-	if (!cpu_has_feature(CPU_FTR_16M_PAGE))
-		return -EINVAL;
-
-	/* Paranoia, caller should have dealt with this */
-	BUG_ON((addr + len)  < addr);
-
-	/* Handle MAP_FIXED */
-	if (flags & MAP_FIXED) {
-		if (prepare_hugepage_range(addr, len, pgoff))
-			return -EINVAL;
-		return addr;
-	}
-
-	if (test_thread_flag(TIF_32BIT)) {
-		curareas = current->mm->context.low_htlb_areas;
-
-		/* First see if we can use the hint address */
-		if (addr && (htlb_check_hinted_area(addr, len) == 0)) {
-			areamask = LOW_ESID_MASK(addr, len);
-			if (open_low_hpage_areas(current->mm, areamask) == 0)
-				return addr;
-		}
-
-		/* Next see if we can map in the existing low areas */
-		addr = htlb_get_low_area(len, curareas);
-		if (addr != -ENOMEM)
-			return addr;
-
-		/* Finally go looking for areas to open */
-		lastshift = 0;
-		for (areamask = LOW_ESID_MASK(0x100000000UL-len, len);
-		     ! lastshift; areamask >>=1) {
-			if (areamask & 1)
-				lastshift = 1;
-
-			addr = htlb_get_low_area(len, curareas | areamask);
-			if ((addr != -ENOMEM)
-			    && open_low_hpage_areas(current->mm, areamask) == 0)
-				return addr;
-		}
-	} else {
-		curareas = current->mm->context.high_htlb_areas;
-
-		/* First see if we can use the hint address */
-		/* We discourage 64-bit processes from doing hugepage
-		 * mappings below 4GB (must use MAP_FIXED) */
-		if ((addr >= 0x100000000UL)
-		    && (htlb_check_hinted_area(addr, len) == 0)) {
-			areamask = HTLB_AREA_MASK(addr, len);
-			if (open_high_hpage_areas(current->mm, areamask) == 0)
-				return addr;
-		}
-
-		/* Next see if we can map in the existing high areas */
-		addr = htlb_get_high_area(len, curareas);
-		if (addr != -ENOMEM)
-			return addr;
-
-		/* Finally go looking for areas to open */
-		lastshift = 0;
-		for (areamask = HTLB_AREA_MASK(TASK_SIZE_USER64-len, len);
-		     ! lastshift; areamask >>=1) {
-			if (areamask & 1)
-				lastshift = 1;
-
-			addr = htlb_get_high_area(len, curareas | areamask);
-			if ((addr != -ENOMEM)
-			    && open_high_hpage_areas(current->mm, areamask) == 0)
-				return addr;
-		}
-	}
-	printk(KERN_DEBUG "hugetlb_get_unmapped_area() unable to open"
-	       " enough areas\n");
-	return -ENOMEM;
+ 	return slice_get_unmapped_area(addr, len, flags,
+				       mmu_huge_psize, 1, 0);
 }
 
 /*
Index: linux-cell/arch/powerpc/mm/mmu_context_64.c
===================================================================
--- linux-cell.orig/arch/powerpc/mm/mmu_context_64.c	2007-05-08 15:27:05.000000000 +1000
+++ linux-cell/arch/powerpc/mm/mmu_context_64.c	2007-05-08 15:27:52.000000000 +1000
@@ -28,6 +28,7 @@ int init_new_context(struct task_struct 
 {
 	int index;
 	int err;
+	int new_context = (mm->context.id == 0);
 
 again:
 	if (!idr_pre_get(&mmu_context_idr, GFP_KERNEL))
@@ -50,9 +51,18 @@ again:
 	}
 
 	mm->context.id = index;
+#ifdef CONFIG_PPC_MM_SLICES
+	/* The old code would re-promote on fork, we don't do that
+	 * when using slices as it could cause problem promoting slices
+	 * that have been forced down to 4K
+	 */
+	if (new_context)
+		slice_set_user_psize(mm, mmu_virtual_psize);
+#else
 	mm->context.user_psize = mmu_virtual_psize;
 	mm->context.sllp = SLB_VSID_USER |
 		mmu_psize_defs[mmu_virtual_psize].sllp;
+#endif
 
 	return 0;
 }
Index: linux-cell/arch/powerpc/mm/slb_low.S
===================================================================
--- linux-cell.orig/arch/powerpc/mm/slb_low.S	2007-05-08 15:27:05.000000000 +1000
+++ linux-cell/arch/powerpc/mm/slb_low.S	2007-05-08 15:27:52.000000000 +1000
@@ -82,31 +82,45 @@ _GLOBAL(slb_miss_kernel_load_io)
 	srdi.	r9,r10,USER_ESID_BITS
 	bne-	8f			/* invalid ea bits set */
 
-	/* Figure out if the segment contains huge pages */
-#ifdef CONFIG_HUGETLB_PAGE
-BEGIN_FTR_SECTION
-	b	1f
-END_FTR_SECTION_IFCLR(CPU_FTR_16M_PAGE)
+
+	/* when using slices, we extract the psize off the slice bitmaps
+	 * and then we need to get the sllp encoding off the mmu_psize_defs
+	 * array.
+	 *
+	 * XXX This is a bit inefficient especially for the normal case,
+	 * so we should try to implement a fast path for the standard page
+	 * size using the old sllp value so we avoid the array. We cannot
+	 * really do dynamic patching unfortunately as processes might flip
+	 * between 4k and 64k standard page size
+	 */
+#ifdef CONFIG_PPC_MM_SLICES
 	cmpldi	r10,16
 
-	lhz	r9,PACALOWHTLBAREAS(r13)
-	mr	r11,r10
+	/* Get the slice index * 4 in r11 and matching slice size mask in r9 */
+	ld	r9,PACALOWSLICESPSIZE(r13)
+	sldi	r11,r10,2
 	blt	5f
+	ld	r9,PACAHIGHSLICEPSIZE(r13)
+	srdi	r11,r10,(SLICE_HIGH_SHIFT - SLICE_LOW_SHIFT - 2)
+	andi.	r11,r11,0x3c
+
+5:	/* Extract the psize and multiply to get an array offset */
+	srd	r9,r9,r11
+	andi.	r9,r9,0xf
+	mulli	r9,r9,MMUPSIZEDEFSIZE
 
-	lhz	r9,PACAHIGHHTLBAREAS(r13)
-	srdi	r11,r10,(HTLB_AREA_SHIFT-SID_SHIFT)
-
-5:	srd	r9,r9,r11
-	andi.	r9,r9,1
-	beq	1f
-_GLOBAL(slb_miss_user_load_huge)
-	li	r11,0
-	b	2f
-1:
-#endif /* CONFIG_HUGETLB_PAGE */
-
+	/* Now get to the array and obtain the sllp
+	 */
+	ld	r11,PACATOC(r13)
+	ld	r11,mmu_psize_defs@got(r11)
+	add	r11,r11,r9
+	ld	r11,MMUPSIZESLLP(r11)
+	ori	r11,r11,SLB_VSID_USER
+#else
+	/* paca context sllp already contains the SLB_VSID_USER bits */
 	lhz	r11,PACACONTEXTSLLP(r13)
-2:
+#endif /* CONFIG_PPC_MM_SLICES */
+
 	ld	r9,PACACONTEXTID(r13)
 	rldimi	r10,r9,USER_ESID_BITS,0
 	b	slb_finish_load
Index: linux-cell/arch/powerpc/mm/hash_utils_64.c
===================================================================
--- linux-cell.orig/arch/powerpc/mm/hash_utils_64.c	2007-05-08 15:27:29.000000000 +1000
+++ linux-cell/arch/powerpc/mm/hash_utils_64.c	2007-05-08 15:28:34.000000000 +1000
@@ -51,6 +51,7 @@
 #include <asm/cputable.h>
 #include <asm/abs_addr.h>
 #include <asm/sections.h>
+#include <asm/spu.h>
 
 #ifdef DEBUG
 #define DBG(fmt...) udbg_printf(fmt)
@@ -601,8 +602,13 @@ static void demote_segment_4k(struct mm_
 {
 	if (mm->context.user_psize == MMU_PAGE_4K)
 		return;
+#ifdef CONFIG_PPC_MM_SLICES
+	slice_set_user_psize(mm, MMU_PAGE_4K);
+#else /* CONFIG_PPC_MM_SLICES */
 	mm->context.user_psize = MMU_PAGE_4K;
 	mm->context.sllp = SLB_VSID_USER | mmu_psize_defs[MMU_PAGE_4K].sllp;
+#endif /* CONFIG_PPC_MM_SLICES */
+
 #ifdef CONFIG_SPE_BASE
 	spu_flush_all_slbs(mm);
 #endif
@@ -670,11 +676,14 @@ int hash_page(unsigned long ea, unsigned
 	if (user_region && cpus_equal(mm->cpu_vm_mask, tmp))
 		local = 1;
 
+#ifdef CONFIG_HUGETLB_PAGE
 	/* Handle hugepage regions */
-	if (unlikely(in_hugepage_area(mm->context, ea))) {
+	if (HPAGE_SHIFT &&
+	    unlikely(get_slice_psize(mm, ea) == mmu_huge_psize)) {
 		DBG_LOW(" -> huge page !\n");
 		return hash_huge_page(mm, access, ea, vsid, local, trap);
 	}
+#endif /* CONFIG_HUGETLB_PAGE */
 
 	/* Get PTE and page size from page tables */
 	ptep = find_linux_pte(pgdir, ea);
@@ -770,10 +779,13 @@ void hash_preload(struct mm_struct *mm, 
 	unsigned long flags;
 	int local = 0;
 
-	/* We don't want huge pages prefaulted for now
-	 */
-	if (unlikely(in_hugepage_area(mm->context, ea)))
+	BUG_ON(REGION_ID(ea) != USER_REGION_ID);
+
+#ifdef CONFIG_PPC_MM_SLICES
+	/* We only prefault standard pages for now */
+	if (unlikely(get_slice_psize(mm, ea) != mm->context.user_psize));
 		return;
+#endif
 
 	DBG_LOW("hash_preload(mm=%p, mm->pgdir=%p, ea=%016lx, access=%lx,"
 		" trap=%lx\n", mm, mm->pgd, ea, access, trap);
Index: linux-cell/arch/powerpc/mm/slb.c
===================================================================
--- linux-cell.orig/arch/powerpc/mm/slb.c	2007-05-08 15:27:05.000000000 +1000
+++ linux-cell/arch/powerpc/mm/slb.c	2007-05-08 15:27:52.000000000 +1000
@@ -198,12 +198,6 @@ void slb_initialize(void)
 	static int slb_encoding_inited;
 	extern unsigned int *slb_miss_kernel_load_linear;
 	extern unsigned int *slb_miss_kernel_load_io;
-#ifdef CONFIG_HUGETLB_PAGE
-	extern unsigned int *slb_miss_user_load_huge;
-	unsigned long huge_llp;
-
-	huge_llp = mmu_psize_defs[mmu_huge_psize].sllp;
-#endif
 
 	/* Prepare our SLB miss handler based on our page size */
 	linear_llp = mmu_psize_defs[mmu_linear_psize].sllp;
@@ -220,11 +214,6 @@ void slb_initialize(void)
 
 		DBG("SLB: linear  LLP = %04x\n", linear_llp);
 		DBG("SLB: io      LLP = %04x\n", io_llp);
-#ifdef CONFIG_HUGETLB_PAGE
-		patch_slb_encoding(slb_miss_user_load_huge,
-				   SLB_VSID_USER | huge_llp);
-		DBG("SLB: huge    LLP = %04x\n", huge_llp);
-#endif
 	}
 
 	get_paca()->stab_rr = SLB_NUM_BOLTED;
Index: linux-cell/arch/powerpc/platforms/cell/spu_base.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/cell/spu_base.c	2007-05-08 15:27:05.000000000 +1000
+++ linux-cell/arch/powerpc/platforms/cell/spu_base.c	2007-05-08 15:27:52.000000000 +1000
@@ -144,12 +144,11 @@ static int __spu_trap_data_seg(struct sp
 
 	switch(REGION_ID(ea)) {
 	case USER_REGION_ID:
-#ifdef CONFIG_HUGETLB_PAGE
-		if (in_hugepage_area(mm->context, ea))
-			psize = mmu_huge_psize;
-		else
+#ifdef CONFIG_PPC_MM_SLICES
+		psize = get_slice_psize(mm, ea);
+#else
+		psize = mm->context.user_psize;
 #endif
-			psize = mm->context.user_psize;
 		vsid = (get_vsid(mm->context.id, ea) << SLB_VSID_SHIFT) |
 				SLB_VSID_USER;
 		break;
Index: linux-cell/include/asm-powerpc/mmu-hash64.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/mmu-hash64.h	2007-05-08 15:27:05.000000000 +1000
+++ linux-cell/include/asm-powerpc/mmu-hash64.h	2007-05-08 15:27:52.000000000 +1000
@@ -350,10 +350,13 @@ typedef unsigned long mm_context_id_t;
 
 typedef struct {
 	mm_context_id_t id;
-	u16 user_psize;			/* page size index */
-	u16 sllp;			/* SLB entry page size encoding */
-#ifdef CONFIG_HUGETLB_PAGE
-	u16 low_htlb_areas, high_htlb_areas;
+	u16 user_psize;		/* page size index */
+
+#ifdef CONFIG_PPC_MM_SLICES
+	u64 low_slices_psize;	/* SLB page size encodings */
+	u64 high_slices_psize;  /* 4 bits per slice for now */
+#else
+	u16 sllp;		/* SLB page size encoding */
 #endif
 	unsigned long vdso_base;
 } mm_context_t;

^ permalink raw reply

* [PATCH 1/5] powerpc: Small fixes & cleanups in segment page size demotion
From: Benjamin Herrenschmidt @ 2007-05-08  6:27 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Hugh Dickins, Paul Mackerras
In-Reply-To: <1178605646.637780.625211974455.qpush@grosgo>

The code for demoting segments to 4K had some issues, like for example,
when using _PAGE_4K_PFN flag, the first CPU to hit it would do the
demotion, but other CPUs hitting the same page wouldn't properly flush
their SLBs if mmu_ci_restriction isn't set. There are also potential
issues with hash_preload not handling _PAGE_4K_PFN. All of these are
non issues on current hardware but might bite us in the future.

This patch thus fixes it by:

 - Taking the test comparing the mm and current CPU context page
sizes to decide to flush SLBs out of the mmu_ci_restrictions test
since that can also be triggered by _PAGE_4K_PFN pages

 - Due to the above being done all the time, demote_segment_4k
doesn't need update the context and flush the SLB

 - demote_segment_4k can be static and doesn't need an EXPORT_SYMBOL

 - Making hash_preload ignore anything that has either _PAGE_4K_PFN
or _PAGE_NO_CACHE set, thus avoiding duplication of the complicated
logic in hash_page() (and possibly making hash_preload a little bit
faster for the normal case).


Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

 arch/powerpc/mm/hash_utils_64.c |   87 +++++++++++++++++++++-------------------
 1 file changed, 46 insertions(+), 41 deletions(-)

Index: linux-cell/arch/powerpc/mm/hash_utils_64.c
===================================================================
--- linux-cell.orig/arch/powerpc/mm/hash_utils_64.c	2007-05-08 14:22:06.000000000 +1000
+++ linux-cell/arch/powerpc/mm/hash_utils_64.c	2007-05-08 15:27:29.000000000 +1000
@@ -596,22 +596,18 @@ unsigned int hash_page_do_lazy_icache(un
  * Demote a segment to using 4k pages.
  * For now this makes the whole process use 4k pages.
  */
-void demote_segment_4k(struct mm_struct *mm, unsigned long addr)
-{
 #ifdef CONFIG_PPC_64K_PAGES
+static void demote_segment_4k(struct mm_struct *mm, unsigned long addr)
+{
 	if (mm->context.user_psize == MMU_PAGE_4K)
 		return;
 	mm->context.user_psize = MMU_PAGE_4K;
 	mm->context.sllp = SLB_VSID_USER | mmu_psize_defs[MMU_PAGE_4K].sllp;
-	get_paca()->context = mm->context;
-	slb_flush_and_rebolt();
 #ifdef CONFIG_SPE_BASE
 	spu_flush_all_slbs(mm);
 #endif
-#endif
 }
-
-EXPORT_SYMBOL_GPL(demote_segment_4k);
+#endif /* CONFIG_PPC_64K_PAGES */
 
 /* Result code is:
  *  0 - handled
@@ -711,40 +707,42 @@ int hash_page(unsigned long ea, unsigned
 		psize = MMU_PAGE_4K;
 	}
 
-	if (mmu_ci_restrictions) {
-		/* If this PTE is non-cacheable, switch to 4k */
-		if (psize == MMU_PAGE_64K &&
-		    (pte_val(*ptep) & _PAGE_NO_CACHE)) {
-			if (user_region) {
-				demote_segment_4k(mm, ea);
-				psize = MMU_PAGE_4K;
-			} else if (ea < VMALLOC_END) {
-				/*
-				 * some driver did a non-cacheable mapping
-				 * in vmalloc space, so switch vmalloc
-				 * to 4k pages
-				 */
-				printk(KERN_ALERT "Reducing vmalloc segment "
-				       "to 4kB pages because of "
-				       "non-cacheable mapping\n");
-				psize = mmu_vmalloc_psize = MMU_PAGE_4K;
-			}
+	/* If this PTE is non-cacheable and we have restrictions on
+	 * using non cacheable large pages, then we switch to 4k
+	 */
+	if (mmu_ci_restrictions && psize == MMU_PAGE_64K &&
+	    (pte_val(*ptep) & _PAGE_NO_CACHE)) {
+		if (user_region) {
+			demote_segment_4k(mm, ea);
+			psize = MMU_PAGE_4K;
+		} else if (ea < VMALLOC_END) {
+			/*
+			 * some driver did a non-cacheable mapping
+			 * in vmalloc space, so switch vmalloc
+			 * to 4k pages
+			 */
+			printk(KERN_ALERT "Reducing vmalloc segment "
+			       "to 4kB pages because of "
+			       "non-cacheable mapping\n");
+			psize = mmu_vmalloc_psize = MMU_PAGE_4K;
 #ifdef CONFIG_SPE_BASE
 			spu_flush_all_slbs(mm);
 #endif
 		}
-		if (user_region) {
-			if (psize != get_paca()->context.user_psize) {
-				get_paca()->context = mm->context;
-				slb_flush_and_rebolt();
-			}
-		} else if (get_paca()->vmalloc_sllp !=
-			   mmu_psize_defs[mmu_vmalloc_psize].sllp) {
-			get_paca()->vmalloc_sllp =
-				mmu_psize_defs[mmu_vmalloc_psize].sllp;
+	}
+	if (user_region) {
+		if (psize != get_paca()->context.user_psize) {
+			get_paca()->context.user_psize =
+				mm->context.user_psize;
 			slb_flush_and_rebolt();
 		}
+	} else if (get_paca()->vmalloc_sllp !=
+		   mmu_psize_defs[mmu_vmalloc_psize].sllp) {
+		get_paca()->vmalloc_sllp =
+			mmu_psize_defs[mmu_vmalloc_psize].sllp;
+		slb_flush_and_rebolt();
 	}
+
 	if (psize == MMU_PAGE_64K)
 		rc = __hash_page_64K(ea, access, vsid, ptep, trap, local);
 	else
@@ -780,13 +778,26 @@ void hash_preload(struct mm_struct *mm, 
 	DBG_LOW("hash_preload(mm=%p, mm->pgdir=%p, ea=%016lx, access=%lx,"
 		" trap=%lx\n", mm, mm->pgd, ea, access, trap);
 
-	/* Get PTE, VSID, access mask */
+	/* Get Linux PTE if available */
 	pgdir = mm->pgd;
 	if (pgdir == NULL)
 		return;
 	ptep = find_linux_pte(pgdir, ea);
 	if (!ptep)
 		return;
+
+#ifdef CONFIG_PPC_64K_PAGES
+	/* If either _PAGE_4K_PFN or _PAGE_NO_CACHE is set (and we are on
+	 * a 64K kernel), then we don't preload, hash_page() will take
+	 * care of it once we actually try to access the page.
+	 * That way we don't have to duplicate all of the logic for segment
+	 * page size demotion here
+	 */
+	if (pte_val(*ptep) & (_PAGE_4K_PFN | _PAGE_NO_CACHE))
+		return;
+#endif /* CONFIG_PPC_64K_PAGES */
+
+	/* Get VSID */
 	vsid = get_vsid(mm->context.id, ea);
 
 	/* Hash it in */
@@ -797,12 +808,6 @@ void hash_preload(struct mm_struct *mm, 
 #ifndef CONFIG_PPC_64K_PAGES
 	__hash_page_4K(ea, access, vsid, ptep, trap, local);
 #else
-	if (mmu_ci_restrictions) {
-		/* If this PTE is non-cacheable, switch to 4k */
-		if (mm->context.user_psize == MMU_PAGE_64K &&
-		    (pte_val(*ptep) & _PAGE_NO_CACHE))
-			demote_segment_4k(mm, ea);
-	}
 	if (mm->context.user_psize == MMU_PAGE_64K)
 		__hash_page_64K(ea, access, vsid, ptep, trap, local);
 	else

^ permalink raw reply

* [PATCH 0/5] This is my pending series for 2.6.22
From: Benjamin Herrenschmidt @ 2007-05-08  6:27 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Hugh Dickins, Paul Mackerras

Mostly, it adds my slice infrastructure that I posted a few times
before, rebased for the current code, and along with it, support
for 64K pages mapping of SPE local stores on 4K kernel 

There's also a bug fix & cleanup for the segment demotion and my
modified version of Hugh Dickins patch to stop using SLAB for
PTE pages.

-DO NOT MERGE JUST YET-

I still want to torture it a bit as I just rebased it now that all of
the get_unmapped_area changes are finally upstream.

Hopefully, I'll give you an Ack tomorrow.

^ permalink raw reply

* Re: [PATCH 1/3] [POWERPC] 8xx: mpc885ads pcmcia support
From: Olof Johansson @ 2007-05-08  6:02 UTC (permalink / raw)
  To: Vitaly Bordug; +Cc: linuxppc-dev, linux-pcmcia, linux-kernel
In-Reply-To: <20070508054840.18428.28313.stgit@localhost.localdomain>

On Tue, May 08, 2007 at 09:48:44AM +0400, Vitaly Bordug wrote:
> 
> Adds support for PowerQuicc on-chip PCMCIA. The driver is implemented as
> of_device, so only arch/powerpc stuff is capable to use it, which now
> implies only mpc885ads reference board.
> 
> To cope with the code that should be hooked inside driver, but is really
> board specific (like set_voltage), global structure mpc8xx_pcmcia_ops
> holds necessary function pointers that are filled in the BSP code.
> 
> Signed-off-by: Vitaly Bordug <vitb@kernel.crashing.org>
> Acked-by: Arnd Bergmann <arnd@arndb.de>

Acked-by: Olof Johansson <olof@lixom.net>

(Hm, just acked the previous post it seems. :)

^ permalink raw reply

* Re: [PATCH 1/3] [POWERPC] 8xx: mpc885ads pcmcia support
From: Olof Johansson @ 2007-05-08  5:58 UTC (permalink / raw)
  To: Vitaly Bordug; +Cc: linuxppc-dev, linux-pcmcia, linux-kernel
In-Reply-To: <20070508003642.5964.37001.stgit@localhost.localdomain>

On Tue, May 08, 2007 at 04:36:51AM +0400, Vitaly Bordug wrote:
> 
> Adds support for PowerQuicc on-chip PCMCIA. The driver is implemented as
> of_device, so only arch/powerpc stuff is capable to use it, which now
> implies only mpc885ads reference board.
> 
> To cope with the code that should be hooked inside driver, but is really
> board specific (like set_voltage), global structure mpc8xx_pcmcia_ops
> holds necessary function pointers that are filled in the BSP code.
> 
> Signed-off-by: Vitaly Bordug <vitb@kernel.crashing.org>
> Acked-by: Arnd Bergmann <arnd@arndb.de>

Acked-by: Olof Johansson <olof@lixom.net>

^ permalink raw reply

* Re: [PATCH 3/3] [POWERPC] dts: kill hardcoded phandles
From: David Gibson @ 2007-05-08  5:54 UTC (permalink / raw)
  To: Vitaly Bordug; +Cc: linuxppc-dev, linux-pcmcia, linux-kernel
In-Reply-To: <20070508054855.18428.29080.stgit@localhost.localdomain>

On Tue, May 08, 2007 at 09:48:56AM +0400, Vitaly Bordug wrote:
> 
> Removed explicit linux,phandle usage. Using references and labels now in
> PQ and PQ2 boards currently supported in arch/powerpc.
> Signed-off-by: Vitaly Bordug <vitb@kernel.crashing.org>
> 
> ---
> 
>  arch/powerpc/boot/dts/mpc8272ads.dts |   42 ++++++++++++----------------------
>  arch/powerpc/boot/dts/mpc866ads.dts  |   31 +++++++++----------------
>  arch/powerpc/boot/dts/mpc885ads.dts  |    2 +-
>  3 files changed, 27 insertions(+), 48 deletions(-)
> 
> diff --git a/arch/powerpc/boot/dts/mpc8272ads.dts b/arch/powerpc/boot/dts/mpc8272ads.dts
> index 423eedc..83461fe 100644
> --- a/arch/powerpc/boot/dts/mpc8272ads.dts
> +++ b/arch/powerpc/boot/dts/mpc8272ads.dts
> @@ -14,12 +14,10 @@
>         compatible = "MPC8260ADS";
>         #address-cells = <1>;
>         #size-cells = <1>;
> -       linux,phandle = <100>;
>  
>         cpus {
>                 #address-cells = <1>;
>                 #size-cells = <0>;
> -               linux,phandle = <200>;
>  
>                 PowerPC,8272@0 {
>                         device_type = "cpu";
> @@ -32,12 +30,10 @@
>                         bus-frequency = <0>;
>                         clock-frequency = <0>;
>                         32-bit;
> -                       linux,phandle = <201>;
>                 };
>         };
>  
> -       interrupt-controller@f8200000 {
> -               linux,phandle = <f8200000>;
> +		pci_pic:interrupt-controller@f8200000 {

I'd like to establish a convention of putting a space after the : and
using capitals for labels unless there's a strong reason not to in a
particular case.  It makes them easier to visually distinguish next to
the node name.

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

^ permalink raw reply

* [PATCH 2/3] [POWERPC] 8xx: fix whitespace and indentation
From: Vitaly Bordug @ 2007-05-08  5:48 UTC (permalink / raw)
  To: linux-pcmcia; +Cc: linuxppc-dev, linux-kernel
In-Reply-To: <20070508053049.18428.50622.stgit@localhost.localdomain>


Rolling forward PCMCIA driver, it was discovered that the indentation
in existing one is very odd. This patch is just result of Lindent run ontop
of culprit files.

Signed-off-by: Vitaly Bordug <vitb@kernel.crashing.org>

---

 drivers/pcmcia/m8xx_pcmcia.c |  548 +++++++++++++++++++++---------------------
 1 files changed, 278 insertions(+), 270 deletions(-)

diff --git a/drivers/pcmcia/m8xx_pcmcia.c b/drivers/pcmcia/m8xx_pcmcia.c
index 40f6e20..79e14ab 100644
--- a/drivers/pcmcia/m8xx_pcmcia.c
+++ b/drivers/pcmcia/m8xx_pcmcia.c
@@ -113,7 +113,7 @@ MODULE_LICENSE("Dual MPL/GPL");
 #define CONFIG_PCMCIA_SLOT_B
 #endif
 
-#endif /* !defined(CONFIG_PCMCIA_SLOT_A) && !defined(CONFIG_PCMCIA_SLOT_B) */
+#endif				/* !defined(CONFIG_PCMCIA_SLOT_A) && !defined(CONFIG_PCMCIA_SLOT_B) */
 
 #if defined(CONFIG_PCMCIA_SLOT_A) && defined(CONFIG_PCMCIA_SLOT_B)
 
@@ -146,9 +146,9 @@ MODULE_LICENSE("Dual MPL/GPL");
 
 /* ------------------------------------------------------------------------- */
 
-#define PCMCIA_MEM_WIN_BASE 0xe0000000 /* base address for memory window 0   */
-#define PCMCIA_MEM_WIN_SIZE 0x04000000 /* each memory window is 64 MByte     */
-#define PCMCIA_IO_WIN_BASE  _IO_BASE   /* base address for io window 0       */
+#define PCMCIA_MEM_WIN_BASE 0xe0000000	/* base address for memory window 0   */
+#define PCMCIA_MEM_WIN_SIZE 0x04000000	/* each memory window is 64 MByte     */
+#define PCMCIA_IO_WIN_BASE  _IO_BASE	/* base address for io window 0       */
 /* ------------------------------------------------------------------------- */
 
 static int pcmcia_schlvl;
@@ -169,8 +169,8 @@ static u32 *m8xx_pgcrx[2];
  */
 
 struct pcmcia_win {
-	u32	br;
-	u32	or;
+	u32 br;
+	u32 or;
 };
 
 /*
@@ -214,7 +214,7 @@ struct pcmcia_win {
 
 /* we keep one lookup table per socket to check flags */
 
-#define PCMCIA_EVENTS_MAX 5  /* 4 max at a time + termination */
+#define PCMCIA_EVENTS_MAX 5	/* 4 max at a time + termination */
 
 struct event_table {
 	u32 regbit;
@@ -224,8 +224,8 @@ struct event_table {
 static const char driver_name[] = "m8xx-pcmcia";
 
 struct socket_info {
-	void	(*handler)(void *info, u32 events);
-	void	*info;
+	void (*handler) (void *info, u32 events);
+	void *info;
 
 	u32 slot;
 	pcmconf8xx_t *pcmcia;
@@ -234,7 +234,7 @@ struct socket_info {
 
 	socket_state_t state;
 	struct pccard_mem_map mem_win[PCMCIA_MEM_WIN_NO];
-	struct pccard_io_map  io_win[PCMCIA_IO_WIN_NO];
+	struct pccard_io_map io_win[PCMCIA_IO_WIN_NO];
 	struct event_table events[PCMCIA_EVENTS_MAX];
 	struct pcmcia_socket socket;
 };
@@ -248,8 +248,7 @@ static struct socket_info socket[PCMCIA_SOCKETS_NO];
 
 #define M8XX_SIZES_NO 32
 
-static const u32 m8xx_size_to_gray[M8XX_SIZES_NO] =
-{
+static const u32 m8xx_size_to_gray[M8XX_SIZES_NO] = {
 	0x00000001, 0x00000002, 0x00000008, 0x00000004,
 	0x00000080, 0x00000040, 0x00000010, 0x00000020,
 	0x00008000, 0x00004000, 0x00001000, 0x00002000,
@@ -265,7 +264,7 @@ static const u32 m8xx_size_to_gray[M8XX_SIZES_NO] =
 
 static irqreturn_t m8xx_interrupt(int irq, void *dev);
 
-#define PCMCIA_BMT_LIMIT (15*4)  /* Bus Monitor Timeout value */
+#define PCMCIA_BMT_LIMIT (15*4)	/* Bus Monitor Timeout value */
 
 /* ------------------------------------------------------------------------- */
 /* board specific stuff:                                                     */
@@ -289,8 +288,9 @@ static int voltage_set(int slot, int vcc, int vpp)
 {
 	u32 reg = 0;
 
-	switch(vcc) {
-	case 0: break;
+	switch (vcc) {
+	case 0:
+		break;
 	case 33:
 		reg |= BCSR1_PCVCTL4;
 		break;
@@ -301,11 +301,12 @@ static int voltage_set(int slot, int vcc, int vpp)
 		return 1;
 	}
 
-	switch(vpp) {
-	case 0: break;
+	switch (vpp) {
+	case 0:
+		break;
 	case 33:
 	case 50:
-		if(vcc == vpp)
+		if (vcc == vpp)
 			reg |= BCSR1_PCVCTL6;
 		else
 			return 1;
@@ -316,25 +317,29 @@ static int voltage_set(int slot, int vcc, int vpp)
 		return 1;
 	}
 
-	if(!((vcc == 50) || (vcc == 0)))
+	if (!((vcc == 50) || (vcc == 0)))
 		return 1;
 
 	/* first, turn off all power */
 
-	out_be32(((u32 *)RPX_CSR_ADDR), in_be32(((u32 *)RPX_CSR_ADDR)) & ~(BCSR1_PCVCTL4 | BCSR1_PCVCTL5 | BCSR1_PCVCTL6 | BCSR1_PCVCTL7));
+	out_be32(((u32 *) RPX_CSR_ADDR),
+		 in_be32(((u32 *) RPX_CSR_ADDR)) & ~(BCSR1_PCVCTL4 |
+						     BCSR1_PCVCTL5 |
+						     BCSR1_PCVCTL6 |
+						     BCSR1_PCVCTL7));
 
 	/* enable new powersettings */
 
-	out_be32(((u32 *)RPX_CSR_ADDR), in_be32(((u32 *)RPX_CSR_ADDR)) | reg);
+	out_be32(((u32 *) RPX_CSR_ADDR), in_be32(((u32 *) RPX_CSR_ADDR)) | reg);
 
 	return 0;
 }
 
 #define socket_get(_slot_) PCMCIA_SOCKET_KEY_5V
-#define hardware_enable(_slot_)  /* No hardware to enable */
-#define hardware_disable(_slot_) /* No hardware to disable */
+#define hardware_enable(_slot_)	/* No hardware to enable */
+#define hardware_disable(_slot_)	/* No hardware to disable */
 
-#endif /* CONFIG_RPXCLASSIC */
+#endif				/* CONFIG_RPXCLASSIC */
 
 /* FADS Boards from Motorola                                               */
 
@@ -346,43 +351,45 @@ static int voltage_set(int slot, int vcc, int vpp)
 {
 	u32 reg = 0;
 
-	switch(vcc) {
-		case 0:
-			break;
-		case 33:
-			reg |= BCSR1_PCCVCC0;
-			break;
-		case 50:
-			reg |= BCSR1_PCCVCC1;
-			break;
-		default:
-			return 1;
+	switch (vcc) {
+	case 0:
+		break;
+	case 33:
+		reg |= BCSR1_PCCVCC0;
+		break;
+	case 50:
+		reg |= BCSR1_PCCVCC1;
+		break;
+	default:
+		return 1;
 	}
 
-	switch(vpp) {
-		case 0:
-			break;
-		case 33:
-		case 50:
-			if(vcc == vpp)
-				reg |= BCSR1_PCCVPP1;
-			else
-				return 1;
-			break;
-		case 120:
-			if ((vcc == 33) || (vcc == 50))
-				reg |= BCSR1_PCCVPP0;
-			else
-				return 1;
-		default:
+	switch (vpp) {
+	case 0:
+		break;
+	case 33:
+	case 50:
+		if (vcc == vpp)
+			reg |= BCSR1_PCCVPP1;
+		else
 			return 1;
+		break;
+	case 120:
+		if ((vcc == 33) || (vcc == 50))
+			reg |= BCSR1_PCCVPP0;
+		else
+			return 1;
+	default:
+		return 1;
 	}
 
 	/* first, turn off all power */
-	out_be32((u32 *)BCSR1, in_be32((u32 *)BCSR1) & ~(BCSR1_PCCVCC_MASK | BCSR1_PCCVPP_MASK));
+	out_be32((u32 *) BCSR1,
+		 in_be32((u32 *) BCSR1) & ~(BCSR1_PCCVCC_MASK |
+					    BCSR1_PCCVPP_MASK));
 
 	/* enable new powersettings */
-	out_be32((u32 *)BCSR1, in_be32((u32 *)BCSR1) | reg);
+	out_be32((u32 *) BCSR1, in_be32((u32 *) BCSR1) | reg);
 
 	return 0;
 }
@@ -391,12 +398,12 @@ static int voltage_set(int slot, int vcc, int vpp)
 
 static void hardware_enable(int slot)
 {
-	out_be32((u32 *)BCSR1, in_be32((u32 *)BCSR1) & ~BCSR1_PCCEN);
+	out_be32((u32 *) BCSR1, in_be32((u32 *) BCSR1) & ~BCSR1_PCCEN);
 }
 
 static void hardware_disable(int slot)
 {
-	out_be32((u32 *)BCSR1, in_be32((u32 *)BCSR1) |  BCSR1_PCCEN);
+	out_be32((u32 *) BCSR1, in_be32((u32 *) BCSR1) | BCSR1_PCCEN);
 }
 
 #endif
@@ -410,7 +417,7 @@ static void hardware_disable(int slot)
 
 static inline void hardware_enable(int slot)
 {
-	 m8xx_pcmcia_ops.hw_ctrl(slot, 1);
+	m8xx_pcmcia_ops.hw_ctrl(slot, 1);
 }
 
 static inline void hardware_disable(int slot)
@@ -436,52 +443,53 @@ static int voltage_set(int slot, int vcc, int vpp)
 {
 	u8 reg = 0;
 
-	switch(vcc) {
-		case 0:
-			break;
-		case 33:
-			reg |= CSR2_VCC_33;
-			break;
-		case 50:
-			reg |= CSR2_VCC_50;
-			break;
-		default:
-			return 1;
+	switch (vcc) {
+	case 0:
+		break;
+	case 33:
+		reg |= CSR2_VCC_33;
+		break;
+	case 50:
+		reg |= CSR2_VCC_50;
+		break;
+	default:
+		return 1;
 	}
 
-	switch(vpp) {
-		case 0:
-			break;
-		case 33:
-		case 50:
-			if(vcc == vpp)
-				reg |= CSR2_VPP_VCC;
-			else
-				return 1;
-			break;
-		case 120:
-			if ((vcc == 33) || (vcc == 50))
-				reg |= CSR2_VPP_12;
-			else
-				return 1;
-		default:
+	switch (vpp) {
+	case 0:
+		break;
+	case 33:
+	case 50:
+		if (vcc == vpp)
+			reg |= CSR2_VPP_VCC;
+		else
+			return 1;
+		break;
+	case 120:
+		if ((vcc == 33) || (vcc == 50))
+			reg |= CSR2_VPP_12;
+		else
 			return 1;
+	default:
+		return 1;
 	}
 
 	/* first, turn off all power */
-	out_8((u8 *)MBX_CSR2_ADDR, in_8((u8 *)MBX_CSR2_ADDR) & ~(CSR2_VCC_MASK | CSR2_VPP_MASK));
+	out_8((u8 *) MBX_CSR2_ADDR,
+	      in_8((u8 *) MBX_CSR2_ADDR) & ~(CSR2_VCC_MASK | CSR2_VPP_MASK));
 
 	/* enable new powersettings */
-	out_8((u8 *)MBX_CSR2_ADDR, in_8((u8 *)MBX_CSR2_ADDR) | reg);
+	out_8((u8 *) MBX_CSR2_ADDR, in_8((u8 *) MBX_CSR2_ADDR) | reg);
 
 	return 0;
 }
 
 #define socket_get(_slot_) PCMCIA_SOCKET_KEY_5V
-#define hardware_enable(_slot_)  /* No hardware to enable */
-#define hardware_disable(_slot_) /* No hardware to disable */
+#define hardware_enable(_slot_)	/* No hardware to enable */
+#define hardware_disable(_slot_)	/* No hardware to disable */
 
-#endif /* CONFIG_MBX */
+#endif				/* CONFIG_MBX */
 
 #if defined(CONFIG_PRxK)
 #include <asm/cpld.h>
@@ -495,43 +503,46 @@ static int voltage_set(int slot, int vcc, int vpp)
 	u8 regread;
 	cpld_regs *ccpld = get_cpld();
 
-	switch(vcc) {
-		case 0:
-			break;
-		case 33:
-			reg |= PCMCIA_VCC_33;
-			break;
-		case 50:
-			reg |= PCMCIA_VCC_50;
-			break;
-		default:
-			return 1;
+	switch (vcc) {
+	case 0:
+		break;
+	case 33:
+		reg |= PCMCIA_VCC_33;
+		break;
+	case 50:
+		reg |= PCMCIA_VCC_50;
+		break;
+	default:
+		return 1;
 	}
 
-	switch(vpp) {
-		case 0:
-			break;
-		case 33:
-		case 50:
-			if(vcc == vpp)
-				reg |= PCMCIA_VPP_VCC;
-			else
-				return 1;
-			break;
-		case 120:
-			if ((vcc == 33) || (vcc == 50))
-				reg |= PCMCIA_VPP_12;
-			else
-				return 1;
-		default:
+	switch (vpp) {
+	case 0:
+		break;
+	case 33:
+	case 50:
+		if (vcc == vpp)
+			reg |= PCMCIA_VPP_VCC;
+		else
 			return 1;
+		break;
+	case 120:
+		if ((vcc == 33) || (vcc == 50))
+			reg |= PCMCIA_VPP_12;
+		else
+			return 1;
+	default:
+		return 1;
 	}
 
 	reg = reg >> (slot << 2);
 	regread = in_8(&ccpld->fpga_pc_ctl);
-	if (reg != (regread & ((PCMCIA_VCC_MASK | PCMCIA_VPP_MASK) >> (slot << 2)))) {
+	if (reg !=
+	    (regread & ((PCMCIA_VCC_MASK | PCMCIA_VPP_MASK) >> (slot << 2)))) {
 		/* enable new powersettings */
-		regread = regread & ~((PCMCIA_VCC_MASK | PCMCIA_VPP_MASK) >> (slot << 2));
+		regread =
+		    regread & ~((PCMCIA_VCC_MASK | PCMCIA_VPP_MASK) >>
+				(slot << 2));
 		out_8(&ccpld->fpga_pc_ctl, reg | regread);
 		msleep(100);
 	}
@@ -540,10 +551,10 @@ static int voltage_set(int slot, int vcc, int vpp)
 }
 
 #define socket_get(_slot_) PCMCIA_SOCKET_KEY_LV
-#define hardware_enable(_slot_)  /* No hardware to enable */
-#define hardware_disable(_slot_) /* No hardware to disable */
+#define hardware_enable(_slot_)	/* No hardware to enable */
+#define hardware_disable(_slot_)	/* No hardware to disable */
 
-#endif /* CONFIG_PRxK */
+#endif				/* CONFIG_PRxK */
 
 static u32 pending_events[PCMCIA_SOCKETS_NO];
 static DEFINE_SPINLOCK(pending_event_lock);
@@ -553,7 +564,7 @@ static irqreturn_t m8xx_interrupt(int irq, void *dev)
 	struct socket_info *s;
 	struct event_table *e;
 	unsigned int i, events, pscr, pipr, per;
-	pcmconf8xx_t	*pcmcia = socket[0].pcmcia;
+	pcmconf8xx_t *pcmcia = socket[0].pcmcia;
 
 	dprintk("Interrupt!\n");
 	/* get interrupt sources */
@@ -562,16 +573,16 @@ static irqreturn_t m8xx_interrupt(int irq, void *dev)
 	pipr = in_be32(&pcmcia->pcmc_pipr);
 	per = in_be32(&pcmcia->pcmc_per);
 
-	for(i = 0; i < PCMCIA_SOCKETS_NO; i++) {
+	for (i = 0; i < PCMCIA_SOCKETS_NO; i++) {
 		s = &socket[i];
 		e = &s->events[0];
 		events = 0;
 
-		while(e->regbit) {
-			if(pscr & e->regbit)
+		while (e->regbit) {
+			if (pscr & e->regbit)
 				events |= e->eventbit;
 
-				e++;
+			e++;
 		}
 
 		/*
@@ -579,13 +590,11 @@ static irqreturn_t m8xx_interrupt(int irq, void *dev)
 		 * not too nice done,
 		 * we depend on that CD2 is the bit to the left of CD1...
 		 */
-		if(events & SS_DETECT)
-			if(((pipr & M8XX_PCMCIA_CD2(i)) >> 1) ^
-				(pipr & M8XX_PCMCIA_CD1(i)))
-			{
+		if (events & SS_DETECT)
+			if (((pipr & M8XX_PCMCIA_CD2(i)) >> 1) ^
+			    (pipr & M8XX_PCMCIA_CD1(i))) {
 				events &= ~SS_DETECT;
 			}
-
 #ifdef PCMCIA_GLITCHY_CD
 		/*
 		 * I've experienced CD problems with my ADS board.
@@ -593,24 +602,23 @@ static irqreturn_t m8xx_interrupt(int irq, void *dev)
 		 * real change of Card detection.
 		 */
 
-		if((events & SS_DETECT) &&
-		   ((pipr &
-		     (M8XX_PCMCIA_CD2(i) | M8XX_PCMCIA_CD1(i))) == 0) &&
-		   (s->state.Vcc | s->state.Vpp)) {
+		if ((events & SS_DETECT) &&
+		    ((pipr &
+		      (M8XX_PCMCIA_CD2(i) | M8XX_PCMCIA_CD1(i))) == 0) &&
+		    (s->state.Vcc | s->state.Vpp)) {
 			events &= ~SS_DETECT;
 			/*printk( "CD glitch workaround - CD = 0x%08x!\n",
-				(pipr & (M8XX_PCMCIA_CD2(i)
-					 | M8XX_PCMCIA_CD1(i))));*/
+			   (pipr & (M8XX_PCMCIA_CD2(i)
+			   | M8XX_PCMCIA_CD1(i)))); */
 		}
 #endif
 
 		/* call the handler */
 
 		dprintk("slot %u: events = 0x%02x, pscr = 0x%08x, "
-			"pipr = 0x%08x\n",
-			i, events, pscr, pipr);
+			"pipr = 0x%08x\n", i, events, pscr, pipr);
 
-		if(events) {
+		if (events) {
 			spin_lock(&pending_event_lock);
 			pending_events[i] |= events;
 			spin_unlock(&pending_event_lock);
@@ -643,11 +651,11 @@ static u32 m8xx_get_graycode(u32 size)
 {
 	u32 k;
 
-	for(k = 0; k < M8XX_SIZES_NO; k++)
-		if(m8xx_size_to_gray[k] == size)
+	for (k = 0; k < M8XX_SIZES_NO; k++)
+		if (m8xx_size_to_gray[k] == size)
 			break;
 
-	if((k == M8XX_SIZES_NO) || (m8xx_size_to_gray[k] == -1))
+	if ((k == M8XX_SIZES_NO) || (m8xx_size_to_gray[k] == -1))
 		k = -1;
 
 	return k;
@@ -657,7 +665,7 @@ static u32 m8xx_get_speed(u32 ns, u32 is_io, u32 bus_freq)
 {
 	u32 reg, clocks, psst, psl, psht;
 
-	if(!ns) {
+	if (!ns) {
 
 		/*
 		 * We get called with IO maps setup to 0ns
@@ -665,10 +673,10 @@ static u32 m8xx_get_speed(u32 ns, u32 is_io, u32 bus_freq)
 		 * They should be 255ns.
 		 */
 
-		if(is_io)
+		if (is_io)
 			ns = 255;
 		else
-			ns = 100;  /* fast memory if 0 */
+			ns = 100;	/* fast memory if 0 */
 	}
 
 	/*
@@ -679,23 +687,23 @@ static u32 m8xx_get_speed(u32 ns, u32 is_io, u32 bus_freq)
 
 /* how we want to adjust the timing - in percent */
 
-#define ADJ 180 /* 80 % longer accesstime - to be sure */
+#define ADJ 180			/* 80 % longer accesstime - to be sure */
 
 	clocks = ((bus_freq / 1000) * ns) / 1000;
-	clocks = (clocks * ADJ) / (100*1000);
-	if(clocks >= PCMCIA_BMT_LIMIT) {
-		printk( "Max access time limit reached\n");
-		clocks = PCMCIA_BMT_LIMIT-1;
+	clocks = (clocks * ADJ) / (100 * 1000);
+	if (clocks >= PCMCIA_BMT_LIMIT) {
+		printk("Max access time limit reached\n");
+		clocks = PCMCIA_BMT_LIMIT - 1;
 	}
 
-	psst = clocks / 7;          /* setup time */
-	psht = clocks / 7;          /* hold time */
-	psl  = (clocks * 5) / 7;    /* strobe length */
+	psst = clocks / 7;	/* setup time */
+	psht = clocks / 7;	/* hold time */
+	psl = (clocks * 5) / 7;	/* strobe length */
 
 	psst += clocks - (psst + psht + psl);
 
-	reg =  psst << 12;
-	reg |= psl  << 7;
+	reg = psst << 12;
+	reg |= psl << 7;
 	reg |= psht << 16;
 
 	return reg;
@@ -710,8 +718,8 @@ static int m8xx_get_status(struct pcmcia_socket *sock, unsigned int *value)
 
 	pipr = in_be32(&pcmcia->pcmc_pipr);
 
-	*value  = ((pipr & (M8XX_PCMCIA_CD1(lsock)
-			    | M8XX_PCMCIA_CD2(lsock))) == 0) ? SS_DETECT : 0;
+	*value = ((pipr & (M8XX_PCMCIA_CD1(lsock)
+			   | M8XX_PCMCIA_CD2(lsock))) == 0) ? SS_DETECT : 0;
 	*value |= (pipr & M8XX_PCMCIA_WP(lsock)) ? SS_WRPROT : 0;
 
 	if (s->state.flags & SS_IOCARD)
@@ -795,16 +803,16 @@ static int m8xx_get_status(struct pcmcia_socket *sock, unsigned int *value)
 	/* read out VS1 and VS2 */
 
 	reg = (pipr & M8XX_PCMCIA_VS_MASK(lsock))
-		>> M8XX_PCMCIA_VS_SHIFT(lsock);
+	    >> M8XX_PCMCIA_VS_SHIFT(lsock);
 
-	if(socket_get(lsock) == PCMCIA_SOCKET_KEY_LV) {
-		switch(reg) {
+	if (socket_get(lsock) == PCMCIA_SOCKET_KEY_LV) {
+		switch (reg) {
 		case 1:
 			*value |= SS_3VCARD;
-			break; /* GND, NC - 3.3V only */
+			break;	/* GND, NC - 3.3V only */
 		case 2:
 			*value |= SS_XVCARD;
-			break; /* NC. GND - x.xV only */
+			break;	/* NC. GND - x.xV only */
 		};
 	}
 
@@ -812,7 +820,7 @@ static int m8xx_get_status(struct pcmcia_socket *sock, unsigned int *value)
 	return 0;
 }
 
-static int m8xx_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
+static int m8xx_set_socket(struct pcmcia_socket *sock, socket_state_t * state)
 {
 	int lsock = container_of(sock, struct socket_info, socket)->slot;
 	struct socket_info *s = &socket[lsock];
@@ -821,20 +829,20 @@ static int m8xx_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
 	unsigned long flags;
 	pcmconf8xx_t *pcmcia = socket[0].pcmcia;
 
-	dprintk( "SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, "
-	      "io_irq %d, csc_mask %#2.2x)\n", lsock, state->flags,
-	      state->Vcc, state->Vpp, state->io_irq, state->csc_mask);
+	dprintk("SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, "
+		"io_irq %d, csc_mask %#2.2x)\n", lsock, state->flags,
+		state->Vcc, state->Vpp, state->io_irq, state->csc_mask);
 
 	/* First, set voltage - bail out if invalid */
-	if(voltage_set(lsock, state->Vcc, state->Vpp))
+	if (voltage_set(lsock, state->Vcc, state->Vpp))
 		return -EINVAL;
 
-
 	/* Take care of reset... */
-	if(state->flags & SS_RESET)
-		out_be32(M8XX_PGCRX(lsock), in_be32(M8XX_PGCRX(lsock)) |  M8XX_PGCRX_CXRESET); /* active high */
+	if (state->flags & SS_RESET)
+		out_be32(M8XX_PGCRX(lsock), in_be32(M8XX_PGCRX(lsock)) | M8XX_PGCRX_CXRESET);	/* active high */
 	else
-		out_be32(M8XX_PGCRX(lsock), in_be32(M8XX_PGCRX(lsock)) & ~M8XX_PGCRX_CXRESET);
+		out_be32(M8XX_PGCRX(lsock),
+			 in_be32(M8XX_PGCRX(lsock)) & ~M8XX_PGCRX_CXRESET);
 
 	/* ... and output enable. */
 
@@ -846,10 +854,11 @@ static int m8xx_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
 	   no pullups are present -> the cards act wierd.
 	   So right now the buffers are enabled if the power is on. */
 
-	if(state->Vcc || state->Vpp)
-		out_be32(M8XX_PGCRX(lsock), in_be32(M8XX_PGCRX(lsock)) & ~M8XX_PGCRX_CXOE); /* active low */
+	if (state->Vcc || state->Vpp)
+		out_be32(M8XX_PGCRX(lsock), in_be32(M8XX_PGCRX(lsock)) & ~M8XX_PGCRX_CXOE);	/* active low */
 	else
-		out_be32(M8XX_PGCRX(lsock), in_be32(M8XX_PGCRX(lsock)) | M8XX_PGCRX_CXOE);
+		out_be32(M8XX_PGCRX(lsock),
+			 in_be32(M8XX_PGCRX(lsock)) | M8XX_PGCRX_CXOE);
 
 	/*
 	 * We'd better turn off interrupts before
@@ -866,17 +875,17 @@ static int m8xx_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
 	e = &s->events[0];
 	reg = 0;
 
-	if(state->csc_mask & SS_DETECT) {
+	if (state->csc_mask & SS_DETECT) {
 		e->eventbit = SS_DETECT;
 		reg |= e->regbit = (M8XX_PCMCIA_CD2(lsock)
 				    | M8XX_PCMCIA_CD1(lsock));
 		e++;
 	}
-	if(state->flags & SS_IOCARD) {
+	if (state->flags & SS_IOCARD) {
 		/*
 		 * I/O card
 		 */
-		if(state->csc_mask & SS_STSCHG) {
+		if (state->csc_mask & SS_STSCHG) {
 			e->eventbit = SS_STSCHG;
 			reg |= e->regbit = M8XX_PCMCIA_BVD1(lsock);
 			e++;
@@ -884,9 +893,10 @@ static int m8xx_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
 		/*
 		 * If io_irq is non-zero we should enable irq.
 		 */
-		if(state->io_irq) {
+		if (state->io_irq) {
 			out_be32(M8XX_PGCRX(lsock),
-				 in_be32(M8XX_PGCRX(lsock)) | mk_int_int_mask(s->hwirq) << 24);
+				 in_be32(M8XX_PGCRX(lsock)) |
+				 mk_int_int_mask(s->hwirq) << 24);
 			/*
 			 * Strange thing here:
 			 * The manual does not tell us which interrupt
@@ -897,33 +907,32 @@ static int m8xx_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
 			 * have to be cleared in PSCR in the interrupt handler.
 			 */
 			reg |= M8XX_PCMCIA_RDY_L(lsock);
-		}
-		else
-			out_be32(M8XX_PGCRX(lsock), in_be32(M8XX_PGCRX(lsock)) & 0x00ffffff);
-	}
-	else {
+		} else
+			out_be32(M8XX_PGCRX(lsock),
+				 in_be32(M8XX_PGCRX(lsock)) & 0x00ffffff);
+	} else {
 		/*
 		 * Memory card
 		 */
-		if(state->csc_mask & SS_BATDEAD) {
+		if (state->csc_mask & SS_BATDEAD) {
 			e->eventbit = SS_BATDEAD;
 			reg |= e->regbit = M8XX_PCMCIA_BVD1(lsock);
 			e++;
 		}
-		if(state->csc_mask & SS_BATWARN) {
+		if (state->csc_mask & SS_BATWARN) {
 			e->eventbit = SS_BATWARN;
 			reg |= e->regbit = M8XX_PCMCIA_BVD2(lsock);
 			e++;
 		}
 		/* What should I trigger on - low/high,raise,fall? */
-		if(state->csc_mask & SS_READY) {
+		if (state->csc_mask & SS_READY) {
 			e->eventbit = SS_READY;
-			reg |= e->regbit = 0; //??
+			reg |= e->regbit = 0;	//??
 			e++;
 		}
 	}
 
-	e->regbit = 0;  /* terminate list */
+	e->regbit = 0;		/* terminate list */
 
 	/*
 	 * Clear the status changed .
@@ -940,7 +949,9 @@ static int m8xx_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
 	 * Ones will enable the interrupt.
 	 */
 
-	reg |= in_be32(&pcmcia->pcmc_per) & (M8XX_PCMCIA_MASK(0) | M8XX_PCMCIA_MASK(1));
+	reg |=
+	    in_be32(&pcmcia->
+		    pcmc_per) & (M8XX_PCMCIA_MASK(0) | M8XX_PCMCIA_MASK(1));
 	out_be32(&pcmcia->pcmc_per, reg);
 
 	spin_unlock_irqrestore(&events_lock, flags);
@@ -961,67 +972,66 @@ static int m8xx_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *io)
 	unsigned int reg, winnr;
 	pcmconf8xx_t *pcmcia = s->pcmcia;
 
-
 #define M8XX_SIZE (io->stop - io->start + 1)
 #define M8XX_BASE (PCMCIA_IO_WIN_BASE + io->start)
 
-	dprintk( "SetIOMap(%d, %d, %#2.2x, %d ns, "
-	      "%#4.4x-%#4.4x)\n", lsock, io->map, io->flags,
-	      io->speed, io->start, io->stop);
+	dprintk("SetIOMap(%d, %d, %#2.2x, %d ns, "
+		"%#4.4x-%#4.4x)\n", lsock, io->map, io->flags,
+		io->speed, io->start, io->stop);
 
 	if ((io->map >= PCMCIA_IO_WIN_NO) || (io->start > 0xffff)
 	    || (io->stop > 0xffff) || (io->stop < io->start))
 		return -EINVAL;
 
-	if((reg = m8xx_get_graycode(M8XX_SIZE)) == -1)
+	if ((reg = m8xx_get_graycode(M8XX_SIZE)) == -1)
 		return -EINVAL;
 
-	if(io->flags & MAP_ACTIVE) {
+	if (io->flags & MAP_ACTIVE) {
 
-		dprintk( "io->flags & MAP_ACTIVE\n");
+		dprintk("io->flags & MAP_ACTIVE\n");
 
 		winnr = (PCMCIA_MEM_WIN_NO * PCMCIA_SOCKETS_NO)
-			+ (lsock * PCMCIA_IO_WIN_NO) + io->map;
+		    + (lsock * PCMCIA_IO_WIN_NO) + io->map;
 
 		/* setup registers */
 
-		w = (void *) &pcmcia->pcmc_pbr0;
+		w = (void *)&pcmcia->pcmc_pbr0;
 		w += winnr;
 
-		out_be32(&w->or, 0); /* turn off window first */
+		out_be32(&w->or, 0);	/* turn off window first */
 		out_be32(&w->br, M8XX_BASE);
 
 		reg <<= 27;
-  		reg |= M8XX_PCMCIA_POR_IO |(lsock << 2);
+		reg |= M8XX_PCMCIA_POR_IO | (lsock << 2);
 
 		reg |= m8xx_get_speed(io->speed, 1, s->bus_freq);
 
-		if(io->flags & MAP_WRPROT)
+		if (io->flags & MAP_WRPROT)
 			reg |= M8XX_PCMCIA_POR_WRPROT;
 
-		/*if(io->flags & (MAP_16BIT | MAP_AUTOSZ))*/
-		if(io->flags & MAP_16BIT)
+		/*if(io->flags & (MAP_16BIT | MAP_AUTOSZ)) */
+		if (io->flags & MAP_16BIT)
 			reg |= M8XX_PCMCIA_POR_16BIT;
 
-		if(io->flags & MAP_ACTIVE)
+		if (io->flags & MAP_ACTIVE)
 			reg |= M8XX_PCMCIA_POR_VALID;
 
 		out_be32(&w->or, reg);
 
 		dprintk("Socket %u: Mapped io window %u at %#8.8x, "
-		      "OR = %#8.8x.\n", lsock, io->map, w->br, w->or);
+			"OR = %#8.8x.\n", lsock, io->map, w->br, w->or);
 	} else {
 		/* shutdown IO window */
 		winnr = (PCMCIA_MEM_WIN_NO * PCMCIA_SOCKETS_NO)
-			+ (lsock * PCMCIA_IO_WIN_NO) + io->map;
+		    + (lsock * PCMCIA_IO_WIN_NO) + io->map;
 
 		/* setup registers */
 
-		w = (void *) &pcmcia->pcmc_pbr0;
+		w = (void *)&pcmcia->pcmc_pbr0;
 		w += winnr;
 
-		out_be32(&w->or, 0); /* turn off window */
-		out_be32(&w->br, 0); /* turn off base address */
+		out_be32(&w->or, 0);	/* turn off window */
+		out_be32(&w->br, 0);	/* turn off base address */
 
 		dprintk("Socket %u: Unmapped io window %u at %#8.8x, "
 			"OR = %#8.8x.\n", lsock, io->map, w->br, w->or);
@@ -1029,15 +1039,14 @@ static int m8xx_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *io)
 
 	/* copy the struct and modify the copy */
 	s->io_win[io->map] = *io;
-	s->io_win[io->map].flags &= (MAP_WRPROT
-				     | MAP_16BIT
-				     | MAP_ACTIVE);
+	s->io_win[io->map].flags &= (MAP_WRPROT | MAP_16BIT | MAP_ACTIVE);
 	dprintk("SetIOMap exit\n");
 
 	return 0;
 }
 
-static int m8xx_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *mem)
+static int m8xx_set_mem_map(struct pcmcia_socket *sock,
+			    struct pccard_mem_map *mem)
 {
 	int lsock = container_of(sock, struct socket_info, socket)->slot;
 	struct socket_info *s = &socket[lsock];
@@ -1046,19 +1055,19 @@ static int m8xx_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *m
 	unsigned int reg, winnr;
 	pcmconf8xx_t *pcmcia = s->pcmcia;
 
-	dprintk( "SetMemMap(%d, %d, %#2.2x, %d ns, "
-	      "%#5.5lx, %#5.5x)\n", lsock, mem->map, mem->flags,
-	      mem->speed, mem->static_start, mem->card_start);
+	dprintk("SetMemMap(%d, %d, %#2.2x, %d ns, "
+		"%#5.5lx, %#5.5x)\n", lsock, mem->map, mem->flags,
+		mem->speed, mem->static_start, mem->card_start);
 
 	if ((mem->map >= PCMCIA_MEM_WIN_NO)
-//	    || ((mem->s) >= PCMCIA_MEM_WIN_SIZE)
+//          || ((mem->s) >= PCMCIA_MEM_WIN_SIZE)
 	    || (mem->card_start >= 0x04000000)
-	    || (mem->static_start & 0xfff)                /* 4KByte resolution */
-	    || (mem->card_start & 0xfff))
+	    || (mem->static_start & 0xfff)	/* 4KByte resolution */
+	    ||(mem->card_start & 0xfff))
 		return -EINVAL;
 
-	if((reg = m8xx_get_graycode(PCMCIA_MEM_WIN_SIZE)) == -1) {
-		printk( "Cannot set size to 0x%08x.\n", PCMCIA_MEM_WIN_SIZE);
+	if ((reg = m8xx_get_graycode(PCMCIA_MEM_WIN_SIZE)) == -1) {
+		printk("Cannot set size to 0x%08x.\n", PCMCIA_MEM_WIN_SIZE);
 		return -EINVAL;
 	}
 	reg <<= 27;
@@ -1067,50 +1076,47 @@ static int m8xx_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *m
 
 	/* Setup the window in the pcmcia controller */
 
-	w = (void *) &pcmcia->pcmc_pbr0;
+	w = (void *)&pcmcia->pcmc_pbr0;
 	w += winnr;
 
 	reg |= lsock << 2;
 
 	reg |= m8xx_get_speed(mem->speed, 0, s->bus_freq);
 
-	if(mem->flags & MAP_ATTRIB)
-		reg |=  M8XX_PCMCIA_POR_ATTRMEM;
+	if (mem->flags & MAP_ATTRIB)
+		reg |= M8XX_PCMCIA_POR_ATTRMEM;
 
-	if(mem->flags & MAP_WRPROT)
+	if (mem->flags & MAP_WRPROT)
 		reg |= M8XX_PCMCIA_POR_WRPROT;
 
-	if(mem->flags & MAP_16BIT)
+	if (mem->flags & MAP_16BIT)
 		reg |= M8XX_PCMCIA_POR_16BIT;
 
-	if(mem->flags & MAP_ACTIVE)
+	if (mem->flags & MAP_ACTIVE)
 		reg |= M8XX_PCMCIA_POR_VALID;
 
 	out_be32(&w->or, reg);
 
 	dprintk("Socket %u: Mapped memory window %u at %#8.8x, "
-	      "OR = %#8.8x.\n", lsock, mem->map, w->br, w->or);
+		"OR = %#8.8x.\n", lsock, mem->map, w->br, w->or);
 
-	if(mem->flags & MAP_ACTIVE) {
+	if (mem->flags & MAP_ACTIVE) {
 		/* get the new base address */
 		mem->static_start = PCMCIA_MEM_WIN_BASE +
-			(PCMCIA_MEM_WIN_SIZE * winnr)
-			+ mem->card_start;
+		    (PCMCIA_MEM_WIN_SIZE * winnr)
+		    + mem->card_start;
 	}
 
 	dprintk("SetMemMap(%d, %d, %#2.2x, %d ns, "
-	      "%#5.5lx, %#5.5x)\n", lsock, mem->map, mem->flags,
-	      mem->speed, mem->static_start, mem->card_start);
+		"%#5.5lx, %#5.5x)\n", lsock, mem->map, mem->flags,
+		mem->speed, mem->static_start, mem->card_start);
 
 	/* copy the struct and modify the copy */
 
 	old = &s->mem_win[mem->map];
 
 	*old = *mem;
-	old->flags &= (MAP_ATTRIB
-		       | MAP_WRPROT
-		       | MAP_16BIT
-		       | MAP_ACTIVE);
+	old->flags &= (MAP_ATTRIB | MAP_WRPROT | MAP_16BIT | MAP_ACTIVE);
 
 	return 0;
 }
@@ -1121,7 +1127,7 @@ static int m8xx_sock_init(struct pcmcia_socket *sock)
 	pccard_io_map io = { 0, 0, 0, 0, 1 };
 	pccard_mem_map mem = { 0, 0, 0, 0, 0, 0 };
 
-	dprintk( "sock_init(%d)\n", s);
+	dprintk("sock_init(%d)\n", s);
 
 	m8xx_set_socket(sock, &dead_socket);
 	for (i = 0; i < PCMCIA_IO_WIN_NO; i++) {
@@ -1143,7 +1149,7 @@ static int m8xx_sock_suspend(struct pcmcia_socket *sock)
 }
 
 static struct pccard_operations m8xx_services = {
-	.init	= m8xx_sock_init,
+	.init = m8xx_sock_init,
 	.suspend = m8xx_sock_suspend,
 	.get_status = m8xx_get_status,
 	.set_socket = m8xx_set_socket,
@@ -1151,7 +1157,8 @@ static struct pccard_operations m8xx_services = {
 	.set_mem_map = m8xx_set_mem_map,
 };
 
-static int __init m8xx_probe(struct of_device *ofdev, const struct of_device_id *match)
+static int __init m8xx_probe(struct of_device *ofdev,
+			     const struct of_device_id *match)
 {
 	struct pcmcia_win *w;
 	unsigned int i, m, hwirq;
@@ -1162,49 +1169,50 @@ static int __init m8xx_probe(struct of_device *ofdev, const struct of_device_id
 	pcmcia_info("%s\n", version);
 
 	pcmcia = of_iomap(np, 0);
-	if(pcmcia == NULL)
+	if (pcmcia == NULL)
 		return -EINVAL;
 
 	pcmcia_schlvl = irq_of_parse_and_map(np, 0);
-	hwirq  = irq_map[pcmcia_schlvl].hwirq;
+	hwirq = irq_map[pcmcia_schlvl].hwirq;
 	if (pcmcia_schlvl < 0)
 		return -EINVAL;
 
 	m8xx_pgcrx[0] = &pcmcia->pcmc_pgcra;
 	m8xx_pgcrx[1] = &pcmcia->pcmc_pgcrb;
 
-
 	pcmcia_info(PCMCIA_BOARD_MSG " using " PCMCIA_SLOT_MSG
 		    " with IRQ %u  (%d). \n", pcmcia_schlvl, hwirq);
 
 	/* Configure Status change interrupt */
 
-	if(request_irq(pcmcia_schlvl, m8xx_interrupt, IRQF_SHARED,
-			  driver_name, socket)) {
+	if (request_irq(pcmcia_schlvl, m8xx_interrupt, IRQF_SHARED,
+			driver_name, socket)) {
 		pcmcia_error("Cannot allocate IRQ %u for SCHLVL!\n",
 			     pcmcia_schlvl);
 		return -1;
 	}
 
-	w = (void *) &pcmcia->pcmc_pbr0;
+	w = (void *)&pcmcia->pcmc_pbr0;
 
-	out_be32(&pcmcia->pcmc_pscr, M8XX_PCMCIA_MASK(0)| M8XX_PCMCIA_MASK(1));
+	out_be32(&pcmcia->pcmc_pscr, M8XX_PCMCIA_MASK(0) | M8XX_PCMCIA_MASK(1));
 	clrbits32(&pcmcia->pcmc_per, M8XX_PCMCIA_MASK(0) | M8XX_PCMCIA_MASK(1));
 
 	/* connect interrupt and disable CxOE */
 
-	out_be32(M8XX_PGCRX(0), M8XX_PGCRX_CXOE | (mk_int_int_mask(hwirq) << 16));
-	out_be32(M8XX_PGCRX(1), M8XX_PGCRX_CXOE | (mk_int_int_mask(hwirq) << 16));
+	out_be32(M8XX_PGCRX(0),
+		 M8XX_PGCRX_CXOE | (mk_int_int_mask(hwirq) << 16));
+	out_be32(M8XX_PGCRX(1),
+		 M8XX_PGCRX_CXOE | (mk_int_int_mask(hwirq) << 16));
 
 	/* intialize the fixed memory windows */
 
-	for(i = 0; i < PCMCIA_SOCKETS_NO; i++){
+	for (i = 0; i < PCMCIA_SOCKETS_NO; i++) {
 		for (m = 0; m < PCMCIA_MEM_WIN_NO; m++) {
 			out_be32(&w->br, PCMCIA_MEM_WIN_BASE +
-				(PCMCIA_MEM_WIN_SIZE
-				 * (m + i * PCMCIA_MEM_WIN_NO)));
+				 (PCMCIA_MEM_WIN_SIZE
+				  * (m + i * PCMCIA_MEM_WIN_NO)));
 
-			out_be32(&w->or, 0);  /* set to not valid */
+			out_be32(&w->or, 0);	/* set to not valid */
 
 			w++;
 		}
@@ -1218,10 +1226,11 @@ static int __init m8xx_probe(struct of_device *ofdev, const struct of_device_id
 	hardware_enable(0);
 	hardware_enable(1);
 
-	for (i = 0 ; i < PCMCIA_SOCKETS_NO; i++) {
+	for (i = 0; i < PCMCIA_SOCKETS_NO; i++) {
 		socket[i].slot = i;
 		socket[i].socket.owner = THIS_MODULE;
-		socket[i].socket.features = SS_CAP_PCCARD | SS_CAP_MEM_ALIGN | SS_CAP_STATIC_MAP;
+		socket[i].socket.features =
+		    SS_CAP_PCCARD | SS_CAP_MEM_ALIGN | SS_CAP_STATIC_MAP;
 		socket[i].socket.irq_mask = 0x000;
 		socket[i].socket.map_size = 0x1000;
 		socket[i].socket.io_offset = 0;
@@ -1234,7 +1243,6 @@ static int __init m8xx_probe(struct of_device *ofdev, const struct of_device_id
 		socket[i].bus_freq = ppc_proc_freq;
 		socket[i].hwirq = hwirq;
 
-
 	}
 
 	for (i = 0; i < PCMCIA_SOCKETS_NO; i++) {
@@ -1246,25 +1254,25 @@ static int __init m8xx_probe(struct of_device *ofdev, const struct of_device_id
 	return 0;
 }
 
-static int m8xx_remove(struct of_device* ofdev)
+static int m8xx_remove(struct of_device *ofdev)
 {
 	u32 m, i;
 	struct pcmcia_win *w;
 	pcmconf8xx_t *pcmcia = socket[0].pcmcia;
 
 	for (i = 0; i < PCMCIA_SOCKETS_NO; i++) {
-		w = (void *) &pcmcia->pcmc_pbr0;
+		w = (void *)&pcmcia->pcmc_pbr0;
 
 		out_be32(&pcmcia->pcmc_pscr, M8XX_PCMCIA_MASK(i));
 		out_be32(&pcmcia->pcmc_per,
-			in_be32(&pcmcia->pcmc_per) & ~M8XX_PCMCIA_MASK(i));
+			 in_be32(&pcmcia->pcmc_per) & ~M8XX_PCMCIA_MASK(i));
 
 		/* turn off interrupt and disable CxOE */
 		out_be32(M8XX_PGCRX(i), M8XX_PGCRX_CXOE);
 
 		/* turn off memory windows */
 		for (m = 0; m < PCMCIA_MEM_WIN_NO; m++) {
-			out_be32(&w->or, 0); /* set to not valid */
+			out_be32(&w->or, 0);	/* set to not valid */
 			w++;
 		}
 
@@ -1299,21 +1307,21 @@ static int m8xx_resume(struct platform_device *pdev)
 
 static struct of_device_id m8xx_pcmcia_match[] = {
 	{
-		.type = "pcmcia",
-		.compatible = "fsl,pq-pcmcia",
-	},
+	 .type = "pcmcia",
+	 .compatible = "fsl,pq-pcmcia",
+	 },
 	{},
 };
 
 MODULE_DEVICE_TABLE(of, m8xx_pcmcia_match);
 
 static struct of_platform_driver m8xx_pcmcia_driver = {
-	.name		= (char *) driver_name,
-	.match_table	= m8xx_pcmcia_match,
-	.probe		= m8xx_probe,
-	.remove		= m8xx_remove,
-	.suspend	= m8xx_suspend,
-	.resume		= m8xx_resume,
+	.name = (char *)driver_name,
+	.match_table = m8xx_pcmcia_match,
+	.probe = m8xx_probe,
+	.remove = m8xx_remove,
+	.suspend = m8xx_suspend,
+	.resume = m8xx_resume,
 };
 
 static int __init m8xx_init(void)

^ permalink raw reply related

* [PATCH 3/3] [POWERPC] dts: kill hardcoded phandles
From: Vitaly Bordug @ 2007-05-08  5:48 UTC (permalink / raw)
  To: linux-pcmcia; +Cc: linuxppc-dev, linux-kernel
In-Reply-To: <20070508053049.18428.50622.stgit@localhost.localdomain>


Removed explicit linux,phandle usage. Using references and labels now in
PQ and PQ2 boards currently supported in arch/powerpc.
Signed-off-by: Vitaly Bordug <vitb@kernel.crashing.org>

---

 arch/powerpc/boot/dts/mpc8272ads.dts |   42 ++++++++++++----------------------
 arch/powerpc/boot/dts/mpc866ads.dts  |   31 +++++++++----------------
 arch/powerpc/boot/dts/mpc885ads.dts  |    2 +-
 3 files changed, 27 insertions(+), 48 deletions(-)

diff --git a/arch/powerpc/boot/dts/mpc8272ads.dts b/arch/powerpc/boot/dts/mpc8272ads.dts
index 423eedc..83461fe 100644
--- a/arch/powerpc/boot/dts/mpc8272ads.dts
+++ b/arch/powerpc/boot/dts/mpc8272ads.dts
@@ -14,12 +14,10 @@
        compatible = "MPC8260ADS";
        #address-cells = <1>;
        #size-cells = <1>;
-       linux,phandle = <100>;
 
        cpus {
                #address-cells = <1>;
                #size-cells = <0>;
-               linux,phandle = <200>;
 
                PowerPC,8272@0 {
                        device_type = "cpu";
@@ -32,12 +30,10 @@
                        bus-frequency = <0>;
                        clock-frequency = <0>;
                        32-bit;
-                       linux,phandle = <201>;
                };
        };
 
-       interrupt-controller@f8200000 {
-               linux,phandle = <f8200000>;
+		pci_pic:interrupt-controller@f8200000 {
                #address-cells = <0>;
                #interrupt-cells = <2>;
                interrupt-controller;
@@ -47,15 +43,13 @@
        };
        memory {
                device_type = "memory";
-               linux,phandle = <300>;
                reg = <00000000 4000000 f4500000 00000020>;
        };
 
        chosen {
                name = "chosen";
                linux,platform = <0>;
-               interrupt-controller = <10c00>;
-               linux,phandle = <400>;
+		interrupt-controller = <&cpm_pic>;
        };
 
        soc8272@f0000000 {
@@ -70,20 +64,17 @@
                        device_type = "mdio";
                        compatible = "fs_enet";
                        reg = <0 0>;
-                       linux,phandle = <24520>;
                        #address-cells = <1>;
                        #size-cells = <0>;
-                       ethernet-phy@0 {
-                               linux,phandle = <2452000>;
-                               interrupt-parent = <10c00>;
+			phy0:ethernet-phy@0 {
+				interrupt-parent = <&cpm_pic>;
                                interrupts = <17 4>;
                                reg = <0>;
                                bitbang = [ 12 12 13 02 02 01 ];
                                device_type = "ethernet-phy";
                        };
-                       ethernet-phy@1 {
-                               linux,phandle = <2452001>;
-                               interrupt-parent = <10c00>;
+			phy1:ethernet-phy@1 {
+				interrupt-parent = <&cpm_pic>;
                                interrupts = <17 4>;
                                bitbang = [ 12 12 13 02 02 01 ];
                                reg = <3>;
@@ -101,8 +92,8 @@
                        reg = <11300 20 8400 100 11380 30>;
                        mac-address = [ 00 11 2F 99 43 54 ];
                        interrupts = <20 2>;
-                       interrupt-parent = <10c00>;
-                       phy-handle = <2452000>;
+			interrupt-parent = <&cpm_pic>;
+			phy-handle = <&phy0>;
                        rx-clock = <13>;
                        tx-clock = <12>;
                };
@@ -115,14 +106,13 @@
                        reg = <11320 20 8500 100 113b0 30>;
                        mac-address = [ 00 11 2F 99 44 54 ];
                        interrupts = <21 2>;
-                       interrupt-parent = <10c00>;
-                       phy-handle = <2452001>;
+			interrupt-parent = <&cpm_pic>;
+			phy-handle = <&phy1>;
                        rx-clock = <17>;
                        tx-clock = <18>;
                };
 
                cpm@f0000000 {
-                       linux,phandle = <f0000000>;
                        #address-cells = <1>;
                        #size-cells = <1>;
                        #interrupt-cells = <2>;
@@ -142,7 +132,7 @@
                                reg = <11a00 20 8000 100>;
                                current-speed = <1c200>;
                                interrupts = <28 2>;
-                               interrupt-parent = <10c00>;
+				interrupt-parent = <&cpm_pic>;
                                clock-setup = <0 00ffffff>;
                                rx-clock = <1>;
                                tx-clock = <1>;
@@ -156,15 +146,14 @@
                                reg = <11a60 20 8300 100>;
                                current-speed = <1c200>;
                                interrupts = <2b 2>;
-                               interrupt-parent = <10c00>;
+				interrupt-parent = <&cpm_pic>;
                                clock-setup = <1b ffffff00>;
                                rx-clock = <4>;
                                tx-clock = <4>;
                        };
 
                };
-               interrupt-controller@10c00 {
-                       linux,phandle = <10c00>;
+			cpm_pic:interrupt-controller@10c00 {
                        #address-cells = <0>;
                        #interrupt-cells = <2>;
                        interrupt-controller;
@@ -174,7 +163,6 @@
 		       compatible = "CPM2";
                };
                pci@0500 {
-                       linux,phandle = <0500>;
                        #interrupt-cells = <1>;
                        #size-cells = <2>;
                        #address-cells = <3>;
@@ -202,7 +190,7 @@
                                         c000 0 0 2 f8200000 43 8
                                         c000 0 0 3 f8200000 40 8
                                         c000 0 0 4 f8200000 41 8>;
-                       interrupt-parent = <10c00>;
+			interrupt-parent = <&cpm_pic>;
                        interrupts = <14 8>;
                        bus-range = <0 0>;
                        ranges = <02000000 0 80000000 80000000 0 40000000
@@ -216,7 +204,7 @@
                        compatible = "talitos";
                        reg = <30000 10000>;
                        interrupts = <b 2>;
-                       interrupt-parent = <10c00>;
+			interrupt-parent = <&cpm_pic>;
                        num-channels = <4>;
                        channel-fifo-len = <18>;
                        exec-units-mask = <0000007e>;
diff --git a/arch/powerpc/boot/dts/mpc866ads.dts b/arch/powerpc/boot/dts/mpc866ads.dts
index c0d06fd..6dd749e 100644
--- a/arch/powerpc/boot/dts/mpc866ads.dts
+++ b/arch/powerpc/boot/dts/mpc866ads.dts
@@ -15,12 +15,10 @@
 	compatible = "mpc8xx";
 	#address-cells = <1>;
 	#size-cells = <1>;
-	linux,phandle = <100>;
 
 	cpus {
 		#address-cells = <1>;
 		#size-cells = <0>;
-		linux,phandle = <200>;
 
 		PowerPC,866@0 {
 			device_type = "cpu";
@@ -34,14 +32,12 @@
 			clock-frequency = <0>;
 			32-bit;
 			interrupts = <f 2>;	// decrementer interrupt
-			interrupt-parent = <ff000000>;
-			linux,phandle = <201>;
+			interrupt-parent = <&mpc8xx_pic>;
 		};
 	};
 
 	memory {
 		device_type = "memory";
-		linux,phandle = <300>;
 		reg = <00000000 800000>;
 	};
 
@@ -57,11 +53,9 @@
 			device_type = "mdio";
 			compatible = "fs_enet";
 			reg = <e80 8>;
-			linux,phandle = <e80>;
 			#address-cells = <1>;
 			#size-cells = <0>;
-			ethernet-phy@f {
-				linux,phandle = <e800f>;
+			phy:ethernet-phy@f {
 				reg = <f>;
 				device_type = "ethernet-phy";
 			};
@@ -75,12 +69,11 @@
 			reg = <e00 188>;
 			mac-address = [ 00 00 0C 00 01 FD ];
 			interrupts = <3 1>;
-			interrupt-parent = <ff000000>;
-			phy-handle = <e800f>;
+			interrupt-parent = <&mpc8xx_pic>;
+			phy-handle = <&phy>;
 		};
 
-		pic@ff000000 {
-			linux,phandle = <ff000000>;
+		mpc8xx_pic:pic@ff000000 {
 			interrupt-controller;
 			#address-cells = <0>;
 			#interrupt-cells = <2>;
@@ -91,7 +84,6 @@
 		};
 
 		cpm@ff000000 {
-			linux,phandle = <ff000000>;
 			#address-cells = <1>;
 			#size-cells = <1>;
 			#interrupt-cells = <2>;
@@ -102,15 +94,14 @@
 			command-proc = <9c0>;
 			brg-frequency = <0>;
 			interrupts = <0 2>;	// cpm error interrupt
-			interrupt-parent = <930>;
+			interrupt-parent = <&cpm_pic>;
 
-			pic@930 {
-				linux,phandle = <930>;
+			cpm_pic:pic@930 {
 				interrupt-controller;
 				#address-cells = <0>;
 				#interrupt-cells = <2>;
 				interrupts = <5 2 0 2>;
-				interrupt-parent = <ff000000>;
+				interrupt-parent = <&mpc8xx_pic>;
 				reg = <930 20>;
 				built-in;
 				device_type = "cpm-pic";
@@ -128,7 +119,7 @@
 				tx-clock = <1>;
 				current-speed = <0>;
 				interrupts = <4 3>;
-				interrupt-parent = <930>;
+				interrupt-parent = <&cpm_pic>;
 			};
 
 			smc@a90 {
@@ -142,7 +133,7 @@
 				tx-clock = <2>;
 				current-speed = <0>;
 				interrupts = <3 3>;
-				interrupt-parent = <930>;
+				interrupt-parent = <&cpm_pic>;
 			};
 
 			scc@a00 {
@@ -153,7 +144,7 @@
 				reg = <a00 18 3c00 80>;
 				mac-address = [ 00 00 0C 00 03 FD ];
 				interrupts = <1e 3>;
-				interrupt-parent = <930>;
+				interrupt-parent = <&cpm_pic>;
 			};
 		};
 	};
diff --git a/arch/powerpc/boot/dts/mpc885ads.dts b/arch/powerpc/boot/dts/mpc885ads.dts
index 9e937df..b292e92 100644
--- a/arch/powerpc/boot/dts/mpc885ads.dts
+++ b/arch/powerpc/boot/dts/mpc885ads.dts
@@ -121,7 +121,7 @@
 			reg = <80 80>;
 			ranges=<0>;
 			clock-frequency = <2faf080>;
-			interrupt-parent = <&mpc8xx-pic>;
+			interrupt-parent = <ff000000>;
 			interrupts = <d 1>;
 		};
 

^ permalink raw reply related

* [PATCH 1/3] [POWERPC] 8xx: mpc885ads pcmcia support
From: Vitaly Bordug @ 2007-05-08  5:48 UTC (permalink / raw)
  To: linux-pcmcia; +Cc: linuxppc-dev, linux-kernel
In-Reply-To: <20070508053049.18428.50622.stgit@localhost.localdomain>


Adds support for PowerQuicc on-chip PCMCIA. The driver is implemented as
of_device, so only arch/powerpc stuff is capable to use it, which now
implies only mpc885ads reference board.

To cope with the code that should be hooked inside driver, but is really
board specific (like set_voltage), global structure mpc8xx_pcmcia_ops
holds necessary function pointers that are filled in the BSP code.

Signed-off-by: Vitaly Bordug <vitb@kernel.crashing.org>
Acked-by: Arnd Bergmann <arnd@arndb.de>

---

 arch/powerpc/boot/dts/mpc885ads.dts          |   13 +
 arch/powerpc/platforms/8xx/m8xx_setup.c      |    5 
 arch/powerpc/platforms/8xx/mpc885ads.h       |    8 +
 arch/powerpc/platforms/8xx/mpc885ads_setup.c |   76 ++++++
 arch/powerpc/sysdev/fsl_soc.c                |   13 +
 arch/powerpc/sysdev/mpc8xx_pic.h             |    2 
 drivers/pcmcia/Kconfig                       |    1 
 drivers/pcmcia/m8xx_pcmcia.c                 |  351 ++++++++++++--------------
 include/asm-powerpc/mpc8xx.h                 |    4 
 include/linux/fsl_devices.h                  |    5 
 10 files changed, 293 insertions(+), 185 deletions(-)

diff --git a/arch/powerpc/boot/dts/mpc885ads.dts b/arch/powerpc/boot/dts/mpc885ads.dts
index 110bf61..9e937df 100644
--- a/arch/powerpc/boot/dts/mpc885ads.dts
+++ b/arch/powerpc/boot/dts/mpc885ads.dts
@@ -112,6 +112,19 @@
 			compatible = "CPM";
 		};
 
+		pcmcia@0080 {
+			#address-cells = <3>;
+			#interrupt-cells = <1>;
+			#size-cells = <2>;
+			compatible = "fsl,pq-pcmcia";
+			device_type = "pcmcia";
+			reg = <80 80>;
+			ranges=<0>;
+			clock-frequency = <2faf080>;
+			interrupt-parent = <&mpc8xx-pic>;
+			interrupts = <d 1>;
+		};
+
 		cpm@ff000000 {
 			linux,phandle = <ff000000>;
 			#address-cells = <1>;
diff --git a/arch/powerpc/platforms/8xx/m8xx_setup.c b/arch/powerpc/platforms/8xx/m8xx_setup.c
index 0901dba..f169355 100644
--- a/arch/powerpc/platforms/8xx/m8xx_setup.c
+++ b/arch/powerpc/platforms/8xx/m8xx_setup.c
@@ -32,6 +32,7 @@
 #include <linux/root_dev.h>
 #include <linux/time.h>
 #include <linux/rtc.h>
+#include <linux/fsl_devices.h>
 
 #include <asm/mmu.h>
 #include <asm/reg.h>
@@ -49,6 +50,10 @@
 
 #include "sysdev/mpc8xx_pic.h"
 
+#ifdef CONFIG_PCMCIA_M8XX
+struct mpc8xx_pcmcia_ops m8xx_pcmcia_ops;
+#endif
+
 void m8xx_calibrate_decr(void);
 extern void m8xx_wdt_handler_install(bd_t *bp);
 extern int cpm_pic_init(void);
diff --git a/arch/powerpc/platforms/8xx/mpc885ads.h b/arch/powerpc/platforms/8xx/mpc885ads.h
index 7c31aec..932b59a 100644
--- a/arch/powerpc/platforms/8xx/mpc885ads.h
+++ b/arch/powerpc/platforms/8xx/mpc885ads.h
@@ -91,5 +91,13 @@
 #define SICR_ENET_MASK	((uint)0x00ff0000)
 #define SICR_ENET_CLKRT	((uint)0x002c0000)
 
+/* 
+ * Some internal interrupt registers use an 8-bit mask for the interrupt
+ * level instead of a number.
+ */
+static inline uint mk_int_int_mask(uint mask) {
+	return (1 << (7 - (mask/2)));
+}
+
 #endif /* __ASM_MPC885ADS_H__ */
 #endif /* __KERNEL__ */
diff --git a/arch/powerpc/platforms/8xx/mpc885ads_setup.c b/arch/powerpc/platforms/8xx/mpc885ads_setup.c
index a57b577..4e76e1c 100644
--- a/arch/powerpc/platforms/8xx/mpc885ads_setup.c
+++ b/arch/powerpc/platforms/8xx/mpc885ads_setup.c
@@ -22,6 +22,7 @@
 
 #include <linux/fs_enet_pd.h>
 #include <linux/fs_uart_pd.h>
+#include <linux/fsl_devices.h>
 #include <linux/mii.h>
 
 #include <asm/delay.h>
@@ -51,6 +52,11 @@ static void init_smc1_uart_ioports(struct fs_uart_platform_info* fpi);
 static void init_smc2_uart_ioports(struct fs_uart_platform_info* fpi);
 static void init_scc3_ioports(struct fs_platform_info* ptr);
 
+#ifdef CONFIG_PCMCIA_M8XX
+static void pcmcia_hw_setup(int slot, int enable);
+static int pcmcia_set_voltage(int slot, int vcc, int vpp);
+#endif
+
 void __init mpc885ads_board_setup(void)
 {
 	cpm8xx_t *cp;
@@ -115,6 +121,12 @@ void __init mpc885ads_board_setup(void)
 	immr_unmap(io_port);
 
 #endif
+
+#ifdef CONFIG_PCMCIA_M8XX
+	/*Set up board specific hook-ups*/
+	m8xx_pcmcia_ops.hw_ctrl = pcmcia_hw_setup;
+	m8xx_pcmcia_ops.voltage_set = pcmcia_set_voltage;
+#endif
 }
 
 
@@ -322,6 +334,70 @@ void init_smc_ioports(struct fs_uart_platform_info *data)
 	}
 }
 
+#ifdef CONFIG_PCMCIA_M8XX
+static void pcmcia_hw_setup(int slot, int enable)
+{
+	unsigned *bcsr_io;
+
+	bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
+	if (enable)
+		clrbits32(bcsr_io, BCSR1_PCCEN);
+	else
+		setbits32(bcsr_io, BCSR1_PCCEN);
+
+	iounmap(bcsr_io);
+}
+
+static int pcmcia_set_voltage(int slot, int vcc, int vpp)
+{
+	u32 reg = 0;
+	unsigned *bcsr_io;
+
+	bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
+
+	switch(vcc) {
+	case 0:
+		break;
+	case 33:
+		reg |= BCSR1_PCCVCC0;
+		break;
+	case 50:
+		reg |= BCSR1_PCCVCC1;
+		break;
+	default:
+		return 1;
+	}
+
+	switch(vpp) {
+	case 0:
+       	break;
+	case 33:
+	case 50:
+       	if(vcc == vpp)
+			reg |= BCSR1_PCCVPP1;
+		else
+			return 1;
+		break;
+	case 120:
+	if ((vcc == 33) || (vcc == 50))
+		reg |= BCSR1_PCCVPP0;
+	else
+		return 1;
+	default:
+		return 1;
+	}
+
+	/* first, turn off all power */
+	clrbits32(bcsr_io, 0x00610000);
+
+	/* enable new powersettings */
+	setbits32(bcsr_io, reg);
+
+	iounmap(bcsr_io);
+	return 0;
+}
+#endif
+
 int platform_device_skip(const char *model, int id)
 {
 #ifdef CONFIG_MPC8xx_SECOND_ETH_SCC3
diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c
index 8a123c7..880e45f 100644
--- a/arch/powerpc/sysdev/fsl_soc.c
+++ b/arch/powerpc/sysdev/fsl_soc.c
@@ -1028,6 +1028,19 @@ err:
 
 arch_initcall(fs_enet_of_init);
 
+static int __init fsl_pcmcia_of_init(void)
+{
+	struct device_node *np = NULL;
+	/*
+	 * Register all the devices which type is "pcmcia"
+	 */
+	while ((np = of_find_compatible_node(np, 
+			"pcmcia", "fsl,pq-pcmcia")) != NULL)
+			    of_platform_device_create(np, "m8xx-pcmcia", NULL);
+	return 0;
+}
+
+arch_initcall(fsl_pcmcia_of_init);
 
 static const char *smc_regs = "regs";
 static const char *smc_pram = "pram";
diff --git a/arch/powerpc/sysdev/mpc8xx_pic.h b/arch/powerpc/sysdev/mpc8xx_pic.h
index afa2ee6..07be061 100644
--- a/arch/powerpc/sysdev/mpc8xx_pic.h
+++ b/arch/powerpc/sysdev/mpc8xx_pic.h
@@ -4,7 +4,7 @@
 #include <linux/irq.h>
 #include <linux/interrupt.h>
 
-extern struct hw_interrupt_type mpc8xx_pic;
+/*extern struct hw_interrupt_type mpc8xx_pic;*/
 
 int mpc8xx_pic_init(void);
 unsigned int mpc8xx_get_irq(void);
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig
index 35f8864..c3fd55d 100644
--- a/drivers/pcmcia/Kconfig
+++ b/drivers/pcmcia/Kconfig
@@ -183,6 +183,7 @@ config PCMCIA_M8XX
         tristate "MPC8xx PCMCIA support"
         depends on PCMCIA && PPC && 8xx 
         select PCCARD_IODYN
+	select PCCARD_NONSTATIC
         help
         Say Y here to include support for PowerPC 8xx series PCMCIA
         controller.
diff --git a/drivers/pcmcia/m8xx_pcmcia.c b/drivers/pcmcia/m8xx_pcmcia.c
index 9721ed7..40f6e20 100644
--- a/drivers/pcmcia/m8xx_pcmcia.c
+++ b/drivers/pcmcia/m8xx_pcmcia.c
@@ -10,7 +10,7 @@
  * Further fixes, v2.6 kernel port
  *     <marcelo.tosatti@cyclades.com>
  * 
- * Some fixes, additions (C) 2005 Montavista Software, Inc. 
+ * Some fixes, additions (C) 2005-2007 Montavista Software, Inc. 
  *     <vbordug@ru.mvista.com>
  *
  * "The ExCA standard specifies that socket controllers should provide
@@ -40,10 +40,6 @@
 #include <linux/fcntl.h>
 #include <linux/string.h>
 
-#include <asm/io.h>
-#include <asm/bitops.h>
-#include <asm/system.h>
-
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
@@ -51,11 +47,18 @@
 #include <linux/ioport.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
-#include <linux/platform_device.h>
+#include <linux/fsl_devices.h>
 
+#include <asm/io.h>
+#include <asm/bitops.h>
+#include <asm/system.h>
+#include <asm/time.h>
 #include <asm/mpc8xx.h>
 #include <asm/8xx_immap.h>
 #include <asm/irq.h>
+#include <asm/fs_pd.h>
+#include <asm/of_device.h>
+#include <asm/of_platform.h>
 
 #include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
@@ -146,27 +149,17 @@ MODULE_LICENSE("Dual MPL/GPL");
 #define PCMCIA_MEM_WIN_BASE 0xe0000000 /* base address for memory window 0   */
 #define PCMCIA_MEM_WIN_SIZE 0x04000000 /* each memory window is 64 MByte     */
 #define PCMCIA_IO_WIN_BASE  _IO_BASE   /* base address for io window 0       */
-
-#define PCMCIA_SCHLVL PCMCIA_INTERRUPT /* Status Change Interrupt Level      */
-
 /* ------------------------------------------------------------------------- */
 
-/* 2.4.x and newer has this always in HZ */
-#define M8XX_BUSFREQ ((((bd_t *)&(__res))->bi_busfreq))
-
-static int pcmcia_schlvl = PCMCIA_SCHLVL;
+static int pcmcia_schlvl;
 
 static DEFINE_SPINLOCK(events_lock);
 
-
 #define PCMCIA_SOCKET_KEY_5V 1
 #define PCMCIA_SOCKET_KEY_LV 2
 
 /* look up table for pgcrx registers */
-static u32 *m8xx_pgcrx[2] = {
-	&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pgcra,
-	&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pgcrb
-};
+static u32 *m8xx_pgcrx[2];
 
 /*
  * This structure is used to address each window in the PCMCIA controller.
@@ -228,11 +221,16 @@ struct event_table {
 	u32 eventbit;
 };
 
+static const char driver_name[] = "m8xx-pcmcia";
+
 struct socket_info {
 	void	(*handler)(void *info, u32 events);
 	void	*info;
 
 	u32 slot;
+	pcmconf8xx_t *pcmcia;
+	u32 bus_freq;
+	int hwirq;
 
 	socket_state_t state;
 	struct pccard_mem_map mem_win[PCMCIA_MEM_WIN_NO];
@@ -408,78 +406,21 @@ static void hardware_disable(int slot)
 #if defined(CONFIG_MPC885ADS)
 
 #define PCMCIA_BOARD_MSG "MPC885ADS"
+#define socket_get(_slot_) PCMCIA_SOCKET_KEY_5V
 
-static int voltage_set(int slot, int vcc, int vpp)
+static inline void hardware_enable(int slot)
 {
-	u32 reg = 0;
-	unsigned *bcsr_io;
-
-	bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
-
-	switch(vcc) {
-		case 0:
-			break;
-		case 33:
-			reg |= BCSR1_PCCVCC0;
-			break;
-		case 50:
-			reg |= BCSR1_PCCVCC1;
-			break;
-		default:
-			goto out_unmap;
-	}
-
-	switch(vpp) {
-		case 0:
-			break;
-		case 33:
-		case 50:
-			if(vcc == vpp)
-				reg |= BCSR1_PCCVPP1;
-			else
-				goto out_unmap;
-			break;
-		case 120:
-			if ((vcc == 33) || (vcc == 50))
-				reg |= BCSR1_PCCVPP0;
-			else
-				goto out_unmap;
-		default:
-			goto out_unmap;
-	}
-
-	/* first, turn off all power */
-	out_be32(bcsr_io, in_be32(bcsr_io) & ~(BCSR1_PCCVCC_MASK | BCSR1_PCCVPP_MASK));
-
-	/* enable new powersettings */
-	out_be32(bcsr_io, in_be32(bcsr_io) | reg);
-
-	iounmap(bcsr_io);
-	return 0;
-
-out_unmap:
-	iounmap(bcsr_io);
-	return 1;
+	 m8xx_pcmcia_ops.hw_ctrl(slot, 1);
 }
 
-#define socket_get(_slot_) PCMCIA_SOCKET_KEY_5V
-
-static void hardware_enable(int slot)
+static inline void hardware_disable(int slot)
 {
-	unsigned *bcsr_io;
-
-	bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
-	out_be32(bcsr_io, in_be32(bcsr_io) & ~BCSR1_PCCEN);
-	iounmap(bcsr_io);
+	m8xx_pcmcia_ops.hw_ctrl(slot, 0);
 }
 
-static void hardware_disable(int slot)
+static inline int voltage_set(int slot, int vcc, int vpp)
 {
-	unsigned *bcsr_io;
-
-	bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
-	out_be32(bcsr_io, in_be32(bcsr_io) |  BCSR1_PCCEN);
-	iounmap(bcsr_io);
+	return m8xx_pcmcia_ops.voltage_set(slot, vcc, vpp);
 }
 
 #endif
@@ -604,48 +545,6 @@ static int voltage_set(int slot, int vcc, int vpp)
 
 #endif /* CONFIG_PRxK */
 
-static void m8xx_shutdown(void)
-{
-	u32 m, i;
-	struct pcmcia_win *w;
-
-	for(i = 0; i < PCMCIA_SOCKETS_NO; i++){
-		w = (void *) &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0;
-
-		out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr, M8XX_PCMCIA_MASK(i));
-		out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per, in_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per) & ~M8XX_PCMCIA_MASK(i));
-
-		/* turn off interrupt and disable CxOE */
-		out_be32(M8XX_PGCRX(i), M8XX_PGCRX_CXOE);
-
-		/* turn off memory windows */
-		for(m = 0; m < PCMCIA_MEM_WIN_NO; m++) {
-			out_be32(&w->or, 0); /* set to not valid */
-			w++;
-		}
-
-		/* turn off voltage */
-		voltage_set(i, 0, 0);
-
-		/* disable external hardware */
-		hardware_disable(i);
-	}
-
-	free_irq(pcmcia_schlvl, NULL);
-}
-
-static struct device_driver m8xx_driver = {
-        .name = "m8xx-pcmcia",
-        .bus = &platform_bus_type,
-        .suspend = pcmcia_socket_dev_suspend,
-        .resume = pcmcia_socket_dev_resume,
-};
-
-static struct platform_device m8xx_device = {
-        .name = "m8xx-pcmcia",
-        .id = 0,
-};
-
 static u32 pending_events[PCMCIA_SOCKETS_NO];
 static DEFINE_SPINLOCK(pending_event_lock);
 
@@ -654,13 +553,14 @@ static irqreturn_t m8xx_interrupt(int irq, void *dev)
 	struct socket_info *s;
 	struct event_table *e;
 	unsigned int i, events, pscr, pipr, per;
+	pcmconf8xx_t	*pcmcia = socket[0].pcmcia;
 
 	dprintk("Interrupt!\n");
 	/* get interrupt sources */
 
-	pscr = in_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr);
-	pipr = in_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pipr);
-	per = in_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per);
+	pscr = in_be32(&pcmcia->pcmc_pscr);
+	pipr = in_be32(&pcmcia->pcmc_pipr);
+	per = in_be32(&pcmcia->pcmc_per);
 
 	for(i = 0; i < PCMCIA_SOCKETS_NO; i++) {
 		s = &socket[i];
@@ -724,7 +624,7 @@ static irqreturn_t m8xx_interrupt(int irq, void *dev)
 			per &= ~M8XX_PCMCIA_RDY_L(0);
 			per &= ~M8XX_PCMCIA_RDY_L(1);
 
-			out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per, per);
+			out_be32(&pcmcia->pcmc_per, per);
 
 			if (events)
 				pcmcia_parse_events(&socket[i].socket, events);
@@ -732,7 +632,7 @@ static irqreturn_t m8xx_interrupt(int irq, void *dev)
 	}
 
 	/* clear the interrupt sources */
-	out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr, pscr);
+	out_be32(&pcmcia->pcmc_pscr, pscr);
 
 	dprintk("Interrupt done.\n");
 
@@ -753,7 +653,7 @@ static u32 m8xx_get_graycode(u32 size)
 	return k;
 }
 
-static u32 m8xx_get_speed(u32 ns, u32 is_io)
+static u32 m8xx_get_speed(u32 ns, u32 is_io, u32 bus_freq)
 {
 	u32 reg, clocks, psst, psl, psht;
 
@@ -781,7 +681,7 @@ static u32 m8xx_get_speed(u32 ns, u32 is_io)
 
 #define ADJ 180 /* 80 % longer accesstime - to be sure */
 
-	clocks = ((M8XX_BUSFREQ / 1000) * ns) / 1000;
+	clocks = ((bus_freq / 1000) * ns) / 1000;
 	clocks = (clocks * ADJ) / (100*1000);
 	if(clocks >= PCMCIA_BMT_LIMIT) {
 		printk( "Max access time limit reached\n");
@@ -806,8 +706,9 @@ static int m8xx_get_status(struct pcmcia_socket *sock, unsigned int *value)
 	int lsock = container_of(sock, struct socket_info, socket)->slot;
 	struct socket_info *s = &socket[lsock];
 	unsigned int pipr, reg;
+	pcmconf8xx_t *pcmcia = s->pcmcia;
 
-	pipr = in_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pipr);
+	pipr = in_be32(&pcmcia->pcmc_pipr);
 
 	*value  = ((pipr & (M8XX_PCMCIA_CD1(lsock)
 			    | M8XX_PCMCIA_CD2(lsock))) == 0) ? SS_DETECT : 0;
@@ -918,6 +819,7 @@ static int m8xx_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
 	struct event_table *e;
 	unsigned int reg;
 	unsigned long flags;
+	pcmconf8xx_t *pcmcia = socket[0].pcmcia;
 
 	dprintk( "SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, "
 	      "io_irq %d, csc_mask %#2.2x)\n", lsock, state->flags,
@@ -927,6 +829,7 @@ static int m8xx_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
 	if(voltage_set(lsock, state->Vcc, state->Vpp))
 		return -EINVAL;
 
+
 	/* Take care of reset... */
 	if(state->flags & SS_RESET)
 		out_be32(M8XX_PGCRX(lsock), in_be32(M8XX_PGCRX(lsock)) |  M8XX_PGCRX_CXRESET); /* active high */
@@ -982,7 +885,8 @@ static int m8xx_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
 		 * If io_irq is non-zero we should enable irq.
 		 */
 		if(state->io_irq) {
-			out_be32(M8XX_PGCRX(lsock), in_be32(M8XX_PGCRX(lsock)) | mk_int_int_mask(state->io_irq) << 24);
+			out_be32(M8XX_PGCRX(lsock),
+				 in_be32(M8XX_PGCRX(lsock)) | mk_int_int_mask(s->hwirq) << 24);
 			/*
 			 * Strange thing here:
 			 * The manual does not tell us which interrupt
@@ -1027,7 +931,7 @@ static int m8xx_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
 	 * Writing ones will clear the bits.
 	 */
 
-	out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr, reg);
+	out_be32(&pcmcia->pcmc_pscr, reg);
 
 	/*
 	 * Write the mask.
@@ -1036,15 +940,8 @@ static int m8xx_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
 	 * Ones will enable the interrupt.
 	 */
 
-	/*
-	  reg |= ((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per
-	  & M8XX_PCMCIA_MASK(lsock);
-	*/
-
-	reg |= in_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per) &
-		(M8XX_PCMCIA_MASK(0) | M8XX_PCMCIA_MASK(1));
-
-	out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per, reg);
+	reg |= in_be32(&pcmcia->pcmc_per) & (M8XX_PCMCIA_MASK(0) | M8XX_PCMCIA_MASK(1));
+	out_be32(&pcmcia->pcmc_per, reg);
 
 	spin_unlock_irqrestore(&events_lock, flags);
 
@@ -1062,6 +959,8 @@ static int m8xx_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *io)
 	struct socket_info *s = &socket[lsock];
 	struct pcmcia_win *w;
 	unsigned int reg, winnr;
+	pcmconf8xx_t *pcmcia = s->pcmcia;
+
 
 #define M8XX_SIZE (io->stop - io->start + 1)
 #define M8XX_BASE (PCMCIA_IO_WIN_BASE + io->start)
@@ -1086,7 +985,7 @@ static int m8xx_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *io)
 
 		/* setup registers */
 
-		w = (void *) &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0;
+		w = (void *) &pcmcia->pcmc_pbr0;
 		w += winnr;
 
 		out_be32(&w->or, 0); /* turn off window first */
@@ -1095,12 +994,13 @@ static int m8xx_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *io)
 		reg <<= 27;
   		reg |= M8XX_PCMCIA_POR_IO |(lsock << 2);
 
-		reg |= m8xx_get_speed(io->speed, 1);
+		reg |= m8xx_get_speed(io->speed, 1, s->bus_freq);
 
 		if(io->flags & MAP_WRPROT)
 			reg |= M8XX_PCMCIA_POR_WRPROT;
 
-		if(io->flags & (MAP_16BIT | MAP_AUTOSZ))
+		/*if(io->flags & (MAP_16BIT | MAP_AUTOSZ))*/
+		if(io->flags & MAP_16BIT)
 			reg |= M8XX_PCMCIA_POR_16BIT;
 
 		if(io->flags & MAP_ACTIVE)
@@ -1117,7 +1017,7 @@ static int m8xx_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *io)
 
 		/* setup registers */
 
-		w = (void *) &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0;
+		w = (void *) &pcmcia->pcmc_pbr0;
 		w += winnr;
 
 		out_be32(&w->or, 0); /* turn off window */
@@ -1144,6 +1044,7 @@ static int m8xx_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *m
 	struct pcmcia_win *w;
 	struct pccard_mem_map *old;
 	unsigned int reg, winnr;
+	pcmconf8xx_t *pcmcia = s->pcmcia;
 
 	dprintk( "SetMemMap(%d, %d, %#2.2x, %d ns, "
 	      "%#5.5lx, %#5.5x)\n", lsock, mem->map, mem->flags,
@@ -1166,12 +1067,12 @@ static int m8xx_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *m
 
 	/* Setup the window in the pcmcia controller */
 
-	w = (void *) &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0;
+	w = (void *) &pcmcia->pcmc_pbr0;
 	w += winnr;
 
 	reg |= lsock << 2;
 
-	reg |= m8xx_get_speed(mem->speed, 0);
+	reg |= m8xx_get_speed(mem->speed, 0, s->bus_freq);
 
 	if(mem->flags & MAP_ATTRIB)
 		reg |=  M8XX_PCMCIA_POR_ATTRMEM;
@@ -1236,60 +1137,69 @@ static int m8xx_sock_init(struct pcmcia_socket *sock)
 
 }
 
-static int m8xx_suspend(struct pcmcia_socket *sock)
+static int m8xx_sock_suspend(struct pcmcia_socket *sock)
 {
 	return m8xx_set_socket(sock, &dead_socket);
 }
 
 static struct pccard_operations m8xx_services = {
 	.init	= m8xx_sock_init,
-	.suspend = m8xx_suspend,
+	.suspend = m8xx_sock_suspend,
 	.get_status = m8xx_get_status,
 	.set_socket = m8xx_set_socket,
 	.set_io_map = m8xx_set_io_map,
 	.set_mem_map = m8xx_set_mem_map,
 };
 
-static int __init m8xx_init(void)
+static int __init m8xx_probe(struct of_device *ofdev, const struct of_device_id *match)
 {
 	struct pcmcia_win *w;
-	unsigned int i,m;
+	unsigned int i, m, hwirq;
+	pcmconf8xx_t *pcmcia;
+	int status;
+	struct device_node *np = ofdev->node;
 
 	pcmcia_info("%s\n", version);
 
-	if (driver_register(&m8xx_driver))
-		return -1;
+	pcmcia = of_iomap(np, 0);
+	if(pcmcia == NULL)
+		return -EINVAL;
+
+	pcmcia_schlvl = irq_of_parse_and_map(np, 0);
+	hwirq  = irq_map[pcmcia_schlvl].hwirq;
+	if (pcmcia_schlvl < 0)
+		return -EINVAL;
+
+	m8xx_pgcrx[0] = &pcmcia->pcmc_pgcra;
+	m8xx_pgcrx[1] = &pcmcia->pcmc_pgcrb;
+
 
 	pcmcia_info(PCMCIA_BOARD_MSG " using " PCMCIA_SLOT_MSG
-		    " with IRQ %u.\n", pcmcia_schlvl);
+		    " with IRQ %u  (%d). \n", pcmcia_schlvl, hwirq);
 
 	/* Configure Status change interrupt */
 
-	if(request_irq(pcmcia_schlvl, m8xx_interrupt, 0,
-			  "m8xx_pcmcia", NULL)) {
+	if(request_irq(pcmcia_schlvl, m8xx_interrupt, IRQF_SHARED,
+			  driver_name, socket)) {
 		pcmcia_error("Cannot allocate IRQ %u for SCHLVL!\n",
 			     pcmcia_schlvl);
 		return -1;
 	}
 
-	w = (void *) &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0;
-
-	out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr,
-		M8XX_PCMCIA_MASK(0)| M8XX_PCMCIA_MASK(1));
+	w = (void *) &pcmcia->pcmc_pbr0;
 
-	out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per,
-		in_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per) &
-		~(M8XX_PCMCIA_MASK(0)| M8XX_PCMCIA_MASK(1)));
+	out_be32(&pcmcia->pcmc_pscr, M8XX_PCMCIA_MASK(0)| M8XX_PCMCIA_MASK(1));
+	clrbits32(&pcmcia->pcmc_per, M8XX_PCMCIA_MASK(0) | M8XX_PCMCIA_MASK(1));
 
-/* connect interrupt and disable CxOE */
+	/* connect interrupt and disable CxOE */
 
-	out_be32(M8XX_PGCRX(0), M8XX_PGCRX_CXOE | (mk_int_int_mask(pcmcia_schlvl) << 16));
-	out_be32(M8XX_PGCRX(1), M8XX_PGCRX_CXOE | (mk_int_int_mask(pcmcia_schlvl) << 16));
+	out_be32(M8XX_PGCRX(0), M8XX_PGCRX_CXOE | (mk_int_int_mask(hwirq) << 16));
+	out_be32(M8XX_PGCRX(1), M8XX_PGCRX_CXOE | (mk_int_int_mask(hwirq) << 16));
 
-/* intialize the fixed memory windows */
+	/* intialize the fixed memory windows */
 
 	for(i = 0; i < PCMCIA_SOCKETS_NO; i++){
-		for(m = 0; m < PCMCIA_MEM_WIN_NO; m++) {
+		for (m = 0; m < PCMCIA_MEM_WIN_NO; m++) {
 			out_be32(&w->br, PCMCIA_MEM_WIN_BASE +
 				(PCMCIA_MEM_WIN_SIZE
 				 * (m + i * PCMCIA_MEM_WIN_NO)));
@@ -1300,16 +1210,14 @@ static int __init m8xx_init(void)
 		}
 	}
 
-/* turn off voltage */
+	/* turn off voltage */
 	voltage_set(0, 0, 0);
 	voltage_set(1, 0, 0);
 
-/* Enable external hardware */
+	/* Enable external hardware */
 	hardware_enable(0);
 	hardware_enable(1);
 
-	platform_device_register(&m8xx_device);
-
 	for (i = 0 ; i < PCMCIA_SOCKETS_NO; i++) {
 		socket[i].slot = i;
 		socket[i].socket.owner = THIS_MODULE;
@@ -1317,30 +1225,105 @@ static int __init m8xx_init(void)
 		socket[i].socket.irq_mask = 0x000;
 		socket[i].socket.map_size = 0x1000;
 		socket[i].socket.io_offset = 0;
-		socket[i].socket.pci_irq = i  ? 7 : 9;
+		socket[i].socket.pci_irq = pcmcia_schlvl;
 		socket[i].socket.ops = &m8xx_services;
-		socket[i].socket.resource_ops = &pccard_iodyn_ops;
+		socket[i].socket.resource_ops = &pccard_nonstatic_ops;
 		socket[i].socket.cb_dev = NULL;
-		socket[i].socket.dev.parent = &m8xx_device.dev;
+		socket[i].socket.dev.parent = &ofdev->dev;
+		socket[i].pcmcia = pcmcia;
+		socket[i].bus_freq = ppc_proc_freq;
+		socket[i].hwirq = hwirq;
+
+
 	}
 
-	for (i = 0; i < PCMCIA_SOCKETS_NO; i++)
-		pcmcia_register_socket(&socket[i].socket);
+	for (i = 0; i < PCMCIA_SOCKETS_NO; i++) {
+		status = pcmcia_register_socket(&socket[i].socket);
+		if (status < 0)
+			pcmcia_error("Socket register failed\n");
+	}
 
 	return 0;
 }
 
-static void __exit m8xx_exit(void)
+static int m8xx_remove(struct of_device* ofdev)
 {
-	int i;
+	u32 m, i;
+	struct pcmcia_win *w;
+	pcmconf8xx_t *pcmcia = socket[0].pcmcia;
+
+	for (i = 0; i < PCMCIA_SOCKETS_NO; i++) {
+		w = (void *) &pcmcia->pcmc_pbr0;
+
+		out_be32(&pcmcia->pcmc_pscr, M8XX_PCMCIA_MASK(i));
+		out_be32(&pcmcia->pcmc_per,
+			in_be32(&pcmcia->pcmc_per) & ~M8XX_PCMCIA_MASK(i));
 
+		/* turn off interrupt and disable CxOE */
+		out_be32(M8XX_PGCRX(i), M8XX_PGCRX_CXOE);
+
+		/* turn off memory windows */
+		for (m = 0; m < PCMCIA_MEM_WIN_NO; m++) {
+			out_be32(&w->or, 0); /* set to not valid */
+			w++;
+		}
+
+		/* turn off voltage */
+		voltage_set(i, 0, 0);
+
+		/* disable external hardware */
+		hardware_disable(i);
+	}
 	for (i = 0; i < PCMCIA_SOCKETS_NO; i++)
 		pcmcia_unregister_socket(&socket[i].socket);
 
-	m8xx_shutdown();
+	free_irq(pcmcia_schlvl, NULL);
 
-	platform_device_unregister(&m8xx_device);
-	driver_unregister(&m8xx_driver);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int m8xx_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	return pcmcia_socket_dev_suspend(&pdev->dev, state);
+}
+
+static int m8xx_resume(struct platform_device *pdev)
+{
+	return pcmcia_socket_dev_resume(&pdev->dev);
+}
+#else
+#define m8xx_suspend NULL
+#define m8xx_resume NULL
+#endif
+
+static struct of_device_id m8xx_pcmcia_match[] = {
+	{
+		.type = "pcmcia",
+		.compatible = "fsl,pq-pcmcia",
+	},
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, m8xx_pcmcia_match);
+
+static struct of_platform_driver m8xx_pcmcia_driver = {
+	.name		= (char *) driver_name,
+	.match_table	= m8xx_pcmcia_match,
+	.probe		= m8xx_probe,
+	.remove		= m8xx_remove,
+	.suspend	= m8xx_suspend,
+	.resume		= m8xx_resume,
+};
+
+static int __init m8xx_init(void)
+{
+	return of_register_platform_driver(&m8xx_pcmcia_driver);
+}
+
+static void __exit m8xx_exit(void)
+{
+	of_unregister_platform_driver(&m8xx_pcmcia_driver);
 }
 
 module_init(m8xx_init);
diff --git a/include/asm-powerpc/mpc8xx.h b/include/asm-powerpc/mpc8xx.h
index 5803711..c1a6efc 100644
--- a/include/asm-powerpc/mpc8xx.h
+++ b/include/asm-powerpc/mpc8xx.h
@@ -23,6 +23,10 @@
 #include <platforms/8xx/mpc885ads.h>
 #endif
 
+#ifdef CONFIG_PCMCIA_M8XX 
+extern struct mpc8xx_pcmcia_ops m8xx_pcmcia_ops;
+#endif 
+
 #endif /* CONFIG_8xx */
 #endif /* __CONFIG_8xx_DEFS */
 #endif /* __KERNEL__ */
diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h
index 73710d6..12e631f 100644
--- a/include/linux/fsl_devices.h
+++ b/include/linux/fsl_devices.h
@@ -120,5 +120,10 @@ struct fsl_spi_platform_data {
 	u32	sysclk;
 };
 
+struct mpc8xx_pcmcia_ops {
+	void(*hw_ctrl)(int slot, int enable);
+	int(*voltage_set)(int slot, int vcc, int vpp);
+};
+
 #endif /* _FSL_DEVICE_H_ */
 #endif /* __KERNEL__ */

^ permalink raw reply related

* [PATCH] [POWERPC] 8xx: PQ SoC IRDA support
From: Vitaly Bordug @ 2007-05-08  5:27 UTC (permalink / raw)
  To: Samuel Ortiz; +Cc: Andrew Morton, linuxppc-dev, linux-kernel


Adds support of IRDA transceiver residing on PowerQUICC processors and
enabling such on mpc885ads reference board. The driver is implemented 
using of_device concept, hereby implies arch/powerpc support of the target.

Signed-off-by: Vitaly Bordug <vitb@kernel.crashing.org>

---

 arch/powerpc/Kconfig                         |    1 
 arch/powerpc/boot/dts/mpc885ads.dts          |   10 
 arch/powerpc/platforms/8xx/mpc885ads_setup.c |   39 +
 arch/powerpc/sysdev/fsl_soc.c                |   58 ++
 drivers/net/irda/Kconfig                     |    4 
 drivers/net/irda/Makefile                    |    1 
 drivers/net/irda/m8xx-sir.c                  |  715 ++++++++++++++++++++++++++
 include/asm-ppc/commproc.h                   |   67 ++
 8 files changed, 895 insertions(+), 0 deletions(-)

diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index a8e08f4..c283907 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -605,6 +605,7 @@ endmenu
 config ISA_DMA_API
 	bool
 	default y
+	depends on !PPC_8xx
 
 menu "Bus options"
 
diff --git a/arch/powerpc/boot/dts/mpc885ads.dts b/arch/powerpc/boot/dts/mpc885ads.dts
index 110bf61..95b280c 100644
--- a/arch/powerpc/boot/dts/mpc885ads.dts
+++ b/arch/powerpc/boot/dts/mpc885ads.dts
@@ -178,6 +178,16 @@
 				interrupt-parent = <930>;
 				phy-handle = <e8002>;
 			};
+
+			scc@a20 {
+				device_type = "network";
+				compatible = "fsl,irda";
+				model = "SCC";
+				device-id = <2>;
+				reg = <a20 18 3d00 80>;
+				interrupts = <1d 3>;
+				interrupt-parent = <930>;
+			};
 		};
 	};
 };
diff --git a/arch/powerpc/platforms/8xx/mpc885ads_setup.c b/arch/powerpc/platforms/8xx/mpc885ads_setup.c
index a57b577..8611318 100644
--- a/arch/powerpc/platforms/8xx/mpc885ads_setup.c
+++ b/arch/powerpc/platforms/8xx/mpc885ads_setup.c
@@ -50,6 +50,7 @@ extern unsigned int mpc8xx_get_irq(void);
 static void init_smc1_uart_ioports(struct fs_uart_platform_info* fpi);
 static void init_smc2_uart_ioports(struct fs_uart_platform_info* fpi);
 static void init_scc3_ioports(struct fs_platform_info* ptr);
+static void init_irda_ioports(void);
 
 void __init mpc885ads_board_setup(void)
 {
@@ -115,6 +116,10 @@ void __init mpc885ads_board_setup(void)
 	immr_unmap(io_port);
 
 #endif
+
+#ifdef CONFIG_8XX_SIR
+	init_irda_ioports();
+#endif
 }
 
 
@@ -322,6 +327,40 @@ void init_smc_ioports(struct fs_uart_platform_info *data)
 	}
 }
 
+static void init_irda_ioports()
+{
+	iop8xx_t *io_port;
+	cpm8xx_t *cp;
+	unsigned *bcsr_io;
+
+	bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
+
+	if (bcsr_io == NULL) {
+		printk(KERN_CRIT "Could not remap BCSR1\n");
+		return;
+	}
+
+	/* Enable the IRDA. */
+	clrbits32(bcsr_io,BCSR1_IRDAEN);
+	iounmap(bcsr_io);
+
+	io_port = (iop8xx_t *)immr_map(im_ioport);
+	cp = (cpm8xx_t *)immr_map(im_cpm);
+
+	/* Configure port A pins. */
+	setbits16(&io_port->iop_papar, 0x000c);
+	clrbits16(&io_port->iop_padir, 0x000c);
+
+	/* Configure Serial Interface clock routing.
+	 * First, clear all SCC bits to zero, then set the ones we want.
+	 */
+	clrbits32(&cp->cp_sicr, 0x0000ff00);
+	setbits32(&cp->cp_sicr, 0x00001200);
+
+	immr_unmap(io_port);
+	immr_unmap(cp);
+}
+
 int platform_device_skip(const char *model, int id)
 {
 #ifdef CONFIG_MPC8xx_SECOND_ETH_SCC3
diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c
index 8a123c7..f827147 100644
--- a/arch/powerpc/sysdev/fsl_soc.c
+++ b/arch/powerpc/sysdev/fsl_soc.c
@@ -1102,4 +1102,62 @@ err:
 
 arch_initcall(cpm_smc_uart_of_init);
 
+static const char *irda_regs = "regs";
+static const char *irda_pram = "pram";
+static const char *irda_irq = "interrupt";
+static char bus_id[9][BUS_ID_SIZE];
+
+static int __init fs_irda_of_init(void)
+{
+	struct device_node *np;
+	unsigned int i;
+	struct platform_device *fs_irda_dev = NULL;
+	int ret;
+
+	for (np = NULL, i = 0;
+	     (np = of_find_compatible_node(np, "network", "fsl,irda")) != NULL;
+	     i++) {
+		struct resource r[4];
+		unsigned int *id;
+		char *model;
+
+		memset(r, 0, sizeof(r));
+
+		model = (char *)get_property(np, "model", NULL);
+		if (model == NULL)
+			return -ENODEV;
+
+		id = (u32 *) get_property(np, "device-id", NULL);
+		if (platform_device_skip(model, *id))
+			continue;
+
+		ret = of_address_to_resource(np, 0, &r[0]);
+		if (ret)
+			return ret;
+		r[0].name = irda_regs;
+
+		if (strstr(model, "SCC")) {
+			ret = of_address_to_resource(np, 1, &r[1]);
+			if (ret)
+				return ret;
+			r[1].name = irda_pram;
+
+			r[2].start = r[2].end = irq_of_parse_and_map(np, 0);
+			r[2].flags = IORESOURCE_IRQ;
+			r[2].name = irda_irq;
+
+			fs_irda_dev =
+				    platform_device_register_simple("fsl-cpm-scc:irda", i, &r[0], 3);
+
+			if (IS_ERR(fs_irda_dev)) {
+				ret = PTR_ERR(fs_irda_dev);
+				return ret;
+			}
+		}
+	}
+	return 0;
+}
+
+arch_initcall(fs_irda_of_init);
+
 #endif /* CONFIG_8xx */
diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig
index 7c8ccc0..b3681e7 100644
--- a/drivers/net/irda/Kconfig
+++ b/drivers/net/irda/Kconfig
@@ -17,6 +17,10 @@ config IRTTY_SIR
 
 	  If unsure, say Y.
 
+config 8XX_SIR
+	  tristate "mpc8xx SIR"
+	  depends on 8xx && IRDA
+
 comment "Dongle support"
 
 config DONGLE
diff --git a/drivers/net/irda/Makefile b/drivers/net/irda/Makefile
index 5be09f1..fc7c0fd 100644
--- a/drivers/net/irda/Makefile
+++ b/drivers/net/irda/Makefile
@@ -34,6 +34,7 @@ obj-$(CONFIG_EP7211_IR)		+= ep7211_ir.o
 obj-$(CONFIG_AU1000_FIR)	+= au1k_ir.o
 # New SIR drivers
 obj-$(CONFIG_IRTTY_SIR)		+= irtty-sir.o	sir-dev.o
+obj-$(CONFIG_8XX_SIR)		+= m8xx-sir.o
 # New dongles drivers for new SIR drivers
 obj-$(CONFIG_ESI_DONGLE)	+= esi-sir.o
 obj-$(CONFIG_TEKRAM_DONGLE)	+= tekram-sir.o
diff --git a/drivers/net/irda/m8xx-sir.c b/drivers/net/irda/m8xx-sir.c
new file mode 100644
index 0000000..6fb215f
--- /dev/null
+++ b/drivers/net/irda/m8xx-sir.c
@@ -0,0 +1,715 @@
+/*
+ * Infra-red SIR driver for the MPC8xx processors.
+ *
+ * Copyright (c) 2005-2007 MontaVista Software Inc.
+ * Author: Yuri Shpilevsky <source@mvista.com>
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/slab.h>
+#include <linux/rtnetlink.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+
+#include <net/irda/irda.h>
+#include <net/irda/irmod.h>
+#include <net/irda/wrapper.h>
+#include <net/irda/irda_device.h>
+
+#include <asm/io.h>
+#include <asm/cacheflush.h>
+#include <asm/irq.h>
+#include <asm/8xx_immap.h>
+#include <asm/pgtable.h>
+#include <asm/mpc8xx.h>
+#include <asm/bitops.h>
+#include <asm/uaccess.h>
+#include <asm/commproc.h>
+#include <asm/fs_pd.h>
+
+/*
+ * Our netdevice.  There is only ever one of these.
+ */
+
+#define CPM_IRDA_RX_PAGES       4
+#define CPM_IRDA_RX_FRSIZE      2048
+#define CPM_IRDA_RX_FRPPG       (PAGE_SIZE / CPM_IRDA_RX_FRSIZE)
+#define RX_RING_SIZE            (CPM_IRDA_RX_FRPPG * CPM_IRDA_RX_PAGES)
+#define TX_RING_SIZE            8	/* Must be power of two */
+#define TX_RING_MOD_MASK        7
+
+struct mpc8xx_irda {
+	unsigned char open;
+
+	int speed;
+	int newspeed;
+
+	/* The saved address of a sent-in-place packet/buffer, for skfree().
+	 */
+	struct sk_buff *tx_skbuff[TX_RING_SIZE];
+	ushort skb_cur;
+	ushort skb_dirty;
+
+	struct net_device_stats stats;
+	struct device *dev;
+	struct irda_platform_data *pdata;
+	struct irlap_cb *irlap;
+	struct qos_info qos;
+
+	scc_t *sccp;
+	scc_ahdlc_t *ahp;
+	int irq;
+	cbd_t *rx_bd_base;
+	cbd_t *tx_bd_base;
+	cbd_t *dirty_tx;
+	cbd_t *cur_rx, *cur_tx;	/* The next free ring entry */
+	unsigned char *rx_vaddr[RX_RING_SIZE];
+	int tx_free;
+	spinlock_t lock;
+};
+
+#define HPSIR_MAX_RXLEN		2050
+#define HPSIR_MAX_TXLEN		2050
+#define TXBUFF_MAX_SIZE		HPSIR_MAX_TXLEN
+
+static void mpc8xx_irda_set_speed(struct net_device *dev, int speed);
+
+/************************************************************************************/
+
+/* Low level init/uninstall function IrDA protocol stack registration
+ */
+
+static void mpc8xx_irda_rx(struct net_device *dev)
+{
+	struct mpc8xx_irda *si = dev->priv;
+	cbd_t *bdp;
+	struct sk_buff *skb;
+	int len;
+	ushort status;
+
+	bdp = si->cur_rx;
+
+	for (;;) {
+		if (bdp->cbd_sc & BD_AHDLC_RX_EMPTY)
+			break;
+		status = bdp->cbd_sc;
+
+		if (status & BD_AHDLC_RX_STATS) {
+			/* process errors
+			 */
+			if (bdp->cbd_sc & BD_AHDLC_RX_AB)
+				si->stats.rx_length_errors++;
+			if (bdp->cbd_sc & BD_AHDLC_RX_CR)	/* CRC Error */
+				si->stats.rx_crc_errors++;
+			if (bdp->cbd_sc & BD_AHDLC_RX_OV)	/* FIFO overrun */
+				si->stats.rx_over_errors++;
+		} else {
+			/* Process the incoming frame.
+			 */
+			len = bdp->cbd_datlen;
+
+			skb = dev_alloc_skb(len + 1);
+			if (skb == NULL) {
+				printk(KERN_INFO
+				       "%s: Memory squeeze, dropping packet.\n",
+				       dev->name);
+				si->stats.rx_dropped++;
+			} else {
+				skb->dev = dev;
+				skb_reserve(skb, 1);
+				memcpy(skb_put(skb, len),
+				       si->rx_vaddr[bdp - si->rx_bd_base], len);
+				skb_trim(skb, skb->len - 2);
+
+				si->stats.rx_packets++;
+				si->stats.rx_bytes += len;
+
+				skb->mac.raw = skb->data;
+				skb->protocol = htons(ETH_P_IRDA);
+				netif_rx(skb);
+			}
+		}
+
+		/* Clear the status flags for this buffer.
+		 */
+		bdp->cbd_sc &= ~BD_AHDLC_RX_STATS;
+
+		/* Mark the buffer empty.
+		 */
+		bdp->cbd_sc |= BD_AHDLC_RX_EMPTY;
+
+		/* Update BD pointer to next entry.
+		 */
+		if (bdp->cbd_sc & BD_AHDLC_RX_WRAP)
+			bdp = si->rx_bd_base;
+		else
+			bdp++;
+	}
+	si->cur_rx = (cbd_t *) bdp;
+}
+
+static irqreturn_t mpc8xx_irda_irq(int irq, void *dev_id)
+{
+	struct net_device *dev = dev_id;
+	struct mpc8xx_irda *si = dev->priv;
+	scc_t *sccp = si->sccp;
+	cbd_t *bdp;
+	ushort int_events;
+	int must_restart = 0;
+
+	/* Get the interrupt events that caused us to be here.
+	 */
+	int_events = in_be16(&sccp->scc_scce);
+	out_be16(&sccp->scc_scce, int_events);
+
+	/* Handle receive event in its own function.
+	 */
+	if (int_events & SCC_AHDLC_RXF)
+		mpc8xx_irda_rx(dev);
+
+	spin_lock(&si->lock);
+
+	/* Transmit OK, or non-fatal error.  Update the buffer descriptors.
+	 */
+	if (int_events & (SCC_AHDLC_TXE | SCC_AHDLC_TXB)) {
+		bdp = si->dirty_tx;
+
+		while ((bdp->cbd_sc & BD_AHDLC_TX_READY) == 0) {
+			if (si->tx_free == TX_RING_SIZE)
+				break;
+
+			if (bdp->cbd_sc & BD_AHDLC_TX_CTS)
+				must_restart = 1;
+
+			si->stats.tx_packets++;
+
+			/* Free the sk buffer associated with this last transmit.
+			 */
+			dev_kfree_skb_irq(si->tx_skbuff[si->skb_dirty]);
+			si->skb_dirty = (si->skb_dirty + 1) & TX_RING_MOD_MASK;
+
+			/* Update pointer to next buffer descriptor to be transmitted.
+			 */
+			if (bdp->cbd_sc & BD_AHDLC_TX_WRAP)
+				bdp = si->tx_bd_base;
+			else
+				bdp++;
+
+			/* Since we have freed up a buffer, the ring is no longer full.
+			 */
+			if (!si->tx_free++) {
+				if (netif_queue_stopped(dev))
+					netif_wake_queue(dev);
+			}
+
+			si->dirty_tx = (cbd_t *) bdp;
+
+			if (si->newspeed) {
+				mpc8xx_irda_set_speed(dev, si->newspeed);
+				si->speed = si->newspeed;
+				si->newspeed = 0;
+			}
+		}
+
+		if (must_restart) {
+			cpm8xx_t *cp = immr_map(im_cpm);
+			printk(KERN_INFO "restart TX\n");
+
+			/* Some transmit errors cause the transmitter to shut
+			 * down.  We now issue a restart transmit.  Since the
+			 * errors close the BD and update the pointers, the restart
+			 * _should_ pick up without having to reset any of our
+			 * pointers either.
+			 */
+			out_be16(&cp->cp_cpcr,
+			    mk_cr_cmd(CPM_CR_CH_SCC2,
+				      CPM_CR_RESTART_TX) | CPM_CR_FLG);
+			while (in_be16(&cp->cp_cpcr) & CPM_CR_FLG) ;
+		}
+	}
+
+	spin_unlock(&si->lock);
+
+	return IRQ_HANDLED;
+}
+
+static int mpc8xx_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct mpc8xx_irda *si = dev->priv;
+	volatile scc_ahdlc_t *ahp = si->ahp;
+	int speed = irda_get_next_speed(skb);
+	cbd_t *bdp;
+	int mtt;
+	u16 xbofs;
+	unsigned long flags;
+
+	/*
+	 * Does this packet contain a request to change the interface
+	 * speed?  If so, remember it until we complete the transmission
+	 * of this frame.
+	 */
+	if (speed != si->speed && speed != -1)
+		si->newspeed = speed;
+
+	mtt = irda_get_mtt(skb);
+
+	spin_lock_irqsave(&si->lock, flags);
+
+	/*
+	 * If this is an empty frame, we can bypass a lot.
+	 */
+	if (skb->len == 0) {
+		if (si->newspeed) {
+			si->newspeed = 0;
+			mpc8xx_irda_set_speed(dev, speed);
+		}
+		spin_unlock_irqrestore(&si->lock, flags);
+		dev_kfree_skb(skb);
+		return 0;
+	}
+
+	/* Get a Tx ring entry */
+	bdp = si->cur_tx;
+
+	/* Clear all of the status flags.
+	 */
+	bdp->cbd_sc &= ~BD_AHDLC_TX_STATS;
+
+	/* Set xbofs
+	 */
+	{
+		struct irda_skb_cb *cb = (struct irda_skb_cb *)skb->cb;
+		xbofs =
+		    (cb->magic != LAP_MAGIC) ? 10 : cb->xbofs + cb->xbofs_delay;
+		xbofs = (xbofs > 163) ? 163 : xbofs;
+		out_be16(&ahp->ahdlc_nof, xbofs);
+	}
+
+	/* Set buffer length and buffer pointer.
+	 */
+	bdp->cbd_datlen = skb->len;
+	bdp->cbd_bufaddr = __pa(skb->data);
+
+	/* Push the data cache so the CPM does not get stale memory data.
+	 */
+	flush_dcache_range((unsigned long)(skb->data),
+			   (unsigned long)(skb->data + skb->len));
+
+	/* Save skb pointer.
+	 */
+	si->tx_skbuff[si->skb_cur] = skb;
+
+	si->stats.tx_bytes += skb->len;
+	si->skb_cur = (si->skb_cur + 1) & TX_RING_MOD_MASK;
+
+	/* If we have a mean turn-around time, impose the specified
+	 * specified delay.  We could shorten this by timing from
+	 * the point we received the packet.
+	 */
+	if (mtt > 0)
+		udelay(mtt);
+
+	/* Send it on its way.  Tell CPM its ready, interrupt when done,
+	 * its the last BD of the frame, and to put the CRC on the end.
+	 */
+	bdp->cbd_sc |=
+	    (BD_AHDLC_TX_READY | BD_AHDLC_TX_INTR | BD_AHDLC_TX_LAST);
+
+	dev->trans_start = jiffies;
+
+	/* If this was the last BD in the ring, start at the beginning again.
+	 */
+	if (bdp->cbd_sc & BD_AHDLC_TX_WRAP)
+		bdp = si->tx_bd_base;
+	else
+		bdp++;
+
+	spin_unlock_irqrestore(&si->lock, flags);
+
+	if (!--si->tx_free)
+		netif_stop_queue(dev);
+
+	si->cur_tx = (cbd_t *) bdp;
+
+	return 0;
+}
+
+static int
+mpc8xx_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd)
+{
+	struct if_irda_req *rq = (struct if_irda_req *)ifreq;
+	struct mpc8xx_irda *si = dev->priv;
+	int ret = -EOPNOTSUPP;
+
+	switch (cmd) {
+	case SIOCSBANDWIDTH:
+		if (capable(CAP_NET_ADMIN)) {
+			/* We are unable to set the speed if the
+			 * device is not running.
+			 */
+			if (si->open)
+				mpc8xx_irda_set_speed(dev, rq->ifr_baudrate);
+			else
+				printk(KERN_INFO
+				       "mpc8xx_irda_ioctl: SIOCSBANDWIDTH: !netif_running\n");
+			ret = 0;
+		}
+		break;
+
+	case SIOCSMEDIABUSY:
+		ret = -EPERM;
+		if (capable(CAP_NET_ADMIN)) {
+			irda_device_set_media_busy(dev, TRUE);
+			ret = 0;
+		}
+		break;
+
+	case SIOCGRECEIVING:
+		rq->ifr_receiving = 0;
+		break;
+
+	default:
+		break;
+	}
+
+	return ret;
+}
+
+static struct net_device_stats *mpc8xx_irda_stats(struct net_device *ndev)
+{
+	struct mpc8xx_irda *si = ndev->priv;
+	return &si->stats;
+}
+
+static int mpc8xx_irda_pd_setup(struct mpc8xx_irda *si)
+{
+	struct platform_device *pdev = to_platform_device(si->dev);
+	struct resource *r;
+
+	/* Fill out IRQ field */
+	si->irq = platform_get_irq_byname(pdev, "interrupt");
+
+	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
+	si->sccp = ioremap(r->start, r->end - r->start + 1);
+
+	if (si->sccp == NULL)
+		return -EINVAL;
+
+	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pram");
+	si->ahp = ioremap(r->start, r->end - r->start + 1);
+
+	if (si->ahp == NULL)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int mpc8xx_irda_startup(struct net_device *dev)
+{
+	struct mpc8xx_irda *si = dev->priv;
+	cbd_t *bdp;
+	volatile cpm8xx_t *cp = immr_map(im_cpm);
+	scc_t *sccp;
+	volatile scc_ahdlc_t *ahp;
+	dma_addr_t mem_addr;
+	int i, j, k;
+	unsigned char *ba;
+	int err = -ENOMEM;
+
+	spin_lock_init(&si->lock);
+
+	if ((err = mpc8xx_irda_pd_setup(si)))
+		return err;
+
+	sccp = si->sccp;
+	ahp = si->ahp;
+
+	/* Disable receive and transmit.
+	 */
+	clrbits32(&sccp->scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+
+	/* Allocate space for the buffer descriptors in the DP ram.
+	 * These are relative offsets in the DP ram address space.
+	 * Initialize base addresses for the buffer descriptors.
+	 */
+	i = cpm_dpalloc(sizeof(cbd_t) * RX_RING_SIZE, 8);
+	out_be16(&ahp->scc_genscc.scc_rbase, i);
+	si->rx_bd_base = cpm_dpram_addr(i);
+	si->cur_rx = si->rx_bd_base;
+
+	i = cpm_dpalloc(sizeof(cbd_t) * TX_RING_SIZE, 8);
+	out_be16(&ahp->scc_genscc.scc_tbase, i);
+	si->tx_bd_base = cpm_dpram_addr(i);
+	si->dirty_tx = si->cur_tx = si->tx_bd_base;
+	si->tx_free = TX_RING_SIZE;
+
+	/* Issue init Tx and Rx BD command for SCC2.
+	 */
+	out_be16(&cp->cp_cpcr, mk_cr_cmd(CPM_CR_CH_SCC2, CPM_CR_INIT_TRX) | CPM_CR_FLG);
+	while (in_be16(&cp->cp_cpcr) & CPM_CR_FLG) ;
+
+	si->skb_cur = si->skb_dirty = 0;
+
+	/* Initialize function code registers for big-endian.
+	 */
+	out_8(&ahp->scc_genscc.scc_rfcr, SCC_EB);
+	out_8(&ahp->scc_genscc.scc_tfcr, SCC_EB);
+
+	/* Set maximum bytes per receive buffer.
+	 * This appears to be an Ethernet frame size, not the buffer
+	 * fragment size.  It must be a multiple of four.
+	 */
+	out_be16(&ahp->scc_genscc.scc_mrblr, 14384);
+
+	/* Set CRC preset and mask.
+	 */
+	out_be32(&ahp->ahdlc_cpres, 0x0000ffff);
+	out_be32(&ahp->ahdlc_cmask, 0x0000f0b8);
+
+	/* Clear zero register.
+	 */
+	out_be16(&ahp->ahdlc_zero, 0);
+
+	/* Program RFTHR to the number of frames to be received
+	 * before generating an interrupt.
+	 */
+	out_be16(&ahp->ahdlc_rfthr, 1);
+
+	/* Program the control character tables, TXCTL_TBL and RXCTL_TBL.
+	 */
+	out_be32(&ahp->ahdlc_txctl_tbl, 0);	// initialized to zero for IrLAP.
+	out_be32(&ahp->ahdlc_rxctl_tbl, 0);	// initialized to zero for IrLAP.
+
+	out_be16(&ahp->ahdlc_bof, 0xC0);	//IRLAP_BOF; /* Begin. of Flag Char */
+	out_be16(&ahp->ahdlc_eof, 0xC1);	//IRLAP_EOF; /* End of Flag Char */
+	out_be16(&ahp->ahdlc_esc, 0x7D);	//IRLAP_ESC; /* Control Escape Char */
+	out_be16(&ahp->ahdlc_nof, 12);
+
+	/* Now allocate the host memory pages and initialize the
+	 * buffer descriptors.
+	 */
+	bdp = si->tx_bd_base;
+	for (i = 0; i < TX_RING_SIZE; i++) {
+		/* Initialize the BD for every fragment in the page.
+		 */
+		bdp->cbd_sc = 0;
+		bdp->cbd_bufaddr = 0;
+		bdp++;
+	}
+
+	/* Set the last buffer to wrap.
+	 */
+	bdp--;
+	bdp->cbd_sc |= BD_SC_WRAP;
+
+	bdp = si->rx_bd_base;
+	k = 0;
+	for (i = 0; i < CPM_IRDA_RX_PAGES; i++) {
+
+		/* Allocate a page.
+		 */
+		ba = (unsigned char *)dma_alloc_coherent(NULL, PAGE_SIZE,
+							 &mem_addr, GFP_KERNEL);
+
+		/* Initialize the BD for every fragment in the page.
+		 */
+		for (j = 0; j < CPM_IRDA_RX_FRPPG; j++) {
+			bdp->cbd_sc = BD_AHDLC_RX_EMPTY | BD_AHDLC_RX_INTR;
+			bdp->cbd_bufaddr = mem_addr;
+			si->rx_vaddr[k++] = ba;
+			mem_addr += CPM_IRDA_RX_FRSIZE;
+			ba += CPM_IRDA_RX_FRSIZE;
+			bdp++;
+		}
+	}
+
+	/* Set the last buffer to wrap.
+	 */
+	bdp--;
+	bdp->cbd_sc |= BD_SC_WRAP;
+
+	out_be16(&sccp->scc_scce, 0xffff);	/* Clear any pending events */
+	out_be16(&sccp->scc_sccm, SCC_AHDLC_TXE | SCC_AHDLC_RXF | SCC_AHDLC_TXB);
+
+	err = request_irq(si->irq, mpc8xx_irda_irq, 0, dev->name, dev);
+	if (err) {
+		kfree(si);
+		return err;
+	}
+
+	/* Set GSMR_H to enable all normal operating modes.
+	 * Set GSMR_L to enable Ethernet to MC68160.
+	 */
+	out_be32(&sccp->scc_gsmrh, SCC_GSMRH_RFW | SCC_GSMRH_IRP);
+	out_be32(&sccp->scc_gsmrl, SCC_GSMRL_SIR | SCC_GSMRL_MODE_AHDLC | SCC_GSMRL_TDCR_16 |
+				   SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16);
+
+	out_be16(&sccp->scc_dsr, 0x7e7e);
+
+	/* Set processing mode.
+	 */
+	out_be16(&sccp->scc_psmr, SCC_PMSR_CHLN);
+
+	/* Enable the transmit and receive processing.
+	 */
+	setbits32(&sccp->scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+
+	netif_start_queue(dev);
+
+	return 0;
+}
+
+static int mpc8xx_irda_start(struct net_device *dev)
+{
+	struct mpc8xx_irda *si = dev->priv;
+	int err = 0;
+
+	if ((err = mpc8xx_irda_startup(dev)))
+		return err;
+
+	mpc8xx_irda_set_speed(dev, si->speed = 9600);
+
+	/* Open new IrLAP layer instance, now that everything should be
+	 * initialized properly
+	 */
+	si->irlap = irlap_open(dev, &si->qos, "MPC8xx SIR");
+	err = -ENOMEM;
+	if (!si->irlap) {
+		si->open = 0;
+		return err;
+	}
+
+	/* Now start the queue
+	 */
+	si->open = 1;
+	netif_start_queue(dev);
+
+	return 0;
+}
+
+static int mpc8xx_irda_stop(struct net_device *dev)
+{
+	struct mpc8xx_irda *si = dev->priv;
+
+	disable_irq(dev->irq);
+
+	/* Stop IrLAP */
+	if (si->irlap) {
+		irlap_close(si->irlap);
+		si->irlap = NULL;
+	}
+
+	netif_stop_queue(dev);
+	si->open = 0;
+
+	/* Free resources
+	 */
+	free_irq(dev->irq, dev);
+
+	return 0;
+}
+
+static void mpc8xx_irda_set_speed(struct net_device *dev, int speed)
+{
+	cpm_setbrg(2, speed);
+}
+
+static int mpc8xx_irda_probe(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct net_device *ndev;
+	struct mpc8xx_irda *si;
+	int err;
+
+	if (!(ndev = alloc_irdadev(sizeof(struct mpc8xx_irda))))
+		return -ENOMEM;
+
+	si = ndev->priv;
+	si->dev = dev;
+	si->pdata = pdev->dev.platform_data;
+
+	ndev->hard_start_xmit = mpc8xx_irda_hard_xmit;
+	ndev->open = mpc8xx_irda_start;
+	ndev->stop = mpc8xx_irda_stop;
+	ndev->do_ioctl = mpc8xx_irda_ioctl;
+	ndev->get_stats = mpc8xx_irda_stats;
+
+	irda_init_max_qos_capabilies(&si->qos);
+
+	/* We support original IRDA up to 115k2.
+	 * Min Turn Time set to 1ms or greater.
+	 */
+
+	si->qos.baud_rate.bits =
+	    IR_9600 | IR_19200 | IR_38400 | IR_57600 | IR_115200;
+	si->qos.min_turn_time.bits = 7;
+	irda_qos_bits_to_value(&si->qos);
+
+	err = register_netdev(ndev);
+
+	if (!err) {
+		dev_set_drvdata(&pdev->dev, ndev);
+		printk(KERN_INFO "IrDA: Registered device %s\n", ndev->name);
+	} else
+		free_netdev(ndev);
+
+	return err;
+}
+
+static int mpc8xx_irda_remove(struct device *_dev)
+{
+	struct net_device *dev = dev_get_drvdata(_dev);
+
+	if (dev) {
+		rtnl_lock();
+		unregister_netdevice(dev);
+		free_netdev(dev);
+		rtnl_unlock();
+	}
+
+	/*
+	 * We now know that the netdevice is no longer in use, and all
+	 * references to our driver have been removed.  The only structure
+	 * which may still be present is the netdevice, which will get
+	 * cleaned up by net/core/dev.c
+	 */
+
+	return 0;
+}
+
+static struct device_driver m8xxir_driver = {
+	.name = "fsl-cpm-scc:irda",
+	.bus = &platform_bus_type,
+	.probe = mpc8xx_irda_probe,
+	.remove = mpc8xx_irda_remove,
+};
+
+static int mpc8xx_irda_init(void)
+{
+	return driver_register(&m8xxir_driver);
+}
+
+static void __exit mpc8xx_irda_exit(void)
+{
+	driver_unregister(&m8xxir_driver);
+}
+
+module_init(mpc8xx_irda_init);
+module_exit(mpc8xx_irda_exit);
+
+MODULE_AUTHOR("source@mvista.com");
+MODULE_DESCRIPTION("MPC8XX SIR");
+MODULE_LICENSE("GPL");
diff --git a/include/asm-ppc/commproc.h b/include/asm-ppc/commproc.h
index 4f99df1..9e251c3 100644
--- a/include/asm-ppc/commproc.h
+++ b/include/asm-ppc/commproc.h
@@ -616,6 +616,73 @@ typedef struct spi {
 #define SPIE_TXB	0x02
 #define SPIE_RXB	0x01
 
+/* Asynchronous HDLC Mode Parameter RAM.
+*/
+typedef struct scc_ahdlc {
+	sccp_t  scc_genscc;
+	uint    ahdlc_res1;	/* Reserved */
+	uint    ahdlc_cmask;	/* Constant mask for CRC */
+	uint    ahdlc_cpres;	/* Preset CRC */
+	ushort  ahdlc_bof;	/* Beginning of flag character */
+	ushort  ahdlc_eof;	/* End of flag character */
+	ushort  ahdlc_esc;	/* Control escape character. */
+	ushort  ahdlc_res2;	/* Reserved */
+	ushort  ahdlc_res3;	/* Reserved */
+	ushort  ahdlc_zero;	/* Clear this field */
+	ushort  ahdlc_res4;	/* Reserved */
+	ushort  ahdlc_rfthr;	/* Received frames threshold */
+	uint    ahdlc_res5;	/* Reserved */
+	uint    ahdlc_txctl_tbl;/* Control Tx character tables */
+	uint    ahdlc_rxctl_tbl;/* Control Rx character tables */
+	ushort  ahdlc_nof;	/* Number of opening flags to be sent at the beginning of a frame */
+	ushort  ahdlc_res6;	/* Reserved */
+} scc_ahdlc_t;
+
+/* SCC Mode Register (PMSR) as used by Ethernet.
+*/
+#define SCC_PMSR_CHLN		((ushort)0x3000)        /* 8 bits character length */
+#define SICR_IRDA_MASK		((uint)0x0000ff00)
+#define SICR_IRDA_CLKRT		((uint)0x00001200)
+
+/* SCC Event register as used by Asynchronous HDLC.
+*/
+#define SCC_AHDLC_GLR		((ushort)0x1000)
+#define SCC_AHDLC_GLT		((ushort)0x0800)
+#define SCC_AHDLC_IDL		((ushort)0x0100)
+#define SCC_AHDLC_BRKE		((ushort)0x0040)
+#define SCC_AHDLC_BRKS		((ushort)0x0020)
+#define SCC_AHDLC_TXE		((ushort)0x0010)
+#define SCC_AHDLC_RXF		((ushort)0x0008)
+#define SCC_AHDLC_BSY		((ushort)0x0004)
+#define SCC_AHDLC_TXB		((ushort)0x0002)
+#define SCC_AHDLC_RXB		((ushort)0x0001)
+
+/* Buffer descriptor control/status used by AHDLC receive.
+*/
+#define BD_AHDLC_RX_EMPTY	((ushort)0x8000)
+#define BD_AHDLC_RX_WRAP	((ushort)0x2000)
+#define BD_AHDLC_RX_INTR	((ushort)0x1000)
+#define BD_AHDLC_RX_LAST	((ushort)0x0800)
+#define BD_AHDLC_RX_FIRST	((ushort)0x0400)
+#define BD_AHDLC_RX_CM		((ushort)0x0200)
+#define BD_AHDLC_RX_BRK		((ushort)0x0080)
+#define BD_AHDLC_RX_BOF		((ushort)0x0040)
+#define BD_AHDLC_RX_AB		((ushort)0x0008)
+#define BD_AHDLC_RX_CR		((ushort)0x0004)
+#define BD_AHDLC_RX_OV		((ushort)0x0002)
+#define BD_AHDLC_RX_CD		((ushort)0x0001)
+#define BD_AHDLC_RX_STATS	((ushort)0x008f)        /* All status bits */
+
+/* Buffer descriptor control/status used by AHDLC transmit.
+*/
+#define BD_AHDLC_TX_READY	((ushort)0x8000)
+#define BD_AHDLC_TX_WRAP	((ushort)0x2000)
+#define BD_AHDLC_TX_INTR	((ushort)0x1000)
+#define BD_AHDLC_TX_LAST	((ushort)0x0800)
+#define BD_AHDLC_TX_CM		((ushort)0x0200)
+#define BD_AHDLC_TX_CTS		((ushort)0x0001)
+#define BD_AHDLC_TX_STATS	((ushort)0x03ff)        /* All status bits */
+
 /*
  * RISC Controller Configuration Register definitons
  */

^ permalink raw reply related

* Re: [PATCH] ehea: Fix skb header access
From: Jeff Garzik @ 2007-05-08  5:17 UTC (permalink / raw)
  To: Thomas Klein
  Cc: Thomas Klein, Jan-Bernd Themann, netdev, linux-kernel,
	Christoph Raisch, Stefan Roscher, linux-ppc, Marcus Eder
In-Reply-To: <200705021607.05338.osstklei@de.ibm.com>

Thomas Klein wrote:
> Adapt to new skb header access functions.
> 
> Signed-off-by: Thomas Klein <tklein@de.ibm.com>

applied

^ permalink raw reply

* Please pull powerpc.git master branch
From: Paul Mackerras @ 2007-05-08  5:16 UTC (permalink / raw)
  To: torvalds; +Cc: linuxppc-dev

Linus,

Please do:

git pull \
git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc.git master

to get another powerpc update for 2.6.22.  The diffstat looks rather
large because this includes a couple of patches from Stephen Rothwell
that rename device_is_compatible to of_device_is_compatible and
get_property to of_get_property, and these renames hit a lot of device
drivers.

There are some patches from Ben that are still pending, including the
page table rework.  I'll send you a pull request for those tomorrow.

Thanks,
Paul.

 Documentation/powerpc/booting-without-of.txt      |    4 
 arch/powerpc/Kconfig                              |   19 
 arch/powerpc/Kconfig.debug                        |   22 
 arch/powerpc/Makefile                             |    2 
 arch/powerpc/boot/44x.c                           |   40 +
 arch/powerpc/boot/44x.h                           |   16 
 arch/powerpc/boot/Makefile                        |   49 +
 arch/powerpc/boot/cuboot-ebony.c                  |   42 +
 arch/powerpc/boot/dcr.h                           |   87 ++
 arch/powerpc/boot/dts/ebony.dts                   |  307 ++++++
 arch/powerpc/boot/dts/holly.dts                   |  198 ++++
 arch/powerpc/boot/dts/lite5200.dts                |   11 
 arch/powerpc/boot/dts/lite5200b.dts               |   11 
 arch/powerpc/boot/dts/mpc832x_mds.dts             |    2 
 arch/powerpc/boot/dts/mpc832x_rdb.dts             |    2 
 arch/powerpc/boot/dts/mpc836x_mds.dts             |    4 
 arch/powerpc/boot/dts/mpc8568mds.dts              |    6 
 arch/powerpc/boot/ebony.c                         |  129 +++
 arch/powerpc/boot/holly.c                         |   38 +
 arch/powerpc/boot/mktree.c                        |   10 
 arch/powerpc/boot/treeboot-ebony.c                |   34 +
 arch/powerpc/boot/wrapper                         |   36 -
 arch/powerpc/configs/ebony_defconfig              |  905 ++++++++++++++++++
 arch/powerpc/configs/holly_defconfig              | 1070 +++++++++++++++++++++
 arch/powerpc/configs/mpc832x_mds_defconfig        |   67 +
 arch/powerpc/configs/mpc832x_rdb_defconfig        |   28 -
 arch/powerpc/configs/mpc836x_mds_defconfig        |   42 +
 arch/powerpc/configs/ps3_defconfig                |  329 +++++-
 arch/powerpc/kernel/Makefile                      |    4 
 arch/powerpc/kernel/asm-offsets.c                 |    4 
 arch/powerpc/kernel/head_44x.S                    |   48 -
 arch/powerpc/kernel/idle.c                        |    5 
 arch/powerpc/kernel/idle_power4.S                 |   21 
 arch/powerpc/kernel/irq.c                         |   38 -
 arch/powerpc/kernel/kprobes.c                     |   10 
 arch/powerpc/kernel/legacy_serial.c               |   14 
 arch/powerpc/kernel/msi.c                         |   38 +
 arch/powerpc/kernel/of_device.c                   |    7 
 arch/powerpc/kernel/of_platform.c                 |    1 
 arch/powerpc/kernel/pci_32.c                      |    2 
 arch/powerpc/kernel/pci_64.c                      |    9 
 arch/powerpc/kernel/ppc_ksyms.c                   |    1 
 arch/powerpc/kernel/prom_init.c                   |   12 
 arch/powerpc/kernel/prom_parse.c                  |   25 
 arch/powerpc/kernel/smp.c                         |   73 +
 arch/powerpc/kernel/swsusp.c                      |   43 +
 arch/powerpc/kernel/swsusp_64.c                   |   24 
 arch/powerpc/kernel/swsusp_asm64.S                |  228 ++++
 arch/powerpc/kernel/sysfs.c                       |    2 
 arch/powerpc/kernel/udbg.c                        |    3 
 arch/powerpc/kernel/udbg_16550.c                  |   23 
 arch/powerpc/kernel/vio.c                         |    2 
 arch/powerpc/lib/dma-noncoherent.c                |    4 
 arch/powerpc/mm/44x_mmu.c                         |   82 --
 arch/powerpc/mm/fault.c                           |   42 -
 arch/powerpc/mm/hash_native_64.c                  |   84 +-
 arch/powerpc/mm/hash_utils_64.c                   |    2 
 arch/powerpc/mm/mem.c                             |    1 
 arch/powerpc/mm/mmu_decl.h                        |    3 
 arch/powerpc/mm/pgtable_32.c                      |   28 -
 arch/powerpc/mm/stab.c                            |    2 
 arch/powerpc/platforms/44x/44x.h                  |    8 
 arch/powerpc/platforms/44x/Kconfig                |   56 +
 arch/powerpc/platforms/44x/Makefile               |    2 
 arch/powerpc/platforms/44x/ebony.c                |   73 +
 arch/powerpc/platforms/44x/misc_44x.S             |   57 +
 arch/powerpc/platforms/52xx/Kconfig               |    1 
 arch/powerpc/platforms/52xx/Makefile              |    2 
 arch/powerpc/platforms/52xx/efika.c               |   15 
 arch/powerpc/platforms/52xx/lite5200.c            |   28 +
 arch/powerpc/platforms/52xx/mpc52xx_pm.c          |  191 ++++
 arch/powerpc/platforms/52xx/mpc52xx_sleep.S       |  154 +++
 arch/powerpc/platforms/83xx/mpc832x_mds.c         |    1 
 arch/powerpc/platforms/83xx/mpc832x_rdb.c         |    1 
 arch/powerpc/platforms/83xx/mpc836x_mds.c         |    1 
 arch/powerpc/platforms/85xx/mpc8544_ds.c          |    2 
 arch/powerpc/platforms/85xx/mpc85xx_cds.c         |    2 
 arch/powerpc/platforms/85xx/mpc85xx_mds.c         |    1 
 arch/powerpc/platforms/86xx/mpc86xx_hpcn.c        |    2 
 arch/powerpc/platforms/Kconfig                    |    1 
 arch/powerpc/platforms/Makefile                   |    3 
 arch/powerpc/platforms/cell/interrupt.c           |    6 
 arch/powerpc/platforms/cell/setup.c               |    2 
 arch/powerpc/platforms/cell/spider-pic.c          |    4 
 arch/powerpc/platforms/chrp/pci.c                 |    2 
 arch/powerpc/platforms/chrp/setup.c               |    2 
 arch/powerpc/platforms/embedded6xx/Kconfig        |   14 
 arch/powerpc/platforms/embedded6xx/Makefile       |    1 
 arch/powerpc/platforms/embedded6xx/holly.c        |  317 ++++++
 arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c |   21 
 arch/powerpc/platforms/maple/pci.c                |   12 
 arch/powerpc/platforms/maple/setup.c              |    2 
 arch/powerpc/platforms/pasemi/cpufreq.c           |    4 
 arch/powerpc/platforms/pasemi/setup.c             |    7 
 arch/powerpc/platforms/powermac/cpufreq_64.c      |    8 
 arch/powerpc/platforms/powermac/feature.c         |   26 -
 arch/powerpc/platforms/powermac/low_i2c.c         |    2 
 arch/powerpc/platforms/powermac/nvram.c           |    4 
 arch/powerpc/platforms/powermac/pci.c             |   30 -
 arch/powerpc/platforms/powermac/pic.c             |    2 
 arch/powerpc/platforms/powermac/setup.c           |  121 +-
 arch/powerpc/platforms/powermac/smp.c             |   18 
 arch/powerpc/platforms/ps3/htab.c                 |    3 
 arch/powerpc/platforms/ps3/interrupt.c            |  234 +++--
 arch/powerpc/platforms/ps3/mm.c                   |    1 
 arch/powerpc/platforms/ps3/setup.c                |    7 
 arch/powerpc/platforms/ps3/smp.c                  |    6 
 arch/powerpc/platforms/ps3/spu.c                  |   18 
 arch/powerpc/platforms/pseries/Makefile           |    1 
 arch/powerpc/platforms/pseries/eeh.c              |   30 +
 arch/powerpc/platforms/pseries/iommu.c            |    6 
 arch/powerpc/platforms/pseries/lpar.c             |    4 
 arch/powerpc/platforms/pseries/msi.c              |  270 +++++
 arch/powerpc/platforms/pseries/pci_dlpar.c        |    1 
 arch/powerpc/platforms/pseries/setup.c            |    2 
 arch/powerpc/platforms/pseries/xics.c             |    4 
 arch/powerpc/sysdev/Makefile                      |    5 
 arch/powerpc/sysdev/dart_iommu.c                  |   46 +
 arch/powerpc/sysdev/mpic.c                        |  162 +++
 arch/powerpc/sysdev/mpic.h                        |   38 +
 arch/powerpc/sysdev/mpic_msi.c                    |  183 ++++
 arch/powerpc/sysdev/mpic_u3msi.c                  |  186 ++++
 arch/powerpc/sysdev/rom.c                         |   32 -
 arch/powerpc/sysdev/tsi108_dev.c                  |    7 
 arch/powerpc/sysdev/tsi108_pci.c                  |   12 
 arch/powerpc/sysdev/uic.c                         |    2 
 arch/ppc/syslib/ppc4xx_sgdma.c                    |    2 
 drivers/ata/sata_svw.c                            |    2 
 drivers/char/agp/uninorth-agp.c                   |    2 
 drivers/char/briq_panel.c                         |    2 
 drivers/char/hvc_iseries.c                        |    2 
 drivers/char/hvc_vio.c                            |    2 
 drivers/char/tpm/tpm_atmel.h                      |    4 
 drivers/hwmon/ams/ams-core.c                      |    6 
 drivers/hwmon/ams/ams-i2c.c                       |    2 
 drivers/hwmon/ams/ams-pmu.c                       |    2 
 drivers/ide/pci/pdc202xx_new.c                    |    2 
 drivers/ide/ppc/pmac.c                            |   18 
 drivers/infiniband/hw/ehca/ehca_main.c            |    2 
 drivers/macintosh/Kconfig                         |   12 
 drivers/macintosh/apm_emu.c                       |  521 +---------
 drivers/macintosh/mac_hid.c                       |    8 
 drivers/macintosh/macio_sysfs.c                   |   27 -
 drivers/macintosh/smu.c                           |    2 
 drivers/macintosh/therm_adt746x.c                 |    4 
 drivers/macintosh/via-pmu-led.c                   |   35 -
 drivers/macintosh/via-pmu.c                       |   12 
 drivers/macintosh/windfarm_lm75_sensor.c          |    4 
 drivers/macintosh/windfarm_max6690_sensor.c       |    2 
 drivers/macintosh/windfarm_smu_controls.c         |    2 
 drivers/macintosh/windfarm_smu_sat.c              |    2 
 drivers/mtd/maps/physmap_of.c                     |    8 
 drivers/net/bmac.c                                |    5 
 drivers/net/ehea/ehea_main.c                      |   13 
 drivers/net/mace.c                                |    4 
 drivers/net/pasemi_mac.c                          |    2 
 drivers/net/spider_net.c                          |    4 
 drivers/net/sungem.c                              |    2 
 drivers/net/sungem_phy.c                          |    2 
 drivers/net/tsi108_eth.c                          |   12 
 drivers/net/tsi108_eth.h                          |    9 
 drivers/net/ucc_geth.c                            |   18 
 drivers/net/ucc_geth_mii.c                        |    4 
 drivers/pci/hotplug/rpaphp_core.c                 |   10 
 drivers/ps3/vuart.c                               |    8 
 drivers/scsi/ibmvscsi/ibmvstgt.c                  |    8 
 drivers/scsi/ibmvscsi/rpa_vscsi.c                 |    4 
 drivers/scsi/mac53c94.c                           |    2 
 drivers/scsi/mesh.c                               |    2 
 drivers/serial/mpc52xx_uart.c                     |    7 
 drivers/serial/of_serial.c                        |    4 
 drivers/serial/pmac_zilog.c                       |    8 
 drivers/usb/host/ehci-ps3.c                       |    4 
 drivers/usb/host/ohci-ppc-of.c                    |    4 
 drivers/usb/host/ohci-ps3.c                       |    4 
 drivers/video/aty/radeon_base.c                   |    6 
 drivers/video/aty/radeon_monitor.c                |   11 
 drivers/video/aty/radeon_pm.c                     |    2 
 drivers/video/nvidia/nv_of.c                      |    8 
 drivers/video/offb.c                              |   32 -
 drivers/video/ps3fb.c                             |   12 
 drivers/video/riva/fbdev.c                        |    4 
 include/asm-powerpc/iommu.h                       |   14 
 include/asm-powerpc/kdebug.h                      |   17 
 include/asm-powerpc/kprobes.h                     |    7 
 include/asm-powerpc/machdep.h                     |   19 
 include/asm-powerpc/mmu-44x.h                     |   78 ++
 include/asm-powerpc/mmu.h                         |    7 
 include/asm-powerpc/mpc52xx.h                     |   11 
 include/asm-powerpc/mpic.h                        |   20 
 include/asm-powerpc/of_device.h                   |    2 
 include/asm-powerpc/page.h                        |   10 
 include/asm-powerpc/page_32.h                     |    2 
 include/asm-powerpc/pgalloc-32.h                  |   41 +
 include/asm-powerpc/pgalloc-64.h                  |  152 +++
 include/asm-powerpc/pgalloc.h                     |  154 ---
 include/asm-powerpc/pgtable-4k.h                  |    3 
 include/asm-powerpc/pgtable-64k.h                 |    5 
 include/asm-powerpc/pgtable-ppc32.h               |  813 ++++++++++++++++
 include/asm-powerpc/pgtable-ppc64.h               |  492 ++++++++++
 include/asm-powerpc/pgtable.h                     |  493 ----------
 include/asm-powerpc/pmac_feature.h                |    2 
 include/asm-powerpc/prom.h                        |   34 -
 include/asm-powerpc/ps3.h                         |   33 -
 include/asm-powerpc/suspend.h                     |    9 
 include/asm-powerpc/tsi108.h                      |   12 
 include/asm-powerpc/tsi108_pci.h                  |   45 +
 include/asm-powerpc/udbg.h                        |    1 
 include/linux/pmu.h                               |    8 
 include/linux/suspend.h                           |    2 
 kernel/power/Kconfig                              |    4 
 sound/aoa/codecs/snd-aoa-codec-onyx.c             |    4 
 sound/aoa/codecs/snd-aoa-codec-tas.c              |    2 
 sound/aoa/soundbus/i2sbus/i2sbus-core.c           |    4 
 sound/oss/dmasound/dmasound_awacs.c               |   16 
 sound/ppc/pmac.c                                  |   14 
 sound/ppc/tumbler.c                               |    2 
 217 files changed, 8176 insertions(+), 2119 deletions(-)
 create mode 100644 arch/powerpc/boot/44x.c
 create mode 100644 arch/powerpc/boot/44x.h
 create mode 100644 arch/powerpc/boot/cuboot-ebony.c
 create mode 100644 arch/powerpc/boot/dcr.h
 create mode 100644 arch/powerpc/boot/dts/ebony.dts
 create mode 100644 arch/powerpc/boot/dts/holly.dts
 create mode 100644 arch/powerpc/boot/ebony.c
 create mode 100644 arch/powerpc/boot/holly.c
 create mode 100644 arch/powerpc/boot/treeboot-ebony.c
 create mode 100644 arch/powerpc/configs/ebony_defconfig
 create mode 100644 arch/powerpc/configs/holly_defconfig
 create mode 100644 arch/powerpc/kernel/msi.c
 create mode 100644 arch/powerpc/kernel/swsusp.c
 create mode 100644 arch/powerpc/kernel/swsusp_64.c
 create mode 100644 arch/powerpc/kernel/swsusp_asm64.S
 create mode 100644 arch/powerpc/platforms/44x/44x.h
 create mode 100644 arch/powerpc/platforms/44x/Kconfig
 create mode 100644 arch/powerpc/platforms/44x/Makefile
 create mode 100644 arch/powerpc/platforms/44x/ebony.c
 create mode 100644 arch/powerpc/platforms/44x/misc_44x.S
 create mode 100644 arch/powerpc/platforms/52xx/mpc52xx_pm.c
 create mode 100644 arch/powerpc/platforms/52xx/mpc52xx_sleep.S
 create mode 100644 arch/powerpc/platforms/embedded6xx/holly.c
 create mode 100644 arch/powerpc/platforms/pseries/msi.c
 create mode 100644 arch/powerpc/sysdev/mpic.h
 create mode 100644 arch/powerpc/sysdev/mpic_msi.c
 create mode 100644 arch/powerpc/sysdev/mpic_u3msi.c
 delete mode 100644 arch/powerpc/sysdev/rom.c
 create mode 100644 include/asm-powerpc/mmu-44x.h
 create mode 100644 include/asm-powerpc/pgalloc-32.h
 create mode 100644 include/asm-powerpc/pgalloc-64.h
 create mode 100644 include/asm-powerpc/pgtable-ppc32.h
 create mode 100644 include/asm-powerpc/pgtable-ppc64.h
 create mode 100644 include/asm-powerpc/suspend.h
 create mode 100644 include/asm-powerpc/tsi108_pci.h

Adrian Bunk (1):
      [POWERPC] drivers/macintosh/mac_hid.c: Make code static

Benjamin Herrenschmidt (1):
      [POWERPC] pmac_feature_call checks platform

Brian King (1):
      [POWERPC] Add powerpc PCI-E reset API implementation

Christian Krafft (1):
      [POWERPC] Uninline of_iomap function

Christoph Hellwig (1):
      [POWERPC] Minor fault path optimization

David Gibson (13):
      [POWERPC] Revise PPC44x MMU code for arch/powerpc
      [POWERPC] Fix STRICT_MM_TYPECHECKS
      [POWERPC] Remove arch/powerpc's dependence on asm-ppc/pg{alloc,table}.h
      [POWERPC] Small cleanups to the cuboot bootwrapper code
      [POWERPC] Kill off the PTE_FMT macro
      [POWERPC] Fix some missing build dependencies in arch/powerpc/boot
      [POWERPC] Fix build problem in ppc4xx_sgdma.c
      [POWERPC] Remove use of 4level-fixup.h for ppc32
      [POWERPC] Add powerpc/platforms/44x, disable platforms/4xx for now
      [POWERPC] Add device tree for Ebony
      [POWERPC] Support for the Ebony 440GP reference board in arch/powerpc
      [POWERPC] Early serial debug support for PPC44x
      [POWERPC] Abolish powerpc_flash_init()

Domen Puncer (4):
      [POWERPC] lite5200(b) DTS fixes
      [POWERPC] lite5200(b) support for i2c
      [POWERPC] Set efika's device_type to "soc"
      [POWERPC] mpc52xx suspend to deep-sleep

Geoff Levand (4):
      [POWERPC] PS3: Add DABR support
      [POWERPC] PS3: Remove duplicate variable assignement
      [POWERPC] PS3: Interrupt routine fixups.
      [POWERPC] PS3: Defconfig updates

Grant Likely (1):
      [POWERPC] Don't shutdown TX on mpc5200 serial port if it is a console

Jan Engelhardt (1):
      [POWERPC] Use menuconfig objects II - Macintosh

Johannes Berg (9):
      [POWERPC] Remove unneeded page_is_ram export
      [POWERPC] apm_emu: Use generic apm-emulation
      [POWERPC] powermac: Fix G5-cpufreq for cpu on/offline
      [POWERPC] Fix suspend states again
      [POWERPC] MPIC sys_device & suspend/resume
      [POWERPC] powermac: Support G5 CPU hotplug
      [POWERPC] DART iommu suspend
      [POWERPC] powermac: Suspend to disk on G5
      [POWERPC] via-pmu: remove LED sleep notifier

Josh Boyer (8):
      [POWERPC] Fix spurious vectors on weird MPIC
      [POWERPC] Add tsi108_pci.h for common PCI functions
      [POWERPC] Generalize tsi108 PHY types
      [POWERPC] Generalize tsi108 PCI setup
      [POWERPC] Add support for 750CL Holly board
      [POWERPC] Holly defconfig
      [POWERPC] Holly DTS
      [POWERPC] Holly bootwrapper

Kevin Corry (1):
      [POWERPC] Change topology_init() to a subsys_initcall

Kim Phillips (4):
      [POWERPC] Document phy-connection-type property
      [POWERPC] Replace undocumented interface properties in dts files
      [POWERPC] Add 'mdio' to bus scan id list for platforms with QE UEC
      [POWERPC] Turn on corresponding PHY drivers in QE UEC platforms defconfigs

Linas Vepstas (2):
      [POWERPC] pseries: Handle null iommu dma-window property correctly
      [POWERPC] Export pcibios_remove_pci_devices

Luke Browning (1):
      [POWERPC] 64K page support for kexec

Mathieu Desnoyers (1):
      [POWERPC] Move of_irq_to_resource from prom.h to prom_parse.c

Michael Ellerman (9):
      [POWERPC] Initialise spinlock in the DEBUG_PAGEALLOC code
      [POWERPC] Add __init annotations to reserve_mem() and stabs_alloc()
      [POWERPC] Rip out the existing powerpc msi stubs
      [POWERPC] PowerPC MSI infrastructure
      [POWERPC] RTAS MSI implementation
      [POWERPC] Tell Phyp we support MSI
      [POWERPC] Enable MSI mappings for MPIC
      [POWERPC] MPIC MSI allocator
      [POWERPC] MPIC U3/U4 MSI backend

Olof Johansson (2):
      [POWERPC] pasemi: Only call of_platform_bus_probe() on relevant platforms
      [POWERPC] pasemi: Update ppc_proc_freq from cpufreq driver

Paul Mackerras (1):
      [POWERPC] Cope with PCI host bridge I/O window not starting at 0

Scott Wood (2):
      [POWERPC] Remove duplicate export of __div64_32.
      [POWERPC] bootwrapper: Only build cuImage if CONFIG_DEVICE_TREE is non-empty

Srinivasa Ds (1):
      [POWERPC] Transparently handle <.symbol> lookup for kprobes

Stephen Rothwell (3):
      [POWERPC] get_property returns const
      [POWERPC] Rename get_property to of_get_property: drivers
      [POWERPC] Rename device_is_compatible to of_device_is_compatible

Sylvain Munaut (2):
      [POWERPC] Export of_device_get_modalias
      [POWERPC] macintosh: Use common modalias generation for macio_sysfs

Takao Shinohara (1):
      [POWERPC] PS3: Fix system slowdown

Zang Roy-r61911 (1):
      [POWERPC] kernel: Remove loops_per_jiffy code for 7448HPC2 platforms

will schmidt (1):
      [POWERPC] Add smp_call_function_map and smp_call_function_single

^ permalink raw reply

* [PATCH 2/3] [POWERPC] 8xx: fix whitespace and indentation
From: Vitaly Bordug @ 2007-05-08  0:43 UTC (permalink / raw)
  To: linux-pcmcia; +Cc: linuxppc-dev, linux-kernel
In-Reply-To: <20070508003642.5964.37001.stgit@localhost.localdomain>


Rolling forward PCMCIA driver, it was discovered that the indentation
in existing one is very odd. This patch is just result of Lindent run ontop
of culprit files.

Signed-off-by: Vitaly Bordug <vitb@kernel.crashing.org>

---

 drivers/pcmcia/m8xx_pcmcia.c |  548 +++++++++++++++++++++---------------------
 1 files changed, 278 insertions(+), 270 deletions(-)

diff --git a/drivers/pcmcia/m8xx_pcmcia.c b/drivers/pcmcia/m8xx_pcmcia.c
index 40f6e20..79e14ab 100644
--- a/drivers/pcmcia/m8xx_pcmcia.c
+++ b/drivers/pcmcia/m8xx_pcmcia.c
@@ -113,7 +113,7 @@ MODULE_LICENSE("Dual MPL/GPL");
 #define CONFIG_PCMCIA_SLOT_B
 #endif
 
-#endif /* !defined(CONFIG_PCMCIA_SLOT_A) && !defined(CONFIG_PCMCIA_SLOT_B) */
+#endif				/* !defined(CONFIG_PCMCIA_SLOT_A) && !defined(CONFIG_PCMCIA_SLOT_B) */
 
 #if defined(CONFIG_PCMCIA_SLOT_A) && defined(CONFIG_PCMCIA_SLOT_B)
 
@@ -146,9 +146,9 @@ MODULE_LICENSE("Dual MPL/GPL");
 
 /* ------------------------------------------------------------------------- */
 
-#define PCMCIA_MEM_WIN_BASE 0xe0000000 /* base address for memory window 0   */
-#define PCMCIA_MEM_WIN_SIZE 0x04000000 /* each memory window is 64 MByte     */
-#define PCMCIA_IO_WIN_BASE  _IO_BASE   /* base address for io window 0       */
+#define PCMCIA_MEM_WIN_BASE 0xe0000000	/* base address for memory window 0   */
+#define PCMCIA_MEM_WIN_SIZE 0x04000000	/* each memory window is 64 MByte     */
+#define PCMCIA_IO_WIN_BASE  _IO_BASE	/* base address for io window 0       */
 /* ------------------------------------------------------------------------- */
 
 static int pcmcia_schlvl;
@@ -169,8 +169,8 @@ static u32 *m8xx_pgcrx[2];
  */
 
 struct pcmcia_win {
-	u32	br;
-	u32	or;
+	u32 br;
+	u32 or;
 };
 
 /*
@@ -214,7 +214,7 @@ struct pcmcia_win {
 
 /* we keep one lookup table per socket to check flags */
 
-#define PCMCIA_EVENTS_MAX 5  /* 4 max at a time + termination */
+#define PCMCIA_EVENTS_MAX 5	/* 4 max at a time + termination */
 
 struct event_table {
 	u32 regbit;
@@ -224,8 +224,8 @@ struct event_table {
 static const char driver_name[] = "m8xx-pcmcia";
 
 struct socket_info {
-	void	(*handler)(void *info, u32 events);
-	void	*info;
+	void (*handler) (void *info, u32 events);
+	void *info;
 
 	u32 slot;
 	pcmconf8xx_t *pcmcia;
@@ -234,7 +234,7 @@ struct socket_info {
 
 	socket_state_t state;
 	struct pccard_mem_map mem_win[PCMCIA_MEM_WIN_NO];
-	struct pccard_io_map  io_win[PCMCIA_IO_WIN_NO];
+	struct pccard_io_map io_win[PCMCIA_IO_WIN_NO];
 	struct event_table events[PCMCIA_EVENTS_MAX];
 	struct pcmcia_socket socket;
 };
@@ -248,8 +248,7 @@ static struct socket_info socket[PCMCIA_SOCKETS_NO];
 
 #define M8XX_SIZES_NO 32
 
-static const u32 m8xx_size_to_gray[M8XX_SIZES_NO] =
-{
+static const u32 m8xx_size_to_gray[M8XX_SIZES_NO] = {
 	0x00000001, 0x00000002, 0x00000008, 0x00000004,
 	0x00000080, 0x00000040, 0x00000010, 0x00000020,
 	0x00008000, 0x00004000, 0x00001000, 0x00002000,
@@ -265,7 +264,7 @@ static const u32 m8xx_size_to_gray[M8XX_SIZES_NO] =
 
 static irqreturn_t m8xx_interrupt(int irq, void *dev);
 
-#define PCMCIA_BMT_LIMIT (15*4)  /* Bus Monitor Timeout value */
+#define PCMCIA_BMT_LIMIT (15*4)	/* Bus Monitor Timeout value */
 
 /* ------------------------------------------------------------------------- */
 /* board specific stuff:                                                     */
@@ -289,8 +288,9 @@ static int voltage_set(int slot, int vcc, int vpp)
 {
 	u32 reg = 0;
 
-	switch(vcc) {
-	case 0: break;
+	switch (vcc) {
+	case 0:
+		break;
 	case 33:
 		reg |= BCSR1_PCVCTL4;
 		break;
@@ -301,11 +301,12 @@ static int voltage_set(int slot, int vcc, int vpp)
 		return 1;
 	}
 
-	switch(vpp) {
-	case 0: break;
+	switch (vpp) {
+	case 0:
+		break;
 	case 33:
 	case 50:
-		if(vcc == vpp)
+		if (vcc == vpp)
 			reg |= BCSR1_PCVCTL6;
 		else
 			return 1;
@@ -316,25 +317,29 @@ static int voltage_set(int slot, int vcc, int vpp)
 		return 1;
 	}
 
-	if(!((vcc == 50) || (vcc == 0)))
+	if (!((vcc == 50) || (vcc == 0)))
 		return 1;
 
 	/* first, turn off all power */
 
-	out_be32(((u32 *)RPX_CSR_ADDR), in_be32(((u32 *)RPX_CSR_ADDR)) & ~(BCSR1_PCVCTL4 | BCSR1_PCVCTL5 | BCSR1_PCVCTL6 | BCSR1_PCVCTL7));
+	out_be32(((u32 *) RPX_CSR_ADDR),
+		 in_be32(((u32 *) RPX_CSR_ADDR)) & ~(BCSR1_PCVCTL4 |
+						     BCSR1_PCVCTL5 |
+						     BCSR1_PCVCTL6 |
+						     BCSR1_PCVCTL7));
 
 	/* enable new powersettings */
 
-	out_be32(((u32 *)RPX_CSR_ADDR), in_be32(((u32 *)RPX_CSR_ADDR)) | reg);
+	out_be32(((u32 *) RPX_CSR_ADDR), in_be32(((u32 *) RPX_CSR_ADDR)) | reg);
 
 	return 0;
 }
 
 #define socket_get(_slot_) PCMCIA_SOCKET_KEY_5V
-#define hardware_enable(_slot_)  /* No hardware to enable */
-#define hardware_disable(_slot_) /* No hardware to disable */
+#define hardware_enable(_slot_)	/* No hardware to enable */
+#define hardware_disable(_slot_)	/* No hardware to disable */
 
-#endif /* CONFIG_RPXCLASSIC */
+#endif				/* CONFIG_RPXCLASSIC */
 
 /* FADS Boards from Motorola                                               */
 
@@ -346,43 +351,45 @@ static int voltage_set(int slot, int vcc, int vpp)
 {
 	u32 reg = 0;
 
-	switch(vcc) {
-		case 0:
-			break;
-		case 33:
-			reg |= BCSR1_PCCVCC0;
-			break;
-		case 50:
-			reg |= BCSR1_PCCVCC1;
-			break;
-		default:
-			return 1;
+	switch (vcc) {
+	case 0:
+		break;
+	case 33:
+		reg |= BCSR1_PCCVCC0;
+		break;
+	case 50:
+		reg |= BCSR1_PCCVCC1;
+		break;
+	default:
+		return 1;
 	}
 
-	switch(vpp) {
-		case 0:
-			break;
-		case 33:
-		case 50:
-			if(vcc == vpp)
-				reg |= BCSR1_PCCVPP1;
-			else
-				return 1;
-			break;
-		case 120:
-			if ((vcc == 33) || (vcc == 50))
-				reg |= BCSR1_PCCVPP0;
-			else
-				return 1;
-		default:
+	switch (vpp) {
+	case 0:
+		break;
+	case 33:
+	case 50:
+		if (vcc == vpp)
+			reg |= BCSR1_PCCVPP1;
+		else
 			return 1;
+		break;
+	case 120:
+		if ((vcc == 33) || (vcc == 50))
+			reg |= BCSR1_PCCVPP0;
+		else
+			return 1;
+	default:
+		return 1;
 	}
 
 	/* first, turn off all power */
-	out_be32((u32 *)BCSR1, in_be32((u32 *)BCSR1) & ~(BCSR1_PCCVCC_MASK | BCSR1_PCCVPP_MASK));
+	out_be32((u32 *) BCSR1,
+		 in_be32((u32 *) BCSR1) & ~(BCSR1_PCCVCC_MASK |
+					    BCSR1_PCCVPP_MASK));
 
 	/* enable new powersettings */
-	out_be32((u32 *)BCSR1, in_be32((u32 *)BCSR1) | reg);
+	out_be32((u32 *) BCSR1, in_be32((u32 *) BCSR1) | reg);
 
 	return 0;
 }
@@ -391,12 +398,12 @@ static int voltage_set(int slot, int vcc, int vpp)
 
 static void hardware_enable(int slot)
 {
-	out_be32((u32 *)BCSR1, in_be32((u32 *)BCSR1) & ~BCSR1_PCCEN);
+	out_be32((u32 *) BCSR1, in_be32((u32 *) BCSR1) & ~BCSR1_PCCEN);
 }
 
 static void hardware_disable(int slot)
 {
-	out_be32((u32 *)BCSR1, in_be32((u32 *)BCSR1) |  BCSR1_PCCEN);
+	out_be32((u32 *) BCSR1, in_be32((u32 *) BCSR1) | BCSR1_PCCEN);
 }
 
 #endif
@@ -410,7 +417,7 @@ static void hardware_disable(int slot)
 
 static inline void hardware_enable(int slot)
 {
-	 m8xx_pcmcia_ops.hw_ctrl(slot, 1);
+	m8xx_pcmcia_ops.hw_ctrl(slot, 1);
 }
 
 static inline void hardware_disable(int slot)
@@ -436,52 +443,53 @@ static int voltage_set(int slot, int vcc, int vpp)
 {
 	u8 reg = 0;
 
-	switch(vcc) {
-		case 0:
-			break;
-		case 33:
-			reg |= CSR2_VCC_33;
-			break;
-		case 50:
-			reg |= CSR2_VCC_50;
-			break;
-		default:
-			return 1;
+	switch (vcc) {
+	case 0:
+		break;
+	case 33:
+		reg |= CSR2_VCC_33;
+		break;
+	case 50:
+		reg |= CSR2_VCC_50;
+		break;
+	default:
+		return 1;
 	}
 
-	switch(vpp) {
-		case 0:
-			break;
-		case 33:
-		case 50:
-			if(vcc == vpp)
-				reg |= CSR2_VPP_VCC;
-			else
-				return 1;
-			break;
-		case 120:
-			if ((vcc == 33) || (vcc == 50))
-				reg |= CSR2_VPP_12;
-			else
-				return 1;
-		default:
+	switch (vpp) {
+	case 0:
+		break;
+	case 33:
+	case 50:
+		if (vcc == vpp)
+			reg |= CSR2_VPP_VCC;
+		else
+			return 1;
+		break;
+	case 120:
+		if ((vcc == 33) || (vcc == 50))
+			reg |= CSR2_VPP_12;
+		else
 			return 1;
+	default:
+		return 1;
 	}
 
 	/* first, turn off all power */
-	out_8((u8 *)MBX_CSR2_ADDR, in_8((u8 *)MBX_CSR2_ADDR) & ~(CSR2_VCC_MASK | CSR2_VPP_MASK));
+	out_8((u8 *) MBX_CSR2_ADDR,
+	      in_8((u8 *) MBX_CSR2_ADDR) & ~(CSR2_VCC_MASK | CSR2_VPP_MASK));
 
 	/* enable new powersettings */
-	out_8((u8 *)MBX_CSR2_ADDR, in_8((u8 *)MBX_CSR2_ADDR) | reg);
+	out_8((u8 *) MBX_CSR2_ADDR, in_8((u8 *) MBX_CSR2_ADDR) | reg);
 
 	return 0;
 }
 
 #define socket_get(_slot_) PCMCIA_SOCKET_KEY_5V
-#define hardware_enable(_slot_)  /* No hardware to enable */
-#define hardware_disable(_slot_) /* No hardware to disable */
+#define hardware_enable(_slot_)	/* No hardware to enable */
+#define hardware_disable(_slot_)	/* No hardware to disable */
 
-#endif /* CONFIG_MBX */
+#endif				/* CONFIG_MBX */
 
 #if defined(CONFIG_PRxK)
 #include <asm/cpld.h>
@@ -495,43 +503,46 @@ static int voltage_set(int slot, int vcc, int vpp)
 	u8 regread;
 	cpld_regs *ccpld = get_cpld();
 
-	switch(vcc) {
-		case 0:
-			break;
-		case 33:
-			reg |= PCMCIA_VCC_33;
-			break;
-		case 50:
-			reg |= PCMCIA_VCC_50;
-			break;
-		default:
-			return 1;
+	switch (vcc) {
+	case 0:
+		break;
+	case 33:
+		reg |= PCMCIA_VCC_33;
+		break;
+	case 50:
+		reg |= PCMCIA_VCC_50;
+		break;
+	default:
+		return 1;
 	}
 
-	switch(vpp) {
-		case 0:
-			break;
-		case 33:
-		case 50:
-			if(vcc == vpp)
-				reg |= PCMCIA_VPP_VCC;
-			else
-				return 1;
-			break;
-		case 120:
-			if ((vcc == 33) || (vcc == 50))
-				reg |= PCMCIA_VPP_12;
-			else
-				return 1;
-		default:
+	switch (vpp) {
+	case 0:
+		break;
+	case 33:
+	case 50:
+		if (vcc == vpp)
+			reg |= PCMCIA_VPP_VCC;
+		else
 			return 1;
+		break;
+	case 120:
+		if ((vcc == 33) || (vcc == 50))
+			reg |= PCMCIA_VPP_12;
+		else
+			return 1;
+	default:
+		return 1;
 	}
 
 	reg = reg >> (slot << 2);
 	regread = in_8(&ccpld->fpga_pc_ctl);
-	if (reg != (regread & ((PCMCIA_VCC_MASK | PCMCIA_VPP_MASK) >> (slot << 2)))) {
+	if (reg !=
+	    (regread & ((PCMCIA_VCC_MASK | PCMCIA_VPP_MASK) >> (slot << 2)))) {
 		/* enable new powersettings */
-		regread = regread & ~((PCMCIA_VCC_MASK | PCMCIA_VPP_MASK) >> (slot << 2));
+		regread =
+		    regread & ~((PCMCIA_VCC_MASK | PCMCIA_VPP_MASK) >>
+				(slot << 2));
 		out_8(&ccpld->fpga_pc_ctl, reg | regread);
 		msleep(100);
 	}
@@ -540,10 +551,10 @@ static int voltage_set(int slot, int vcc, int vpp)
 }
 
 #define socket_get(_slot_) PCMCIA_SOCKET_KEY_LV
-#define hardware_enable(_slot_)  /* No hardware to enable */
-#define hardware_disable(_slot_) /* No hardware to disable */
+#define hardware_enable(_slot_)	/* No hardware to enable */
+#define hardware_disable(_slot_)	/* No hardware to disable */
 
-#endif /* CONFIG_PRxK */
+#endif				/* CONFIG_PRxK */
 
 static u32 pending_events[PCMCIA_SOCKETS_NO];
 static DEFINE_SPINLOCK(pending_event_lock);
@@ -553,7 +564,7 @@ static irqreturn_t m8xx_interrupt(int irq, void *dev)
 	struct socket_info *s;
 	struct event_table *e;
 	unsigned int i, events, pscr, pipr, per;
-	pcmconf8xx_t	*pcmcia = socket[0].pcmcia;
+	pcmconf8xx_t *pcmcia = socket[0].pcmcia;
 
 	dprintk("Interrupt!\n");
 	/* get interrupt sources */
@@ -562,16 +573,16 @@ static irqreturn_t m8xx_interrupt(int irq, void *dev)
 	pipr = in_be32(&pcmcia->pcmc_pipr);
 	per = in_be32(&pcmcia->pcmc_per);
 
-	for(i = 0; i < PCMCIA_SOCKETS_NO; i++) {
+	for (i = 0; i < PCMCIA_SOCKETS_NO; i++) {
 		s = &socket[i];
 		e = &s->events[0];
 		events = 0;
 
-		while(e->regbit) {
-			if(pscr & e->regbit)
+		while (e->regbit) {
+			if (pscr & e->regbit)
 				events |= e->eventbit;
 
-				e++;
+			e++;
 		}
 
 		/*
@@ -579,13 +590,11 @@ static irqreturn_t m8xx_interrupt(int irq, void *dev)
 		 * not too nice done,
 		 * we depend on that CD2 is the bit to the left of CD1...
 		 */
-		if(events & SS_DETECT)
-			if(((pipr & M8XX_PCMCIA_CD2(i)) >> 1) ^
-				(pipr & M8XX_PCMCIA_CD1(i)))
-			{
+		if (events & SS_DETECT)
+			if (((pipr & M8XX_PCMCIA_CD2(i)) >> 1) ^
+			    (pipr & M8XX_PCMCIA_CD1(i))) {
 				events &= ~SS_DETECT;
 			}
-
 #ifdef PCMCIA_GLITCHY_CD
 		/*
 		 * I've experienced CD problems with my ADS board.
@@ -593,24 +602,23 @@ static irqreturn_t m8xx_interrupt(int irq, void *dev)
 		 * real change of Card detection.
 		 */
 
-		if((events & SS_DETECT) &&
-		   ((pipr &
-		     (M8XX_PCMCIA_CD2(i) | M8XX_PCMCIA_CD1(i))) == 0) &&
-		   (s->state.Vcc | s->state.Vpp)) {
+		if ((events & SS_DETECT) &&
+		    ((pipr &
+		      (M8XX_PCMCIA_CD2(i) | M8XX_PCMCIA_CD1(i))) == 0) &&
+		    (s->state.Vcc | s->state.Vpp)) {
 			events &= ~SS_DETECT;
 			/*printk( "CD glitch workaround - CD = 0x%08x!\n",
-				(pipr & (M8XX_PCMCIA_CD2(i)
-					 | M8XX_PCMCIA_CD1(i))));*/
+			   (pipr & (M8XX_PCMCIA_CD2(i)
+			   | M8XX_PCMCIA_CD1(i)))); */
 		}
 #endif
 
 		/* call the handler */
 
 		dprintk("slot %u: events = 0x%02x, pscr = 0x%08x, "
-			"pipr = 0x%08x\n",
-			i, events, pscr, pipr);
+			"pipr = 0x%08x\n", i, events, pscr, pipr);
 
-		if(events) {
+		if (events) {
 			spin_lock(&pending_event_lock);
 			pending_events[i] |= events;
 			spin_unlock(&pending_event_lock);
@@ -643,11 +651,11 @@ static u32 m8xx_get_graycode(u32 size)
 {
 	u32 k;
 
-	for(k = 0; k < M8XX_SIZES_NO; k++)
-		if(m8xx_size_to_gray[k] == size)
+	for (k = 0; k < M8XX_SIZES_NO; k++)
+		if (m8xx_size_to_gray[k] == size)
 			break;
 
-	if((k == M8XX_SIZES_NO) || (m8xx_size_to_gray[k] == -1))
+	if ((k == M8XX_SIZES_NO) || (m8xx_size_to_gray[k] == -1))
 		k = -1;
 
 	return k;
@@ -657,7 +665,7 @@ static u32 m8xx_get_speed(u32 ns, u32 is_io, u32 bus_freq)
 {
 	u32 reg, clocks, psst, psl, psht;
 
-	if(!ns) {
+	if (!ns) {
 
 		/*
 		 * We get called with IO maps setup to 0ns
@@ -665,10 +673,10 @@ static u32 m8xx_get_speed(u32 ns, u32 is_io, u32 bus_freq)
 		 * They should be 255ns.
 		 */
 
-		if(is_io)
+		if (is_io)
 			ns = 255;
 		else
-			ns = 100;  /* fast memory if 0 */
+			ns = 100;	/* fast memory if 0 */
 	}
 
 	/*
@@ -679,23 +687,23 @@ static u32 m8xx_get_speed(u32 ns, u32 is_io, u32 bus_freq)
 
 /* how we want to adjust the timing - in percent */
 
-#define ADJ 180 /* 80 % longer accesstime - to be sure */
+#define ADJ 180			/* 80 % longer accesstime - to be sure */
 
 	clocks = ((bus_freq / 1000) * ns) / 1000;
-	clocks = (clocks * ADJ) / (100*1000);
-	if(clocks >= PCMCIA_BMT_LIMIT) {
-		printk( "Max access time limit reached\n");
-		clocks = PCMCIA_BMT_LIMIT-1;
+	clocks = (clocks * ADJ) / (100 * 1000);
+	if (clocks >= PCMCIA_BMT_LIMIT) {
+		printk("Max access time limit reached\n");
+		clocks = PCMCIA_BMT_LIMIT - 1;
 	}
 
-	psst = clocks / 7;          /* setup time */
-	psht = clocks / 7;          /* hold time */
-	psl  = (clocks * 5) / 7;    /* strobe length */
+	psst = clocks / 7;	/* setup time */
+	psht = clocks / 7;	/* hold time */
+	psl = (clocks * 5) / 7;	/* strobe length */
 
 	psst += clocks - (psst + psht + psl);
 
-	reg =  psst << 12;
-	reg |= psl  << 7;
+	reg = psst << 12;
+	reg |= psl << 7;
 	reg |= psht << 16;
 
 	return reg;
@@ -710,8 +718,8 @@ static int m8xx_get_status(struct pcmcia_socket *sock, unsigned int *value)
 
 	pipr = in_be32(&pcmcia->pcmc_pipr);
 
-	*value  = ((pipr & (M8XX_PCMCIA_CD1(lsock)
-			    | M8XX_PCMCIA_CD2(lsock))) == 0) ? SS_DETECT : 0;
+	*value = ((pipr & (M8XX_PCMCIA_CD1(lsock)
+			   | M8XX_PCMCIA_CD2(lsock))) == 0) ? SS_DETECT : 0;
 	*value |= (pipr & M8XX_PCMCIA_WP(lsock)) ? SS_WRPROT : 0;
 
 	if (s->state.flags & SS_IOCARD)
@@ -795,16 +803,16 @@ static int m8xx_get_status(struct pcmcia_socket *sock, unsigned int *value)
 	/* read out VS1 and VS2 */
 
 	reg = (pipr & M8XX_PCMCIA_VS_MASK(lsock))
-		>> M8XX_PCMCIA_VS_SHIFT(lsock);
+	    >> M8XX_PCMCIA_VS_SHIFT(lsock);
 
-	if(socket_get(lsock) == PCMCIA_SOCKET_KEY_LV) {
-		switch(reg) {
+	if (socket_get(lsock) == PCMCIA_SOCKET_KEY_LV) {
+		switch (reg) {
 		case 1:
 			*value |= SS_3VCARD;
-			break; /* GND, NC - 3.3V only */
+			break;	/* GND, NC - 3.3V only */
 		case 2:
 			*value |= SS_XVCARD;
-			break; /* NC. GND - x.xV only */
+			break;	/* NC. GND - x.xV only */
 		};
 	}
 
@@ -812,7 +820,7 @@ static int m8xx_get_status(struct pcmcia_socket *sock, unsigned int *value)
 	return 0;
 }
 
-static int m8xx_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
+static int m8xx_set_socket(struct pcmcia_socket *sock, socket_state_t * state)
 {
 	int lsock = container_of(sock, struct socket_info, socket)->slot;
 	struct socket_info *s = &socket[lsock];
@@ -821,20 +829,20 @@ static int m8xx_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
 	unsigned long flags;
 	pcmconf8xx_t *pcmcia = socket[0].pcmcia;
 
-	dprintk( "SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, "
-	      "io_irq %d, csc_mask %#2.2x)\n", lsock, state->flags,
-	      state->Vcc, state->Vpp, state->io_irq, state->csc_mask);
+	dprintk("SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, "
+		"io_irq %d, csc_mask %#2.2x)\n", lsock, state->flags,
+		state->Vcc, state->Vpp, state->io_irq, state->csc_mask);
 
 	/* First, set voltage - bail out if invalid */
-	if(voltage_set(lsock, state->Vcc, state->Vpp))
+	if (voltage_set(lsock, state->Vcc, state->Vpp))
 		return -EINVAL;
 
-
 	/* Take care of reset... */
-	if(state->flags & SS_RESET)
-		out_be32(M8XX_PGCRX(lsock), in_be32(M8XX_PGCRX(lsock)) |  M8XX_PGCRX_CXRESET); /* active high */
+	if (state->flags & SS_RESET)
+		out_be32(M8XX_PGCRX(lsock), in_be32(M8XX_PGCRX(lsock)) | M8XX_PGCRX_CXRESET);	/* active high */
 	else
-		out_be32(M8XX_PGCRX(lsock), in_be32(M8XX_PGCRX(lsock)) & ~M8XX_PGCRX_CXRESET);
+		out_be32(M8XX_PGCRX(lsock),
+			 in_be32(M8XX_PGCRX(lsock)) & ~M8XX_PGCRX_CXRESET);
 
 	/* ... and output enable. */
 
@@ -846,10 +854,11 @@ static int m8xx_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
 	   no pullups are present -> the cards act wierd.
 	   So right now the buffers are enabled if the power is on. */
 
-	if(state->Vcc || state->Vpp)
-		out_be32(M8XX_PGCRX(lsock), in_be32(M8XX_PGCRX(lsock)) & ~M8XX_PGCRX_CXOE); /* active low */
+	if (state->Vcc || state->Vpp)
+		out_be32(M8XX_PGCRX(lsock), in_be32(M8XX_PGCRX(lsock)) & ~M8XX_PGCRX_CXOE);	/* active low */
 	else
-		out_be32(M8XX_PGCRX(lsock), in_be32(M8XX_PGCRX(lsock)) | M8XX_PGCRX_CXOE);
+		out_be32(M8XX_PGCRX(lsock),
+			 in_be32(M8XX_PGCRX(lsock)) | M8XX_PGCRX_CXOE);
 
 	/*
 	 * We'd better turn off interrupts before
@@ -866,17 +875,17 @@ static int m8xx_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
 	e = &s->events[0];
 	reg = 0;
 
-	if(state->csc_mask & SS_DETECT) {
+	if (state->csc_mask & SS_DETECT) {
 		e->eventbit = SS_DETECT;
 		reg |= e->regbit = (M8XX_PCMCIA_CD2(lsock)
 				    | M8XX_PCMCIA_CD1(lsock));
 		e++;
 	}
-	if(state->flags & SS_IOCARD) {
+	if (state->flags & SS_IOCARD) {
 		/*
 		 * I/O card
 		 */
-		if(state->csc_mask & SS_STSCHG) {
+		if (state->csc_mask & SS_STSCHG) {
 			e->eventbit = SS_STSCHG;
 			reg |= e->regbit = M8XX_PCMCIA_BVD1(lsock);
 			e++;
@@ -884,9 +893,10 @@ static int m8xx_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
 		/*
 		 * If io_irq is non-zero we should enable irq.
 		 */
-		if(state->io_irq) {
+		if (state->io_irq) {
 			out_be32(M8XX_PGCRX(lsock),
-				 in_be32(M8XX_PGCRX(lsock)) | mk_int_int_mask(s->hwirq) << 24);
+				 in_be32(M8XX_PGCRX(lsock)) |
+				 mk_int_int_mask(s->hwirq) << 24);
 			/*
 			 * Strange thing here:
 			 * The manual does not tell us which interrupt
@@ -897,33 +907,32 @@ static int m8xx_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
 			 * have to be cleared in PSCR in the interrupt handler.
 			 */
 			reg |= M8XX_PCMCIA_RDY_L(lsock);
-		}
-		else
-			out_be32(M8XX_PGCRX(lsock), in_be32(M8XX_PGCRX(lsock)) & 0x00ffffff);
-	}
-	else {
+		} else
+			out_be32(M8XX_PGCRX(lsock),
+				 in_be32(M8XX_PGCRX(lsock)) & 0x00ffffff);
+	} else {
 		/*
 		 * Memory card
 		 */
-		if(state->csc_mask & SS_BATDEAD) {
+		if (state->csc_mask & SS_BATDEAD) {
 			e->eventbit = SS_BATDEAD;
 			reg |= e->regbit = M8XX_PCMCIA_BVD1(lsock);
 			e++;
 		}
-		if(state->csc_mask & SS_BATWARN) {
+		if (state->csc_mask & SS_BATWARN) {
 			e->eventbit = SS_BATWARN;
 			reg |= e->regbit = M8XX_PCMCIA_BVD2(lsock);
 			e++;
 		}
 		/* What should I trigger on - low/high,raise,fall? */
-		if(state->csc_mask & SS_READY) {
+		if (state->csc_mask & SS_READY) {
 			e->eventbit = SS_READY;
-			reg |= e->regbit = 0; //??
+			reg |= e->regbit = 0;	//??
 			e++;
 		}
 	}
 
-	e->regbit = 0;  /* terminate list */
+	e->regbit = 0;		/* terminate list */
 
 	/*
 	 * Clear the status changed .
@@ -940,7 +949,9 @@ static int m8xx_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
 	 * Ones will enable the interrupt.
 	 */
 
-	reg |= in_be32(&pcmcia->pcmc_per) & (M8XX_PCMCIA_MASK(0) | M8XX_PCMCIA_MASK(1));
+	reg |=
+	    in_be32(&pcmcia->
+		    pcmc_per) & (M8XX_PCMCIA_MASK(0) | M8XX_PCMCIA_MASK(1));
 	out_be32(&pcmcia->pcmc_per, reg);
 
 	spin_unlock_irqrestore(&events_lock, flags);
@@ -961,67 +972,66 @@ static int m8xx_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *io)
 	unsigned int reg, winnr;
 	pcmconf8xx_t *pcmcia = s->pcmcia;
 
-
 #define M8XX_SIZE (io->stop - io->start + 1)
 #define M8XX_BASE (PCMCIA_IO_WIN_BASE + io->start)
 
-	dprintk( "SetIOMap(%d, %d, %#2.2x, %d ns, "
-	      "%#4.4x-%#4.4x)\n", lsock, io->map, io->flags,
-	      io->speed, io->start, io->stop);
+	dprintk("SetIOMap(%d, %d, %#2.2x, %d ns, "
+		"%#4.4x-%#4.4x)\n", lsock, io->map, io->flags,
+		io->speed, io->start, io->stop);
 
 	if ((io->map >= PCMCIA_IO_WIN_NO) || (io->start > 0xffff)
 	    || (io->stop > 0xffff) || (io->stop < io->start))
 		return -EINVAL;
 
-	if((reg = m8xx_get_graycode(M8XX_SIZE)) == -1)
+	if ((reg = m8xx_get_graycode(M8XX_SIZE)) == -1)
 		return -EINVAL;
 
-	if(io->flags & MAP_ACTIVE) {
+	if (io->flags & MAP_ACTIVE) {
 
-		dprintk( "io->flags & MAP_ACTIVE\n");
+		dprintk("io->flags & MAP_ACTIVE\n");
 
 		winnr = (PCMCIA_MEM_WIN_NO * PCMCIA_SOCKETS_NO)
-			+ (lsock * PCMCIA_IO_WIN_NO) + io->map;
+		    + (lsock * PCMCIA_IO_WIN_NO) + io->map;
 
 		/* setup registers */
 
-		w = (void *) &pcmcia->pcmc_pbr0;
+		w = (void *)&pcmcia->pcmc_pbr0;
 		w += winnr;
 
-		out_be32(&w->or, 0); /* turn off window first */
+		out_be32(&w->or, 0);	/* turn off window first */
 		out_be32(&w->br, M8XX_BASE);
 
 		reg <<= 27;
-  		reg |= M8XX_PCMCIA_POR_IO |(lsock << 2);
+		reg |= M8XX_PCMCIA_POR_IO | (lsock << 2);
 
 		reg |= m8xx_get_speed(io->speed, 1, s->bus_freq);
 
-		if(io->flags & MAP_WRPROT)
+		if (io->flags & MAP_WRPROT)
 			reg |= M8XX_PCMCIA_POR_WRPROT;
 
-		/*if(io->flags & (MAP_16BIT | MAP_AUTOSZ))*/
-		if(io->flags & MAP_16BIT)
+		/*if(io->flags & (MAP_16BIT | MAP_AUTOSZ)) */
+		if (io->flags & MAP_16BIT)
 			reg |= M8XX_PCMCIA_POR_16BIT;
 
-		if(io->flags & MAP_ACTIVE)
+		if (io->flags & MAP_ACTIVE)
 			reg |= M8XX_PCMCIA_POR_VALID;
 
 		out_be32(&w->or, reg);
 
 		dprintk("Socket %u: Mapped io window %u at %#8.8x, "
-		      "OR = %#8.8x.\n", lsock, io->map, w->br, w->or);
+			"OR = %#8.8x.\n", lsock, io->map, w->br, w->or);
 	} else {
 		/* shutdown IO window */
 		winnr = (PCMCIA_MEM_WIN_NO * PCMCIA_SOCKETS_NO)
-			+ (lsock * PCMCIA_IO_WIN_NO) + io->map;
+		    + (lsock * PCMCIA_IO_WIN_NO) + io->map;
 
 		/* setup registers */
 
-		w = (void *) &pcmcia->pcmc_pbr0;
+		w = (void *)&pcmcia->pcmc_pbr0;
 		w += winnr;
 
-		out_be32(&w->or, 0); /* turn off window */
-		out_be32(&w->br, 0); /* turn off base address */
+		out_be32(&w->or, 0);	/* turn off window */
+		out_be32(&w->br, 0);	/* turn off base address */
 
 		dprintk("Socket %u: Unmapped io window %u at %#8.8x, "
 			"OR = %#8.8x.\n", lsock, io->map, w->br, w->or);
@@ -1029,15 +1039,14 @@ static int m8xx_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *io)
 
 	/* copy the struct and modify the copy */
 	s->io_win[io->map] = *io;
-	s->io_win[io->map].flags &= (MAP_WRPROT
-				     | MAP_16BIT
-				     | MAP_ACTIVE);
+	s->io_win[io->map].flags &= (MAP_WRPROT | MAP_16BIT | MAP_ACTIVE);
 	dprintk("SetIOMap exit\n");
 
 	return 0;
 }
 
-static int m8xx_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *mem)
+static int m8xx_set_mem_map(struct pcmcia_socket *sock,
+			    struct pccard_mem_map *mem)
 {
 	int lsock = container_of(sock, struct socket_info, socket)->slot;
 	struct socket_info *s = &socket[lsock];
@@ -1046,19 +1055,19 @@ static int m8xx_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *m
 	unsigned int reg, winnr;
 	pcmconf8xx_t *pcmcia = s->pcmcia;
 
-	dprintk( "SetMemMap(%d, %d, %#2.2x, %d ns, "
-	      "%#5.5lx, %#5.5x)\n", lsock, mem->map, mem->flags,
-	      mem->speed, mem->static_start, mem->card_start);
+	dprintk("SetMemMap(%d, %d, %#2.2x, %d ns, "
+		"%#5.5lx, %#5.5x)\n", lsock, mem->map, mem->flags,
+		mem->speed, mem->static_start, mem->card_start);
 
 	if ((mem->map >= PCMCIA_MEM_WIN_NO)
-//	    || ((mem->s) >= PCMCIA_MEM_WIN_SIZE)
+//          || ((mem->s) >= PCMCIA_MEM_WIN_SIZE)
 	    || (mem->card_start >= 0x04000000)
-	    || (mem->static_start & 0xfff)                /* 4KByte resolution */
-	    || (mem->card_start & 0xfff))
+	    || (mem->static_start & 0xfff)	/* 4KByte resolution */
+	    ||(mem->card_start & 0xfff))
 		return -EINVAL;
 
-	if((reg = m8xx_get_graycode(PCMCIA_MEM_WIN_SIZE)) == -1) {
-		printk( "Cannot set size to 0x%08x.\n", PCMCIA_MEM_WIN_SIZE);
+	if ((reg = m8xx_get_graycode(PCMCIA_MEM_WIN_SIZE)) == -1) {
+		printk("Cannot set size to 0x%08x.\n", PCMCIA_MEM_WIN_SIZE);
 		return -EINVAL;
 	}
 	reg <<= 27;
@@ -1067,50 +1076,47 @@ static int m8xx_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *m
 
 	/* Setup the window in the pcmcia controller */
 
-	w = (void *) &pcmcia->pcmc_pbr0;
+	w = (void *)&pcmcia->pcmc_pbr0;
 	w += winnr;
 
 	reg |= lsock << 2;
 
 	reg |= m8xx_get_speed(mem->speed, 0, s->bus_freq);
 
-	if(mem->flags & MAP_ATTRIB)
-		reg |=  M8XX_PCMCIA_POR_ATTRMEM;
+	if (mem->flags & MAP_ATTRIB)
+		reg |= M8XX_PCMCIA_POR_ATTRMEM;
 
-	if(mem->flags & MAP_WRPROT)
+	if (mem->flags & MAP_WRPROT)
 		reg |= M8XX_PCMCIA_POR_WRPROT;
 
-	if(mem->flags & MAP_16BIT)
+	if (mem->flags & MAP_16BIT)
 		reg |= M8XX_PCMCIA_POR_16BIT;
 
-	if(mem->flags & MAP_ACTIVE)
+	if (mem->flags & MAP_ACTIVE)
 		reg |= M8XX_PCMCIA_POR_VALID;
 
 	out_be32(&w->or, reg);
 
 	dprintk("Socket %u: Mapped memory window %u at %#8.8x, "
-	      "OR = %#8.8x.\n", lsock, mem->map, w->br, w->or);
+		"OR = %#8.8x.\n", lsock, mem->map, w->br, w->or);
 
-	if(mem->flags & MAP_ACTIVE) {
+	if (mem->flags & MAP_ACTIVE) {
 		/* get the new base address */
 		mem->static_start = PCMCIA_MEM_WIN_BASE +
-			(PCMCIA_MEM_WIN_SIZE * winnr)
-			+ mem->card_start;
+		    (PCMCIA_MEM_WIN_SIZE * winnr)
+		    + mem->card_start;
 	}
 
 	dprintk("SetMemMap(%d, %d, %#2.2x, %d ns, "
-	      "%#5.5lx, %#5.5x)\n", lsock, mem->map, mem->flags,
-	      mem->speed, mem->static_start, mem->card_start);
+		"%#5.5lx, %#5.5x)\n", lsock, mem->map, mem->flags,
+		mem->speed, mem->static_start, mem->card_start);
 
 	/* copy the struct and modify the copy */
 
 	old = &s->mem_win[mem->map];
 
 	*old = *mem;
-	old->flags &= (MAP_ATTRIB
-		       | MAP_WRPROT
-		       | MAP_16BIT
-		       | MAP_ACTIVE);
+	old->flags &= (MAP_ATTRIB | MAP_WRPROT | MAP_16BIT | MAP_ACTIVE);
 
 	return 0;
 }
@@ -1121,7 +1127,7 @@ static int m8xx_sock_init(struct pcmcia_socket *sock)
 	pccard_io_map io = { 0, 0, 0, 0, 1 };
 	pccard_mem_map mem = { 0, 0, 0, 0, 0, 0 };
 
-	dprintk( "sock_init(%d)\n", s);
+	dprintk("sock_init(%d)\n", s);
 
 	m8xx_set_socket(sock, &dead_socket);
 	for (i = 0; i < PCMCIA_IO_WIN_NO; i++) {
@@ -1143,7 +1149,7 @@ static int m8xx_sock_suspend(struct pcmcia_socket *sock)
 }
 
 static struct pccard_operations m8xx_services = {
-	.init	= m8xx_sock_init,
+	.init = m8xx_sock_init,
 	.suspend = m8xx_sock_suspend,
 	.get_status = m8xx_get_status,
 	.set_socket = m8xx_set_socket,
@@ -1151,7 +1157,8 @@ static struct pccard_operations m8xx_services = {
 	.set_mem_map = m8xx_set_mem_map,
 };
 
-static int __init m8xx_probe(struct of_device *ofdev, const struct of_device_id *match)
+static int __init m8xx_probe(struct of_device *ofdev,
+			     const struct of_device_id *match)
 {
 	struct pcmcia_win *w;
 	unsigned int i, m, hwirq;
@@ -1162,49 +1169,50 @@ static int __init m8xx_probe(struct of_device *ofdev, const struct of_device_id
 	pcmcia_info("%s\n", version);
 
 	pcmcia = of_iomap(np, 0);
-	if(pcmcia == NULL)
+	if (pcmcia == NULL)
 		return -EINVAL;
 
 	pcmcia_schlvl = irq_of_parse_and_map(np, 0);
-	hwirq  = irq_map[pcmcia_schlvl].hwirq;
+	hwirq = irq_map[pcmcia_schlvl].hwirq;
 	if (pcmcia_schlvl < 0)
 		return -EINVAL;
 
 	m8xx_pgcrx[0] = &pcmcia->pcmc_pgcra;
 	m8xx_pgcrx[1] = &pcmcia->pcmc_pgcrb;
 
-
 	pcmcia_info(PCMCIA_BOARD_MSG " using " PCMCIA_SLOT_MSG
 		    " with IRQ %u  (%d). \n", pcmcia_schlvl, hwirq);
 
 	/* Configure Status change interrupt */
 
-	if(request_irq(pcmcia_schlvl, m8xx_interrupt, IRQF_SHARED,
-			  driver_name, socket)) {
+	if (request_irq(pcmcia_schlvl, m8xx_interrupt, IRQF_SHARED,
+			driver_name, socket)) {
 		pcmcia_error("Cannot allocate IRQ %u for SCHLVL!\n",
 			     pcmcia_schlvl);
 		return -1;
 	}
 
-	w = (void *) &pcmcia->pcmc_pbr0;
+	w = (void *)&pcmcia->pcmc_pbr0;
 
-	out_be32(&pcmcia->pcmc_pscr, M8XX_PCMCIA_MASK(0)| M8XX_PCMCIA_MASK(1));
+	out_be32(&pcmcia->pcmc_pscr, M8XX_PCMCIA_MASK(0) | M8XX_PCMCIA_MASK(1));
 	clrbits32(&pcmcia->pcmc_per, M8XX_PCMCIA_MASK(0) | M8XX_PCMCIA_MASK(1));
 
 	/* connect interrupt and disable CxOE */
 
-	out_be32(M8XX_PGCRX(0), M8XX_PGCRX_CXOE | (mk_int_int_mask(hwirq) << 16));
-	out_be32(M8XX_PGCRX(1), M8XX_PGCRX_CXOE | (mk_int_int_mask(hwirq) << 16));
+	out_be32(M8XX_PGCRX(0),
+		 M8XX_PGCRX_CXOE | (mk_int_int_mask(hwirq) << 16));
+	out_be32(M8XX_PGCRX(1),
+		 M8XX_PGCRX_CXOE | (mk_int_int_mask(hwirq) << 16));
 
 	/* intialize the fixed memory windows */
 
-	for(i = 0; i < PCMCIA_SOCKETS_NO; i++){
+	for (i = 0; i < PCMCIA_SOCKETS_NO; i++) {
 		for (m = 0; m < PCMCIA_MEM_WIN_NO; m++) {
 			out_be32(&w->br, PCMCIA_MEM_WIN_BASE +
-				(PCMCIA_MEM_WIN_SIZE
-				 * (m + i * PCMCIA_MEM_WIN_NO)));
+				 (PCMCIA_MEM_WIN_SIZE
+				  * (m + i * PCMCIA_MEM_WIN_NO)));
 
-			out_be32(&w->or, 0);  /* set to not valid */
+			out_be32(&w->or, 0);	/* set to not valid */
 
 			w++;
 		}
@@ -1218,10 +1226,11 @@ static int __init m8xx_probe(struct of_device *ofdev, const struct of_device_id
 	hardware_enable(0);
 	hardware_enable(1);
 
-	for (i = 0 ; i < PCMCIA_SOCKETS_NO; i++) {
+	for (i = 0; i < PCMCIA_SOCKETS_NO; i++) {
 		socket[i].slot = i;
 		socket[i].socket.owner = THIS_MODULE;
-		socket[i].socket.features = SS_CAP_PCCARD | SS_CAP_MEM_ALIGN | SS_CAP_STATIC_MAP;
+		socket[i].socket.features =
+		    SS_CAP_PCCARD | SS_CAP_MEM_ALIGN | SS_CAP_STATIC_MAP;
 		socket[i].socket.irq_mask = 0x000;
 		socket[i].socket.map_size = 0x1000;
 		socket[i].socket.io_offset = 0;
@@ -1234,7 +1243,6 @@ static int __init m8xx_probe(struct of_device *ofdev, const struct of_device_id
 		socket[i].bus_freq = ppc_proc_freq;
 		socket[i].hwirq = hwirq;
 
-
 	}
 
 	for (i = 0; i < PCMCIA_SOCKETS_NO; i++) {
@@ -1246,25 +1254,25 @@ static int __init m8xx_probe(struct of_device *ofdev, const struct of_device_id
 	return 0;
 }
 
-static int m8xx_remove(struct of_device* ofdev)
+static int m8xx_remove(struct of_device *ofdev)
 {
 	u32 m, i;
 	struct pcmcia_win *w;
 	pcmconf8xx_t *pcmcia = socket[0].pcmcia;
 
 	for (i = 0; i < PCMCIA_SOCKETS_NO; i++) {
-		w = (void *) &pcmcia->pcmc_pbr0;
+		w = (void *)&pcmcia->pcmc_pbr0;
 
 		out_be32(&pcmcia->pcmc_pscr, M8XX_PCMCIA_MASK(i));
 		out_be32(&pcmcia->pcmc_per,
-			in_be32(&pcmcia->pcmc_per) & ~M8XX_PCMCIA_MASK(i));
+			 in_be32(&pcmcia->pcmc_per) & ~M8XX_PCMCIA_MASK(i));
 
 		/* turn off interrupt and disable CxOE */
 		out_be32(M8XX_PGCRX(i), M8XX_PGCRX_CXOE);
 
 		/* turn off memory windows */
 		for (m = 0; m < PCMCIA_MEM_WIN_NO; m++) {
-			out_be32(&w->or, 0); /* set to not valid */
+			out_be32(&w->or, 0);	/* set to not valid */
 			w++;
 		}
 
@@ -1299,21 +1307,21 @@ static int m8xx_resume(struct platform_device *pdev)
 
 static struct of_device_id m8xx_pcmcia_match[] = {
 	{
-		.type = "pcmcia",
-		.compatible = "fsl,pq-pcmcia",
-	},
+	 .type = "pcmcia",
+	 .compatible = "fsl,pq-pcmcia",
+	 },
 	{},
 };
 
 MODULE_DEVICE_TABLE(of, m8xx_pcmcia_match);
 
 static struct of_platform_driver m8xx_pcmcia_driver = {
-	.name		= (char *) driver_name,
-	.match_table	= m8xx_pcmcia_match,
-	.probe		= m8xx_probe,
-	.remove		= m8xx_remove,
-	.suspend	= m8xx_suspend,
-	.resume		= m8xx_resume,
+	.name = (char *)driver_name,
+	.match_table = m8xx_pcmcia_match,
+	.probe = m8xx_probe,
+	.remove = m8xx_remove,
+	.suspend = m8xx_suspend,
+	.resume = m8xx_resume,
 };
 
 static int __init m8xx_init(void)

^ permalink raw reply related

* [PATCH 1/3] [POWERPC] 8xx: mpc885ads pcmcia support
From: Vitaly Bordug @ 2007-05-08  0:36 UTC (permalink / raw)
  To: linux-pcmcia; +Cc: linuxppc-dev, linux-kernel


Adds support for PowerQuicc on-chip PCMCIA. The driver is implemented as
of_device, so only arch/powerpc stuff is capable to use it, which now
implies only mpc885ads reference board.

To cope with the code that should be hooked inside driver, but is really
board specific (like set_voltage), global structure mpc8xx_pcmcia_ops
holds necessary function pointers that are filled in the BSP code.

Signed-off-by: Vitaly Bordug <vitb@kernel.crashing.org>
Acked-by: Arnd Bergmann <arnd@arndb.de>

---

 arch/powerpc/boot/dts/mpc885ads.dts          |   13 +
 arch/powerpc/platforms/8xx/m8xx_setup.c      |    5 
 arch/powerpc/platforms/8xx/mpc885ads.h       |    8 +
 arch/powerpc/platforms/8xx/mpc885ads_setup.c |   76 ++++++
 arch/powerpc/sysdev/fsl_soc.c                |   13 +
 arch/powerpc/sysdev/mpc8xx_pic.h             |    2 
 drivers/pcmcia/Kconfig                       |    1 
 drivers/pcmcia/m8xx_pcmcia.c                 |  351 ++++++++++++--------------
 include/asm-powerpc/mpc8xx.h                 |    4 
 include/linux/fsl_devices.h                  |    5 
 10 files changed, 293 insertions(+), 185 deletions(-)

diff --git a/arch/powerpc/boot/dts/mpc885ads.dts b/arch/powerpc/boot/dts/mpc885ads.dts
index 110bf61..9e937df 100644
--- a/arch/powerpc/boot/dts/mpc885ads.dts
+++ b/arch/powerpc/boot/dts/mpc885ads.dts
@@ -112,6 +112,19 @@
 			compatible = "CPM";
 		};
 
+		pcmcia@0080 {
+			#address-cells = <3>;
+			#interrupt-cells = <1>;
+			#size-cells = <2>;
+			compatible = "fsl,pq-pcmcia";
+			device_type = "pcmcia";
+			reg = <80 80>;
+			ranges=<0>;
+			clock-frequency = <2faf080>;
+			interrupt-parent = <&mpc8xx-pic>;
+			interrupts = <d 1>;
+		};
+
 		cpm@ff000000 {
 			linux,phandle = <ff000000>;
 			#address-cells = <1>;
diff --git a/arch/powerpc/platforms/8xx/m8xx_setup.c b/arch/powerpc/platforms/8xx/m8xx_setup.c
index 0901dba..f169355 100644
--- a/arch/powerpc/platforms/8xx/m8xx_setup.c
+++ b/arch/powerpc/platforms/8xx/m8xx_setup.c
@@ -32,6 +32,7 @@
 #include <linux/root_dev.h>
 #include <linux/time.h>
 #include <linux/rtc.h>
+#include <linux/fsl_devices.h>
 
 #include <asm/mmu.h>
 #include <asm/reg.h>
@@ -49,6 +50,10 @@
 
 #include "sysdev/mpc8xx_pic.h"
 
+#ifdef CONFIG_PCMCIA_M8XX
+struct mpc8xx_pcmcia_ops m8xx_pcmcia_ops;
+#endif
+
 void m8xx_calibrate_decr(void);
 extern void m8xx_wdt_handler_install(bd_t *bp);
 extern int cpm_pic_init(void);
diff --git a/arch/powerpc/platforms/8xx/mpc885ads.h b/arch/powerpc/platforms/8xx/mpc885ads.h
index 7c31aec..932b59a 100644
--- a/arch/powerpc/platforms/8xx/mpc885ads.h
+++ b/arch/powerpc/platforms/8xx/mpc885ads.h
@@ -91,5 +91,13 @@
 #define SICR_ENET_MASK	((uint)0x00ff0000)
 #define SICR_ENET_CLKRT	((uint)0x002c0000)
 
+/* 
+ * Some internal interrupt registers use an 8-bit mask for the interrupt
+ * level instead of a number.
+ */
+static inline uint mk_int_int_mask(uint mask) {
+	return (1 << (7 - (mask/2)));
+}
+
 #endif /* __ASM_MPC885ADS_H__ */
 #endif /* __KERNEL__ */
diff --git a/arch/powerpc/platforms/8xx/mpc885ads_setup.c b/arch/powerpc/platforms/8xx/mpc885ads_setup.c
index a57b577..4e76e1c 100644
--- a/arch/powerpc/platforms/8xx/mpc885ads_setup.c
+++ b/arch/powerpc/platforms/8xx/mpc885ads_setup.c
@@ -22,6 +22,7 @@
 
 #include <linux/fs_enet_pd.h>
 #include <linux/fs_uart_pd.h>
+#include <linux/fsl_devices.h>
 #include <linux/mii.h>
 
 #include <asm/delay.h>
@@ -51,6 +52,11 @@ static void init_smc1_uart_ioports(struct fs_uart_platform_info* fpi);
 static void init_smc2_uart_ioports(struct fs_uart_platform_info* fpi);
 static void init_scc3_ioports(struct fs_platform_info* ptr);
 
+#ifdef CONFIG_PCMCIA_M8XX
+static void pcmcia_hw_setup(int slot, int enable);
+static int pcmcia_set_voltage(int slot, int vcc, int vpp);
+#endif
+
 void __init mpc885ads_board_setup(void)
 {
 	cpm8xx_t *cp;
@@ -115,6 +121,12 @@ void __init mpc885ads_board_setup(void)
 	immr_unmap(io_port);
 
 #endif
+
+#ifdef CONFIG_PCMCIA_M8XX
+	/*Set up board specific hook-ups*/
+	m8xx_pcmcia_ops.hw_ctrl = pcmcia_hw_setup;
+	m8xx_pcmcia_ops.voltage_set = pcmcia_set_voltage;
+#endif
 }
 
 
@@ -322,6 +334,70 @@ void init_smc_ioports(struct fs_uart_platform_info *data)
 	}
 }
 
+#ifdef CONFIG_PCMCIA_M8XX
+static void pcmcia_hw_setup(int slot, int enable)
+{
+	unsigned *bcsr_io;
+
+	bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
+	if (enable)
+		clrbits32(bcsr_io, BCSR1_PCCEN);
+	else
+		setbits32(bcsr_io, BCSR1_PCCEN);
+
+	iounmap(bcsr_io);
+}
+
+static int pcmcia_set_voltage(int slot, int vcc, int vpp)
+{
+	u32 reg = 0;
+	unsigned *bcsr_io;
+
+	bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
+
+	switch(vcc) {
+	case 0:
+		break;
+	case 33:
+		reg |= BCSR1_PCCVCC0;
+		break;
+	case 50:
+		reg |= BCSR1_PCCVCC1;
+		break;
+	default:
+		return 1;
+	}
+
+	switch(vpp) {
+	case 0:
+       	break;
+	case 33:
+	case 50:
+       	if(vcc == vpp)
+			reg |= BCSR1_PCCVPP1;
+		else
+			return 1;
+		break;
+	case 120:
+	if ((vcc == 33) || (vcc == 50))
+		reg |= BCSR1_PCCVPP0;
+	else
+		return 1;
+	default:
+		return 1;
+	}
+
+	/* first, turn off all power */
+	clrbits32(bcsr_io, 0x00610000);
+
+	/* enable new powersettings */
+	setbits32(bcsr_io, reg);
+
+	iounmap(bcsr_io);
+	return 0;
+}
+#endif
+
 int platform_device_skip(const char *model, int id)
 {
 #ifdef CONFIG_MPC8xx_SECOND_ETH_SCC3
diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c
index 8a123c7..880e45f 100644
--- a/arch/powerpc/sysdev/fsl_soc.c
+++ b/arch/powerpc/sysdev/fsl_soc.c
@@ -1028,6 +1028,19 @@ err:
 
 arch_initcall(fs_enet_of_init);
 
+static int __init fsl_pcmcia_of_init(void)
+{
+	struct device_node *np = NULL;
+	/*
+	 * Register all the devices which type is "pcmcia"
+	 */
+	while ((np = of_find_compatible_node(np, 
+			"pcmcia", "fsl,pq-pcmcia")) != NULL)
+			    of_platform_device_create(np, "m8xx-pcmcia", NULL);
+	return 0;
+}
+
+arch_initcall(fsl_pcmcia_of_init);
 
 static const char *smc_regs = "regs";
 static const char *smc_pram = "pram";
diff --git a/arch/powerpc/sysdev/mpc8xx_pic.h b/arch/powerpc/sysdev/mpc8xx_pic.h
index afa2ee6..07be061 100644
--- a/arch/powerpc/sysdev/mpc8xx_pic.h
+++ b/arch/powerpc/sysdev/mpc8xx_pic.h
@@ -4,7 +4,7 @@
 #include <linux/irq.h>
 #include <linux/interrupt.h>
 
-extern struct hw_interrupt_type mpc8xx_pic;
+/*extern struct hw_interrupt_type mpc8xx_pic;*/
 
 int mpc8xx_pic_init(void);
 unsigned int mpc8xx_get_irq(void);
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig
index 35f8864..c3fd55d 100644
--- a/drivers/pcmcia/Kconfig
+++ b/drivers/pcmcia/Kconfig
@@ -183,6 +183,7 @@ config PCMCIA_M8XX
         tristate "MPC8xx PCMCIA support"
         depends on PCMCIA && PPC && 8xx 
         select PCCARD_IODYN
+	select PCCARD_NONSTATIC
         help
         Say Y here to include support for PowerPC 8xx series PCMCIA
         controller.
diff --git a/drivers/pcmcia/m8xx_pcmcia.c b/drivers/pcmcia/m8xx_pcmcia.c
index 9721ed7..40f6e20 100644
--- a/drivers/pcmcia/m8xx_pcmcia.c
+++ b/drivers/pcmcia/m8xx_pcmcia.c
@@ -10,7 +10,7 @@
  * Further fixes, v2.6 kernel port
  *     <marcelo.tosatti@cyclades.com>
  * 
- * Some fixes, additions (C) 2005 Montavista Software, Inc. 
+ * Some fixes, additions (C) 2005-2007 Montavista Software, Inc. 
  *     <vbordug@ru.mvista.com>
  *
  * "The ExCA standard specifies that socket controllers should provide
@@ -40,10 +40,6 @@
 #include <linux/fcntl.h>
 #include <linux/string.h>
 
-#include <asm/io.h>
-#include <asm/bitops.h>
-#include <asm/system.h>
-
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
@@ -51,11 +47,18 @@
 #include <linux/ioport.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
-#include <linux/platform_device.h>
+#include <linux/fsl_devices.h>
 
+#include <asm/io.h>
+#include <asm/bitops.h>
+#include <asm/system.h>
+#include <asm/time.h>
 #include <asm/mpc8xx.h>
 #include <asm/8xx_immap.h>
 #include <asm/irq.h>
+#include <asm/fs_pd.h>
+#include <asm/of_device.h>
+#include <asm/of_platform.h>
 
 #include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
@@ -146,27 +149,17 @@ MODULE_LICENSE("Dual MPL/GPL");
 #define PCMCIA_MEM_WIN_BASE 0xe0000000 /* base address for memory window 0   */
 #define PCMCIA_MEM_WIN_SIZE 0x04000000 /* each memory window is 64 MByte     */
 #define PCMCIA_IO_WIN_BASE  _IO_BASE   /* base address for io window 0       */
-
-#define PCMCIA_SCHLVL PCMCIA_INTERRUPT /* Status Change Interrupt Level      */
-
 /* ------------------------------------------------------------------------- */
 
-/* 2.4.x and newer has this always in HZ */
-#define M8XX_BUSFREQ ((((bd_t *)&(__res))->bi_busfreq))
-
-static int pcmcia_schlvl = PCMCIA_SCHLVL;
+static int pcmcia_schlvl;
 
 static DEFINE_SPINLOCK(events_lock);
 
-
 #define PCMCIA_SOCKET_KEY_5V 1
 #define PCMCIA_SOCKET_KEY_LV 2
 
 /* look up table for pgcrx registers */
-static u32 *m8xx_pgcrx[2] = {
-	&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pgcra,
-	&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pgcrb
-};
+static u32 *m8xx_pgcrx[2];
 
 /*
  * This structure is used to address each window in the PCMCIA controller.
@@ -228,11 +221,16 @@ struct event_table {
 	u32 eventbit;
 };
 
+static const char driver_name[] = "m8xx-pcmcia";
+
 struct socket_info {
 	void	(*handler)(void *info, u32 events);
 	void	*info;
 
 	u32 slot;
+	pcmconf8xx_t *pcmcia;
+	u32 bus_freq;
+	int hwirq;
 
 	socket_state_t state;
 	struct pccard_mem_map mem_win[PCMCIA_MEM_WIN_NO];
@@ -408,78 +406,21 @@ static void hardware_disable(int slot)
 #if defined(CONFIG_MPC885ADS)
 
 #define PCMCIA_BOARD_MSG "MPC885ADS"
+#define socket_get(_slot_) PCMCIA_SOCKET_KEY_5V
 
-static int voltage_set(int slot, int vcc, int vpp)
+static inline void hardware_enable(int slot)
 {
-	u32 reg = 0;
-	unsigned *bcsr_io;
-
-	bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
-
-	switch(vcc) {
-		case 0:
-			break;
-		case 33:
-			reg |= BCSR1_PCCVCC0;
-			break;
-		case 50:
-			reg |= BCSR1_PCCVCC1;
-			break;
-		default:
-			goto out_unmap;
-	}
-
-	switch(vpp) {
-		case 0:
-			break;
-		case 33:
-		case 50:
-			if(vcc == vpp)
-				reg |= BCSR1_PCCVPP1;
-			else
-				goto out_unmap;
-			break;
-		case 120:
-			if ((vcc == 33) || (vcc == 50))
-				reg |= BCSR1_PCCVPP0;
-			else
-				goto out_unmap;
-		default:
-			goto out_unmap;
-	}
-
-	/* first, turn off all power */
-	out_be32(bcsr_io, in_be32(bcsr_io) & ~(BCSR1_PCCVCC_MASK | BCSR1_PCCVPP_MASK));
-
-	/* enable new powersettings */
-	out_be32(bcsr_io, in_be32(bcsr_io) | reg);
-
-	iounmap(bcsr_io);
-	return 0;
-
-out_unmap:
-	iounmap(bcsr_io);
-	return 1;
+	 m8xx_pcmcia_ops.hw_ctrl(slot, 1);
 }
 
-#define socket_get(_slot_) PCMCIA_SOCKET_KEY_5V
-
-static void hardware_enable(int slot)
+static inline void hardware_disable(int slot)
 {
-	unsigned *bcsr_io;
-
-	bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
-	out_be32(bcsr_io, in_be32(bcsr_io) & ~BCSR1_PCCEN);
-	iounmap(bcsr_io);
+	m8xx_pcmcia_ops.hw_ctrl(slot, 0);
 }
 
-static void hardware_disable(int slot)
+static inline int voltage_set(int slot, int vcc, int vpp)
 {
-	unsigned *bcsr_io;
-
-	bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
-	out_be32(bcsr_io, in_be32(bcsr_io) |  BCSR1_PCCEN);
-	iounmap(bcsr_io);
+	return m8xx_pcmcia_ops.voltage_set(slot, vcc, vpp);
 }
 
 #endif
@@ -604,48 +545,6 @@ static int voltage_set(int slot, int vcc, int vpp)
 
 #endif /* CONFIG_PRxK */
 
-static void m8xx_shutdown(void)
-{
-	u32 m, i;
-	struct pcmcia_win *w;
-
-	for(i = 0; i < PCMCIA_SOCKETS_NO; i++){
-		w = (void *) &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0;
-
-		out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr, M8XX_PCMCIA_MASK(i));
-		out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per, in_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per) & ~M8XX_PCMCIA_MASK(i));
-
-		/* turn off interrupt and disable CxOE */
-		out_be32(M8XX_PGCRX(i), M8XX_PGCRX_CXOE);
-
-		/* turn off memory windows */
-		for(m = 0; m < PCMCIA_MEM_WIN_NO; m++) {
-			out_be32(&w->or, 0); /* set to not valid */
-			w++;
-		}
-
-		/* turn off voltage */
-		voltage_set(i, 0, 0);
-
-		/* disable external hardware */
-		hardware_disable(i);
-	}
-
-	free_irq(pcmcia_schlvl, NULL);
-}
-
-static struct device_driver m8xx_driver = {
-        .name = "m8xx-pcmcia",
-        .bus = &platform_bus_type,
-        .suspend = pcmcia_socket_dev_suspend,
-        .resume = pcmcia_socket_dev_resume,
-};
-
-static struct platform_device m8xx_device = {
-        .name = "m8xx-pcmcia",
-        .id = 0,
-};
-
 static u32 pending_events[PCMCIA_SOCKETS_NO];
 static DEFINE_SPINLOCK(pending_event_lock);
 
@@ -654,13 +553,14 @@ static irqreturn_t m8xx_interrupt(int irq, void *dev)
 	struct socket_info *s;
 	struct event_table *e;
 	unsigned int i, events, pscr, pipr, per;
+	pcmconf8xx_t	*pcmcia = socket[0].pcmcia;
 
 	dprintk("Interrupt!\n");
 	/* get interrupt sources */
 
-	pscr = in_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr);
-	pipr = in_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pipr);
-	per = in_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per);
+	pscr = in_be32(&pcmcia->pcmc_pscr);
+	pipr = in_be32(&pcmcia->pcmc_pipr);
+	per = in_be32(&pcmcia->pcmc_per);
 
 	for(i = 0; i < PCMCIA_SOCKETS_NO; i++) {
 		s = &socket[i];
@@ -724,7 +624,7 @@ static irqreturn_t m8xx_interrupt(int irq, void *dev)
 			per &= ~M8XX_PCMCIA_RDY_L(0);
 			per &= ~M8XX_PCMCIA_RDY_L(1);
 
-			out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per, per);
+			out_be32(&pcmcia->pcmc_per, per);
 
 			if (events)
 				pcmcia_parse_events(&socket[i].socket, events);
@@ -732,7 +632,7 @@ static irqreturn_t m8xx_interrupt(int irq, void *dev)
 	}
 
 	/* clear the interrupt sources */
-	out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr, pscr);
+	out_be32(&pcmcia->pcmc_pscr, pscr);
 
 	dprintk("Interrupt done.\n");
 
@@ -753,7 +653,7 @@ static u32 m8xx_get_graycode(u32 size)
 	return k;
 }
 
-static u32 m8xx_get_speed(u32 ns, u32 is_io)
+static u32 m8xx_get_speed(u32 ns, u32 is_io, u32 bus_freq)
 {
 	u32 reg, clocks, psst, psl, psht;
 
@@ -781,7 +681,7 @@ static u32 m8xx_get_speed(u32 ns, u32 is_io)
 
 #define ADJ 180 /* 80 % longer accesstime - to be sure */
 
-	clocks = ((M8XX_BUSFREQ / 1000) * ns) / 1000;
+	clocks = ((bus_freq / 1000) * ns) / 1000;
 	clocks = (clocks * ADJ) / (100*1000);
 	if(clocks >= PCMCIA_BMT_LIMIT) {
 		printk( "Max access time limit reached\n");
@@ -806,8 +706,9 @@ static int m8xx_get_status(struct pcmcia_socket *sock, unsigned int *value)
 	int lsock = container_of(sock, struct socket_info, socket)->slot;
 	struct socket_info *s = &socket[lsock];
 	unsigned int pipr, reg;
+	pcmconf8xx_t *pcmcia = s->pcmcia;
 
-	pipr = in_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pipr);
+	pipr = in_be32(&pcmcia->pcmc_pipr);
 
 	*value  = ((pipr & (M8XX_PCMCIA_CD1(lsock)
 			    | M8XX_PCMCIA_CD2(lsock))) == 0) ? SS_DETECT : 0;
@@ -918,6 +819,7 @@ static int m8xx_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
 	struct event_table *e;
 	unsigned int reg;
 	unsigned long flags;
+	pcmconf8xx_t *pcmcia = socket[0].pcmcia;
 
 	dprintk( "SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, "
 	      "io_irq %d, csc_mask %#2.2x)\n", lsock, state->flags,
@@ -927,6 +829,7 @@ static int m8xx_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
 	if(voltage_set(lsock, state->Vcc, state->Vpp))
 		return -EINVAL;
 
+
 	/* Take care of reset... */
 	if(state->flags & SS_RESET)
 		out_be32(M8XX_PGCRX(lsock), in_be32(M8XX_PGCRX(lsock)) |  M8XX_PGCRX_CXRESET); /* active high */
@@ -982,7 +885,8 @@ static int m8xx_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
 		 * If io_irq is non-zero we should enable irq.
 		 */
 		if(state->io_irq) {
-			out_be32(M8XX_PGCRX(lsock), in_be32(M8XX_PGCRX(lsock)) | mk_int_int_mask(state->io_irq) << 24);
+			out_be32(M8XX_PGCRX(lsock),
+				 in_be32(M8XX_PGCRX(lsock)) | mk_int_int_mask(s->hwirq) << 24);
 			/*
 			 * Strange thing here:
 			 * The manual does not tell us which interrupt
@@ -1027,7 +931,7 @@ static int m8xx_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
 	 * Writing ones will clear the bits.
 	 */
 
-	out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr, reg);
+	out_be32(&pcmcia->pcmc_pscr, reg);
 
 	/*
 	 * Write the mask.
@@ -1036,15 +940,8 @@ static int m8xx_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
 	 * Ones will enable the interrupt.
 	 */
 
-	/*
-	  reg |= ((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per
-	  & M8XX_PCMCIA_MASK(lsock);
-	*/
-
-	reg |= in_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per) &
-		(M8XX_PCMCIA_MASK(0) | M8XX_PCMCIA_MASK(1));
-
-	out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per, reg);
+	reg |= in_be32(&pcmcia->pcmc_per) & (M8XX_PCMCIA_MASK(0) | M8XX_PCMCIA_MASK(1));
+	out_be32(&pcmcia->pcmc_per, reg);
 
 	spin_unlock_irqrestore(&events_lock, flags);
 
@@ -1062,6 +959,8 @@ static int m8xx_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *io)
 	struct socket_info *s = &socket[lsock];
 	struct pcmcia_win *w;
 	unsigned int reg, winnr;
+	pcmconf8xx_t *pcmcia = s->pcmcia;
+
 
 #define M8XX_SIZE (io->stop - io->start + 1)
 #define M8XX_BASE (PCMCIA_IO_WIN_BASE + io->start)
@@ -1086,7 +985,7 @@ static int m8xx_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *io)
 
 		/* setup registers */
 
-		w = (void *) &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0;
+		w = (void *) &pcmcia->pcmc_pbr0;
 		w += winnr;
 
 		out_be32(&w->or, 0); /* turn off window first */
@@ -1095,12 +994,13 @@ static int m8xx_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *io)
 		reg <<= 27;
   		reg |= M8XX_PCMCIA_POR_IO |(lsock << 2);
 
-		reg |= m8xx_get_speed(io->speed, 1);
+		reg |= m8xx_get_speed(io->speed, 1, s->bus_freq);
 
 		if(io->flags & MAP_WRPROT)
 			reg |= M8XX_PCMCIA_POR_WRPROT;
 
-		if(io->flags & (MAP_16BIT | MAP_AUTOSZ))
+		/*if(io->flags & (MAP_16BIT | MAP_AUTOSZ))*/
+		if(io->flags & MAP_16BIT)
 			reg |= M8XX_PCMCIA_POR_16BIT;
 
 		if(io->flags & MAP_ACTIVE)
@@ -1117,7 +1017,7 @@ static int m8xx_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *io)
 
 		/* setup registers */
 
-		w = (void *) &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0;
+		w = (void *) &pcmcia->pcmc_pbr0;
 		w += winnr;
 
 		out_be32(&w->or, 0); /* turn off window */
@@ -1144,6 +1044,7 @@ static int m8xx_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *m
 	struct pcmcia_win *w;
 	struct pccard_mem_map *old;
 	unsigned int reg, winnr;
+	pcmconf8xx_t *pcmcia = s->pcmcia;
 
 	dprintk( "SetMemMap(%d, %d, %#2.2x, %d ns, "
 	      "%#5.5lx, %#5.5x)\n", lsock, mem->map, mem->flags,
@@ -1166,12 +1067,12 @@ static int m8xx_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *m
 
 	/* Setup the window in the pcmcia controller */
 
-	w = (void *) &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0;
+	w = (void *) &pcmcia->pcmc_pbr0;
 	w += winnr;
 
 	reg |= lsock << 2;
 
-	reg |= m8xx_get_speed(mem->speed, 0);
+	reg |= m8xx_get_speed(mem->speed, 0, s->bus_freq);
 
 	if(mem->flags & MAP_ATTRIB)
 		reg |=  M8XX_PCMCIA_POR_ATTRMEM;
@@ -1236,60 +1137,69 @@ static int m8xx_sock_init(struct pcmcia_socket *sock)
 
 }
 
-static int m8xx_suspend(struct pcmcia_socket *sock)
+static int m8xx_sock_suspend(struct pcmcia_socket *sock)
 {
 	return m8xx_set_socket(sock, &dead_socket);
 }
 
 static struct pccard_operations m8xx_services = {
 	.init	= m8xx_sock_init,
-	.suspend = m8xx_suspend,
+	.suspend = m8xx_sock_suspend,
 	.get_status = m8xx_get_status,
 	.set_socket = m8xx_set_socket,
 	.set_io_map = m8xx_set_io_map,
 	.set_mem_map = m8xx_set_mem_map,
 };
 
-static int __init m8xx_init(void)
+static int __init m8xx_probe(struct of_device *ofdev, const struct of_device_id *match)
 {
 	struct pcmcia_win *w;
-	unsigned int i,m;
+	unsigned int i, m, hwirq;
+	pcmconf8xx_t *pcmcia;
+	int status;
+	struct device_node *np = ofdev->node;
 
 	pcmcia_info("%s\n", version);
 
-	if (driver_register(&m8xx_driver))
-		return -1;
+	pcmcia = of_iomap(np, 0);
+	if(pcmcia == NULL)
+		return -EINVAL;
+
+	pcmcia_schlvl = irq_of_parse_and_map(np, 0);
+	hwirq  = irq_map[pcmcia_schlvl].hwirq;
+	if (pcmcia_schlvl < 0)
+		return -EINVAL;
+
+	m8xx_pgcrx[0] = &pcmcia->pcmc_pgcra;
+	m8xx_pgcrx[1] = &pcmcia->pcmc_pgcrb;
+
 
 	pcmcia_info(PCMCIA_BOARD_MSG " using " PCMCIA_SLOT_MSG
-		    " with IRQ %u.\n", pcmcia_schlvl);
+		    " with IRQ %u  (%d). \n", pcmcia_schlvl, hwirq);
 
 	/* Configure Status change interrupt */
 
-	if(request_irq(pcmcia_schlvl, m8xx_interrupt, 0,
-			  "m8xx_pcmcia", NULL)) {
+	if(request_irq(pcmcia_schlvl, m8xx_interrupt, IRQF_SHARED,
+			  driver_name, socket)) {
 		pcmcia_error("Cannot allocate IRQ %u for SCHLVL!\n",
 			     pcmcia_schlvl);
 		return -1;
 	}
 
-	w = (void *) &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0;
-
-	out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr,
-		M8XX_PCMCIA_MASK(0)| M8XX_PCMCIA_MASK(1));
+	w = (void *) &pcmcia->pcmc_pbr0;
 
-	out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per,
-		in_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per) &
-		~(M8XX_PCMCIA_MASK(0)| M8XX_PCMCIA_MASK(1)));
+	out_be32(&pcmcia->pcmc_pscr, M8XX_PCMCIA_MASK(0)| M8XX_PCMCIA_MASK(1));
+	clrbits32(&pcmcia->pcmc_per, M8XX_PCMCIA_MASK(0) | M8XX_PCMCIA_MASK(1));
 
-/* connect interrupt and disable CxOE */
+	/* connect interrupt and disable CxOE */
 
-	out_be32(M8XX_PGCRX(0), M8XX_PGCRX_CXOE | (mk_int_int_mask(pcmcia_schlvl) << 16));
-	out_be32(M8XX_PGCRX(1), M8XX_PGCRX_CXOE | (mk_int_int_mask(pcmcia_schlvl) << 16));
+	out_be32(M8XX_PGCRX(0), M8XX_PGCRX_CXOE | (mk_int_int_mask(hwirq) << 16));
+	out_be32(M8XX_PGCRX(1), M8XX_PGCRX_CXOE | (mk_int_int_mask(hwirq) << 16));
 
-/* intialize the fixed memory windows */
+	/* intialize the fixed memory windows */
 
 	for(i = 0; i < PCMCIA_SOCKETS_NO; i++){
-		for(m = 0; m < PCMCIA_MEM_WIN_NO; m++) {
+		for (m = 0; m < PCMCIA_MEM_WIN_NO; m++) {
 			out_be32(&w->br, PCMCIA_MEM_WIN_BASE +
 				(PCMCIA_MEM_WIN_SIZE
 				 * (m + i * PCMCIA_MEM_WIN_NO)));
@@ -1300,16 +1210,14 @@ static int __init m8xx_init(void)
 		}
 	}
 
-/* turn off voltage */
+	/* turn off voltage */
 	voltage_set(0, 0, 0);
 	voltage_set(1, 0, 0);
 
-/* Enable external hardware */
+	/* Enable external hardware */
 	hardware_enable(0);
 	hardware_enable(1);
 
-	platform_device_register(&m8xx_device);
-
 	for (i = 0 ; i < PCMCIA_SOCKETS_NO; i++) {
 		socket[i].slot = i;
 		socket[i].socket.owner = THIS_MODULE;
@@ -1317,30 +1225,105 @@ static int __init m8xx_init(void)
 		socket[i].socket.irq_mask = 0x000;
 		socket[i].socket.map_size = 0x1000;
 		socket[i].socket.io_offset = 0;
-		socket[i].socket.pci_irq = i  ? 7 : 9;
+		socket[i].socket.pci_irq = pcmcia_schlvl;
 		socket[i].socket.ops = &m8xx_services;
-		socket[i].socket.resource_ops = &pccard_iodyn_ops;
+		socket[i].socket.resource_ops = &pccard_nonstatic_ops;
 		socket[i].socket.cb_dev = NULL;
-		socket[i].socket.dev.parent = &m8xx_device.dev;
+		socket[i].socket.dev.parent = &ofdev->dev;
+		socket[i].pcmcia = pcmcia;
+		socket[i].bus_freq = ppc_proc_freq;
+		socket[i].hwirq = hwirq;
+
+
 	}
 
-	for (i = 0; i < PCMCIA_SOCKETS_NO; i++)
-		pcmcia_register_socket(&socket[i].socket);
+	for (i = 0; i < PCMCIA_SOCKETS_NO; i++) {
+		status = pcmcia_register_socket(&socket[i].socket);
+		if (status < 0)
+			pcmcia_error("Socket register failed\n");
+	}
 
 	return 0;
 }
 
-static void __exit m8xx_exit(void)
+static int m8xx_remove(struct of_device* ofdev)
 {
-	int i;
+	u32 m, i;
+	struct pcmcia_win *w;
+	pcmconf8xx_t *pcmcia = socket[0].pcmcia;
+
+	for (i = 0; i < PCMCIA_SOCKETS_NO; i++) {
+		w = (void *) &pcmcia->pcmc_pbr0;
+
+		out_be32(&pcmcia->pcmc_pscr, M8XX_PCMCIA_MASK(i));
+		out_be32(&pcmcia->pcmc_per,
+			in_be32(&pcmcia->pcmc_per) & ~M8XX_PCMCIA_MASK(i));
 
+		/* turn off interrupt and disable CxOE */
+		out_be32(M8XX_PGCRX(i), M8XX_PGCRX_CXOE);
+
+		/* turn off memory windows */
+		for (m = 0; m < PCMCIA_MEM_WIN_NO; m++) {
+			out_be32(&w->or, 0); /* set to not valid */
+			w++;
+		}
+
+		/* turn off voltage */
+		voltage_set(i, 0, 0);
+
+		/* disable external hardware */
+		hardware_disable(i);
+	}
 	for (i = 0; i < PCMCIA_SOCKETS_NO; i++)
 		pcmcia_unregister_socket(&socket[i].socket);
 
-	m8xx_shutdown();
+	free_irq(pcmcia_schlvl, NULL);
 
-	platform_device_unregister(&m8xx_device);
-	driver_unregister(&m8xx_driver);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int m8xx_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	return pcmcia_socket_dev_suspend(&pdev->dev, state);
+}
+
+static int m8xx_resume(struct platform_device *pdev)
+{
+	return pcmcia_socket_dev_resume(&pdev->dev);
+}
+#else
+#define m8xx_suspend NULL
+#define m8xx_resume NULL
+#endif
+
+static struct of_device_id m8xx_pcmcia_match[] = {
+	{
+		.type = "pcmcia",
+		.compatible = "fsl,pq-pcmcia",
+	},
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, m8xx_pcmcia_match);
+
+static struct of_platform_driver m8xx_pcmcia_driver = {
+	.name		= (char *) driver_name,
+	.match_table	= m8xx_pcmcia_match,
+	.probe		= m8xx_probe,
+	.remove		= m8xx_remove,
+	.suspend	= m8xx_suspend,
+	.resume		= m8xx_resume,
+};
+
+static int __init m8xx_init(void)
+{
+	return of_register_platform_driver(&m8xx_pcmcia_driver);
+}
+
+static void __exit m8xx_exit(void)
+{
+	of_unregister_platform_driver(&m8xx_pcmcia_driver);
 }
 
 module_init(m8xx_init);
diff --git a/include/asm-powerpc/mpc8xx.h b/include/asm-powerpc/mpc8xx.h
index 5803711..c1a6efc 100644
--- a/include/asm-powerpc/mpc8xx.h
+++ b/include/asm-powerpc/mpc8xx.h
@@ -23,6 +23,10 @@
 #include <platforms/8xx/mpc885ads.h>
 #endif
 
+#ifdef CONFIG_PCMCIA_M8XX 
+extern struct mpc8xx_pcmcia_ops m8xx_pcmcia_ops;
+#endif 
+
 #endif /* CONFIG_8xx */
 #endif /* __CONFIG_8xx_DEFS */
 #endif /* __KERNEL__ */
diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h
index 73710d6..12e631f 100644
--- a/include/linux/fsl_devices.h
+++ b/include/linux/fsl_devices.h
@@ -120,5 +120,10 @@ struct fsl_spi_platform_data {
 	u32	sysclk;
 };
 
+struct mpc8xx_pcmcia_ops {
+	void(*hw_ctrl)(int slot, int enable);
+	int(*voltage_set)(int slot, int vcc, int vpp);
+};
+
 #endif /* _FSL_DEVICE_H_ */
 #endif /* __KERNEL__ */

^ permalink raw reply related

* [PATCH 3/3] [POWERPC] dts: kill hardcoded phandles
From: Vitaly Bordug @ 2007-05-08  0:50 UTC (permalink / raw)
  To: linux-pcmcia; +Cc: linuxppc-dev, linux-kernel
In-Reply-To: <20070508003642.5964.37001.stgit@localhost.localdomain>


Removed explicit linux,phandle usage. Using references and labels now in
PQ and PQ2 boards currently supported in arch/powerpc.
Signed-off-by: Vitaly Bordug <vitb@kernel.crashing.org>

---

 arch/powerpc/boot/dts/mpc8272ads.dts |   42 ++++++++++++----------------------
 arch/powerpc/boot/dts/mpc866ads.dts  |   31 +++++++++----------------
 arch/powerpc/boot/dts/mpc885ads.dts  |    2 +-
 3 files changed, 27 insertions(+), 48 deletions(-)

diff --git a/arch/powerpc/boot/dts/mpc8272ads.dts b/arch/powerpc/boot/dts/mpc8272ads.dts
index 423eedc..83461fe 100644
--- a/arch/powerpc/boot/dts/mpc8272ads.dts
+++ b/arch/powerpc/boot/dts/mpc8272ads.dts
@@ -14,12 +14,10 @@
        compatible = "MPC8260ADS";
        #address-cells = <1>;
        #size-cells = <1>;
-       linux,phandle = <100>;
 
        cpus {
                #address-cells = <1>;
                #size-cells = <0>;
-               linux,phandle = <200>;
 
                PowerPC,8272@0 {
                        device_type = "cpu";
@@ -32,12 +30,10 @@
                        bus-frequency = <0>;
                        clock-frequency = <0>;
                        32-bit;
-                       linux,phandle = <201>;
                };
        };
 
-       interrupt-controller@f8200000 {
-               linux,phandle = <f8200000>;
+		pci_pic:interrupt-controller@f8200000 {
                #address-cells = <0>;
                #interrupt-cells = <2>;
                interrupt-controller;
@@ -47,15 +43,13 @@
        };
        memory {
                device_type = "memory";
-               linux,phandle = <300>;
                reg = <00000000 4000000 f4500000 00000020>;
        };
 
        chosen {
                name = "chosen";
                linux,platform = <0>;
-               interrupt-controller = <10c00>;
-               linux,phandle = <400>;
+		interrupt-controller = <&cpm_pic>;
        };
 
        soc8272@f0000000 {
@@ -70,20 +64,17 @@
                        device_type = "mdio";
                        compatible = "fs_enet";
                        reg = <0 0>;
-                       linux,phandle = <24520>;
                        #address-cells = <1>;
                        #size-cells = <0>;
-                       ethernet-phy@0 {
-                               linux,phandle = <2452000>;
-                               interrupt-parent = <10c00>;
+			phy0:ethernet-phy@0 {
+				interrupt-parent = <&cpm_pic>;
                                interrupts = <17 4>;
                                reg = <0>;
                                bitbang = [ 12 12 13 02 02 01 ];
                                device_type = "ethernet-phy";
                        };
-                       ethernet-phy@1 {
-                               linux,phandle = <2452001>;
-                               interrupt-parent = <10c00>;
+			phy1:ethernet-phy@1 {
+				interrupt-parent = <&cpm_pic>;
                                interrupts = <17 4>;
                                bitbang = [ 12 12 13 02 02 01 ];
                                reg = <3>;
@@ -101,8 +92,8 @@
                        reg = <11300 20 8400 100 11380 30>;
                        mac-address = [ 00 11 2F 99 43 54 ];
                        interrupts = <20 2>;
-                       interrupt-parent = <10c00>;
-                       phy-handle = <2452000>;
+			interrupt-parent = <&cpm_pic>;
+			phy-handle = <&phy0>;
                        rx-clock = <13>;
                        tx-clock = <12>;
                };
@@ -115,14 +106,13 @@
                        reg = <11320 20 8500 100 113b0 30>;
                        mac-address = [ 00 11 2F 99 44 54 ];
                        interrupts = <21 2>;
-                       interrupt-parent = <10c00>;
-                       phy-handle = <2452001>;
+			interrupt-parent = <&cpm_pic>;
+			phy-handle = <&phy1>;
                        rx-clock = <17>;
                        tx-clock = <18>;
                };
 
                cpm@f0000000 {
-                       linux,phandle = <f0000000>;
                        #address-cells = <1>;
                        #size-cells = <1>;
                        #interrupt-cells = <2>;
@@ -142,7 +132,7 @@
                                reg = <11a00 20 8000 100>;
                                current-speed = <1c200>;
                                interrupts = <28 2>;
-                               interrupt-parent = <10c00>;
+				interrupt-parent = <&cpm_pic>;
                                clock-setup = <0 00ffffff>;
                                rx-clock = <1>;
                                tx-clock = <1>;
@@ -156,15 +146,14 @@
                                reg = <11a60 20 8300 100>;
                                current-speed = <1c200>;
                                interrupts = <2b 2>;
-                               interrupt-parent = <10c00>;
+				interrupt-parent = <&cpm_pic>;
                                clock-setup = <1b ffffff00>;
                                rx-clock = <4>;
                                tx-clock = <4>;
                        };
 
                };
-               interrupt-controller@10c00 {
-                       linux,phandle = <10c00>;
+			cpm_pic:interrupt-controller@10c00 {
                        #address-cells = <0>;
                        #interrupt-cells = <2>;
                        interrupt-controller;
@@ -174,7 +163,6 @@
 		       compatible = "CPM2";
                };
                pci@0500 {
-                       linux,phandle = <0500>;
                        #interrupt-cells = <1>;
                        #size-cells = <2>;
                        #address-cells = <3>;
@@ -202,7 +190,7 @@
                                         c000 0 0 2 f8200000 43 8
                                         c000 0 0 3 f8200000 40 8
                                         c000 0 0 4 f8200000 41 8>;
-                       interrupt-parent = <10c00>;
+			interrupt-parent = <&cpm_pic>;
                        interrupts = <14 8>;
                        bus-range = <0 0>;
                        ranges = <02000000 0 80000000 80000000 0 40000000
@@ -216,7 +204,7 @@
                        compatible = "talitos";
                        reg = <30000 10000>;
                        interrupts = <b 2>;
-                       interrupt-parent = <10c00>;
+			interrupt-parent = <&cpm_pic>;
                        num-channels = <4>;
                        channel-fifo-len = <18>;
                        exec-units-mask = <0000007e>;
diff --git a/arch/powerpc/boot/dts/mpc866ads.dts b/arch/powerpc/boot/dts/mpc866ads.dts
index c0d06fd..6dd749e 100644
--- a/arch/powerpc/boot/dts/mpc866ads.dts
+++ b/arch/powerpc/boot/dts/mpc866ads.dts
@@ -15,12 +15,10 @@
 	compatible = "mpc8xx";
 	#address-cells = <1>;
 	#size-cells = <1>;
-	linux,phandle = <100>;
 
 	cpus {
 		#address-cells = <1>;
 		#size-cells = <0>;
-		linux,phandle = <200>;
 
 		PowerPC,866@0 {
 			device_type = "cpu";
@@ -34,14 +32,12 @@
 			clock-frequency = <0>;
 			32-bit;
 			interrupts = <f 2>;	// decrementer interrupt
-			interrupt-parent = <ff000000>;
-			linux,phandle = <201>;
+			interrupt-parent = <&mpc8xx_pic>;
 		};
 	};
 
 	memory {
 		device_type = "memory";
-		linux,phandle = <300>;
 		reg = <00000000 800000>;
 	};
 
@@ -57,11 +53,9 @@
 			device_type = "mdio";
 			compatible = "fs_enet";
 			reg = <e80 8>;
-			linux,phandle = <e80>;
 			#address-cells = <1>;
 			#size-cells = <0>;
-			ethernet-phy@f {
-				linux,phandle = <e800f>;
+			phy:ethernet-phy@f {
 				reg = <f>;
 				device_type = "ethernet-phy";
 			};
@@ -75,12 +69,11 @@
 			reg = <e00 188>;
 			mac-address = [ 00 00 0C 00 01 FD ];
 			interrupts = <3 1>;
-			interrupt-parent = <ff000000>;
-			phy-handle = <e800f>;
+			interrupt-parent = <&mpc8xx_pic>;
+			phy-handle = <&phy>;
 		};
 
-		pic@ff000000 {
-			linux,phandle = <ff000000>;
+		mpc8xx_pic:pic@ff000000 {
 			interrupt-controller;
 			#address-cells = <0>;
 			#interrupt-cells = <2>;
@@ -91,7 +84,6 @@
 		};
 
 		cpm@ff000000 {
-			linux,phandle = <ff000000>;
 			#address-cells = <1>;
 			#size-cells = <1>;
 			#interrupt-cells = <2>;
@@ -102,15 +94,14 @@
 			command-proc = <9c0>;
 			brg-frequency = <0>;
 			interrupts = <0 2>;	// cpm error interrupt
-			interrupt-parent = <930>;
+			interrupt-parent = <&cpm_pic>;
 
-			pic@930 {
-				linux,phandle = <930>;
+			cpm_pic:pic@930 {
 				interrupt-controller;
 				#address-cells = <0>;
 				#interrupt-cells = <2>;
 				interrupts = <5 2 0 2>;
-				interrupt-parent = <ff000000>;
+				interrupt-parent = <&mpc8xx_pic>;
 				reg = <930 20>;
 				built-in;
 				device_type = "cpm-pic";
@@ -128,7 +119,7 @@
 				tx-clock = <1>;
 				current-speed = <0>;
 				interrupts = <4 3>;
-				interrupt-parent = <930>;
+				interrupt-parent = <&cpm_pic>;
 			};
 
 			smc@a90 {
@@ -142,7 +133,7 @@
 				tx-clock = <2>;
 				current-speed = <0>;
 				interrupts = <3 3>;
-				interrupt-parent = <930>;
+				interrupt-parent = <&cpm_pic>;
 			};
 
 			scc@a00 {
@@ -153,7 +144,7 @@
 				reg = <a00 18 3c00 80>;
 				mac-address = [ 00 00 0C 00 03 FD ];
 				interrupts = <1e 3>;
-				interrupt-parent = <930>;
+				interrupt-parent = <&cpm_pic>;
 			};
 		};
 	};
diff --git a/arch/powerpc/boot/dts/mpc885ads.dts b/arch/powerpc/boot/dts/mpc885ads.dts
index 9e937df..b292e92 100644
--- a/arch/powerpc/boot/dts/mpc885ads.dts
+++ b/arch/powerpc/boot/dts/mpc885ads.dts
@@ -121,7 +121,7 @@
 			reg = <80 80>;
 			ranges=<0>;
 			clock-frequency = <2faf080>;
-			interrupt-parent = <&mpc8xx-pic>;
+			interrupt-parent = <ff000000>;
 			interrupts = <d 1>;
 		};
 

^ permalink raw reply related

* [PATCH] [POWERPC] 8xx: PQ SoC IRDA support
From: Vitaly Bordug @ 2007-05-08  1:30 UTC (permalink / raw)
  To: Samuel Ortiz; +Cc: Andrew Morton, linuxppc-dev, linux-kernel


Adds support of IRDA transceiver residing on PowerQUICC processors and
enabling such on mpc885ads reference board. The driver is implemented 
using of_device concept, hereby implies arch/powerpc support of the target.

Signed-off-by: Vitaly Bordug <vitb@kernel.crashing.org>

Signed-off-by: Vitaly Bordug <vitb@kernel.crashing.org>                                                                                  
---

 arch/powerpc/Kconfig                         |    1 
 arch/powerpc/boot/dts/mpc885ads.dts          |   10 
 arch/powerpc/platforms/8xx/mpc885ads_setup.c |   39 +
 arch/powerpc/sysdev/fsl_soc.c                |   58 ++
 drivers/net/irda/Kconfig                     |    4 
 drivers/net/irda/Makefile                    |    1 
 drivers/net/irda/m8xx-sir.c                  |  715 ++++++++++++++++++++++++++
 include/asm-ppc/commproc.h                   |   67 ++
 8 files changed, 895 insertions(+), 0 deletions(-)

diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index a8e08f4..c283907 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -605,6 +605,7 @@ endmenu
 config ISA_DMA_API
 	bool
 	default y
+	depends on !PPC_8xx
 
 menu "Bus options"
 
diff --git a/arch/powerpc/boot/dts/mpc885ads.dts b/arch/powerpc/boot/dts/mpc885ads.dts
index 110bf61..95b280c 100644
--- a/arch/powerpc/boot/dts/mpc885ads.dts
+++ b/arch/powerpc/boot/dts/mpc885ads.dts
@@ -178,6 +178,16 @@
 				interrupt-parent = <930>;
 				phy-handle = <e8002>;
 			};
+
+			scc@a20 {
+				device_type = "network";
+				compatible = "fsl,irda";
+				model = "SCC";
+				device-id = <2>;
+				reg = <a20 18 3d00 80>;
+				interrupts = <1d 3>;
+				interrupt-parent = <930>;
+			};
 		};
 	};
 };
diff --git a/arch/powerpc/platforms/8xx/mpc885ads_setup.c b/arch/powerpc/platforms/8xx/mpc885ads_setup.c
index a57b577..8611318 100644
--- a/arch/powerpc/platforms/8xx/mpc885ads_setup.c
+++ b/arch/powerpc/platforms/8xx/mpc885ads_setup.c
@@ -50,6 +50,7 @@ extern unsigned int mpc8xx_get_irq(void);
 static void init_smc1_uart_ioports(struct fs_uart_platform_info* fpi);
 static void init_smc2_uart_ioports(struct fs_uart_platform_info* fpi);
 static void init_scc3_ioports(struct fs_platform_info* ptr);
+static void init_irda_ioports(void);
 
 void __init mpc885ads_board_setup(void)
 {
@@ -115,6 +116,10 @@ void __init mpc885ads_board_setup(void)
 	immr_unmap(io_port);
 
 #endif
+
+#ifdef CONFIG_8XX_SIR
+	init_irda_ioports();
+#endif
 }
 
 
@@ -322,6 +327,40 @@ void init_smc_ioports(struct fs_uart_platform_info *data)
 	}
 }
 
+static void init_irda_ioports()
+{
+	iop8xx_t *io_port;
+	cpm8xx_t *cp;
+	unsigned *bcsr_io;
+
+	bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
+
+	if (bcsr_io == NULL) {
+		printk(KERN_CRIT "Could not remap BCSR1\n");
+		return;
+	}
+
+	/* Enable the IRDA. */
+	clrbits32(bcsr_io,BCSR1_IRDAEN);
+	iounmap(bcsr_io);
+
+	io_port = (iop8xx_t *)immr_map(im_ioport);
+	cp = (cpm8xx_t *)immr_map(im_cpm);
+
+	/* Configure port A pins. */
+	setbits16(&io_port->iop_papar, 0x000c);
+	clrbits16(&io_port->iop_padir, 0x000c);
+
+	/* Configure Serial Interface clock routing.
+	 * First, clear all SCC bits to zero, then set the ones we want.
+	 */
+	clrbits32(&cp->cp_sicr, 0x0000ff00);
+	setbits32(&cp->cp_sicr, 0x00001200);
+
+	immr_unmap(io_port);
+	immr_unmap(cp);
+}
+
 int platform_device_skip(const char *model, int id)
 {
 #ifdef CONFIG_MPC8xx_SECOND_ETH_SCC3
diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c
index 8a123c7..f827147 100644
--- a/arch/powerpc/sysdev/fsl_soc.c
+++ b/arch/powerpc/sysdev/fsl_soc.c
@@ -1102,4 +1102,62 @@ err:
 
 arch_initcall(cpm_smc_uart_of_init);
 
+static const char *irda_regs = "regs";
+static const char *irda_pram = "pram";
+static const char *irda_irq = "interrupt";
+static char bus_id[9][BUS_ID_SIZE];
+
+static int __init fs_irda_of_init(void)
+{
+	struct device_node *np;
+	unsigned int i;
+	struct platform_device *fs_irda_dev = NULL;
+	int ret;
+
+	for (np = NULL, i = 0;
+	     (np = of_find_compatible_node(np, "network", "fsl,irda")) != NULL;
+	     i++) {
+		struct resource r[4];
+		unsigned int *id;
+		char *model;
+
+		memset(r, 0, sizeof(r));
+
+		model = (char *)get_property(np, "model", NULL);
+		if (model == NULL)
+			return -ENODEV;
+
+		id = (u32 *) get_property(np, "device-id", NULL);
+		if (platform_device_skip(model, *id))
+			continue;
+
+		ret = of_address_to_resource(np, 0, &r[0]);
+		if (ret)
+			return ret;
+		r[0].name = irda_regs;
+
+		if (strstr(model, "SCC")) {
+			ret = of_address_to_resource(np, 1, &r[1]);
+			if (ret)
+				return ret;
+			r[1].name = irda_pram;
+
+			r[2].start = r[2].end = irq_of_parse_and_map(np, 0);
+			r[2].flags = IORESOURCE_IRQ;
+			r[2].name = irda_irq;
+
+			fs_irda_dev =
+				    platform_device_register_simple("fsl-cpm-scc:irda", i, &r[0], 3);
+
+			if (IS_ERR(fs_irda_dev)) {
+				ret = PTR_ERR(fs_irda_dev);
+				return ret;
+			}
+		}
+	}
+	return 0;
+}
+
+arch_initcall(fs_irda_of_init);
+
 #endif /* CONFIG_8xx */
diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig
index 7c8ccc0..b3681e7 100644
--- a/drivers/net/irda/Kconfig
+++ b/drivers/net/irda/Kconfig
@@ -17,6 +17,10 @@ config IRTTY_SIR
 
 	  If unsure, say Y.
 
+config 8XX_SIR
+	  tristate "mpc8xx SIR"
+	  depends on 8xx && IRDA
+
 comment "Dongle support"
 
 config DONGLE
diff --git a/drivers/net/irda/Makefile b/drivers/net/irda/Makefile
index 5be09f1..fc7c0fd 100644
--- a/drivers/net/irda/Makefile
+++ b/drivers/net/irda/Makefile
@@ -34,6 +34,7 @@ obj-$(CONFIG_EP7211_IR)		+= ep7211_ir.o
 obj-$(CONFIG_AU1000_FIR)	+= au1k_ir.o
 # New SIR drivers
 obj-$(CONFIG_IRTTY_SIR)		+= irtty-sir.o	sir-dev.o
+obj-$(CONFIG_8XX_SIR)		+= m8xx-sir.o
 # New dongles drivers for new SIR drivers
 obj-$(CONFIG_ESI_DONGLE)	+= esi-sir.o
 obj-$(CONFIG_TEKRAM_DONGLE)	+= tekram-sir.o
diff --git a/drivers/net/irda/m8xx-sir.c b/drivers/net/irda/m8xx-sir.c
new file mode 100644
index 0000000..6fb215f
--- /dev/null
+++ b/drivers/net/irda/m8xx-sir.c
@@ -0,0 +1,715 @@
+/*
+ * Infra-red SIR driver for the MPC8xx processors.
+ *
+ * Copyright (c) 2005-2007 MontaVista Software Inc.
+ * Author: Yuri Shpilevsky <source@mvista.com>
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/slab.h>
+#include <linux/rtnetlink.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+
+#include <net/irda/irda.h>
+#include <net/irda/irmod.h>
+#include <net/irda/wrapper.h>
+#include <net/irda/irda_device.h>
+
+#include <asm/io.h>
+#include <asm/cacheflush.h>
+#include <asm/irq.h>
+#include <asm/8xx_immap.h>
+#include <asm/pgtable.h>
+#include <asm/mpc8xx.h>
+#include <asm/bitops.h>
+#include <asm/uaccess.h>
+#include <asm/commproc.h>
+#include <asm/fs_pd.h>
+
+/*
+ * Our netdevice.  There is only ever one of these.
+ */
+
+#define CPM_IRDA_RX_PAGES       4
+#define CPM_IRDA_RX_FRSIZE      2048
+#define CPM_IRDA_RX_FRPPG       (PAGE_SIZE / CPM_IRDA_RX_FRSIZE)
+#define RX_RING_SIZE            (CPM_IRDA_RX_FRPPG * CPM_IRDA_RX_PAGES)
+#define TX_RING_SIZE            8	/* Must be power of two */
+#define TX_RING_MOD_MASK        7
+
+struct mpc8xx_irda {
+	unsigned char open;
+
+	int speed;
+	int newspeed;
+
+	/* The saved address of a sent-in-place packet/buffer, for skfree().
+	 */
+	struct sk_buff *tx_skbuff[TX_RING_SIZE];
+	ushort skb_cur;
+	ushort skb_dirty;
+
+	struct net_device_stats stats;
+	struct device *dev;
+	struct irda_platform_data *pdata;
+	struct irlap_cb *irlap;
+	struct qos_info qos;
+
+	scc_t *sccp;
+	scc_ahdlc_t *ahp;
+	int irq;
+	cbd_t *rx_bd_base;
+	cbd_t *tx_bd_base;
+	cbd_t *dirty_tx;
+	cbd_t *cur_rx, *cur_tx;	/* The next free ring entry */
+	unsigned char *rx_vaddr[RX_RING_SIZE];
+	int tx_free;
+	spinlock_t lock;
+};
+
+#define HPSIR_MAX_RXLEN		2050
+#define HPSIR_MAX_TXLEN		2050
+#define TXBUFF_MAX_SIZE		HPSIR_MAX_TXLEN
+
+static void mpc8xx_irda_set_speed(struct net_device *dev, int speed);
+
+/************************************************************************************/
+
+/* Low level init/uninstall function IrDA protocol stack registration
+ */
+
+static void mpc8xx_irda_rx(struct net_device *dev)
+{
+	struct mpc8xx_irda *si = dev->priv;
+	cbd_t *bdp;
+	struct sk_buff *skb;
+	int len;
+	ushort status;
+
+	bdp = si->cur_rx;
+
+	for (;;) {
+		if (bdp->cbd_sc & BD_AHDLC_RX_EMPTY)
+			break;
+		status = bdp->cbd_sc;
+
+		if (status & BD_AHDLC_RX_STATS) {
+			/* process errors
+			 */
+			if (bdp->cbd_sc & BD_AHDLC_RX_AB)
+				si->stats.rx_length_errors++;
+			if (bdp->cbd_sc & BD_AHDLC_RX_CR)	/* CRC Error */
+				si->stats.rx_crc_errors++;
+			if (bdp->cbd_sc & BD_AHDLC_RX_OV)	/* FIFO overrun */
+				si->stats.rx_over_errors++;
+		} else {
+			/* Process the incoming frame.
+			 */
+			len = bdp->cbd_datlen;
+
+			skb = dev_alloc_skb(len + 1);
+			if (skb == NULL) {
+				printk(KERN_INFO
+				       "%s: Memory squeeze, dropping packet.\n",
+				       dev->name);
+				si->stats.rx_dropped++;
+			} else {
+				skb->dev = dev;
+				skb_reserve(skb, 1);
+				memcpy(skb_put(skb, len),
+				       si->rx_vaddr[bdp - si->rx_bd_base], len);
+				skb_trim(skb, skb->len - 2);
+
+				si->stats.rx_packets++;
+				si->stats.rx_bytes += len;
+
+				skb->mac.raw = skb->data;
+				skb->protocol = htons(ETH_P_IRDA);
+				netif_rx(skb);
+			}
+		}
+
+		/* Clear the status flags for this buffer.
+		 */
+		bdp->cbd_sc &= ~BD_AHDLC_RX_STATS;
+
+		/* Mark the buffer empty.
+		 */
+		bdp->cbd_sc |= BD_AHDLC_RX_EMPTY;
+
+		/* Update BD pointer to next entry.
+		 */
+		if (bdp->cbd_sc & BD_AHDLC_RX_WRAP)
+			bdp = si->rx_bd_base;
+		else
+			bdp++;
+	}
+	si->cur_rx = (cbd_t *) bdp;
+}
+
+static irqreturn_t mpc8xx_irda_irq(int irq, void *dev_id)
+{
+	struct net_device *dev = dev_id;
+	struct mpc8xx_irda *si = dev->priv;
+	scc_t *sccp = si->sccp;
+	cbd_t *bdp;
+	ushort int_events;
+	int must_restart = 0;
+
+	/* Get the interrupt events that caused us to be here.
+	 */
+	int_events = in_be16(&sccp->scc_scce);
+	out_be16(&sccp->scc_scce, int_events);
+
+	/* Handle receive event in its own function.
+	 */
+	if (int_events & SCC_AHDLC_RXF)
+		mpc8xx_irda_rx(dev);
+
+	spin_lock(&si->lock);
+
+	/* Transmit OK, or non-fatal error.  Update the buffer descriptors.
+	 */
+	if (int_events & (SCC_AHDLC_TXE | SCC_AHDLC_TXB)) {
+		bdp = si->dirty_tx;
+
+		while ((bdp->cbd_sc & BD_AHDLC_TX_READY) == 0) {
+			if (si->tx_free == TX_RING_SIZE)
+				break;
+
+			if (bdp->cbd_sc & BD_AHDLC_TX_CTS)
+				must_restart = 1;
+
+			si->stats.tx_packets++;
+
+			/* Free the sk buffer associated with this last transmit.
+			 */
+			dev_kfree_skb_irq(si->tx_skbuff[si->skb_dirty]);
+			si->skb_dirty = (si->skb_dirty + 1) & TX_RING_MOD_MASK;
+
+			/* Update pointer to next buffer descriptor to be transmitted.
+			 */
+			if (bdp->cbd_sc & BD_AHDLC_TX_WRAP)
+				bdp = si->tx_bd_base;
+			else
+				bdp++;
+
+			/* Since we have freed up a buffer, the ring is no longer full.
+			 */
+			if (!si->tx_free++) {
+				if (netif_queue_stopped(dev))
+					netif_wake_queue(dev);
+			}
+
+			si->dirty_tx = (cbd_t *) bdp;
+
+			if (si->newspeed) {
+				mpc8xx_irda_set_speed(dev, si->newspeed);
+				si->speed = si->newspeed;
+				si->newspeed = 0;
+			}
+		}
+
+		if (must_restart) {
+			cpm8xx_t *cp = immr_map(im_cpm);
+			printk(KERN_INFO "restart TX\n");
+
+			/* Some transmit errors cause the transmitter to shut
+			 * down.  We now issue a restart transmit.  Since the
+			 * errors close the BD and update the pointers, the restart
+			 * _should_ pick up without having to reset any of our
+			 * pointers either.
+			 */
+			out_be16(&cp->cp_cpcr,
+			    mk_cr_cmd(CPM_CR_CH_SCC2,
+				      CPM_CR_RESTART_TX) | CPM_CR_FLG);
+			while (in_be16(&cp->cp_cpcr) & CPM_CR_FLG) ;
+		}
+	}
+
+	spin_unlock(&si->lock);
+
+	return IRQ_HANDLED;
+}
+
+static int mpc8xx_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct mpc8xx_irda *si = dev->priv;
+	volatile scc_ahdlc_t *ahp = si->ahp;
+	int speed = irda_get_next_speed(skb);
+	cbd_t *bdp;
+	int mtt;
+	u16 xbofs;
+	unsigned long flags;
+
+	/*
+	 * Does this packet contain a request to change the interface
+	 * speed?  If so, remember it until we complete the transmission
+	 * of this frame.
+	 */
+	if (speed != si->speed && speed != -1)
+		si->newspeed = speed;
+
+	mtt = irda_get_mtt(skb);
+
+	spin_lock_irqsave(&si->lock, flags);
+
+	/*
+	 * If this is an empty frame, we can bypass a lot.
+	 */
+	if (skb->len == 0) {
+		if (si->newspeed) {
+			si->newspeed = 0;
+			mpc8xx_irda_set_speed(dev, speed);
+		}
+		spin_unlock_irqrestore(&si->lock, flags);
+		dev_kfree_skb(skb);
+		return 0;
+	}
+
+	/* Get a Tx ring entry */
+	bdp = si->cur_tx;
+
+	/* Clear all of the status flags.
+	 */
+	bdp->cbd_sc &= ~BD_AHDLC_TX_STATS;
+
+	/* Set xbofs
+	 */
+	{
+		struct irda_skb_cb *cb = (struct irda_skb_cb *)skb->cb;
+		xbofs =
+		    (cb->magic != LAP_MAGIC) ? 10 : cb->xbofs + cb->xbofs_delay;
+		xbofs = (xbofs > 163) ? 163 : xbofs;
+		out_be16(&ahp->ahdlc_nof, xbofs);
+	}
+
+	/* Set buffer length and buffer pointer.
+	 */
+	bdp->cbd_datlen = skb->len;
+	bdp->cbd_bufaddr = __pa(skb->data);
+
+	/* Push the data cache so the CPM does not get stale memory data.
+	 */
+	flush_dcache_range((unsigned long)(skb->data),
+			   (unsigned long)(skb->data + skb->len));
+
+	/* Save skb pointer.
+	 */
+	si->tx_skbuff[si->skb_cur] = skb;
+
+	si->stats.tx_bytes += skb->len;
+	si->skb_cur = (si->skb_cur + 1) & TX_RING_MOD_MASK;
+
+	/* If we have a mean turn-around time, impose the specified
+	 * specified delay.  We could shorten this by timing from
+	 * the point we received the packet.
+	 */
+	if (mtt > 0)
+		udelay(mtt);
+
+	/* Send it on its way.  Tell CPM its ready, interrupt when done,
+	 * its the last BD of the frame, and to put the CRC on the end.
+	 */
+	bdp->cbd_sc |=
+	    (BD_AHDLC_TX_READY | BD_AHDLC_TX_INTR | BD_AHDLC_TX_LAST);
+
+	dev->trans_start = jiffies;
+
+	/* If this was the last BD in the ring, start at the beginning again.
+	 */
+	if (bdp->cbd_sc & BD_AHDLC_TX_WRAP)
+		bdp = si->tx_bd_base;
+	else
+		bdp++;
+
+	spin_unlock_irqrestore(&si->lock, flags);
+
+	if (!--si->tx_free)
+		netif_stop_queue(dev);
+
+	si->cur_tx = (cbd_t *) bdp;
+
+	return 0;
+}
+
+static int
+mpc8xx_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd)
+{
+	struct if_irda_req *rq = (struct if_irda_req *)ifreq;
+	struct mpc8xx_irda *si = dev->priv;
+	int ret = -EOPNOTSUPP;
+
+	switch (cmd) {
+	case SIOCSBANDWIDTH:
+		if (capable(CAP_NET_ADMIN)) {
+			/* We are unable to set the speed if the
+			 * device is not running.
+			 */
+			if (si->open)
+				mpc8xx_irda_set_speed(dev, rq->ifr_baudrate);
+			else
+				printk(KERN_INFO
+				       "mpc8xx_irda_ioctl: SIOCSBANDWIDTH: !netif_running\n");
+			ret = 0;
+		}
+		break;
+
+	case SIOCSMEDIABUSY:
+		ret = -EPERM;
+		if (capable(CAP_NET_ADMIN)) {
+			irda_device_set_media_busy(dev, TRUE);
+			ret = 0;
+		}
+		break;
+
+	case SIOCGRECEIVING:
+		rq->ifr_receiving = 0;
+		break;
+
+	default:
+		break;
+	}
+
+	return ret;
+}
+
+static struct net_device_stats *mpc8xx_irda_stats(struct net_device *ndev)
+{
+	struct mpc8xx_irda *si = ndev->priv;
+	return &si->stats;
+}
+
+static int mpc8xx_irda_pd_setup(struct mpc8xx_irda *si)
+{
+	struct platform_device *pdev = to_platform_device(si->dev);
+	struct resource *r;
+
+	/* Fill out IRQ field */
+	si->irq = platform_get_irq_byname(pdev, "interrupt");
+
+	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
+	si->sccp = ioremap(r->start, r->end - r->start + 1);
+
+	if (si->sccp == NULL)
+		return -EINVAL;
+
+	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pram");
+	si->ahp = ioremap(r->start, r->end - r->start + 1);
+
+	if (si->ahp == NULL)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int mpc8xx_irda_startup(struct net_device *dev)
+{
+	struct mpc8xx_irda *si = dev->priv;
+	cbd_t *bdp;
+	volatile cpm8xx_t *cp = immr_map(im_cpm);
+	scc_t *sccp;
+	volatile scc_ahdlc_t *ahp;
+	dma_addr_t mem_addr;
+	int i, j, k;
+	unsigned char *ba;
+	int err = -ENOMEM;
+
+	spin_lock_init(&si->lock);
+
+	if ((err = mpc8xx_irda_pd_setup(si)))
+		return err;
+
+	sccp = si->sccp;
+	ahp = si->ahp;
+
+	/* Disable receive and transmit.
+	 */
+	clrbits32(&sccp->scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+
+	/* Allocate space for the buffer descriptors in the DP ram.
+	 * These are relative offsets in the DP ram address space.
+	 * Initialize base addresses for the buffer descriptors.
+	 */
+	i = cpm_dpalloc(sizeof(cbd_t) * RX_RING_SIZE, 8);
+	out_be16(&ahp->scc_genscc.scc_rbase, i);
+	si->rx_bd_base = cpm_dpram_addr(i);
+	si->cur_rx = si->rx_bd_base;
+
+	i = cpm_dpalloc(sizeof(cbd_t) * TX_RING_SIZE, 8);
+	out_be16(&ahp->scc_genscc.scc_tbase, i);
+	si->tx_bd_base = cpm_dpram_addr(i);
+	si->dirty_tx = si->cur_tx = si->tx_bd_base;
+	si->tx_free = TX_RING_SIZE;
+
+	/* Issue init Tx and Rx BD command for SCC2.
+	 */
+	out_be16(&cp->cp_cpcr, mk_cr_cmd(CPM_CR_CH_SCC2, CPM_CR_INIT_TRX) | CPM_CR_FLG);
+	while (in_be16(&cp->cp_cpcr) & CPM_CR_FLG) ;
+
+	si->skb_cur = si->skb_dirty = 0;
+
+	/* Initialize function code registers for big-endian.
+	 */
+	out_8(&ahp->scc_genscc.scc_rfcr, SCC_EB);
+	out_8(&ahp->scc_genscc.scc_tfcr, SCC_EB);
+
+	/* Set maximum bytes per receive buffer.
+	 * This appears to be an Ethernet frame size, not the buffer
+	 * fragment size.  It must be a multiple of four.
+	 */
+	out_be16(&ahp->scc_genscc.scc_mrblr, 14384);
+
+	/* Set CRC preset and mask.
+	 */
+	out_be32(&ahp->ahdlc_cpres, 0x0000ffff);
+	out_be32(&ahp->ahdlc_cmask, 0x0000f0b8);
+
+	/* Clear zero register.
+	 */
+	out_be16(&ahp->ahdlc_zero, 0);
+
+	/* Program RFTHR to the number of frames to be received
+	 * before generating an interrupt.
+	 */
+	out_be16(&ahp->ahdlc_rfthr, 1);
+
+	/* Program the control character tables, TXCTL_TBL and RXCTL_TBL.
+	 */
+	out_be32(&ahp->ahdlc_txctl_tbl, 0);	// initialized to zero for IrLAP.
+	out_be32(&ahp->ahdlc_rxctl_tbl, 0);	// initialized to zero for IrLAP.
+
+	out_be16(&ahp->ahdlc_bof, 0xC0);	//IRLAP_BOF; /* Begin. of Flag Char */
+	out_be16(&ahp->ahdlc_eof, 0xC1);	//IRLAP_EOF; /* End of Flag Char */
+	out_be16(&ahp->ahdlc_esc, 0x7D);	//IRLAP_ESC; /* Control Escape Char */
+	out_be16(&ahp->ahdlc_nof, 12);
+
+	/* Now allocate the host memory pages and initialize the
+	 * buffer descriptors.
+	 */
+	bdp = si->tx_bd_base;
+	for (i = 0; i < TX_RING_SIZE; i++) {
+		/* Initialize the BD for every fragment in the page.
+		 */
+		bdp->cbd_sc = 0;
+		bdp->cbd_bufaddr = 0;
+		bdp++;
+	}
+
+	/* Set the last buffer to wrap.
+	 */
+	bdp--;
+	bdp->cbd_sc |= BD_SC_WRAP;
+
+	bdp = si->rx_bd_base;
+	k = 0;
+	for (i = 0; i < CPM_IRDA_RX_PAGES; i++) {
+
+		/* Allocate a page.
+		 */
+		ba = (unsigned char *)dma_alloc_coherent(NULL, PAGE_SIZE,
+							 &mem_addr, GFP_KERNEL);
+
+		/* Initialize the BD for every fragment in the page.
+		 */
+		for (j = 0; j < CPM_IRDA_RX_FRPPG; j++) {
+			bdp->cbd_sc = BD_AHDLC_RX_EMPTY | BD_AHDLC_RX_INTR;
+			bdp->cbd_bufaddr = mem_addr;
+			si->rx_vaddr[k++] = ba;
+			mem_addr += CPM_IRDA_RX_FRSIZE;
+			ba += CPM_IRDA_RX_FRSIZE;
+			bdp++;
+		}
+	}
+
+	/* Set the last buffer to wrap.
+	 */
+	bdp--;
+	bdp->cbd_sc |= BD_SC_WRAP;
+
+	out_be16(&sccp->scc_scce, 0xffff);	/* Clear any pending events */
+	out_be16(&sccp->scc_sccm, SCC_AHDLC_TXE | SCC_AHDLC_RXF | SCC_AHDLC_TXB);
+
+	err = request_irq(si->irq, mpc8xx_irda_irq, 0, dev->name, dev);
+	if (err) {
+		kfree(si);
+		return err;
+	}
+
+	/* Set GSMR_H to enable all normal operating modes.
+	 * Set GSMR_L to enable Ethernet to MC68160.
+	 */
+	out_be32(&sccp->scc_gsmrh, SCC_GSMRH_RFW | SCC_GSMRH_IRP);
+	out_be32(&sccp->scc_gsmrl, SCC_GSMRL_SIR | SCC_GSMRL_MODE_AHDLC | SCC_GSMRL_TDCR_16 |
+				   SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16);
+
+	out_be16(&sccp->scc_dsr, 0x7e7e);
+
+	/* Set processing mode.
+	 */
+	out_be16(&sccp->scc_psmr, SCC_PMSR_CHLN);
+
+	/* Enable the transmit and receive processing.
+	 */
+	setbits32(&sccp->scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+
+	netif_start_queue(dev);
+
+	return 0;
+}
+
+static int mpc8xx_irda_start(struct net_device *dev)
+{
+	struct mpc8xx_irda *si = dev->priv;
+	int err = 0;
+
+	if ((err = mpc8xx_irda_startup(dev)))
+		return err;
+
+	mpc8xx_irda_set_speed(dev, si->speed = 9600);
+
+	/* Open new IrLAP layer instance, now that everything should be
+	 * initialized properly
+	 */
+	si->irlap = irlap_open(dev, &si->qos, "MPC8xx SIR");
+	err = -ENOMEM;
+	if (!si->irlap) {
+		si->open = 0;
+		return err;
+	}
+
+	/* Now start the queue
+	 */
+	si->open = 1;
+	netif_start_queue(dev);
+
+	return 0;
+}
+
+static int mpc8xx_irda_stop(struct net_device *dev)
+{
+	struct mpc8xx_irda *si = dev->priv;
+
+	disable_irq(dev->irq);
+
+	/* Stop IrLAP */
+	if (si->irlap) {
+		irlap_close(si->irlap);
+		si->irlap = NULL;
+	}
+
+	netif_stop_queue(dev);
+	si->open = 0;
+
+	/* Free resources
+	 */
+	free_irq(dev->irq, dev);
+
+	return 0;
+}
+
+static void mpc8xx_irda_set_speed(struct net_device *dev, int speed)
+{
+	cpm_setbrg(2, speed);
+}
+
+static int mpc8xx_irda_probe(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct net_device *ndev;
+	struct mpc8xx_irda *si;
+	int err;
+
+	if (!(ndev = alloc_irdadev(sizeof(struct mpc8xx_irda))))
+		return -ENOMEM;
+
+	si = ndev->priv;
+	si->dev = dev;
+	si->pdata = pdev->dev.platform_data;
+
+	ndev->hard_start_xmit = mpc8xx_irda_hard_xmit;
+	ndev->open = mpc8xx_irda_start;
+	ndev->stop = mpc8xx_irda_stop;
+	ndev->do_ioctl = mpc8xx_irda_ioctl;
+	ndev->get_stats = mpc8xx_irda_stats;
+
+	irda_init_max_qos_capabilies(&si->qos);
+
+	/* We support original IRDA up to 115k2.
+	 * Min Turn Time set to 1ms or greater.
+	 */
+
+	si->qos.baud_rate.bits =
+	    IR_9600 | IR_19200 | IR_38400 | IR_57600 | IR_115200;
+	si->qos.min_turn_time.bits = 7;
+	irda_qos_bits_to_value(&si->qos);
+
+	err = register_netdev(ndev);
+
+	if (!err) {
+		dev_set_drvdata(&pdev->dev, ndev);
+		printk(KERN_INFO "IrDA: Registered device %s\n", ndev->name);
+	} else
+		free_netdev(ndev);
+
+	return err;
+}
+
+static int mpc8xx_irda_remove(struct device *_dev)
+{
+	struct net_device *dev = dev_get_drvdata(_dev);
+
+	if (dev) {
+		rtnl_lock();
+		unregister_netdevice(dev);
+		free_netdev(dev);
+		rtnl_unlock();
+	}
+
+	/*
+	 * We now know that the netdevice is no longer in use, and all
+	 * references to our driver have been removed.  The only structure
+	 * which may still be present is the netdevice, which will get
+	 * cleaned up by net/core/dev.c
+	 */
+
+	return 0;
+}
+
+static struct device_driver m8xxir_driver = {
+	.name = "fsl-cpm-scc:irda",
+	.bus = &platform_bus_type,
+	.probe = mpc8xx_irda_probe,
+	.remove = mpc8xx_irda_remove,
+};
+
+static int mpc8xx_irda_init(void)
+{
+	return driver_register(&m8xxir_driver);
+}
+
+static void __exit mpc8xx_irda_exit(void)
+{
+	driver_unregister(&m8xxir_driver);
+}
+
+module_init(mpc8xx_irda_init);
+module_exit(mpc8xx_irda_exit);
+
+MODULE_AUTHOR("source@mvista.com");
+MODULE_DESCRIPTION("MPC8XX SIR");
+MODULE_LICENSE("GPL");
diff --git a/include/asm-ppc/commproc.h b/include/asm-ppc/commproc.h
index 4f99df1..9e251c3 100644
--- a/include/asm-ppc/commproc.h
+++ b/include/asm-ppc/commproc.h
@@ -616,6 +616,73 @@ typedef struct spi {
 #define SPIE_TXB	0x02
 #define SPIE_RXB	0x01
 
+/* Asynchronous HDLC Mode Parameter RAM.
+*/
+typedef struct scc_ahdlc {
+	sccp_t  scc_genscc;
+	uint    ahdlc_res1;	/* Reserved */
+	uint    ahdlc_cmask;	/* Constant mask for CRC */
+	uint    ahdlc_cpres;	/* Preset CRC */
+	ushort  ahdlc_bof;	/* Beginning of flag character */
+	ushort  ahdlc_eof;	/* End of flag character */
+	ushort  ahdlc_esc;	/* Control escape character. */
+	ushort  ahdlc_res2;	/* Reserved */
+	ushort  ahdlc_res3;	/* Reserved */
+	ushort  ahdlc_zero;	/* Clear this field */
+	ushort  ahdlc_res4;	/* Reserved */
+	ushort  ahdlc_rfthr;	/* Received frames threshold */
+	uint    ahdlc_res5;	/* Reserved */
+	uint    ahdlc_txctl_tbl;/* Control Tx character tables */
+	uint    ahdlc_rxctl_tbl;/* Control Rx character tables */
+	ushort  ahdlc_nof;	/* Number of opening flags to be sent at the beginning of a frame */
+	ushort  ahdlc_res6;	/* Reserved */
+} scc_ahdlc_t;
+
+/* SCC Mode Register (PMSR) as used by Ethernet.
+*/
+#define SCC_PMSR_CHLN		((ushort)0x3000)        /* 8 bits character length */
+#define SICR_IRDA_MASK		((uint)0x0000ff00)
+#define SICR_IRDA_CLKRT		((uint)0x00001200)
+
+/* SCC Event register as used by Asynchronous HDLC.
+*/
+#define SCC_AHDLC_GLR		((ushort)0x1000)
+#define SCC_AHDLC_GLT		((ushort)0x0800)
+#define SCC_AHDLC_IDL		((ushort)0x0100)
+#define SCC_AHDLC_BRKE		((ushort)0x0040)
+#define SCC_AHDLC_BRKS		((ushort)0x0020)
+#define SCC_AHDLC_TXE		((ushort)0x0010)
+#define SCC_AHDLC_RXF		((ushort)0x0008)
+#define SCC_AHDLC_BSY		((ushort)0x0004)
+#define SCC_AHDLC_TXB		((ushort)0x0002)
+#define SCC_AHDLC_RXB		((ushort)0x0001)
+
+/* Buffer descriptor control/status used by AHDLC receive.
+*/
+#define BD_AHDLC_RX_EMPTY	((ushort)0x8000)
+#define BD_AHDLC_RX_WRAP	((ushort)0x2000)
+#define BD_AHDLC_RX_INTR	((ushort)0x1000)
+#define BD_AHDLC_RX_LAST	((ushort)0x0800)
+#define BD_AHDLC_RX_FIRST	((ushort)0x0400)
+#define BD_AHDLC_RX_CM		((ushort)0x0200)
+#define BD_AHDLC_RX_BRK		((ushort)0x0080)
+#define BD_AHDLC_RX_BOF		((ushort)0x0040)
+#define BD_AHDLC_RX_AB		((ushort)0x0008)
+#define BD_AHDLC_RX_CR		((ushort)0x0004)
+#define BD_AHDLC_RX_OV		((ushort)0x0002)
+#define BD_AHDLC_RX_CD		((ushort)0x0001)
+#define BD_AHDLC_RX_STATS	((ushort)0x008f)        /* All status bits */
+
+/* Buffer descriptor control/status used by AHDLC transmit.
+*/
+#define BD_AHDLC_TX_READY	((ushort)0x8000)
+#define BD_AHDLC_TX_WRAP	((ushort)0x2000)
+#define BD_AHDLC_TX_INTR	((ushort)0x1000)
+#define BD_AHDLC_TX_LAST	((ushort)0x0800)
+#define BD_AHDLC_TX_CM		((ushort)0x0200)
+#define BD_AHDLC_TX_CTS		((ushort)0x0001)
+#define BD_AHDLC_TX_STATS	((ushort)0x03ff)        /* All status bits */
+
 /*
  * RISC Controller Configuration Register definitons
  */

^ permalink raw reply related

* [PATCH] [POWERPC] iSeries: make HVC_ISERIES the default
From: Stephen Rothwell @ 2007-05-08  5:05 UTC (permalink / raw)
  To: paulus; +Cc: ppc-dev

This makes the new iSeries virtual console drivers (nvc_iseries) the
default and prevents viocons being built unless explicitly selected.
Also it makes no sense to have the console as a module.

Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
---
 arch/powerpc/platforms/iseries/Kconfig |    4 +++-
 drivers/char/Kconfig                   |    3 ++-
 2 files changed, 5 insertions(+), 2 deletions(-)

-- 
Cheers,
Stephen Rothwell                    sfr@canb.auug.org.au

diff --git a/arch/powerpc/platforms/iseries/Kconfig b/arch/powerpc/platforms/iseries/Kconfig
index 46c3a8e..761d9e9 100644
--- a/arch/powerpc/platforms/iseries/Kconfig
+++ b/arch/powerpc/platforms/iseries/Kconfig
@@ -7,7 +7,9 @@ menu "iSeries device drivers"
 	depends on PPC_ISERIES
 
 config VIOCONS
-	tristate "iSeries Virtual Console Support (Obsolete)"
+	bool "iSeries Virtual Console Support (Obsolete)"
+	depends on !HVC_ISERIES
+	default n
 	help
 	  This is the old virtual console driver for legacy iSeries.
 	  You should use the iSeries Hypervisor Virtual Console
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index a26d917..f888a79 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -631,7 +631,8 @@ config HVC_CONSOLE
 
 config HVC_ISERIES
 	bool "iSeries Hypervisor Virtual Console support"
-	depends on PPC_ISERIES && !VIOCONS
+	depends on PPC_ISERIES
+	default y
 	select HVC_DRIVER
 	help
 	  iSeries machines support a hypervisor virtual console.
-- 
1.5.1.3

^ permalink raw reply related


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