LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/9 v2] powerpc: mv64x60 and prpmc2800 DTS cleanups
From: Dale Farnsworth @ 2008-04-07 18:32 UTC (permalink / raw)
  To: paulus; +Cc: linuxppc-dev

This series of patches again attempts to clean up and document
the Marvell MV64x60 device tree.  It supersedes Mark Greer's
series posted on 11 December 2007.  See:
http://ozlabs.org/pipermail/linuxppc-dev/2007-December/047986.html

These apply on the powerpc-next branch, and I'd like to get them
into 2.6.26.

This revision changes the name of the mv64360 dts node to
"system-controller", and as a result changes the text added
to Documentation/powerpc/booting-without-of.txt

I believe all comments on the previous version of this series
have been addressed.

Thanks,
-Dale

^ permalink raw reply

* [PATCH 1/9 v2] powerpc: change FDT compatible prefix to mrvl
From: Dale Farnsworth @ 2008-04-07 18:38 UTC (permalink / raw)
  To: paulus; +Cc: linuxppc-dev
In-Reply-To: <20080407183228.GA7438@farnsworth.org>

From: Dale Farnsworth <dale@farnsworth.org>

Follow the convention that compatible names are prefixed by the
vendor's stock ticker symbol.  For Marvell Technology Group Ltd.,
that's MRVL.

Signed-off-by: Dale Farnsworth <dale@farnsworth.org>
Acked-by: Mark A. Greer <mgreer@mvista.com>
Acked-by: Grant Likely <grant.likely@secretlab.ca>

Index: linux-2.6/arch/powerpc/boot/dts/prpmc2800.dts
===================================================================
--- linux-2.6.orig/arch/powerpc/boot/dts/prpmc2800.dts
+++ linux-2.6/arch/powerpc/boot/dts/prpmc2800.dts
@@ -44,7 +44,7 @@
 		#address-cells = <1>;
 		#size-cells = <1>;
 		model = "mv64360";			/* Default */
-		compatible = "marvell,mv64x60";
+		compatible = "mrvl,mv64x60";
 		clock-frequency = <7f28155>;		/* 133.333333 MHz */
 		reg = <f1000000 00010000>;
 		virtual-reg = <f1000000>;
@@ -72,7 +72,7 @@
 			#address-cells = <1>;
 			#size-cells = <0>;
 			device_type = "mdio";
