LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: Re: [PATCH] General CHRP/MPC5K2 platform support patch
From: Benjamin Herrenschmidt @ 2006-10-28 20:12 UTC (permalink / raw)
  To: Nicolas DET; +Cc: akpm, linuxppc-dev, sl, sha, linuxppc-embedded
In-Reply-To: <200610281343.k9SDhTJm020310@post.webmailer.de>


> > As I said before, NR_IRQ is a poor choice for the size of the revmap.
> > You should have a constant somewhere defining what is your max HW irq
> > number. and use that +1, or a hw irq count.
> 
> Done: 64

Even with a new numbering invloving the category in top bits and the bit
number in the bottom ?

Ben.

^ permalink raw reply

* External Bus on 440GP
From: Madhu Saravana Sibi Govindan @ 2006-10-29  7:59 UTC (permalink / raw)
  To: linuxppc-embedded

Hello all,

I have a question about linux on 440gp and a custom board.

We use the Universal boot-loader, U-boot, to initialize the board and
then, boot linux. The flash chip on the board is 4 MB in size.

I'm trying to access the flash chip (attached to the External Bus
Interface) in a custom device driver running in linux.  The behavior
I'm seeing is this: when the EBC0_B0CR (Bank Configuration register 0)
is set to 0xffc5800 (Base address: 0xffc, size = 4 MB, usage: RW and
width = 8 bits) and when do an ioremap64 to map the physical space of
the flash chip into the virtual address, all accesses to the flash chip
are successful.  Please note that the virtual address returned by
ioremap64 is different from
0xffc00000.

But, when I do an ioremap first and use the virtual address (the most
significant 12  bits) to program the EBC0_B0CR, all accesses to the
flash chip result in a timeout error on the bus.
The IBM 440GP documentation clearly says that the bits in the EBC0_B0CR
is used to enable the correct chip select signal. Why am I seeing the
above behavior?

I'm actually trying to access a custom chip on the EBI bus using the
same method. I got the same error, so I tried the flash chip....

I'd be thankful if someone could point me to what might be going wrong.
I'd be glad to provide as much information as necessary.

Thanks in advance,
G.Sibi

PS: My apologies if this question doesn't belong here....

^ permalink raw reply

* device tree for lite5200b
From: Grant Likely @ 2006-10-29 22:58 UTC (permalink / raw)
  To: linuxppc-embedded list, Sylvain Munaut

Sylvain,

Here's my second draft of a device tree for the lite5200b.  Enjoy

Note: The interrupt mappings are not correct.  I assumed 2 bits for L1
and 8 for L2.  Nicolas' code uses 2 and 6.

g.

/*
 * Lite5200b board Device Tree Source
 *
 * Copyright 2006 Secret Lab Technologies Ltd.
 * Grant Likely <grant.likely@secretlab.ca>
 *
 * 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.
 */

/ {
	model = "Lite5200b";
	compatible = "mpc5200";
	#address-cells = <1>;
	#size-cells = <1>;

	cpus {
		#cpus = <1>;
		#address-cells = <1>;
		#size-cells = <0>;

		PowerPC,5200@0 {
			device_type = "cpu";
			reg = <0>;
			d-cache-line-size = <20>;
			i-cache-line-size = <20>;
			d-cache-size = <4000>;		// L1, 16K
			i-cache-size = <4000>;		// L1, 16K
			timebase-frequency = <0>;	// from bootloader
			bus-frequency = <0>;		// from bootloader
			clock-frequency = <0>;		// from bootloader
			32-bit;
		};
	};

	memory {
		device_type = "memory";
		reg = <00000000 10000000>;	// 256MB
	};

	soc5200@f0000000 {
		#interrupt-cells = <2>;
		device_type = "soc";
		ranges = <0 f0000000 f0010000>;
		reg = <f0000000 00010000>;
		bus-frequency = <0>;		// from bootloader

		pic@500 {
			// 5200 interrupts are encoded into two levels;
			// Level 1 is 2 bits; [CRIT=0,MAIN=1,PERF=2,SDMA=3]
			// Level 2 is 5 bits
			// The levels are encoded into a single cell:
			// in binary: xxxx xx11 xxx2 2222
			linux,phandle = <500>;
			interrupt-controller;
			device_type = "interrupt_controller";
			compatible = "mpc52xx-pic";
			reg = <500 80>;
			built-in;
		};

		gpt@600 {	// General Purpose Timer
			compatible = "mpc5200-gpt";
			device_type = "gpt";
			reg = <600 10>;
			interrupts = <109 2>;
			interrupt-parent = <500>;
		};

		gpt@610 {	// General Purpose Timer
			compatible = "mpc5200-gpt";
			device_type = "gpt";
			reg = <610 10>;
			interrupts = <10a 2>;
			interrupt-parent = <500>;
		};

		gpt@620 {	// General Purpose Timer
			compatible = "mpc5200-gpt";
			device_type = "gpt";
			reg = <620 10>;
			interrupts = <10b 2>;
			interrupt-parent = <500>;
		};

		gpt@630 {	// General Purpose Timer
			compatible = "mpc5200-gpt";
			device_type = "gpt";
			reg = <630 10>;
			interrupts = <10c 2>;
			interrupt-parent = <500>;
		};

		gpt@640 {	// General Purpose Timer
			compatible = "mpc5200-gpt";
			device_type = "gpt";
			reg = <640 10>;
			interrupts = <10d 2>;
			interrupt-parent = <500>;
		};

		gpt@650 {	// General Purpose Timer
			compatible = "mpc5200-gpt";
			device_type = "gpt";
			reg = <650 10>;
			interrupts = <10e 2>;
			interrupt-parent = <500>;
		};

		gpt@660 {	// General Purpose Timer
			compatible = "mpc5200-gpt";
			device_type = "gpt";
			reg = <660 10>;
			interrupts = <10f 2>;
			interrupt-parent = <500>;
		};

		gpt@670 {	// General Purpose Timer
			compatible = "mpc5200-gpt";
			device_type = "gpt";
			reg = <670 10>;
			interrupts = <110 2>;
			interrupt-parent = <500>;
		};

		rtc@800 {	// Real time clock
			compatible = "mpc5200-rtc";
			device_type = "rtc";
			reg = <800 100>;
			interrupts = <105 2 106 2>;
			interrupt-parent = <500>;
		};

		mscan@900 {
			device_type = "mscan";
			compatible = "mpc5200-mscan";
			interrupts = <211 2>;
			interrupt-parent = <500>;
			reg = <900 80>;
		};

		mscan@980 {
			device_type = "mscan";
			compatible = "mpc5200-mscan";
			interrupts = <212 2>;
			interrupt-parent = <500>;
			reg = <980 80>;
		};

		pci@0d00 {
			#interrupt-cells = <1>;
			#size-cells = <2>;
			#address-cells = <3>;
			device_type = "pci";
			compatible = "mpc5200-pci";
			// I actually know very little about setting up PCI,
			// so anything here would just be pulled out of my
			// butt.  Instead I'll leave these placeholders until
			// I figure out what it should be
			//
			// interrupt-map-mask = <>;
			// interrupt-map = <>;
			// bus-range = <>;
			// ranges = <>;
			//
			clock-frequency = <3f940aa>;
			interrupts = <208 2 209 2 20a 2>;
			interrupt-parent = <500>;
		};

		spi@f00 {
			device_type = "spi";
			compatible = "mpc5200-spi";
			reg = <f00 20>;
			interrupts = <20d 2 20e 2>;
			interrupt-parent = <500>;
		};

		serial@2000 {		// PSC1
			device_type = "serial";
			compatible = "mpc5200-psc";
			reg = <2000 100>;
			interrupts = <201 2>;
			interrupt-parent = <500>;
		};

		// PSC2 in spi mode example
		spi@2200 {		// PSC2
			device_type = "spi";
			compatible = "mpc5200-psc";
			reg = <2200 100>;
			interrupts = <202 2>;
			interrupt-parent = <500>;
		};

		// PSC3 in CODEC mode example
		i2s@2400 {		// PSC3
			device_type = "i2s";
			compatible = "mpc5200-psc";
			reg = <2400 100>;
			interrupts = <203 2>;
			interrupt-parent = <500>;
		};

		// PSC4 unconfigured
		//serial@2600 {		// PSC4
		//	device_type = "serial";
		//	compatible = "mpc5200-psc";
		//	reg = <2600 100>;
		//	interrupts = <20b 2>;
		//	interrupt-parent = <500>;
		//};

		// PSC5 unconfigured
		//serial@2800 {		// PSC5
		//	device_type = "serial";
		//	compatible = "mpc5200-psc";
		//	reg = <2800 100>;
		//	interrupts = <20c 2>;
		//	interrupt-parent = <500>;
		//};

		// PSC6 in AC97 mode example
		ac97@2c00 {		// PSC6
			device_type = "ac97";
			compatible = "mpc5200-psc";
			reg = <2c00 100>;
			interrupts = <204 2>;
			interrupt-parent = <500>;
		};

		ethernet@3000 {
			device_type = "network";
			compatible = "mpc5200-fec";
			reg = <3000 800>;
			mac-address = [ 02 03 04 05 06 07 ]; // Bad!
			interrupts = <205 2>;
			interrupt-parent = <500>;
		};

		ata@3a00 {
			device_type = "ata";
			compatible = "mpc5200-ata";
			reg = <3a00 100>;
			interrupts = <207 2>;
			interrupt-parent = <500>;
		};

		i2c@3d00 {
			device_type = "i2c";
			compatible = "mpc5200-i2c";
			reg = <3d00 40>;
			interrupts = <20f 2>;
			interrupt-parent = <500>;
		};

		i2c@3d40 {
			device_type = "i2c";
			compatible = "mpc5200-i2c";
			reg = <3d40 40>;
			interrupts = <210 2>;
			interrupt-parent = <500>;
		};
	};
};
-- 
Grant Likely, B.Sc. P.Eng.
Secret Lab Technologies Ltd.
grant.likely@secretlab.ca
(403) 399-0195

^ permalink raw reply

* [PATCH 1/2] Add MPC52xx Interrupt controller support for ARCH=powerpc
From: Nicolas DET @ 2006-10-29 23:10 UTC (permalink / raw)
  To: linuxppc-embedded; +Cc: sl, sha, linuxppc-dev

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

This patch add MPC52xx Interrupt controller for ARCH=powerpc.

It includes the main code in arch/powerpc/sysdev/ ad well as an header file in
include/asm-powerpc.

Signed-off-by: Nicolas DET <nd@bplan-gmbh.de>

