LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/2] kexec: Added generic --reuseinitrd option
From: Michael Neuling @ 2007-04-23  8:30 UTC (permalink / raw)
  To: kexec; +Cc: linuxppc-dev, horms, Fastboot mailing list, miltonm
In-Reply-To: <5129.1176956949@neuling.org>

Adds a generic --reuseinitrd option and performs some sanity checks on
it.  Can be used with the retain_initrd kernel option.

---
This series attempts to address some of Milton's concerns.

 kexec/kexec.c |   33 +++++++++++++++++++++++++++++++++
 kexec/kexec.h |    2 ++
 2 files changed, 35 insertions(+)

Index: kexec-tools-testing/kexec/kexec.c
===================================================================
--- kexec-tools-testing.orig/kexec/kexec.c
+++ kexec-tools-testing/kexec/kexec.c
@@ -748,6 +748,7 @@ void usage(void)
 	       "                      load code into.\n"
 	       "     --mem-max=<addr> Specify the highest memory address to\n"
 	       "                      load code into.\n"
+	       "     --reuseinird     Reuse initrd from first boot.\n"
 	       "\n"
 	       "Supported kernel file types and options: \n");
 	for (i = 0; i < file_types; i++) {
@@ -772,6 +773,29 @@ static int kexec_loaded(void)
 	return ret;
 }
 
+/* check we retained the initrd */
+void check_reuse_initrd(void)
+{
+	FILE * fp;
+	char * line = NULL;
+	size_t len = 0;
+	ssize_t read;
+
+	fp = fopen("/proc/cmdline", "r");
+	if (fp == NULL)
+		die("unable to open /proc/cmdline\n");
+	read = getline(&line, &len, fp);
+	if (strstr(line, "retain_initrd") == NULL)
+		die("unrecoverable error: current boot didn't "
+		    "retain the initrd for reuse.\n");
+}
+
+/* Arch hook for reuse_initrd */
+void __attribute__((weak)) arch_reuse_initrd(void)
+{
+	die("--reuseinitrd not implemented on this architecture\n");
+}
+
 int main(int argc, char *argv[])
 {
 	int do_load = 1;
@@ -780,6 +804,7 @@ int main(int argc, char *argv[])
 	int do_sync = 1;
 	int do_ifdown = 0;
 	int do_unload = 0;
+	int do_reuse_initrd = 0;
 	unsigned long kexec_flags = 0;
 	char *type = 0;
 	char *endptr;
@@ -860,6 +885,9 @@ int main(int argc, char *argv[])
 				return 1;
 			}
 			break;
+		case OPT_REUSE_INITRD:
+			do_reuse_initrd = 1;
+			break;
 		default:
 			break;
 		}
@@ -890,6 +918,11 @@ int main(int argc, char *argv[])
 		}
 	}
 
+	if (do_reuse_initrd){
+		check_reuse_initrd();
+		arch_reuse_initrd();
+	}
+
 	if (do_unload) {
 		result = k_unload(kexec_flags);
 	}
Index: kexec-tools-testing/kexec/kexec.h
===================================================================
--- kexec-tools-testing.orig/kexec/kexec.h
+++ kexec-tools-testing/kexec/kexec.h
@@ -163,6 +163,7 @@ extern int file_types;
 #define OPT_MEM_MIN             256
 #define OPT_MEM_MAX             257
 #define OPT_MAX			258
+#define OPT_REUSE_INITRD	259
 #define KEXEC_OPTIONS \
 	{ "help",		0, 0, OPT_HELP }, \
 	{ "version",		0, 0, OPT_VERSION }, \
@@ -175,6 +176,7 @@ extern int file_types;
 	{ "load-panic",         0, 0, OPT_PANIC }, \
 	{ "mem-min",		1, 0, OPT_MEM_MIN }, \
 	{ "mem-max",		1, 0, OPT_MEM_MAX }, \
+	{ "reuseinitrd",	0, 0, OPT_REUSE_INITRD }, \
 
 #define KEXEC_OPT_STR "hvdfxluet:p"
 

^ permalink raw reply

* Re: [PATCH 7/7] MPIC MSI backend
From: Segher Boessenkool @ 2007-04-23  8:24 UTC (permalink / raw)
  To: Olof Johansson; +Cc: linuxppc-dev, linux-pci, Milton Miller
In-Reply-To: <20070422193017.GA27048@lixom.net>

>> mpic_htmsi deals with MSIs that come in over hypertransport
>> to the MPIC on CPC925/CPC945; this has nothing to
>> do with HT APICs.
>
> Maybe it should be named mpic_cpc9x5msi instead?

Yeah probably, esp. since there are more MSI sources
on those chips, not just HT; and if support for those
sources gets added later, it should go to this file :-)


Segher

^ permalink raw reply

* [PATCH] generic check_legacy_ioport
From: Olaf Hering @ 2007-04-23  8:15 UTC (permalink / raw)
  To: linuxppc-dev
In-Reply-To: <20070417210745.GA3567@aepfle.de>


check_legacy_ioport makes only sense on PREP, CHRP and pSeries.
They may have an isa node with PS/2, parport, floppy and serial ports.
Cell has IPMI, check for that too.

Remove the check_legacy_ioport call from ppc_md, its not needed anymore.
Hardware capabilities come from the device-tree.

Signed-off-by: Olaf Hering <olaf@aepfle.de>

---
 arch/powerpc/kernel/setup-common.c      |   35 ++++++++++++++++++++++++++++++--
 arch/powerpc/platforms/cell/setup.c     |   10 ---------
 arch/powerpc/platforms/celleb/setup.c   |   10 ---------
 arch/powerpc/platforms/iseries/setup.c  |   10 ---------
 arch/powerpc/platforms/pasemi/setup.c   |    7 ------
 arch/powerpc/platforms/powermac/setup.c |   10 ---------
 arch/powerpc/platforms/pseries/setup.c  |   27 ------------------------
 include/asm-powerpc/io.h                |    7 +++++-
 include/asm-powerpc/machdep.h           |    3 --
 9 files changed, 39 insertions(+), 80 deletions(-)

--- a/arch/powerpc/kernel/setup-common.c
+++ b/arch/powerpc/kernel/setup-common.c
@@ -498,9 +498,40 @@ void probe_machine(void)
 
 int check_legacy_ioport(unsigned long base_port)
 {
-	if (ppc_md.check_legacy_ioport == NULL)
+	struct device_node *np = NULL;
+
+	switch(base_port) {
+#if defined(CONFIG_SERIO_I8042) || defined(CONFIG_SERIO_I8042_MODULE)
+	case I8042_DATA_REG:
+		np = of_find_node_by_type(NULL, "8042");
+		break;
+#endif
+#if defined(CONFIG_BLK_DEV_FD) || defined(CONFIG_BLK_DEV_FD_MODULE)
+	case FDC_BASE: /* FDC1 */
+		np = of_find_node_by_type(NULL, "fdc");
+		break;
+#endif
+#if defined(CONFIG_IPMI_HANDLER) || defined(CONFIG_IPMI_HANDLER_MODULE)
+	case 0xca2:
+	case 0xca9:
+	case 0xe4:
+		np = of_find_node_by_type(NULL, "ipmi");
+		break;
+#endif
+#ifdef CONFIG_PPC_PREP
+	case _PIDXR:
+	case _PNPWRP:
+	case PNPBIOS_BASE:
+		/* implement me for PReP */
+#endif
+	default:
+		break;
+	}
+	if (np) {
+		of_node_put(np);
 		return 0;
-	return ppc_md.check_legacy_ioport(base_port);
+	}
+	return -ENODEV;
 }
 EXPORT_SYMBOL(check_legacy_ioport);
 
--- a/arch/powerpc/platforms/cell/setup.c
+++ b/arch/powerpc/platforms/cell/setup.c
@@ -190,15 +190,6 @@ static int __init cell_probe(void)
 	return 1;
 }
 