-			compatible = "marvell,mv64x60-mdio";
+			compatible = "mrvl,mv64x60-mdio";
 			ethernet-phy@1 {
 				device_type = "ethernet-phy";
 				compatible = "broadcom,bcm5421";
@@ -93,7 +93,7 @@
 			reg = <2000 2000>;
 			eth0 {
 				device_type = "network";
-				compatible = "marvell,mv64x60-eth";
+				compatible = "mrvl,mv64x60-eth";
 				block-index = <0>;
 				interrupts = <20>;
 				interrupt-parent = <&/mv64x60/pic>;
@@ -102,7 +102,7 @@
 			};
 			eth1 {
 				device_type = "network";
-				compatible = "marvell,mv64x60-eth";
+				compatible = "mrvl,mv64x60-eth";
 				block-index = <1>;
 				interrupts = <21>;
 				interrupt-parent = <&/mv64x60/pic>;
@@ -113,7 +113,7 @@
 
 		sdma@4000 {
 			device_type = "dma";
-			compatible = "marvell,mv64x60-sdma";
+			compatible = "mrvl,mv64x60-sdma";
 			reg = <4000 c18>;
 			virtual-reg = <f1004000>;
 			interrupt-base = <0>;
@@ -123,7 +123,7 @@
 
 		sdma@6000 {
 			device_type = "dma";
-			compatible = "marvell,mv64x60-sdma";
+			compatible = "mrvl,mv64x60-sdma";
 			reg = <6000 c18>;
 			virtual-reg = <f1006000>;
 			interrupt-base = <0>;
@@ -132,7 +132,7 @@
 		};
 
 		brg@b200 {
-			compatible = "marvell,mv64x60-brg";
+			compatible = "mrvl,mv64x60-brg";
 			reg = <b200 8>;
 			clock-src = <8>;
 			clock-frequency = <7ed6b40>;
@@ -141,7 +141,7 @@
 		};
 
 		brg@b208 {
-			compatible = "marvell,mv64x60-brg";
+			compatible = "mrvl,mv64x60-brg";
 			reg = <b208 8>;
 			clock-src = <8>;
 			clock-frequency = <7ed6b40>;
@@ -164,7 +164,7 @@
 
 		mpsc@8000 {
 			device_type = "serial";
-			compatible = "marvell,mpsc";
+			compatible = "mrvl,mpsc";
 			reg = <8000 38>;
 			virtual-reg = <f1008000>;
 			sdma = <&/mv64x60/sdma@4000>;
@@ -184,7 +184,7 @@
 
 		mpsc@9000 {
 			device_type = "serial";
-			compatible = "marvell,mpsc";
+			compatible = "mrvl,mpsc";
 			reg = <9000 38>;
 			virtual-reg = <f1009000>;
 			sdma = <&/mv64x60/sdma@6000>;
@@ -203,14 +203,14 @@
 		};
 
 		wdt@b410 {			/* watchdog timer */
-			compatible = "marvell,mv64x60-wdt";
+			compatible = "mrvl,mv64x60-wdt";
 			reg = <b410 8>;
 			timeout = <a>;		/* wdt timeout in seconds */
 		};
 
 		i2c@c000 {
 			device_type = "i2c";
-			compatible = "marvell,mv64x60-i2c";
+			compatible = "mrvl,mv64x60-i2c";
 			reg = <c000 20>;
 			virtual-reg = <f100c000>;
 			freq_m = <8>;
@@ -224,18 +224,18 @@
 		pic {
 			#interrupt-cells = <1>;
 			#address-cells = <0>;
-			compatible = "marvell,mv64x60-pic";
+			compatible = "mrvl,mv64x60-pic";
 			reg = <0000 88>;
 			interrupt-controller;
 		};
 
 		mpp@f000 {
-			compatible = "marvell,mv64x60-mpp";
+			compatible = "mrvl,mv64x60-mpp";
 			reg = <f000 10>;
 		};
 
 		gpp@f100 {
-			compatible = "marvell,mv64x60-gpp";
+			compatible = "mrvl,mv64x60-gpp";
 			reg = <f100 20>;
 		};
 
@@ -244,7 +244,7 @@
 			#size-cells = <2>;
 			#interrupt-cells = <1>;
 			device_type = "pci";
-			compatible = "marvell,mv64x60-pci";
+			compatible = "mrvl,mv64x60-pci";
 			reg = <0cf8 8>;
 			ranges = <01000000 0        0 88000000 0 01000000
 				  02000000 0 80000000 80000000 0 08000000>;
@@ -281,28 +281,28 @@
 		};
 
 		cpu-error@0070 {
-			compatible = "marvell,mv64x60-cpu-error";
+			compatible = "mrvl,mv64x60-cpu-error";
 			reg = <0070 10 0128 28>;
 			interrupts = <03>;
 			interrupt-parent = <&/mv64x60/pic>;
 		};
 
 		sram-ctrl@0380 {
-			compatible = "marvell,mv64x60-sram-ctrl";
+			compatible = "mrvl,mv64x60-sram-ctrl";
 			reg = <0380 80>;
 			interrupts = <0d>;
 			interrupt-parent = <&/mv64x60/pic>;
 		};
 
 		pci-error@1d40 {
-			compatible = "marvell,mv64x60-pci-error";
+			compatible = "mrvl,mv64x60-pci-error";
 			reg = <1d40 40 0c28 4>;
 			interrupts = <0c>;
 			interrupt-parent = <&/mv64x60/pic>;
 		};
 
 		mem-ctrl@1400 {
-			compatible = "marvell,mv64x60-mem-ctrl";
+			compatible = "mrvl,mv64x60-mem-ctrl";
 			reg = <1400 60>;
 			interrupts = <11>;
 			interrupt-parent = <&/mv64x60/pic>;
Index: linux-2.6/arch/powerpc/boot/serial.c
===================================================================
--- linux-2.6.orig/arch/powerpc/boot/serial.c
+++ linux-2.6/arch/powerpc/boot/serial.c
@@ -119,7 +119,7 @@ int serial_console_init(void)
 
 	if (dt_is_compatible(devp, "ns16550"))
 		rc = ns16550_console_init(devp, &serial_cd);
-	else if (dt_is_compatible(devp, "marvell,mpsc"))
+	else if (dt_is_compatible(devp, "mrvl,mpsc"))
 		rc = mpsc_console_init(devp, &serial_cd);
 	else if (dt_is_compatible(devp, "fsl,cpm1-scc-uart") ||
 	         dt_is_compatible(devp, "fsl,cpm1-smc-uart") ||
Index: linux-2.6/arch/powerpc/platforms/embedded6xx/prpmc2800.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/embedded6xx/prpmc2800.c
+++ linux-2.6/arch/powerpc/platforms/embedded6xx/prpmc2800.c
@@ -49,13 +49,13 @@ static void __init prpmc2800_setup_arch(
 	 * ioremap mpp and gpp registers in case they are later
 	 * needed by prpmc2800_reset_board().
 	 */
-	np = of_find_compatible_node(NULL, NULL, "marvell,mv64x60-mpp");
+	np = of_find_compatible_node(NULL, NULL, "mrvl,mv64x60-mpp");
 	reg = of_get_property(np, "reg", NULL);
 	paddr = of_translate_address(np, reg);
 	of_node_put(np);
 	mv64x60_mpp_reg_base = ioremap(paddr, reg[1]);
 
-	np = of_find_compatible_node(NULL, NULL, "marvell,mv64x60-gpp");
+	np = of_find_compatible_node(NULL, NULL, "mrvl,mv64x60-gpp");
 	reg = of_get_property(np, "reg", NULL);
 	paddr = of_translate_address(np, reg);
 	of_node_put(np);
Index: linux-2.6/arch/powerpc/sysdev/mv64x60_dev.c
===================================================================
--- linux-2.6.orig/arch/powerpc/sysdev/mv64x60_dev.c
+++ linux-2.6/arch/powerpc/sysdev/mv64x60_dev.c
@@ -446,22 +446,22 @@ static int __init mv64x60_device_setup(v
 	int err;
 
 	id = 0;
-	for_each_compatible_node(np, "serial", "marvell,mpsc")
+	for_each_compatible_node(np, "serial", "mrvl,mpsc")
 		if ((err = mv64x60_mpsc_device_setup(np, id++)))
 			goto error;
 
 	id = 0;
-	for_each_compatible_node(np, "network", "marvell,mv64x60-eth")
+	for_each_compatible_node(np, "network", "mrvl,mv64x60-eth")
 		if ((err = mv64x60_eth_device_setup(np, id++)))
 			goto error;
 
 	id = 0;
-	for_each_compatible_node(np, "i2c", "marvell,mv64x60-i2c")
+	for_each_compatible_node(np, "i2c", "mrvl,mv64x60-i2c")
 		if ((err = mv64x60_i2c_device_setup(np, id++)))
 			goto error;
 
 	/* support up to one watchdog timer */
-	np = of_find_compatible_node(np, NULL, "marvell,mv64x60-wdt");
+	np = of_find_compatible_node(np, NULL, "mrvl,mv64x60-wdt");
 	if (np) {
 		if ((err = mv64x60_wdt_device_setup(np, id)))
 			goto error;
@@ -489,7 +489,7 @@ static int __init mv64x60_add_mpsc_conso
 	if (!np)
 		goto not_mpsc;
 
-	if (!of_device_is_compatible(np, "marvell,mpsc"))
+	if (!of_device_is_compatible(np, "mrvl,mpsc"))
 		goto not_mpsc;
 
 	prop = of_get_property(np, "block-index", NULL);
Index: linux-2.6/arch/powerpc/sysdev/mv64x60_pci.c
===================================================================
--- linux-2.6.orig/arch/powerpc/sysdev/mv64x60_pci.c
+++ linux-2.6/arch/powerpc/sysdev/mv64x60_pci.c
@@ -86,14 +86,14 @@ static int __init mv64x60_sysfs_init(voi
 	struct platform_device *pdev;
 	const unsigned int *prop;
 
-	np = of_find_compatible_node(NULL, NULL, "marvell,mv64x60");
+	np = of_find_compatible_node(NULL, NULL, "mrvl,mv64x60");
 	if (!np)
 		return 0;
 
 	prop = of_get_property(np, "hs_reg_valid", NULL);
 	of_node_put(np);
 
-	pdev = platform_device_register_simple("marvell,mv64x60", 0, NULL, 0);
+	pdev = platform_device_register_simple("mrvl,mv64x60", 0, NULL, 0);
 	if (IS_ERR(pdev))
 		return PTR_ERR(pdev);
 
@@ -166,6 +166,6 @@ void __init mv64x60_pci_init(void)
 {
 	struct device_node *np;
 
-	for_each_compatible_node(np, "pci", "marvell,mv64x60-pci")
+	for_each_compatible_node(np, "pci", "mrvl,mv64x60-pci")
 		mv64x60_add_bridge(np);
 }
Index: linux-2.6/arch/powerpc/sysdev/mv64x60_pic.c
===================================================================
--- linux-2.6.orig/arch/powerpc/sysdev/mv64x60_pic.c
+++ linux-2.6/arch/powerpc/sysdev/mv64x60_pic.c
@@ -238,13 +238,13 @@ void __init mv64x60_init_irq(void)
 	const unsigned int *reg;
 	unsigned long flags;
 
-	np = of_find_compatible_node(NULL, NULL, "marvell,mv64x60-gpp");
+	np = of_find_compatible_node(NULL, NULL, "mrvl,mv64x60-gpp");
 	reg = of_get_property(np, "reg", &size);
 	paddr = of_translate_address(np, reg);
 	mv64x60_gpp_reg_base = ioremap(paddr, reg[1]);
 	of_node_put(np);
 
-	np = of_find_compatible_node(NULL, NULL, "marvell,mv64x60-pic");
+	np = of_find_compatible_node(NULL, NULL, "mrvl,mv64x60-pic");
 	reg = of_get_property(np, "reg", &size);
 	paddr = of_translate_address(np, reg);
 	mv64x60_irq_reg_base = ioremap(paddr, reg[1]);
Index: linux-2.6/arch/powerpc/sysdev/mv64x60_udbg.c
===================================================================
--- linux-2.6.orig/arch/powerpc/sysdev/mv64x60_udbg.c
+++ linux-2.6/arch/powerpc/sysdev/mv64x60_udbg.c
@@ -85,7 +85,7 @@ static void mv64x60_udbg_init(void)
 	if (!stdout)
 		return;
 
-	for_each_compatible_node(np, "serial", "marvell,mpsc") {
+	for_each_compatible_node(np, "serial", "mrvl,mpsc") {
 		if (np == stdout)
 			break;
 	}

^ permalink raw reply

* [PATCH 2/9 v2] powerpc: prpmc2800: convert DTS to v1 and add labels
From: Dale Farnsworth @ 2008-04-07 18:46 UTC (permalink / raw)
  To: paulus; +Cc: linuxppc-dev
In-Reply-To: <20080407183228.GA7438@farnsworth.org>

From: Mark A. Greer <mgreer@mvista.com>

Update the prpmc2800 DTS file to version 1 and add labels.
I verified that there was no change in the resulting dtb file.

Signed-off-by: Mark A. Greer <mgreer@mvista.com>
Signed-off-by: Dale Farnsworth <dale@farnsworth.org>

---
 arch/powerpc/boot/dts/prpmc2800.dts |  264 +++++++++++++-------------
 1 file changed, 134 insertions(+), 130 deletions(-)

Index: linux-2.6/arch/powerpc/boot/dts/prpmc2800.dts
===================================================================
--- linux-2.6.orig/arch/powerpc/boot/dts/prpmc2800.dts
+++ linux-2.6/arch/powerpc/boot/dts/prpmc2800.dts
@@ -11,6 +11,8 @@
  * if it can determine the exact PrPMC type.
  */
 
+/dts-v1/;
+
 / {
 	#address-cells = <1>;
 	#size-cells = <1>;
@@ -25,19 +27,19 @@
 		PowerPC,7447 {
 			device_type = "cpu";
 			reg = <0>;
-			clock-frequency = <2bb0b140>;	/* Default (733 MHz) */
-			bus-frequency = <7f28155>;	/* 133.333333 MHz */
-			timebase-frequency = <1fca055>;	/* 33.333333 MHz */
-			i-cache-line-size = <20>;
-			d-cache-line-size = <20>;
-			i-cache-size = <8000>;
-			d-cache-size = <8000>;
+			clock-frequency = <733000000>;	/* Default */
+			bus-frequency = <133333333>;
+			timebase-frequency = <33333333>;
+			i-cache-line-size = <32>;
+			d-cache-line-size = <32>;
+			i-cache-size = <32768>;
+			d-cache-size = <32768>;
 		};
 	};
 
 	memory {
 		device_type = "memory";
-		reg = <00000000 20000000>;	/* Default (512MB) */
+		reg = <0x0 0x20000000>;			/* Default (512MB) */
 	};
 
 	mv64x60@f1000000 { /* Marvell Discovery */
@@ -45,26 +47,26 @@
 		#size-cells = <1>;
 		model = "mv64360";			/* Default */
 		compatible = "mrvl,mv64x60";
-		clock-frequency = <7f28155>;		/* 133.333333 MHz */
-		reg = <f1000000 00010000>;
-		virtual-reg = <f1000000>;
-		ranges = <88000000 88000000 01000000	/* PCI 0 I/O Space */
-			  80000000 80000000 08000000	/* PCI 0 MEM Space */
-			  a0000000 a0000000 04000000	/* User FLASH */
-			  00000000 f1000000 00010000	/* Bridge's regs */
-			  f2000000 f2000000 00040000>;	/* Integrated SRAM */
+		clock-frequency = <133333333>;
+		reg = <0xf1000000 0x10000>;
+		virtual-reg = <0xf1000000>;
+		ranges = <0x88000000 0x88000000 0x1000000 /* PCI 0 I/O Space */
+			  0x80000000 0x80000000 0x8000000 /* PCI 0 MEM Space */
+			  0xa0000000 0xa0000000 0x4000000 /* User FLASH */
+			  0x00000000 0xf1000000 0x0010000 /* Bridge's regs */
+			  0xf2000000 0xf2000000 0x0040000>;/* Integrated SRAM */
 
 		flash@a0000000 {
 			device_type = "rom";
 			compatible = "direct-mapped";
-			reg = <a0000000 4000000>; /* Default (64MB) */
+			reg = <0xa0000000 0x4000000>; /* Default (64MB) */
 			probe-type = "CFI";
 			bank-width = <4>;
-			partitions = <00000000 00100000 /* RO */
-				      00100000 00040001 /* RW */
-				      00140000 00400000 /* RO */
-				      00540000 039c0000 /* RO */
-				      03f00000 00100000>; /* RO */
+			partitions = <0x00000000 0x00100000 /* RO */
+				      0x00100000 0x00040001 /* RW */
+				      0x00140000 0x00400000 /* RO */
+				      0x00540000 0x039c0000 /* RO */
+				      0x03f00000 0x00100000>; /* RO */
 			partition-names = "FW Image A", "FW Config Data", "Kernel Image", "Filesystem", "FW Image B";
 		};
 
@@ -73,170 +75,170 @@
 			#size-cells = <0>;
 			device_type = "mdio";
 			compatible = "mrvl,mv64x60-mdio";
-			ethernet-phy@1 {
+			PHY0: ethernet-phy@1 {
 				device_type = "ethernet-phy";
 				compatible = "broadcom,bcm5421";
-				interrupts = <4c>;	/* GPP 12 */
-				interrupt-parent = <&/mv64x60/pic>;
+				interrupts = <76>;	/* GPP 12 */
+				interrupt-parent = <&PIC>;
 				reg = <1>;
 			};
-			ethernet-phy@3 {
+			PHY1: ethernet-phy@3 {
 				device_type = "ethernet-phy";
 				compatible = "broadcom,bcm5421";
-				interrupts = <4c>;	/* GPP 12 */
-				interrupt-parent = <&/mv64x60/pic>;
+				interrupts = <76>;	/* GPP 12 */
+				interrupt-parent = <&PIC>;
 				reg = <3>;
 			};
 		};
 
 		ethernet@2000 {
-			reg = <2000 2000>;
+			reg = <0x2000 0x2000>;
 			eth0 {
 				device_type = "network";
 				compatible = "mrvl,mv64x60-eth";
 				block-index = <0>;
-				interrupts = <20>;
-				interrupt-parent = <&/mv64x60/pic>;
-				phy = <&/mv64x60/mdio/ethernet-phy@1>;
+				interrupts = <32>;
+				interrupt-parent = <&PIC>;
+				phy = <&PHY0>;
 				local-mac-address = [ 00 00 00 00 00 00 ];
 			};
 			eth1 {
 				device_type = "network";
 				compatible = "mrvl,mv64x60-eth";
 				block-index = <1>;
-				interrupts = <21>;
-				interrupt-parent = <&/mv64x60/pic>;
-				phy = <&/mv64x60/mdio/ethernet-phy@3>;
+				interrupts = <33>;
+				interrupt-parent = <&PIC>;
+				phy = <&PHY1>;
 				local-mac-address = [ 00 00 00 00 00 00 ];
 			};
 		};
 
-		sdma@4000 {
+		SDMA0: sdma@4000 {
 			device_type = "dma";
 			compatible = "mrvl,mv64x60-sdma";
-			reg = <4000 c18>;
-			virtual-reg = <f1004000>;
+			reg = <0x4000 0xc18>;
+			virtual-reg = <0xf1004000>;
 			interrupt-base = <0>;
-			interrupts = <24>;
-			interrupt-parent = <&/mv64x60/pic>;
+			interrupts = <36>;
+			interrupt-parent = <&PIC>;
 		};
 
-		sdma@6000 {
+		SDMA1: sdma@6000 {
 			device_type = "dma";
 			compatible = "mrvl,mv64x60-sdma";
-			reg = <6000 c18>;
-			virtual-reg = <f1006000>;
+			reg = <0x6000 0xc18>;
+			virtual-reg = <0xf1006000>;
 			interrupt-base = <0>;
-			interrupts = <26>;
-			interrupt-parent = <&/mv64x60/pic>;
+			interrupts = <38>;
+			interrupt-parent = <&PIC>;
 		};
 
-		brg@b200 {
+		BRG0: brg@b200 {
 			compatible = "mrvl,mv64x60-brg";
-			reg = <b200 8>;
+			reg = <0xb200 0x8>;
 			clock-src = <8>;
-			clock-frequency = <7ed6b40>;
-			current-speed = <2580>;
+			clock-frequency = <133000000>;
+			current-speed = <9600>;
 			bcr = <0>;
 		};
 
-		brg@b208 {
+		BRG1: brg@b208 {
 			compatible = "mrvl,mv64x60-brg";
-			reg = <b208 8>;
+			reg = <0xb208 0x8>;
 			clock-src = <8>;
-			clock-frequency = <7ed6b40>;
-			current-speed = <2580>;
+			clock-frequency = <133000000>;
+			current-speed = <9600>;
 			bcr = <0>;
 		};
 
-		cunit@f200 {
-			reg = <f200 200>;
+		CUNIT: cunit@f200 {
+			reg = <0xf200 0x200>;
 		};
 
-		mpscrouting@b400 {
-			reg = <b400 c>;
+		MPSCROUTING: mpscrouting@b400 {
+			reg = <0xb400 0xc>;
 		};
 
-		mpscintr@b800 {
-			reg = <b800 100>;
-			virtual-reg = <f100b800>;
+		MPSCINTR: mpscintr@b800 {
+			reg = <0xb800 0x100>;
+			virtual-reg = <0xf100b800>;
 		};
 
-		mpsc@8000 {
+		MPSC0: mpsc@8000 {
 			device_type = "serial";
 			compatible = "mrvl,mpsc";
-			reg = <8000 38>;
-			virtual-reg = <f1008000>;
-			sdma = <&/mv64x60/sdma@4000>;
-			brg = <&/mv64x60/brg@b200>;
-			cunit = <&/mv64x60/cunit@f200>;
-			mpscrouting = <&/mv64x60/mpscrouting@b400>;
-			mpscintr = <&/mv64x60/mpscintr@b800>;
+			reg = <0x8000 0x38>;
+			virtual-reg = <0xf1008000>;
+			sdma = <&SDMA0>;
+			brg = <&BRG0>;
+			cunit = <&CUNIT>;
+			mpscrouting = <&MPSCROUTING>;
+			mpscintr = <&MPSCINTR>;
 			block-index = <0>;
-			max_idle = <28>;
+			max_idle = <40>;
 			chr_1 = <0>;
 			chr_2 = <0>;
 			chr_10 = <3>;
 			mpcr = <0>;
-			interrupts = <28>;
-			interrupt-parent = <&/mv64x60/pic>;
+			interrupts = <40>;
+			interrupt-parent = <&PIC>;
 		};
 
-		mpsc@9000 {
+		MPSC1: mpsc@9000 {
 			device_type = "serial";
 			compatible = "mrvl,mpsc";
-			reg = <9000 38>;
-			virtual-reg = <f1009000>;
-			sdma = <&/mv64x60/sdma@6000>;
-			brg = <&/mv64x60/brg@b208>;
-			cunit = <&/mv64x60/cunit@f200>;
-			mpscrouting = <&/mv64x60/mpscrouting@b400>;
-			mpscintr = <&/mv64x60/mpscintr@b800>;
+			reg = <0x9000 0x38>;
+			virtual-reg = <0xf1009000>;
+			sdma = <&SDMA1>;
+			brg = <&BRG1>;
+			cunit = <&CUNIT>;
+			mpscrouting = <&MPSCROUTING>;
+			mpscintr = <&MPSCINTR>;
 			block-index = <1>;
-			max_idle = <28>;
+			max_idle = <40>;
 			chr_1 = <0>;
 			chr_2 = <0>;
 			chr_10 = <3>;
 			mpcr = <0>;
-			interrupts = <2a>;
-			interrupt-parent = <&/mv64x60/pic>;
+			interrupts = <42>;
+			interrupt-parent = <&PIC>;
 		};
 
 		wdt@b410 {			/* watchdog timer */
 			compatible = "mrvl,mv64x60-wdt";
-			reg = <b410 8>;
-			timeout = <a>;		/* wdt timeout in seconds */
+			reg = <0xb410 0x8>;
+			timeout = <10>;		/* wdt timeout in seconds */
 		};
 
 		i2c@c000 {
 			device_type = "i2c";
 			compatible = "mrvl,mv64x60-i2c";
-			reg = <c000 20>;
-			virtual-reg = <f100c000>;
+			reg = <0xc000 0x20>;
+			virtual-reg = <0xf100c000>;
 			freq_m = <8>;
 			freq_n = <3>;
-			timeout = <3e8>;		/* 1000 = 1 second */
+			timeout = <1000>;		/* 1000 = 1 second */
 			retries = <1>;
-			interrupts = <25>;
-			interrupt-parent = <&/mv64x60/pic>;
+			interrupts = <37>;
+			interrupt-parent = <&PIC>;
 		};
 
-		pic {
+		PIC: pic {
 			#interrupt-cells = <1>;
 			#address-cells = <0>;
 			compatible = "mrvl,mv64x60-pic";
-			reg = <0000 88>;
+			reg = <0x0 0x88>;
 			interrupt-controller;
 		};
 
 		mpp@f000 {
 			compatible = "mrvl,mv64x60-mpp";
-			reg = <f000 10>;
+			reg = <0xf000 0x10>;
 		};
 
 		gpp@f100 {
 			compatible = "mrvl,mv64x60-gpp";
-			reg = <f100 20>;
+			reg = <0xf100 0x20>;
 		};
 
 		pci@80000000 {
@@ -245,72 +247,74 @@
 			#interrupt-cells = <1>;
 			device_type = "pci";
 			compatible = "mrvl,mv64x60-pci";
-			reg = <0cf8 8>;
-			ranges = <01000000 0        0 88000000 0 01000000
-				  02000000 0 80000000 80000000 0 08000000>;
-			bus-range = <0 ff>;
-			clock-frequency = <3EF1480>;
-			interrupt-pci-iack = <0c34>;
-			interrupt-parent = <&/mv64x60/pic>;
-			interrupt-map-mask = <f800 0 0 7>;
+			reg = <0xcf8 0x8>;
+			ranges = <0x01000000 0x0        0x0
+					0x88000000 0x0 0x01000000
+				  0x02000000 0x0 0x80000000
+				  	0x80000000 0x0 0x08000000>;
+			bus-range = <0 255>;
+			clock-frequency = <66000000>;
+			interrupt-pci-iack = <0xc34>;
+			interrupt-parent = <&PIC>;
+			interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
 			interrupt-map = <
 				/* IDSEL 0x0a */
-				5000 0 0 1 &/mv64x60/pic 50
-				5000 0 0 2 &/mv64x60/pic 51
-				5000 0 0 3 &/mv64x60/pic 5b
-				5000 0 0 4 &/mv64x60/pic 5d
+				0x5000 0 0 1 &PIC 80
+				0x5000 0 0 2 &PIC 81
+				0x5000 0 0 3 &PIC 91
+				0x5000 0 0 4 &PIC 93
 
 				/* IDSEL 0x0b */
-				5800 0 0 1 &/mv64x60/pic 5b
-				5800 0 0 2 &/mv64x60/pic 5d
-				5800 0 0 3 &/mv64x60/pic 50
-				5800 0 0 4 &/mv64x60/pic 51
+				0x5800 0 0 1 &PIC 91
+				0x5800 0 0 2 &PIC 93
+				0x5800 0 0 3 &PIC 80
+				0x5800 0 0 4 &PIC 81
 
 				/* IDSEL 0x0c */
-				6000 0 0 1 &/mv64x60/pic 5b
-				6000 0 0 2 &/mv64x60/pic 5d
-				6000 0 0 3 &/mv64x60/pic 50
-				6000 0 0 4 &/mv64x60/pic 51
+				0x6000 0 0 1 &PIC 91
+				0x6000 0 0 2 &PIC 93
+				0x6000 0 0 3 &PIC 80
+				0x6000 0 0 4 &PIC 81
 
 				/* IDSEL 0x0d */
-				6800 0 0 1 &/mv64x60/pic 5d
-				6800 0 0 2 &/mv64x60/pic 50
-				6800 0 0 3 &/mv64x60/pic 51
-				6800 0 0 4 &/mv64x60/pic 5b
+				0x6800 0 0 1 &PIC 93
+				0x6800 0 0 2 &PIC 80
+				0x6800 0 0 3 &PIC 81
+				0x6800 0 0 4 &PIC 91
 			>;
 		};
 
 		cpu-error@0070 {
 			compatible = "mrvl,mv64x60-cpu-error";
-			reg = <0070 10 0128 28>;
-			interrupts = <03>;
-			interrupt-parent = <&/mv64x60/pic>;
+			reg = <0x70 0x10 0x128 0x28>;
+			interrupts = <3>;
+			interrupt-parent = <&PIC>;
 		};
 
 		sram-ctrl@0380 {
 			compatible = "mrvl,mv64x60-sram-ctrl";
-			reg = <0380 80>;
-			interrupts = <0d>;
-			interrupt-parent = <&/mv64x60/pic>;
+			reg = <0x380 0x80>;
+			interrupts = <13>;
+			interrupt-parent = <&PIC>;
 		};
 
 		pci-error@1d40 {
 			compatible = "mrvl,mv64x60-pci-error";
-			reg = <1d40 40 0c28 4>;
-			interrupts = <0c>;
-			interrupt-parent = <&/mv64x60/pic>;
+			reg = <0x1d40 0x40 0xc28 0x4>;
+			interrupts = <12>;
+			interrupt-parent = <&PIC>;
 		};
 
 		mem-ctrl@1400 {
 			compatible = "mrvl,mv64x60-mem-ctrl";
-			reg = <1400 60>;
-			interrupts = <11>;
-			interrupt-parent = <&/mv64x60/pic>;
+			reg = <0x1400 0x60>;
+			interrupts = <17>;
+			interrupt-parent = <&PIC>;
 		};
 	};
 
 	chosen {
 		bootargs = "ip=on";
-		linux,stdout-path = "/mv64x60@f1000000/mpsc@8000";
+		linux,stdout-path = &MPSC0;
 	};
 };

^ permalink raw reply

* [PATCH 3/9 v2] powerpc: fix frequencies in prpmc2800.dts
From: Dale Farnsworth @ 2008-04-07 18:47 UTC (permalink / raw)
  To: paulus; +Cc: linuxppc-dev
In-Reply-To: <20080407183228.GA7438@farnsworth.org>

From: Dale Farnsworth <dale@farnsworth.org>

After the conversion to dts v1 format, seeing the frequencies
in decimal made it obvious that some of them had been
incorrectly truncated.  This fixes them.  Note that the PCI
frequency comes from a different source and is documented
as 66MHz, so it was left at 66000000.

Signed-off-by: Dale Farnsworth <dale@farnsworth.org>
Acked-by: Mark A. Greer <mgreer@mvista.com>

---
 arch/powerpc/boot/dts/prpmc2800.dts |    6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

Index: linux-2.6/arch/powerpc/boot/dts/prpmc2800.dts
===================================================================
--- linux-2.6.orig/arch/powerpc/boot/dts/prpmc2800.dts
+++ linux-2.6/arch/powerpc/boot/dts/prpmc2800.dts
@@ -27,7 +27,7 @@
 		PowerPC,7447 {
 			device_type = "cpu";
 			reg = <0>;
-			clock-frequency = <733000000>;	/* Default */
+			clock-frequency = <733333333>;	/* Default */
 			bus-frequency = <133333333>;
 			timebase-frequency = <33333333>;
 			i-cache-line-size = <32>;
@@ -137,7 +137,7 @@
 			compatible = "mrvl,mv64x60-brg";
 			reg = <0xb200 0x8>;
 			clock-src = <8>;
-			clock-frequency = <133000000>;
+			clock-frequency = <133333333>;
 			current-speed = <9600>;
 			bcr = <0>;
 		};
@@ -146,7 +146,7 @@
 			compatible = "mrvl,mv64x60-brg";
 			reg = <0xb208 0x8>;
 			clock-src = <8>;
-			clock-frequency = <133000000>;
+			clock-frequency = <133333333>;
 			current-speed = <9600>;
 			bcr = <0>;
 		};

^ permalink raw reply

* [PATCH 4/9 v2] powerpc: mv64x60: Fix FDT compatible names: mv64x60 => mv64360
From: Dale Farnsworth @ 2008-04-07 18:49 UTC (permalink / raw)
  To: paulus; +Cc: linuxppc-dev
In-Reply-To: <20080407183228.GA7438@farnsworth.org>

From: Mark A. Greer <mgreer@mvista.com>

Compatible names should refer to a specific version of the hardware,
without wildcards.  Change each instance of mv64x60 to mv64360, which
is the oldest version we currently support.

Signed-off-by: Mark A. Greer <mgreer@mvista.com>
Signed-off-by: Dale Farnsworth <dale@farnsworth.org>

---
 arch/powerpc/boot/dts/prpmc2800.dts            |   40 +++++++--------
 arch/powerpc/boot/serial.c                     |    2 
 arch/powerpc/platforms/embedded6xx/prpmc2800.c |    4 -
 arch/powerpc/sysdev/mv64x60_dev.c              |   10 +--
 arch/powerpc/sysdev/mv64x60_pci.c              |    6 +-
 arch/powerpc/sysdev/mv64x60_pic.c              |    4 -
 arch/powerpc/sysdev/mv64x60_udbg.c             |    2 
 7 files changed, 34 insertions(+), 34 deletions(-)

Index: linux-2.6/arch/powerpc/boot/dts/prpmc2800.dts
===================================================================
--- linux-2.6.orig/arch/powerpc/boot/dts/prpmc2800.dts
+++ linux-2.6/arch/powerpc/boot/dts/prpmc2800.dts
@@ -46,7 +46,7 @@
 		#address-cells = <1>;
 		#size-cells = <1>;
 		model = "mv64360";			/* Default */
-		compatible = "mrvl,mv64x60";
+		compatible = "mrvl,mv64360";
 		clock-frequency = <133333333>;
 		reg = <0xf1000000 0x10000>;
 		virtual-reg = <0xf1000000>;
@@ -74,7 +74,7 @@
 			#address-cells = <1>;
 			#size-cells = <0>;
 			device_type = "mdio";
-			compatible = "mrvl,mv64x60-mdio";
+			compatible = "mrvl,mv64360-mdio";
 			PHY0: ethernet-phy@1 {
 				device_type = "ethernet-phy";
 				compatible = "broadcom,bcm5421";
@@ -95,7 +95,7 @@
 			reg = <0x2000 0x2000>;
 			eth0 {
 				device_type = "network";
-				compatible = "mrvl,mv64x60-eth";
+				compatible = "mrvl,mv64360-eth";
 				block-index = <0>;
 				interrupts = <32>;
 				interrupt-parent = <&PIC>;
@@ -104,7 +104,7 @@
 			};
 			eth1 {
 				device_type = "network";
-				compatible = "mrvl,mv64x60-eth";
+				compatible = "mrvl,mv64360-eth";
 				block-index = <1>;
 				interrupts = <33>;
 				interrupt-parent = <&PIC>;
@@ -115,7 +115,7 @@
 
 		SDMA0: sdma@4000 {
 			device_type = "dma";
-			compatible = "mrvl,mv64x60-sdma";
+			compatible = "mrvl,mv64360-sdma";
 			reg = <0x4000 0xc18>;
 			virtual-reg = <0xf1004000>;
 			interrupt-base = <0>;
@@ -125,7 +125,7 @@
 
 		SDMA1: sdma@6000 {
 			device_type = "dma";
-			compatible = "mrvl,mv64x60-sdma";
+			compatible = "mrvl,mv64360-sdma";
 			reg = <0x6000 0xc18>;
 			virtual-reg = <0xf1006000>;
 			interrupt-base = <0>;
@@ -134,7 +134,7 @@
 		};
 
 		BRG0: brg@b200 {
-			compatible = "mrvl,mv64x60-brg";
+			compatible = "mrvl,mv64360-brg";
 			reg = <0xb200 0x8>;
 			clock-src = <8>;
 			clock-frequency = <133333333>;
@@ -143,7 +143,7 @@
 		};
 
 		BRG1: brg@b208 {
-			compatible = "mrvl,mv64x60-brg";
+			compatible = "mrvl,mv64360-brg";
 			reg = <0xb208 0x8>;
 			clock-src = <8>;
 			clock-frequency = <133333333>;
@@ -166,7 +166,7 @@
 
 		MPSC0: mpsc@8000 {
 			device_type = "serial";
-			compatible = "mrvl,mpsc";
+			compatible = "mrvl,mv64360-mpsc";
 			reg = <0x8000 0x38>;
 			virtual-reg = <0xf1008000>;
 			sdma = <&SDMA0>;
@@ -186,7 +186,7 @@
 
 		MPSC1: mpsc@9000 {
 			device_type = "serial";
-			compatible = "mrvl,mpsc";
+			compatible = "mrvl,mv64360-mpsc";
 			reg = <0x9000 0x38>;
 			virtual-reg = <0xf1009000>;
 			sdma = <&SDMA1>;
@@ -205,14 +205,14 @@
 		};
 
 		wdt@b410 {			/* watchdog timer */
-			compatible = "mrvl,mv64x60-wdt";
+			compatible = "mrvl,mv64360-wdt";
 			reg = <0xb410 0x8>;
 			timeout = <10>;		/* wdt timeout in seconds */
 		};
 
 		i2c@c000 {
 			device_type = "i2c";
-			compatible = "mrvl,mv64x60-i2c";
+			compatible = "mrvl,mv64360-i2c";
 			reg = <0xc000 0x20>;
 			virtual-reg = <0xf100c000>;
 			freq_m = <8>;
@@ -226,18 +226,18 @@
 		PIC: pic {
 			#interrupt-cells = <1>;
 			#address-cells = <0>;
-			compatible = "mrvl,mv64x60-pic";
+			compatible = "mrvl,mv64360-pic";
 			reg = <0x0 0x88>;
 			interrupt-controller;
 		};
 
 		mpp@f000 {
-			compatible = "mrvl,mv64x60-mpp";
+			compatible = "mrvl,mv64360-mpp";
 			reg = <0xf000 0x10>;
 		};
 
 		gpp@f100 {
-			compatible = "mrvl,mv64x60-gpp";
+			compatible = "mrvl,mv64360-gpp";
 			reg = <0xf100 0x20>;
 		};
 
@@ -246,7 +246,7 @@
 			#size-cells = <2>;
 			#interrupt-cells = <1>;
 			device_type = "pci";
-			compatible = "mrvl,mv64x60-pci";
+			compatible = "mrvl,mv64360-pci";
 			reg = <0xcf8 0x8>;
 			ranges = <0x01000000 0x0        0x0
 					0x88000000 0x0 0x01000000
@@ -285,28 +285,28 @@
 		};
 
 		cpu-error@0070 {
-			compatible = "mrvl,mv64x60-cpu-error";
+			compatible = "mrvl,mv64360-cpu-error";
 			reg = <0x70 0x10 0x128 0x28>;
 			interrupts = <3>;
 			interrupt-parent = <&PIC>;
 		};
 
 		sram-ctrl@0380 {
-			compatible = "mrvl,mv64x60-sram-ctrl";
+			compatible = "mrvl,mv64360-sram-ctrl";
 			reg = <0x380 0x80>;
 			interrupts = <13>;
 			interrupt-parent = <&PIC>;
 		};
 
 		pci-error@1d40 {
-			compatible = "mrvl,mv64x60-pci-error";
+			compatible = "mrvl,mv64360-pci-error";
 			reg = <0x1d40 0x40 0xc28 0x4>;
 			interrupts = <12>;
 			interrupt-parent = <&PIC>;
 		};
 
 		mem-ctrl@1400 {
-			compatible = "mrvl,mv64x60-mem-ctrl";
+			compatible = "mrvl,mv64360-mem-ctrl";
 			reg = <0x1400 0x60>;
 			interrupts = <17>;
 			interrupt-parent = <&PIC>;
Index: linux-2.6/arch/powerpc/boot/serial.c
===================================================================
--- linux-2.6.orig/arch/powerpc/boot/serial.c
+++ linux-2.6/arch/powerpc/boot/serial.c
@@ -119,7 +119,7 @@ int serial_console_init(void)
 
 	if (dt_is_compatible(devp, "ns16550"))
 		rc = ns16550_console_init(devp, &serial_cd);
-	else if (dt_is_compatible(devp, "mrvl,mpsc"))
+	else if (dt_is_compatible(devp, "mrvl,mv64360-mpsc"))
 		rc = mpsc_console_init(devp, &serial_cd);
 	else if (dt_is_compatible(devp, "fsl,cpm1-scc-uart") ||
 	         dt_is_compatible(devp, "fsl,cpm1-smc-uart") ||
Index: linux-2.6/arch/powerpc/platforms/embedded6xx/prpmc2800.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/embedded6xx/prpmc2800.c
+++ linux-2.6/arch/powerpc/platforms/embedded6xx/prpmc2800.c
@@ -49,13 +49,13 @@ static void __init prpmc2800_setup_arch(
 	 * ioremap mpp and gpp registers in case they are later
 	 * needed by prpmc2800_reset_board().
 	 */
-	np = of_find_compatible_node(NULL, NULL, "mrvl,mv64x60-mpp");
+	np = of_find_compatible_node(NULL, NULL, "mrvl,mv64360-mpp");
 	reg = of_get_property(np, "reg", NULL);
 	paddr = of_translate_address(np, reg);
 	of_node_put(np);
 	mv64x60_mpp_reg_base = ioremap(paddr, reg[1]);
 
-	np = of_find_compatible_node(NULL, NULL, "mrvl,mv64x60-gpp");
+	np = of_find_compatible_node(NULL, NULL, "mrvl,mv64360-gpp");
 	reg = of_get_property(np, "reg", NULL);
 	paddr = of_translate_address(np, reg);
 	of_node_put(np);
Index: linux-2.6/arch/powerpc/sysdev/mv64x60_dev.c
===================================================================
--- linux-2.6.orig/arch/powerpc/sysdev/mv64x60_dev.c
+++ linux-2.6/arch/powerpc/sysdev/mv64x60_dev.c
@@ -446,22 +446,22 @@ static int __init mv64x60_device_setup(v
 	int err;
 
 	id = 0;
-	for_each_compatible_node(np, "serial", "mrvl,mpsc")
+	for_each_compatible_node(np, "serial", "mrvl,mv64360-mpsc")
 		if ((err = mv64x60_mpsc_device_setup(np, id++)))
 			goto error;
 
 	id = 0;
-	for_each_compatible_node(np, "network", "mrvl,mv64x60-eth")
+	for_each_compatible_node(np, "network", "mrvl,mv64360-eth")
 		if ((err = mv64x60_eth_device_setup(np, id++)))
 			goto error;
 
 	id = 0;
-	for_each_compatible_node(np, "i2c", "mrvl,mv64x60-i2c")
+	for_each_compatible_node(np, "i2c", "mrvl,mv64360-i2c")
 		if ((err = mv64x60_i2c_device_setup(np, id++)))
 			goto error;
 
 	/* support up to one watchdog timer */
-	np = of_find_compatible_node(np, NULL, "mrvl,mv64x60-wdt");
+	np = of_find_compatible_node(np, NULL, "mrvl,mv64360-wdt");
 	if (np) {
 		if ((err = mv64x60_wdt_device_setup(np, id)))
 			goto error;
@@ -489,7 +489,7 @@ static int __init mv64x60_add_mpsc_conso
 	if (!np)
 		goto not_mpsc;
 
-	if (!of_device_is_compatible(np, "mrvl,mpsc"))
+	if (!of_device_is_compatible(np, "mrvl,mv64360-mpsc"))
 		goto not_mpsc;
 
 	prop = of_get_property(np, "block-index", NULL);
Index: linux-2.6/arch/powerpc/sysdev/mv64x60_pci.c
===================================================================
--- linux-2.6.orig/arch/powerpc/sysdev/mv64x60_pci.c
+++ linux-2.6/arch/powerpc/sysdev/mv64x60_pci.c
@@ -86,14 +86,14 @@ static int __init mv64x60_sysfs_init(voi
 	struct platform_device *pdev;
 	const unsigned int *prop;
 
-	np = of_find_compatible_node(NULL, NULL, "mrvl,mv64x60");
+	np = of_find_compatible_node(NULL, NULL, "mrvl,mv64360");
 	if (!np)
 		return 0;
 
 	prop = of_get_property(np, "hs_reg_valid", NULL);
 	of_node_put(np);
 
-	pdev = platform_device_register_simple("mrvl,mv64x60", 0, NULL, 0);
+	pdev = platform_device_register_simple("mrvl,mv64360", 0, NULL, 0);
 	if (IS_ERR(pdev))
 		return PTR_ERR(pdev);
 
@@ -166,6 +166,6 @@ void __init mv64x60_pci_init(void)
 {
 	struct device_node *np;
 
-	for_each_compatible_node(np, "pci", "mrvl,mv64x60-pci")
+	for_each_compatible_node(np, "pci", "mrvl,mv64360-pci")
 		mv64x60_add_bridge(np);
 }
Index: linux-2.6/arch/powerpc/sysdev/mv64x60_pic.c
===================================================================
--- linux-2.6.orig/arch/powerpc/sysdev/mv64x60_pic.c
+++ linux-2.6/arch/powerpc/sysdev/mv64x60_pic.c
@@ -238,13 +238,13 @@ void __init mv64x60_init_irq(void)
 	const unsigned int *reg;
 	unsigned long flags;
 
-	np = of_find_compatible_node(NULL, NULL, "mrvl,mv64x60-gpp");
+	np = of_find_compatible_node(NULL, NULL, "mrvl,mv64360-gpp");
 	reg = of_get_property(np, "reg", &size);
 	paddr = of_translate_address(np, reg);
 	mv64x60_gpp_reg_base = ioremap(paddr, reg[1]);
 	of_node_put(np);
 
-	np = of_find_compatible_node(NULL, NULL, "mrvl,mv64x60-pic");
+	np = of_find_compatible_node(NULL, NULL, "mrvl,mv64360-pic");
 	reg = of_get_property(np, "reg", &size);
 	paddr = of_translate_address(np, reg);
 	mv64x60_irq_reg_base = ioremap(paddr, reg[1]);
Index: linux-2.6/arch/powerpc/sysdev/mv64x60_udbg.c
===================================================================
--- linux-2.6.orig/arch/powerpc/sysdev/mv64x60_udbg.c
+++ linux-2.6/arch/powerpc/sysdev/mv64x60_udbg.c
@@ -85,7 +85,7 @@ static void mv64x60_udbg_init(void)
 	if (!stdout)
 		return;
 
-	for_each_compatible_node(np, "serial", "mrvl,mpsc") {
+	for_each_compatible_node(np, "serial", "mrvl,mv64360-mpsc") {
 		if (np == stdout)
 			break;
 	}

^ permalink raw reply

* [PATCH 5/9 v2] powerpc: mv64x60: remove device tree absolute path references
From: Dale Farnsworth @ 2008-04-07 18:50 UTC (permalink / raw)
  To: paulus; +Cc: linuxppc-dev
In-Reply-To: <20080407183228.GA7438@farnsworth.org>

From: Dale Farnsworth <dale@farnsworth.org>

Replace several device node absolute path lookups in the mv64x60
bootwrapper code with lookups by compatible or device_type
properties.

Signed-off-by: Dale Farnsworth <dale@farnsworth.org>
Acked-by: Mark A. Greer <mgreer@mvista.com>

---
 arch/powerpc/boot/mv64x60.c     |    4 ++--
 arch/powerpc/boot/mv64x60_i2c.c |    2 +-
 arch/powerpc/boot/prpmc2800.c   |   23 ++++++++++++-----------
 3 files changed, 15 insertions(+), 14 deletions(-)

--- a/arch/powerpc/boot/mv64x60.c
+++ b/arch/powerpc/boot/mv64x60.c
@@ -535,7 +535,7 @@ u8 *mv64x60_get_bridge_pbase(void)
 	u32 v[2];
 	void *devp;
 
-	devp = finddevice("/mv64x60");
+	devp = find_node_by_compatible(NULL, "mrvl,mv64360");
 	if (devp == NULL)
 		goto err_out;
 	if (getprop(devp, "reg", v, sizeof(v)) != sizeof(v))
@@ -553,7 +553,7 @@ u8 *mv64x60_get_bridge_base(void)
 	u32 v;
 	void *devp;
 
-	devp = finddevice("/mv64x60");
+	devp = find_node_by_compatible(NULL, "mrvl,mv64360");
 	if (devp == NULL)
 		goto err_out;
 	if (getprop(devp, "virtual-reg", &v, sizeof(v)) != sizeof(v))
diff --git a/arch/powerpc/boot/mv64x60_i2c.c b/arch/powerpc/boot/mv64x60_i2c.c
index d085377..a69cd7a 100644
--- a/arch/powerpc/boot/mv64x60_i2c.c
+++ b/arch/powerpc/boot/mv64x60_i2c.c
@@ -185,7 +185,7 @@ int mv64x60_i2c_open(void)
 	u32 v;
 	void *devp;
 
-	devp = finddevice("/mv64x60/i2c");
+	devp = find_node_by_compatible(NULL, "mrvl,mv64360-i2c");
 	if (devp == NULL)
 		goto err_out;
 	if (getprop(devp, "virtual-reg", &v, sizeof(v)) != sizeof(v))
diff --git a/arch/powerpc/boot/prpmc2800.c b/arch/powerpc/boot/prpmc2800.c
index 05c3245..f74b2cf 100644
--- a/arch/powerpc/boot/prpmc2800.c
+++ b/arch/powerpc/boot/prpmc2800.c
@@ -344,20 +344,20 @@ static void prpmc2800_bridge_setup(u32 mem_size)
 			acc_bits);
 
 	/* Get the cpu -> pci i/o & mem mappings from the device tree */
-	devp = finddevice("/mv64x60/pci@80000000");
+	devp = find_node_by_compatible(NULL, "mrvl,mv64360-pci");
 	if (devp == NULL)
-		fatal("Error: Missing /mv64x60/pci@80000000"
+		fatal("Error: Missing mrvl,mv64360-pci"
 				" device tree node\n\r");
 
 	rc = getprop(devp, "ranges", v, sizeof(v));
 	if (rc != sizeof(v))
-		fatal("Error: Can't find /mv64x60/pci@80000000/ranges"
+		fatal("Error: Can't find mrvl,mv64360-pci ranges"
 				" property\n\r");
 
 	/* Get the cpu -> pci i/o & mem mappings from the device tree */
-	devp = finddevice("/mv64x60");
+	devp = find_node_by_compatible(NULL, "mrvl,mv64360");
 	if (devp == NULL)
-		fatal("Error: Missing /mv64x60 device tree node\n\r");
+		fatal("Error: Missing mrvl,mv64360 device tree node\n\r");
 
 	enables = in_le32((u32 *)(bridge_base + MV64x60_CPU_BAR_ENABLE));
 	enables |= 0x0007fe00; /* Disable all cpu->pci windows */
@@ -429,9 +429,9 @@ static void prpmc2800_fixups(void)
 	setprop(devp, "model", model, l);
 
 	/* Set /cpus/PowerPC,7447/clock-frequency */
-	devp = finddevice("/cpus/PowerPC,7447");
+	devp = find_node_by_prop_value_str(NULL, "device_type", "cpu");
 	if (devp == NULL)
-		fatal("Error: Missing proper /cpus device tree node\n\r");
+		fatal("Error: Missing proper cpu device tree node\n\r");
 	v[0] = bip->core_speed;
 	setprop(devp, "clock-frequency", &v[0], sizeof(v[0]));
 
@@ -443,16 +443,17 @@ static void prpmc2800_fixups(void)
 	v[1] = bip->mem_size;
 	setprop(devp, "reg", v, sizeof(v));
 
-	/* Update /mv64x60/model, if this is a mv64362 */
+	/* Update model, if this is a mv64362 */
 	if (bip->bridge_type == BRIDGE_TYPE_MV64362) {
-		devp = finddevice("/mv64x60");
+		devp = find_node_by_compatible(NULL, "mrvl,mv64360");
 		if (devp == NULL)
-			fatal("Error: Missing /mv64x60 device tree node\n\r");
+			fatal("Error: Missing mrvl,mv64360"
+					" device tree node\n\r");
 		setprop(devp, "model", "mv64362", strlen("mv64362") + 1);
 	}
 
 	/* Set User FLASH size */
-	devp = finddevice("/mv64x60/flash@a0000000");
+	devp = find_node_by_compatible(NULL, "direct-mapped");
 	if (devp == NULL)
 		fatal("Error: Missing User FLASH device tree node\n\r");
 	rc = getprop(devp, "reg", v, sizeof(v));

^ permalink raw reply related

* [PATCH 6/9 v2] powerpc: prpmc2800: clean up dts properties
From: Dale Farnsworth @ 2008-04-07 18:51 UTC (permalink / raw)
  To: paulus; +Cc: linuxppc-dev
In-Reply-To: <20080407183228.GA7438@farnsworth.org>

From: Mark A. Greer <mgreer@mvista.com>

Remove several unused (or software config only) properties.
Rename marvel node to "system-controller".  Also, rename the
"block-index" property to "cell-index" to conform to current
practice.

Signed-off-by: Mark A. Greer <mgreer@mvista.com>
Signed-off-by: Dale Farnsworth <dale@farnsworth.org>

---
 arch/powerpc/boot/dts/prpmc2800.dts |   27 ++------------------------
 arch/powerpc/boot/mpsc.c            |    2 -
 arch/powerpc/sysdev/mv64x60_dev.c   |   18 ++++++-----------
 3 files changed, 11 insertions(+), 36 deletions(-)

Index: linux-2.6/arch/powerpc/boot/dts/prpmc2800.dts
===================================================================
--- linux-2.6.orig/arch/powerpc/boot/dts/prpmc2800.dts
+++ linux-2.6/arch/powerpc/boot/dts/prpmc2800.dts
@@ -42,7 +42,7 @@
 		reg = <0x0 0x20000000>;			/* Default (512MB) */
 	};
 
-	mv64x60@f1000000 { /* Marvell Discovery */
+	system-controller@f1000000 { /* Marvell Discovery mv64360 */
 		#address-cells = <1>;
 		#size-cells = <1>;
 		model = "mv64360";			/* Default */
@@ -114,21 +114,17 @@
 		};
 
 		SDMA0: sdma@4000 {
-			device_type = "dma";
 			compatible = "mrvl,mv64360-sdma";
 			reg = <0x4000 0xc18>;
 			virtual-reg = <0xf1004000>;
-			interrupt-base = <0>;
 			interrupts = <36>;
 			interrupt-parent = <&PIC>;
 		};
 
 		SDMA1: sdma@6000 {
-			device_type = "dma";
 			compatible = "mrvl,mv64360-sdma";
 			reg = <0x6000 0xc18>;
 			virtual-reg = <0xf1006000>;
-			interrupt-base = <0>;
 			interrupts = <38>;
 			interrupt-parent = <&PIC>;
 		};
@@ -139,7 +135,6 @@
 			clock-src = <8>;
 			clock-frequency = <133333333>;
 			current-speed = <9600>;
-			bcr = <0>;
 		};
 
 		BRG1: brg@b208 {
@@ -148,7 +143,6 @@
 			clock-src = <8>;
 			clock-frequency = <133333333>;
 			current-speed = <9600>;
-			bcr = <0>;
 		};
 
 		CUNIT: cunit@f200 {
@@ -174,12 +168,7 @@
 			cunit = <&CUNIT>;
 			mpscrouting = <&MPSCROUTING>;
 			mpscintr = <&MPSCINTR>;
-			block-index = <0>;
-			max_idle = <40>;
-			chr_1 = <0>;
-			chr_2 = <0>;
-			chr_10 = <3>;
-			mpcr = <0>;
+			cell-index = <0>;
 			interrupts = <40>;
 			interrupt-parent = <&PIC>;
 		};
@@ -194,12 +183,7 @@
 			cunit = <&CUNIT>;
 			mpscrouting = <&MPSCROUTING>;
 			mpscintr = <&MPSCINTR>;
-			block-index = <1>;
-			max_idle = <40>;
-			chr_1 = <0>;
-			chr_2 = <0>;
-			chr_10 = <3>;
-			mpcr = <0>;
+			cell-index = <1>;
 			interrupts = <42>;
 			interrupt-parent = <&PIC>;
 		};
@@ -207,7 +191,6 @@
 		wdt@b410 {			/* watchdog timer */
 			compatible = "mrvl,mv64360-wdt";
 			reg = <0xb410 0x8>;
-			timeout = <10>;		/* wdt timeout in seconds */
 		};
 
 		i2c@c000 {
@@ -215,10 +198,6 @@
 			compatible = "mrvl,mv64360-i2c";
 			reg = <0xc000 0x20>;
 			virtual-reg = <0xf100c000>;
-			freq_m = <8>;
-			freq_n = <3>;
-			timeout = <1000>;		/* 1000 = 1 second */
-			retries = <1>;
 			interrupts = <37>;
 			interrupt-parent = <&PIC>;
 		};
Index: linux-2.6/arch/powerpc/boot/mpsc.c
===================================================================
--- linux-2.6.orig/arch/powerpc/boot/mpsc.c
+++ linux-2.6/arch/powerpc/boot/mpsc.c
@@ -141,7 +141,7 @@ int mpsc_console_init(void *devp, struct
 	if (mpscintr_base == NULL)
 		goto err_out;
 
-	n = getprop(devp, "block-index", &v, sizeof(v));
+	n = getprop(devp, "cell-index", &v, sizeof(v));
 	if (n != sizeof(v))
 		goto err_out;
 	reg_set = (int)v;
Index: linux-2.6/arch/powerpc/sysdev/mv64x60_dev.c
===================================================================
--- linux-2.6.orig/arch/powerpc/sysdev/mv64x60_dev.c
+++ linux-2.6/arch/powerpc/sysdev/mv64x60_dev.c
@@ -127,7 +127,7 @@ static int __init mv64x60_mpsc_device_se
 	if (err)
 		return err;
 
-	prop = of_get_property(np, "block-index", NULL);
+	prop = of_get_property(np, "cell-index", NULL);
 	if (!prop)
 		return -ENODEV;
 	port_number = *(int *)prop;
@@ -136,6 +136,7 @@ static int __init mv64x60_mpsc_device_se
 
 	pdata.cache_mgmt = 1; /* All current revs need this set */
 
+	pdata.max_idle = 40; /* default */
 	prop = of_get_property(np, "max_idle", NULL);
 	if (prop)
 		pdata.max_idle = *prop;
@@ -345,21 +346,19 @@ static int __init mv64x60_i2c_device_set
 
 	memset(&pdata, 0, sizeof(pdata));
 
+	pdata.freq_m = 8;	/* default */
 	prop = of_get_property(np, "freq_m", NULL);
 	if (!prop)
 		return -ENODEV;
 	pdata.freq_m = *prop;
 
+	pdata.freq_m = 3;	/* default */
 	prop = of_get_property(np, "freq_n", NULL);
 	if (!prop)
 		return -ENODEV;
 	pdata.freq_n = *prop;
 
-	prop = of_get_property(np, "timeout", NULL);
-	if (prop)
-		pdata.timeout = *prop;
-	else
-		pdata.timeout = 1000;	/* 1 second */
+	pdata.timeout = 1000;				/* default: 1 second */
 
 	pdev = platform_device_alloc(MV64XXX_I2C_CTLR_NAME, id);
 	if (!pdev)
@@ -401,10 +400,7 @@ static int __init mv64x60_wdt_device_set
 
 	memset(&pdata, 0, sizeof(pdata));
 
-	prop = of_get_property(np, "timeout", NULL);
-	if (!prop)
-		return -ENODEV;
-	pdata.timeout = *prop;
+	pdata.timeout = 10;			/* Default: 10 seconds */
 
 	np = of_get_parent(np);
 	if (!np)
@@ -492,7 +488,7 @@ static int __init mv64x60_add_mpsc_conso
 	if (!of_device_is_compatible(np, "mrvl,mv64360-mpsc"))
 		goto not_mpsc;
 
-	prop = of_get_property(np, "block-index", NULL);
+	prop = of_get_property(np, "cell-index", NULL);
 	if (!prop)
 		goto not_mpsc;
 

^ permalink raw reply

* [PATCH 7/9 v2] powerpc: mv643xx_eth: prepare to support multiple silicon blocks
From: Dale Farnsworth @ 2008-04-07 18:53 UTC (permalink / raw)
  To: paulus; +Cc: linuxppc-dev
In-Reply-To: <20080407183228.GA7438@farnsworth.org>

From: Dale Farnsworth <dale@farnsworth.org>

The mv643xx_eth driver is being modified to support multiple instances
of the ethernet silicon block on the same platform.  Each block contains
a single register bank containing the registers for up to three ports
interleaved within that bank.  This patch updates the PowerPC OF to
platform_device glue code to support multiple silicon blocks, each
with up to three ethernet ports.  The main difference is that we now
allow multiple mv64x60_shared platform_devices to be registered and
we provide each port platform_device with a pointer to its associated
shared platform_device.  The pointer will not be used until the
mv643xx_eth driver changes are committed.

Signed-off-by: Dale Farnsworth <dale@farnsworth.org>
Acked-by: Mark Greer <mgreer@mvista.com>

---
 arch/powerpc/boot/dts/prpmc2800.dts |   13 ++++--
 arch/powerpc/sysdev/mv64x60_dev.c   |   52 ++++++++++++++------------
 2 files changed, 37 insertions(+), 28 deletions(-)

Index: linux-2.6/arch/powerpc/boot/dts/prpmc2800.dts
===================================================================
--- linux-2.6.orig/arch/powerpc/boot/dts/prpmc2800.dts
+++ linux-2.6/arch/powerpc/boot/dts/prpmc2800.dts
@@ -91,21 +91,24 @@
 			};
 		};
 
-		ethernet@2000 {
+		ethernet-group@2000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "mrvl,mv64360-eth-group";
 			reg = <0x2000 0x2000>;
-			eth0 {
+			ethernet@0 {
 				device_type = "network";
 				compatible = "mrvl,mv64360-eth";
-				block-index = <0>;
+				reg = <0>;
 				interrupts = <32>;
 				interrupt-parent = <&PIC>;
 				phy = <&PHY0>;
 				local-mac-address = [ 00 00 00 00 00 00 ];
 			};
-			eth1 {
+			ethernet@1 {
 				device_type = "network";
 				compatible = "mrvl,mv64360-eth";
-				block-index = <1>;
+				reg = <1>;
 				interrupts = <33>;
 				interrupt-parent = <&PIC>;
 				phy = <&PHY1>;
Index: linux-2.6/arch/powerpc/sysdev/mv64x60_dev.c
===================================================================
--- linux-2.6.orig/arch/powerpc/sysdev/mv64x60_dev.c
+++ linux-2.6/arch/powerpc/sysdev/mv64x60_dev.c
@@ -206,30 +206,24 @@ error:
 /*
  * Create mv64x60_eth platform devices
  */
-static int __init eth_register_shared_pdev(struct device_node *np)
+static struct platform_device * __init mv64x60_eth_register_shared_pdev(
+						struct device_node *np, int id)
 {
 	struct platform_device *pdev;
 	struct resource r[1];
 	int err;
 
-	np = of_get_parent(np);
-	if (!np)
-		return -ENODEV;
-
 	err = of_address_to_resource(np, 0, &r[0]);
-	of_node_put(np);
 	if (err)
-		return err;
+		return ERR_PTR(err);
 
-	pdev = platform_device_register_simple(MV643XX_ETH_SHARED_NAME, 0,
+	pdev = platform_device_register_simple(MV643XX_ETH_SHARED_NAME, id,
 					       r, 1);
-	if (IS_ERR(pdev))
-		return PTR_ERR(pdev);
-
-	return 0;
+	return pdev;
 }
 
-static int __init mv64x60_eth_device_setup(struct device_node *np, int id)
+static int __init mv64x60_eth_device_setup(struct device_node *np, int id,
+					   struct platform_device *shared_pdev)
 {
 	struct resource r[1];
 	struct mv643xx_eth_platform_data pdata;
@@ -240,16 +234,12 @@ static int __init mv64x60_eth_device_set
 	const phandle *ph;
 	int err;
 
-	/* only register the shared platform device the first time through */
-	if (id == 0 && (err = eth_register_shared_pdev(np)))
-		return err;
-
 	memset(r, 0, sizeof(r));
 	of_irq_to_resource(np, 0, &r[0]);
 
 	memset(&pdata, 0, sizeof(pdata));
 
-	prop = of_get_property(np, "block-index", NULL);
+	prop = of_get_property(np, "reg", NULL);
 	if (!prop)
 		return -ENODEV;
 	pdata.port_number = *prop;
@@ -302,7 +292,7 @@ static int __init mv64x60_eth_device_set
 
 	of_node_put(phy);
 
-	pdev = platform_device_alloc(MV643XX_ETH_NAME, pdata.port_number);
+	pdev = platform_device_alloc(MV643XX_ETH_NAME, id);
 	if (!pdev)
 		return -ENOMEM;
 
@@ -437,8 +427,9 @@ error:
 
 static int __init mv64x60_device_setup(void)
 {
-	struct device_node *np = NULL;
-	int id;
+	struct device_node *np, *np2;
+	struct platform_device *pdev;
+	int id, id2;
 	int err;
 
 	id = 0;
@@ -447,9 +438,24 @@ static int __init mv64x60_device_setup(v
 			goto error;
 
 	id = 0;
-	for_each_compatible_node(np, "network", "mrvl,mv64360-eth")
-		if ((err = mv64x60_eth_device_setup(np, id++)))
+	id2 = 0;
+	for_each_compatible_node(np, NULL, "mrvl,mv64360-eth-group") {
+		pdev = mv64x60_eth_register_shared_pdev(np, id++);
+		if (IS_ERR(pdev)) {
+			err = PTR_ERR(pdev);
 			goto error;
+		}
+		for_each_child_of_node(np, np2) {
+			if (!of_device_is_compatible(np2,
+					"mrvl,mv64360-eth"))
+				continue;
+			err = mv64x60_eth_device_setup(np2, id2++, pdev);
+			if (err) {
+				of_node_put(np2);
+				goto error;
+			}
+		}
+	}
 
 	id = 0;
 	for_each_compatible_node(np, "i2c", "mrvl,mv64360-i2c")

^ permalink raw reply

* [PATCH 8/9 v2] powerpc: Document the mv64x60 device tree bindings
From: Dale Farnsworth @ 2008-04-07 18:54 UTC (permalink / raw)
  To: paulus; +Cc: linuxppc-dev
In-Reply-To: <20080407183228.GA7438@farnsworth.org>

From: Dale Farnsworth <dale@farnsworth.org>

Add the device tree bindings for the Marvell mv64x60 series of
system controller chips in booting-without-of.text.

Signed-off-by: Dale Farnsworth <dale@farnsworth.org>
Acked-by: Mark A. Greer <mgreer@mvista.com>

---
 Documentation/powerpc/booting-without-of.txt |  549 ++++++++++++++++-
 1 file changed, 546 insertions(+), 3 deletions(-)

Index: linux-2.6/Documentation/powerpc/booting-without-of.txt
===================================================================
--- linux-2.6.orig/Documentation/powerpc/booting-without-of.txt
+++ linux-2.6/Documentation/powerpc/booting-without-of.txt
@@ -59,7 +59,30 @@ Table of Contents
       p) Freescale Synchronous Serial Interface
 	  q) USB EHCI controllers
 
-  VII - Specifying interrupt information for devices
+  VII - Marvell Discovery mv64[345]6x System Controller chips
+    1) The /system-controller node
+    2) Child nodes of /system-controller
+      a) Marvell Discovery MDIO bus
+      b) Marvell Discovery ethernet controller
+      c) Marvell Discovery PHY nodes
+      d) Marvell Discovery SDMA nodes
+      e) Marvell Discovery BRG nodes
+      f) Marvell Discovery CUNIT nodes
+      g) Marvell Discovery MPSCROUTING nodes
+      h) Marvell Discovery MPSCINTR nodes
+      i) Marvell Discovery MPSC nodes
+      j) Marvell Discovery Watch Dog Timer nodes
+      k) Marvell Discovery I2C nodes
+      l) Marvell Discovery PIC (Programmable Interrupt Controller) nodes
+      m) Marvell Discovery MPP (Multipurpose Pins) multiplexing nodes
+      n) Marvell Discovery GPP (General Purpose Pins) nodes
+      o) Marvell Discovery PCI host bridge node
+      p) Marvell Discovery CPU Error nodes
+      q) Marvell Discovery SRAM Controller nodes
+      r) Marvell Discovery PCI Error Handler nodes
+      s) Marvell Discovery Memory Controller nodes
+
+  VIII - Specifying interrupt information for devices
     1) interrupts property
     2) interrupt-parent property
     3) OpenPIC Interrupt Controllers
@@ -2817,9 +2840,529 @@ platforms are moved over to use the flat
 	   };
 
 
-   More devices will be defined as this spec matures.
+VII - Marvell Discovery mv64[345]6x System Controller chips
+===========================================================
+
+The Marvell mv64[345]60 series of system controller chips contain
+many of the peripherals needed to implement a complete computer
+system.  In this section, we define device tree nodes to describe
+the system controller chip itself and each of the peripherals
+which it contains.  Compatible string values for each node are
+prefixed with the string "mrvl,", which is the stock ticker symbol
+for Marvell Technology Group Ltd.
+
+1) The /system-controller node
+
+  This node is used to represent the system-controller and must be
+  present when the system uses a system contller chip. The top-level
+  system-controller node contains information that is global to all
+  devices within the system controller chip. The node name begins
+  with "system-controller" followed by the unit address, which is
+  the base address of the memory-mapped register set for the system
+  controller chip.
+
+  Required properties:
+
+    - ranges : Describes the translation of system controller addresses
+      for memory mapped registers.
+    - clock-frequency: Contains the main clock frequency for the system
+      controller chip.
+    - reg : This property defines the address and size of the
+      memory-mapped registers contained within the system controller
+      chip.  The address specified in the "reg" property should match
+      the unit address of the system-controller node.
+    - #address-cells : Address representation for system controller
+      devices.  This field represents the number of cells needed to
+      represent the address of the memory-mapped registers of devices
+      within the system controller chip.
+    - #size-cells : Size representation for for the memory-mapped
+      registers within the system controller chip.
+    - #interrupt-cells : Defines the width of cells used to represent
+      interrupts.
+
+  Optional properties:
+
+    - model : The specific model of the system controller chip.  Such
+      as, "mv64360", "mv64460", or "mv64560".
+    - compatible : A string identifying the compatibility identifiers
+      of the system controller chip.
+
+  The system-controller node contains child nodes for each system
+  controller device that the platform uses.  Nodes should not be created
+  for devices which exist on the system controller chip but are not used
+  
+  Example Marvell Discovery mv64360 system-controller node:
+
+    system-controller@f1000000 { /* Marvell Discovery mv64360 */
+	    #address-cells = <1>;
+	    #size-cells = <1>;
+	    model = "mv64360";                      /* Default */
+	    compatible = "mrvl,mv64360";
+	    clock-frequency = <133333333>;
+	    reg = <0xf1000000 0x10000>;
+	    virtual-reg = <0xf1000000>;
+	    ranges = <0x88000000 0x88000000 0x1000000 /* PCI 0 I/O Space */
+		    0x80000000 0x80000000 0x8000000 /* PCI 0 MEM Space */
+		    0xa0000000 0xa0000000 0x4000000 /* User FLASH */
+		    0x00000000 0xf1000000 0x0010000 /* Bridge's regs */
+		    0xf2000000 0xf2000000 0x0040000>;/* Integrated SRAM */
+
+	    [ child node definitions... ]
+    }
+
+2) Child nodes of /system-controller
+   
+   a) Marvell Discovery MDIO bus
+
+   The MDIO is a bus to which the PHY devices are connected.  For each
+   device that exists on this bus, a child node should be created.  See
+   the definition of the PHY node below for an example of how to define
+   a PHY.
+
+   Required properties:
+     - #address-cells : Should be <1>
+     - #size-cells : Should be <0>
+     - device_type : Should be "mdio"
+     - compatible : Should be "mrvl,mv64360-mdio"
+
+   Example:
+
+     mdio {
+	     #address-cells = <1>;
+	     #size-cells = <0>;
+	     device_type = "mdio";
+	     compatible = "mrvl,mv64360-mdio";
+
+	     ethernet-phy@0 {
+		     ......
+	     };
+     };
+
+
+   b) Marvell Discovery ethernet controller
+   
+   The Discover ethernet controller is described with two levels
+   of nodes.  The first level describes an ethernet silicon block
+   and the second level describes up to 3 ethernet nodes within
+   that block.  The reason for the multiple levels is that the
+   registers for the node are interleaved within a single set
+   of registers.  The "ethernet-block" level describes the
+   shared register set, and the "ethernet" nodes describe ethernet
+   port-specific properties.
+
+   Ethernet block node
+
+   Required properties:
+     - #address-cells : <1>
+     - #size-cells : <0>
+     - compatible : "mrvl,mv64360-eth-block"
+     - reg : Offset and length of the register set for this block
+     
+   Example Discovery Ethernet block node:
+     ethernet-block@2000 {
+	     #address-cells = <1>;
+	     #size-cells = <0>;
+	     compatible = "mrvl,mv64360-eth-block";
+	     reg = <0x2000 0x2000>;
+	     ethernet@0 {
+		     .......
+	     };
+     };
+
+   Ethernet port node
+
+   Required properties:
+     - device_type : Should be "network".
+     - compatible : Should be "mrvl,mv64360-eth".
+     - reg : Should be <0>, <1>, or <2>, according to which registers
+       within the silicon block the device uses.
+     - interrupts : <a> where a is the interrupt number for the port.
+     - interrupt-parent : the phandle for the interrupt controller
+       that services interrupts for this device.
+     - phy : the phandle for the PHY connected to this ethernet
+       controller.
+     - local-mac-address : 6 bytes, MAC address
+
+   Example Discovery Ethernet port node:
+     ethernet@0 {
+	     device_type = "network";
+	     compatible = "mrvl,mv64360-eth";
+	     reg = <0>;
+	     interrupts = <32>;
+	     interrupt-parent = <&PIC>;
+	     phy = <&PHY0>;
+	     local-mac-address = [ 00 00 00 00 00 00 ];
+     };
+
+
+
+   c) Marvell Discovery PHY nodes
+
+   Required properties:
+     - device_type : Should be "ethernet-phy"
+     - interrupts : <a> where a is the interrupt number for this phy.
+     - interrupt-parent : the phandle for the interrupt controller that
+       services interrupts for this device.
+     - reg : The ID number for the phy, usually a small integer
+
+   Example Discovery PHY node:
+     ethernet-phy@1 {
+	     device_type = "ethernet-phy";
+	     compatible = "broadcom,bcm5421";
+	     interrupts = <76>;      /* GPP 12 */
+	     interrupt-parent = <&PIC>;
+	     reg = <1>;
+     };
+
+
+   d) Marvell Discovery SDMA nodes
+
+   Represent DMA hardware associated with the MPSC (multiprotocol
+   serial controllers).
+
+   Required properties:
+     - compatible : "mrvl,mv64360-sdma"
+     - reg : Offset and length of the register set for this device
+     - interrupts : <a> where a is the interrupt number for the DMA
+       device.
+     - interrupt-parent : the phandle for the interrupt controller
+       that services interrupts for this device.
+
+   Example Discovery SDMA node:
+     sdma@4000 {
+	     compatible = "mrvl,mv64360-sdma";
+	     reg = <0x4000 0xc18>;
+	     virtual-reg = <0xf1004000>;
+	     interrupts = <36>;
+	     interrupt-parent = <&PIC>;
+     };
+   
+
+   e) Marvell Discovery BRG nodes
+
+   Represent baud rate generator hardware associated with the MPSC
+   (multiprotocol serial controllers).
+
+   Required properties:
+     - compatible : "mrvl,mv64360-brg"
+     - reg : Offset and length of the register set for this device
+     - clock-src : A value from 0 to 15 which selects the clock
+       source for the baud rate generator.  This value corresponds
+       to the CLKS value in the BRGx configuration register.  See
+       the mv64x60 User's Manual.
+     - clock-frequence : The frequency (in Hz) of the baud rate
+       generator's input clock.
+     - current-speed : The current speed setting (presumably by
+       firmware) of the baud rate generator.
+
+   Example Discovery BRG node:
+     brg@b200 {
+	     compatible = "mrvl,mv64360-brg";
+	     reg = <0xb200 0x8>;
+	     clock-src = <8>;
+	     clock-frequency = <133333333>;
+	     current-speed = <9600>;
+     };
+
+   
+   f) Marvell Discovery CUNIT nodes
+
+   Represent the Serial Communications Unit device hardware.
+
+   Required properties:
+     - reg : Offset and length of the register set for this device
+
+   Example Discovery CUNIT node:
+     cunit@f200 {
+	     reg = <0xf200 0x200>;
+     };
+
+
+   g) Marvell Discovery MPSCROUTING nodes
+
+   Represent the Discovery's MPSC routing hardware
+
+   Required properties:
+     - reg : Offset and length of the register set for this device
+
+   Example Discovery CUNIT node:
+     mpscrouting@b500 {
+	     reg = <0xb400 0xc>;
+     };
+
+
+   h) Marvell Discovery MPSCINTR nodes
+
+   Represent the Discovery's MPSC DMA interrupt hardware registers
+   (SDMA cause and mask registers).
+
+   Required properties:
+     - reg : Offset and length of the register set for this device
+
+   Example Discovery MPSCINTR node:
+     mpsintr@b800 {
+	     reg = <0xb800 0x100>;
+     };
+
+
+   i) Marvell Discovery MPSC nodes
+
+   Represent the Discovery's MPSC (Multiprotocol Serial Controller)
+   serial port.
+
+   Required properties:
+     - device_type : "serial"
+     - compatible : "mrvl,mv64360-mpsc"
+     - reg : Offset and length of the register set for this device
+     - sdma : the phandle for the SDMA node used by this port
+     - brg : the phandle for the BRG node used by this port
+     - cunit : the phandle for the CUNIT node used by this port
+     - mpscrouting : the phandle for the MPSCROUTING node used by this port
+     - mpscintr : the phandle for the MPSCINTR node used by this port
+     - cell-index : the hardware index of this cell in the MPSC core
+     - max_idle : value needed for MPSC CHR3 (Maximum Frame Length)
+       register
+     - interrupts : <a> where a is the interrupt number for the MPSC.
+     - interrupt-parent : the phandle for the interrupt controller
+       that services interrupts for this device.
+     
+   Example Discovery MPSCINTR node:
+     mpsc@8000 {
+	     device_type = "serial";
+	     compatible = "mrvl,mv64360-mpsc";
+	     reg = <0x8000 0x38>;
+	     virtual-reg = <0xf1008000>;
+	     sdma = <&SDMA0>;
+	     brg = <&BRG0>;
+	     cunit = <&CUNIT>;
+	     mpscrouting = <&MPSCROUTING>;
+	     mpscintr = <&MPSCINTR>;
+	     cell-index = <0>;
+	     max_idle = <40>;
+	     interrupts = <40>;
+	     interrupt-parent = <&PIC>;
+     };
+
+
+   j) Marvell Discovery Watch Dog Timer nodes
+
+   Represent the Discovery's watchdog timer hardware
+
+   Required properties:
+     - compatible : "mrvl,mv64360-wdt"
+     - reg : Offset and length of the register set for this device
+
+   Example Discovery Watch Dog Timer node:
+     wdt@b410 {
+	     compatible = "mrvl,mv64360-wdt";
+	     reg = <0xb410 0x8>;
+     };
+
+
+   k) Marvell Discovery I2C nodes
+
+   Represent the Discovery's I2C hardware
+
+   Required properties:
+     - device_type : "i2c"
+     - compatible : "mrvl,mv64360-i2c"
+     - reg : Offset and length of the register set for this device
+     - interrupts : <a> where a is the interrupt number for the I2C.
+     - interrupt-parent : the phandle for the interrupt controller
+       that services interrupts for this device.
+
+   Example Discovery I2C node:
+	     compatible = "mrvl,mv64360-i2c";
+	     reg = <0xc000 0x20>;
+	     virtual-reg = <0xf100c000>;
+	     interrupts = <37>;
+	     interrupt-parent = <&PIC>;
+     };
+
+
+   l) Marvell Discovery PIC (Programmable Interrupt Controller) nodes
+
+   Represent the Discovery's PIC hardware
+
+   Required properties:
+     - #interrupt-cells : <1>
+     - #address-cells : <0>
+     - compatible : "mrvl,mv64360-pic"
+     - reg : Offset and length of the register set for this device
+     - interrupt-controller
+
+   Example Discovery PIC node:
+     pic {
+	     #interrupt-cells = <1>;
+	     #address-cells = <0>;
+	     compatible = "mrvl,mv64360-pic";
+	     reg = <0x0 0x88>;
+	     interrupt-controller;
+     };
+
+
+   m) Marvell Discovery MPP (Multipurpose Pins) multiplexing nodes
+
+   Represent the Discovery's MPP hardware
+
+   Required properties:
+     - compatible : "mrvl,mv64360-mpp"
+     - reg : Offset and length of the register set for this device
+
+   Example Discovery MPP node:
+     mpp@f000 {
+	     compatible = "mrvl,mv64360-mpp";
+	     reg = <0xf000 0x10>;
+     };
+
+
+   n) Marvell Discovery GPP (General Purpose Pins) nodes
+
+   Represent the Discovery's GPP hardware
+
+   Required properties:
+     - compatible : "mrvl,mv64360-gpp"
+     - reg : Offset and length of the register set for this device
+
+   Example Discovery GPP node:
+     gpp@f000 {
+	     compatible = "mrvl,mv64360-gpp";
+	     reg = <0xf100 0x20>;
+     };
+
+
+   o) Marvell Discovery PCI host bridge node
+
+   Represents the Discovery's PCI host bridge device.  The properties
+   for this node conform to Rev 2.1 of the PCI Bus Binding to IEEE
+   1275-1994.  A typical value for the compatible property is
+   "mrvl,mv64360-pci".
+
+   Example Discovery PCI host bridge node
+     pci@80000000 {       
+	     #address-cells = <3>;
+	     #size-cells = <2>;
+	     #interrupt-cells = <1>;
+	     device_type = "pci";
+	     compatible = "mrvl,mv64360-pci";
+	     reg = <0xcf8 0x8>;
+	     ranges = <0x01000000 0x0        0x0
+			     0x88000000 0x0 0x01000000
+		       0x02000000 0x0 0x80000000
+			     0x80000000 0x0 0x08000000>;
+	     bus-range = <0 255>;
+	     clock-frequency = <66000000>;
+	     interrupt-parent = <&PIC>;
+	     interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+	     interrupt-map = <
+		     /* IDSEL 0x0a */
+		     0x5000 0 0 1 &PIC 80
+		     0x5000 0 0 2 &PIC 81
+		     0x5000 0 0 3 &PIC 91
+		     0x5000 0 0 4 &PIC 93
+
+		     /* IDSEL 0x0b */
+		     0x5800 0 0 1 &PIC 91
+		     0x5800 0 0 2 &PIC 93
+		     0x5800 0 0 3 &PIC 80
+		     0x5800 0 0 4 &PIC 81
+
+		     /* IDSEL 0x0c */
+		     0x6000 0 0 1 &PIC 91
+		     0x6000 0 0 2 &PIC 93
+		     0x6000 0 0 3 &PIC 80
+		     0x6000 0 0 4 &PIC 81
+
+		     /* IDSEL 0x0d */
+		     0x6800 0 0 1 &PIC 93
+		     0x6800 0 0 2 &PIC 80
+		     0x6800 0 0 3 &PIC 81
+		     0x6800 0 0 4 &PIC 91
+	     >;
+     };
+
+
+   p) Marvell Discovery CPU Error nodes
+
+   Represent the Discovery's CPU error handler device.
+
+   Required properties:
+     - compatible : "mrvl,mv64360-cpu-error"
+     - reg : Offset and length of the register set for this device
+     - interrupts : the interrupt number for this device
+     - interrupt-parent : the phandle for the interrupt controller
+       that services interrupts for this device.
+
+   Example Discovery CPU Error node:
+     cpu-error@0070 {
+	     compatible = "mrvl,mv64360-cpu-error";
+	     reg = <0x70 0x10 0x128 0x28>;
+	     interrupts = <3>;
+	     interrupt-parent = <&PIC>;
+     };
+
+
+   q) Marvell Discovery SRAM Controller nodes
+
+   Represent the Discovery's SRAM controller device.
+
+   Required properties:
+     - compatible : "mrvl,mv64360-sram-ctrl"
+     - reg : Offset and length of the register set for this device
+     - interrupts : the interrupt number for this device
+     - interrupt-parent : the phandle for the interrupt controller
+       that services interrupts for this device.
+
+   Example Discovery SRAM Controller node:
+     sram-ctrl@0380 {
+	     compatible = "mrvl,mv64360-sram-ctrl";
+	     reg = <0x380 0x80>;
+	     interrupts = <13>;
+	     interrupt-parent = <&PIC>;
+     };
+
+
+   r) Marvell Discovery PCI Error Handler nodes
+
+   Represent the Discovery's PCI error handler device.
+
+   Required properties:
+     - compatible : "mrvl,mv64360-pci-error"
+     - reg : Offset and length of the register set for this device
+     - interrupts : the interrupt number for this device
+     - interrupt-parent : the phandle for the interrupt controller
+       that services interrupts for this device.
+
+   Example Discovery PCI Error Handler node:
+     pci-error@1d40 {
+	     compatible = "mrvl,mv64360-pci-error";
+	     reg = <0x1d40 0x40 0xc28 0x4>;
+	     interrupts = <12>;
+	     interrupt-parent = <&PIC>;
+     };
+
+
+   s) Marvell Discovery Memory Controller nodes
+
+   Represent the Discovery's memory controller device.
+
+   Required properties:
+     - compatible : "mrvl,mv64360-mem-ctrl"
+     - reg : Offset and length of the register set for this device
+     - interrupts : the interrupt number for this device
+     - interrupt-parent : the phandle for the interrupt controller
+       that services interrupts for this device.
+
+   Example Discovery Memory Controller node:
+     mem-ctrl@1400 {
+	     compatible = "mrvl,mv64360-mem-ctrl";
+	     reg = <0x1400 0x60>;
+	     interrupts = <17>;
+	     interrupt-parent = <&PIC>;
+     };
+
 