[-- Attachment #2: archpowerpc_mpc52x.patch --]
[-- Type: application/octet-stream, Size: 25257 bytes --]

--- a/arch/powerpc/sysdev/mpc52xx_pic.c	1970-01-01 01:00:00.000000000 +0100
+++ b/arch/powerpc/sysdev/mpc52xx_pic.c	2009-10-29 22:27:13.000000000 +0100
@@ -0,0 +1,557 @@
+/*
+ *
+ * Programmable Interrupt Controller functions for the Freescale MPC52xx.
+ * 
+ * Copyright (C) 2006 bplan GmbH
+ * 
+ * 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.
+ *
+ */
+
+#undef DEBUG
+
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/stddef.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/hardirq.h>
+
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/prom.h>
+#include <asm/mpc52xx.h>
+
+static struct mpc52xx_intr __iomem *intr;
+static struct mpc52xx_sdma __iomem *sdma;
+static struct irq_host *mpc52xx_irqhost = NULL;
+
+static unsigned char mpc52xx_map_senses[4] = {
+	IRQ_TYPE_LEVEL_HIGH,
+	IRQ_TYPE_EDGE_FALLING,
+	IRQ_TYPE_EDGE_RISING,
+	IRQ_TYPE_LEVEL_LOW,
+};
+
+/*
+ * void call to be used for .ack in the irq_chip_ops
+ * indeed, some of our irq does noy need ack
+ * but the kernel call .ack if it's valid or not
+*/
+
+static void mpc52xx_voidfunc(unsigned int virq)
+{
+#ifdef DEBUG
+	int irq;
+	int l2irq;
+
+	irq = irq_map[virq].hwirq;
+	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
+
+	pr_debug("%s: irq=%x, l2=%d\n", __func__, irq, l2irq);
+#endif
+}
+
+/*
+ * Critial interrupt irq_chip
+*/
+static void mpc52xx_crit_mask(unsigned int virq)
+{
+	u32 val;
+	int irq;
+	int l2irq;
+
+	irq = irq_map[virq].hwirq;
+	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
+
+	pr_debug("%s: irq=%x, l2=%d\n", __func__, irq, l2irq);
+
+	if (l2irq != 0)
+		BUG();
+
+	val = in_be32(&intr->ctrl);
+	val &= ~(1 << 11);
+	out_be32(&intr->ctrl, val);
+}
+
+static void mpc52xx_crit_unmask(unsigned int virq)
+{
+	u32 val;
+	int irq;
+	int l2irq;
+
+	irq = irq_map[virq].hwirq;
+	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
+
+	pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
+
+	if (l2irq != 0)
+		BUG();
+
+	val = in_be32(&intr->ctrl);
+	val |= 1 << 11;
+	out_be32(&intr->ctrl, val);
+}
+
+static void mpc52xx_crit_ack(unsigned int virq)
+{
+	u32 val;
+	int irq;
+	int l2irq;
+
+	irq = irq_map[virq].hwirq;
+	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
+
+	pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
+
+	if (l2irq != 0)
+		BUG();
+
+	val = in_be32(&intr->ctrl);
+	val |= 0x08000000;
+	out_be32(&intr->ctrl, val);
+}
+
+static struct irq_chip mpc52xx_crit_irqchip = {
+	.typename = "MPC52xx IRQ0",
+	.mask = mpc52xx_crit_mask,
+	.unmask = mpc52xx_crit_unmask,
+	.ack = mpc52xx_crit_ack,
+};
+
+/*
+ * IRQ[1-3] interrupt irq_chip
+*/
+
+static void mpc52xx_mainirq_mask(unsigned int virq)
+{
+	u32 val;
+	int irq;
+	int l2irq;
+
+	irq = irq_map[virq].hwirq;
+	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
+
+	pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
+
+	val = in_be32(&intr->ctrl);
+	val &= ~(1 << (11 - l2irq));
+	out_be32(&intr->ctrl, val);
+}
+
+static void mpc52xx_mainirq_unmask(unsigned int virq)
+{
+	u32 val;
+	int irq;
+	int l2irq;
+
+	irq = irq_map[virq].hwirq;
+	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
+
+	pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
+
+	val = in_be32(&intr->ctrl);
+	val |= 1 << (11 - l2irq);
+	out_be32(&intr->ctrl, val);
+}
+
+static void mpc52xx_mainirq_ack(unsigned int virq)
+{
+	u32 val;
+	int irq;
+	int l2irq;
+
+	irq = irq_map[virq].hwirq;
+	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
+
+	pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
+
+	val = in_be32(&intr->ctrl);
+	val |= 0x08000000 >> l2irq;
+	out_be32(&intr->ctrl, val);
+}
+
+static struct irq_chip mpc52xx_mainirq_irqchip = {
+	.typename = " MPC52xx IRQ[1-3] ",
+	.mask = mpc52xx_mainirq_mask,
+	.unmask = mpc52xx_mainirq_unmask,
+	.ack = mpc52xx_mainirq_ack,
+};
+
+/*
+ * Main interrupt irq_chip
+*/
+
+static void mpc52xx_main_mask(unsigned int virq)
+{
+	u32 val;
+	int irq;
+	int l2irq;
+
+	irq = irq_map[virq].hwirq;
+	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
+
+	pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
+
+	val = in_be32(&intr->main_mask);
+	val |= 1 << (16 - l2irq);
+	out_be32(&intr->main_mask, val);
+}
+
+static void mpc52xx_main_unmask(unsigned int virq)
+{
+	u32 val;
+	int irq;
+	int l2irq;
+
+	irq = irq_map[virq].hwirq;
+	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
+
+	pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
+
+	val = in_be32(&intr->main_mask);
+	val &= ~(1 << (16 - l2irq));
+	out_be32(&intr->main_mask, val);
+}
+
+static struct irq_chip mpc52xx_main_irqchip = {
+	.typename = "MPC52xx Main",
+	.mask = mpc52xx_main_mask,
+	.unmask = mpc52xx_main_unmask,
+	.ack = mpc52xx_voidfunc,
+};
+
+/*
+ * Peripherals interrupt irq_chip
+*/
+
+static void mpc52xx_periph_mask(unsigned int virq)
+{
+	u32 val;
+	int irq;
+	int l2irq;
+
+	irq = irq_map[virq].hwirq;
+	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
+
+	pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
+
+	val = in_be32(&intr->per_mask);
+	val |= 1 << (31 - l2irq);
+	out_be32(&intr->per_mask, val);
+}
+
+static void mpc52xx_periph_unmask(unsigned int virq)
+{
+	u32 val;
+	int irq;
+	int l2irq;
+
+	irq = irq_map[virq].hwirq;
+	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
+
+	pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
+
+	val = in_be32(&intr->per_mask);
+	val &= ~(1 << (31 - l2irq));
+	out_be32(&intr->per_mask, val);
+}
+
+static struct irq_chip mpc52xx_periph_irqchip = {
+	.typename = "MPC52xx Peripherals",
+	.mask = mpc52xx_periph_mask,
+	.unmask = mpc52xx_periph_unmask,
+	.ack = mpc52xx_voidfunc,
+};
+
+/*
+ * SDMA interrupt irq_chip
+*/
+
+static void mpc52xx_sdma_mask(unsigned int virq)
+{
+	u32 val;
+	int irq;
+	int l2irq;
+
+	irq = irq_map[virq].hwirq;
+	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
+
+	pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
+
+	val = in_be32(&sdma->IntMask);
+	val |= 1 << l2irq;
+	out_be32(&sdma->IntMask, val);
+}
+
+static void mpc52xx_sdma_unmask(unsigned int virq)
+{
+	u32 val;
+	int irq;
+	int l2irq;
+
+	irq = irq_map[virq].hwirq;
+	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
+
+	pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
+
+	val = in_be32(&sdma->IntMask);
+	val &= ~(1 << l2irq);
+	out_be32(&sdma->IntMask, val);
+}
+
+static void mpc52xx_sdma_ack(unsigned int virq)
+{
+	int irq;
+	int l2irq;
+
+	irq = irq_map[virq].hwirq;
+	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
+
+	pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
+
+	out_be32(&sdma->IntPend, 1 << l2irq);
+}
+
+static struct irq_chip mpc52xx_sdma_irqchip = {
+	.typename = "MPC52xx SDMA",
+	.mask = mpc52xx_sdma_mask,
+	.unmask = mpc52xx_sdma_unmask,
+	.ack = mpc52xx_sdma_ack,
+};
+
+/*
+ * irq_host
+*/
+
+static int mpc52xx_irqhost_match(struct irq_host *h, struct device_node *node)
+{
+	pr_debug("%s: %p vs %p\n", __func__, find_mpc52xx_picnode(), node);
+	return mpc52xx_irqhost->host_data == node;
+}
+
+static int mpc52xx_irqhost_xlate(struct irq_host *h, struct device_node *ct,
+				 u32 * intspec, unsigned int intsize,
+				 irq_hw_number_t * out_hwirq,
+				 unsigned int *out_flags)
+{
+	int intrvect_l1;
+	int intrvect_l2;
+	int intrvect_type;
+	int intrvect_linux;
+
+	if (intsize != 3)
+		return -1;
+
+	intrvect_l1 = (int)intspec[0];
+	intrvect_l2 = (int)intspec[1];
+	intrvect_type = (int)intspec[2];
+
+	intrvect_linux =
+	    (intrvect_l1 << MPC52xx_IRQ_L1_OFFSET) & MPC52xx_IRQ_L1_MASK;
+	intrvect_linux |=
+	    (intrvect_l2 << MPC52xx_IRQ_L2_OFFSET) & MPC52xx_IRQ_L2_MASK;
+
+	pr_debug("return %x, l1=%d, l2=%d\n", intrvect_linux, intrvect_l1,
+		 intrvect_l2);
+
+	*out_hwirq = intrvect_linux;
+	*out_flags = mpc52xx_map_senses[intrvect_type];
+
+	return 0;
+}
+
+/*
+ * this function retrieves the correct IRQ type out
+ * of the MPC regs
+ * Only externals IRQs needs this
+*/
+static int mpc52xx_irqx_gettype(int irq)
+{
+	int type;
+	u32 ctrl_reg;
+
+	ctrl_reg = in_be32(&intr->ctrl);
+	type = (ctrl_reg >> (24 - irq * 2)) & 0x3;
+
+	return mpc52xx_map_senses[type];
+}
+
+static int mpc52xx_irqhost_map(struct irq_host *h, unsigned int virq,
+			       irq_hw_number_t irq)
+{
+	int l1irq;
+	int l2irq;
+	struct irq_chip *good_irqchip;
+	void *good_handle;
+	int type;
+
+	l1irq = (irq & MPC52xx_IRQ_L1_MASK) >> MPC52xx_IRQ_L1_OFFSET;
+	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
+
+	/*
+	 * Most of ours IRQs will be level low
+	 * Only external IRQs on some platform may be others
+	 */
+	type = IRQ_TYPE_LEVEL_LOW;
+
+	switch (l1irq) {
+	case MPC52xx_IRQ_L1_CRIT:
+		pr_debug("%s: Critical. l2=%x\n", __func__, l2irq);
+
+		if (l2irq != 0)
+			BUG();
+
+		type = mpc52xx_irqx_gettype(l2irq);
+		good_irqchip = &mpc52xx_crit_irqchip;
+		break;
+
+	case MPC52xx_IRQ_L1_MAIN:
+		pr_debug("%s: Main IRQ[1-3] l2=%x\n", __func__, l2irq);
+
+		if ((l2irq >= 0) && (l2irq <= 3)) {
+			type = mpc52xx_irqx_gettype(l2irq);
+			good_irqchip = &mpc52xx_mainirq_irqchip;
+		} else {
+			good_irqchip = &mpc52xx_main_irqchip;
+		}
+		break;
+
+	case MPC52xx_IRQ_L1_PERP:
+		pr_debug("%s: Peripherals. l2=%x\n", __func__, l2irq);
+		good_irqchip = &mpc52xx_periph_irqchip;
+		break;
+
+	case MPC52xx_IRQ_L1_SDMA:
+		pr_debug("%s: SDMA. l2=%x\n", __func__, l2irq);
+		good_irqchip = &mpc52xx_sdma_irqchip;
+		break;
+
+	default:
+		pr_debug("%s: Error, unknown L1 IRQ (0x%x)\n", __func__, l1irq);
+		printk(KERN_ERR "Unknow IRQ!\n");
+		return -EINVAL;
+	}
+
+	switch (type) {
+	case IRQ_TYPE_EDGE_FALLING:
+	case IRQ_TYPE_EDGE_RISING:
+		good_handle = handle_edge_irq;
+		break;
+	default:
+		good_handle = handle_level_irq;
+	}
+
+	set_irq_chip_and_handler(virq, good_irqchip, good_handle);
+	set_irq_type(virq, type);
+
+	pr_debug("%s: virq=%x, hw=%x. type=%x\n", __func__, virq,
+		 (int)irq, type);
+
+	return 0;
+}
+
+static struct irq_host_ops mpc52xx_irqhost_ops = {
+	.match = mpc52xx_irqhost_match,
+	.xlate = mpc52xx_irqhost_xlate,
+	.map = mpc52xx_irqhost_map,
+};
+
+/*
+ * init (public)
+*/
+
+void __init mpc52xx_init_irq(void)
+{
+	u32 intr_ctrl;
+
+	/* Remap the necessary zones */
+	intr = ioremap(MPC52xx_PA(MPC52xx_INTR_OFFSET), MPC52xx_INTR_SIZE);
+	sdma = ioremap(MPC52xx_PA(MPC52xx_SDMA_OFFSET), MPC52xx_SDMA_SIZE);
+
+	if ((intr == NULL) || (sdma == NULL))
+		panic("Can't ioremap PIC/SDMA register or init_irq !");
+
+	/* Disable all interrupt sources. */
+	out_be32(&sdma->IntPend, 0xffffffff);	/* 1 means clear pending */
+	out_be32(&sdma->IntMask, 0xffffffff);	/* 1 means disabled */
+	out_be32(&intr->per_mask, 0x7ffffc00);	/* 1 means disabled */
+	out_be32(&intr->main_mask, 0x00010fff);	/* 1 means disabled */
+	intr_ctrl = in_be32(&intr->ctrl);
+	intr_ctrl &= 0x00ff0000;	/* Keeps IRQ[0-3] config */
+	intr_ctrl |= 0x0f000000 |	/* clear IRQ 0-3 */
+	    0x00001000 |	/* MEE master external enable */
+	    0x00000000 |	/* 0 means disable IRQ 0-3 */
+	    0x00000001;		/* CEb route critical normally */
+	out_be32(&intr->ctrl, intr_ctrl);
+
+	/* Zero a bunch of the priority settings.  */
+	out_be32(&intr->per_pri1, 0);
+	out_be32(&intr->per_pri2, 0);
+	out_be32(&intr->per_pri3, 0);
+	out_be32(&intr->main_pri1, 0);
+	out_be32(&intr->main_pri2, 0);
+
+	/*
+	 * As last step, add an irq host to translate the real
+	 * hw irq information provided by the ofw to linux virq
+	 */
+
+	mpc52xx_irqhost =
+	    irq_alloc_host(IRQ_HOST_MAP_LINEAR, 0xd0,
+			   &mpc52xx_irqhost_ops, -1);
+
+	if (mpc52xx_irqhost)
+		mpc52xx_irqhost->host_data = (void *)find_mpc52xx_picnode();
+}
+
+/*
+ * get_irq (public)
+*/
+unsigned int mpc52xx_get_irq(void)
+{
+	u32 status;
+	int irq = NO_IRQ_IGNORE;
+
+	status = in_be32(&intr->enc_status);
+	if (status & 0x00000400) {	/* critical */
+		irq = (status >> 8) & 0x3;
+		if (irq == 2)	/* high priority peripheral */
+			goto peripheral;
+		irq |=
+		    (MPC52xx_IRQ_L1_CRIT << MPC52xx_IRQ_L1_OFFSET) &
+		    MPC52xx_IRQ_L1_MASK;
+	} else if (status & 0x00200000) {	/* main */
+		irq = (status >> 16) & 0x1f;
+		if (irq == 4)	/* low priority peripheral */
+			goto peripheral;
+		irq |=
+		    (MPC52xx_IRQ_L1_MAIN << MPC52xx_IRQ_L1_OFFSET) &
+		    MPC52xx_IRQ_L1_MASK;
+	} else if (status & 0x20000000) {	/* peripheral */
+	      peripheral:
+		irq = (status >> 24) & 0x1f;
+		if (irq == 0) {	/* bestcomm */
+			status = in_be32(&sdma->IntPend);
+			irq = ffs(status) - 1;
+			irq |=
+			    (MPC52xx_IRQ_L1_SDMA << MPC52xx_IRQ_L1_OFFSET) &
+			    MPC52xx_IRQ_L1_MASK;
+		} else
+			irq |=
+			    (MPC52xx_IRQ_L1_PERP << MPC52xx_IRQ_L1_OFFSET) &
+			    MPC52xx_IRQ_L1_MASK;
+
+	}
+
+	pr_debug("%s: irq=%x. virq=%d\n", __func__, irq,
+		 irq_linear_revmap(mpc52xx_irqhost, irq));
+
+	return irq_linear_revmap(mpc52xx_irqhost, irq);
+}
--- a/arch/powerpc/sysdev/Makefile	2006-10-29 20:07:28.000000000 +0100
+++ b/arch/powerpc/sysdev/Makefile	2009-10-29 23:06:19.000000000 +0100
@@ -13,6 +13,7 @@ obj-$(CONFIG_FSL_SOC)		+= fsl_soc.o
 obj-$(CONFIG_PPC_TODC)		+= todc.o
 obj-$(CONFIG_TSI108_BRIDGE)	+= tsi108_pci.o tsi108_dev.o
 obj-$(CONFIG_QUICC_ENGINE)	+= qe_lib/
+obj-$(CONFIG_PPC_MPC52xx_PIC)	+= mpc52xx_pic.o
 
 ifeq ($(CONFIG_PPC_MERGE),y)
 obj-$(CONFIG_PPC_I8259)		+= i8259.o
--- a/include/asm-powerpc/mpc52xx.h	1970-01-01 01:00:00.000000000 +0100
+++ b/include/asm-powerpc/mpc52xx.h	2009-10-29 22:27:13.000000000 +0100
@@ -0,0 +1,367 @@
+/*
+ * include/asm-powerpc/mpc52xx.h
+ * 
+ * Prototypes, etc. for the Freescale MPC52xx embedded cpu chips
+ * May need to be cleaned as the port goes on ...
+ *
+ * Copyright (C) 2006 bplan GmbH
+ *
+ * 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 __ASM_POWERPC_MPC52xx_H__
+#define __ASM_POWERPC_MPC52xx_H__
+
+#ifndef __ASSEMBLY__
+#include <asm/types.h>
+#include <asm/prom.h>
+
+#endif				/* __ASSEMBLY__ */
+
+#define PCI_DRAM_OFFSET 0
+#define _IO_BASE        0
+#define _ISA_MEM_BASE   0
+
+/* ======================================================================== */
+/* Main registers/struct addresses                                          */
+/* ======================================================================== */
+
+/* MBAR position */
+#define MPC52xx_MBAR		0xf0000000	/* Phys address */
+#define MPC52xx_MBAR_VIRT	0xf0000000	/* Virt address */
+#define MPC52xx_MBAR_SIZE	0x00010000
+
+#define MPC52xx_PA(x)		((phys_addr_t)(MPC52xx_MBAR + (x)))
+#define MPC52xx_VA(x)		((void __iomem *)(MPC52xx_MBAR_VIRT + (x)))
+
+/* Registers zone offset/size  */
+#define MPC52xx_MMAP_CTL_OFFSET		0x0000
+#define MPC52xx_MMAP_CTL_SIZE		0x068
+#define MPC52xx_SDRAM_OFFSET		0x0100
+#define MPC52xx_SDRAM_SIZE		0x010
+#define MPC52xx_CDM_OFFSET		0x0200
+#define MPC52xx_CDM_SIZE		0x038
+#define MPC52xx_INTR_OFFSET		0x0500
+#define MPC52xx_INTR_SIZE		0x04c
+#define MPC52xx_GPTx_OFFSET(x)		(0x0600 + ((x)<<4))
+#define MPC52xx_GPT_SIZE		0x010
+#define MPC52xx_RTC_OFFSET		0x0800
+#define MPC52xx_RTC_SIZE		0x024
+#define MPC52xx_GPIO_OFFSET		0x0b00
+#define MPC52xx_GPIO_SIZE		0x040
+#define MPC52xx_GPIO_WKUP_OFFSET	0x0c00
+#define MPC52xx_GPIO_WKUP_SIZE		0x028
+#define MPC52xx_PCI_OFFSET		0x0d00
+#define MPC52xx_PCI_SIZE		0x100
+#define MPC52xx_SDMA_OFFSET		0x1200
+#define MPC52xx_SDMA_SIZE		0x100
+#define MPC52xx_XLB_OFFSET		0x1f00
+#define MPC52xx_XLB_SIZE		0x100
+#define MPC52xx_PSCx_OFFSET(x)		(((x)!=6)?(0x1e00+((x)<<9)):0x2c00)
+#define MPC52xx_PSC_SIZE		0x0a0
+
+/* SRAM used for SDMA */
+#define MPC52xx_SRAM_OFFSET		0x8000
+#define MPC52xx_SRAM_SIZE		0x4000
+
+/* ======================================================================== */
+/* IRQ mapping                                                              */
+/* ======================================================================== */
+
+#define MPC52xx_IRQ_L1_CRIT	(0)
+#define MPC52xx_IRQ_L1_MAIN	(1)
+#define MPC52xx_IRQ_L1_PERP	(2)
+#define MPC52xx_IRQ_L1_SDMA	(3)
+
+#define MPC52xx_IRQ_L1_OFFSET   (6)
+#define MPC52xx_IRQ_L1_MASK     (0x00c0)
+
+#define MPC52xx_IRQ_L2_OFFSET   (0)
+#define MPC52xx_IRQ_L2_MASK     (0x003f)
+
+/*
+ * 24 peripherals ints
+ * + 16 mains ints
+ * + 4 crit
+ * + 16 bestcomm task
+ * = 64
+*/
+#define MPC52xx_IRQ_MAXCOUNT     (64)
+
+/* ======================================================================== */
+/* Structures mapping of some unit register set                             */
+/* ======================================================================== */
+
+#ifndef __ASSEMBLY__
+
+/* Memory Mapping Control */
+struct mpc52xx_mmap_ctl {
+	u32 mbar;		/* MMAP_CTRL + 0x00 */
+
+	u32 cs0_start;		/* MMAP_CTRL + 0x04 */
+	u32 cs0_stop;		/* MMAP_CTRL + 0x08 */
+	u32 cs1_start;		/* MMAP_CTRL + 0x0c */
+	u32 cs1_stop;		/* MMAP_CTRL + 0x10 */
+	u32 cs2_start;		/* MMAP_CTRL + 0x14 */
+	u32 cs2_stop;		/* MMAP_CTRL + 0x18 */
+	u32 cs3_start;		/* MMAP_CTRL + 0x1c */
+	u32 cs3_stop;		/* MMAP_CTRL + 0x20 */
+	u32 cs4_start;		/* MMAP_CTRL + 0x24 */
+	u32 cs4_stop;		/* MMAP_CTRL + 0x28 */
+	u32 cs5_start;		/* MMAP_CTRL + 0x2c */
+	u32 cs5_stop;		/* MMAP_CTRL + 0x30 */
+
+	u32 sdram0;		/* MMAP_CTRL + 0x34 */
+	u32 sdram1;		/* MMAP_CTRL + 0X38 */
+
+	u32 reserved[4];	/* MMAP_CTRL + 0x3c .. 0x48 */
+
+	u32 boot_start;		/* MMAP_CTRL + 0x4c */
+	u32 boot_stop;		/* MMAP_CTRL + 0x50 */
+
+	u32 ipbi_ws_ctrl;	/* MMAP_CTRL + 0x54 */
+
+	u32 cs6_start;		/* MMAP_CTRL + 0x58 */
+	u32 cs6_stop;		/* MMAP_CTRL + 0x5c */
+	u32 cs7_start;		/* MMAP_CTRL + 0x60 */
+	u32 cs7_stop;		/* MMAP_CTRL + 0x64 */
+};
+
+/* SDRAM control */
+struct mpc52xx_sdram {
+	u32 mode;		/* SDRAM + 0x00 */
+	u32 ctrl;		/* SDRAM + 0x04 */
+	u32 config1;		/* SDRAM + 0x08 */
+	u32 config2;		/* SDRAM + 0x0c */
+};
+
+/* Interrupt controller */
+struct mpc52xx_intr {
+	u32 per_mask;		/* INTR + 0x00 */
+	u32 per_pri1;		/* INTR + 0x04 */
+	u32 per_pri2;		/* INTR + 0x08 */
+	u32 per_pri3;		/* INTR + 0x0c */
+	u32 ctrl;		/* INTR + 0x10 */
+	u32 main_mask;		/* INTR + 0x14 */
+	u32 main_pri1;		/* INTR + 0x18 */
+	u32 main_pri2;		/* INTR + 0x1c */
+	u32 reserved1;		/* INTR + 0x20 */
+	u32 enc_status;		/* INTR + 0x24 */
+	u32 crit_status;	/* INTR + 0x28 */
+	u32 main_status;	/* INTR + 0x2c */
+	u32 per_status;		/* INTR + 0x30 */
+	u32 reserved2;		/* INTR + 0x34 */
+	u32 per_error;		/* INTR + 0x38 */
+};
+
+/* SDMA */
+struct mpc52xx_sdma {
+	u32 taskBar;		/* SDMA + 0x00 */
+	u32 currentPointer;	/* SDMA + 0x04 */
+	u32 endPointer;		/* SDMA + 0x08 */
+	u32 variablePointer;	/* SDMA + 0x0c */
+
+	u8 IntVect1;		/* SDMA + 0x10 */
+	u8 IntVect2;		/* SDMA + 0x11 */
+	u16 PtdCntrl;		/* SDMA + 0x12 */
+
+	u32 IntPend;		/* SDMA + 0x14 */
+	u32 IntMask;		/* SDMA + 0x18 */
+
+	u16 tcr[16];		/* SDMA + 0x1c .. 0x3a */
+
+	u8 ipr[32];		/* SDMA + 0x3c .. 0x5b */
+
+	u32 cReqSelect;		/* SDMA + 0x5c */
+	u32 task_size0;		/* SDMA + 0x60 */
+	u32 task_size1;		/* SDMA + 0x64 */
+	u32 MDEDebug;		/* SDMA + 0x68 */
+	u32 ADSDebug;		/* SDMA + 0x6c */
+	u32 Value1;		/* SDMA + 0x70 */
+	u32 Value2;		/* SDMA + 0x74 */
+	u32 Control;		/* SDMA + 0x78 */
+	u32 Status;		/* SDMA + 0x7c */
+	u32 PTDDebug;		/* SDMA + 0x80 */
+};
+
+/* GPT */
+struct mpc52xx_gpt {
+	u32 mode;		/* GPTx + 0x00 */
+	u32 count;		/* GPTx + 0x04 */
+	u32 pwm;		/* GPTx + 0x08 */
+	u32 status;		/* GPTx + 0X0c */
+};
+
+/* RTC */
+struct mpc52xx_rtc {
+	u32 time_set;		/* RTC + 0x00 */
+	u32 date_set;		/* RTC + 0x04 */
+	u32 stopwatch;		/* RTC + 0x08 */
+	u32 int_enable;		/* RTC + 0x0c */
+	u32 time;		/* RTC + 0x10 */
+	u32 date;		/* RTC + 0x14 */
+	u32 stopwatch_intr;	/* RTC + 0x18 */
+	u32 bus_error;		/* RTC + 0x1c */
+	u32 dividers;		/* RTC + 0x20 */
+};
+
+/* GPIO */
+struct mpc52xx_gpio {
+	u32 port_config;	/* GPIO + 0x00 */
+	u32 simple_gpioe;	/* GPIO + 0x04 */
+	u32 simple_ode;		/* GPIO + 0x08 */
+	u32 simple_ddr;		/* GPIO + 0x0c */
+	u32 simple_dvo;		/* GPIO + 0x10 */
+	u32 simple_ival;	/* GPIO + 0x14 */
+	u8 outo_gpioe;		/* GPIO + 0x18 */
+	u8 reserved1[3];	/* GPIO + 0x19 */
+	u8 outo_dvo;		/* GPIO + 0x1c */
+	u8 reserved2[3];	/* GPIO + 0x1d */
+	u8 sint_gpioe;		/* GPIO + 0x20 */
+	u8 reserved3[3];	/* GPIO + 0x21 */
+	u8 sint_ode;		/* GPIO + 0x24 */
+	u8 reserved4[3];	/* GPIO + 0x25 */
+	u8 sint_ddr;		/* GPIO + 0x28 */
+	u8 reserved5[3];	/* GPIO + 0x29 */
+	u8 sint_dvo;		/* GPIO + 0x2c */
+	u8 reserved6[3];	/* GPIO + 0x2d */
+	u8 sint_inten;		/* GPIO + 0x30 */
+	u8 reserved7[3];	/* GPIO + 0x31 */
+	u16 sint_itype;		/* GPIO + 0x34 */
+	u16 reserved8;		/* GPIO + 0x36 */
+	u8 gpio_control;	/* GPIO + 0x38 */
+	u8 reserved9[3];	/* GPIO + 0x39 */
+	u8 sint_istat;		/* GPIO + 0x3c */
+	u8 sint_ival;		/* GPIO + 0x3d */
+	u8 bus_errs;		/* GPIO + 0x3e */
+	u8 reserved10;		/* GPIO + 0x3f */
+};
+
+#define MPC52xx_GPIO_PSC_CONFIG_UART_WITHOUT_CD	4
+#define MPC52xx_GPIO_PSC_CONFIG_UART_WITH_CD	5
+#define MPC52xx_GPIO_PCI_DIS			(1<<15)
+
+/* GPIO with WakeUp*/
+struct mpc52xx_gpio_wkup {
+	u8 wkup_gpioe;		/* GPIO_WKUP + 0x00 */
+	u8 reserved1[3];	/* GPIO_WKUP + 0x03 */
+	u8 wkup_ode;		/* GPIO_WKUP + 0x04 */
+	u8 reserved2[3];	/* GPIO_WKUP + 0x05 */
+	u8 wkup_ddr;		/* GPIO_WKUP + 0x08 */
+	u8 reserved3[3];	/* GPIO_WKUP + 0x09 */
+	u8 wkup_dvo;		/* GPIO_WKUP + 0x0C */
+	u8 reserved4[3];	/* GPIO_WKUP + 0x0D */
+	u8 wkup_inten;		/* GPIO_WKUP + 0x10 */
+	u8 reserved5[3];	/* GPIO_WKUP + 0x11 */
+	u8 wkup_iinten;		/* GPIO_WKUP + 0x14 */
+	u8 reserved6[3];	/* GPIO_WKUP + 0x15 */
+	u16 wkup_itype;		/* GPIO_WKUP + 0x18 */
+	u8 reserved7[2];	/* GPIO_WKUP + 0x1A */
+	u8 wkup_maste;		/* GPIO_WKUP + 0x1C */
+	u8 reserved8[3];	/* GPIO_WKUP + 0x1D */
+	u8 wkup_ival;		/* GPIO_WKUP + 0x20 */
+	u8 reserved9[3];	/* GPIO_WKUP + 0x21 */
+	u8 wkup_istat;		/* GPIO_WKUP + 0x24 */
+	u8 reserved10[3];	/* GPIO_WKUP + 0x25 */
+};
+
+/* XLB Bus control */
+struct mpc52xx_xlb {
+	u8 reserved[0x40];
+	u32 config;		/* XLB + 0x40 */
+	u32 version;		/* XLB + 0x44 */
+	u32 status;		/* XLB + 0x48 */
+	u32 int_enable;		/* XLB + 0x4c */
+	u32 addr_capture;	/* XLB + 0x50 */
+	u32 bus_sig_capture;	/* XLB + 0x54 */
+	u32 addr_timeout;	/* XLB + 0x58 */
+	u32 data_timeout;	/* XLB + 0x5c */
+	u32 bus_act_timeout;	/* XLB + 0x60 */
+	u32 master_pri_enable;	/* XLB + 0x64 */
+	u32 master_priority;	/* XLB + 0x68 */
+	u32 base_address;	/* XLB + 0x6c */
+	u32 snoop_window;	/* XLB + 0x70 */
+};
+
+#define MPC52xx_XLB_CFG_PLDIS		(1 << 31)
+#define MPC52xx_XLB_CFG_SNOOP		(1 << 15)
+
+/* Clock Distribution control */
+struct mpc52xx_cdm {
+	u32 jtag_id;		/* CDM + 0x00  reg0 read only */
+	u32 rstcfg;		/* CDM + 0x04  reg1 read only */
+	u32 breadcrumb;		/* CDM + 0x08  reg2 */
+
+	u8 mem_clk_sel;		/* CDM + 0x0c  reg3 byte0 */
+	u8 xlb_clk_sel;		/* CDM + 0x0d  reg3 byte1 read only */
+	u8 ipb_clk_sel;		/* CDM + 0x0e  reg3 byte2 */
+	u8 pci_clk_sel;		/* CDM + 0x0f  reg3 byte3 */
+
+	u8 ext_48mhz_en;	/* CDM + 0x10  reg4 byte0 */
+	u8 fd_enable;		/* CDM + 0x11  reg4 byte1 */
+	u16 fd_counters;	/* CDM + 0x12  reg4 byte2,3 */
+
+	u32 clk_enables;	/* CDM + 0x14  reg5 */
+
+	u8 osc_disable;		/* CDM + 0x18  reg6 byte0 */
+	u8 reserved0[3];	/* CDM + 0x19  reg6 byte1,2,3 */
+
+	u8 ccs_sleep_enable;	/* CDM + 0x1c  reg7 byte0 */
+	u8 osc_sleep_enable;	/* CDM + 0x1d  reg7 byte1 */
+	u8 reserved1;		/* CDM + 0x1e  reg7 byte2 */
+	u8 ccs_qreq_test;	/* CDM + 0x1f  reg7 byte3 */
+
+	u8 soft_reset;		/* CDM + 0x20  u8 byte0 */
+	u8 no_ckstp;		/* CDM + 0x21  u8 byte0 */
+	u8 reserved2[2];	/* CDM + 0x22  u8 byte1,2,3 */
+
+	u8 pll_lock;		/* CDM + 0x24  reg9 byte0 */
+	u8 pll_looselock;	/* CDM + 0x25  reg9 byte1 */
+	u8 pll_sm_lockwin;	/* CDM + 0x26  reg9 byte2 */
+	u8 reserved3;		/* CDM + 0x27  reg9 byte3 */
+
+	u16 reserved4;		/* CDM + 0x28  reg10 byte0,1 */
+	u16 mclken_div_psc1;	/* CDM + 0x2a  reg10 byte2,3 */
+
+	u16 reserved5;		/* CDM + 0x2c  reg11 byte0,1 */
+	u16 mclken_div_psc2;	/* CDM + 0x2e  reg11 byte2,3 */
+
+	u16 reserved6;		/* CDM + 0x30  reg12 byte0,1 */
+	u16 mclken_div_psc3;	/* CDM + 0x32  reg12 byte2,3 */
+
+	u16 reserved7;		/* CDM + 0x34  reg13 byte0,1 */
+	u16 mclken_div_psc6;	/* CDM + 0x36  reg13 byte2,3 */
+};
+
+#endif				/* __ASSEMBLY__ */
+
+/* ========================================================================= */
+/* Prototypes for MPC52xx syslib                                             */
+/* ========================================================================= */
+
+#ifndef __ASSEMBLY__
+
+extern void mpc52xx_init_irq(void);
+extern unsigned int mpc52xx_get_irq(void);
+
+static inline struct device_node *find_mpc52xx_picnode(void)
+{
+	return of_find_compatible_node(NULL, "interrupt-controller",
+				       "mpc5200-pic");
+}
+
+	/* Matching of PSC function */
+struct mpc52xx_psc_func {
+	int id;
+	char *func;
+};
+
+extern int mpc52xx_match_psc_function(int psc_idx, const char *func);
+extern struct mpc52xx_psc_func mpc52xx_psc_functions[];
+	/* This array is to be defined in platform file */
+
+#endif				/* __ASSEMBLY__ */
+
+#endif				/* _ASM_POWERPC_MPC52xx_H__ */

^ permalink raw reply

* [PATCH 2/2] Add Efika support as a new platform
From: Nicolas DET @ 2006-10-29 23:11 UTC (permalink / raw)
  To: linuxppc-embedded; +Cc: sl, sha, linuxppc-dev

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

This patch add Efika (http://www.bplan-gmbh.de/efika_spec_en.html) support as a
new platform for ARCH=powerpc

It patches arch/powerpc/Kconfig and arch/powerpc/platform/Makefile and add
arch/powerpc/platforms/efika.h setup.c pci.c and Makefile.c

Signed-off-by: Nicolas DET <nd@bplan-gmbh.de>

[-- Attachment #2: archpowerpc_efika.patch --]
[-- Type: application/octet-stream, Size: 8619 bytes --]

--- a/arch/powerpc/platforms/efika/setup.c	1970-01-01 01:00:00.000000000 +0100
+++ b/arch/powerpc/platforms/efika/setup.c	2009-10-29 22:08:31.000000000 +0100
@@ -0,0 +1,145 @@
+/*
+ *
+ * Efika 5K2 platform setup
+ * 
+ * Copyright (C) 2006 bplan GmbH
+ * 
+ * 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.
+ *
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/user.h>
+#include <linux/interrupt.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/utsrelease.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/console.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+#include <linux/initrd.h>
+#include <linux/module.h>
+#include <linux/timer.h>
+
+#include <asm/pgtable.h>
+#include <asm/prom.h>
+#include <asm/dma.h>
+#include <asm/machdep.h>
+#include <asm/irq.h>
+#include <asm/sections.h>
+#include <asm/time.h>
+#include <asm/rtas.h>
+#include <asm/mpc52xx.h>
+
+#include "efika.h"
+
+void rtas_indicator_progress(char *, unsigned short);
+
+extern unsigned long loops_per_jiffy;
+
+static void efika_show_cpuinfo(struct seq_file *m)
+{
+	struct device_node *root;
+	const char *revision = NULL;
+	const char *codegendescription = NULL;
+	const char *codegenvendor = NULL;
+
+	root = find_path_device("/");
+	if (root) {
+		revision = get_property(root, "revision", NULL);
+		codegendescription =
+		    get_property(root, "CODEGEN,description", NULL);
+		codegenvendor = get_property(root, "CODEGEN,vendor", NULL);
+	}
+
+	if (codegendescription)
+		seq_printf(m, "machine\t\t: %s\n", codegendescription);
+	else
+		seq_printf(m, "machine\t\t: Efika\n");
+
+	if (revision)
+		seq_printf(m, "revision\t: %s\n", revision);
+
+	if (codegenvendor)
+		seq_printf(m, "vendor\t\t: %s\n", codegenvendor);
+}
+
+static void __init efika_setup_arch(void)
+{
+	/* init to some ~sane value until calibrate_delay() runs */
+	loops_per_jiffy = 50000000 / HZ;
+
+	rtas_initialize();
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	initrd_below_start_ok = 1;
+
+	if (initrd_start)
+		ROOT_DEV = Root_RAM0;
+	else
+#endif
+		ROOT_DEV = Root_SDA2;	/* sda2 (sda1 is for the kernel) */
+
+	pci_create_OF_bus_map();
+
+	efika_pcisetup();
+
+	if (ppc_md.progress)
+		ppc_md.progress("Linux/PPC " UTS_RELEASE " runnung on Efika ;-)\n", 0x0);
+}
+
+static void __init efika_init_IRQ(void)
+{
+	mpc52xx_init_irq();
+}
+
+static void __init efika_init(void)
+{
+	if (ppc_md.progress)
+		ppc_md.progress("  Have fun with your Efika!    ", 0x7777);
+}
+
+static int __init efika_probe(void)
+{
+	char *model = of_get_flat_dt_prop(of_get_flat_dt_root(),
+					  "model", NULL);
+
+	if (model == NULL)
+		return 0;
+	if (strcmp(model, "EFIKA5K2"))
+		return 0;
+
+	ISA_DMA_THRESHOLD = ~0L;
+	DMA_MODE_READ = 0x44;
+	DMA_MODE_WRITE = 0x48;
+
+	return 1;
+}
+
+define_machine(efika)
+{
+	.name = EFIKA_PLATFORM_NAME,
+	.probe = efika_probe,
+	.setup_arch = efika_setup_arch,
+	.init = efika_init,
+	.show_cpuinfo = efika_show_cpuinfo,
+	.init_IRQ = efika_init_IRQ,
+	.get_irq = mpc52xx_get_irq,
+	.restart = rtas_restart,
+	.power_off = rtas_power_off,
+	.halt = rtas_halt,
+	.set_rtc_time = rtas_set_rtc_time,
+	.get_rtc_time = rtas_get_rtc_time,
+	.progress = rtas_progress,
+	.get_boot_time = rtas_get_boot_time,
+	.calibrate_decr = generic_calibrate_decr,
+	.phys_mem_access_prot = pci_phys_mem_access_prot,
+};
--- a/arch/powerpc/platforms/efika/pci.c	1970-01-01 01:00:00.000000000 +0100
+++ b/arch/powerpc/platforms/efika/pci.c	2009-10-29 22:08:31.000000000 +0100
@@ -0,0 +1,118 @@
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/irq.h>
+#include <asm/hydra.h>
+#include <asm/prom.h>
+#include <asm/gg2.h>
+#include <asm/machdep.h>
+#include <asm/sections.h>
+#include <asm/pci-bridge.h>
+#include <asm/grackle.h>
+#include <asm/rtas.h>
+
+#include "efika.h"
+
+/*
+ * Access functions for PCI config space using RTAS calls.
+ */
+static int rtas_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
+			    int len, u32 * val)
+{
+	struct pci_controller *hose = bus->sysdata;
+	unsigned long addr = (offset & 0xff) | ((devfn & 0xff) << 8)
+	    | (((bus->number - hose->first_busno) & 0xff) << 16)
+	    | (hose->index << 24);
+	int ret = -1;
+	int rval;
+
+	rval = rtas_call(rtas_token("read-pci-config"), 2, 2, &ret, addr, len);
+	*val = ret;
+	return rval ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
+}
+
+static int rtas_write_config(struct pci_bus *bus, unsigned int devfn,
+			     int offset, int len, u32 val)
+{
+	struct pci_controller *hose = bus->sysdata;
+	unsigned long addr = (offset & 0xff) | ((devfn & 0xff) << 8)
+	    | (((bus->number - hose->first_busno) & 0xff) << 16)
+	    | (hose->index << 24);
+	int rval;
+
+	rval = rtas_call(rtas_token("write-pci-config"), 3, 1, NULL,
+			 addr, len, val);
+	return rval ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops rtas_pci_ops = {
+	rtas_read_config,
+	rtas_write_config
+};
+
+void __init efika_pcisetup(void)
+{
+	const int *bus_range;
+	int len;
+	struct pci_controller *hose;
+	struct device_node *root;
+	struct device_node *dev;
+
+	root = of_find_node_by_path("/");
+	if (root == NULL) {
+		printk(KERN_WARNING EFIKA_PLATFORM_NAME
+		       ": Unable to find the root node\n");
+		return;
+	}
+
+	for (dev = NULL;;) {
+		dev = of_get_next_child(root, dev);
+		if ((dev == NULL) || (strcmp(dev->name, "pci") == 0))
+			break;
+	}
+
+	if (dev == NULL) {
+		printk(KERN_WARNING EFIKA_PLATFORM_NAME
+		       ": Unable to find the PCI bridge node\n");
+		return;
+	}
+
+	bus_range = get_property(dev, "bus-range", &len);
+	if (bus_range == NULL || len < 2 * sizeof(int)) {
+		printk(KERN_WARNING EFIKA_PLATFORM_NAME
+		       ": Can't get bus-range for %s\n", dev->full_name);
+		return;
+	}
+	if (bus_range[1] == bus_range[0])
+		printk(KERN_INFO EFIKA_PLATFORM_NAME ": PCI bus %d",
+		       bus_range[0]);
+	else
+		printk(KERN_INFO EFIKA_PLATFORM_NAME ": PCI buses %d..%d",
+		       bus_range[0], bus_range[1]);
+	printk(" controlled by %s", dev->full_name);
+	printk("\n");
+
+	hose = pcibios_alloc_controller();
+	if (!hose) {
+		printk(KERN_WARNING EFIKA_PLATFORM_NAME
+		       ": Can't allocate PCI controller structure for %s\n",
+		       dev->full_name);
+		return;
+	}
+
+	hose->arch_data = dev;
+	hose->first_busno = bus_range[0];
+	hose->last_busno = bus_range[1];
+	hose->ops = &rtas_pci_ops;
+
+	pci_process_bridge_OF_ranges(hose, dev, 1);
+
+	printk(KERN_INFO EFIKA_PLATFORM_NAME ": PCI bus setup done\n");
+}
--- a/arch/powerpc/platforms/efika/efika.h	1970-01-01 01:00:00.000000000 +0100
+++ b/arch/powerpc/platforms/efika/efika.h	2009-10-29 22:08:31.000000000 +0100
@@ -0,0 +1,19 @@
+/*
+ * Efika 5K2 platform setup - Header file
+ *
+ * Copyright (C) 2006 bplan GmbH
+ *
+ * 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 __ARCH_POWERPC_EFIKA__
+#define __ARCH_POWERPC_EFIKA__
+
+#define EFIKA_PLATFORM_NAME "Efika"
+
+void __init efika_pcisetup(void);
+
+#endif
--- a/arch/powerpc/platforms/efika/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ b/arch/powerpc/platforms/efika/Makefile	2009-10-29 22:14:59.000000000 +0100
@@ -0,0 +1 @@
+obj-y += setup.o pci.o
--- a/arch/powerpc/platforms/Makefile	2006-10-29 20:07:27.000000000 +0100
+++ b/arch/powerpc/platforms/Makefile	2009-10-29 22:08:31.000000000 +0100
@@ -6,6 +6,7 @@ obj-$(CONFIG_PPC_PMAC)		+= powermac/
 endif
 endif
 obj-$(CONFIG_PPC_CHRP)		+= chrp/
+obj-$(CONFIG_PPC_EFIKA)		+= efika/
 obj-$(CONFIG_4xx)		+= 4xx/
 obj-$(CONFIG_PPC_83xx)		+= 83xx/
 obj-$(CONFIG_PPC_85xx)		+= 85xx/
--- a/arch/powerpc/Kconfig	2006-10-29 20:07:27.000000000 +0100
+++ b/arch/powerpc/Kconfig	2009-10-29 22:14:00.000000000 +0100
@@ -386,6 +386,19 @@ config PPC_CHRP
 	select PPC_UDBG_16550
 	default y
 
+config PPC_MPC52xx_PIC
+        bool
+	default y
+
+config PPC_EFIKA
+	bool "bPlan Efika 5k2. MPC5200B based computer"
+	depends on PPC_MULTIPLATFORM && PPC32
+	select PPC_RTAS
+	select RTAS_PROC
+	select PPC_MPC52xx
+	select PPC_MPC52xx_PIC
+	default y
+
 config PPC_PMAC
 	bool "Apple PowerMac based machines"
 	depends on PPC_MULTIPLATFORM

^ permalink raw reply

* Re: glibc-2.5 test suite hangs/crashes the machine
From: Benjamin Herrenschmidt @ 2006-10-30  1:47 UTC (permalink / raw)
  To: Jeff Bailey
  Cc: linuxppc-dev, Fabio Massimo Di Nitto, Paul Mackerras,
	Steve Munroe, Ben Collins
In-Reply-To: <1161966154.18515.1.camel@localhost.localdomain>

On Fri, 2006-10-27 at 12:22 -0400, Jeff Bailey wrote:
> Le vendredi 27 octobre 2006 à 07:56 +0200, Fabio Massimo Di Nitto a
> écrit :
> > Hi everybody,
> > 
> > i am in the process of bootstrapping the new toolchain for ubuntu and I am
> > hitting a problem building glibc-2.5 on ppc.
> > 
> > This behaviour has been reproduced on 2.6.15/2.6.17 and 2.6.19-rc2 (where the
> > machine crashes) and with ppc32 and ppc64 kernels.
> > A hard reboot of the machine is required to get rid of the Zl processes hanging
> > around that keep spinning the CPU at 100%.
> > 
> > I did place sources here: http://people.ubuntu.com/~fabbione/benh/
> > 
> > but i start to believe it is a kernel bug we are exploiting only now.
> > 
> > Any hint or help for what to look for would be extremely appreciated.
> 
> Heya Fabio, just an update, it looks like the tests that are zombie'ing
> are the nptl tst-robust[1-8] tests.  According to /proc/##/wchan, the
> tasks are cheerfully spinning in do_exit.

So I've built that glibc with debian 2.6.16 kernel headers (since Fabio
says the problem doesn't happen with glibc built with 2.6.19 headers)
and have ran that with 2.6.19-rc3-git-du-jour.

The machine didn't crash, nor did I see any zombie with those
tst-robust[1-8], however, I did get as SIGBUS with tst-robustpi1. I've
tracked it down to being an alignment exception. It looks like glibc is
doing a lwarx on a non-aligned value, though I can't say precisely
what's up here. I don't know how I can get a backtrace when running
those test-cases... the test harness seems to catch signals, I suppose
it could be modified to spit one out.

At this point, it would be useful to have somebody who knows glibc to
tell us:

 - what are those tst-robust all about ? (what do they do "special" that
might trigger bad reactions with older kernels)
 - how can glibc ever do atomic operations on a non-aligned value ?

Ben.

^ permalink raw reply

* unsubscribe
From: Usha Rani Konudula @ 2006-10-30  2:05 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: linuxppc-dev
In-Reply-To: <1162026503.14822.5.camel@localhost.localdomain>

unsubscribe

^ permalink raw reply

* Re: glibc-2.5 test suite hangs/crashes the machine
From: Benjamin Herrenschmidt @ 2006-10-30  3:02 UTC (permalink / raw)
  To: Fabio Massimo Di Nitto
  Cc: linuxppc-dev, Jeff Bailey, Paul Mackerras, Ben Collins
In-Reply-To: <45419F79.2020300@ubuntu.com>

Does that patch fixes it ?

Index: linux-work/arch/powerpc/kernel/traps.c
===================================================================
--- linux-work.orig/arch/powerpc/kernel/traps.c	2006-10-23 14:41:37.000000000 +1000
+++ linux-work/arch/powerpc/kernel/traps.c	2006-10-30 13:59:41.000000000 +1100
@@ -843,7 +843,7 @@ void __kprobes program_check_exception(s
 
 void alignment_exception(struct pt_regs *regs)
 {
-	int fixed = 0;
+	int sig, fixed = 0;
 
 	/* we don't implement logging of alignment exceptions */
 	if (!(current->thread.align_ctl & PR_UNALIGN_SIGBUS))
@@ -856,15 +856,11 @@ void alignment_exception(struct pt_regs 
 	}
 
 	/* Operand address was bad */
-	if (fixed == -EFAULT) {
-		if (user_mode(regs))
-			_exception(SIGSEGV, regs, SEGV_ACCERR, regs->dar);
-		else
-			/* Search exception table */
-			bad_page_fault(regs, regs->dar, SIGSEGV);
-		return;
-	}
-	_exception(SIGBUS, regs, BUS_ADRALN, regs->dar);
+	sig = fixed == -EFAULT ? SIGSEGV : SIGBUS;
+	if (user_mode(regs))
+		_exception(sig, regs, SEGV_ACCERR, regs->dar);
+	else
+		bad_page_fault(regs, regs->dar, sig);
 }
 
 void StackOverflow(struct pt_regs *regs)

^ permalink raw reply

* Re: [PATCH] qe_lib: Remove immrbar_virt_to_phys() function
From: Paul Mackerras @ 2006-10-30  3:21 UTC (permalink / raw)
  To: Li Yang; +Cc: linuxppc-dev
In-Reply-To: <453F44E6.8030706@freescale.com>

Li Yang writes:

> Remove private physical address mapping routine in qe_lib.  Users
> of qe_lib should use generic functions like iopa().
> The change also addresses a bug found by Timur Tabi that cmd_input
> got mapped in qe_issue_cmd().  It should be written to CECDR
> unmodified.

Do you mean that the argument to qe_issue_cmd is a physical address?
It seems to me that the bug fix you mention is the main thing the
patch does, and the removal of immrvar_virt_to_phys is a cleanup on
the side that is made possible by the bugfix.

Paul.

^ permalink raw reply

* Re: Building ELDK 3.0/3.1 from SRPMS
From: John W @ 2006-10-30  3:38 UTC (permalink / raw)
  To: Wolfgang Denk; +Cc: linuxppc-embedded
In-Reply-To: <20061027211942.B7FEB3535FD@atlas.denx.de>

Thanks Wolfgang!  Loading RH7.3 and updating
everything with YUM seemed to do the trick to building
ELDK 3.0!

On a another note, I am also trying to build ELDK
2.1.0 from SRPMS on the same RH7.3 machine, and I am
comming across two problems:
1.  The SRPM for mount-2.11g-5a.src.rpm from the
Yellowdog 2.3 release seems to have "bad magic" in
that when trying to install the SRPM, there is some
sort of validation problem.  In remeding this, I am
using mount-2.11g-5a.src.rpm from the Yellowdog 2.2
release.    It probably isn't safe to to so, but I was
wondering how you over came this issue.

2.  I'm pretty sure that not all of my applications
are building in the ELDK2.1.0 release,  for example
when I check out the log for
/build/ppc-2006-10-27/logs/ppc_4xx/build_modutils.log,
it has the following error:
gperf -a -C -E -g -H is_reserved_hash -k 1,3,$ -N
is_reserved_word -p -t keyword
s.gperf > keywords.c.tmp
/bin/sh: gperf: command not found
make[1]: *** [keywords.c] Error 127
make[1]: Leaving directory
`/opt/eldkv2.1.0/build/ppc-2006-10-27/work/usr/src/de
nx/BUILD/modutils-2.4.13/genksyms'
make: *** [all] Error 2
error: Bad exit status from
/opt/eldkv2.1.0/build/ppc-2006-10-27/work/var/tmp/rp
m-tmp.26616 (%build)

Does mean that I need to go get gperf?

Thanks for the help!

John Woo


--- Wolfgang Denk <wd@denx.de> wrote:

> Dear John,
> 
> in message
> <20061027182114.24662.qmail@web50315.mail.yahoo.com>
> you wrote:
> > 
> > I having trouble rebuilding ELDK 3.0 & ELDK 3.1
> from
> > the source RPMS.  I have spent a great deal of
> time on
> > this, and I have a feeling that maybe I=92m just
> not
> > doing something correctly (setting up the build
> > environment, retrieving source/specs from CVS..
> > etc..).  My build machine is Red Hat 9.0 without
> any
> > updates (Kernel 2.4.20-8, the Shrike release).
> 
> This will not work; to build ELDK 3.x from scratch
> you need a  RH-7.3
> box *with* all updates installed.
> 
> Best regards,
> 
> Wolfgang Denk
> 
> -- 
> Software Engineering:  Embedded and Realtime
> Systems,  Embedded Linux
> Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80
> Email: wd@denx.de
> e-credibility: the non-guaranteeable likelihood that
>  the  electronic
> data you're seeing is genuine rather than somebody's
> made-up crap.
> - Karl Lehenbauer
> 



 
____________________________________________________________________________________
Get your email and see which of your friends are online - Right on the New Yahoo.com 
(http://www.yahoo.com/preview) 

^ permalink raw reply

* Re: [RFC] bootwrapper: prevent fdt from being overwritten by kernel
From: Paul Mackerras @ 2006-10-30  4:16 UTC (permalink / raw)
  To: Mark A. Greer; +Cc: linuxppc-dev
In-Reply-To: <20061026225045.GA19839@mag.az.mvista.com>

Mark A. Greer writes:

> If the fdt that's wrapped in a zImage isn't edited, it will still be
> sitting in the zImage when the kernel boots
> (i.e., at 0x400000 + <some offset into the zImage>).
> 
> That's okay until you get a large enough kernel (e.g., initramfs)
> which will overwrite the fdt when the kernel is relocated to 0.

Oops :)

> To handle that, I changed the sandpoint.c:platform_init() to base the
> simple_alloc heap at the greater of either the end of the zImage or the end
> of the kernel once its decompressed & relocated to 0.  It then copies
> the dtb to an area allocated by simple_alloc so I know its safe from
> being overwritten.

That sounds reasonable.

> In addition, I moved the vmlinux elf header decompress code from
> prep_kernel() to its own routine and called it before platform_init.
> I then pass the elf header ptr into platform_init.  That way,
> platform_init can figure out where the end of the kernel will
> be and put the dtb beyond it.  The OF code can now change
> claim_base in platform_init instead of needing the platform_ops.image_hdr
> hook.

Hmmm.  What if platform_init needs to e.g. turn on caches or do other
things that need to be done before decompressing?  I think it's
important to provide some way for the platform code to do things
really early on.

Paul.

^ permalink raw reply

* [PATCH] powerpc: map 4K iommu pages even on 64K largepage systems
From: Benjamin Herrenschmidt @ 2006-10-30  5:15 UTC (permalink / raw)
  To: linuxppc-dev list; +Cc: Olof Johansson, Paul Mackerras

The 10Gigabit ethernet device drivers appear to be able to chew
up all 256MB of TCE mappings on pSeries systems, as evidenced by
numerous error messages:

 iommu_alloc failed, tbl c0000000010d5c48 vaddr c0000000d875eff0 npages 1

Some experimentaiton indicates that this is essentially because
one 1500 byte ethernet MTU gets mapped as a 64K DMA region when
the large 64K pages are enabled. Thus, it doesn't take much to
exhaust all of the available DMA mappings for a high-speed card.

This patch changes the iommu allocator to work with its own 
unique, distinct page size. Although the patch is long, its
actually quite simple: it just #defines  distinct IOMMU_PAGE_SIZE
and then uses this in al the places tha matter.

As a side effect , it also dramatically improves network performances
on platforms with H-calls on iommu translation inserts/removes (since
we no longer call it 16 times for a 1500 bytes packet when the iommu HW
is still 4k).

In the future, we might want to make the IOMMU_PAGE_SIZE a variable
in the iommu_table instance, thus allowing support for different HW
page sizes in the iommu itself.

Signed-off-by: Linas Vepstas <linas@austin.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---

iSeries friendly version of it. Needs to go to RHEL5 too.

Index: linux-cell/arch/powerpc/kernel/iommu.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/iommu.c	2006-10-09 12:03:33.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/iommu.c	2006-10-30 14:04:38.000000000 +1100
@@ -47,6 +47,17 @@ static int novmerge = 0;
 static int novmerge = 1;
 #endif
 
+static inline unsigned long iommu_num_pages(unsigned long vaddr,
+					    unsigned long slen)
+{
+	unsigned long npages;
+
+	npages = IOMMU_PAGE_ALIGN(vaddr + slen) - (vaddr & IOMMU_PAGE_MASK);
+	npages >>= IOMMU_PAGE_SHIFT;
+
+	return npages;
+}
+
 static int __init setup_iommu(char *str)
 {
 	if (!strcmp(str, "novmerge"))
@@ -178,10 +189,10 @@ static dma_addr_t iommu_alloc(struct iom
 	}
 
 	entry += tbl->it_offset;	/* Offset into real TCE table */
-	ret = entry << PAGE_SHIFT;	/* Set the return dma address */
+	ret = entry << IOMMU_PAGE_SHIFT;	/* Set the return dma address */
 
 	/* Put the TCEs in the HW table */
-	ppc_md.tce_build(tbl, entry, npages, (unsigned long)page & PAGE_MASK,
+	ppc_md.tce_build(tbl, entry, npages, (unsigned long)page & IOMMU_PAGE_MASK,
 			 direction);
 
 
@@ -203,7 +214,7 @@ static void __iommu_free(struct iommu_ta
 	unsigned long entry, free_entry;
 	unsigned long i;
 
-	entry = dma_addr >> PAGE_SHIFT;
+	entry = dma_addr >> IOMMU_PAGE_SHIFT;
 	free_entry = entry - tbl->it_offset;
 
 	if (((free_entry + npages) > tbl->it_size) ||
@@ -270,7 +281,7 @@ int iommu_map_sg(struct device *dev, str
 	/* Init first segment length for backout at failure */
 	outs->dma_length = 0;
 
-	DBG("mapping %d elements:\n", nelems);
+	DBG("sg mapping %d elements:\n", nelems);
 
 	spin_lock_irqsave(&(tbl->it_lock), flags);
 
@@ -285,9 +296,8 @@ int iommu_map_sg(struct device *dev, str
 		}
 		/* Allocate iommu entries for that segment */
 		vaddr = (unsigned long)page_address(s->page) + s->offset;
-		npages = PAGE_ALIGN(vaddr + slen) - (vaddr & PAGE_MASK);
-		npages >>= PAGE_SHIFT;
-		entry = iommu_range_alloc(tbl, npages, &handle, mask >> PAGE_SHIFT, 0);
+		npages = iommu_num_pages(vaddr, slen);
+		entry = iommu_range_alloc(tbl, npages, &handle, mask >> IOMMU_PAGE_SHIFT, 0);
 
 		DBG("  - vaddr: %lx, size: %lx\n", vaddr, slen);
 
@@ -301,14 +311,14 @@ int iommu_map_sg(struct device *dev, str
 
 		/* Convert entry to a dma_addr_t */
 		entry += tbl->it_offset;
-		dma_addr = entry << PAGE_SHIFT;
-		dma_addr |= s->offset;
+		dma_addr = entry << IOMMU_PAGE_SHIFT;
+		dma_addr |= (s->offset & ~IOMMU_PAGE_MASK);
 
-		DBG("  - %lx pages, entry: %lx, dma_addr: %lx\n",
+		DBG("  - %lu pages, entry: %lx, dma_addr: %lx\n",
 			    npages, entry, dma_addr);
 
 		/* Insert into HW table */
-		ppc_md.tce_build(tbl, entry, npages, vaddr & PAGE_MASK, direction);
+		ppc_md.tce_build(tbl, entry, npages, vaddr & IOMMU_PAGE_MASK, direction);
 
 		/* If we are in an open segment, try merging */
 		if (segstart != s) {
@@ -323,7 +333,7 @@ int iommu_map_sg(struct device *dev, str
 				DBG("    can't merge, new segment.\n");
 			} else {
 				outs->dma_length += s->length;
-				DBG("    merged, new len: %lx\n", outs->dma_length);
+				DBG("    merged, new len: %ux\n", outs->dma_length);
 			}
 		}
 
@@ -367,9 +377,8 @@ int iommu_map_sg(struct device *dev, str
 		if (s->dma_length != 0) {
 			unsigned long vaddr, npages;
 
-			vaddr = s->dma_address & PAGE_MASK;
-			npages = (PAGE_ALIGN(s->dma_address + s->dma_length) - vaddr)
-				>> PAGE_SHIFT;
+			vaddr = s->dma_address & IOMMU_PAGE_MASK;
+			npages = iommu_num_pages(s->dma_address, s->dma_length);
 			__iommu_free(tbl, vaddr, npages);
 			s->dma_address = DMA_ERROR_CODE;
 			s->dma_length = 0;
@@ -398,8 +407,7 @@ void iommu_unmap_sg(struct iommu_table *
 
 		if (sglist->dma_length == 0)
 			break;
-		npages = (PAGE_ALIGN(dma_handle + sglist->dma_length)
-			  - (dma_handle & PAGE_MASK)) >> PAGE_SHIFT;
+		npages = iommu_num_pages(dma_handle,sglist->dma_length);
 		__iommu_free(tbl, dma_handle, npages);
 		sglist++;
 	}
@@ -532,12 +540,11 @@ dma_addr_t iommu_map_single(struct iommu
 	BUG_ON(direction == DMA_NONE);
 
 	uaddr = (unsigned long)vaddr;
-	npages = PAGE_ALIGN(uaddr + size) - (uaddr & PAGE_MASK);
-	npages >>= PAGE_SHIFT;
+	npages = iommu_num_pages(uaddr, size);
 
 	if (tbl) {
 		dma_handle = iommu_alloc(tbl, vaddr, npages, direction,
-					 mask >> PAGE_SHIFT, 0);
+					 mask >> IOMMU_PAGE_SHIFT, 0);
 		if (dma_handle == DMA_ERROR_CODE) {
 			if (printk_ratelimit())  {
 				printk(KERN_INFO "iommu_alloc failed, "
@@ -545,7 +552,7 @@ dma_addr_t iommu_map_single(struct iommu
 						tbl, vaddr, npages);
 			}
 		} else
-			dma_handle |= (uaddr & ~PAGE_MASK);
+			dma_handle |= (uaddr & ~IOMMU_PAGE_MASK);
 	}
 
 	return dma_handle;
@@ -554,11 +561,14 @@ dma_addr_t iommu_map_single(struct iommu
 void iommu_unmap_single(struct iommu_table *tbl, dma_addr_t dma_handle,
 		size_t size, enum dma_data_direction direction)
 {
+	unsigned int npages;
+
 	BUG_ON(direction == DMA_NONE);
 
-	if (tbl)
-		iommu_free(tbl, dma_handle, (PAGE_ALIGN(dma_handle + size) -
-					(dma_handle & PAGE_MASK)) >> PAGE_SHIFT);
+	if (tbl) {
+		npages = iommu_num_pages(dma_handle, size);
+		iommu_free(tbl, dma_handle, npages);
+	}
 }
 
 /* Allocates a contiguous real buffer and creates mappings over it.
@@ -570,11 +580,11 @@ void *iommu_alloc_coherent(struct iommu_
 {
 	void *ret = NULL;
 	dma_addr_t mapping;
-	unsigned int npages, order;
+	unsigned int order;
+	unsigned int nio_pages, io_order;
 	struct page *page;
 
 	size = PAGE_ALIGN(size);
-	npages = size >> PAGE_SHIFT;
 	order = get_order(size);
 
  	/*
@@ -598,8 +608,10 @@ void *iommu_alloc_coherent(struct iommu_
 	memset(ret, 0, size);
 
 	/* Set up tces to cover the allocated range */
-	mapping = iommu_alloc(tbl, ret, npages, DMA_BIDIRECTIONAL,
-			      mask >> PAGE_SHIFT, order);
+	nio_pages = size >> IOMMU_PAGE_SHIFT;
+	io_order = get_iommu_order(size);
+	mapping = iommu_alloc(tbl, ret, nio_pages, DMA_BIDIRECTIONAL,
+			      mask >> IOMMU_PAGE_SHIFT, io_order);
 	if (mapping == DMA_ERROR_CODE) {
 		free_pages((unsigned long)ret, order);
 		return NULL;
@@ -611,12 +623,13 @@ void *iommu_alloc_coherent(struct iommu_
 void iommu_free_coherent(struct iommu_table *tbl, size_t size,
 			 void *vaddr, dma_addr_t dma_handle)
 {
-	unsigned int npages;
-
 	if (tbl) {
+		unsigned int nio_pages;
+
+		size = PAGE_ALIGN(size);
+		nio_pages = size >> IOMMU_PAGE_SHIFT;
+		iommu_free(tbl, dma_handle, nio_pages);
 		size = PAGE_ALIGN(size);
-		npages = size >> PAGE_SHIFT;
-		iommu_free(tbl, dma_handle, npages);
 		free_pages((unsigned long)vaddr, get_order(size));
 	}
 }
Index: linux-cell/include/asm-powerpc/iommu.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/iommu.h	2006-10-06 13:45:32.000000000 +1000
+++ linux-cell/include/asm-powerpc/iommu.h	2006-10-30 14:04:38.000000000 +1100
@@ -22,17 +22,35 @@
 #define _ASM_IOMMU_H
 #ifdef __KERNEL__
 
-#include <asm/types.h>
+#include <linux/compiler.h>
 #include <linux/spinlock.h>
 #include <linux/device.h>
 #include <linux/dma-mapping.h>
+#include <asm/types.h>
+#include <asm/bitops.h>
+
+#define IOMMU_PAGE_SHIFT      12
+#define IOMMU_PAGE_SIZE       (ASM_CONST(1) << IOMMU_PAGE_SHIFT)
+#define IOMMU_PAGE_MASK       (~((1 << IOMMU_PAGE_SHIFT) - 1))
+#define IOMMU_PAGE_ALIGN(addr) _ALIGN_UP(addr, IOMMU_PAGE_SIZE)
+
+#ifndef __ASSEMBLY__
+
+/* Pure 2^n version of get_order */
+static __inline__ __attribute_const__ int get_iommu_order(unsigned long size)
+{
+	return __ilog2((size - 1) >> IOMMU_PAGE_SHIFT) + 1;
+}
+
+#endif   /* __ASSEMBLY__ */
+
 
 /*
  * IOMAP_MAX_ORDER defines the largest contiguous block
  * of dma space we can get.  IOMAP_MAX_ORDER = 13
  * allows up to 2**12 pages (4096 * 4096) = 16 MB
  */
-#define IOMAP_MAX_ORDER 13
+#define IOMAP_MAX_ORDER		13
 
 struct iommu_table {
 	unsigned long  it_busno;     /* Bus number this table belongs to */
Index: linux-cell/include/asm-powerpc/tce.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/tce.h	2006-10-06 13:45:32.000000000 +1000
+++ linux-cell/include/asm-powerpc/tce.h	2006-10-27 15:41:49.000000000 +1000
@@ -22,6 +22,8 @@
 #define _ASM_POWERPC_TCE_H
 #ifdef __KERNEL__
 
+#include <asm/iommu.h>
+
 /*
  * Tces come in two formats, one for the virtual bus and a different
  * format for PCI
@@ -33,7 +35,6 @@
 
 #define TCE_SHIFT	12
 #define TCE_PAGE_SIZE	(1 << TCE_SHIFT)
-#define TCE_PAGE_FACTOR	(PAGE_SHIFT - TCE_SHIFT)
 
 #define TCE_ENTRY_SIZE		8		/* each TCE is 64 bits */
 
Index: linux-cell/arch/powerpc/kernel/vio.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/vio.c	2006-10-06 13:47:54.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/vio.c	2006-10-30 14:04:38.000000000 +1100
@@ -92,9 +92,9 @@ static struct iommu_table *vio_build_iom
 				&tbl->it_index, &offset, &size);
 
 		/* TCE table size - measured in tce entries */
-		tbl->it_size = size >> PAGE_SHIFT;
+		tbl->it_size = size >> IOMMU_PAGE_SHIFT;
 		/* offset for VIO should always be 0 */
-		tbl->it_offset = offset >> PAGE_SHIFT;
+		tbl->it_offset = offset >> IOMMU_PAGE_SHIFT;
 		tbl->it_busno = 0;
 		tbl->it_type = TCE_VB;
 
Index: linux-cell/arch/powerpc/platforms/pseries/iommu.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/pseries/iommu.c	2006-10-09 12:03:33.000000000 +1000
+++ linux-cell/arch/powerpc/platforms/pseries/iommu.c	2006-10-30 14:20:45.000000000 +1100
@@ -57,9 +57,6 @@ static void tce_build_pSeries(struct iom
 	u64 *tcep;
 	u64 rpn;
 
-	index <<= TCE_PAGE_FACTOR;
-	npages <<= TCE_PAGE_FACTOR;
-
 	proto_tce = TCE_PCI_READ; // Read allowed
 
 	if (direction != DMA_TO_DEVICE)
@@ -82,9 +79,6 @@ static void tce_free_pSeries(struct iomm
 {
 	u64 *tcep;
 
-	npages <<= TCE_PAGE_FACTOR;
-	index <<= TCE_PAGE_FACTOR;
-
 	tcep = ((u64 *)tbl->it_base) + index;
 
 	while (npages--)
@@ -95,7 +89,6 @@ static unsigned long tce_get_pseries(str
 {
 	u64 *tcep;
 
-	index <<= TCE_PAGE_FACTOR;
 	tcep = ((u64 *)tbl->it_base) + index;
 
 	return *tcep;
@@ -109,9 +102,6 @@ static void tce_build_pSeriesLP(struct i
 	u64 proto_tce, tce;
 	u64 rpn;
 
-	tcenum <<= TCE_PAGE_FACTOR;
-	npages <<= TCE_PAGE_FACTOR;
-
 	rpn = (virt_to_abs(uaddr)) >> TCE_SHIFT;
 	proto_tce = TCE_PCI_READ;
 	if (direction != DMA_TO_DEVICE)
@@ -146,7 +136,7 @@ static void tce_buildmulti_pSeriesLP(str
 	u64 rpn;
 	long l, limit;
 
-	if (TCE_PAGE_FACTOR == 0 && npages == 1)
+	if (npages == 1)
 		return tce_build_pSeriesLP(tbl, tcenum, npages, uaddr,
 					   direction);
 
@@ -164,9 +154,6 @@ static void tce_buildmulti_pSeriesLP(str
 		__get_cpu_var(tce_page) = tcep;
 	}
 
-	tcenum <<= TCE_PAGE_FACTOR;
-	npages <<= TCE_PAGE_FACTOR;
-
 	rpn = (virt_to_abs(uaddr)) >> TCE_SHIFT;
 	proto_tce = TCE_PCI_READ;
 	if (direction != DMA_TO_DEVICE)
@@ -207,9 +194,6 @@ static void tce_free_pSeriesLP(struct io
 {
 	u64 rc;
 
-	tcenum <<= TCE_PAGE_FACTOR;
-	npages <<= TCE_PAGE_FACTOR;
-
 	while (npages--) {
 		rc = plpar_tce_put((u64)tbl->it_index, (u64)tcenum << 12, 0);
 
@@ -229,9 +213,6 @@ static void tce_freemulti_pSeriesLP(stru
 {
 	u64 rc;
 
-	tcenum <<= TCE_PAGE_FACTOR;
-	npages <<= TCE_PAGE_FACTOR;
-
 	rc = plpar_tce_stuff((u64)tbl->it_index, (u64)tcenum << 12, 0, npages);
 
 	if (rc && printk_ratelimit()) {
@@ -248,7 +229,6 @@ static unsigned long tce_get_pSeriesLP(s
 	u64 rc;
 	unsigned long tce_ret;
 
-	tcenum <<= TCE_PAGE_FACTOR;
 	rc = plpar_tce_get((u64)tbl->it_index, (u64)tcenum << 12, &tce_ret);
 
 	if (rc && printk_ratelimit()) {
@@ -289,7 +269,7 @@ static void iommu_table_setparms(struct 
 	tbl->it_busno = phb->bus->number;
 
 	/* Units of tce entries */
-	tbl->it_offset = phb->dma_window_base_cur >> PAGE_SHIFT;
+	tbl->it_offset = phb->dma_window_base_cur >> IOMMU_PAGE_SHIFT;
 
 	/* Test if we are going over 2GB of DMA space */
 	if (phb->dma_window_base_cur + phb->dma_window_size > 0x80000000ul) {
@@ -300,7 +280,7 @@ static void iommu_table_setparms(struct 
 	phb->dma_window_base_cur += phb->dma_window_size;
 
 	/* Set the tce table size - measured in entries */
-	tbl->it_size = phb->dma_window_size >> PAGE_SHIFT;
+	tbl->it_size = phb->dma_window_size >> IOMMU_PAGE_SHIFT;
 
 	tbl->it_index = 0;
 	tbl->it_blocksize = 16;
@@ -325,8 +305,8 @@ static void iommu_table_setparms_lpar(st
 	tbl->it_base   = 0;
 	tbl->it_blocksize  = 16;
 	tbl->it_type = TCE_PCI;
-	tbl->it_offset = offset >> PAGE_SHIFT;
-	tbl->it_size = size >> PAGE_SHIFT;
+	tbl->it_offset = offset >> IOMMU_PAGE_SHIFT;
+	tbl->it_size = size >> IOMMU_PAGE_SHIFT;
 }
 
 static void iommu_bus_setup_pSeries(struct pci_bus *bus)
@@ -522,8 +502,6 @@ static void iommu_dev_setup_pSeriesLP(st
 	const void *dma_window = NULL;
 	struct pci_dn *pci;
 
-	DBG("iommu_dev_setup_pSeriesLP, dev %p (%s)\n", dev, pci_name(dev));
-
 	/* dev setup for LPAR is a little tricky, since the device tree might
 	 * contain the dma-window properties per-device and not neccesarily
 	 * for the bus. So we need to search upwards in the tree until we
@@ -532,6 +510,9 @@ static void iommu_dev_setup_pSeriesLP(st
 	 */
 	dn = pci_device_to_OF_node(dev);
 
+	DBG("iommu_dev_setup_pSeriesLP, dev %p (%s) %s\n",
+	     dev, pci_name(dev), dn->full_name);
+
 	for (pdn = dn; pdn && PCI_DN(pdn) && !PCI_DN(pdn)->iommu_table;
 	     pdn = pdn->parent) {
 		dma_window = get_property(pdn, "ibm,dma-window", NULL);
Index: linux-cell/arch/powerpc/sysdev/dart.h
===================================================================
--- linux-cell.orig/arch/powerpc/sysdev/dart.h	2006-10-06 13:47:54.000000000 +1000
+++ linux-cell/arch/powerpc/sysdev/dart.h	2006-10-27 15:41:49.000000000 +1000
@@ -72,7 +72,6 @@
 
 #define DART_PAGE_SHIFT		12
 #define DART_PAGE_SIZE		(1 << DART_PAGE_SHIFT)
-#define DART_PAGE_FACTOR	(PAGE_SHIFT - DART_PAGE_SHIFT)
 
 
 #endif /* _POWERPC_SYSDEV_DART_H */
Index: linux-cell/arch/powerpc/sysdev/dart_iommu.c
===================================================================
--- linux-cell.orig/arch/powerpc/sysdev/dart_iommu.c	2006-10-06 13:47:54.000000000 +1000
+++ linux-cell/arch/powerpc/sysdev/dart_iommu.c	2006-10-30 14:04:38.000000000 +1100
@@ -156,9 +156,6 @@ static void dart_build(struct iommu_tabl
 
 	DBG("dart: build at: %lx, %lx, addr: %x\n", index, npages, uaddr);
 
-	index <<= DART_PAGE_FACTOR;
-	npages <<= DART_PAGE_FACTOR;
-
 	dp = ((unsigned int*)tbl->it_base) + index;
 
 	/* On U3, all memory is contigous, so we can move this
@@ -199,9 +196,6 @@ static void dart_free(struct iommu_table
 
 	DBG("dart: free at: %lx, %lx\n", index, npages);
 
-	index <<= DART_PAGE_FACTOR;
-	npages <<= DART_PAGE_FACTOR;
-
 	dp  = ((unsigned int *)tbl->it_base) + index;
 
 	while (npages--)
@@ -281,7 +275,7 @@ static void iommu_table_dart_setup(void)
 	iommu_table_dart.it_busno = 0;
 	iommu_table_dart.it_offset = 0;
 	/* it_size is in number of entries */
-	iommu_table_dart.it_size = (dart_tablesize / sizeof(u32)) >> DART_PAGE_FACTOR;
+	iommu_table_dart.it_size = dart_tablesize / sizeof(u32);
 
 	/* Initialize the common IOMMU code */
 	iommu_table_dart.it_base = (unsigned long)dart_vbase;
Index: linux-cell/arch/powerpc/platforms/iseries/iommu.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/iseries/iommu.c	2006-10-06 13:47:54.000000000 +1000
+++ linux-cell/arch/powerpc/platforms/iseries/iommu.c	2006-10-30 14:10:44.000000000 +1100
@@ -43,9 +43,6 @@ static void tce_build_iSeries(struct iom
 	u64 rc;
 	u64 tce, rpn;
 
-	index <<= TCE_PAGE_FACTOR;
-	npages <<= TCE_PAGE_FACTOR;
-
 	while (npages--) {
 		rpn = virt_to_abs(uaddr) >> TCE_SHIFT;
 		tce = (rpn & TCE_RPN_MASK) << TCE_RPN_SHIFT;
@@ -75,9 +72,6 @@ static void tce_free_iSeries(struct iomm
 {
 	u64 rc;
 
-	npages <<= TCE_PAGE_FACTOR;
-	index <<= TCE_PAGE_FACTOR;
-
 	while (npages--) {
 		rc = HvCallXm_setTce((u64)tbl->it_index, (u64)index, 0);
 		if (rc)
@@ -136,10 +130,9 @@ void iommu_table_getparms_iSeries(unsign
 		panic("PCI_DMA: parms->size is zero, parms is 0x%p", parms);
 
 	/* itc_size is in pages worth of table, it_size is in # of entries */
-	tbl->it_size = ((parms->itc_size * TCE_PAGE_SIZE) /
-			TCE_ENTRY_SIZE) >> TCE_PAGE_FACTOR;
+	tbl->it_size = (parms->itc_size * TCE_PAGE_SIZE) / TCE_ENTRY_SIZE;
 	tbl->it_busno = parms->itc_busno;
-	tbl->it_offset = parms->itc_offset >> TCE_PAGE_FACTOR;
+	tbl->it_offset = parms->itc_offset;
 	tbl->it_index = parms->itc_index;
 	tbl->it_blocksize = 1;
 	tbl->it_type = virtbus ? TCE_VB : TCE_PCI;

^ permalink raw reply

* Re: [PATCH 2/3] Create compat_sys_migrate_pages
From: Benjamin Herrenschmidt @ 2006-10-30  5:29 UTC (permalink / raw)
  To: Christoph Lameter; +Cc: Stephen Rothwell, ppc-dev, ak, LKML, linux-mm, paulus
In-Reply-To: <Pine.LNX.4.64.0610270622480.7342@schroedinger.engr.sgi.com>

On Fri, 2006-10-27 at 06:24 -0700, Christoph Lameter wrote:
> On Fri, 27 Oct 2006, Stephen Rothwell wrote:
> 
> > No they aren't because they have compat routines that convert the bitmaps
> > before calling the "normal" syscall.  They, importantly, only use
> > compat_alloc_user_space once each.
> 
> Ah...
> 
> > > Fixing get_nodes() to do the proper thing would fix all of these
> > > without having to touch sys_migrate_pages or creating a compat_ function
> > > (which usually is placed in kernel/compat.c)
> > 
> > You need the compat_ version of the syscalls to know if you were called
> > from a 32bit application in order to know if you may need to fixup the
> > bitmaps that are passed from/to user mode.
> 
> The compat functions should be placed in kernel/compat.c next to 
> compat_sys_move_pages.

I disagree.. it's really annoying when they are away from their
respective "non-compat" function, especially when they are more than
just wrappers copying/converting arguments...

Now, if only we had done a sane ABI in the first place...
 
Ben.

^ permalink raw reply

* RE: [PATCH] qe_lib: Remove immrbar_virt_to_phys() function
From: Li Yang-r58472 @ 2006-10-30  6:22 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev
In-Reply-To: <17733.28614.62353.822225@cargo.ozlabs.ibm.com>

> -----Original Message-----
> From: Paul Mackerras [mailto:paulus@samba.org]
> Sent: Monday, October 30, 2006 11:22 AM
> To: Li Yang-r58472
> Cc: linuxppc-dev@ozlabs.org
> Subject: Re: [PATCH] qe_lib: Remove immrbar_virt_to_phys() function
>=20
> Li Yang writes:
>=20
> > Remove private physical address mapping routine in qe_lib.  Users
> > of qe_lib should use generic functions like iopa().
> > The change also addresses a bug found by Timur Tabi that cmd_input
> > got mapped in qe_issue_cmd().  It should be written to CECDR
> > unmodified.
>=20
> Do you mean that the argument to qe_issue_cmd is a physical address?
> It seems to me that the bug fix you mention is the main thing the
> patch does, and the removal of immrvar_virt_to_phys is a cleanup on
> the side that is made possible by the bugfix.

The argument cmd_input should be offset to the MURAM base.  The cleanup
is inspired by the bugfix but not result of the bugfix.  There are still
other users of the immrbar_virt_to_phy() which can be replaced.  The
bugfix can be covered by the work of removing all users of the routine.
Or the removal will be depending on the bugfix to complete its work.  Do
you suggest us to separate the patches?

- Leo

^ permalink raw reply

* [PATCH 1/2] Create compat_sys_migrate_pages.
From: Stephen Rothwell @ 2006-10-30  7:17 UTC (permalink / raw)
  To: LKML; +Cc: linux-mm, ak, ppc-dev, pj, paulus, Christoph Lameter

This is needed on bigendian 64bit architectures.

Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
---
 include/linux/compat.h |    4 ++++
 kernel/compat.c        |   33 +++++++++++++++++++++++++++++++++
 kernel/sys_ni.c        |    1 +
 3 files changed, 38 insertions(+), 0 deletions(-)

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

diff --git a/include/linux/compat.h b/include/linux/compat.h
index f155319..80b17f4 100644
--- a/include/linux/compat.h
+++ b/include/linux/compat.h
@@ -230,5 +230,9 @@ asmlinkage long compat_sys_adjtimex(stru
 extern int compat_printk(const char *fmt, ...);
 extern void sigset_from_compat(sigset_t *set, compat_sigset_t *compat);
 
+asmlinkage long compat_sys_migrate_pages(compat_pid_t pid,
+		compat_ulong_t maxnode, const compat_ulong_t __user *old_nodes,
+		const compat_ulong_t __user *new_nodes);
+
 #endif /* CONFIG_COMPAT */
 #endif /* _LINUX_COMPAT_H */
diff --git a/kernel/compat.c b/kernel/compat.c
index d4898aa..6952dd0 100644
--- a/kernel/compat.c
+++ b/kernel/compat.c
@@ -982,4 +982,37 @@ asmlinkage long compat_sys_move_pages(pi
 	}
 	return sys_move_pages(pid, nr_pages, pages, nodes, status, flags);
 }
+
+asmlinkage long compat_sys_migrate_pages(compat_pid_t pid,
+			compat_ulong_t maxnode,
+			const compat_ulong_t __user *old_nodes,
+			const compat_ulong_t __user *new_nodes)
+{
+	unsigned long __user *old = NULL;
+	unsigned long __user *new = NULL;
+	nodemask_t tmp_mask;
+	unsigned long nr_bits;
+	unsigned long size;
+
+	nr_bits = min_t(unsigned long, maxnode - 1, MAX_NUMNODES);
+	size = ALIGN(nr_bits, BITS_PER_LONG) / 8;
+	if (old_nodes) {
+		if (compat_get_bitmap(nodes_addr(tmp_mask), old_nodes, nr_bits))
+			return -EFAULT;
+		old = compat_alloc_user_space(new_nodes ? size * 2 : size);
+		if (new_nodes)
+			new = old + size / sizeof(unsigned long);
+		if (copy_to_user(old, nodes_addr(tmp_mask), size))
+			return -EFAULT;
+	}
+	if (new_nodes) {
+		if (compat_get_bitmap(nodes_addr(tmp_mask), new_nodes, nr_bits))
+			return -EFAULT;
+		if (new == NULL)
+			new = compat_alloc_user_space(size);
+		if (copy_to_user(new, nodes_addr(tmp_mask), size))
+			return -EFAULT;
+	}
+	return sys_migrate_pages(pid, nr_bits + 1, old, new);
+}
 #endif
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index 0e53314..d7306d0 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -135,6 +135,7 @@ cond_syscall(sys_madvise);
 cond_syscall(sys_mremap);
 cond_syscall(sys_remap_file_pages);
 cond_syscall(compat_sys_move_pages);
+cond_syscall(compat_sys_migrate_pages);
 
 /* block-layer dependent */
 cond_syscall(sys_bdflush);
-- 
1.4.3.2

^ permalink raw reply related

* [PATCH 2/2] [POWERPC] Wire up sys_migrate_pages
From: Stephen Rothwell @ 2006-10-30  7:18 UTC (permalink / raw)
  To: LKML; +Cc: linux-mm, ak, ppc-dev, pj, paulus, Christoph Lameter
In-Reply-To: <20061030181701.23ea7cba.sfr@canb.auug.org.au>


Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
---
 include/asm-powerpc/systbl.h |    2 +-
 include/asm-powerpc/unistd.h |    2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

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

diff --git a/include/asm-powerpc/systbl.h b/include/asm-powerpc/systbl.h
index eac85ce..c6a0318 100644
--- a/include/asm-powerpc/systbl.h
+++ b/include/asm-powerpc/systbl.h
@@ -261,7 +261,7 @@ SYSX(sys_ni_syscall, ppc_fadvise64_64, p
 PPC_SYS_SPU(rtas)
 OLDSYS(debug_setcontext)
 SYSCALL(ni_syscall)
-SYSCALL(ni_syscall)
+COMPAT_SYS(migrate_pages)
 COMPAT_SYS(mbind)
 COMPAT_SYS(get_mempolicy)
 COMPAT_SYS(set_mempolicy)
diff --git a/include/asm-powerpc/unistd.h b/include/asm-powerpc/unistd.h
index 464a48c..b5fe932 100644
--- a/include/asm-powerpc/unistd.h
+++ b/include/asm-powerpc/unistd.h
@@ -276,7 +276,7 @@ #endif
 #define __NR_rtas		255
 #define __NR_sys_debug_setcontext 256
 /* Number 257 is reserved for vserver */
-/* 258 currently unused */
+#define __NR_migrate_pages	258
 #define __NR_mbind		259
 #define __NR_get_mempolicy	260
 #define __NR_set_mempolicy	261
-- 
1.4.3.2

^ permalink raw reply related

* Re: [PATCH] Xilinx UART Lite 2.6.18 driver
From: Peter Korsgaard @ 2006-10-30  8:23 UTC (permalink / raw)
  To: linuxppc-embedded
In-Reply-To: <4542CE8A.9030904@dlasys.net>

>>>>> "David" == David H Lynch <dhlii@dlasys.net> writes:

David>     There is a substantial time/code difference between the
David> time ulite_console_setup() is called and the time the platform
David> device is initiallized.

Huh?

(gdb) br ulite_probe
Breakpoint 2 at 0xc00f7530: file drivers/serial/uartlite.c, line 397.
(gdb) br ulite_console_setup
Breakpoint 3 at 0xc00f7454: file drivers/serial/uartlite.c, line 342.
(gdb) c
Continuing.

Breakpoint 2, ulite_probe (pdev=0xc00ddb50) at drivers/serial/uartlite.c:397
397                     return -EINVAL;
(gdb) c
Continuing.

Breakpoint 3, ulite_console_setup (co=0xc00e2f14, options=0xc00fe00f "115200")
    at drivers/serial/uartlite.c:342
342             if (co->index < 0 || co->index >= ULITE_NR_UARTS)

_probe get's called before console_setup, so we have all the
information to output console data right away.

David>     But for now, if you are not going to bother making
David> console_settup() work you might as well not put the rest of the
David> early serial code in at all.

Not going to make it work? What doesn't work?

-- 
Bye, Peter Korsgaard

^ permalink raw reply

* Xubuntu and Xenomai on the Lite5200 (IceCube)...
From: David Jander @ 2006-10-30 11:09 UTC (permalink / raw)
  To: linuxppc-embedded list


Hi all,

I got the task to help make Linux run on the IceCube, with support for MSCAN, 
FEC and USB. After a rather exciting jurney I managed to get kernel 2.6.18 
working with bestcomm DMA and FEC support backported from DENX's git 
2.6.19-rcsomething, and Xenomai installed upon that.
Btw, before Wolfgang Denk starts complaining why I didn't use his 2.4 kernel, 
it's because I wasn't smart enough to get USB working. If it does work, 
please tell me how, I just get errors when plugging in a USB device "kernel: 
usb.c: USB device not accepting new address=2 (error=-110)". 
This seems to work fine in 2.6, though.
It was not easy, so I wrote everything down (I hope I didn't forget anything 
important):

http://yopesblog.blogspot.com/2006/10/how-to-run-ubuntu-and-xenomai-on.html

If anyone wants to tell me what I did wrong (probably a lot), please tell me.
I am posting this to the list hoping someone else will benefit from it. I 
certainly would have.

Greetings,

-- 
David Jander

^ permalink raw reply

* Re: glibc-2.5 test suite hangs/crashes the machine
From: Fabio Massimo Di Nitto @ 2006-10-30 11:35 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: linuxppc-dev, Jeff Bailey, Paul Mackerras, Ben Collins
In-Reply-To: <1162177334.25682.144.camel@localhost.localdomain>

Benjamin Herrenschmidt wrote:
> Does that patch fixes it ?
> 

tested with kernel .17 and headers from .19 and the build hangs. Still tons of
Zl processes around.

On the note building with kernel .19 and .19 headers it all goes smooth.

Fabio

-- 
I'm going to make him an offer he can't refuse.

^ permalink raw reply

* Re: CPM2 SCC/SMC break handling broken
From: Laurent Pinchart @ 2006-10-30 15:23 UTC (permalink / raw)
  To: Ricardo Scop; +Cc: linuxppc-embedded
In-Reply-To: <200610271620.23046.scop@digitel.com.br>

Hi Ricardo,

> > > > I need to generate a break on a CPM2 SMC serial port (same issue with
> > > > SCC serial ports).
> > > >
> > > > The tcsendbreak() man page states that the function should generate a
> > > > break between 250ms and 500ms, but testing showed that the break is
> > > > one character long (10 bits in 8N1 mode).
> > >
> > > [snip]
> > >
> > > > CPM_CR_STOP_TX is documented to generate a break of BRKCR characters.
> > > > The BRKCR register is initialized to 1, so only 1 break character is
> > > > sent, which won't last between 250ms and 500ms.
> > >
> > > [snip]
> > >
> > > > Could anyone think of a proper solution which would not disturb the
> > > > other drivers too much ?
> > >
> > > Well, one could always set the BRKCR parameter to the maximum number of
> > > break characters permitted by it's size, since the break condition will
> > > anyway end as soon as the RESTART TX command is issued as a consequence
> > > of the tty->driver->break_ctl(tty, 0) call. But I did not test this.
> >
> > That's a very good idea, but the documentation is a bit misleading here.
> > I tested the CPM2 behaviour, and found out that the break will last BRKCR
> > characters, even if a RESTART TX command is sent sooner.
> >
> > The user manual states
> >
> > "The SMC sends a programmable number of break characters according to
> > BRKCR and reverts to idle or sends data if a RESTART TRANSMIT is issued
> > before completion."
> >
> > I suppose they meant that, if a RESTART TX command is issued before
> > completion of the break sequence, the SMC will send data at the end of
> > the break sequence. This is at least the behaviour I noticed after trying
> > your idea.
>
> Too bad.... :( One more good idea to the junk bin.
>
> Hmm, just a wild shot you can try, while you're at that: what about setting
> BRKCR to zero and issuing another STOP TRANSMIT, just before the RESTART
> TRANSMIT?

Wow, congratulations. I wouldn't have thought about that.

static void cpm_uart_break_ctl(struct uart_port *port, int break_state)
{
        struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
        int line = pinfo - cpm_uart_ports;
        volatile u16 *brkcr = IS_SMC(pinfo) ? &pinfo->smcup->smc_brkcr
                                : &pinfo->sccup->scc_brkcr;

        pr_debug("CPM uart[%d]:break ctrl, break_state: %d\n", port->line,
                break_state);

        if (break_state)
        {
                *brkcr = 32767;
                cpm_line_cr_cmd(line, CPM_CR_STOP_TX);
        }
        else
        {
                *brkcr = 0;
                cpm_line_cr_cmd(line, CPM_CR_STOP_TX);
                cpm_line_cr_cmd(line, CPM_CR_RESTART_TX);
        }
}

This is a bit hackish though, but it works and doesn't require any API 
modification.

Vitaly, could you give me your opinion ?

> Another reasonable shot would be to disable and reenable the transmitter in
> an attempt to stop the break sequence; though I don't know what happens to
> the SMC state machine in this case.
>
> Too wild guesses? Well, maybe someone at Freescale can have a better idea.
> :)

I could try contacting them, but they will probably tell me that I should just 
set BRKCR to the number of characters I want to send. I doubt they will care 
that the kernel break handling code doesn't allow us to do that easily.

Thanks for your help.

Best regards,

Laurent Pinchart

^ permalink raw reply

* AW: Xubuntu and Xenomai on the Lite5200 (IceCube)...
From: Achim Machura @ 2006-10-30 15:32 UTC (permalink / raw)
  To: 'David Jander'; +Cc: Linuxppc-Embedded (E-Mail)
In-Reply-To: <200610301209.38103.david.jander@protonic.nl>

Hello, David,

We have had the same problem,

after enabling pci in the kernelconfig,
usb is working.

best regards

Achim

> -----Ursprungliche Nachricht-----
> Von: linuxppc-embedded-bounces+machura=berghof.com@ozlabs.org
> [mailto:linuxppc-embedded-bounces+machura=berghof.com@ozlabs.org]Im
> Auftrag von David Jander
> Gesendet: Montag, 30. Oktober 2006 12:10
> An: linuxppc-embedded list
> Betreff: Xubuntu and Xenomai on the Lite5200 (IceCube)...
>
>
>
> Hi all,
>
> I got the task to help make Linux run on the IceCube, with
> support for MSCAN,
> FEC and USB. After a rather exciting jurney I managed to get
> kernel 2.6.18
> working with bestcomm DMA and FEC support backported from DENX's git
> 2.6.19-rcsomething, and Xenomai installed upon that.
> Btw, before Wolfgang Denk starts complaining why I didn't use
> his 2.4 kernel,
> it's because I wasn't smart enough to get USB working. If it
> does work,
> please tell me how, I just get errors when plugging in a USB
> device "kernel:
> usb.c: USB device not accepting new address=2 (error=-110)".
> This seems to work fine in 2.6, though.
> It was not easy, so I wrote everything down (I hope I didn't
> forget anything
> important):
>
> http://yopesblog.blogspot.com/2006/10/how-to-run-ubuntu-and-xe
nomai-on.html

If anyone wants to tell me what I did wrong (probably a lot), please tell
me.
I am posting this to the list hoping someone else will benefit from it. I
certainly would have.

Greetings,

--
David Jander
_______________________________________________
Linuxppc-embedded mailing list
Linuxppc-embedded@ozlabs.org
https://ozlabs.org/mailman/listinfo/linuxppc-embedded

^ permalink raw reply

* Re: CPM2 SCC/SMC break handling broken
From: Vitaly Bordug @ 2006-10-30 15:40 UTC (permalink / raw)
  To: Laurent Pinchart; +Cc: linuxppc-embedded
In-Reply-To: <200610301623.51537.laurent.pinchart@tbox.biz>

On Mon, 30 Oct 2006 16:23:51 +0100
Laurent Pinchart <laurent.pinchart@tbox.biz> wrote:

> Hi Ricardo,
> 
> > > > > I need to generate a break on a CPM2 SMC serial port (same issue with
> > > > > SCC serial ports).
> > > > >
> > > > > The tcsendbreak() man page states that the function should generate a
> > > > > break between 250ms and 500ms, but testing showed that the break is
> > > > > one character long (10 bits in 8N1 mode).
> > > >
> > > > [snip]
> > > >
> > > > > CPM_CR_STOP_TX is documented to generate a break of BRKCR characters.
> > > > > The BRKCR register is initialized to 1, so only 1 break character is
> > > > > sent, which won't last between 250ms and 500ms.
> > > >
> > > > [snip]
> > > >
> > > > > Could anyone think of a proper solution which would not disturb the
> > > > > other drivers too much ?
> > > >
> > > > Well, one could always set the BRKCR parameter to the maximum number of
> > > > break characters permitted by it's size, since the break condition will
> > > > anyway end as soon as the RESTART TX command is issued as a consequence
> > > > of the tty->driver->break_ctl(tty, 0) call. But I did not test this.
> > >
> > > That's a very good idea, but the documentation is a bit misleading here.
> > > I tested the CPM2 behaviour, and found out that the break will last BRKCR
> > > characters, even if a RESTART TX command is sent sooner.
> > >
> > > The user manual states
> > >
> > > "The SMC sends a programmable number of break characters according to
> > > BRKCR and reverts to idle or sends data if a RESTART TRANSMIT is issued
> > > before completion."
> > >
> > > I suppose they meant that, if a RESTART TX command is issued before
> > > completion of the break sequence, the SMC will send data at the end of
> > > the break sequence. This is at least the behaviour I noticed after trying
> > > your idea.
> >
> > Too bad.... :( One more good idea to the junk bin.
> >
> > Hmm, just a wild shot you can try, while you're at that: what about setting
> > BRKCR to zero and issuing another STOP TRANSMIT, just before the RESTART
> > TRANSMIT?
> 
> Wow, congratulations. I wouldn't have thought about that.
> 
> static void cpm_uart_break_ctl(struct uart_port *port, int break_state)
> {
>         struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
>         int line = pinfo - cpm_uart_ports;
>         volatile u16 *brkcr = IS_SMC(pinfo) ? &pinfo->smcup->smc_brkcr
>                                 : &pinfo->sccup->scc_brkcr;
> 
>         pr_debug("CPM uart[%d]:break ctrl, break_state: %d\n", port->line,
>                 break_state);
> 
>         if (break_state)
>         {
>                 *brkcr = 32767;
>                 cpm_line_cr_cmd(line, CPM_CR_STOP_TX);
>         }
>         else
>         {
>                 *brkcr = 0;
>                 cpm_line_cr_cmd(line, CPM_CR_STOP_TX);
>                 cpm_line_cr_cmd(line, CPM_CR_RESTART_TX);
>         }
> }
> 
> This is a bit hackish though, but it works and doesn't require any API 
> modification.
> 
> Vitaly, could you give me your opinion ?
I'm fine with this change. Can you provide a sorta more complete reference why it is required?
I understood in general, but as author, you can explain the reason more clear I beleive...


Thanks.
-V

^ permalink raw reply

* Re: AW: Xubuntu and Xenomai on the Lite5200 (IceCube)...
From: David Jander @ 2006-10-30 16:10 UTC (permalink / raw)
  To: linuxppc-embedded, achim.machura
In-Reply-To: <001001c6fc38$adf4d670$34f1ff0a@beint.local>

On Monday 30 October 2006 16:32, Achim Machura wrote:
> Hello, David,
>
> We have had the same problem,
>
> after enabling pci in the kernelconfig,
> usb is working.

Duh. And how is one supposed to know that?
Thanks for the tip ;-)

Greetings,

-- 
David Jander

^ permalink raw reply

* [DTC][PATCH] increment default output blob version from 3 to 16
From: Kim Phillips @ 2006-10-30 16:48 UTC (permalink / raw)
  To: linuxppc-dev list

increment default output blob version from 3 to 16

---
 dtc.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/dtc.c b/dtc.c
index 646b814..3cb94e6 100644
--- a/dtc.c
+++ b/dtc.c
@@ -113,7 +113,7 @@ int main(int argc, char *argv[])
 	int opt;
 	FILE *inf = NULL;
 	FILE *outf = NULL;
-	int outversion = 3;
+	int outversion = 0x10;
 	int reservenum = 1;
 	int boot_cpuid_phys = 0xfeedbeef;
 
-- 
1.4.2.3

^ permalink raw reply related

* Re: [PATCH 1/2] Add MPC52xx Interrupt controller support for ARCH=powerpc
From: Dale Farnsworth @ 2006-10-30 17:37 UTC (permalink / raw)
  To: linuxppc-embedded
In-Reply-To: <200610292310.k9TNAHXZ013852@post.webmailer.de>

In article <200610292310.k9TNAHXZ013852@post.webmailer.de> Nicolas wrote:
> This patch add MPC52xx Interrupt controller for ARCH=powerpc.
> 
> It includes the main code in arch/powerpc/sysdev/ ad well as an header
> file in include/asm-powerpc.
> 
> Signed-off-by: Nicolas DET <nd@bplan-gmbh.de>

NAK.

Two requests:
  1.  Please include patches inline so that they may be easily reviewed.
  2.  Please do not remove copyright lines from files you modify.

-Dale

^ 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