-/*
- * Cell has no legacy IO; anything calling this function has to
- * fail or bad things will happen
- */
-static int cell_check_legacy_ioport(unsigned int baseport)
-{
-	return -ENODEV;
-}
-
 define_machine(cell) {
 	.name			= "Cell",
 	.probe			= cell_probe,
@@ -211,7 +202,6 @@ define_machine(cell) {
 	.get_rtc_time		= rtas_get_rtc_time,
 	.set_rtc_time		= rtas_set_rtc_time,
 	.calibrate_decr		= generic_calibrate_decr,
-	.check_legacy_ioport	= cell_check_legacy_ioport,
 	.progress		= cell_progress,
 	.init_IRQ       	= cell_init_irq,
 	.pci_setup_phb		= rtas_setup_phb,
--- a/arch/powerpc/platforms/celleb/setup.c
+++ b/arch/powerpc/platforms/celleb/setup.c
@@ -128,15 +128,6 @@ static int __init celleb_probe(void)
 	return 1;
 }
 
-/*
- * Cell has no legacy IO; anything calling this function has to
- * fail or bad things will happen
- */
-static int celleb_check_legacy_ioport(unsigned int baseport)
-{
-	return -ENODEV;
-}
-
 #ifdef CONFIG_KEXEC
 static void celleb_kexec_cpu_down(int crash, int secondary)
 {
@@ -173,7 +164,6 @@ define_machine(celleb) {
 	.get_rtc_time		= beat_get_rtc_time,
 	.set_rtc_time		= beat_set_rtc_time,
 	.calibrate_decr		= generic_calibrate_decr,
-	.check_legacy_ioport	= celleb_check_legacy_ioport,
 	.progress		= celleb_progress,
 	.power_save		= beat_power_save,
 	.nvram_size		= beat_nvram_get_size,
--- a/arch/powerpc/platforms/iseries/setup.c
+++ b/arch/powerpc/platforms/iseries/setup.c
@@ -628,15 +628,6 @@ static void iseries_iounmap(volatile voi
 {
 }
 
-/*
- * iSeries has no legacy IO, anything calling this function has to
- * fail or bad things will happen
- */
-static int iseries_check_legacy_ioport(unsigned int baseport)
-{
-	return -ENODEV;
-}
-
 static int __init iseries_probe(void)
 {
 	unsigned long root = of_get_flat_dt_root();
@@ -667,7 +658,6 @@ define_machine(iseries) {
 	.calibrate_decr	= generic_calibrate_decr,
 	.progress	= iSeries_progress,
 	.probe		= iseries_probe,
-	.check_legacy_ioport	= iseries_check_legacy_ioport,
 	.ioremap	= iseries_ioremap,
 	.iounmap	= iseries_iounmap,
 	/* XXX Implement enable_pmcs for iSeries */
--- a/arch/powerpc/platforms/pasemi/setup.c
+++ b/arch/powerpc/platforms/pasemi/setup.c
@@ -101,12 +101,6 @@ void __init pas_setup_arch(void)
 	pasemi_idle_init();
 }
 
-/* No legacy IO on our parts */
-static int pas_check_legacy_ioport(unsigned int baseport)
-{
-	return -ENODEV;
-}
-
 static __init void pas_init_IRQ(void)
 {
 	struct device_node *np;
@@ -237,7 +231,6 @@ define_machine(pas) {
 	.restart		= pas_restart,
 	.get_boot_time		= pas_get_boot_time,
 	.calibrate_decr		= generic_calibrate_decr,
-	.check_legacy_ioport    = pas_check_legacy_ioport,
 	.progress		= pas_progress,
 	.machine_check_exception = pas_machine_check_handler,
 	.pci_irq_fixup		= pas_pci_irq_fixup,
--- a/arch/powerpc/platforms/powermac/setup.c
+++ b/arch/powerpc/platforms/powermac/setup.c
@@ -616,15 +616,6 @@ static void __init pmac_init_early(void)
 #endif
 }
 
-/*
- * pmac has no legacy IO, anything calling this function has to
- * fail or bad things will happen
- */
-static int pmac_check_legacy_ioport(unsigned int baseport)
-{
-	return -ENODEV;
-}
-
 static int __init pmac_declare_of_platform_devices(void)
 {
 	struct device_node *np;
@@ -736,7 +727,6 @@ define_machine(powermac) {
 	.get_rtc_time		= pmac_get_rtc_time,
 	.calibrate_decr		= pmac_calibrate_decr,
 	.feature_call		= pmac_do_feature_call,
-	.check_legacy_ioport	= pmac_check_legacy_ioport,
 	.progress		= udbg_progress,
 #ifdef CONFIG_PPC64
 	.pci_probe_mode		= pmac_pci_probe_mode,
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -334,32 +334,6 @@ static void __init pSeries_init_early(vo
 	DBG(" <- pSeries_init_early()\n");
 }
 
-
-static int pSeries_check_legacy_ioport(unsigned int baseport)
-{
-	struct device_node *np;
-
-#define I8042_DATA_REG	0x60
-#define FDC_BASE	0x3f0
-
-
-	switch(baseport) {
-	case I8042_DATA_REG:
-		np = of_find_node_by_type(NULL, "8042");
-		if (np == NULL)
-			return -ENODEV;
-		of_node_put(np);
-		break;
-	case FDC_BASE:
-		np = of_find_node_by_type(NULL, "fdc");
-		if (np == NULL)
-			return -ENODEV;
-		of_node_put(np);
-		break;
-	}
-	return 0;
-}
-
 /*
  * Called very early, MMU is off, device-tree isn't unflattened
  */
@@ -532,7 +506,6 @@ define_machine(pseries) {
 	.set_rtc_time		= rtas_set_rtc_time,
 	.calibrate_decr		= generic_calibrate_decr,
 	.progress		= rtas_progress,
-	.check_legacy_ioport	= pSeries_check_legacy_ioport,
 	.system_reset_exception = pSeries_system_reset_exception,
 	.machine_check_exception = pSeries_machine_check_exception,
 };
--- a/include/asm-powerpc/io.h
+++ b/include/asm-powerpc/io.h
@@ -11,7 +11,12 @@
 
 /* Check of existence of legacy devices */
 extern int check_legacy_ioport(unsigned long base_port);
-#define PNPBIOS_BASE	0xf000	/* only relevant for PReP */
+#define I8042_DATA_REG	0x60
+#define FDC_BASE	0x3f0
+/* only relevant for PReP */
+#define _PIDXR		0x279
+#define _PNPWRP		0xa79
+#define PNPBIOS_BASE	0xf000
 
 #include <linux/compiler.h>
 #include <asm/page.h>
--- a/include/asm-powerpc/machdep.h
+++ b/include/asm-powerpc/machdep.h
@@ -153,9 +153,6 @@ struct machdep_calls {
 	 */
 	long	 	(*feature_call)(unsigned int feature, ...);
 
-	/* Check availability of legacy devices like i8042 */
-	int 		(*check_legacy_ioport)(unsigned int baseport);
-
 	/* Get legacy PCI/IDE interrupt mapping */ 
 	int		(*pci_get_legacy_ide_irq)(struct pci_dev *dev, int channel);
 	

^ permalink raw reply

* Re: [PATCH][RFC] PCMCIA support for 8xx using platform devices
From: Christoph Hellwig @ 2007-04-23  7:59 UTC (permalink / raw)
  To: Vitaly Bordug; +Cc: linuxppc-dev, linux-pcmcia, lkml, Arnd Bergmann
In-Reply-To: <20070423101427.3a1d4983@localhost.localdomain>

On Mon, Apr 23, 2007 at 10:14:27AM +0400, Vitaly Bordug wrote:
> On Sun, 22 Apr 2007 23:49:41 +0200
> Arnd Bergmann wrote:
> 
> > On Sunday 22 April 2007, Vitaly Bordug wrote:
> > > This utilizes PCMCIA on mpc885ads and mpc866ads from arch/powerpc.
> > > In the new approach, direct IMMR accesses from within drivers/ were
> > > totally eliminated, that requires hardware_enable,
> > > hardware_disable, voltage_set board-specific functions to be moved
> > > over to BSP code section (arch/powerpc/platforms/8xx in 885 case).
> > > There is just no way to have both arch/ppc and arch/powerpc
> > > approaches to work simultaneously because of that.  
> > 
> > Maybe I'm missing a key issue here, but what's the point of adding
> > more platform_devices for stuff that is already in the device tree?
> > Shouldn't this be made an of_platform_driver instead so you can
> > use the existing of_device directly?
> > 
> Was thinking of it but platform_device is better for migration purposes. Hence,
> assuming somebody would want to have pcmcia working not bothering to add whole arch/powerpc support,
> it can be accomplished quickly.

That's a horrible argument.  Please do it properly, and let arch/ppc die
as it should.  We shouldn't be adding anything to it anymore anyway.

^ permalink raw reply

* Re: [PATCH] Start split out of common open firmware code
From: Stephen Rothwell @ 2007-04-23  7:43 UTC (permalink / raw)
  To: Segher Boessenkool; +Cc: paulus, David Miller, linuxppc-dev
In-Reply-To: <17cfcd2e089f7154354fe6c4c1cadf3c@kernel.crashing.org>

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

On Thu, 12 Apr 2007 09:00:45 +0200 Segher Boessenkool <segher@kernel.crashing.org> wrote:
>
> drivers/ is the wrong place to put this IMHO.  Why not
> use kernel/openfirmware/*.[ch] ?

We have drivers/acpi as a precedent ...

--
Cheers,
Stephen Rothwell                    sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply

* Re: [PATCH][RFC] PCMCIA support for 8xx using platform devices
From: Vitaly Bordug @ 2007-04-23  6:14 UTC (permalink / raw)
  To: Arnd Bergmann; +Cc: linuxppc-dev, linux-pcmcia, lkml
In-Reply-To: <200704222349.42368.arnd@arndb.de>

On Sun, 22 Apr 2007 23:49:41 +0200
Arnd Bergmann wrote:

> On Sunday 22 April 2007, Vitaly Bordug wrote:
> > This utilizes PCMCIA on mpc885ads and mpc866ads from arch/powerpc.
> > In the new approach, direct IMMR accesses from within drivers/ were
> > totally eliminated, that requires hardware_enable,
> > hardware_disable, voltage_set board-specific functions to be moved
> > over to BSP code section (arch/powerpc/platforms/8xx in 885 case).
> > There is just no way to have both arch/ppc and arch/powerpc
> > approaches to work simultaneously because of that.  
> 
> Maybe I'm missing a key issue here, but what's the point of adding
> more platform_devices for stuff that is already in the device tree?
> Shouldn't this be made an of_platform_driver instead so you can
> use the existing of_device directly?
> 
Was thinking of it but platform_device is better for migration purposes. Hence,
assuming somebody would want to have pcmcia working not bothering to add whole arch/powerpc support,
it can be accomplished quickly. OTOH, further change from pd to of_device is not hard as well. So far, most ppc stuff (if not all) still existing both in ppc/ and powerpc/ paths, and to keep consistency platform_devices are used here and there. So, with pd approach arch/ppc/ boards are encouraged to get source device/driver bus ready, hereby simplifying transition to of_device later.

With current bootwrapper activities it may happen sooner, but there are many places in kernel nobody want to move for almost zero value..



-- 
Sincerely, Vitaly

^ permalink raw reply

* Re: mpc5200 linux 2.4 wakeup interrupt problem
From: Domen Puncer @ 2007-04-23  6:27 UTC (permalink / raw)
  To: RonLee; +Cc: linuxppc-embedded
In-Reply-To: <10111122.post@talk.nabble.com>

On 20/04/07 15:07 -0700, RonLee wrote:
> 
> Hello,
>  
> I am running linux on a mpc5200 chip and Im having problems with the
> mpc5200's simple and wakeup interrupts.  The version of Linux I am starting
> with is linuxppc_2_4_devel_1_0_0 from Denx.  Modifications have been made to
> the kernel, but none for enabling the wakeup register set and/or the wakeup
> interrupts.
>  
> Does a patch exist to enable this behavior?  Can anyone point me in the
> right direction if I would like to enable the wakeup interrupts myself?
>  
> I noticed the behavior when attempting to write a device driver to interface
> with the psc1_4 pin on the mpc5200 chip.  I am able to get the chip to
> generate interrupts, but when the interrupts occur I get the following error
> message in /proc/kmsg "Unhandled interrupt c, disabled".  After getting this
> error, I installed an interrupt handler on IRQ 12 (hex c).  This caused the
> kernel to lock up.

Maybe you forgot to acknowledge the IRQ (and so it always reenters your
handler). For gpio wakeup interrupts see wkup_istat (MBAR+0xc24).

HTH

	Domen
>  
> Thanks for any help,
> -Ron

^ permalink raw reply

* Re: [PATCH 6/7] MPIC MSI allocator
From: Milton Miller @ 2007-04-23  6:20 UTC (permalink / raw)
  To: michael; +Cc: linuxppc-dev, linux-pci
In-Reply-To: <1177301062.3889.27.camel@concordia.ozlabs.ibm.com>


On Apr 22, 2007, at 11:04 PM, Michael Ellerman wrote:

> On Sat, 2007-04-21 at 18:17 -0500, Milton Miller wrote:
>> On Apr 19, 2007, Michael Ellerman wrote:
>>> To support MSI on MPIC we need a way to reserve and allocate hardware
>>> irq
>>> numbers, this patch implements an allocator for that.

>>> +	/* Reserve source numbers we know are reserved in the HW */
>>> +	for (i = 0;   i < 8;   i++) __mpic_msi_reserve_hwirq(mpic, i);
>>> +	for (i = 42;  i < 46;  i++) __mpic_msi_reserve_hwirq(mpic, i);
>>> +	for (i = 100; i < 105; i++) __mpic_msi_reserve_hwirq(mpic, i);
>>
>> More lines please.
>>
>>> +#else
>>> +static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic) { return 
>>> -1;
>>> }
>>
>> and here.
>
> Blank lines aren't free you know!

I didn't ask for any blank ones, so you can keep the bill. :-)

>>
>>> +	if (len % 8 != 0) {

Here you use 8 as the size of the element to process.

>>> +		printk(KERN_WARNING "mpic: Malformed msi-available-ranges "
>>> +		       "property on %s\n", mpic->of_node->full_name);
>>> +		return -EINVAL;
>>> +	}
>>> +
>>> +	bitmap_allocate_region(mpic->hwirq_bitmap, 0,
>>> +			       fls(mpic->irq_count) - 1);
>>> +
>>> +	/* Format is: (<u32 start> <u32 count>)+ */
>>> +	len /= sizeof(u32);

Here you hide a divide by 4 and follow with divide by 2.

>>> +	for (i = 0; i < len / 2; i++, p += 2)
>>
>> how about just dividing by the calculated 8 above?  or use
>> count = len / 8.
>
> I'm not sure I follow. If you can think of a clearer way I'm all ears,
> or are you just trying to save a divide :)

I'm saying that it doesn't make sense to do both of the above.
I'd move the comment on being pairs of cells to before the
if () EINVAL then follow immediately with the divide.  If you
think that hides length being adjusted then I was optionally
suggesting making a new variable count to use in the for loop.

Actually, since i isn't used in the loop you could just
increment i by 8 while < len, and save both divides.

milton

^ permalink raw reply

* Re: [PATCH 2/7] Powerpc MSI infrastructure
From: Michael Ellerman @ 2007-04-23  4:28 UTC (permalink / raw)
  To: Milton Miller; +Cc: linuxppc-dev, linux-pci
In-Reply-To: <5978bcffcf3b9348ebd4349ba8c2730a@bga.com>

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

On Sat, 2007-04-21 at 18:15 -0500, Milton Miller wrote:
> On Apr 19, 2007, Michael Ellerman wrote:
> > This patch provides the architecture specific hooks to support MSI on
> > powerpc. We implement the newly added arch_setup_msi_irqs() and
> > arch_teardown_msi_irqs(), and then delegate to ppc_md routines.
> >
> 
> > Index: msi-new/arch/powerpc/kernel/msi.c
> > ===================================================================
> > --- /dev/null
> > +++ msi-new/arch/powerpc/kernel/msi.c
> > @@ -0,0 +1,38 @@
> > +/*
> > + * Copyright 2006-2007, Michael Ellerman, 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.
> > + */
> > +
> > +#include <linux/kernel.h>
> > +#include <linux/msi.h>
> > +
> > +#include <asm/machdep.h>
> > +
> > +int arch_msi_check_device(struct pci_dev* dev, int nvec, int type)
> > +{
> > +	if (ppc_md.msi_check_device) {
> > +		pr_debug("msi: Using platform check routine.\n");
> > +		return ppc_md.msi_check_device(dev, nvec, type);
> > +	}
> > +
> > +	if (!ppc_md.setup_msi_irqs || !ppc_md.teardown_msi_irqs) {
> > +		pr_debug("msi: Platform doesn't provide MSI callbacks.\n");
> > +		return -ENOSYS;
> > +	}
> 
> Should we not do this check first?  Or do you expect some platform
> to fill out these hooks in the check call above?  Othewise we will
> branch to function pointer NULL.

Not really. More a case of if you provide check then you'd better get
your act together and provide the others. I'll rearrange it to be safer.

> 
> > +
> > +        return 0;
> > +}
> > +
> > +int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
> > +{
> > +	return ppc_md.setup_msi_irqs(dev, nvec, type);
> > +}
> > +
> > +void arch_teardown_msi_irqs(struct pci_dev *dev)
> > +{
> > +	return ppc_md.teardown_msi_irqs(dev);
> > +}
> 
> 
> > Index: msi-new/arch/powerpc/kernel/Makefile
> > ===================================================================
> > --- msi-new.orig/arch/powerpc/kernel/Makefile
> > +++ msi-new/arch/powerpc/kernel/Makefile
> 
> > +obj-$(CONFIG_PCI_MSI)		+= msi.o
> 
> 
> Do we really need a new file for these simple hooks?  It doesn't look
> like anthing else is going to be added to it either.   I'd prefer to
> just do an ifdef in pci.c.   Hmmm, we don't seem to have that, but
> these are soo small I'd include machdep.h and put them inline in
> asm-powerpc/pci.h.

I'd rather leave it as is. We can't have them inline, because they're
already defined in drivers/pci/msi.c. And having the CONFIG logic in the
Makefile is cleaner than #ifdef goo. Also it might grow one day, if we
make the hooks per pci_dev or per bus rather than in ppc_md.

cheers

-- 
Michael Ellerman
OzLabs, IBM Australia Development Lab

wwweb: http://michael.ellerman.id.au
phone: +61 2 6212 1183 (tie line 70 21183)

We do not inherit the earth from our ancestors,
we borrow it from our children. - S.M.A.R.T Person

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

^ permalink raw reply

* Re: [PATCH 7/7] MPIC MSI backend
From: Michael Ellerman @ 2007-04-23  4:24 UTC (permalink / raw)
  To: Olof Johansson; +Cc: linuxppc-dev, linux-pci, Milton Miller
In-Reply-To: <20070422193017.GA27048@lixom.net>

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

On Sun, 2007-04-22 at 14:30 -0500, Olof Johansson wrote:
> On Sun, Apr 22, 2007 at 09:06:15AM +0200, Segher Boessenkool wrote:
> 
> > mpic_htmsi deals with MSIs that come in over hypertransport
> > to the MPIC on CPC925/CPC945; this has nothing to
> > do with HT APICs.
> 
> Maybe it should be named mpic_cpc9x5msi instead?

Yeah, seems fair enough.

cheers

-- 
Michael Ellerman
OzLabs, IBM Australia Development Lab

wwweb: http://michael.ellerman.id.au
phone: +61 2 6212 1183 (tie line 70 21183)

We do not inherit the earth from our ancestors,
we borrow it from our children. - S.M.A.R.T Person

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

^ permalink raw reply

* Re: [PATCH 5/7] Enable MSI mappings for MPIC
From: Michael Ellerman @ 2007-04-23  4:10 UTC (permalink / raw)
  To: Milton Miller; +Cc: linux-pci, linuxppc-dev
In-Reply-To: <b876ed7a2f13ad05a04f0aac3b364c9a@bga.com>

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

On Sat, 2007-04-21 at 23:53 -0500, Milton Miller wrote:
> On Apr 21, 2007, at 7:06 PM, Benjamin Herrenschmidt wrote:
> >> This is just begging to be written in terms of
> >> pci_bus_find_ht_capability.  Well,
> >> we have pci_bus_find_capability, and pci_find_ht_capability, I'm sure
> >> we could
> >> create that.   It also means this and the other nearby functions want
> >> to be
> >> written in terms of a struct pci_bus and config accessors.
> >
> > A lot of that code has to run way before the PCI config stuff is even
> > useable and certainly before the PCI layer data structures have been
> > created.... Sucks but that's how it is for now. We might be able to
> > tweak and delay init of the APICs etc... but I don't think I can be
> > bothered for now as it's a bit of a corner case.
> >
> 
> I wasn't proposing to make the code wait until the pci layer had
> discovered the ht bridge.  Rather I was thinking that a struct
> pci_bus instance created for the purpose with only ops and maybe
> sysdata initialized.  The purpose being to reuse the generic code.

That'd be nice in a way. Although there'd be scope for breakage from
time to time as PCI changes get made without taking into account this
special case.

> Maybe I'll have to code something up.   Perhaps when I'm a bit
> less overloaded.

All yours :)

cheers

-- 
Michael Ellerman
OzLabs, IBM Australia Development Lab

wwweb: http://michael.ellerman.id.au
phone: +61 2 6212 1183 (tie line 70 21183)

We do not inherit the earth from our ancestors,
we borrow it from our children. - S.M.A.R.T Person

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

^ permalink raw reply

* Re: [PATCH 6/7] MPIC MSI allocator
From: Michael Ellerman @ 2007-04-23  4:04 UTC (permalink / raw)
  To: Milton Miller; +Cc: linuxppc-dev, linux-pci
In-Reply-To: <5f69d29368a24aad95648b40e0dfc07e@bga.com>

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

On Sat, 2007-04-21 at 18:17 -0500, Milton Miller wrote:
> On Apr 19, 2007, Michael Ellerman wrote:
> > To support MSI on MPIC we need a way to reserve and allocate hardware 
> > irq
> > numbers, this patch implements an allocator for that.
> 
> > Index: msi-new/arch/powerpc/sysdev/mpic_msi.c
> > ===================================================================
> > --- /dev/null
> > +++ msi-new/arch/powerpc/sysdev/mpic_msi.c
> ...
> > +irq_hw_number_t mpic_msi_alloc_hwirqs(struct mpic *mpic, int num)
> > +{
> > +	unsigned long flags;
> > +	int offset, order = fls(num) - 1;
> 
> get_count_order would be more clear.  Also it has
> a correction factor.  (Applies several places).

I was hoping someone would point out something better than fls, fixed.

> > +#ifdef CONFIG_MPIC_BROKEN_U3
> > +static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic)
> > +{
> > +	irq_hw_number_t hwirq;
> > +	struct irq_host_ops *ops = mpic->irqhost->ops;
> > +	struct device_node *np;
> > +	int flags, index, i;
> > +	struct of_irq oirq;
> > +
> > +	pr_debug("mpic: found U3, guessing msi allocator setup\n");
> > +
> > +	/* Reserve source numbers we know are reserved in the HW */
> > +	for (i = 0;   i < 8;   i++) __mpic_msi_reserve_hwirq(mpic, i);
> > +	for (i = 42;  i < 46;  i++) __mpic_msi_reserve_hwirq(mpic, i);
> > +	for (i = 100; i < 105; i++) __mpic_msi_reserve_hwirq(mpic, i);
> 
> More lines please.
> 
> > +#else
> > +static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic) { return -1; 
> > }
> 
> and here.

Blank lines aren't free you know!

> 
> > +	if (len % 8 != 0) {
> > +		printk(KERN_WARNING "mpic: Malformed msi-available-ranges "
> > +		       "property on %s\n", mpic->of_node->full_name);
> > +		return -EINVAL;
> > +	}
> > +
> > +	bitmap_allocate_region(mpic->hwirq_bitmap, 0,
> > +			       fls(mpic->irq_count) - 1);
> > +
> > +	/* Format is: (<u32 start> <u32 count>)+ */
> > +	len /= sizeof(u32);
> > +	for (i = 0; i < len / 2; i++, p += 2)
> 
> how about just dividing by the calculated 8 above?  or use
> count = len / 8.

I'm not sure I follow. If you can think of a clearer way I'm all ears,
or are you just trying to save a divide :)

> 
> > +		mpic_msi_free_hwirqs(mpic, *p, *(p + 1));
> > +
> > +	return 0;
> > +}
> > +
> > +int mpic_msi_init_allocator(struct mpic *mpic)
> > +{
> > +	int rc, size;
> > +
> > +	BUG_ON(mpic->hwirq_bitmap);
> > +	spin_lock_init(&mpic->bitmap_lock);
> > +
> > +	size = mpic->irq_count / 8;
> > +	pr_debug("mpic: allocator bitmap size is 0x%x bytes\n", size);
> 
> BITS_TO_LONGS() * sizeof(long).   We need to round up to longs to
> use bitmask_*, especially being a big endian architecture.

Eww, sorry that's horrible. Fixed.

cheers

-- 
Michael Ellerman
OzLabs, IBM Australia Development Lab

wwweb: http://michael.ellerman.id.au
phone: +61 2 6212 1183 (tie line 70 21183)

We do not inherit the earth from our ancestors,
we borrow it from our children. - S.M.A.R.T Person

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

^ permalink raw reply

* Re: [PATCH 6/7] MPIC MSI allocator
From: Michael Ellerman @ 2007-04-23  3:53 UTC (permalink / raw)
  To: Olof Johansson; +Cc: linuxppc-dev, linux-pci
In-Reply-To: <20070423035025.GA29839@lixom.net>

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

On Sun, 2007-04-22 at 22:50 -0500, Olof Johansson wrote:
> On Thu, Apr 19, 2007 at 05:35:28PM +1000, Michael Ellerman wrote:
> > To support MSI on MPIC we need a way to reserve and allocate hardware irq
> > numbers, this patch implements an allocator for that.
> > 
> > New firmware platforms must define a "msi-available-ranges" property on their
> > MPIC node for MSI to work. For BROKEN_U3 we do a best-guess setup.
> 
> It's time to rename BROKEN_U3. It used to be the config option to enable
> a few workarounds, but now it's used to select whenever there's a U3 in
> the system. Care to do it in the scope of this patch set?

Yeah it's pretty ugly. I guess I can do it. Got an idea for a better
name? MPIC_HT?

> > Index: msi-new/include/asm-powerpc/mpic.h
> > ===================================================================
> > --- msi-new.orig/include/asm-powerpc/mpic.h
> > +++ msi-new/include/asm-powerpc/mpic.h
> > @@ -292,6 +292,11 @@ struct mpic
> >  	u32			*hw_set;
> >  #endif
> >  
> > +#ifdef CONFIG_PCI_MSI
> > +	spinlock_t		bitmap_lock;
> > +	unsigned long		*hwirq_bitmap;
> > +#endif
> 
> Besides the #ifdef there's nothing in the name that indicates that it's
> used for msi. Better names could be useful.

True. Although, it doesn't necessarily have anything to do with MSI,
it's just a bitmap of hwirqs that are used/free. As it happens we only
need it when we're doing MSI though.

> 
> > @@ -440,5 +445,11 @@ void mpic_set_clk_ratio(struct mpic *mpi
> >  /* Enable/Disable EPIC serial interrupt mode */
> >  void mpic_set_serial_int(struct mpic *mpic, int enable);
> >  
> > +#ifdef CONFIG_PCI_MSI
> > +extern int mpic_msi_init_allocator(struct mpic *mpic);
> > +extern irq_hw_number_t mpic_msi_alloc_hwirqs(struct mpic *mpic, int num);
> > +extern void mpic_msi_free_hwirqs(struct mpic *mpic, int offset, int num);
> > +#endif
> 
> These should go in mpic.h instead.

Yep.

cheers

-- 
Michael Ellerman
OzLabs, IBM Australia Development Lab

wwweb: http://michael.ellerman.id.au
phone: +61 2 6212 1183 (tie line 70 21183)

We do not inherit the earth from our ancestors,
we borrow it from our children. - S.M.A.R.T Person

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

^ permalink raw reply

* Re: [PATCH 7/7] MPIC MSI backend
From: Michael Ellerman @ 2007-04-23  3:45 UTC (permalink / raw)
  To: Milton Miller; +Cc: linuxppc-dev, linux-pci
In-Reply-To: <e4520bd4be50f2884003a9421863627c@bga.com>

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

On Sat, 2007-04-21 at 18:17 -0500, Milton Miller wrote:
> On Apr 19, 2007, Michael Ellerman wrote:
> > MPIC MSI backend. Based on code from Segher, heavily hacked by me.
> > Renamed to mpic_htmsi, as it only deals with MSI over Hypertransport.
> ...
> > Index: msi-new/arch/powerpc/sysdev/Makefile
> > ===================================================================
> > --- msi-new.orig/arch/powerpc/sysdev/Makefile
> > +++ msi-new/arch/powerpc/sysdev/Makefile
> > @@ -4,6 +4,7 @@ endif
> >
> >  mpic-obj-y			:= mpic.o
> >  mpic-obj-$(CONFIG_PCI_MSI)	+= mpic_msi.o
> > +mpic-obj-$(CONFIG_PCI_MSI)	+= mpic_htmsi.o
> >  obj-$(CONFIG_MPIC)		+= $(mpic-obj-y)
> 
> This is overly complicated.  You aren't going to be making this
> a seperate link object anyways.   It should end up somehting like
> 
> mpic-msi-$(CONFIG_PCI_MSI)	:= mpic_msi.o mpic_htmsi.o
> obj-$(CONFIG_MPIC)		+= mpic.o $(mpic-msi-y)

Fixed.

> > -static void mpic_unmask_irq(unsigned int irq)
> > +void mpic_unmask_irq(unsigned int irq)
> ...
> > -static void mpic_mask_irq(unsigned int irq)
> > +void mpic_mask_irq(unsigned int irq)
> ...
> Ok mpic.c is big enough already.

Yeah I tried it the other way, but it was messy.

> > Index: msi-new/arch/powerpc/sysdev/mpic.h
> > ===================================================================
> > --- msi-new.orig/arch/powerpc/sysdev/mpic.h
> > +++ msi-new/arch/powerpc/sysdev/mpic.h
> > @@ -11,14 +11,23 @@
> >   *
> >   */
> >
> > +#include <linux/irq.h>
> > +
> 
> Why do you need this now?   You already had uses of irq_ht_umber_t
> and struct mpic.  Unless this should be in the earlier patch?

Cruft, removed.

> >  #ifdef CONFIG_PCI_MSI
> >  extern void mpic_msi_reserve_hwirq(struct mpic *mpic, irq_hw_number_t 
> > hwirq);
> > +extern int mpic_htmsi_init(struct mpic *mpic);
> >  #else
> >  static inline void mpic_msi_reserve_hwirq(struct mpic *mpic,
> >  					  irq_hw_number_t hwirq)
> >  {
> >  	return;
> >  }
> > +static inline int mpic_htmsi_init(struct mpic *mpic) { return -1; }
> 
> more lines please

OK.

> > +int mpic_htmsi_init(struct mpic *mpic)
> > +{
> > +	int rc;
> > +
> > +	rc = mpic_msi_init_allocator(mpic);
> > +	if (rc) {
> > +		pr_debug("htmsi: Error allocating bitmap!\n");
> > +		return rc;
> > +	}
> > +
> > +	pr_debug("htmsi: Registering MPIC MSI callbacks.\n");
> > +
> > +	BUG_ON(msi_mpic);
> > +	msi_mpic = mpic;
> > +
> > +	ppc_md.setup_msi_irqs = htmsi_setup_msi_irqs;
> > +	ppc_md.teardown_msi_irqs = htmsi_teardown_msi_irqs;
> > +	ppc_md.msi_check_device = htmsi_msi_check_device;
> 
> Unlike the rtas patch, this one didn't advertise it was
> going to set the arch hooks unconditionally.

Yeah OK, fixed.

cheers

-- 
Michael Ellerman
OzLabs, IBM Australia Development Lab

wwweb: http://michael.ellerman.id.au
phone: +61 2 6212 1183 (tie line 70 21183)

We do not inherit the earth from our ancestors,
we borrow it from our children. - S.M.A.R.T Person

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

^ permalink raw reply

* Re: [PATCH 6/7] MPIC MSI allocator
From: Olof Johansson @ 2007-04-23  3:50 UTC (permalink / raw)
  To: Michael Ellerman; +Cc: linuxppc-dev, linux-pci
In-Reply-To: <20070419073555.D2C3EDDEFD@ozlabs.org>

On Thu, Apr 19, 2007 at 05:35:28PM +1000, Michael Ellerman wrote:
> To support MSI on MPIC we need a way to reserve and allocate hardware irq
> numbers, this patch implements an allocator for that.
> 
> New firmware platforms must define a "msi-available-ranges" property on their
> MPIC node for MSI to work. For BROKEN_U3 we do a best-guess setup.

It's time to rename BROKEN_U3. It used to be the config option to enable
a few workarounds, but now it's used to select whenever there's a U3 in
the system. Care to do it in the scope of this patch set?

> Index: msi-new/include/asm-powerpc/mpic.h
> ===================================================================
> --- msi-new.orig/include/asm-powerpc/mpic.h
> +++ msi-new/include/asm-powerpc/mpic.h
> @@ -292,6 +292,11 @@ struct mpic
>  	u32			*hw_set;
>  #endif
>  
> +#ifdef CONFIG_PCI_MSI
> +	spinlock_t		bitmap_lock;
> +	unsigned long		*hwirq_bitmap;
> +#endif

Besides the #ifdef there's nothing in the name that indicates that it's
used for msi. Better names could be useful.

> @@ -440,5 +445,11 @@ void mpic_set_clk_ratio(struct mpic *mpi
>  /* Enable/Disable EPIC serial interrupt mode */
>  void mpic_set_serial_int(struct mpic *mpic, int enable);
>  
> +#ifdef CONFIG_PCI_MSI
> +extern int mpic_msi_init_allocator(struct mpic *mpic);
> +extern irq_hw_number_t mpic_msi_alloc_hwirqs(struct mpic *mpic, int num);
> +extern void mpic_msi_free_hwirqs(struct mpic *mpic, int offset, int num);
> +#endif

These should go in mpic.h instead.


-Olof

^ permalink raw reply

* Re: where is the sk_buff allocation
From: Olof Johansson @ 2007-04-23  3:02 UTC (permalink / raw)
  To: Ming Liu; +Cc: linuxppc-embedded
In-Reply-To: <BAY138-F10BA8CB23D5BDA5802D8F3B2540@phx.gbl>

On Sun, Apr 22, 2007 at 06:14:18PM +0000, Ming Liu wrote:
> Dear all,
> I am reading and understanding the Xilinx Temac device driver. I know that 
> hard_start_xmit() is used to transmit the packets. In this function, a 
> pointer skb which points to a sk_buff needs to be passed to show the 
> location of the socket buffer. But where is that sk_buff allocation 
> sentence, and how its address (skb) is passed to the hard_start_xmit() 
> function? I want to change the address of the sk_buff in my system and try 
> to fit this socket buffer in a pre-defined location.

The sk_buff is allocated by the network stack and passed down to the
driver.  If you need the buffer to be located in a specific location
before transmitting it, then you'll have to copy it there by hand.


-Olof

^ permalink raw reply

* Re: [PATCH][RFC][POWERPC] i2c: adds support for i2c bus on 8xx
From: Olof Johansson @ 2007-04-23  2:57 UTC (permalink / raw)
  To: Vitaly Bordug; +Cc: Jean Delvare, linuxppc-dev@ozlabs.org, lkml
In-Reply-To: <20070420082714.4f10f186@localhost.localdomain>

On Fri, Apr 20, 2007 at 08:27:14AM +0400, Vitaly Bordug wrote:

> diff --git a/arch/powerpc/platforms/8xx/mpc885ads_setup.c b/arch/powerpc/platforms/8xx/mpc885ads_setup.c
> index 9bd81c7..d32e066 100644
> --- a/arch/powerpc/platforms/8xx/mpc885ads_setup.c
> +++ b/arch/powerpc/platforms/8xx/mpc885ads_setup.c
> @@ -51,6 +51,7 @@ static void init_smc1_uart_ioports(struc
>  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);
> +static void init_i2c_ioports(void);
>  
>  void __init mpc885ads_board_setup(void)
>  {
> @@ -120,6 +121,10 @@ #endif
>  #ifdef CONFIG_8XX_SIR
>  	init_irda_ioports();
>  #endif
> +
> +#ifdef CONFIG_I2C_RPXLITE
> +	init_i2c_ioports();
> +#endif

Does it hurt to always do it, even when the driver is not enabled? THat'd
do away with an ifdef.

Also, if you move the static function up, you don't need a prototype. That
goes for other stuff in this file too.

>  }
>  
>  
> @@ -361,6 +366,15 @@ static void init_irda_ioports()
>  	immr_unmap(cp);
>  }
>  
> +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);
> +}

Looks like you moved this out of the driver and into the platform
code. What happens to other platforms where it's used?

> +
>  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 419b688..7ecd537 100644
> --- a/arch/powerpc/sysdev/fsl_soc.c
> +++ b/arch/powerpc/sysdev/fsl_soc.c
> @@ -331,7 +331,7 @@ static int __init fsl_i2c_of_init(void)
>  	for (np = NULL, i = 0;
>  	     (np = of_find_compatible_node(np, "i2c", "fsl-i2c")) != NULL;
>  	     i++) {
> -		struct resource r[2];
> +		struct resource r[3];

Why? No code that uses it has been changed. Is it a bugfix?

>  		struct fsl_i2c_platform_data i2c_data;
>  		const unsigned char *flags = NULL;
>  
> @@ -1215,4 +1215,63 @@ err:
>  
>  arch_initcall(fs_irda_of_init);
>  
> +static const char *i2c_regs = "regs";
> +static const char *i2c_pram = "pram";
> +static const char *i2c_irq = "interrupt";
> +
> +static int __init fsl_i2c_cpm_of_init(void)
> +{
> +	struct device_node *np;
> +	unsigned int i;
> +	struct platform_device *i2c_dev;
> +	int ret;
> +
> +	for (np = NULL, i = 0;
> +	     (np = of_find_compatible_node(np, "i2c", "fsl-i2c-cpm")) != NULL;
> +	     i++) {
> +		struct resource r[3];
> +		struct fsl_i2c_platform_data i2c_data;
> +
> +		memset(&r, 0, sizeof(r));
> +		memset(&i2c_data, 0, sizeof(i2c_data));
> +
> +		ret = of_address_to_resource(np, 0, &r[0]);
> +		if (ret)
> +			goto err;
> +		r[0].name = i2c_regs;
> +
> +		ret = of_address_to_resource(np, 1, &r[1]);
> +		if (ret)
> +			goto err;
> +		r[1].name = i2c_pram;
> +
> +		r[2].start = r[2].end = irq_of_parse_and_map(np, 0);
> +		r[2].flags = IORESOURCE_IRQ;
> +		r[2].name = i2c_irq;
> +
> +		i2c_dev = platform_device_register_simple("fsl-i2c-cpm", i, &r[0], 3);
> +		if (IS_ERR(i2c_dev)) {
> +			ret = PTR_ERR(i2c_dev);
> +			goto err;
> +		}
> +
> +		ret =
> +		    platform_device_add_data(i2c_dev, &i2c_data,
> +					     sizeof(struct
> +						    fsl_i2c_platform_data));
> +		if (ret)
> +			goto unreg;
> +	}
> +
> +	return 0;
> +
> +unreg:
> +	platform_device_unregister(i2c_dev);
> +err:
> +	return ret;
> +}
> +
> +arch_initcall(fsl_i2c_cpm_of_init);

This could all be done with an of_platform driver instead, and avoid the above.
(Someone else already suggested that I believe).

>  #endif /* CONFIG_8xx */
> diff --git a/drivers/i2c/algos/Kconfig b/drivers/i2c/algos/Kconfig
> index 5889907..7d7fb87 100644
> --- a/drivers/i2c/algos/Kconfig
> +++ b/drivers/i2c/algos/Kconfig
> @@ -37,6 +37,8 @@ config I2C_ALGOPCA
>  config I2C_ALGO8XX
>  	tristate "MPC8xx CPM I2C interface"
>  	depends on 8xx
> +	help
> +	  8xx I2C Algorithm
>  
>  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-bi
>  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..b1f414a
> --- /dev/null
> +++ b/drivers/i2c/algos/i2c-algo-8xx.c
> @@ -0,0 +1,622 @@
> +/*
> + * 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)
> + */
> +
> +
> +/* $Id: i2c-algo-8xx.c,v 1.15 2004/11/20 08:02:24 khali Exp $ */
> +
> +#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>
> +
> +#define CPM_MAX_READ	513
> +#undef	I2C_CHIP_ERRATA /* Try ot define this if you have an older CPU(earlier than rev D4) */
> +
> +static wait_queue_head_t iic_wait;
> +static ushort r_tbase, r_rbase;
> +
> +int cpm_debug = 0;
> +int cpm_scan = 0;
> +
> +static irqreturn_t cpm_iic_interrupt(int irq, void *dev_id)
> +{
> +	i2c8xx_t *i2c = (i2c8xx_t *) dev_id;
> +	if (cpm_debug > 1)
> +		printk("cpm_iic_interrupt(dev_id=%p)\n", 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 void cpm_iic_init(struct i2c_algo_8xx_data *cpm)
> +{
> +	iic_t *iip = cpm->iip;
> +	i2c8xx_t *i2c = cpm->i2c;
> +	unsigned char brg;
> +
> +	if (cpm_debug)
> +		printk(KERN_DEBUG "cpm_iic_init()\n");
> +
> +	/* 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) {
> +		printk("iip %p, dp_addr 0x%x\n", cpm->iip, cpm->dp_addr);
> +		printk("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;
> +		u16 v = mk_cr_cmd(CPM_CR_CH_I2C, CPM_CR_INIT_TRX) | CPM_CR_FLG;
> +
> +		out_be16(&cp->cp_cpcr, v);
> +		while (in_be16(&cp->cp_cpcr) & CPM_CR_FLG) ;
> +	} 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 = (unsigned char)(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);
> +
> +	init_waitqueue_head(&iic_wait);
> +
> +	/* Install interrupt handler.
> +	 */
> +	if (cpm_debug) {
> +		printk("%s[%d] Install ISR for IRQ %d\n",
> +		       __func__, __LINE__, CPMVEC_I2C);
> +	}
> +	request_irq(cpm->irq, cpm_iic_interrupt, 0, "8xx_i2c", i2c);
> +}
> +
> +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_algo_8xx_data *cpm)
> +{
> +	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);
> +		while (in_be16(&cp->cp_cpcr) & CPM_CR_FLG) ;
> +	}
> +	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_algo_8xx_data *cpm, u_char abyte, char *buf, int count)
> +{
> +	iic_t *iip = cpm->iip;
> +	i2c8xx_t *i2c = cpm->i2c;
> +	cbd_t *tbdf, *rbdf;
> +	u_char *tb;
> +	unsigned long tmo;
> +	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)
> +		printk("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;
> +
> +	if (count > 16) {
> +		/* 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);
> +	} else {		/* busy wait for small transfers, its faster */
> +		out_8(&i2c->i2c_i2cmr, 0x00);	/* Disable I2C 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 */
> +
> +		tmo = jiffies + 1 * HZ;
> +		while (!(in_8(&i2c->i2c_i2cer) & 0x11 || time_after(jiffies, tmo))) ;/* Busy wait, with a timeout */
> +	}
> +
> +	if ( res < 0) {
> +		force_close(cpm);
> +		if (cpm_debug)
> +			printk("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) {
> +		printk("tx sc %04x, rx sc %04x\n", tbdf->cbd_sc, rbdf->cbd_sc);
> +	}
> +
> +	if (tbdf->cbd_sc & BD_SC_READY) {
> +		printk("IIC read; complete but tbuf ready\n");
> +		force_close(cpm);
> +		printk("tx sc %04x, rx sc %04x\n", tbdf->cbd_sc, rbdf->cbd_sc);
> +	}
> +
> +	if (tbdf->cbd_sc & BD_SC_NAK) {
> +		if (cpm_debug)
> +			printk("IIC read; no ack\n");
> +		return -EREMOTEIO;
> +	}
> +
> +	if (rbdf->cbd_sc & BD_SC_EMPTY) {
> +		/* force_close(cpm); */
> +		if (cpm_debug) {
> +			printk("IIC read; complete but rbuf empty\n");
> +			printk("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)
> +			printk("IIC read; Overrun\n");
> +		return -EREMOTEIO;;
> +	}
> +
> +	if (cpm_debug)
> +		printk("read %d bytes\n", rbdf->cbd_datlen);
> +
> +	if (rbdf->cbd_datlen < count) {
> +		if (cpm_debug)
> +			printk("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_algo_8xx_data *cpm, u_char abyte, char *buf, int count)
> +{
> +	iic_t *iip = cpm->iip;
> +	i2c8xx_t *i2c = cpm->i2c;
> +	cbd_t *tbdf;
> +	u_char *tb;
> +	unsigned long tmo;
> +	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)
> +		printk("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;
> +
> +	if (count > 16) {
> +		/* 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);
> +	} else {		/* busy wait for small transfers, its faster */
> +		out_8(&i2c->i2c_i2cmr, 0x00);	/* Disable I2C 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 */
> +		tmo = jiffies + 1 * HZ;
> +		while (!(in_8(&i2c->i2c_i2cer) & 0x12 || time_after(jiffies, tmo))) ;/* Busy wait, with a timeout */
> +	}
> +
> +	if ( res < 0) {
> +		force_close(cpm);
> +		if (cpm_debug)
> +			printk("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) {
> +		printk("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)
> +			printk("IIC write; no ack\n");
> +		return 0;
> +	}
> +
> +	if (tbdf->cbd_sc & BD_SC_READY) {
> +		if (cpm_debug)
> +			printk("IIC write; complete but tbuf ready\n");
> +		return 0;
> +	}
> +
> +	return count;
> +}
> +
> +/* See if an IIC address exists..
> + * addr = 7 bit address, unshifted
> + */
> +static int cpm_iic_tryaddress(struct i2c_algo_8xx_data *cpm, int addr)
> +{
> +	iic_t *iip = cpm->iip;
> +	i2c8xx_t *i2c = cpm->i2c;
> +	cbd_t *tbdf, *rbdf;
> +	u_char *tb;
> +	unsigned long len;
> +	int res = 0;
> +
> +	if (cpm_debug > 1)
> +		printk("cpm_iic_tryaddress(cpm=%p,addr=%d)\n", cpm, addr);
> +
> +	/* check for and use a microcode relocation patch */
> +	if (cpm->reloc) {
> +		cpm_reset_iic_params(iip);
> +	}
> +
> +	if (cpm_debug && addr == 0) {
> +		printk("iip %p, dp_addr 0x%x\n", cpm->iip, cpm->dp_addr);
> +		printk("iic_tbase %d, r_tbase %d\n", iip->iic_tbase, r_tbase);
> +	}
> +
> +	tbdf = (cbd_t *) cpm_dpram_addr(iip->iic_tbase);
> +	rbdf = (cbd_t *) cpm_dpram_addr(iip->iic_rbase);
> +
> +	tb = cpm->temp;
> +	tb = (u_char *) (((uint) tb + 15) & ~15);
> +
> +	/* do a simple read */
> +	tb[0] = (addr << 1) | 1;	/* device address (+ read) */
> +	len = 2;
> +
> +	flush_dcache_range((unsigned long)tb, (unsigned long)(tb + 2));
> +
> +	tbdf->cbd_bufaddr = __pa(tb);
> +	tbdf->cbd_datlen = len;
> +	tbdf->cbd_sc = BD_SC_READY | BD_SC_LAST | BD_SC_WRAP | BD_IIC_START;
> +
> +	rbdf->cbd_datlen = 0;
> +	rbdf->cbd_bufaddr = __pa(tb + 2);
> +	rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP | BD_SC_INTRPT;
> +
> +	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 */
> +
> +	if (cpm_debug > 1)
> +		printk("about to sleep\n");
> +
> +	/* wait for IIC transfer */
> +	res = wait_event_interruptible_timeout(iic_wait, 0, 1 * HZ);
> +
> +#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 ( res < 0) {
> +		force_close(cpm);
> +		if (cpm_debug)
> +			printk("IIC tryaddress: timeout!\n");
> +		return -EIO;
> +	}
> +
> +	if (cpm_debug > 1)
> +		printk("back from sleep\n");
> +
> +	if (tbdf->cbd_sc & BD_SC_NAK) {
> +		if (cpm_debug > 1)
> +			printk("IIC try; no ack\n");
> +		return 0;
> +	}
> +
> +	if (tbdf->cbd_sc & BD_SC_READY) {
> +		printk("IIC try; complete but tbuf ready\n");
> +	}
> +
> +	return 1;
> +}
> +
> +static int cpm_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
> +{
> +	struct i2c_algo_8xx_data *cpm = adap->algo_data;
> +	struct i2c_msg *pmsg;
> +	int i, ret;
> +	u_char addr;
> +
> +	for (i = 0; i < num; i++) {
> +		pmsg = &msgs[i];
> +
> +		if (cpm_debug)
> +			printk("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_NOSTART)) {
> +		}
> +		if (pmsg->flags & I2C_M_RD) {
> +			/* read bytes into buffer */
> +			ret = cpm_iic_read(cpm, addr, pmsg->buf, pmsg->len);
> +			if (cpm_debug)
> +				printk("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(cpm, addr, pmsg->buf, pmsg->len);
> +			if (cpm_debug)
> +				printk("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_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR |
> +	    I2C_FUNC_PROTOCOL_MANGLING;
> +}
> +
> +/* -----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)
> +{
> +	struct i2c_algo_8xx_data *cpm = adap->algo_data;
> +	int i;
> +
> +	if (cpm_debug)
> +		printk("i2c-algo-8xx.o: hw routines for %s registered.\n",
> +		       adap->name);
> +
> +	/* register new adapter to i2c module... */
> +
> +	adap->algo = &cpm_algo;
> +
> +	i2c_add_adapter(adap);
> +	cpm_iic_init(cpm);
> +
> +	/* scan bus */
> +	if (cpm_scan) {
> +		printk(KERN_INFO " i2c-algo-8xx.o: scanning bus %s...\n",
> +			adap->name);
> +		for (i = 0; i < 128; i++) {
> +			if (cpm_iic_tryaddress(cpm, i))
> +				printk("(%02x)",i<<1);
> +		}
> +		printk("\n");
> +	}
> +
> +	return 0;
> +}
> +
> +int i2c_8xx_del_bus(struct i2c_adapter *adap)
> +{
> +	struct i2c_algo_8xx_data *cpm = adap->algo_data;
> +
> +	cpm_iic_shutdown(cpm);
> +
> +	return i2c_del_adapter(adap);
> +}
> +
> +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 4afc795..83d9aef 100644
> --- a/drivers/i2c/busses/Kconfig
> +++ b/drivers/i2c/busses/Kconfig
> @@ -385,8 +385,8 @@ config I2C_PROSAVAGE
>  	  will be called i2c-prosavage.
>  
>  config I2C_RPXLITE
> -	tristate "Embedded Planet RPX Lite/Classic support"
> -	depends on RPXLITE || RPXCLASSIC
> +	tristate "Embedded Planet RPX Lite/Classic and Freescale 86x/885 ads support"
> +	depends on RPXLITE || RPXCLASSIC || MPC86XADS || MPC885ADS
>  	select I2C_ALGO8XX
>  
>  config I2C_S3C2410
> diff --git a/drivers/i2c/busses/i2c-rpx.c b/drivers/i2c/busses/i2c-rpx.c
> index 8764df0..ebddd94 100644
> --- a/drivers/i2c/busses/i2c-rpx.c
> +++ b/drivers/i2c/busses/i2c-rpx.c
> @@ -14,88 +14,129 @@
>  #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/mpc8xx.h>
>  #include <asm/commproc.h>
> +#include <asm/fs_pd.h>
>  
>  
> -static void
> -rpx_iic_init(struct i2c_algo_8xx_data *data)
> +struct m8xx_i2c {
> +	char *base;
> +	struct device *dev;
> +	struct i2c_adapter adap;
> +	struct i2c_algo_8xx_data *algo_8xx;
> +};
> +
> +static struct i2c_algo_8xx_data rpx_data;
> +
> +static struct i2c_adapter rpx_ops = {
> +	.owner		= THIS_MODULE,
> +	.name		= "m8xx",
> +	.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 platform_device *pdev = to_platform_device(i2c->dev);
> +
> +	cp = data->cp = (cpm8xx_t *)immr_map(im_cpm);	/* pointer to Communication Processor */
>  
> -	cp = cpmp;	/* Get pointer to Communication Processor */
> -	immap = (immap_t *)IMAP_ADDR;	/* and to internal registers */
> +	data->irq = platform_get_irq_byname(pdev, "interrupt");
> +  
> +	if (data->irq < 0)
> +		return -EINVAL;
>  
> -	data->iip = (iic_t *)&cp->cp_dparam[PROFF_IIC];
> +	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pram");
> +	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;
> -
> -	/* Initialize Port B IIC pins.
> -	*/
> -	cp->cp_pbpar |= 0x00000030;
> -	cp->cp_pbdir |= 0x00000030;
> -	cp->cp_pbodr |= 0x00000030;
> +	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
> +	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 device *device)
>  {
> -	/* install interrupt handler */
> -	cpm_install_handler(irq, func, data);
> -
> -	return 0;
> -}
> +	int result = 0;
> +	struct m8xx_i2c *i2c;
> +	struct platform_device *pdev = to_platform_device(device);
>  
> -static struct i2c_algo_8xx_data rpx_data = {
> -	.setisr = rpx_install_isr
> -};
> +	if (!(i2c = kmalloc(sizeof(*i2c), GFP_KERNEL))) {
> +		return -ENOMEM;
> +	}
> +	memset(i2c, 0, sizeof(*i2c));
> +	i2c->dev = device;
> +	i2c->algo_8xx = &rpx_data;
>  
> -static struct i2c_adapter rpx_ops = {
> -	.owner		= THIS_MODULE,
> -	.name		= "m8xx",
> -	.id		= I2C_HW_MPC8XX_EPON,
> -	.algo_data	= &rpx_data,
> -};
> +	rpx_iic_init(i2c);
>  
> -int __init i2c_rpx_init(void)
> -{
> -	printk(KERN_INFO "i2c-rpx: i2c MPC8xx driver\n");
> +	dev_set_drvdata(device, 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 = &pdev->dev;
>  
> -	if (i2c_8xx_add_bus(&rpx_ops) < 0) {
> +	if ((result = i2c_8xx_add_bus(&rpx_ops) < 0)) {
>  		printk(KERN_ERR "i2c-rpx: Unable to register with I2C\n");
> -		return -ENODEV;
> +		kfree(i2c);
>  	}
>  
> +	return result;
> +}
> +
> +
> +static int i2c_rpx_remove(struct device *device)
> +{
> +	struct m8xx_i2c *i2c = dev_get_drvdata(device);
> +
> +	i2c_8xx_del_bus(&i2c->adap);
> +	dev_set_drvdata(device, NULL);
> +
> +	kfree(i2c);
>  	return 0;
>  }
>  
> -void __exit i2c_rpx_exit(void)
> +
> +/* Structure for a device driver */
> +static struct device_driver i2c_rpx_driver = {
> +	.name = "fsl-i2c-cpm",
> +	.bus = &platform_bus_type,
> +	.probe = i2c_rpx_probe,
> +	.remove = i2c_rpx_remove,
> +};
> +
> +static int __init i2c_rpx_init(void)
>  {
> -	i2c_8xx_del_bus(&rpx_ops);
> +	return driver_register(&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)
> +{
> +	driver_unregister(&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..a644512
> --- /dev/null
> +++ b/include/linux/i2c-algo-8xx.h
> @@ -0,0 +1,29 @@
> +/* ------------------------------------------------------------------------- */
> +/* i2c-algo-8xx.h i2c driver algorithms for MPX8XX CPM			     */
> +/* ------------------------------------------------------------------------- */
> +
> +/* $Id$ */
> +
> +#ifndef I2C_ALGO_8XX_H
> +#define I2C_ALGO_8XX_H
> +
> +#include <linux/i2c.h>
> +#include <asm/8xx_immap.h>
> +#include <asm/commproc.h>
> +
> +struct i2c_algo_8xx_data {
> +	uint dp_addr;
> +	int reloc;
> +	int irq;
> +	i2c8xx_t *i2c;
> +	iic_t	*iip;
> +	cpm8xx_t *cp;
> +
> +	u_char	temp[513];
> +};
> +
> +extern int i2c_8xx_add_bus(struct i2c_adapter *);
> +extern int i2c_8xx_del_bus(struct i2c_adapter *);
> +
> +#endif /* I2C_ALGO_8XX_H */
> +
> 
> 
> -- 
> Sincerely, Vitaly
> 
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-dev

^ permalink raw reply

* Re: Kernel Panic booting cdrom
From: Michael Ellerman @ 2007-04-23  2:10 UTC (permalink / raw)
  To: David Huffman; +Cc: linuxppc-dev, Nathan Lynch
In-Reply-To: <46292B07.3030907@storix.com>

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

On Fri, 2007-04-20 at 14:05 -0700, David Huffman wrote:
> Nathan,
> 
> I think I determined why I received a kernel panic and the numa=off 
> argument fixed the problem. When we boot from cdrom we specify maxcpus=1 
> as a kernel argument. A system with numa enabled fails.  I plan on 
> adding numa=off whenever I use maxcpus=1, but I wonder if you could 
> answer a question for me.
> 
> I originally was told that in the case where I am booting a basic system 
> into an initrd instead of in normal mode, I should use maxcpus=1 because 
> there may be power and cooling daemons that are not running and try to 
> limit the system resources by limiting the number of cpus. Does this 
> sound right? I can successfully boot a cdrom without the maxcpus flag on 
> an SMP system but maybe it is typically not a good idea?
> 
> I can prevent the kernel panics by removing maxcpus=1 and not adding 
> numa=off. I am a little more informed about numa (now), but I am fuzzy 
> as to all the implications with allowing more cpus for cdrom install 
> media. The maxcpus=1 argument was something we added to our install boot 
> media years ago and few here remember why it was such a great idea. The 
> power/resource management was the only thing we could come up with.

maxcpus=x is poorly tested, I would definitely NOT recommend it.

I don't think there's any issue with power etc. With maxcpus=1 all the
other CPUs are still running, they're just not used by the kernel - in
fact a cursory glance suggests they will do less power saving in that
situation than when they're in use but idle.

cheers

-- 
Michael Ellerman
OzLabs, IBM Australia Development Lab

wwweb: http://michael.ellerman.id.au
phone: +61 2 6212 1183 (tie line 70 21183)

We do not inherit the earth from our ancestors,
we borrow it from our children. - S.M.A.R.T Person

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

^ permalink raw reply

* [PATCH] [v2] powerpc: save trap number in bad_stack
From: Olof Johansson @ 2007-04-22 23:38 UTC (permalink / raw)
  To: paulus; +Cc: linuxppc-dev, anton
In-Reply-To: <20070416062347.GA20196@lixom.net>

Save the trap number in the case of getting a bad stack in an exception
handler. It is sometimes useful to know what exception it was that caused
this to happen. Without this, no trap is reported.

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

---

Changes since last time: Reduce to a u16 and move it.

Index: powerpc/arch/powerpc/kernel/asm-offsets.c
===================================================================
--- powerpc.orig/arch/powerpc/kernel/asm-offsets.c
+++ powerpc/arch/powerpc/kernel/asm-offsets.c
@@ -139,6 +139,7 @@ int main(void)
 	DEFINE(PACA_SYSTEM_TIME, offsetof(struct paca_struct, system_time));
 	DEFINE(PACA_SLBSHADOWPTR, offsetof(struct paca_struct, slb_shadow_ptr));
 	DEFINE(PACA_DATA_OFFSET, offsetof(struct paca_struct, data_offset));
+	DEFINE(PACA_TRAP_SAVE, offsetof(struct paca_struct, trap_save));
 
 	DEFINE(SLBSHADOW_STACKVSID,
 	       offsetof(struct slb_shadow, save_area[SLB_NUM_BOLTED - 1].vsid));
Index: powerpc/include/asm-powerpc/paca.h
===================================================================
--- powerpc.orig/include/asm-powerpc/paca.h
+++ powerpc/include/asm-powerpc/paca.h
@@ -68,6 +68,7 @@ struct paca_struct {
 	void *emergency_sp;		/* pointer to emergency stack */
 	u64 data_offset;		/* per cpu data offset */
 	s16 hw_cpu_id;			/* Physical processor number */
+	u16 trap_save;			/* Used when bad stack is encountered */
 	u8 cpu_start;			/* At startup, processor spins until */
 					/* this becomes non-zero. */
 	struct slb_shadow *slb_shadow_ptr;
Index: powerpc/arch/powerpc/kernel/head_64.S
===================================================================
--- powerpc.orig/arch/powerpc/kernel/head_64.S
+++ powerpc/arch/powerpc/kernel/head_64.S
@@ -278,8 +278,12 @@ exception_marker:
 	beq-	1f;							   \
 	ld	r1,PACAKSAVE(r13);	/* kernel stack to use		*/ \
 1:	cmpdi	cr1,r1,0;		/* check if r1 is in userspace	*/ \
-	bge-	cr1,bad_stack;		/* abort if it is		*/ \
-	std	r9,_CCR(r1);		/* save CR in stackframe	*/ \
+	bge-	cr1,2f;			/* abort if it is		*/ \
+	b	3f;							   \
+2:	li	r1,(n);			/* will be reloaded later	*/ \
+	stw	r1,PACA_TRAP_SAVE(r13);					   \
+	b	bad_stack;						   \
+3:	std	r9,_CCR(r1);		/* save CR in stackframe	*/ \
 	std	r11,_NIP(r1);		/* save SRR0 in stackframe	*/ \
 	std	r12,_MSR(r1);		/* save SRR1 in stackframe	*/ \
 	std	r10,0(r1);		/* make stack chain pointer	*/ \
@@ -940,6 +944,8 @@ bad_stack:
 	SAVE_2GPRS(7,r1)
 	SAVE_10GPRS(12,r1)
 	SAVE_10GPRS(22,r1)
+	lwz	r12,PACA_TRAP_SAVE(r13)
+	std	r12,_TRAP(r1)
 	addi	r11,r1,INT_FRAME_SIZE
 	std	r11,0(r1)
 	li	r12,0

^ permalink raw reply

* Re: [PATCH] powerpc: save trap number in bad_stack
From: Olof Johansson @ 2007-04-22 23:34 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev, paulus, anton
In-Reply-To: <1177024678.7286.23.camel@localhost.localdomain>

On Fri, Apr 20, 2007 at 09:17:58AM +1000, Benjamin Herrenschmidt wrote:
> Can you put it elsewhere in the PACA (around less frequently used
> bits) ? This is a pretty hot area of the PACA...

Good point, I didn't think much about layout when I added it. There's
actually room right before if it's reduced in size (which is easy to do).
See patch posted separately.


-Olof

^ permalink raw reply

* Re: Fw: [PATCH][RFC] PCMCIA support for 8xx using platform devices
From: Arnd Bergmann @ 2007-04-22 21:49 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Vitaly Bordug, linux-pcmcia, lkml
In-Reply-To: <20070422232658.5f427fd3@localhost.localdomain>

On Sunday 22 April 2007, Vitaly Bordug wrote:
> This utilizes PCMCIA on mpc885ads and mpc866ads from arch/powerpc. In the
> new approach, direct IMMR accesses from within drivers/ were totally
> eliminated, that requires hardware_enable, hardware_disable, voltage_set
> board-specific functions to be moved over to BSP code section   
> (arch/powerpc/platforms/8xx in 885 case). There is just no way to have
> both arch/ppc and arch/powerpc approaches to work simultaneously because
> of that.  

Maybe I'm missing a key issue here, but what's the point of adding
more platform_devices for stuff that is already in the device tree?
Shouldn't this be made an of_platform_driver instead so you can
use the existing of_device directly?

	Arnd <><

^ permalink raw reply

* Fw: [PATCH][RFC] PCMCIA support for 8xx using platform devices
From: Vitaly Bordug @ 2007-04-22 19:26 UTC (permalink / raw)
  To: linuxppc-dev@ozlabs.org; +Cc: linux-pcmcia, lkml

This utilizes PCMCIA on mpc885ads and mpc866ads from arch/powerpc. In the new approach,
direct IMMR accesses from within drivers/ were totally eliminated, that requires hardware_enable, hardware_disable, voltage_set board-specific functions to be moved over to BSP code section 
(arch/powerpc/platforms/8xx in 885 case). There is just no way to have both arch/ppc and arch/powerpc approaches to work simultaneously because of that.

It implies a bit of work to move other target's bits over to BSP region, but no ifdef hell worths it,
in addition to the fact of being moved/merged to arch/powerpc, the code would spot this problem 
anyway.

Signed-off-by: Vitaly Bordug <vitb@kernel.crashing.org>
---
This is FW of original message sent to linux-pcmcia@lists.infradead.org to attach wider audience.
Original maillist kept in loop to prevent misunderstanding...

 arch/powerpc/boot/dts/mpc885ads.dts          |   12 +
 arch/powerpc/platforms/8xx/mpc885ads.h       |    5 
 arch/powerpc/platforms/8xx/mpc885ads_setup.c |   63 +++++
 arch/powerpc/sysdev/fsl_soc.c                |   58 ++++
 drivers/pcmcia/Kconfig                       |    1 
 drivers/pcmcia/m8xx_pcmcia.c                 |  342 ++++++++++++--------------
 include/linux/fs_pcmcia_pd.h                 |   27 ++
 7 files changed, 318 insertions(+), 190 deletions(-)

diff --git a/arch/powerpc/boot/dts/mpc885ads.dts b/arch/powerpc/boot/dts/mpc885ads.dts
index 90e047a..330ac91 100644
--- a/arch/powerpc/boot/dts/mpc885ads.dts
+++ b/arch/powerpc/boot/dts/mpc885ads.dts
@@ -112,6 +112,18 @@
 			compatible = "CPM";
 		};
 
+               pcmcia@0080 {
+                       linux,phandle = <0080>;
+                       #interrupt-cells = <1>;
+                       #size-cells = <2>;
+                       compatible = "8xx";
+                       device_type = "pcmcia";
+                       reg = <80 80>;
+                       clock-frequency = <2faf080>;
+                       interrupt-parent = <ff000000>;
+                       interrupts = <d 1>;
+		};
+
 		cpm@ff000000 {
 			linux,phandle = <ff000000>;
 			#address-cells = <1>;
diff --git a/arch/powerpc/platforms/8xx/mpc885ads.h b/arch/powerpc/platforms/8xx/mpc885ads.h
index 7c31aec..4439346 100644
--- a/arch/powerpc/platforms/8xx/mpc885ads.h
+++ b/arch/powerpc/platforms/8xx/mpc885ads.h
@@ -91,5 +91,10 @@ #define PC_ENET_RENA	((ushort)0x0800)
 #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.
+ */
+#define mk_int_int_mask(IL) (1 << (7 - (IL/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 394f983..1ba423f 100644
--- a/arch/powerpc/platforms/8xx/mpc885ads_setup.c
+++ b/arch/powerpc/platforms/8xx/mpc885ads_setup.c
@@ -22,6 +22,7 @@ #include <linux/root_dev.h>
 
 #include <linux/fs_enet_pd.h>
 #include <linux/fs_uart_pd.h>
+#include <linux/fs_pcmcia_pd.h>
 #include <linux/mii.h>
 
 #include <asm/delay.h>
@@ -375,6 +376,68 @@ static void init_i2c_ioports()
         setbits16(&cp->cp_pbodr, 0x0030);
 }
 
+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);
+}
+
+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;
+}
+
 int platform_device_skip(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 355c05d..753118d 100644
--- a/arch/powerpc/sysdev/fsl_soc.c
+++ b/arch/powerpc/sysdev/fsl_soc.c
@@ -26,6 +26,7 @@ #include <linux/phy.h>
 #include <linux/fsl_devices.h>
 #include <linux/fs_enet_pd.h>
 #include <linux/fs_uart_pd.h>
+#include <linux/fs_pcmcia_pd.h>
 
 #include <asm/system.h>
 #include <asm/atomic.h>
@@ -862,6 +863,8 @@ #ifdef CONFIG_8xx
 
 extern void init_scc_ioports(struct fs_platform_info*);
 extern int platform_device_skip(char *model, int id);
+extern void pcmcia_hw_setup(int slot, int enable);
+extern int pcmcia_set_voltage(int slot, int vcc, int vpp);
 
 static int __init fs_enet_mdio_of_init(void)
 {
@@ -1267,5 +1270,60 @@ err:
 
 arch_initcall(fsl_i2c_cpm_of_init);
 
+static const char *pcmcia_regs = "regs";
+static const char *pcmcia_irq = "interrupt";
+
+static int __init fsl_pcmcia_of_init(void)
+{
+	struct device_node *np;
+	unsigned int i;
+	struct platform_device *pcmcia_dev;
+	int ret;
+
+	for (np = NULL, i = 0;
+	     (np = of_find_compatible_node(np, "pcmcia", "8xx")) != NULL;
+	     i++) {
+		struct resource r[2];
+		struct fs_pcmcia_platform_data pcmcia_data;
+
+		memset(&r, 0, sizeof(r));
+		memset(&pcmcia_data, 0, sizeof(pcmcia_data));
+
+		ret = of_address_to_resource(np, 0, &r[0]);
+		if (ret)
+			goto err;
+		r[0].name = pcmcia_regs;
+
+		r[1].start = r[1].end = irq_of_parse_and_map(np, 0);
+		r[1].flags = IORESOURCE_IRQ;
+		r[1].name = pcmcia_irq;
+
+		pcmcia_data.hwirq = irq_map[r[1].start].hwirq;
+		pcmcia_data.hw_setup = pcmcia_hw_setup;
+		pcmcia_data.voltage_set = pcmcia_set_voltage;
+		pcmcia_data.bus_freq = ppc_proc_freq;
+
+		pcmcia_dev = platform_device_register_simple("m8xx-pcmcia", i, &r[0], 2);
+		if (IS_ERR(pcmcia_dev)) {
+			ret = PTR_ERR(pcmcia_dev);
+			goto err;
+		}
+		ret =
+		    platform_device_add_data(pcmcia_dev, &pcmcia_data,
+					     sizeof(struct
+						    fs_pcmcia_platform_data));
+		if (ret)
+			goto unreg;
+	}
+
+	return 0;
+
+unreg:
+	platform_device_unregister(pcmcia_dev);
+err:
+	return ret;
+}
+
+arch_initcall(fsl_pcmcia_of_init);
 
 #endif /* CONFIG_8xx */
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..ddac883 100644
--- a/drivers/pcmcia/m8xx_pcmcia.c
+++ b/drivers/pcmcia/m8xx_pcmcia.c
@@ -40,10 +40,6 @@ #include <linux/types.h>
 #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>
@@ -52,10 +48,16 @@ #include <linux/ioport.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
+#include <linux/fs_pcmcia_pd.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 <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
@@ -146,27 +148,18 @@ #endif
 #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);
+static spinlock_t events_lock = SPIN_LOCK_UNLOCKED;
 
 
 #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;
+	struct platform_device *pdev;
+	struct fs_pcmcia_platform_data *pdata;
 
 	socket_state_t state;
 	struct pccard_mem_map mem_win[PCMCIA_MEM_WIN_NO];
@@ -404,83 +402,15 @@ static void hardware_disable(int slot)
 #endif
 
 /* MPC885ADS Boards */
-
 #if defined(CONFIG_MPC885ADS)
 
 #define PCMCIA_BOARD_MSG "MPC885ADS"
-
-static int voltage_set(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:
-			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;
-}
-
 #define socket_get(_slot_) PCMCIA_SOCKET_KEY_5V
 
-static void hardware_enable(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);
-}
-
-static 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);
-}
+/* These functions are defined in the board-specific code */
+#define hardware_enable(_slot_)	pdata->hw_setup(_slot_, 1)
+#define hardware_disable(_slot_) pdata->hw_setup(_slot_, 0)
+#define voltage_set(slot, vcc, vpp)	pdata->voltage_set(slot, vcc, vpp)
 
 #endif
 
@@ -541,6 +471,7 @@ #define hardware_enable(_slot_)  /* No h
 #define hardware_disable(_slot_) /* No hardware to disable */
 
 #endif /* CONFIG_MBX */
+/* Motorola MBX860 */
 
 #if defined(CONFIG_PRxK)
 #include <asm/cpld.h>
@@ -604,63 +535,22 @@ #define hardware_disable(_slot_) /* No h
 
 #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);
+static spinlock_t pending_event_lock = SPIN_LOCK_UNLOCKED;
 
 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 +614,7 @@ #endif
 			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 +622,7 @@ #endif
 	}
 
 	/* 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 +643,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 +671,7 @@ static u32 m8xx_get_speed(u32 ns, u32 is
 
 #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 +696,9 @@ static int m8xx_get_status(struct pcmcia
 	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;
@@ -915,9 +806,11 @@ static int m8xx_set_socket(struct pcmcia
 {
 	int lsock = container_of(sock, struct socket_info, socket)->slot;
 	struct socket_info *s = &socket[lsock];
+	struct fs_pcmcia_platform_data *pdata = s->pdata;
 	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 +820,7 @@ static int m8xx_set_socket(struct pcmcia
 	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 +876,8 @@ static int m8xx_set_socket(struct pcmcia
 		 * 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);
+			int hwirq = s->pdata->hwirq;
+			out_be32(M8XX_PGCRX(lsock), in_be32(M8XX_PGCRX(lsock)) | mk_int_int_mask(hwirq) << 24);
 			/*
 			 * Strange thing here:
 			 * The manual does not tell us which interrupt
@@ -1027,7 +922,7 @@ static int m8xx_set_socket(struct pcmcia
 	 * 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 +931,8 @@ static int m8xx_set_socket(struct pcmcia
 	 * 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 +950,8 @@ static int m8xx_set_io_map(struct pcmcia
 	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 +976,7 @@ #define M8XX_BASE (PCMCIA_IO_WIN_BASE + 
 
 		/* 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 +985,13 @@ #define M8XX_BASE (PCMCIA_IO_WIN_BASE + 
 		reg <<= 27;
   		reg |= M8XX_PCMCIA_POR_IO |(lsock << 2);
 
-		reg |= m8xx_get_speed(io->speed, 1);
+		reg |= m8xx_get_speed(io->speed, 1, s->pdata->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 +1008,7 @@ #define M8XX_BASE (PCMCIA_IO_WIN_BASE + 
 
 		/* 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 +1035,7 @@ static int m8xx_set_mem_map(struct pcmci
 	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 +1058,12 @@ static int m8xx_set_mem_map(struct pcmci
 
 	/* 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->pdata->bus_freq);
 
 	if(mem->flags & MAP_ATTRIB)
 		reg |=  M8XX_PCMCIA_POR_ATTRMEM;
@@ -1236,57 +1128,69 @@ static int m8xx_sock_init(struct pcmcia_
 
 }
 
-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 platform_device *pdev)
 {
 	struct pcmcia_win *w;
-	unsigned int i,m;
+	unsigned int i, m, hwirq;
+	pcmconf8xx_t *pcmcia;
+	int status;
+	struct resource *r;
+	struct fs_pcmcia_platform_data *pdata = pdev->dev.platform_data;
 
 	pcmcia_info("%s\n", version);
 
-	if (driver_register(&m8xx_driver))
-		return -1;
+	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
+
+	pcmcia = ioremap(r->start, r->end - r->start + 1);
+	if(pcmcia == NULL)
+		return -EINVAL;
+
+	pcmcia_schlvl = platform_get_irq_byname(pdev,"interrupt");
+	if (pcmcia_schlvl < 0)
+		return -EINVAL;
+	hwirq = pdata->hwirq;
+
+	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++) {
@@ -1300,16 +1204,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 +1219,90 @@ 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 = &pdev->dev;
+		socket[i].pcmcia = pcmcia;
+		socket[i].pdata = pdata;
 	}
 
-	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 __exit m8xx_shutdown(struct platform_device *pdev)
 {
-	int i;
+	u32 m, i;
+	struct pcmcia_win *w;
+	pcmconf8xx_t *pcmcia = socket[0].pcmcia;
+	struct fs_pcmcia_platform_data *pdata = socket[0].pdata;
+
+	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);
+
+	return 0;
+}
+
+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);
+}
 
-	platform_device_unregister(&m8xx_device);
-	driver_unregister(&m8xx_driver);
+static struct platform_driver m8xx_driver = {
+	.driver = {
+		.name		= (char *) driver_name,
+		.owner		= THIS_MODULE,
+	},
+	.probe		= m8xx_probe,
+	.remove		= __exit_p(m8xx_shutdown),
+	.suspend	= m8xx_suspend,
+	.resume		= m8xx_resume,
+};
+
+
+static int __init m8xx_init(void)
+{
+	return platform_driver_register(&m8xx_driver);
+}
+
+static void __exit m8xx_exit(void)
+{
+	platform_driver_unregister(&m8xx_driver);
 }
 
 module_init(m8xx_init);
diff --git a/include/linux/fs_pcmcia_pd.h b/include/linux/fs_pcmcia_pd.h
new file mode 100644
index 0000000..2769a11
--- /dev/null
+++ b/include/linux/fs_pcmcia_pd.h
@@ -0,0 +1,27 @@
+/*
+ * Platform information definitions for the CPM Uart driver.
+ *
+ * 2007 (c) MontaVista Software, Inc.
+ * Yuri Shpilevsky <yshpilevsky@ru.mvista.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef FS_PCMCIA_PD_H
+#define FS_PCMCIA_PD_H
+
+#include <linux/version.h>
+#include <asm/types.h>
+
+struct fs_pcmcia_platform_data {
+	void(*hw_setup)(int slot, int enable);
+	int(*voltage_set)(int slot, int vcc, int vpp);
+
+	/* device specific information */
+	int hwirq;
+	u32 bus_freq;
+};
+
+#endif


-- 
Sincerely, 
Vitaly


-- 
Sincerely, 
Vitaly

_______________________________________________
Linux PCMCIA reimplementation list
http://lists.infradead.org/mailman/listinfo/linux-pcmcia


-- 
Sincerely, Vitaly

^ permalink raw reply related

* Re: [PATCH 7/7] MPIC MSI backend
From: Olof Johansson @ 2007-04-22 19:30 UTC (permalink / raw)
  To: Segher Boessenkool; +Cc: linuxppc-dev, linux-pci, Milton Miller
In-Reply-To: <ca8197808a747b83c14461f6fec375db@kernel.crashing.org>

On Sun, Apr 22, 2007 at 09:06:15AM +0200, Segher Boessenkool wrote:

> mpic_htmsi deals with MSIs that come in over hypertransport
> to the MPIC on CPC925/CPC945; this has nothing to
> do with HT APICs.

Maybe it should be named mpic_cpc9x5msi instead?


-Olof

^ permalink raw reply

* where is the sk_buff allocation
From: Ming Liu @ 2007-04-22 18:06 UTC (permalink / raw)
  To: linuxppc-embedded

Dear all,
I am reading and understanding the Xilinx Temac device driver. I know that 
hard_start_xmit() is used to transmit the packets. In this function, a 
pointer skb which points to a sk_buff needs to be passed to show the 
location of the socket buffer. But where is that sk_buff allocation 
sentence, and how its address (skb) is passed to the hard_start_xmit() 
function? I want to change the address of the sk_buff in my system and try 
to fit this socket buffer in a pre-defined location.

Thanks for your telling.

BR
Ming

_________________________________________________________________
享用世界上最大的电子邮件系统― MSN Hotmail。  http://www.hotmail.com  

^ permalink raw reply

* where is the sk_buff allocation
From: Ming Liu @ 2007-04-22 18:14 UTC (permalink / raw)
  To: linuxppc-embedded

Dear all,
I am reading and understanding the Xilinx Temac device driver. I know that 
hard_start_xmit() is used to transmit the packets. In this function, a 
pointer skb which points to a sk_buff needs to be passed to show the 
location of the socket buffer. But where is that sk_buff allocation 
sentence, and how its address (skb) is passed to the hard_start_xmit() 
function? I want to change the address of the sk_buff in my system and try 
to fit this socket buffer in a pre-defined location.

Thanks for your telling.

BR
Ming

_________________________________________________________________
享用世界上最大的电子邮件系统― MSN Hotmail。  http://www.hotmail.com  

^ permalink raw reply


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