-VII - Specifying interrupt information for devices
+VIII - Specifying interrupt information for devices
 ===================================================
 
 The device tree represents the busses and devices of a hardware

^ permalink raw reply

* [PATCH 9/9 v2] powerpc: prpmc2800 needs a dtbImage
From: Dale Farnsworth @ 2008-04-07 18:55 UTC (permalink / raw)
  To: paulus; +Cc: linuxppc-dev
In-Reply-To: <20080407183228.GA7438@farnsworth.org>

From: Dale Farnsworth <dale@farnsworth.org>

The prpmc2800 platform requires a zImage formatted file with an
embedded dtb file.  Rename the requested boot image file to
dtbImage.prpmc2800.

Signed-off-by: Dale Farnsworth <dale@farnsworth.org>
Acked-by: Mark A. Greer <mgreer@mvista.com>
Acked-by: Grant Likely <grant.likely@secretlab.ca>

---
 arch/powerpc/boot/Makefile |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

--- a/arch/powerpc/boot/Makefile
+++ b/arch/powerpc/boot/Makefile
@@ -192,7 +192,7 @@ image-$(CONFIG_PPC_CHRP)		+= zImage.chrp
 image-$(CONFIG_PPC_EFIKA)		+= zImage.chrp
 image-$(CONFIG_PPC_PMAC)		+= zImage.pmac
 image-$(CONFIG_PPC_HOLLY)		+= zImage.holly
-image-$(CONFIG_PPC_PRPMC2800)		+= zImage.prpmc2800
+image-$(CONFIG_PPC_PRPMC2800)		+= dtbImage.prpmc2800
 image-$(CONFIG_PPC_ISERIES)		+= zImage.iseries
 image-$(CONFIG_DEFAULT_UIMAGE)		+= uImage
 

^ permalink raw reply

* Re: MVL Linux on MPC8560 Booting goes into infinite loop in early_init memset_io ( )
From: David Baird @ 2008-04-07 19:50 UTC (permalink / raw)
  To: linuxppc-embedded; +Cc: Deepak Gaur
In-Reply-To: <47FA4601.1080707@freescale.com>

On Mon, Apr 7, 2008 at 10:04 AM, Scott Wood <scottwood@freescale.com> wrote:
>  BTW, it's generally bad form to post the same question repeatedly.  If you
> have new information regarding your problem, just post a followup in the
> same thread containing the new information.

Agreed!  I was about to respond to your new post, and then I
discovered this nearly identical slightly older post.

On Mon, Apr 7, 2008 at 12:37 AM, Deepak Gaur <gaur.deepak@gmail.com> wrote:
> While booting MVL linux on MPC8560 based board the kernel goes into a
> infinite loop in setup.c

Someone please correct me if I am wrong, but those symbols inside the
BSS should only be variables (not functions....) which are initialized
to zero.  The whole reason for BSS is to initialize variables to a
0/null value.

Now, about the infinite loop.  Can you check to see if perhaps you are
getting an exception?

I have no experience with the MPC8560, but I've seen a couple problems
that occur involving memset_io.  What happens is that a TLB miss
exception occurs when the CPU gets inside of memset_io.  Do you have
the ability to check that with a debugger (by setting breakpoints at
exceptions, such as the data and instruction TLB miss exceptions) to
see if you are getting exceptions?

^ permalink raw reply

* Re: MVL Linux on MPC8560 Booting goes into infinite loop in early_init memset_io ( )
From: David Baird @ 2008-04-07 19:56 UTC (permalink / raw)
  To: linuxppc-embedded
In-Reply-To: <440abda90804071250v60bd970fh938e9690836ab61@mail.gmail.com>

On Mon, Apr 7, 2008 at 1:50 PM, David Baird <dhbaird@gmail.com> wrote:
> On Mon, Apr 7, 2008 at 10:04 AM, Scott Wood <scottwood@freescale.com> wrote:
>  >  BTW, it's generally bad form to post the same question repeatedly.  If you
>  > have new information regarding your problem, just post a followup in the
>  > same thread containing the new information.
>
>  Agreed!  I was about to respond to your new post, and then I
>  discovered this nearly identical slightly older post.

(Oops, I got that backwards.  This is the newer post...)

^ permalink raw reply

* [PATCH] siimage: fix kernel oops on PPC 44x
From: Sergei Shtylyov @ 2008-04-07 20:05 UTC (permalink / raw)
  To: bzolnier; +Cc: linux-ide, linuxppc-dev

Fix kernel oops due to machine check occuring in init_chipset_siimage() on PPC
44x platforms.  These 32-bit CPUs have 36-bit physical address and PCI I/O and
memory spaces are mapped beyond 4 GB; arch/ppc/ code has a fixup in ioremap()
that creates an illusion of the PCI I/O and memory resources being mapped below
4 GB, while arch/powerpc/ code got rid of this fixup with PPC 44x having instead
CONFIG_RESOURCES_64BIT=y -- this causes the resources to be truncated to 32-bit
'unsigned long' type in this driver, and so non-existant memory being ioremap'ed
and then accessed...

Thanks to Valentine Barshak for providing an initial patch and explanations.

Signed-off-by: Sergei Shtylyov <sshtylyov@ru.mvista.com>

 drivers/ide/pci/siimage.c |    2 +-
 1 files changed, 1 insertion(+), 1 deletion(-)

Index: linux-2.6/drivers/ide/pci/siimage.c
===================================================================
--- linux-2.6.orig/drivers/ide/pci/siimage.c
+++ linux-2.6/drivers/ide/pci/siimage.c
@@ -492,7 +492,7 @@ static void proc_reports_siimage (struct
  
 static unsigned int setup_mmio_siimage (struct pci_dev *dev, const char *name)
 {
-	unsigned long bar5	= pci_resource_start(dev, 5);
+	resource_size_t bar5	= pci_resource_start(dev, 5);
 	unsigned long barsize	= pci_resource_len(dev, 5);
 	u8 tmpbyte	= 0;
 	void __iomem *ioaddr;

^ permalink raw reply

* Re: [PATCH 1/9 v2] powerpc: change FDT compatible prefix to mrvl
From: Segher Boessenkool @ 2008-04-07 20:49 UTC (permalink / raw)
  To: Dale Farnsworth; +Cc: linuxppc-dev, paulus
In-Reply-To: <20080407183817.GB7438@farnsworth.org>

> Follow the convention that compatible names are prefixed by the
> vendor's stock ticker symbol.  For Marvell Technology Group Ltd.,
> that's MRVL.

> -		compatible = "marvell,mv64x60";
> +		compatible = "mrvl,mv64x60";

NAK.

Either use the stock ticker, in UPPER CASE, or use a nice
descriptive name.  The lower case space is "free for all",
using shortened names (like "mrvl") there only increases
the chances of collisions.


Segher

^ permalink raw reply

* [PATCH 0 of 3] KVM for PowerPC 440
From: Hollis Blanchard @ 2008-04-07 20:53 UTC (permalink / raw)
  To: linuxppc-dev, kvm-devel; +Cc: kvm-ppc-devel

Implement initial support for KVM for PowerPC 440. There are just two small
prerequisite patches, and then the bulk of the code can't be split easily.

Please review; I would like to submit these for 2.6.26. There is plenty of work
to do, both functional and optimization, but this code is sufficient to run
unmodified 440 Linux guests on a 440 Linux host. What's your favorite bike shed
color?

(Note for current users: since KVM_EXIT_DCR changed, you must rebuild your
userspace to match this kernel.)

^ permalink raw reply

* [PATCH 1 of 3] [POWERPC 44x] Export tlb_44x_hwater for KVM
From: Hollis Blanchard @ 2008-04-07 20:53 UTC (permalink / raw)
  To: linuxppc-dev, kvm-devel; +Cc: kvm-ppc-devel
In-Reply-To: <patchbomb.1207601611@localhost.localdomain>

1 file changed, 2 insertions(+)
include/asm-powerpc/mmu-44x.h |    2 ++


PowerPC 440 KVM needs to know how many TLB entries are used for the host kernel
linear mapping (it does not modify these mappings when switching between guest
and host execution).

Signed-off-by: Hollis Blanchard <hollisb@us.ibm.com>

diff --git a/include/asm-powerpc/mmu-44x.h b/include/asm-powerpc/mmu-44x.h
--- a/include/asm-powerpc/mmu-44x.h
+++ b/include/asm-powerpc/mmu-44x.h
@@ -53,6 +53,8 @@
 
 #ifndef __ASSEMBLY__
 
+extern unsigned int tlb_44x_hwater;
+
 typedef unsigned long long phys_addr_t;
 
 typedef struct {

^ permalink raw reply

* [PATCH 2 of 3] [KVM] Add DCR access information to struct kvm_run
From: Hollis Blanchard @ 2008-04-07 20:53 UTC (permalink / raw)
  To: linuxppc-dev, kvm-devel; +Cc: kvm-ppc-devel
In-Reply-To: <patchbomb.1207601611@localhost.localdomain>

1 file changed, 7 insertions(+)
include/linux/kvm.h |    7 +++++++


Device Control Registers are essentially another address space found on PowerPC
4xx processors, analogous to PIO on x86. DCRs are always 32 bits, and are
identified by a 32-bit number. We forward DCR accesses to userspace for
emulation.

Signed-off-by: Hollis Blanchard <hollisb@us.ibm.com>

diff --git a/include/linux/kvm.h b/include/linux/kvm.h
--- a/include/linux/kvm.h
+++ b/include/linux/kvm.h
@@ -76,6 +76,7 @@
 #define KVM_EXIT_TPR_ACCESS       12
 #define KVM_EXIT_S390_SIEIC       13
 #define KVM_EXIT_S390_RESET       14
+#define KVM_EXIT_DCR              15
 
 /* for KVM_RUN, returned by mmap(vcpu_fd, offset=0) */
 struct kvm_run {
@@ -155,6 +156,12 @@
 #define KVM_S390_RESET_CPU_INIT  8
 #define KVM_S390_RESET_IPL       16
 		__u64 s390_reset_flags;
+		/* KVM_EXIT_DCR */
+		struct {
+			__u32 dcrn;
+			__u32 data;
+			__u8  is_write;
+		} dcr;
 		/* Fix the size of the union. */
 		char padding[256];
 	};

^ permalink raw reply

* [PATCH 3 of 3] [KVM POWERPC] PowerPC 440 KVM implementation
From: Hollis Blanchard @ 2008-04-07 20:53 UTC (permalink / raw)
  To: linuxppc-dev, kvm-devel; +Cc: kvm-ppc-devel
In-Reply-To: <patchbomb.1207601611@localhost.localdomain>

17 files changed, 3022 insertions(+), 2 deletions(-)
MAINTAINERS                         |    7 
arch/powerpc/Kconfig                |    1 
arch/powerpc/Kconfig.debug          |    1 
arch/powerpc/Makefile               |    1 
arch/powerpc/kernel/asm-offsets.c   |   26 
arch/powerpc/kvm/44x_tlb.c          |  224 +++++++
arch/powerpc/kvm/44x_tlb.h          |   91 +++
arch/powerpc/kvm/Kconfig            |   54 +
arch/powerpc/kvm/Makefile           |   15 
arch/powerpc/kvm/booke_interrupts.S |  436 ++++++++++++++
arch/powerpc/kvm/emulate.c          |  753 +++++++++++++++++++++++++
arch/powerpc/kvm/powerpc.c          | 1031 +++++++++++++++++++++++++++++++++++
include/asm-powerpc/kvm.h           |   53 +
include/asm-powerpc/kvm_asm.h       |   55 +
include/asm-powerpc/kvm_host.h      |  152 +++++
include/asm-powerpc/kvm_para.h      |   38 +
include/asm-powerpc/kvm_ppc.h       |   86 ++


Currently supports only PowerPC 440 Linux guests on 440 hosts. (Only tested
with 440EP "Bamboo" guests so far, but with appropriate userspace support other
SoC/board combinations should work.)

Interrupt handling: We use IVPR to hijack the host interrupt vectors while
running the guest, but hand off decrementer and external interrupts for normal
guest processing.

Address spaces: We take advantage of the fact that Linux doesn't use the AS=1
address space (in host or guest), which gives us virtual address space to use
for guest mappings. While the guest is running, the host kernel remains mapped
in AS=0, but the guest can only use AS=1 mappings.

TLB entries: The TLB entries covering the host linear address space remain
present while running the guest (which reduces the overhead of lightweight
exits). We keep three copies of the TLB:
 - guest TLB: contents of the TLB as the guest sees it
 - shadow TLB: the TLB that is actually in hardware while guest is running
 - host TLB: to restore TLB state when context switching guest -> host
When a TLB miss occurs because a mapping was not present in the shadow TLB, but
was present in the guest TLB, KVM handles the fault without invoking the guest.
Large guest pages are backed by multiple 4KB shadow pages through this
mechanism.

Instruction emulation: The guest kernel executes at user level, so executing
privileged instructions trap into KVM, where we decode and emulate them. Future
performance work will focus on reducing the overhead and frequency of these
traps.

IO: MMIO and DCR accesses are emulated by userspace. We use virtio for network
and block IO, so those drivers must be enabled in the guest. It's possible that
some qemu device emulation (e.g. e1000 or rtl8139) may also work with little
effort.

Signed-off-by: Hollis Blanchard <hollisb@us.ibm.com>

diff --git a/MAINTAINERS b/MAINTAINERS
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2302,6 +2302,13 @@
 W:	kvm.sourceforge.net
 S:	Supported
 
+KERNEL VIRTUAL MACHINE (KVM) FOR POWERPC
+P:	Hollis Blanchard
+M:	hollisb@us.ibm.com
+L:	kvm-ppc-devel@lists.sourceforge.net
+W:	kvm.sourceforge.net
+S:	Supported
+
 KERNEL VIRTUAL MACHINE For Itanium(KVM/IA64)
 P:	Anthony Xu
 M:	anthony.xu@intel.com
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -722,3 +722,4 @@
 config PPC_LIB_RHEAP
 	bool
 
+source "arch/powerpc/kvm/Kconfig"
diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug
--- a/arch/powerpc/Kconfig.debug
+++ b/arch/powerpc/Kconfig.debug
@@ -151,6 +151,7 @@
 
 config PPC_EARLY_DEBUG
 	bool "Early debugging (dangerous)"
+	depends on !KVM
 	help
 	  Say Y to enable some early debugging facilities that may be available
 	  for your processor/board combination. Those facilities are hacks
diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
--- a/arch/powerpc/Makefile
+++ b/arch/powerpc/Makefile
@@ -147,6 +147,7 @@
 				   arch/powerpc/platforms/
 core-$(CONFIG_MATH_EMULATION)	+= arch/powerpc/math-emu/
 core-$(CONFIG_XMON)		+= arch/powerpc/xmon/
+core-$(CONFIG_KVM) 		+= arch/powerpc/kvm/
 
 drivers-$(CONFIG_OPROFILE)	+= arch/powerpc/oprofile/
 
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -23,6 +23,7 @@
 #include <linux/mm.h>
 #include <linux/suspend.h>
 #include <linux/hrtimer.h>
+#include <linux/kvm_host.h>
 #ifdef CONFIG_PPC64
 #include <linux/time.h>
 #include <linux/hardirq.h>
@@ -329,5 +330,30 @@
 
 	DEFINE(PGD_TABLE_SIZE, PGD_TABLE_SIZE);
 
+#ifdef CONFIG_KVM
+	DEFINE(TLBE_BYTES, sizeof(struct tlbe));
+
+	DEFINE(VCPU_HOST_STACK, offsetof(struct kvm_vcpu, arch.host_stack));
+	DEFINE(VCPU_HOST_PID, offsetof(struct kvm_vcpu, arch.host_pid));
+	DEFINE(VCPU_HOST_TLB, offsetof(struct kvm_vcpu, arch.host_tlb));
+	DEFINE(VCPU_SHADOW_TLB, offsetof(struct kvm_vcpu, arch.shadow_tlb));
+	DEFINE(VCPU_GPRS, offsetof(struct kvm_vcpu, arch.gpr));
+	DEFINE(VCPU_LR, offsetof(struct kvm_vcpu, arch.lr));
+	DEFINE(VCPU_CR, offsetof(struct kvm_vcpu, arch.cr));
+	DEFINE(VCPU_XER, offsetof(struct kvm_vcpu, arch.xer));
+	DEFINE(VCPU_CTR, offsetof(struct kvm_vcpu, arch.ctr));
+	DEFINE(VCPU_PC, offsetof(struct kvm_vcpu, arch.pc));
+	DEFINE(VCPU_MSR, offsetof(struct kvm_vcpu, arch.msr));
+	DEFINE(VCPU_SPRG4, offsetof(struct kvm_vcpu, arch.sprg4));
+	DEFINE(VCPU_SPRG5, offsetof(struct kvm_vcpu, arch.sprg5));
+	DEFINE(VCPU_SPRG6, offsetof(struct kvm_vcpu, arch.sprg6));
+	DEFINE(VCPU_SPRG7, offsetof(struct kvm_vcpu, arch.sprg7));
+	DEFINE(VCPU_PID, offsetof(struct kvm_vcpu, arch.pid));
+
+	DEFINE(VCPU_LAST_INST, offsetof(struct kvm_vcpu, arch.last_inst));
+	DEFINE(VCPU_FAULT_DEAR, offsetof(struct kvm_vcpu, arch.fault_dear));
+	DEFINE(VCPU_FAULT_ESR, offsetof(struct kvm_vcpu, arch.fault_esr));
+#endif
+
 	return 0;
 }
diff --git a/arch/powerpc/kvm/44x_tlb.c b/arch/powerpc/kvm/44x_tlb.c
new file mode 100644
--- /dev/null
+++ b/arch/powerpc/kvm/44x_tlb.c
@@ -0,0 +1,224 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * 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, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Copyright IBM Corp. 2007
+ *
+ * Authors: Hollis Blanchard <hollisb@us.ibm.com>
+ */
+
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/kvm_host.h>
+#include <linux/highmem.h>
+#include <asm/mmu-44x.h>
+#include <asm/kvm_ppc.h>
+
+#include "44x_tlb.h"
+
+#define PPC44x_TLB_USER_PERM_MASK (PPC44x_TLB_UX|PPC44x_TLB_UR|PPC44x_TLB_UW)
+#define PPC44x_TLB_SUPER_PERM_MASK (PPC44x_TLB_SX|PPC44x_TLB_SR|PPC44x_TLB_SW)
+
+static unsigned int kvmppc_tlb_44x_pos;
+
+static u32 kvmppc_44x_tlb_shadow_attrib(u32 attrib, int usermode)
+{
+	/* XXX remove mask when Linux is fixed */
+	attrib &= 0xf03f;
+
+	if (!usermode) {
+		/* Guest is in supervisor mode, so we need to translate guest
+		 * supervisor permissions into user permissions. */
+		attrib &= ~PPC44x_TLB_USER_PERM_MASK;
+		attrib |= (attrib & PPC44x_TLB_SUPER_PERM_MASK) << 3;
+	}
+
+	/* Make sure host can always access this memory. */
+	attrib |= PPC44x_TLB_SX|PPC44x_TLB_SR|PPC44x_TLB_SW;
+
+	return attrib;
+}
+
+/* Search the guest TLB for a matching entry. */
+int kvmppc_44x_tlb_index(struct kvm_vcpu *vcpu, gva_t eaddr, unsigned int pid,
+                         unsigned int as)
+{
+	int i;
+
+	/* XXX Replace loop with fancy data structures. */
+	for (i = 0; i < PPC44x_TLB_SIZE; i++) {
+		struct tlbe *tlbe = &vcpu->arch.guest_tlb[i];
+		unsigned int tid;
+
+		if (eaddr < get_tlb_eaddr(tlbe))
+			continue;
+
+		if (eaddr > get_tlb_end(tlbe))
+			continue;
+
+		tid = get_tlb_tid(tlbe);
+		if (tid && (tid != pid))
+			continue;
+
+		if (!get_tlb_v(tlbe))
+			continue;
+
+		if (get_tlb_ts(tlbe) != as)
+			continue;
+
+		return i;
+	}
+
+	return -1;
+}
+
+struct tlbe *kvmppc_44x_itlb_search(struct kvm_vcpu *vcpu, gva_t eaddr)
+{
+	unsigned int as = !!(vcpu->arch.msr & MSR_IS);
+	unsigned int index;
+
+	index = kvmppc_44x_tlb_index(vcpu, eaddr, vcpu->arch.pid, as);
+	if (index == -1)
+		return NULL;
+	return &vcpu->arch.guest_tlb[index];
+}
+
+struct tlbe *kvmppc_44x_dtlb_search(struct kvm_vcpu *vcpu, gva_t eaddr)
+{
+	unsigned int as = !!(vcpu->arch.msr & MSR_DS);
+	unsigned int index;
+
+	index = kvmppc_44x_tlb_index(vcpu, eaddr, vcpu->arch.pid, as);
+	if (index == -1)
+		return NULL;
+	return &vcpu->arch.guest_tlb[index];
+}
+
+static int kvmppc_44x_tlbe_is_writable(struct tlbe *tlbe)
+{
+	return tlbe->word2 & (PPC44x_TLB_SW|PPC44x_TLB_UW);
+}
+
+/* Must be called with mmap_sem locked for writing. */
+static void kvmppc_44x_shadow_release(struct kvm_vcpu *vcpu,
+                                      unsigned int index)
+{
+	struct tlbe *stlbe = &vcpu->arch.shadow_tlb[index];
+	struct page *page = vcpu->arch.shadow_pages[index];
+
+	kunmap(vcpu->arch.shadow_pages[index]);
+
+	if (get_tlb_v(stlbe)) {
+		if (kvmppc_44x_tlbe_is_writable(stlbe))
+			kvm_release_page_dirty(page);
+		else
+			kvm_release_page_clean(page);
+	}
+}
+
+/* Caller must ensure that the specified guest TLB entry is safe to insert into
+ * the shadow TLB. */
+void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 gvaddr, gfn_t gfn, u64 asid,
+                    u32 flags)
+{
+	struct page *new_page;
+	struct tlbe *stlbe;
+	hpa_t hpaddr;
+	unsigned int victim;
+
+	/* Future optimization: don't overwrite the TLB entry containing the
+	 * current PC (or stack?). */
+	victim = kvmppc_tlb_44x_pos++;
+	if (kvmppc_tlb_44x_pos > tlb_44x_hwater)
+		kvmppc_tlb_44x_pos = 0;
+	stlbe = &vcpu->arch.shadow_tlb[victim];
+
+	/* Get reference to new page. */
+	down_write(&current->mm->mmap_sem);
+	new_page = gfn_to_page(vcpu->kvm, gfn);
+	if (is_error_page(new_page)) {
+		printk(KERN_ERR "Couldn't get guest page!\n");
+		kvm_release_page_clean(new_page);
+		return;
+	}
+	hpaddr = page_to_phys(new_page);
+
+	/* Drop reference to old page. */
+	kvmppc_44x_shadow_release(vcpu, victim);
+	up_write(&current->mm->mmap_sem);
+
+	vcpu->arch.shadow_pages[victim] = new_page;
+
+	/* XXX Make sure (va, size) doesn't overlap any other
+	 * entries. 440x6 user manual says the result would be
+	 * "undefined." */
+
+	/* XXX what about AS? */
+
+	stlbe->tid = asid & 0xff;
+
+	/* Force TS=1 for all guest mappings. */
+	/* For now we hardcode 4KB mappings, but it will be important to
+	 * use host large pages in the future. */
+	stlbe->word0 = (gvaddr & PAGE_MASK) | PPC44x_TLB_VALID | PPC44x_TLB_TS
+	               | PPC44x_TLB_4K;
+
+	stlbe->word1 = (hpaddr & 0xfffffc00) | ((hpaddr >> 32) & 0xf);
+	stlbe->word2 = kvmppc_44x_tlb_shadow_attrib(flags,
+	                                            vcpu->arch.msr & MSR_PR);
+}
+
+void kvmppc_mmu_invalidate(struct kvm_vcpu *vcpu, u64 eaddr, u64 asid)
+{
+	unsigned int pid = asid & 0xff;
+	int i;
+
+	/* XXX Replace loop with fancy data structures. */
+	down_write(&current->mm->mmap_sem);
+	for (i = 0; i <= tlb_44x_hwater; i++) {
+		struct tlbe *stlbe = &vcpu->arch.shadow_tlb[i];
+		unsigned int tid;
+
+		if (!get_tlb_v(stlbe))
+			continue;
+
+		if (eaddr < get_tlb_eaddr(stlbe))
+			continue;
+
+		if (eaddr > get_tlb_end(stlbe))
+			continue;
+
+		tid = get_tlb_tid(stlbe);
+		if (tid && (tid != pid))
+			continue;
+
+		kvmppc_44x_shadow_release(vcpu, i);
+		stlbe->word0 = 0;
+	}
+	up_write(&current->mm->mmap_sem);
+}
+
+/* Invalidate all mappings, so that when they fault back in they will get the
+ * proper permission bits. */
+void kvmppc_mmu_priv_switch(struct kvm_vcpu *vcpu, int usermode)
+{
+	int i;
+
+	/* XXX Replace loop with fancy data structures. */
+	down_write(&current->mm->mmap_sem);
+	for (i = 0; i <= tlb_44x_hwater; i++) {
+		kvmppc_44x_shadow_release(vcpu, i);
+		vcpu->arch.shadow_tlb[i].word0 = 0;
+	}
+	up_write(&current->mm->mmap_sem);
+}
diff --git a/arch/powerpc/kvm/44x_tlb.h b/arch/powerpc/kvm/44x_tlb.h
new file mode 100644
--- /dev/null
+++ b/arch/powerpc/kvm/44x_tlb.h
@@ -0,0 +1,91 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * 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, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Copyright IBM Corp. 2007
+ *
+ * Authors: Hollis Blanchard <hollisb@us.ibm.com>
+ */
+
+#ifndef __KVM_POWERPC_TLB_H__
+#define __KVM_POWERPC_TLB_H__
+
+#include <linux/kvm_host.h>
+#include <asm/mmu-44x.h>
+
+extern int kvmppc_44x_tlb_index(struct kvm_vcpu *vcpu, gva_t eaddr,
+                                unsigned int pid, unsigned int as);
+extern struct tlbe *kvmppc_44x_dtlb_search(struct kvm_vcpu *vcpu, gva_t eaddr);
+extern struct tlbe *kvmppc_44x_itlb_search(struct kvm_vcpu *vcpu, gva_t eaddr);
+
+/* TLB helper functions */
+static inline unsigned int get_tlb_size(const struct tlbe *tlbe)
+{
+	return (tlbe->word0 >> 4) & 0xf;
+}
+
+static inline gva_t get_tlb_eaddr(const struct tlbe *tlbe)
+{
+	return tlbe->word0 & 0xfffffc00;
+}
+
+static inline gva_t get_tlb_bytes(const struct tlbe *tlbe)
+{
+	unsigned int pgsize = get_tlb_size(tlbe);
+	return 1 << 10 << (pgsize << 1);
+}
+
+static inline gva_t get_tlb_end(const struct tlbe *tlbe)
+{
+	return get_tlb_eaddr(tlbe) + get_tlb_bytes(tlbe) - 1;
+}
+
+static inline u64 get_tlb_raddr(const struct tlbe *tlbe)
+{
+	u64 word1 = tlbe->word1;
+	return ((word1 & 0xf) << 32) | (word1 & 0xfffffc00);
+}
+
+static inline unsigned int get_tlb_tid(const struct tlbe *tlbe)
+{
+	return tlbe->tid & 0xff;
+}
+
+static inline unsigned int get_tlb_ts(const struct tlbe *tlbe)
+{
+	return (tlbe->word0 >> 8) & 0x1;
+}
+
+static inline unsigned int get_tlb_v(const struct tlbe *tlbe)
+{
+	return (tlbe->word0 >> 9) & 0x1;
+}
+
+static inline unsigned int get_mmucr_stid(const struct kvm_vcpu *vcpu)
+{
+	return vcpu->arch.mmucr & 0xff;
+}
+
+static inline unsigned int get_mmucr_sts(const struct kvm_vcpu *vcpu)
+{
+	return (vcpu->arch.mmucr >> 16) & 0x1;
+}
+
+static inline gpa_t tlb_xlate(struct tlbe *tlbe, gva_t eaddr)
+{
+	unsigned int pgmask = get_tlb_bytes(tlbe) - 1;
+
+	return get_tlb_raddr(tlbe) | (eaddr & pgmask);
+}
+
+#endif /* __KVM_POWERPC_TLB_H__ */
diff --git a/arch/powerpc/kvm/Kconfig b/arch/powerpc/kvm/Kconfig
new file mode 100644
--- /dev/null
+++ b/arch/powerpc/kvm/Kconfig
@@ -0,0 +1,54 @@
+#
+# KVM configuration
+#
+
+menuconfig VIRTUALIZATION
+	bool "Virtualization"
+	---help---
+	  Say Y here to get to see options for using your Linux host to run
+	  other operating systems inside virtual machines (guests).
+	  This option alone does not add any kernel code.
+
+	  If you say N, all options in this submenu will be skipped and
+	  disabled.
+
+if VIRTUALIZATION
+
+config KVM
+	tristate "Kernel-based Virtual Machine (KVM) support"
+	depends on EXPERIMENTAL
+	select PREEMPT_NOTIFIERS
+	select ANON_INODES
+	---help---
+	  Support hosting virtualized guest machines. You will also
+	  need to select one or more of the processor modules below.
+
+	  This module provides access to the hardware capabilities through
+	  a character device node named /dev/kvm.
+
+	  To compile this as a module, choose M here: the module
+	  will be called kvm.
+
+	  If unsure, say N.
+
+config KVM_POWERPC
+	bool
+
+config KVM_POWERPC_440
+	tristate "KVM guest support for PowerPC 440"
+	depends on KVM && 44x
+	select KVM_POWERPC
+	---help---
+	  Provides support for KVM on 440 processors.
+
+config KVM_PPC_VIRTIO
+       bool "Virtio Support"
+       select VIRTIO
+       select VIRTIO_RING
+       ---help---
+         Say yes here to activate virtio support
+
+source drivers/virtio/Kconfig
+
+endif # VIRTUALIZATION
+
diff --git a/arch/powerpc/kvm/Makefile b/arch/powerpc/kvm/Makefile
new file mode 100644
--- /dev/null
+++ b/arch/powerpc/kvm/Makefile
@@ -0,0 +1,15 @@
+#
+# Makefile for Kernel-based Virtual Machine module
+#
+
+EXTRA_CFLAGS += -Ivirt/kvm -Iarch/powerpc/kvm
+
+common-objs = $(addprefix ../../../virt/kvm/, kvm_main.o)
+
+kvm-objs := $(common-objs)
+obj-$(CONFIG_KVM) += kvm.o
+
+kvm-powerpc-objs := powerpc.o emulate.o 44x_tlb.o booke_interrupts.o
+obj-$(CONFIG_KVM_POWERPC) += kvm-powerpc.o
+
+AFLAGS_booke_interrupts.o := -I$(obj)
diff --git a/arch/powerpc/kvm/booke_interrupts.S b/arch/powerpc/kvm/booke_interrupts.S
new file mode 100644
--- /dev/null
+++ b/arch/powerpc/kvm/booke_interrupts.S
@@ -0,0 +1,436 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * 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, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Copyright IBM Corp. 2007
+ *
+ * Authors: Hollis Blanchard <hollisb@us.ibm.com>
+ */
+
+#include <asm/ppc_asm.h>
+#include <asm/kvm_asm.h>
+#include <asm/reg.h>
+#include <asm/mmu-44x.h>
+#include <asm/page.h>
+#include <asm/asm-offsets.h>
+
+#define KVMPPC_MSR_MASK (MSR_CE|MSR_EE|MSR_PR|MSR_DE|MSR_ME|MSR_IS|MSR_DS)
+
+#define VCPU_GPR(n)     (VCPU_GPRS + (n * 4))
+
+/* The host stack layout: */
+#define HOST_R1         0 /* Implied by stwu. */
+#define HOST_CALLEE_LR  4
+#define HOST_RUN        8
+/* r2 is special: it holds 'current', and it made nonvolatile in the
+ * kernel with the -ffixed-r2 gcc option. */
+#define HOST_R2         12
+#define HOST_NV_GPRS    16
+#define HOST_NV_GPR(n)  (HOST_NV_GPRS + ((n - 14) * 4))
+#define HOST_MIN_STACK_SIZE (HOST_NV_GPR(31) + 4)
+#define HOST_STACK_SIZE (((HOST_MIN_STACK_SIZE + 15) / 16) * 16) /* Align. */
+#define HOST_STACK_LR   (HOST_STACK_SIZE + 4) /* In caller stack frame. */
+
+#define NEED_INST_MASK ((1<<BOOKE_INTERRUPT_PROGRAM) | \
+                        (1<<BOOKE_INTERRUPT_DTLB_MISS))
+
+#define NEED_DEAR_MASK ((1<<BOOKE_INTERRUPT_DATA_STORAGE) | \
+                        (1<<BOOKE_INTERRUPT_DTLB_MISS))
+
+#define NEED_ESR_MASK ((1<<BOOKE_INTERRUPT_DATA_STORAGE) | \
+                       (1<<BOOKE_INTERRUPT_INST_STORAGE) | \
+                       (1<<BOOKE_INTERRUPT_PROGRAM) | \
+                       (1<<BOOKE_INTERRUPT_DTLB_MISS))
+
+.macro KVM_HANDLER ivor_nr
+_GLOBAL(kvmppc_handler_\ivor_nr)
+	/* Get pointer to vcpu and record exit number. */
+	mtspr	SPRN_SPRG0, r4
+	mfspr	r4, SPRN_SPRG1
+	stw	r5, VCPU_GPR(r5)(r4)
+	stw	r6, VCPU_GPR(r6)(r4)
+	mfctr	r5
+	lis	r6, kvmppc_resume_host@h
+	stw	r5, VCPU_CTR(r4)
+	li	r5, \ivor_nr
+	ori	r6, r6, kvmppc_resume_host@l
+	mtctr	r6
+	bctr
+.endm
+
+_GLOBAL(kvmppc_handlers_start)
+KVM_HANDLER BOOKE_INTERRUPT_CRITICAL
+KVM_HANDLER BOOKE_INTERRUPT_MACHINE_CHECK
+KVM_HANDLER BOOKE_INTERRUPT_DATA_STORAGE
+KVM_HANDLER BOOKE_INTERRUPT_INST_STORAGE
+KVM_HANDLER BOOKE_INTERRUPT_EXTERNAL
+KVM_HANDLER BOOKE_INTERRUPT_ALIGNMENT
+KVM_HANDLER BOOKE_INTERRUPT_PROGRAM
+KVM_HANDLER BOOKE_INTERRUPT_FP_UNAVAIL
+KVM_HANDLER BOOKE_INTERRUPT_SYSCALL
+KVM_HANDLER BOOKE_INTERRUPT_AP_UNAVAIL
+KVM_HANDLER BOOKE_INTERRUPT_DECREMENTER
+KVM_HANDLER BOOKE_INTERRUPT_FIT
+KVM_HANDLER BOOKE_INTERRUPT_WATCHDOG
+KVM_HANDLER BOOKE_INTERRUPT_DTLB_MISS
+KVM_HANDLER BOOKE_INTERRUPT_ITLB_MISS
+KVM_HANDLER BOOKE_INTERRUPT_DEBUG
+
+_GLOBAL(kvmppc_handler_len)
+	.long kvmppc_handler_1 - kvmppc_handler_0
+
+
+/* Registers:
+ *  SPRG0: guest r4
+ *  r4: vcpu pointer
+ *  r5: KVM exit number
+ */
+_GLOBAL(kvmppc_resume_host)
+	stw	r3, VCPU_GPR(r3)(r4)
+	mfcr	r3
+	stw	r3, VCPU_CR(r4)
+	stw	r7, VCPU_GPR(r7)(r4)
+	stw	r8, VCPU_GPR(r8)(r4)
+	stw	r9, VCPU_GPR(r9)(r4)
+
+	li	r6, 1
+	slw	r6, r6, r5
+
+	/* Save the faulting instruction and all GPRs for emulation. */
+	andi.	r7, r6, NEED_INST_MASK
+	beq	..skip_inst_copy
+	mfspr	r9, SPRN_SRR0
+	mfmsr	r8
+	ori	r7, r8, MSR_DS
+	mtmsr	r7
+	isync
+	lwz	r9, 0(r9)
+	mtmsr	r8
+	isync
+	stw	r9, VCPU_LAST_INST(r4)
+
+	stw	r15, VCPU_GPR(r15)(r4)
+	stw	r16, VCPU_GPR(r16)(r4)
+	stw	r17, VCPU_GPR(r17)(r4)
+	stw	r18, VCPU_GPR(r18)(r4)
+	stw	r19, VCPU_GPR(r19)(r4)
+	stw	r20, VCPU_GPR(r20)(r4)
+	stw	r21, VCPU_GPR(r21)(r4)
+	stw	r22, VCPU_GPR(r22)(r4)
+	stw	r23, VCPU_GPR(r23)(r4)
+	stw	r24, VCPU_GPR(r24)(r4)
+	stw	r25, VCPU_GPR(r25)(r4)
+	stw	r26, VCPU_GPR(r26)(r4)
+	stw	r27, VCPU_GPR(r27)(r4)
+	stw	r28, VCPU_GPR(r28)(r4)
+	stw	r29, VCPU_GPR(r29)(r4)
+	stw	r30, VCPU_GPR(r30)(r4)
+	stw	r31, VCPU_GPR(r31)(r4)
+..skip_inst_copy:
+
+	/* Also grab DEAR and ESR before the host can clobber them. */
+
+	andi.	r7, r6, NEED_DEAR_MASK
+	beq	..skip_dear
+	mfspr	r9, SPRN_DEAR
+	stw	r9, VCPU_FAULT_DEAR(r4)
+..skip_dear:
+
+	andi.	r7, r6, NEED_ESR_MASK
+	beq	..skip_esr
+	mfspr	r9, SPRN_ESR
+	stw	r9, VCPU_FAULT_ESR(r4)
+..skip_esr:
+
+	/* Save remaining volatile guest register state to vcpu. */
+	stw	r0, VCPU_GPR(r0)(r4)
+	stw	r1, VCPU_GPR(r1)(r4)
+	stw	r2, VCPU_GPR(r2)(r4)
+	stw	r10, VCPU_GPR(r10)(r4)
+	stw	r11, VCPU_GPR(r11)(r4)
+	stw	r12, VCPU_GPR(r12)(r4)
+	stw	r13, VCPU_GPR(r13)(r4)
+	stw	r14, VCPU_GPR(r14)(r4) /* We need a NV GPR below. */
+	mflr	r3
+	stw	r3, VCPU_LR(r4)
+	mfxer	r3
+	stw	r3, VCPU_XER(r4)
+	mfspr	r3, SPRN_SPRG0
+	stw	r3, VCPU_GPR(r4)(r4)
+	mfspr	r3, SPRN_SRR0
+	stw	r3, VCPU_PC(r4)
+
+	/* Restore host stack pointer and PID before IVPR, since the host
+	 * exception handlers use them. */
+	lwz	r1, VCPU_HOST_STACK(r4)
+	lwz	r3, VCPU_HOST_PID(r4)
+	mtspr	SPRN_PID, r3
+
+	/* Restore host IVPR before re-enabling interrupts. We cheat and know
+	 * that Linux IVPR is always 0xc0000000. */
+	lis	r3, 0xc000
+	mtspr	SPRN_IVPR, r3
+
+	/* Switch to kernel stack and jump to handler. */
+	LOAD_REG_ADDR(r3, kvmppc_handle_exit)
+	mtctr	r3
+	lwz	r3, HOST_RUN(r1)
+	lwz	r2, HOST_R2(r1)
+	mr	r14, r4 /* Save vcpu pointer. */
+
+	bctrl	/* kvmppc_handle_exit() */
+
+	/* Restore vcpu pointer and the nonvolatiles we used. */
+	mr	r4, r14
+	lwz	r14, VCPU_GPR(r14)(r4)
+
+	/* Sometimes instruction emulation must restore complete GPR state. */
+	andi.	r5, r3, RESUME_FLAG_NV
+	beq	..skip_nv_load
+	lwz	r15, VCPU_GPR(r15)(r4)
+	lwz	r16, VCPU_GPR(r16)(r4)
+	lwz	r17, VCPU_GPR(r17)(r4)
+	lwz	r18, VCPU_GPR(r18)(r4)
+	lwz	r19, VCPU_GPR(r19)(r4)
+	lwz	r20, VCPU_GPR(r20)(r4)
+	lwz	r21, VCPU_GPR(r21)(r4)
+	lwz	r22, VCPU_GPR(r22)(r4)
+	lwz	r23, VCPU_GPR(r23)(r4)
+	lwz	r24, VCPU_GPR(r24)(r4)
+	lwz	r25, VCPU_GPR(r25)(r4)
+	lwz	r26, VCPU_GPR(r26)(r4)
+	lwz	r27, VCPU_GPR(r27)(r4)
+	lwz	r28, VCPU_GPR(r28)(r4)
+	lwz	r29, VCPU_GPR(r29)(r4)
+	lwz	r30, VCPU_GPR(r30)(r4)
+	lwz	r31, VCPU_GPR(r31)(r4)
+..skip_nv_load:
+
+	/* Should we return to the guest? */
+	andi.	r5, r3, RESUME_FLAG_HOST
+	beq	lightweight_exit
+
+	srawi	r3, r3, 2 /* Shift -ERR back down. */
+
+heavyweight_exit:
+	/* Not returning to guest. */
+
+	/* We already saved guest volatile register state; now save the
+	 * non-volatiles. */
+	stw	r15, VCPU_GPR(r15)(r4)
+	stw	r16, VCPU_GPR(r16)(r4)
+	stw	r17, VCPU_GPR(r17)(r4)
+	stw	r18, VCPU_GPR(r18)(r4)
+	stw	r19, VCPU_GPR(r19)(r4)
+	stw	r20, VCPU_GPR(r20)(r4)
+	stw	r21, VCPU_GPR(r21)(r4)
+	stw	r22, VCPU_GPR(r22)(r4)
+	stw	r23, VCPU_GPR(r23)(r4)
+	stw	r24, VCPU_GPR(r24)(r4)
+	stw	r25, VCPU_GPR(r25)(r4)
+	stw	r26, VCPU_GPR(r26)(r4)
+	stw	r27, VCPU_GPR(r27)(r4)
+	stw	r28, VCPU_GPR(r28)(r4)
+	stw	r29, VCPU_GPR(r29)(r4)
+	stw	r30, VCPU_GPR(r30)(r4)
+	stw	r31, VCPU_GPR(r31)(r4)
+
+	/* Load host non-volatile register state from host stack. */
+	lwz	r14, HOST_NV_GPR(r14)(r1)
+	lwz	r15, HOST_NV_GPR(r15)(r1)
+	lwz	r16, HOST_NV_GPR(r16)(r1)
+	lwz	r17, HOST_NV_GPR(r17)(r1)
+	lwz	r18, HOST_NV_GPR(r18)(r1)
+	lwz	r19, HOST_NV_GPR(r19)(r1)
+	lwz	r20, HOST_NV_GPR(r20)(r1)
+	lwz	r21, HOST_NV_GPR(r21)(r1)
+	lwz	r22, HOST_NV_GPR(r22)(r1)
+	lwz	r23, HOST_NV_GPR(r23)(r1)
+	lwz	r24, HOST_NV_GPR(r24)(r1)
+	lwz	r25, HOST_NV_GPR(r25)(r1)
+	lwz	r26, HOST_NV_GPR(r26)(r1)
+	lwz	r27, HOST_NV_GPR(r27)(r1)
+	lwz	r28, HOST_NV_GPR(r28)(r1)
+	lwz	r29, HOST_NV_GPR(r29)(r1)
+	lwz	r30, HOST_NV_GPR(r30)(r1)
+	lwz	r31, HOST_NV_GPR(r31)(r1)
+
+	/* Return to kvm_vcpu_run(). */
+	lwz	r4, HOST_STACK_LR(r1)
+	addi	r1, r1, HOST_STACK_SIZE
+	mtlr	r4
+	/* r3 still contains the return code from kvmppc_handle_exit(). */
+	blr
+
+
+/* Registers:
+ *  r3: kvm_run pointer
+ *  r4: vcpu pointer
+ */
+_GLOBAL(__kvmppc_vcpu_run)
+	stwu	r1, -HOST_STACK_SIZE(r1)
+	stw	r1, VCPU_HOST_STACK(r4)	/* Save stack pointer to vcpu. */
+
+	/* Save host state to stack. */
+	stw	r3, HOST_RUN(r1)
+	mflr	r3
+	stw	r3, HOST_STACK_LR(r1)
+
+	/* Save host non-volatile register state to stack. */
+	stw	r14, HOST_NV_GPR(r14)(r1)
+	stw	r15, HOST_NV_GPR(r15)(r1)
+	stw	r16, HOST_NV_GPR(r16)(r1)
+	stw	r17, HOST_NV_GPR(r17)(r1)
+	stw	r18, HOST_NV_GPR(r18)(r1)
+	stw	r19, HOST_NV_GPR(r19)(r1)
+	stw	r20, HOST_NV_GPR(r20)(r1)
+	stw	r21, HOST_NV_GPR(r21)(r1)
+	stw	r22, HOST_NV_GPR(r22)(r1)
+	stw	r23, HOST_NV_GPR(r23)(r1)
+	stw	r24, HOST_NV_GPR(r24)(r1)
+	stw	r25, HOST_NV_GPR(r25)(r1)
+	stw	r26, HOST_NV_GPR(r26)(r1)
+	stw	r27, HOST_NV_GPR(r27)(r1)
+	stw	r28, HOST_NV_GPR(r28)(r1)
+	stw	r29, HOST_NV_GPR(r29)(r1)
+	stw	r30, HOST_NV_GPR(r30)(r1)
+	stw	r31, HOST_NV_GPR(r31)(r1)
+
+	/* Load guest non-volatiles. */
+	lwz	r14, VCPU_GPR(r14)(r4)
+	lwz	r15, VCPU_GPR(r15)(r4)
+	lwz	r16, VCPU_GPR(r16)(r4)
+	lwz	r17, VCPU_GPR(r17)(r4)
+	lwz	r18, VCPU_GPR(r18)(r4)
+	lwz	r19, VCPU_GPR(r19)(r4)
+	lwz	r20, VCPU_GPR(r20)(r4)
+	lwz	r21, VCPU_GPR(r21)(r4)
+	lwz	r22, VCPU_GPR(r22)(r4)
+	lwz	r23, VCPU_GPR(r23)(r4)
+	lwz	r24, VCPU_GPR(r24)(r4)
+	lwz	r25, VCPU_GPR(r25)(r4)
+	lwz	r26, VCPU_GPR(r26)(r4)
+	lwz	r27, VCPU_GPR(r27)(r4)
+	lwz	r28, VCPU_GPR(r28)(r4)
+	lwz	r29, VCPU_GPR(r29)(r4)
+	lwz	r30, VCPU_GPR(r30)(r4)
+	lwz	r31, VCPU_GPR(r31)(r4)
+
+lightweight_exit:
+	stw	r2, HOST_R2(r1)
+
+	mfspr	r3, SPRN_PID
+	stw	r3, VCPU_HOST_PID(r4)
+	lwz	r3, VCPU_PID(r4)
+	mtspr	SPRN_PID, r3
+
+	/* Prevent all TLB updates. */
+	mfmsr	r5
+	lis	r6, (MSR_EE|MSR_CE|MSR_ME|MSR_DE)@h
+	ori	r6, r6, (MSR_EE|MSR_CE|MSR_ME|MSR_DE)@l
+	andc	r6, r5, r6
+	mtmsr	r6
+
+	/* Save the host's non-pinned TLB mappings, and load the guest mappings
+	 * over them. Leave the host's "pinned" kernel mappings in place. */
+	/* XXX optimization: use generation count to avoid swapping unmodified
+	 * entries. */
+	mfspr	r10, SPRN_MMUCR			/* Save host MMUCR. */
+	lis	r8, tlb_44x_hwater@ha
+	lwz	r8, tlb_44x_hwater@l(r8)
+	addi	r3, r4, VCPU_HOST_TLB - 4
+	addi	r9, r4, VCPU_SHADOW_TLB - 4
+	li	r6, 0
+1:
+	/* Save host entry. */
+	tlbre	r7, r6, PPC44x_TLB_PAGEID
+	mfspr	r5, SPRN_MMUCR
+	stwu	r5, 4(r3)
+	stwu	r7, 4(r3)
+	tlbre	r7, r6, PPC44x_TLB_XLAT
+	stwu	r7, 4(r3)
+	tlbre	r7, r6, PPC44x_TLB_ATTRIB
+	stwu	r7, 4(r3)
+	/* Load guest entry. */
+	lwzu	r7, 4(r9)
+	mtspr	SPRN_MMUCR, r7
+	lwzu	r7, 4(r9)
+	tlbwe	r7, r6, PPC44x_TLB_PAGEID
+	lwzu	r7, 4(r9)
+	tlbwe	r7, r6, PPC44x_TLB_XLAT
+	lwzu	r7, 4(r9)
+	tlbwe	r7, r6, PPC44x_TLB_ATTRIB
+	/* Increment index. */
+	addi	r6, r6, 1
+	cmpw	r6, r8
+	blt	1b
+	mtspr	SPRN_MMUCR, r10			/* Restore host MMUCR. */
+
+	iccci	0, 0 /* XXX hack */
+
+	/* Load some guest volatiles. */
+	lwz	r0, VCPU_GPR(r0)(r4)
+	lwz	r2, VCPU_GPR(r2)(r4)
+	lwz	r9, VCPU_GPR(r9)(r4)
+	lwz	r10, VCPU_GPR(r10)(r4)
+	lwz	r11, VCPU_GPR(r11)(r4)
+	lwz	r12, VCPU_GPR(r12)(r4)
+	lwz	r13, VCPU_GPR(r13)(r4)
+	lwz	r3, VCPU_LR(r4)
+	mtlr	r3
+	lwz	r3, VCPU_XER(r4)
+	mtxer	r3
+
+	/* Switch the IVPR. XXX If we take a TLB miss after this we're screwed,
+	 * so how do we make sure vcpu won't fault? */
+	lis	r8, kvmppc_44x_handlers@ha
+	lwz	r8, kvmppc_44x_handlers@l(r8)
+	mtspr	SPRN_IVPR, r8
+
+	/* Save vcpu pointer for the exception handlers. */
+	mtspr	SPRN_SPRG1, r4
+
+	/* Can't switch the stack pointer until after IVPR is switched,
+	 * because host interrupt handlers would get confused. */
+	lwz	r1, VCPU_GPR(r1)(r4)
+
+	/* XXX handle USPRG0 */
+	/* Host interrupt handlers may have clobbered these guest-readable
+	 * SPRGs, so we need to reload them here with the guest's values. */
+	lwz	r3, VCPU_SPRG4(r4)
+	mtspr	SPRN_SPRG4, r3
+	lwz	r3, VCPU_SPRG5(r4)
+	mtspr	SPRN_SPRG5, r3
+	lwz	r3, VCPU_SPRG6(r4)
+	mtspr	SPRN_SPRG6, r3
+	lwz	r3, VCPU_SPRG7(r4)
+	mtspr	SPRN_SPRG7, r3
+
+	/* Finish loading guest volatiles and jump to guest. */
+	lwz	r3, VCPU_CTR(r4)
+	mtctr	r3
+	lwz	r3, VCPU_CR(r4)
+	mtcr	r3
+	lwz	r5, VCPU_GPR(r5)(r4)
+	lwz	r6, VCPU_GPR(r6)(r4)
+	lwz	r7, VCPU_GPR(r7)(r4)
+	lwz	r8, VCPU_GPR(r8)(r4)
+	lwz	r3, VCPU_PC(r4)
+	mtsrr0	r3
+	lwz	r3, VCPU_MSR(r4)
+	oris	r3, r3, KVMPPC_MSR_MASK@h
+	ori	r3, r3, KVMPPC_MSR_MASK@l
+	mtsrr1	r3
+	lwz	r3, VCPU_GPR(r3)(r4)
+	lwz	r4, VCPU_GPR(r4)(r4)
+	rfi
diff --git a/arch/powerpc/kvm/emulate.c b/arch/powerpc/kvm/emulate.c
new file mode 100644
--- /dev/null
+++ b/arch/powerpc/kvm/emulate.c
@@ -0,0 +1,753 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * 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, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Copyright IBM Corp. 2007
+ *
+ * Authors: Hollis Blanchard <hollisb@us.ibm.com>
+ */
+
+#include <linux/jiffies.h>
+#include <linux/timer.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/kvm_host.h>
+
+#include <asm/dcr.h>
+#include <asm/time.h>
+#include <asm/byteorder.h>
+#include <asm/kvm_ppc.h>
+
+#include "44x_tlb.h"
+
+#define DCRN_CPR0_CFGADDR	0xc
+#define DCRN_CPR0_CFGDATA	0xd
+
+/* Instruction decoding */
+static inline unsigned int get_op(u32 inst)
+{
+	return inst >> 26;
+}
+
+static inline unsigned int get_xop(u32 inst)
+{
+	return (inst >> 1) & 0x3ff;
+}
+
+static inline unsigned int get_sprn(u32 inst)
+{
+	return ((inst >> 16) & 0x1f) | ((inst >> 6) & 0x3e0);
+}
+
+static inline unsigned int get_dcrn(u32 inst)
+{
+	return ((inst >> 16) & 0x1f) | ((inst >> 6) & 0x3e0);
+}
+
+static inline unsigned int get_rt(u32 inst)
+{
+	return (inst >> 21) & 0x1f;
+}
+
+static inline unsigned int get_rs(u32 inst)
+{
+	return (inst >> 21) & 0x1f;
+}
+
+static inline unsigned int get_ra(u32 inst)
+{
+	return (inst >> 16) & 0x1f;
+}
+
+static inline unsigned int get_rb(u32 inst)
+{
+	return (inst >> 11) & 0x1f;
+}
+
+static inline unsigned int get_rc(u32 inst)
+{
+	return inst & 0x1;
+}
+
+static inline unsigned int get_ws(u32 inst)
+{
+	return (inst >> 11) & 0x1f;
+}
+
+static inline unsigned int get_d(u32 inst)
+{
+	return inst & 0xffff;
+}
+
+static int tlbe_is_host_safe(const struct kvm_vcpu *vcpu,
+                             const struct tlbe *tlbe)
+{
+	gpa_t gpa;
+
+	if (!get_tlb_v(tlbe))
+		return 0;
+
+	/* Does it match current guest AS? */
+	/* XXX what about IS != DS? */
+	if (get_tlb_ts(tlbe) != !!(vcpu->arch.msr & MSR_IS))
+		return 0;
+
+	gpa = get_tlb_raddr(tlbe);
+	if (!gfn_to_memslot(vcpu->kvm, gpa >> PAGE_SHIFT))
+		/* Mapping is not for RAM. */
+		return 0;
+
+	return 1;
+}
+
+static int kvmppc_emul_tlbwe(struct kvm_vcpu *vcpu, u32 inst)
+{
+	u64 eaddr;
+	u64 raddr;
+	u64 asid;
+	u32 flags;
+	struct tlbe *tlbe;
+	unsigned int ra;
+	unsigned int rs;
+	unsigned int ws;
+	unsigned int index;
+
+	ra = get_ra(inst);
+	rs = get_rs(inst);
+	ws = get_ws(inst);
+
+	index = vcpu->arch.gpr[ra];
+	if (index > PPC44x_TLB_SIZE) {
+		printk("%s: index %d\n", __func__, index);
+		kvmppc_dump_vcpu(vcpu);
+		return EMULATE_FAIL;
+	}
+
+	tlbe = &vcpu->arch.guest_tlb[index];
+
+	/* Invalidate shadow mappings for the about-to-be-clobbered TLBE. */
+	if (tlbe->word0 & PPC44x_TLB_VALID) {
+		eaddr = get_tlb_eaddr(tlbe);
+		asid = (tlbe->word0 & PPC44x_TLB_TS) | tlbe->tid;
+		kvmppc_mmu_invalidate(vcpu, eaddr, asid);
+	}
+
+	switch (ws) {
+	case PPC44x_TLB_PAGEID:
+		tlbe->tid = vcpu->arch.mmucr & 0xff;
+		tlbe->word0 = vcpu->arch.gpr[rs];
+		break;
+
+	case PPC44x_TLB_XLAT:
+		tlbe->word1 = vcpu->arch.gpr[rs];
+		break;
+
+	case PPC44x_TLB_ATTRIB:
+		tlbe->word2 = vcpu->arch.gpr[rs];
+		break;
+
+	default:
+		return EMULATE_FAIL;
+	}
+
+	if (tlbe_is_host_safe(vcpu, tlbe)) {
+		eaddr = get_tlb_eaddr(tlbe);
+		raddr = get_tlb_raddr(tlbe);
+		asid = (tlbe->word0 & PPC44x_TLB_TS) | tlbe->tid;
+		flags = tlbe->word2 & 0xffff;
+
+		/* Create a 4KB mapping on the host. If the guest wanted a
+		 * large page, only the first 4KB is mapped here and the rest
+		 * are mapped on the fly. */
+		kvmppc_mmu_map(vcpu, eaddr, raddr >> PAGE_SHIFT, asid, flags);
+	}
+
+	return EMULATE_DONE;
+}
+
+static void kvmppc_emulate_dec(struct kvm_vcpu *vcpu)
+{
+	if (vcpu->arch.tcr & TCR_DIE) {
+		/* The decrementer ticks at the same rate as the timebase, so
+		 * that's how we convert the guest DEC value to the number of
+		 * host ticks. */
+		unsigned long nr_jiffies;
+
+		nr_jiffies = vcpu->arch.dec / tb_ticks_per_jiffy;
+		mod_timer(&vcpu->arch.dec_timer,
+		          get_jiffies_64() + nr_jiffies);
+	} else {
+		del_timer(&vcpu->arch.dec_timer);
+	}
+}
+
+static void kvmppc_emul_rfi(struct kvm_vcpu *vcpu)
+{
+	vcpu->arch.pc = vcpu->arch.srr0;
+	kvmppc_set_msr(vcpu, vcpu->arch.srr1);
+}
+
+/* XXX to do:
+ * lhax
+ * lhaux
+ * lswx
+ * lswi
+ * stswx
+ * stswi
+ * lha
+ * lhau
+ * lmw
+ * stmw
+ *
+ * XXX is_bigendian should depend on MMU mapping or MSR[LE]
+ */
+int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
+{
+	u32 inst = vcpu->arch.last_inst;
+	u32 ea;
+	int ra;
+	int rb;
+	int rc;
+	int rs;
+	int rt;
+	int sprn;
+	int dcrn;
+	enum emulation_result emulated = EMULATE_DONE;
+	int advance = 1;
+
+	switch (get_op(inst)) {
+	case 3:                                                 /* trap */
+		printk("trap!\n");
+		kvmppc_queue_exception(vcpu, BOOKE_INTERRUPT_PROGRAM);
+		advance = 0;
+		break;
+
+	case 19:
+		switch (get_xop(inst)) {
+		case 50:                                        /* rfi */
+			kvmppc_emul_rfi(vcpu);
+			advance = 0;
+			break;
+
+		default:
+			emulated = EMULATE_FAIL;
+			break;
+		}
+		break;
+
+	case 31:
+		switch (get_xop(inst)) {
+
+		case 83:                                        /* mfmsr */
+			rt = get_rt(inst);
+			vcpu->arch.gpr[rt] = vcpu->arch.msr;
+			break;
+
+		case 87:                                        /* lbzx */
+			rt = get_rt(inst);
+			emulated = kvmppc_handle_load(run, vcpu, rt, 1, 1);
+			break;
+
+		case 131:                                       /* wrtee */
+			rs = get_rs(inst);
+			vcpu->arch.msr = (vcpu->arch.msr & ~MSR_EE)
+			                 | (vcpu->arch.gpr[rs] & MSR_EE);
+			break;
+
+		case 146:                                       /* mtmsr */
+			rs = get_rs(inst);
+			kvmppc_set_msr(vcpu, vcpu->arch.gpr[rs]);
+			break;
+
+		case 163:                                       /* wrteei */
+			vcpu->arch.msr = (vcpu->arch.msr & ~MSR_EE)
+			                 | (inst & MSR_EE);
+			break;
+
+		case 215:                                       /* stbx */
+			rs = get_rs(inst);
+			emulated = kvmppc_handle_store(run, vcpu,
+			                               vcpu->arch.gpr[rs],
+			                               1, 1);
+			break;
+
+		case 247:                                       /* stbux */
+			rs = get_rs(inst);
+			ra = get_ra(inst);
+			rb = get_rb(inst);
+
+			ea = vcpu->arch.gpr[rb];
+			if (ra)
+				ea += vcpu->arch.gpr[ra];
+
+			emulated = kvmppc_handle_store(run, vcpu,
+			                               vcpu->arch.gpr[rs],
+			                               1, 1);
+			vcpu->arch.gpr[rs] = ea;
+			break;
+
+		case 279:                                       /* lhzx */
+			rt = get_rt(inst);
+			emulated = kvmppc_handle_load(run, vcpu, rt, 2, 1);
+			break;
+
+		case 311:                                       /* lhzux */
+			rt = get_rt(inst);
+			ra = get_ra(inst);
+			rb = get_rb(inst);
+
+			ea = vcpu->arch.gpr[rb];
+			if (ra)
+				ea += vcpu->arch.gpr[ra];
+
+			emulated = kvmppc_handle_load(run, vcpu, rt, 2, 1);
+			vcpu->arch.gpr[ra] = ea;
+			break;
+
+		case 323:                                       /* mfdcr */
+			dcrn = get_dcrn(inst);
+			rt = get_rt(inst);
+
+			/* emulate some access in kernel */
+			switch (dcrn) {
+			case DCRN_CPR0_CFGADDR:
+				vcpu->arch.gpr[rt] = vcpu->arch.cpr0_cfgaddr;
+				break;
+			case DCRN_CPR0_CFGDATA:
+				local_irq_disable();
+				mtdcr(DCRN_CPR0_CFGADDR,
+				      vcpu->arch.cpr0_cfgaddr);
+				vcpu->arch.gpr[rt] = mfdcr(DCRN_CPR0_CFGDATA);
+				local_irq_enable();
+				break;
+			default:
+				run->dcr.dcrn = dcrn;
+				run->dcr.data =  0;
+				run->dcr.is_write = 0;
+				vcpu->arch.io_gpr = rt;
+				vcpu->arch.dcr_needed = 1;
+				emulated = EMULATE_DO_DCR;
+			}
+
+			break;
+
+		case 339:                                       /* mfspr */
+			sprn = get_sprn(inst);
+			rt = get_rt(inst);
+
+			switch (sprn) {
+			case SPRN_SRR0:
+				vcpu->arch.gpr[rt] = vcpu->arch.srr0; break;
+			case SPRN_SRR1:
+				vcpu->arch.gpr[rt] = vcpu->arch.srr1; break;
+			case SPRN_MMUCR:
+				vcpu->arch.gpr[rt] = vcpu->arch.mmucr; break;
+			case SPRN_PID:
+				vcpu->arch.gpr[rt] = vcpu->arch.pid; break;
+			case SPRN_IVPR:
+				vcpu->arch.gpr[rt] = vcpu->arch.ivpr; break;
+			case SPRN_CCR0:
+				vcpu->arch.gpr[rt] = vcpu->arch.ccr0; break;
+			case SPRN_CCR1:
+				vcpu->arch.gpr[rt] = vcpu->arch.ccr1; break;
+			case SPRN_PVR:
+				vcpu->arch.gpr[rt] = vcpu->arch.pvr; break;
+			case SPRN_DEAR:
+				vcpu->arch.gpr[rt] = vcpu->arch.dear; break;
+			case SPRN_ESR:
+				vcpu->arch.gpr[rt] = vcpu->arch.esr; break;
+			case SPRN_DBCR0:
+				vcpu->arch.gpr[rt] = vcpu->arch.dbcr0; break;
+			case SPRN_DBCR1:
+				vcpu->arch.gpr[rt] = vcpu->arch.dbcr1; break;
+
+			/* Note: mftb and TBRL/TBWL are user-accessible, so
+			 * the guest can always access the real TB anyways.
+			 * In fact, we probably will never see these traps. */
+			case SPRN_TBWL:
+				vcpu->arch.gpr[rt] = mftbl(); break;
+			case SPRN_TBWU:
+				vcpu->arch.gpr[rt] = mftbu(); break;
+
+			case SPRN_SPRG0:
+				vcpu->arch.gpr[rt] = vcpu->arch.sprg0; break;
+			case SPRN_SPRG1:
+				vcpu->arch.gpr[rt] = vcpu->arch.sprg1; break;
+			case SPRN_SPRG2:
+				vcpu->arch.gpr[rt] = vcpu->arch.sprg2; break;
+			case SPRN_SPRG3:
+				vcpu->arch.gpr[rt] = vcpu->arch.sprg3; break;
+			/* Note: SPRG4-7 are user-readable, so we don't get
+			 * a trap. */
+
+			case SPRN_IVOR0:
+				vcpu->arch.gpr[rt] = vcpu->arch.ivor[0]; break;
+			case SPRN_IVOR1:
+				vcpu->arch.gpr[rt] = vcpu->arch.ivor[1]; break;
+			case SPRN_IVOR2:
+				vcpu->arch.gpr[rt] = vcpu->arch.ivor[2]; break;
+			case SPRN_IVOR3:
+				vcpu->arch.gpr[rt] = vcpu->arch.ivor[3]; break;
+			case SPRN_IVOR4:
+				vcpu->arch.gpr[rt] = vcpu->arch.ivor[4]; break;
+			case SPRN_IVOR5:
+				vcpu->arch.gpr[rt] = vcpu->arch.ivor[5]; break;
+			case SPRN_IVOR6:
+				vcpu->arch.gpr[rt] = vcpu->arch.ivor[6]; break;
+			case SPRN_IVOR7:
+				vcpu->arch.gpr[rt] = vcpu->arch.ivor[7]; break;
+			case SPRN_IVOR8:
+				vcpu->arch.gpr[rt] = vcpu->arch.ivor[8]; break;
+			case SPRN_IVOR9:
+				vcpu->arch.gpr[rt] = vcpu->arch.ivor[9]; break;
+			case SPRN_IVOR10:
+				vcpu->arch.gpr[rt] = vcpu->arch.ivor[10]; break;
+			case SPRN_IVOR11:
+				vcpu->arch.gpr[rt] = vcpu->arch.ivor[11]; break;
+			case SPRN_IVOR12:
+				vcpu->arch.gpr[rt] = vcpu->arch.ivor[12]; break;
+			case SPRN_IVOR13:
+				vcpu->arch.gpr[rt] = vcpu->arch.ivor[13]; break;
+			case SPRN_IVOR14:
+				vcpu->arch.gpr[rt] = vcpu->arch.ivor[14]; break;
+			case SPRN_IVOR15:
+				vcpu->arch.gpr[rt] = vcpu->arch.ivor[15]; break;
+
+			default:
+				printk("mfspr: unknown spr %x\n", sprn);
+				vcpu->arch.gpr[rt] = 0;
+				break;
+			}
+			break;
+
+		case 407:                                       /* sthx */
+			rs = get_rs(inst);
+			ra = get_ra(inst);
+			rb = get_rb(inst);
+
+			emulated = kvmppc_handle_store(run, vcpu,
+			                               vcpu->arch.gpr[rs],
+			                               2, 1);
+			break;
+
+		case 439:                                       /* sthux */
+			rs = get_rs(inst);
+			ra = get_ra(inst);
+			rb = get_rb(inst);
+
+			ea = vcpu->arch.gpr[rb];
+			if (ra)
+				ea += vcpu->arch.gpr[ra];
+
+			emulated = kvmppc_handle_store(run, vcpu,
+			                               vcpu->arch.gpr[rs],
+			                               2, 1);
+			vcpu->arch.gpr[ra] = ea;
+			break;
+
+		case 451:                                       /* mtdcr */
+			dcrn = get_dcrn(inst);
+			rs = get_rs(inst);
+
+			/* emulate some access in kernel */
+			switch (dcrn) {
+			case DCRN_CPR0_CFGADDR:
+				vcpu->arch.cpr0_cfgaddr = vcpu->arch.gpr[rs];
+				break;
+			default:
+				run->dcr.dcrn = dcrn;
+				run->dcr.data = vcpu->arch.gpr[rs];
+				run->dcr.is_write = 1;
+				vcpu->arch.dcr_needed = 1;
+				emulated = EMULATE_DO_DCR;
+			}
+
+			break;
+
+		case 467:                                       /* mtspr */
+			sprn = get_sprn(inst);
+			rs = get_rs(inst);
+			switch (sprn) {
+			case SPRN_SRR0:
+				vcpu->arch.srr0 = vcpu->arch.gpr[rs]; break;
+			case SPRN_SRR1:
+				vcpu->arch.srr1 = vcpu->arch.gpr[rs]; break;
+			case SPRN_MMUCR:
+				vcpu->arch.mmucr = vcpu->arch.gpr[rs]; break;
+			case SPRN_PID:
+				vcpu->arch.pid = vcpu->arch.gpr[rs]; break;
+			case SPRN_CCR0:
+				vcpu->arch.ccr0 = vcpu->arch.gpr[rs]; break;
+			case SPRN_CCR1:
+				vcpu->arch.ccr1 = vcpu->arch.gpr[rs]; break;
+			case SPRN_DEAR:
+				vcpu->arch.dear = vcpu->arch.gpr[rs]; break;
+			case SPRN_ESR:
+				vcpu->arch.esr = vcpu->arch.gpr[rs]; break;
+			case SPRN_DBCR0:
+				vcpu->arch.dbcr0 = vcpu->arch.gpr[rs]; break;
+			case SPRN_DBCR1:
+				vcpu->arch.dbcr1 = vcpu->arch.gpr[rs]; break;
+
+			/* XXX We need to context-switch the timebase for
+			 * watchdog and FIT. */
+			case SPRN_TBWL: break;
+			case SPRN_TBWU: break;
+
+			case SPRN_DEC:
+				vcpu->arch.dec = vcpu->arch.gpr[rs];
+				kvmppc_emulate_dec(vcpu);
+				break;
+
+			case SPRN_TSR:
+				vcpu->arch.tsr &= ~vcpu->arch.gpr[rs]; break;
+
+			case SPRN_TCR:
+				vcpu->arch.tcr = vcpu->arch.gpr[rs];
+				kvmppc_emulate_dec(vcpu);
+				break;
+
+			case SPRN_SPRG0:
+				vcpu->arch.sprg0 = vcpu->arch.gpr[rs]; break;
+			case SPRN_SPRG1:
+				vcpu->arch.sprg1 = vcpu->arch.gpr[rs]; break;
+			case SPRN_SPRG2:
+				vcpu->arch.sprg2 = vcpu->arch.gpr[rs]; break;
+			case SPRN_SPRG3:
+				vcpu->arch.sprg3 = vcpu->arch.gpr[rs]; break;
+
+			/* Note: SPRG4-7 are user-readable. These values are
+			 * loaded into the real SPRGs when resuming the
+			 * guest. */
+			case SPRN_SPRG4:
+				vcpu->arch.sprg4 = vcpu->arch.gpr[rs]; break;
+			case SPRN_SPRG5:
+				vcpu->arch.sprg5 = vcpu->arch.gpr[rs]; break;
+			case SPRN_SPRG6:
+				vcpu->arch.sprg6 = vcpu->arch.gpr[rs]; break;
+			case SPRN_SPRG7:
+				vcpu->arch.sprg7 = vcpu->arch.gpr[rs]; break;
+
+			case SPRN_IVPR:
+				vcpu->arch.ivpr = vcpu->arch.gpr[rs]; break;
+			case SPRN_IVOR0:
+				vcpu->arch.ivor[0] = vcpu->arch.gpr[rs]; break;
+			case SPRN_IVOR1:
+				vcpu->arch.ivor[1] = vcpu->arch.gpr[rs]; break;
+			case SPRN_IVOR2:
+				vcpu->arch.ivor[2] = vcpu->arch.gpr[rs]; break;
+			case SPRN_IVOR3:
+				vcpu->arch.ivor[3] = vcpu->arch.gpr[rs]; break;
+			case SPRN_IVOR4:
+				vcpu->arch.ivor[4] = vcpu->arch.gpr[rs]; break;
+			case SPRN_IVOR5:
+				vcpu->arch.ivor[5] = vcpu->arch.gpr[rs]; break;
+			case SPRN_IVOR6:
+				vcpu->arch.ivor[6] = vcpu->arch.gpr[rs]; break;
+			case SPRN_IVOR7:
+				vcpu->arch.ivor[7] = vcpu->arch.gpr[rs]; break;
+			case SPRN_IVOR8:
+				vcpu->arch.ivor[8] = vcpu->arch.gpr[rs]; break;
+			case SPRN_IVOR9:
+				vcpu->arch.ivor[9] = vcpu->arch.gpr[rs]; break;
+			case SPRN_IVOR10:
+				vcpu->arch.ivor[10] = vcpu->arch.gpr[rs]; break;
+			case SPRN_IVOR11:
+				vcpu->arch.ivor[11] = vcpu->arch.gpr[rs]; break;
+			case SPRN_IVOR12:
+				vcpu->arch.ivor[12] = vcpu->arch.gpr[rs]; break;
+			case SPRN_IVOR13:
+				vcpu->arch.ivor[13] = vcpu->arch.gpr[rs]; break;
+			case SPRN_IVOR14:
+				vcpu->arch.ivor[14] = vcpu->arch.gpr[rs]; break;
+			case SPRN_IVOR15:
+				vcpu->arch.ivor[15] = vcpu->arch.gpr[rs]; break;
+
+			default:
+				printk("mtspr: unknown spr %x\n", sprn);
+				emulated = EMULATE_FAIL;
+				break;
+			}
+			break;
+
+		case 470:                                       /* dcbi */
+			/* Do nothing. The guest is performing dcbi because
+			 * hardware DMA is not snooped by the dcache, but
+			 * emulated DMA either goes through the dcache as
+			 * normal writes, or the host kernel has handled dcache
+			 * coherence. */
+			break;
+
+		case 534:                                       /* lwbrx */
+			rt = get_rt(inst);
+			emulated = kvmppc_handle_load(run, vcpu, rt, 4, 0);
+			break;
+
+		case 566:                                       /* tlbsync */
+			break;
+
+		case 662:                                       /* stwbrx */
+			rs = get_rs(inst);
+			ra = get_ra(inst);
+			rb = get_rb(inst);
+
+			emulated = kvmppc_handle_store(run, vcpu,
+			                               vcpu->arch.gpr[rs],
+			                               4, 0);
+			break;
+
+		case 978:                                       /* tlbwe */
+			emulated = kvmppc_emul_tlbwe(vcpu, inst);
+			break;
+
+		case 914:       {                               /* tlbsx */
+			int index;
+			unsigned int as = get_mmucr_sts(vcpu);
+			unsigned int pid = get_mmucr_stid(vcpu);
+
+			rt = get_rt(inst);
+			ra = get_ra(inst);
+			rb = get_rb(inst);
+			rc = get_rc(inst);
+
+			ea = vcpu->arch.gpr[rb];
+			if (ra)
+				ea += vcpu->arch.gpr[ra];
+
+			index = kvmppc_44x_tlb_index(vcpu, ea, pid, as);
+			if (rc) {
+				if (index < 0)
+					vcpu->arch.cr &= ~0x20000000;
+				else
+					vcpu->arch.cr |= 0x20000000;
+			}
+			vcpu->arch.gpr[rt] = index;
+
+			}
+			break;
+
+		case 790:                                       /* lhbrx */
+			rt = get_rt(inst);
+			emulated = kvmppc_handle_load(run, vcpu, rt, 2, 0);
+			break;
+
+		case 918:                                       /* sthbrx */
+			rs = get_rs(inst);
+			ra = get_ra(inst);
+			rb = get_rb(inst);
+
+			emulated = kvmppc_handle_store(run, vcpu,
+			                               vcpu->arch.gpr[rs],
+			                               2, 0);
+			break;
+
+		case 966:                                       /* iccci */
+			break;
+
+		default:
+			printk("unknown: op %d xop %d\n", get_op(inst),
+				get_xop(inst));
+			emulated = EMULATE_FAIL;
+			break;
+		}
+		break;
+
+	case 32:                                                /* lwz */
+		rt = get_rt(inst);
+		emulated = kvmppc_handle_load(run, vcpu, rt, 4, 1);
+		break;
+
+	case 33:                                                /* lwzu */
+		ra = get_ra(inst);
+		rt = get_rt(inst);
+		emulated = kvmppc_handle_load(run, vcpu, rt, 4, 1);
+		vcpu->arch.gpr[ra] = vcpu->arch.paddr_accessed;
+		break;
+
+	case 34:                                                /* lbz */
+		rt = get_rt(inst);
+		emulated = kvmppc_handle_load(run, vcpu, rt, 1, 1);
+		break;
+
+	case 35:                                                /* lbzu */
+		ra = get_ra(inst);
+		rt = get_rt(inst);
+		emulated = kvmppc_handle_load(run, vcpu, rt, 1, 1);
+		vcpu->arch.gpr[ra] = vcpu->arch.paddr_accessed;
+		break;
+
+	case 36:                                                /* stw */
+		rs = get_rs(inst);
+		emulated = kvmppc_handle_store(run, vcpu, vcpu->arch.gpr[rs],
+		                               4, 1);
+		break;
+
+	case 37:                                                /* stwu */
+		ra = get_ra(inst);
+		rs = get_rs(inst);
+		emulated = kvmppc_handle_store(run, vcpu, vcpu->arch.gpr[rs],
+		                               4, 1);
+		vcpu->arch.gpr[ra] = vcpu->arch.paddr_accessed;
+		break;
+
+	case 38:                                                /* stb */
+		rs = get_rs(inst);
+		emulated = kvmppc_handle_store(run, vcpu, vcpu->arch.gpr[rs],
+		                               1, 1);
+		break;
+
+	case 39:                                                /* stbu */
+		ra = get_ra(inst);
+		rs = get_rs(inst);
+		emulated = kvmppc_handle_store(run, vcpu, vcpu->arch.gpr[rs],
+		                               1, 1);
+		vcpu->arch.gpr[ra] = vcpu->arch.paddr_accessed;
+		break;
+
+	case 40:                                                /* lhz */
+		rt = get_rt(inst);
+		emulated = kvmppc_handle_load(run, vcpu, rt, 2, 1);
+		break;
+
+	case 41:                                                /* lhzu */
+		ra = get_ra(inst);
+		rt = get_rt(inst);
+		emulated = kvmppc_handle_load(run, vcpu, rt, 2, 1);
+		vcpu->arch.gpr[ra] = vcpu->arch.paddr_accessed;
+		break;
+
+	case 44:                                                /* sth */
+		rs = get_rs(inst);
+		emulated = kvmppc_handle_store(run, vcpu, vcpu->arch.gpr[rs],
+		                               2, 1);
+		break;
+
+	case 45:                                                /* sthu */
+		ra = get_ra(inst);
+		rs = get_rs(inst);
+		emulated = kvmppc_handle_store(run, vcpu, vcpu->arch.gpr[rs],
+		                               2, 1);
+		vcpu->arch.gpr[ra] = vcpu->arch.paddr_accessed;
+		break;
+
+	default:
+		printk("unknown op %d\n", get_op(inst));
+		emulated = EMULATE_FAIL;
+		break;
+	}
+
+	if (advance)
+		vcpu->arch.pc += 4; /* Advance past emulated instruction. */
+
+	return emulated;
+}
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c
new file mode 100644
--- /dev/null
+++ b/arch/powerpc/kvm/powerpc.c
@@ -0,0 +1,1031 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * 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, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Copyright IBM Corp. 2007
+ *
+ * Authors: Hollis Blanchard <hollisb@us.ibm.com>
+ *          Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
+ */
+
+/* Code to support 440 hosts. */
+
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/kvm_host.h>
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/fs.h>
+#include <asm/cputable.h>
+#include <asm/cacheflush.h>
+#include <asm/uaccess.h>
+#include <asm/kvm_ppc.h>
+
+#include "44x_tlb.h"
+
+unsigned long kvmppc_44x_handlers;
+
+#define VM_STAT(x) offsetof(struct kvm, stat.x), KVM_STAT_VM
+#define VCPU_STAT(x) offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU
+
+struct kvm_stats_debugfs_item debugfs_entries[] = {
+	{ "exits",      VCPU_STAT(sum_exits) },
+	{ "mmio",       VCPU_STAT(mmio_exits) },
+	{ "dcr",        VCPU_STAT(dcr_exits) },
+	{ "sig",        VCPU_STAT(signal_exits) },
+	{ "light",      VCPU_STAT(light_exits) },
+	{ "itlb_r",     VCPU_STAT(itlb_real_miss_exits) },
+	{ "itlb_v",     VCPU_STAT(itlb_virt_miss_exits) },
+	{ "dtlb_r",     VCPU_STAT(dtlb_real_miss_exits) },
+	{ "dtlb_v",     VCPU_STAT(dtlb_virt_miss_exits) },
+	{ "sysc",       VCPU_STAT(syscall_exits) },
+	{ "isi",        VCPU_STAT(isi_exits) },
+	{ "dsi",        VCPU_STAT(dsi_exits) },
+	{ "inst_emu",   VCPU_STAT(emulated_inst_exits) },
+	{ "dec",        VCPU_STAT(dec_exits) },
+	{ "ext_intr",   VCPU_STAT(ext_intr_exits) },
+	{ NULL }
+};
+
+static const u32 interrupt_msr_mask[16] = {
+	[BOOKE_INTERRUPT_CRITICAL]      = MSR_ME,
+	[BOOKE_INTERRUPT_MACHINE_CHECK] = 0,
+	[BOOKE_INTERRUPT_DATA_STORAGE]  = MSR_CE|MSR_ME|MSR_DE,
+	[BOOKE_INTERRUPT_INST_STORAGE]  = MSR_CE|MSR_ME|MSR_DE,
+	[BOOKE_INTERRUPT_EXTERNAL]      = MSR_CE|MSR_ME|MSR_DE,
+	[BOOKE_INTERRUPT_ALIGNMENT]     = MSR_CE|MSR_ME|MSR_DE,
+	[BOOKE_INTERRUPT_PROGRAM]       = MSR_CE|MSR_ME|MSR_DE,
+	[BOOKE_INTERRUPT_FP_UNAVAIL]    = MSR_CE|MSR_ME|MSR_DE,
+	[BOOKE_INTERRUPT_SYSCALL]       = MSR_CE|MSR_ME|MSR_DE,
+	[BOOKE_INTERRUPT_AP_UNAVAIL]    = MSR_CE|MSR_ME|MSR_DE,
+	[BOOKE_INTERRUPT_DECREMENTER]   = MSR_CE|MSR_ME|MSR_DE,
+	[BOOKE_INTERRUPT_FIT]           = MSR_CE|MSR_ME|MSR_DE,
+	[BOOKE_INTERRUPT_WATCHDOG]      = MSR_ME,
+	[BOOKE_INTERRUPT_DTLB_MISS]     = MSR_CE|MSR_ME|MSR_DE,
+	[BOOKE_INTERRUPT_ITLB_MISS]     = MSR_CE|MSR_ME|MSR_DE,
+	[BOOKE_INTERRUPT_DEBUG]         = MSR_ME,
+};
+
+const unsigned char exception_priority[] = {
+	[BOOKE_INTERRUPT_DATA_STORAGE] = 0,
+	[BOOKE_INTERRUPT_INST_STORAGE] = 1,
+	[BOOKE_INTERRUPT_ALIGNMENT] = 2,
+	[BOOKE_INTERRUPT_PROGRAM] = 3,
+	[BOOKE_INTERRUPT_FP_UNAVAIL] = 4,
+	[BOOKE_INTERRUPT_SYSCALL] = 5,
+	[BOOKE_INTERRUPT_AP_UNAVAIL] = 6,
+	[BOOKE_INTERRUPT_DTLB_MISS] = 7,
+	[BOOKE_INTERRUPT_ITLB_MISS] = 8,
+	[BOOKE_INTERRUPT_MACHINE_CHECK] = 9,
+	[BOOKE_INTERRUPT_DEBUG] = 10,
+	[BOOKE_INTERRUPT_CRITICAL] = 11,
+	[BOOKE_INTERRUPT_WATCHDOG] = 12,
+	[BOOKE_INTERRUPT_EXTERNAL] = 13,
+	[BOOKE_INTERRUPT_FIT] = 14,
+	[BOOKE_INTERRUPT_DECREMENTER] = 15,
+};
+
+const unsigned char priority_exception[] = {
+	BOOKE_INTERRUPT_DATA_STORAGE,
+	BOOKE_INTERRUPT_INST_STORAGE,
+	BOOKE_INTERRUPT_ALIGNMENT,
+	BOOKE_INTERRUPT_PROGRAM,
+	BOOKE_INTERRUPT_FP_UNAVAIL,
+	BOOKE_INTERRUPT_SYSCALL,
+	BOOKE_INTERRUPT_AP_UNAVAIL,
+	BOOKE_INTERRUPT_DTLB_MISS,
+	BOOKE_INTERRUPT_ITLB_MISS,
+	BOOKE_INTERRUPT_MACHINE_CHECK,
+	BOOKE_INTERRUPT_DEBUG,
+	BOOKE_INTERRUPT_CRITICAL,
+	BOOKE_INTERRUPT_WATCHDOG,
+	BOOKE_INTERRUPT_EXTERNAL,
+	BOOKE_INTERRUPT_FIT,
+	BOOKE_INTERRUPT_DECREMENTER,
+};
+
+
+gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn)
+{
+	return gfn;
+}
+
+void kvmppc_dump_tlbs(struct kvm_vcpu *vcpu)
+{
+	struct tlbe *tlbe;
+	int i;
+
+	printk("vcpu %d TLB dump:\n", vcpu->vcpu_id);
+	printk("| %2s | %3s | %8s | %8s | %8s |\n",
+			"nr", "tid", "word0", "word1", "word2");
+
+	for (i = 0; i < PPC44x_TLB_SIZE; i++) {
+		tlbe = &vcpu->arch.guest_tlb[i];
+		if (tlbe->word0 & PPC44x_TLB_VALID)
+			printk(" G%2d |  %02X | %08X | %08X | %08X |\n",
+			       i, tlbe->tid, tlbe->word0, tlbe->word1,
+			       tlbe->word2);
+	}
+
+	for (i = 0; i < PPC44x_TLB_SIZE; i++) {
+		tlbe = &vcpu->arch.shadow_tlb[i];
+		if (tlbe->word0 & PPC44x_TLB_VALID)
+			printk(" S%2d | %02X | %08X | %08X | %08X |\n",
+			       i, tlbe->tid, tlbe->word0, tlbe->word1,
+			       tlbe->word2);
+	}
+}
+
+/* TODO: use vcpu_printf() */
+void kvmppc_dump_vcpu(struct kvm_vcpu *vcpu)
+{
+	int i;
+
+	printk("pc:   %08x msr:  %08x\n", vcpu->arch.pc, vcpu->arch.msr);
+	printk("lr:   %08x ctr:  %08x\n", vcpu->arch.lr, vcpu->arch.ctr);
+	printk("srr0: %08x srr1: %08x\n", vcpu->arch.srr0, vcpu->arch.srr1);
+
+	printk("exceptions: %08lx\n", vcpu->arch.pending_exceptions);
+
+	for (i = 0; i < 32; i += 4) {
+		printk("gpr%02d: %08x %08x %08x %08x\n", i,
+		       vcpu->arch.gpr[i],
+		       vcpu->arch.gpr[i+1],
+		       vcpu->arch.gpr[i+2],
+		       vcpu->arch.gpr[i+3]);
+	}
+}
+
+int kvm_cpu_has_interrupt(struct kvm_vcpu *v)
+{
+	/* XXX implement me */
+	return 0;
+}
+
+int kvm_arch_vcpu_runnable(struct kvm_vcpu *v)
+{
+	return 1;
+}
+
+/* Check if we are ready to deliver the interrupt */
+static int kvmppc_can_deliver_interrupt(struct kvm_vcpu *vcpu, int interrupt)
+{
+	int r;
+
+	switch (interrupt) {
+	case BOOKE_INTERRUPT_CRITICAL:
+		r = vcpu->arch.msr & MSR_CE;
+		break;
+	case BOOKE_INTERRUPT_MACHINE_CHECK:
+		r = vcpu->arch.msr & MSR_ME;
+		break;
+	case BOOKE_INTERRUPT_EXTERNAL:
+		r = vcpu->arch.msr & MSR_EE;
+		break;
+	case BOOKE_INTERRUPT_DECREMENTER:
+		r = vcpu->arch.msr & MSR_EE;
+		break;
+	case BOOKE_INTERRUPT_FIT:
+		r = vcpu->arch.msr & MSR_EE;
+		break;
+	case BOOKE_INTERRUPT_WATCHDOG:
+		r = vcpu->arch.msr & MSR_CE;
+		break;
+	case BOOKE_INTERRUPT_DEBUG:
+		r = vcpu->arch.msr & MSR_DE;
+		break;
+	default:
+		r = 1;
+	}
+
+	return r;
+}
+
+static void kvmppc_deliver_interrupt(struct kvm_vcpu *vcpu, int interrupt)
+{
+	switch (interrupt) {
+	case BOOKE_INTERRUPT_DECREMENTER:
+		vcpu->arch.tsr |= TSR_DIS;
+		break;
+	}
+
+	vcpu->arch.srr0 = vcpu->arch.pc;
+	vcpu->arch.srr1 = vcpu->arch.msr;
+	vcpu->arch.pc = vcpu->arch.ivpr | vcpu->arch.ivor[interrupt];
+	kvmppc_set_msr(vcpu, vcpu->arch.msr & interrupt_msr_mask[interrupt]);
+}
+
+/* Check pending exceptions and deliver one, if possible. */
+static void kvmppc_check_and_deliver_interrupts(struct kvm_vcpu *vcpu)
+{
+	unsigned long *pending = &vcpu->arch.pending_exceptions;
+	unsigned int exception;
+	unsigned int priority;
+
+	priority = find_first_bit(pending, BITS_PER_BYTE * sizeof(*pending));
+	while (priority <= BOOKE_MAX_INTERRUPT) {
+		exception = priority_exception[priority];
+		if (kvmppc_can_deliver_interrupt(vcpu, exception)) {
+			kvmppc_clear_exception(vcpu, exception);
+			kvmppc_deliver_interrupt(vcpu, exception);
+			break;
+		}
+
+		priority = find_next_bit(pending,
+		                         BITS_PER_BYTE * sizeof(*pending),
+		                         priority + 1);
+	}
+}
+
+static int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu)
+{
+	enum emulation_result er;
+	int r;
+
+	er = kvmppc_emulate_instruction(run, vcpu);
+	switch (er) {
+	case EMULATE_DONE:
+		/* Future optimization: only reload non-volatiles if they were
+		 * actually modified. */
+		r = RESUME_GUEST_NV;
+		break;
+	case EMULATE_DO_MMIO:
+		run->exit_reason = KVM_EXIT_MMIO;
+		/* We must reload nonvolatiles because "update" load/store
+		 * instructions modify register state. */
+		/* Future optimization: only reload non-volatiles if they were
+		 * actually modified. */
+		r = RESUME_HOST_NV;
+		break;
+	case EMULATE_FAIL:
+		/* XXX Deliver Program interrupt to guest. */
+		printk(KERN_EMERG "%s: emulation failed (%08x)\n", __func__,
+		       vcpu->arch.last_inst);
+		r = RESUME_HOST;
+		break;
+	default:
+		BUG();
+	}
+
+	return r;
+}
+
+/**
+ * kvmppc_handle_exit
+ * 
+ * Return value is in the form (errcode<<2 | RESUME_FLAG_HOST | RESUME_FLAG_NV)
+ */
+int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
+                       unsigned int exit_nr)
+{
+	enum emulation_result er;
+	int r = RESUME_HOST;
+
+	local_irq_enable();
+
+	run->exit_reason = KVM_EXIT_UNKNOWN;
+	run->ready_for_interrupt_injection = 1;
+
+	switch (exit_nr) {
+	case BOOKE_INTERRUPT_MACHINE_CHECK:
+		printk("MACHINE CHECK: %lx\n", mfspr(SPRN_MCSR));
+		kvmppc_dump_vcpu(vcpu);
+		r = RESUME_HOST;
+		break;
+
+	case BOOKE_INTERRUPT_EXTERNAL:
+	case BOOKE_INTERRUPT_DECREMENTER:
+		/* Since we switched IVPR back to the host's value, the host
+		 * handled this interrupt the moment we enabled interrupts.
+		 * Now we just offer it a chance to reschedule the guest. */
+
+		/* XXX At this point the TLB still holds our shadow TLB, so if
+		 * we do reschedule the host will fault over it. Perhaps we
+		 * should politely restore the host's entries to minimize
+		 * misses before ceding control. */
+		if (need_resched())
+			cond_resched();
+		if (exit_nr == BOOKE_INTERRUPT_DECREMENTER)
+			vcpu->stat.dec_exits++;
+		else
+			vcpu->stat.ext_intr_exits++;
+		r = RESUME_GUEST;
+		break;
+
+	case BOOKE_INTERRUPT_PROGRAM:
+		if (vcpu->arch.msr & MSR_PR) {
+			/* Program traps generated by user-level software must be handled
+			 * by the guest kernel. */
+			vcpu->arch.esr = vcpu->arch.fault_esr;
+			kvmppc_queue_exception(vcpu, BOOKE_INTERRUPT_PROGRAM);
+			r = RESUME_GUEST;
+			break;
+		}
+
+		er = kvmppc_emulate_instruction(run, vcpu);
+		switch (er) {
+		case EMULATE_DONE:
+			/* Future optimization: only reload non-volatiles if
+			 * they were actually modified by emulation. */
+			vcpu->stat.emulated_inst_exits++;
+			r = RESUME_GUEST_NV;
+			break;
+		case EMULATE_DO_DCR:
+			run->exit_reason = KVM_EXIT_DCR;
+			r = RESUME_HOST;
+			break;
+		case EMULATE_FAIL:
+			/* XXX Deliver Program interrupt to guest. */
+			printk(KERN_CRIT "%s: emulation at %x failed (%08x)\n",
+			       __func__, vcpu->arch.pc, vcpu->arch.last_inst);
+			/* For debugging, encode the failing instruction and
+			 * report it to userspace. */
+			run->hw.hardware_exit_reason = ~0ULL << 32;
+			run->hw.hardware_exit_reason |= vcpu->arch.last_inst;
+			r = RESUME_HOST;
+			break;
+		default:
+			BUG();
+		}
+		break;
+
+	case BOOKE_INTERRUPT_DATA_STORAGE:
+		vcpu->arch.dear = vcpu->arch.fault_dear;
+		vcpu->arch.esr = vcpu->arch.fault_esr;
+		kvmppc_queue_exception(vcpu, exit_nr);
+		vcpu->stat.dsi_exits++;
+		r = RESUME_GUEST;
+		break;
+
+	case BOOKE_INTERRUPT_INST_STORAGE:
+		vcpu->arch.esr = vcpu->arch.fault_esr;
+		kvmppc_queue_exception(vcpu, exit_nr);
+		vcpu->stat.isi_exits++;
+		r = RESUME_GUEST;
+		break;
+
+	case BOOKE_INTERRUPT_SYSCALL:
+		kvmppc_queue_exception(vcpu, exit_nr);
+		vcpu->stat.syscall_exits++;
+		r = RESUME_GUEST;
+		break;
+
+	case BOOKE_INTERRUPT_DTLB_MISS: {
+		struct tlbe *gtlbe;
+		unsigned long eaddr = vcpu->arch.fault_dear;
+		gfn_t gfn;
+
+		/* Check the guest TLB. */
+		gtlbe = kvmppc_44x_dtlb_search(vcpu, eaddr);
+		if (!gtlbe) {
+			/* The guest didn't have a mapping for it. */
+			kvmppc_queue_exception(vcpu, exit_nr);
+			vcpu->arch.dear = vcpu->arch.fault_dear;
+			vcpu->arch.esr = vcpu->arch.fault_esr;
+			vcpu->stat.dtlb_real_miss_exits++;
+			r = RESUME_GUEST;
+			break;
+		}
+
+		vcpu->arch.paddr_accessed = tlb_xlate(gtlbe, eaddr);
+		gfn = vcpu->arch.paddr_accessed >> PAGE_SHIFT;
+
+		if (kvm_is_visible_gfn(vcpu->kvm, gfn)) {
+			/* The guest TLB had a mapping, but the shadow TLB
+			 * didn't, and it is RAM. This could be because:
+			 * a) the entry is mapping the host kernel, or
+			 * b) the guest used a large mapping which we're faking
+			 * Either way, we need to satisfy the fault without
+			 * invoking the guest. */
+			kvmppc_mmu_map(vcpu, eaddr, gfn, gtlbe->tid,
+			               gtlbe->word2);
+			vcpu->stat.dtlb_virt_miss_exits++;
+			r = RESUME_GUEST;
+		} else {
+			/* Guest has mapped and accessed a page which is not
+			 * actually RAM. */
+			r = kvmppc_emulate_mmio(run, vcpu);
+		}
+
+		break;
+	}
+
+	case BOOKE_INTERRUPT_ITLB_MISS: {
+		struct tlbe *gtlbe;
+		unsigned long eaddr = vcpu->arch.pc;
+		gfn_t gfn;
+
+		r = RESUME_GUEST;
+
+		/* Check the guest TLB. */
+		gtlbe = kvmppc_44x_itlb_search(vcpu, eaddr);
+		if (!gtlbe) {
+			/* The guest didn't have a mapping for it. */
+			kvmppc_queue_exception(vcpu, exit_nr);
+			vcpu->stat.itlb_real_miss_exits++;
+			break;
+		}
+
+		vcpu->stat.itlb_virt_miss_exits++;
+
+		gfn = tlb_xlate(gtlbe, eaddr) >> PAGE_SHIFT;
+
+		if (kvm_is_visible_gfn(vcpu->kvm, gfn)) {
+			/* The guest TLB had a mapping, but the shadow TLB
+			 * didn't. This could be because:
+			 * a) the entry is mapping the host kernel, or
+			 * b) the guest used a large mapping which we're faking
+			 * Either way, we need to satisfy the fault without
+			 * invoking the guest. */
+			kvmppc_mmu_map(vcpu, eaddr, gfn, gtlbe->tid,
+			               gtlbe->word2);
+		} else {
+			/* Guest mapped and leaped at non-RAM! */
+			kvmppc_queue_exception(vcpu,
+			                       BOOKE_INTERRUPT_MACHINE_CHECK);
+		}
+
+		break;
+	}
+
+	default:
+		printk(KERN_EMERG "exit_nr %d\n", exit_nr);
+		BUG();
+	}
+
+	local_irq_disable();
+
+	kvmppc_check_and_deliver_interrupts(vcpu);
+
+	/* Do some exit accounting. */
+	vcpu->stat.sum_exits++;
+	if (!(r & RESUME_HOST)) {
+		/* To avoid clobbering exit_reason, only check for signals if
+		 * we aren't already exiting to userspace for some other
+		 * reason. */
+		if (signal_pending(current)) {
+			run->exit_reason = KVM_EXIT_INTR;
+			r = (-EINTR << 2) | RESUME_HOST | (r & RESUME_FLAG_NV);
+
+			vcpu->stat.signal_exits++;
+		} else {
+			vcpu->stat.light_exits++;
+		}
+	} else {
+		switch (run->exit_reason) {
+		case KVM_EXIT_MMIO:
+			vcpu->stat.mmio_exits++;
+			break;
+		case KVM_EXIT_DCR:
+			vcpu->stat.dcr_exits++;
+			break;
+		case KVM_EXIT_INTR:
+			vcpu->stat.signal_exits++;
+			break;
+		}
+	}
+
+	return r;
+}
+
+
+void kvm_arch_hardware_enable(void *garbage)
+{
+}
+
+void kvm_arch_hardware_disable(void *garbage)
+{
+}
+
+int kvm_arch_hardware_setup(void)
+{
+	return 0;
+}
+
+void kvm_arch_hardware_unsetup(void)
+{
+}
+
+void kvm_arch_check_processor_compat(void *rtn)
+{
+	int r;
+
+	if (strcmp(cur_cpu_spec->platform, "ppc440") == 0)
+		r = 0;
+	else
+		r = -ENOTSUPP;
+
+	*(int *)rtn = r;
+}
+
+struct kvm *kvm_arch_create_vm(void)
+{
+	struct kvm *kvm;
+
+	kvm = kzalloc(sizeof(struct kvm), GFP_KERNEL);
+	if (!kvm)
+		return ERR_PTR(-ENOMEM);
+
+	return kvm;
+}
+
+static void kvmppc_free_vcpus(struct kvm *kvm)
+{
+	unsigned int i;
+
+	for (i = 0; i < KVM_MAX_VCPUS; ++i) {
+		if (kvm->vcpus[i]) {
+			kvm_arch_vcpu_free(kvm->vcpus[i]);
+			kvm->vcpus[i] = NULL;
+		}
+	}
+
+}
+
+void kvm_arch_destroy_vm(struct kvm *kvm)
+{
+	kvmppc_free_vcpus(kvm);
+	kvm_free_physmem(kvm);
+	kfree(kvm);
+}
+
+int kvm_dev_ioctl_check_extension(long ext)
+{
+	int r;
+
+	switch (ext) {
+	case KVM_CAP_USER_MEMORY:
+		r = 1;
+		break;
+	default:
+		r = 0;
+		break;
+	}
+	return r;
+
+}
+
+long kvm_arch_dev_ioctl(struct file *filp,
+                        unsigned int ioctl, unsigned long arg)
+{
+	return -EINVAL;
+}
+
+int kvm_arch_set_memory_region(struct kvm *kvm,
+                               struct kvm_userspace_memory_region *mem,
+                               struct kvm_memory_slot old,
+                               int user_alloc)
+{
+	return 0;
+}
+
+struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id)
+{
+	struct kvm_vcpu *vcpu;
+	int err;
+
+	vcpu = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL);
+	if (!vcpu) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	err = kvm_vcpu_init(vcpu, kvm, id);
+	if (err)
+		goto free_vcpu;
+
+	return vcpu;
+
+free_vcpu:
+	kmem_cache_free(kvm_vcpu_cache, vcpu);
+out:
+	return ERR_PTR(err);
+}
+
+void kvm_arch_vcpu_free(struct kvm_vcpu *vcpu)
+{
+	kvm_vcpu_uninit(vcpu);
+	kmem_cache_free(kvm_vcpu_cache, vcpu);
+}
+
+void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
+{
+	kvm_arch_vcpu_free(vcpu);
+}
+
+static void kvmppc_decrementer_func(unsigned long data)
+{
+	struct kvm_vcpu *vcpu = (struct kvm_vcpu *)data;
+
+	kvmppc_queue_exception(vcpu, BOOKE_INTERRUPT_DECREMENTER);
+}
+
+int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
+{
+	setup_timer(&vcpu->arch.dec_timer, kvmppc_decrementer_func,
+	            (unsigned long)vcpu);
+
+	return 0;
+}
+
+/* Initial guest state: 16MB mapping 0 -> 0, PC = 0, MSR = 0, R1 = 16MB */
+int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
+{
+	struct tlbe *tlbe = &vcpu->arch.guest_tlb[0];
+
+	tlbe->tid = 0;
+	tlbe->word0 = PPC44x_TLB_16M | PPC44x_TLB_VALID;
+	tlbe->word1 = 0;
+	tlbe->word2 = PPC44x_TLB_SX | PPC44x_TLB_SW | PPC44x_TLB_SR;
+
+	tlbe++;
+	tlbe->tid = 0;
+	tlbe->word0 = 0xef600000 | PPC44x_TLB_4K | PPC44x_TLB_VALID;
+	tlbe->word1 = 0xef600000;
+	tlbe->word2 = PPC44x_TLB_SX | PPC44x_TLB_SW | PPC44x_TLB_SR
+	              | PPC44x_TLB_I | PPC44x_TLB_G;
+
+	vcpu->arch.pc = 0;
+	vcpu->arch.msr = 0;
+	vcpu->arch.gpr[1] = (16<<20) - 8; /* -8 for the callee-save LR slot */
+
+	/* Eye-catching number so we know if the guest takes an interrupt
+	 * before it's programmed its own IVPR. */
+	vcpu->arch.ivpr = 0x55550000;
+
+	/* Since the guest can directly access the timebase, it must know the
+	 * real timebase frequency. Accordingly, it must see the state of
+	 * CCR1[TCS]. */
+	vcpu->arch.ccr1 = mfspr(SPRN_CCR1);
+
+	return 0;
+}
+
+void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu)
+{
+}
+
+void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
+{
+}
+
+void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
+{
+}
+
+void decache_vcpus_on_cpu(int cpu)
+{
+}
+
+int kvm_arch_vcpu_ioctl_debug_guest(struct kvm_vcpu *vcpu,
+                                    struct kvm_debug_guest *dbg)
+{
+	return -ENOTSUPP;
+}
+
+int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
+{
+	return -ENOTSUPP;
+}
+
+int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
+{
+	regs->pc = vcpu->arch.pc;
+	regs->cr = vcpu->arch.cr;
+	regs->ctr = vcpu->arch.ctr;
+	regs->lr = vcpu->arch.lr;
+	regs->xer = vcpu->arch.xer;
+	regs->msr = vcpu->arch.msr;
+	regs->srr0 = vcpu->arch.srr0;
+	regs->srr1 = vcpu->arch.srr1;
+	regs->pid = vcpu->arch.pid;
+	regs->sprg0 = vcpu->arch.sprg0;
+	regs->sprg1 = vcpu->arch.sprg1;
+	regs->sprg2 = vcpu->arch.sprg2;
+	regs->sprg3 = vcpu->arch.sprg3;
+	regs->sprg5 = vcpu->arch.sprg4;
+	regs->sprg6 = vcpu->arch.sprg5;
+	regs->sprg7 = vcpu->arch.sprg6;
+
+	memcpy(regs->gpr, vcpu->arch.gpr, sizeof(regs->gpr));
+	memcpy(regs->fpr, vcpu->arch.fpr, sizeof(regs->fpr));
+
+	return 0;
+}
+
+int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
+                                  struct kvm_sregs *sregs)
+{
+	return -ENOTSUPP;
+}
+
+static void kvmppc_complete_dcr_load(struct kvm_vcpu *vcpu,
+                                     struct kvm_run *run)
+{
+	u32 *gpr = &vcpu->arch.gpr[vcpu->arch.io_gpr];
+
+	*gpr = run->dcr.data;
+}
+
+static void kvmppc_complete_mmio_load(struct kvm_vcpu *vcpu,
+                                      struct kvm_run *run)
+{
+	u32 *gpr = &vcpu->arch.gpr[vcpu->arch.io_gpr];
+
+	if (run->mmio.len > sizeof(*gpr)) {
+		printk(KERN_ERR "bad MMIO length: %d\n", run->mmio.len);
+		return;
+	}
+
+	if (vcpu->arch.mmio_is_bigendian) {
+		switch (run->mmio.len) {
+		case 4: *gpr = *(u32 *)run->mmio.data; break;
+		case 2: *gpr = *(u16 *)run->mmio.data; break;
+		case 1: *gpr = *(u8 *)run->mmio.data; break;
+		}
+	} else {
+		/* Convert BE data from userland back to LE. */
+		switch (run->mmio.len) {
+		case 4: *gpr = ld_le32((u32 *)run->mmio.data); break;
+		case 2: *gpr = ld_le16((u16 *)run->mmio.data); break;
+		case 1: *gpr = *(u8 *)run->mmio.data; break;
+		}
+	}
+}
+
+int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
+                       unsigned int rt, unsigned int bytes, int is_bigendian)
+{
+	if (bytes > sizeof(run->mmio.data)) {
+		printk(KERN_ERR "%s: bad MMIO length: %d\n", __func__,
+		       run->mmio.len);
+	}
+
+	run->mmio.phys_addr = vcpu->arch.paddr_accessed;
+	run->mmio.len = bytes;
+	run->mmio.is_write = 0;
+
+	vcpu->arch.io_gpr = rt;
+	vcpu->arch.mmio_is_bigendian = is_bigendian;
+	vcpu->mmio_needed = 1;
+	vcpu->mmio_is_write = 0;
+
+	return EMULATE_DO_MMIO;
+}
+
+int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu,
+                        u32 val, unsigned int bytes, int is_bigendian)
+{
+	void *data = run->mmio.data;
+
+	if (bytes > sizeof(run->mmio.data)) {
+		printk(KERN_ERR "%s: bad MMIO length: %d\n", __func__,
+		       run->mmio.len);
+	}
+
+	run->mmio.phys_addr = vcpu->arch.paddr_accessed;
+	run->mmio.len = bytes;
+	run->mmio.is_write = 1;
+	vcpu->mmio_needed = 1;
+	vcpu->mmio_is_write = 1;
+
+	/* Store the value at the lowest bytes in 'data'. */
+	if (is_bigendian) {
+		switch (bytes) {
+		case 4: *(u32 *)data = val; break;
+		case 2: *(u16 *)data = val; break;
+		case 1: *(u8  *)data = val; break;
+		}
+	} else {
+		/* Store LE value into 'data'. */
+		switch (bytes) {
+		case 4: st_le32(data, val); break;
+		case 2: st_le16(data, val); break;
+		case 1: *(u8 *)data = val; break;
+		}
+	}
+
+	return EMULATE_DO_MMIO;
+}
+
+int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
+{
+	int r;
+	sigset_t sigsaved;
+
+	if (vcpu->sigset_active)
+		sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved);
+
+	if (vcpu->mmio_needed) {
+		if (!vcpu->mmio_is_write)
+			kvmppc_complete_mmio_load(vcpu, run);
+		vcpu->mmio_needed = 0;
+	} else if (vcpu->arch.dcr_needed) {
+		if (!vcpu->arch.dcr_is_write)
+			kvmppc_complete_dcr_load(vcpu, run);
+		vcpu->arch.dcr_needed = 0;
+	}
+
+	kvmppc_check_and_deliver_interrupts(vcpu);
+
+	local_irq_disable();
+	kvm_guest_enter();
+	r = __kvmppc_vcpu_run(run, vcpu);
+	kvm_guest_exit();
+	local_irq_enable();
+
+	if (vcpu->sigset_active)
+		sigprocmask(SIG_SETMASK, &sigsaved, NULL);
+
+	return r;
+}
+
+int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
+{
+	return -ENOTSUPP;
+}
+
+int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
+{
+	vcpu->arch.pc = regs->pc;
+	vcpu->arch.cr = regs->cr;
+	vcpu->arch.ctr = regs->ctr;
+	vcpu->arch.lr = regs->lr;
+	vcpu->arch.xer = regs->xer;
+	vcpu->arch.msr = regs->msr;
+	vcpu->arch.srr0 = regs->srr0;
+	vcpu->arch.srr1 = regs->srr1;
+	vcpu->arch.sprg0 = regs->sprg0;
+	vcpu->arch.sprg1 = regs->sprg1;
+	vcpu->arch.sprg2 = regs->sprg2;
+	vcpu->arch.sprg3 = regs->sprg3;
+	vcpu->arch.sprg5 = regs->sprg4;
+	vcpu->arch.sprg6 = regs->sprg5;
+	vcpu->arch.sprg7 = regs->sprg6;
+
+	memcpy(vcpu->arch.gpr, regs->gpr, sizeof(vcpu->arch.gpr));
+	memcpy(vcpu->arch.fpr, regs->fpr, sizeof(vcpu->arch.fpr));
+
+	return 0;
+}
+
+int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
+                                  struct kvm_sregs *sregs)
+{
+	return -ENOTSUPP;
+}
+
+/* 'linear_address' is actually an encoding of AS|PID|EADDR . */
+int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu,
+                                  struct kvm_translation *tr)
+{
+	struct tlbe *gtlbe;
+	int index;
+	gva_t eaddr;
+	u8 pid;
+	u8 as;
+
+	eaddr = tr->linear_address;
+	pid = (tr->linear_address >> 32) & 0xff;
+	as = (tr->linear_address >> 40) & 0x1;
+
+	index = kvmppc_44x_tlb_index(vcpu, eaddr, pid, as);
+	if (index == -1) {
+		tr->valid = 0;
+		return 0;
+	}
+
+	gtlbe = &vcpu->arch.guest_tlb[index];
+
+	tr->physical_address = tlb_xlate(gtlbe, eaddr);
+	/* XXX what does "writeable" and "usermode" even mean? */
+	tr->valid = 1;
+
+	return 0;
+}
+
+int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu,
+				struct kvm_interrupt *irq)
+{
+	kvmppc_queue_exception(vcpu, BOOKE_INTERRUPT_EXTERNAL);
+
+	return 0;
+}
+
+long kvm_arch_vcpu_ioctl(struct file *filp,
+                         unsigned int ioctl, unsigned long arg)
+{
+	struct kvm_vcpu *vcpu = filp->private_data;
+	void __user *argp = (void __user *)arg;
+	long r;
+
+	switch (ioctl) {
+	case KVM_INTERRUPT: {
+		struct kvm_interrupt irq;
+		r = -EFAULT;
+		if (copy_from_user(&irq, argp, sizeof(irq)))
+			goto out;
+		r = kvm_vcpu_ioctl_interrupt(vcpu, &irq);
+		break;
+	}
+	default:
+		r = -EINVAL;
+	}
+
+out:
+	return r;
+}
+
+int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log)
+{
+	return -ENOTSUPP;
+}
+
+long kvm_arch_vm_ioctl(struct file *filp,
+                       unsigned int ioctl, unsigned long arg)
+{
+	long r;
+
+	switch (ioctl) {
+	default:
+		r = -EINVAL;
+	}
+
+	return r;
+}
+
+int kvm_arch_init(void *opaque)
+{
+	return 0;
+}
+
+void kvm_arch_exit(void)
+{
+}
+
+static int kvmppc_44x_init(void)
+{
+	unsigned long ivor[16];
+	unsigned long max_ivor = 0;
+	int i;
+
+	/* We install our own exception handlers by hijacking IVPR. IVPR must
+	 * be 16-bit aligned, so we need a 64KB allocation. */
+	kvmppc_44x_handlers = __get_free_pages(GFP_KERNEL | __GFP_ZERO,
+	                                       VCPU_SIZE_ORDER);
+	if (!kvmppc_44x_handlers)
+		return -ENOMEM;
+
+	/* XXX make sure our handlers are smaller than Linux's */
+
+	/* Copy our interrupt handlers to match host IVORs. That way we don't
+	 * have to swap the IVORs on every guest/host transition. */
+	ivor[0] = mfspr(SPRN_IVOR0);
+	ivor[1] = mfspr(SPRN_IVOR1);
+	ivor[2] = mfspr(SPRN_IVOR2);
+	ivor[3] = mfspr(SPRN_IVOR3);
+	ivor[4] = mfspr(SPRN_IVOR4);
+	ivor[5] = mfspr(SPRN_IVOR5);
+	ivor[6] = mfspr(SPRN_IVOR6);
+	ivor[7] = mfspr(SPRN_IVOR7);
+	ivor[8] = mfspr(SPRN_IVOR8);
+	ivor[9] = mfspr(SPRN_IVOR9);
+	ivor[10] = mfspr(SPRN_IVOR10);
+	ivor[11] = mfspr(SPRN_IVOR11);
+	ivor[12] = mfspr(SPRN_IVOR12);
+	ivor[13] = mfspr(SPRN_IVOR13);
+	ivor[14] = mfspr(SPRN_IVOR14);
+	ivor[15] = mfspr(SPRN_IVOR15);
+
+	for (i = 0; i < 16; i++) {
+		if (ivor[i] > max_ivor)
+			max_ivor = ivor[i];
+
+		memcpy((void *)kvmppc_44x_handlers + ivor[i],
+		       kvmppc_handlers_start + i * kvmppc_handler_len,
+		       kvmppc_handler_len);
+	}
+	flush_icache_range(kvmppc_44x_handlers,
+	                   kvmppc_44x_handlers + max_ivor + kvmppc_handler_len);
+
+	return kvm_init(NULL, sizeof(struct kvm_vcpu), THIS_MODULE);
+}
+
+static void __exit kvmppc_44x_exit(void)
+{
+	free_pages(kvmppc_44x_handlers, VCPU_SIZE_ORDER);
+	kvm_exit();
+}
+
+module_init(kvmppc_44x_init)
+module_exit(kvmppc_44x_exit)
diff --git a/include/asm-powerpc/kvm.h b/include/asm-powerpc/kvm.h
--- a/include/asm-powerpc/kvm.h
+++ b/include/asm-powerpc/kvm.h
@@ -1,6 +1,55 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * 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, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Copyright IBM Corp. 2007
+ *
+ * Authors: Hollis Blanchard <hollisb@us.ibm.com>
+ */
+
 #ifndef __LINUX_KVM_POWERPC_H
 #define __LINUX_KVM_POWERPC_H
 
-/* powerpc does not support KVM */
+#include <asm/types.h>
 
-#endif
+struct kvm_regs {
+	__u32 pc;
+	__u32 cr;
+	__u32 ctr;
+	__u32 lr;
+	__u32 xer;
+	__u32 msr;
+	__u32 srr0;
+	__u32 srr1;
+	__u32 pid;
+
+	__u32 sprg0;
+	__u32 sprg1;
+	__u32 sprg2;
+	__u32 sprg3;
+	__u32 sprg4;
+	__u32 sprg5;
+	__u32 sprg6;
+	__u32 sprg7;
+
+	__u64 fpr[32];
+	__u32 gpr[32];
+};
+
+struct kvm_sregs {
+};
+
+struct kvm_fpu {
+};
+
+#endif /* __LINUX_KVM_POWERPC_H */
diff --git a/include/asm-powerpc/kvm_asm.h b/include/asm-powerpc/kvm_asm.h
new file mode 100644
--- /dev/null
+++ b/include/asm-powerpc/kvm_asm.h
@@ -0,0 +1,55 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * 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, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Copyright IBM Corp. 2008
+ *
+ * Authors: Hollis Blanchard <hollisb@us.ibm.com>
+ */
+
+#ifndef __POWERPC_KVM_ASM_H__
+#define __POWERPC_KVM_ASM_H__
+
+/* IVPR must be 64KiB-aligned. */
+#define VCPU_SIZE_ORDER 4
+#define VCPU_SIZE_LOG   (VCPU_SIZE_ORDER + 12)
+#define VCPU_TLB_PGSZ   PPC44x_TLB_64K
+#define VCPU_SIZE_BYTES (1<<VCPU_SIZE_LOG)
+
+#define BOOKE_INTERRUPT_CRITICAL 0
+#define BOOKE_INTERRUPT_MACHINE_CHECK 1
+#define BOOKE_INTERRUPT_DATA_STORAGE 2
+#define BOOKE_INTERRUPT_INST_STORAGE 3
+#define BOOKE_INTERRUPT_EXTERNAL 4
+#define BOOKE_INTERRUPT_ALIGNMENT 5
+#define BOOKE_INTERRUPT_PROGRAM 6
+#define BOOKE_INTERRUPT_FP_UNAVAIL 7
+#define BOOKE_INTERRUPT_SYSCALL 8
+#define BOOKE_INTERRUPT_AP_UNAVAIL 9
+#define BOOKE_INTERRUPT_DECREMENTER 10
+#define BOOKE_INTERRUPT_FIT 11
+#define BOOKE_INTERRUPT_WATCHDOG 12
+#define BOOKE_INTERRUPT_DTLB_MISS 13
+#define BOOKE_INTERRUPT_ITLB_MISS 14
+#define BOOKE_INTERRUPT_DEBUG 15
+#define BOOKE_MAX_INTERRUPT 15
+
+#define RESUME_FLAG_NV          (1<<0)  /* Reload guest nonvolatile state? */
+#define RESUME_FLAG_HOST        (1<<1)  /* Resume host? */
+
+#define RESUME_GUEST            0
+#define RESUME_GUEST_NV         RESUME_FLAG_NV
+#define RESUME_HOST             RESUME_FLAG_HOST
+#define RESUME_HOST_NV          (RESUME_FLAG_HOST|RESUME_FLAG_NV)
+
+#endif /* __POWERPC_KVM_ASM_H__ */
diff --git a/include/asm-powerpc/kvm_host.h b/include/asm-powerpc/kvm_host.h
new file mode 100644
--- /dev/null
+++ b/include/asm-powerpc/kvm_host.h
@@ -0,0 +1,152 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * 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, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Copyright IBM Corp. 2007
+ *
+ * Authors: Hollis Blanchard <hollisb@us.ibm.com>
+ */
+
+#ifndef __POWERPC_KVM_HOST_H__
+#define __POWERPC_KVM_HOST_H__
+
+#include <linux/mutex.h>
+#include <linux/timer.h>
+#include <linux/types.h>
+#include <linux/kvm_types.h>
+#include <asm/kvm_asm.h>
+
+#define KVM_MAX_VCPUS 1
+#define KVM_MEMORY_SLOTS 32
+/* memory slots that does not exposed to userspace */
+#define KVM_PRIVATE_MEM_SLOTS 4
+
+/* We don't currently support large pages. */
+#define KVM_PAGES_PER_HPAGE (1<<31)
+
+struct kvm;
+struct kvm_run;
+struct kvm_vcpu;
+
+struct kvm_vm_stat {
+	u32 remote_tlb_flush;
+};
+
+struct kvm_vcpu_stat {
+	u32 sum_exits;
+	u32 mmio_exits;
+	u32 dcr_exits;
+	u32 signal_exits;
+	u32 light_exits;
+	/* Account for special types of light exits: */
+	u32 itlb_real_miss_exits;
+	u32 itlb_virt_miss_exits;
+	u32 dtlb_real_miss_exits;
+	u32 dtlb_virt_miss_exits;
+	u32 syscall_exits;
+	u32 isi_exits;
+	u32 dsi_exits;
+	u32 emulated_inst_exits;
+	u32 dec_exits;
+	u32 ext_intr_exits;
+};
+
+struct tlbe {
+	u32 tid; /* Only the low 8 bits are used. */
+	u32 word0;
+	u32 word1;
+	u32 word2;
+};
+
+struct kvm_arch {
+};
+
+struct kvm_vcpu_arch {
+	/* Unmodified copy of the guest's TLB. */
+	struct tlbe guest_tlb[PPC44x_TLB_SIZE];
+	/* TLB that's actually used when the guest is running. */
+	struct tlbe shadow_tlb[PPC44x_TLB_SIZE];
+	/* Pages which are referenced in the shadow TLB. */
+	struct page *shadow_pages[PPC44x_TLB_SIZE];
+	/* Copy of the host's TLB. */
+	struct tlbe host_tlb[PPC44x_TLB_SIZE];
+
+	u32 host_stack;
+	u32 host_pid;
+
+	u64 fpr[32];
+	u32 gpr[32];
+
+	u32 pc;
+	u32 cr;
+	u32 ctr;
+	u32 lr;
+	u32 xer;
+
+	u32 msr;
+	u32 mmucr;
+	u32 sprg0;
+	u32 sprg1;
+	u32 sprg2;
+	u32 sprg3;
+	u32 sprg4;
+	u32 sprg5;
+	u32 sprg6;
+	u32 sprg7;
+	u32 srr0;
+	u32 srr1;
+	u32 csrr0;
+	u32 csrr1;
+	u32 dsrr0;
+	u32 dsrr1;
+	u32 dear;
+	u32 esr;
+	u32 dec;
+	u32 decar;
+	u32 tbl;
+	u32 tbu;
+	u32 tcr;
+	u32 tsr;
+	u32 ivor[16];
+	u32 ivpr;
+	u32 pir;
+	u32 pid;
+	u32 pvr;
+	u32 ccr0;
+	u32 ccr1;
+	u32 dbcr0;
+	u32 dbcr1;
+
+	u32 last_inst;
+	u32 fault_dear;
+	u32 fault_esr;
+	gpa_t paddr_accessed;
+
+	u8 io_gpr; /* GPR used as IO source/target */
+	u8 mmio_is_bigendian;
+	u8 dcr_needed;
+	u8 dcr_is_write;
+
+	u32 cpr0_cfgaddr; /* holds the last set cpr0_cfgaddr */
+
+	struct timer_list dec_timer;
+	unsigned long pending_exceptions;
+};
+
+struct kvm_guest_debug {
+	int enabled;
+	unsigned long bp[4];
+	int singlestep;
+};
+
+#endif /* __POWERPC_KVM_HOST_H__ */
diff --git a/include/asm-powerpc/kvm_para.h b/include/asm-powerpc/kvm_para.h
new file mode 100644
--- /dev/null
+++ b/include/asm-powerpc/kvm_para.h
@@ -0,0 +1,38 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * 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, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Copyright IBM Corp. 2008
+ *
+ * Authors: Hollis Blanchard <hollisb@us.ibm.com>
+ */
+
+#ifndef __POWERPC_KVM_PARA_H__
+#define __POWERPC_KVM_PARA_H__
+
+#ifdef __KERNEL__
+
+static inline int kvm_para_available(void)
+{
+	return 0;
+}
+
+static inline unsigned int kvm_arch_para_features(void)
+{
+	return 0;
+}
+
+#endif /* __KERNEL__ */
+
+#endif /* __POWERPC_KVM_PARA_H__ */
+
diff --git a/include/asm-powerpc/kvm_ppc.h b/include/asm-powerpc/kvm_ppc.h
new file mode 100644
--- /dev/null
+++ b/include/asm-powerpc/kvm_ppc.h
@@ -0,0 +1,86 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * 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, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Copyright IBM Corp. 2008
+ *
+ * Authors: Hollis Blanchard <hollisb@us.ibm.com>
+ */
+
+#ifndef __POWERPC_KVM_PPC_H__
+#define __POWERPC_KVM_PPC_H__
+
+/* This file exists just so we can dereference kvm_vcpu, avoiding nested header
+ * dependencies. */
+
+#include <linux/mutex.h>
+#include <linux/timer.h>
+#include <linux/types.h>
+#include <linux/kvm_types.h>
+#include <linux/kvm_host.h>
+
+struct kvm_tlb {
+	struct tlbe guest_tlb[PPC44x_TLB_SIZE];
+	struct tlbe shadow_tlb[PPC44x_TLB_SIZE];
+};
+
+enum emulation_result {
+	EMULATE_DONE,         /* no further processing */
+	EMULATE_DO_MMIO,      /* kvm_run filled with MMIO request */
+	EMULATE_DO_DCR,       /* kvm_run filled with DCR request */
+	EMULATE_FAIL,         /* can't emulate this instruction */
+};
+
+extern const unsigned char exception_priority[];
+extern const unsigned char priority_exception[];
+
+extern int __kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu);
+extern char kvmppc_handlers_start[];
+extern unsigned long kvmppc_handler_len;
+
+extern void kvmppc_dump_vcpu(struct kvm_vcpu *vcpu);
+extern int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
+                              unsigned int rt, unsigned int bytes,
+                              int is_bigendian);
+extern int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu,
+                               u32 val, unsigned int bytes, int is_bigendian);
+
+extern int kvmppc_emulate_instruction(struct kvm_run *run,
+                                      struct kvm_vcpu *vcpu);
+
+extern void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 gvaddr, gfn_t gfn,
+                           u64 asid, u32 flags);
+extern void kvmppc_mmu_invalidate(struct kvm_vcpu *vcpu, u64 eaddr, u64 asid);
+extern void kvmppc_mmu_priv_switch(struct kvm_vcpu *vcpu, int usermode);
+
+static inline void kvmppc_queue_exception(struct kvm_vcpu *vcpu, int exception)
+{
+	unsigned int priority = exception_priority[exception];
+	set_bit(priority, &vcpu->arch.pending_exceptions);
+}
+
+static inline void kvmppc_clear_exception(struct kvm_vcpu *vcpu, int exception)
+{
+	unsigned int priority = exception_priority[exception];
+	clear_bit(priority, &vcpu->arch.pending_exceptions);
+}
+
+static inline void kvmppc_set_msr(struct kvm_vcpu *vcpu, u32 new_msr)
+{
+	if ((new_msr & MSR_PR) != (vcpu->arch.msr & MSR_PR))
+		kvmppc_mmu_priv_switch(vcpu, new_msr & MSR_PR);
+
+	vcpu->arch.msr = new_msr;
+}
+
+#endif /* __POWERPC_KVM_PPC_H__ */

^ permalink raw reply

* Re: [PATCH] siimage: fix kernel oops on PPC 44x
From: Bartlomiej Zolnierkiewicz @ 2008-04-07 21:29 UTC (permalink / raw)
  To: Sergei Shtylyov; +Cc: linux-ide, linuxppc-dev
In-Reply-To: <200804080005.03683.sshtylyov@ru.mvista.com>

On Monday 07 April 2008, Sergei Shtylyov wrote:
> Fix kernel oops due to machine check occuring in init_chipset_siimage() on PPC
> 44x platforms.  These 32-bit CPUs have 36-bit physical address and PCI I/O and
> memory spaces are mapped beyond 4 GB; arch/ppc/ code has a fixup in ioremap()
> that creates an illusion of the PCI I/O and memory resources being mapped below
> 4 GB, while arch/powerpc/ code got rid of this fixup with PPC 44x having instead
> CONFIG_RESOURCES_64BIT=y -- this causes the resources to be truncated to 32-bit
> 'unsigned long' type in this driver, and so non-existant memory being ioremap'ed
> and then accessed...
> 
> Thanks to Valentine Barshak for providing an initial patch and explanations.
> 
> Signed-off-by: Sergei Shtylyov <sshtylyov@ru.mvista.com>

applied and pushed to Linus, thanks!

I guess that it would be worth to audit the rest of IDE code for
pci_resource_{start,end}() vs 'unsigned long' occurences and fix them.

[ Even if they work at the moment they are just bugs waiting to happened
  when we add support for some new platforms or rewrite the code... ]

^ permalink raw reply

* Re: [RFC][PATCH] initial port of fixmap over from x86 for ppc32
From: Kumar Gala @ 2008-04-07 21:36 UTC (permalink / raw)
  To: Scott Wood; +Cc: linuxppc-dev, Paul Mackerras, hollisb
In-Reply-To: <20080407162053.GB2688@loki.buserror.net>


On Apr 7, 2008, at 11:20 AM, Scott Wood wrote:
> On Mon, Apr 07, 2008 at 08:09:57AM -0500, Kumar Gala wrote:
>> On Apr 6, 2008, at 6:48 PM, Paul Mackerras wrote:
>>> More generally, I think we need to take an overall look at what  
>>> things
>>> we are using fixed virtual addresses for, and why they need to be
>>> fixed.  If there are indeed several such things then we can  
>>> introduce
>>> the fixmap stuff.
>>
>> The list as I see it:
>> * kmap
>> * pci-e config for 4xx/83xx
>> * kexec/kdump (ben commented on this when Dale posted his patches for
>> ppc32 support)
>>
>> future:
>> * possible usage by HV
>>
>> since we already have three users and a possible fourth it seems  
>> like a
>> useful change.
>
> Another possible use is a BAT/TLB1 mapping for SoC registers (or  
> anything
> else on the board which is frequently accessed), which can be reused  
> by
> ioremap() to avoid wasting normal TLB entries, and to facilitate early
> debugging.

x86 has an early ioremap() that is implemented on top of their fixmap  
usage that we could also steal if desired :)

- k

^ permalink raw reply

* Re: 4xx defconfig reorg
From: Kumar Gala @ 2008-04-07 21:36 UTC (permalink / raw)
  To: jwboyer; +Cc: linuxppc-dev, paulus
In-Reply-To: <1207487181.6809.18.camel@vader.jdub.homelinux.org>


On Apr 6, 2008, at 8:06 AM, Josh Boyer wrote:
> Hi All,
>
> Unless someone screams loudly and has reasons why this shouldn't go  
> in,
> the following commit should hit the 4xx next branch in the next day or
> so.
>
> josh

If this is acceptable to people, I'll make similar defconfig movements  
for the Freescale parts.

- k

> commit eaf997b847be3c351eb9d0107e0562035dc58095
> Author: Josh Boyer <jwboyer@linux.vnet.ibm.com>
> Date:   Sun Apr 6 08:01:21 2008 -0500
>
>   [POWERPC] 4xx: Reorganize 4xx defconfigs
>
>   Board specific defconfigs are useful, however with the ability to do
>   multi-board defconfigs they aren't needed in the top level configs  
> directory
>
>   Move the 4xx board specific defconfigs to individual directories  
> under
>   arch/powerpc/configs.
>
>   Signed-off-by: Josh Boyer <jwboyer@linux.vnet.ibm.com>
>
> arch/powerpc/configs/{ => 40x}/ep405_defconfig     |    0
> arch/powerpc/configs/{ => 40x}/kilauea_defconfig   |    0
> arch/powerpc/configs/{ => 40x}/makalu_defconfig    |    0
> arch/powerpc/configs/{ => 40x}/walnut_defconfig    |    0
> arch/powerpc/configs/{ => 44x}/bamboo_defconfig    |    0
> .../configs/{ => 44x}/canyonlands_defconfig        |    0
> arch/powerpc/configs/{ => 44x}/ebony_defconfig     |    0
> arch/powerpc/configs/{ => 44x}/katmai_defconfig    |    0
> arch/powerpc/configs/{ => 44x}/rainier_defconfig   |    0
> arch/powerpc/configs/{ => 44x}/sequoia_defconfig   |    0
> arch/powerpc/configs/{ => 44x}/taishan_defconfig   |    0
> arch/powerpc/configs/{ => 44x}/warp_defconfig      |    0
> 12 files changed, 0 insertions(+), 0 deletions(-)
>
>
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-dev

^ permalink raw reply

* Re: [PATCH 1/9 v2] powerpc: change FDT compatible prefix to mrvl
From: Dale Farnsworth @ 2008-04-07 21:53 UTC (permalink / raw)
  To: Segher Boessenkool; +Cc: linuxppc-dev, paulus
In-Reply-To: <7b4fa46820f05cd088680ed3eb521ad6@kernel.crashing.org>

On Mon, Apr 07, 2008 at 10:49:40PM +0200, Segher Boessenkool wrote:
>> Follow the convention that compatible names are prefixed by the
>> vendor's stock ticker symbol.  For Marvell Technology Group Ltd.,
>> that's MRVL.
>
>> -		compatible = "marvell,mv64x60";
>> +		compatible = "mrvl,mv64x60";
>
> NAK.
>
> Either use the stock ticker, in UPPER CASE, or use a nice
> descriptive name.  The lower case space is "free for all",
> using shortened names (like "mrvl") there only increases
> the chances of collisions.

[Oops, I forgot to copy the list on my reply to Segher.
Segher, sorry for the repeat.]

Frankly Segher, it doesn't matter to me.  However, NONE of the
existing DTS files use upper-case stock ticker.  I see no reason
to deviate from the existing convention (even if that convention
doesn't follow the previous convention of using upper-case).

Since it seems that the convention for compatible property
prefixes hasn't been decided yet, maybe it would be best for
me to back out this patch and redo those that follow.

I'll do that and repost the series.

-Dale

^ permalink raw reply

* [PATCH 0/8 v3] [POWERPC] mv64x60 and prpmc2800 DTS cleanups
From: Dale Farnsworth @ 2008-04-07 22:00 UTC (permalink / raw)
  To: paulus; +Cc: linuxppc-dev

This series of patches again attempts to clean up and document
the Marvell MV64x60 device tree.  It supersedes Mark Greer's
series posted on 11 December 2007.  See:
http://ozlabs.org/pipermail/linuxppc-dev/2007-December/047986.html

These apply on the powerpc-next branch, and I'd like to get them
into 2.6.26.

This series differs from v2 in that the compatible property
prefix string has been left unchanged as "marvell".

Thanks,
-Dale

^ permalink raw reply

* [PATCH 1/8 v3] [POWERPC] prpmc2800: convert DTS to v1 and add labels
From: Dale Farnsworth @ 2008-04-07 22:07 UTC (permalink / raw)
  To: paulus; +Cc: linuxppc-dev
In-Reply-To: <20080407220027.GA24510@farnsworth.org>

From: Mark A. Greer <mgreer@mvista.com>

Update the prpmc2800 DTS file to version 1 and add labels.
I verified that there was no change in the resulting dtb file.

Signed-off-by: Mark A. Greer <mgreer@mvista.com>
Signed-off-by: Dale Farnsworth <dale@farnsworth.org>

---
 arch/powerpc/boot/dts/prpmc2800.dts |  264 +++++++++++++-------------
 1 file changed, 134 insertions(+), 130 deletions(-)

Index: linux-2.6/arch/powerpc/boot/dts/prpmc2800.dts
===================================================================
--- linux-2.6.orig/arch/powerpc/boot/dts/prpmc2800.dts
+++ linux-2.6/arch/powerpc/boot/dts/prpmc2800.dts
@@ -11,6 +11,8 @@
  * if it can determine the exact PrPMC type.
  */
 
+/dts-v1/;
+
 / {
 	#address-cells = <1>;
 	#size-cells = <1>;
@@ -25,19 +27,19 @@
 		PowerPC,7447 {
 			device_type = "cpu";
 			reg = <0>;
-			clock-frequency = <2bb0b140>;	/* Default (733 MHz) */
-			bus-frequency = <7f28155>;	/* 133.333333 MHz */
-			timebase-frequency = <1fca055>;	/* 33.333333 MHz */
-			i-cache-line-size = <20>;
-			d-cache-line-size = <20>;
-			i-cache-size = <8000>;
-			d-cache-size = <8000>;
+			clock-frequency = <733000000>;	/* Default */
+			bus-frequency = <133333333>;
+			timebase-frequency = <33333333>;
+			i-cache-line-size = <32>;
+			d-cache-line-size = <32>;
+			i-cache-size = <32768>;
+			d-cache-size = <32768>;
 		};
 	};
 
 	memory {
 		device_type = "memory";
-		reg = <00000000 20000000>;	/* Default (512MB) */
+		reg = <0x0 0x20000000>;			/* Default (512MB) */
 	};
 
 	mv64x60@f1000000 { /* Marvell Discovery */
@@ -45,26 +47,26 @@
 		#size-cells = <1>;
 		model = "mv64360";			/* Default */
 		compatible = "marvell,mv64x60";
-		clock-frequency = <7f28155>;		/* 133.333333 MHz */
-		reg = <f1000000 00010000>;
-		virtual-reg = <f1000000>;
-		ranges = <88000000 88000000 01000000	/* PCI 0 I/O Space */
-			  80000000 80000000 08000000	/* PCI 0 MEM Space */
-			  a0000000 a0000000 04000000	/* User FLASH */
-			  00000000 f1000000 00010000	/* Bridge's regs */
-			  f2000000 f2000000 00040000>;	/* Integrated SRAM */
+		clock-frequency = <133333333>;
+		reg = <0xf1000000 0x10000>;
+		virtual-reg = <0xf1000000>;
+		ranges = <0x88000000 0x88000000 0x1000000 /* PCI 0 I/O Space */
+			  0x80000000 0x80000000 0x8000000 /* PCI 0 MEM Space */
+			  0xa0000000 0xa0000000 0x4000000 /* User FLASH */
+			  0x00000000 0xf1000000 0x0010000 /* Bridge's regs */
+			  0xf2000000 0xf2000000 0x0040000>;/* Integrated SRAM */
 
 		flash@a0000000 {
 			device_type = "rom";
 			compatible = "direct-mapped";
-			reg = <a0000000 4000000>; /* Default (64MB) */
+			reg = <0xa0000000 0x4000000>; /* Default (64MB) */
 			probe-type = "CFI";
 			bank-width = <4>;
-			partitions = <00000000 00100000 /* RO */
-				      00100000 00040001 /* RW */
-				      00140000 00400000 /* RO */
-				      00540000 039c0000 /* RO */
-				      03f00000 00100000>; /* RO */
+			partitions = <0x00000000 0x00100000 /* RO */
+				      0x00100000 0x00040001 /* RW */
+				      0x00140000 0x00400000 /* RO */
+				      0x00540000 0x039c0000 /* RO */
+				      0x03f00000 0x00100000>; /* RO */
 			partition-names = "FW Image A", "FW Config Data", "Kernel Image", "Filesystem", "FW Image B";
 		};
 
@@ -73,170 +75,170 @@
 			#size-cells = <0>;
 			device_type = "mdio";
 			compatible = "marvell,mv64x60-mdio";
-			ethernet-phy@1 {
+			PHY0: ethernet-phy@1 {
 				device_type = "ethernet-phy";
 				compatible = "broadcom,bcm5421";
-				interrupts = <4c>;	/* GPP 12 */
-				interrupt-parent = <&/mv64x60/pic>;
+				interrupts = <76>;	/* GPP 12 */
+				interrupt-parent = <&PIC>;
 				reg = <1>;
 			};
-			ethernet-phy@3 {
+			PHY1: ethernet-phy@3 {
 				device_type = "ethernet-phy";
 				compatible = "broadcom,bcm5421";
-				interrupts = <4c>;	/* GPP 12 */
-				interrupt-parent = <&/mv64x60/pic>;
+				interrupts = <76>;	/* GPP 12 */
+				interrupt-parent = <&PIC>;
 				reg = <3>;
 			};
 		};
 
 		ethernet@2000 {
-			reg = <2000 2000>;
+			reg = <0x2000 0x2000>;
 			eth0 {
 				device_type = "network";
 				compatible = "marvell,mv64x60-eth";
 				block-index = <0>;
-				interrupts = <20>;
-				interrupt-parent = <&/mv64x60/pic>;
-				phy = <&/mv64x60/mdio/ethernet-phy@1>;
+				interrupts = <32>;
+				interrupt-parent = <&PIC>;
+				phy = <&PHY0>;
 				local-mac-address = [ 00 00 00 00 00 00 ];
 			};
 			eth1 {
 				device_type = "network";
 				compatible = "marvell,mv64x60-eth";
 				block-index = <1>;
-				interrupts = <21>;
-				interrupt-parent = <&/mv64x60/pic>;
-				phy = <&/mv64x60/mdio/ethernet-phy@3>;
+				interrupts = <33>;
+				interrupt-parent = <&PIC>;
+				phy = <&PHY1>;
 				local-mac-address = [ 00 00 00 00 00 00 ];
 			};
 		};
 
-		sdma@4000 {
+		SDMA0: sdma@4000 {
 			device_type = "dma";
 			compatible = "marvell,mv64x60-sdma";
-			reg = <4000 c18>;
-			virtual-reg = <f1004000>;
+			reg = <0x4000 0xc18>;
+			virtual-reg = <0xf1004000>;
 			interrupt-base = <0>;
-			interrupts = <24>;
-			interrupt-parent = <&/mv64x60/pic>;
+			interrupts = <36>;
+			interrupt-parent = <&PIC>;
 		};
 
-		sdma@6000 {
+		SDMA1: sdma@6000 {
 			device_type = "dma";
 			compatible = "marvell,mv64x60-sdma";
-			reg = <6000 c18>;
-			virtual-reg = <f1006000>;
+			reg = <0x6000 0xc18>;
+			virtual-reg = <0xf1006000>;
 			interrupt-base = <0>;
-			interrupts = <26>;
-			interrupt-parent = <&/mv64x60/pic>;
+			interrupts = <38>;
+			interrupt-parent = <&PIC>;
 		};
 
-		brg@b200 {
+		BRG0: brg@b200 {
 			compatible = "marvell,mv64x60-brg";
-			reg = <b200 8>;
+			reg = <0xb200 0x8>;
 			clock-src = <8>;
-			clock-frequency = <7ed6b40>;
-			current-speed = <2580>;
+			clock-frequency = <133000000>;
+			current-speed = <9600>;
 			bcr = <0>;
 		};
 
-		brg@b208 {
+		BRG1: brg@b208 {
 			compatible = "marvell,mv64x60-brg";
-			reg = <b208 8>;
+			reg = <0xb208 0x8>;
 			clock-src = <8>;
-			clock-frequency = <7ed6b40>;
-			current-speed = <2580>;
+			clock-frequency = <133000000>;
+			current-speed = <9600>;
 			bcr = <0>;
 		};
 
-		cunit@f200 {
-			reg = <f200 200>;
+		CUNIT: cunit@f200 {
+			reg = <0xf200 0x200>;
 		};
 
-		mpscrouting@b400 {
-			reg = <b400 c>;
+		MPSCROUTING: mpscrouting@b400 {
+			reg = <0xb400 0xc>;
 		};
 
-		mpscintr@b800 {
-			reg = <b800 100>;
-			virtual-reg = <f100b800>;
+		MPSCINTR: mpscintr@b800 {
+			reg = <0xb800 0x100>;
+			virtual-reg = <0xf100b800>;
 		};
 
-		mpsc@8000 {
+		MPSC0: mpsc@8000 {
 			device_type = "serial";
 			compatible = "marvell,mpsc";
-			reg = <8000 38>;
-			virtual-reg = <f1008000>;
-			sdma = <&/mv64x60/sdma@4000>;
-			brg = <&/mv64x60/brg@b200>;
-			cunit = <&/mv64x60/cunit@f200>;
-			mpscrouting = <&/mv64x60/mpscrouting@b400>;
-			mpscintr = <&/mv64x60/mpscintr@b800>;
+			reg = <0x8000 0x38>;
+			virtual-reg = <0xf1008000>;
+			sdma = <&SDMA0>;
+			brg = <&BRG0>;
+			cunit = <&CUNIT>;
+			mpscrouting = <&MPSCROUTING>;
+			mpscintr = <&MPSCINTR>;
 			block-index = <0>;
-			max_idle = <28>;
+			max_idle = <40>;
 			chr_1 = <0>;
 			chr_2 = <0>;
 			chr_10 = <3>;
 			mpcr = <0>;
-			interrupts = <28>;
-			interrupt-parent = <&/mv64x60/pic>;
+			interrupts = <40>;
+			interrupt-parent = <&PIC>;
 		};
 
-		mpsc@9000 {
+		MPSC1: mpsc@9000 {
 			device_type = "serial";
 			compatible = "marvell,mpsc";
-			reg = <9000 38>;
-			virtual-reg = <f1009000>;
-			sdma = <&/mv64x60/sdma@6000>;
-			brg = <&/mv64x60/brg@b208>;
-			cunit = <&/mv64x60/cunit@f200>;
-			mpscrouting = <&/mv64x60/mpscrouting@b400>;
-			mpscintr = <&/mv64x60/mpscintr@b800>;
+			reg = <0x9000 0x38>;
+			virtual-reg = <0xf1009000>;
+			sdma = <&SDMA1>;
+			brg = <&BRG1>;
+			cunit = <&CUNIT>;
+			mpscrouting = <&MPSCROUTING>;
+			mpscintr = <&MPSCINTR>;
 			block-index = <1>;
-			max_idle = <28>;
+			max_idle = <40>;
 			chr_1 = <0>;
 			chr_2 = <0>;
 			chr_10 = <3>;
 			mpcr = <0>;
-			interrupts = <2a>;
-			interrupt-parent = <&/mv64x60/pic>;
+			interrupts = <42>;
+			interrupt-parent = <&PIC>;
 		};
 
 		wdt@b410 {			/* watchdog timer */
 			compatible = "marvell,mv64x60-wdt";
-			reg = <b410 8>;
-			timeout = <a>;		/* wdt timeout in seconds */
+			reg = <0xb410 0x8>;
+			timeout = <10>;		/* wdt timeout in seconds */
 		};
 
 		i2c@c000 {
 			device_type = "i2c";
 			compatible = "marvell,mv64x60-i2c";
-			reg = <c000 20>;
-			virtual-reg = <f100c000>;
+			reg = <0xc000 0x20>;
+			virtual-reg = <0xf100c000>;
 			freq_m = <8>;
 			freq_n = <3>;
-			timeout = <3e8>;		/* 1000 = 1 second */
+			timeout = <1000>;		/* 1000 = 1 second */
 			retries = <1>;
-			interrupts = <25>;
-			interrupt-parent = <&/mv64x60/pic>;
+			interrupts = <37>;
+			interrupt-parent = <&PIC>;
 		};
 
-		pic {
+		PIC: pic {
 			#interrupt-cells = <1>;
 			#address-cells = <0>;
 			compatible = "marvell,mv64x60-pic";
-			reg = <0000 88>;
+			reg = <0x0 0x88>;
 			interrupt-controller;
 		};
 
 		mpp@f000 {
 			compatible = "marvell,mv64x60-mpp";
-			reg = <f000 10>;
+			reg = <0xf000 0x10>;
 		};
 
 		gpp@f100 {
 			compatible = "marvell,mv64x60-gpp";
-			reg = <f100 20>;
+			reg = <0xf100 0x20>;
 		};
 
 		pci@80000000 {
@@ -245,72 +247,74 @@
 			#interrupt-cells = <1>;
 			device_type = "pci";
 			compatible = "marvell,mv64x60-pci";
-			reg = <0cf8 8>;
-			ranges = <01000000 0        0 88000000 0 01000000
-				  02000000 0 80000000 80000000 0 08000000>;
-			bus-range = <0 ff>;
-			clock-frequency = <3EF1480>;
-			interrupt-pci-iack = <0c34>;
-			interrupt-parent = <&/mv64x60/pic>;
-			interrupt-map-mask = <f800 0 0 7>;
+			reg = <0xcf8 0x8>;
+			ranges = <0x01000000 0x0        0x0
+					0x88000000 0x0 0x01000000
+				  0x02000000 0x0 0x80000000
+				  	0x80000000 0x0 0x08000000>;
+			bus-range = <0 255>;
+			clock-frequency = <66000000>;
+			interrupt-pci-iack = <0xc34>;
+			interrupt-parent = <&PIC>;
+			interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
 			interrupt-map = <
 				/* IDSEL 0x0a */
-				5000 0 0 1 &/mv64x60/pic 50
-				5000 0 0 2 &/mv64x60/pic 51
-				5000 0 0 3 &/mv64x60/pic 5b
-				5000 0 0 4 &/mv64x60/pic 5d
+				0x5000 0 0 1 &PIC 80
+				0x5000 0 0 2 &PIC 81
+				0x5000 0 0 3 &PIC 91
+				0x5000 0 0 4 &PIC 93
 
 				/* IDSEL 0x0b */
-				5800 0 0 1 &/mv64x60/pic 5b
-				5800 0 0 2 &/mv64x60/pic 5d
-				5800 0 0 3 &/mv64x60/pic 50
-				5800 0 0 4 &/mv64x60/pic 51
+				0x5800 0 0 1 &PIC 91
+				0x5800 0 0 2 &PIC 93
+				0x5800 0 0 3 &PIC 80
+				0x5800 0 0 4 &PIC 81
 
 				/* IDSEL 0x0c */
-				6000 0 0 1 &/mv64x60/pic 5b
-				6000 0 0 2 &/mv64x60/pic 5d
-				6000 0 0 3 &/mv64x60/pic 50
-				6000 0 0 4 &/mv64x60/pic 51
+				0x6000 0 0 1 &PIC 91
+				0x6000 0 0 2 &PIC 93
+				0x6000 0 0 3 &PIC 80
+				0x6000 0 0 4 &PIC 81
 
 				/* IDSEL 0x0d */
-				6800 0 0 1 &/mv64x60/pic 5d
-				6800 0 0 2 &/mv64x60/pic 50
-				6800 0 0 3 &/mv64x60/pic 51
-				6800 0 0 4 &/mv64x60/pic 5b
+				0x6800 0 0 1 &PIC 93
+				0x6800 0 0 2 &PIC 80
+				0x6800 0 0 3 &PIC 81
+				0x6800 0 0 4 &PIC 91
 			>;
 		};
 
 		cpu-error@0070 {
 			compatible = "marvell,mv64x60-cpu-error";
-			reg = <0070 10 0128 28>;
-			interrupts = <03>;
-			interrupt-parent = <&/mv64x60/pic>;
+			reg = <0x70 0x10 0x128 0x28>;
+			interrupts = <3>;
+			interrupt-parent = <&PIC>;
 		};
 
 		sram-ctrl@0380 {
 			compatible = "marvell,mv64x60-sram-ctrl";
-			reg = <0380 80>;
-			interrupts = <0d>;
-			interrupt-parent = <&/mv64x60/pic>;
+			reg = <0x380 0x80>;
+			interrupts = <13>;
+			interrupt-parent = <&PIC>;
 		};
 
 		pci-error@1d40 {
 			compatible = "marvell,mv64x60-pci-error";
-			reg = <1d40 40 0c28 4>;
-			interrupts = <0c>;
-			interrupt-parent = <&/mv64x60/pic>;
+			reg = <0x1d40 0x40 0xc28 0x4>;
+			interrupts = <12>;
+			interrupt-parent = <&PIC>;
 		};
 
 		mem-ctrl@1400 {
 			compatible = "marvell,mv64x60-mem-ctrl";
-			reg = <1400 60>;
-			interrupts = <11>;
-			interrupt-parent = <&/mv64x60/pic>;
+			reg = <0x1400 0x60>;
+			interrupts = <17>;
+			interrupt-parent = <&PIC>;
 		};
 	};
 
 	chosen {
 		bootargs = "ip=on";
-		linux,stdout-path = "/mv64x60@f1000000/mpsc@8000";
+		linux,stdout-path = &MPSC0;
 	};
 };

^ permalink raw reply

* [PATCH 2/8 v3] [POWERPC] prpmc2800: fix frequencies in prpmc2800.dts
From: Dale Farnsworth @ 2008-04-07 22:08 UTC (permalink / raw)
  To: paulus; +Cc: linuxppc-dev
In-Reply-To: <20080407220027.GA24510@farnsworth.org>

From: Dale Farnsworth <dale@farnsworth.org>

After the conversion to dts v1 format, seeing the frequencies
in decimal made it obvious that some of them had been
incorrectly truncated.  This fixes them.  Note that the PCI
frequency comes from a different source and is documented
as 66MHz, so it was left at 66000000.

Signed-off-by: Dale Farnsworth <dale@farnsworth.org>
Acked-by: Mark A. Greer <mgreer@mvista.com>

---
 arch/powerpc/boot/dts/prpmc2800.dts |    6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

Index: linux-2.6/arch/powerpc/boot/dts/prpmc2800.dts
===================================================================
--- linux-2.6.orig/arch/powerpc/boot/dts/prpmc2800.dts
+++ linux-2.6/arch/powerpc/boot/dts/prpmc2800.dts
@@ -27,7 +27,7 @@
 		PowerPC,7447 {
 			device_type = "cpu";
 			reg = <0>;
-			clock-frequency = <733000000>;	/* Default */
+			clock-frequency = <733333333>;	/* Default */
 			bus-frequency = <133333333>;
 			timebase-frequency = <33333333>;
 			i-cache-line-size = <32>;
@@ -137,7 +137,7 @@
 			compatible = "marvell,mv64x60-brg";
 			reg = <0xb200 0x8>;
 			clock-src = <8>;
-			clock-frequency = <133000000>;
+			clock-frequency = <133333333>;
 			current-speed = <9600>;
 			bcr = <0>;
 		};
@@ -146,7 +146,7 @@
 			compatible = "marvell,mv64x60-brg";
 			reg = <0xb208 0x8>;
 			clock-src = <8>;
-			clock-frequency = <133000000>;
+			clock-frequency = <133333333>;
 			current-speed = <9600>;
 			bcr = <0>;
 		};

^ 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