LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3] NTP: Add a CONFIG_RTC_SYSTOHC configuration
From: Jason Gunthorpe @ 2012-12-17 21:30 UTC (permalink / raw)
  To: John Stultz
  Cc: Alessandro Zummo, rtc-linux, linux-kernel, Thomas Gleixner,
	linuxppc-dev, linux-arm-kernel
In-Reply-To: <50CBB917.7090502@linaro.org>

The purpose of this option is to allow ARM/etc systems that rely on the
class RTC subsystem to have the same kind of automatic NTP based
synchronization that we have on PC platforms. Today ARM does not
implement update_persistent_clock and makes extensive use of the class
RTC system.

When enabled CONFIG_RTC_SYSTOHC will provide a generic
rtc_update_persistent_clock that stores the current time in the RTC and
is intended complement the existing CONFIG_RTC_HCTOSYS option that loads
the RTC at boot.

Like with RTC_HCTOSYS the platform's update_persistent_clock is used
first, if it works. Platforms with mixed class RTC and non-RTC drivers
need to return ENODEV when class RTC should be used. Such an update for
PPC is included in this patch.

Long term, implementations of update_persistent_clock should migrate to
proper class RTC drivers and use CONFIG_RTC_SYSTOHC instead.

Tested on ARM kirkwood and PPC405

Signed-off-by: Jason Gunthorpe <jgunthorpe@obsidianresearch.com>
---
 arch/powerpc/kernel/time.c |    2 +-
 drivers/rtc/Kconfig        |   10 +++++++++-
 drivers/rtc/Makefile       |    1 +
 drivers/rtc/systohc.c      |   44 ++++++++++++++++++++++++++++++++++++++++++++
 include/linux/rtc.h        |    1 +
 kernel/time/ntp.c          |   16 ++++++++++++----
 6 files changed, 68 insertions(+), 6 deletions(-)
 create mode 100644 drivers/rtc/systohc.c

v3 changes:
- Test menuconfig, reorder options to look better, fix kconfig
  RTC_HCTOSYS_DEVICE to be 'or' not 'and'
- Change the function name to rtc_set_ntp_time to avoid confusing
  this api with the distinct *_persistant_clock stuff
- Fix typo in the ENODEV test to be || not &&
- Fully retest on ARM+PPC

diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index ce4cb77..bc844a8 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -667,7 +667,7 @@ int update_persistent_clock(struct timespec now)
 	struct rtc_time tm;
 
 	if (!ppc_md.set_rtc_time)
-		return 0;
+		return -ENODEV;
 
 	to_tm(now.tv_sec + 1 + timezone_offset, &tm);
 	tm.tm_year -= 1900;
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 19c03ab..b377e96 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -25,9 +25,17 @@ config RTC_HCTOSYS
 	  the value read from a specified RTC device. This is useful to avoid
 	  unnecessary fsck runs at boot time, and to network better.
 
+config RTC_SYSTOHC
+	bool "Set the RTC time based on NTP synchronization"
+	default y
+	help
+	  If you say yes here, the system time (wall clock) will be stored
+	  in the RTC specified by RTC_HCTOSYS_DEVICE approximately every 11
+	  minutes if userspace reports synchronized NTP status.
+
 config RTC_HCTOSYS_DEVICE
 	string "RTC used to set the system time"
-	depends on RTC_HCTOSYS = y
+	depends on RTC_HCTOSYS = y || RTC_SYSTOHC = y
 	default "rtc0"
 	help
 	  The RTC device that will be used to (re)initialize the system
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 56297f0..69d11f1 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -6,6 +6,7 @@ ccflags-$(CONFIG_RTC_DEBUG)	:= -DDEBUG
 
 obj-$(CONFIG_RTC_LIB)		+= rtc-lib.o
 obj-$(CONFIG_RTC_HCTOSYS)	+= hctosys.o
+obj-$(CONFIG_RTC_SYSTOHC)	+= systohc.o
 obj-$(CONFIG_RTC_CLASS)		+= rtc-core.o
 rtc-core-y			:= class.o interface.o
 
diff --git a/drivers/rtc/systohc.c b/drivers/rtc/systohc.c
new file mode 100644
index 0000000..bf3e242
--- /dev/null
+++ b/drivers/rtc/systohc.c
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ *
+ */
+#include <linux/rtc.h>
+#include <linux/time.h>
+
+/**
+ * rtc_set_ntp_time - Save NTP synchronized time to the RTC
+ * @now: Current time of day
+ *
+ * Replacement for the NTP platform function update_persistent_clock
+ * that stores time for later retrieval by rtc_hctosys.
+ *
+ * Returns 0 on successful RTC update, -ENODEV if a RTC update is not
+ * possible at all, and various other -errno for specific temporary failure
+ * cases.
+ *
+ * If temporary failure is indicated the caller should try again 'soon'
+ */
+int rtc_set_ntp_time(struct timespec now)
+{
+	struct rtc_device *rtc;
+	struct rtc_time tm;
+	int err = -ENODEV;
+
+	if (now.tv_nsec < (NSEC_PER_SEC >> 1))
+		rtc_time_to_tm(now.tv_sec, &tm);
+	else
+		rtc_time_to_tm(now.tv_sec + 1, &tm);
+
+	rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
+	if (rtc) {
+		/* rtc_hctosys exclusively uses UTC, so we call set_time here,
+		 * not set_mmss. */
+		if (rtc->ops && (rtc->ops->set_time || rtc->ops->set_mmss))
+			err = rtc_set_time(rtc, &tm);
+		rtc_class_close(rtc);
+	}
+
+	return err;
+}
diff --git a/include/linux/rtc.h b/include/linux/rtc.h
index 9531845..11d05f9 100644
--- a/include/linux/rtc.h
+++ b/include/linux/rtc.h
@@ -138,6 +138,7 @@ extern void rtc_device_unregister(struct rtc_device *rtc);
 extern int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm);
 extern int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm);
 extern int rtc_set_mmss(struct rtc_device *rtc, unsigned long secs);
+extern int rtc_set_ntp_time(struct timespec now);
 int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm);
 extern int rtc_read_alarm(struct rtc_device *rtc,
 			struct rtc_wkalrm *alrm);
diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c
index 24174b4..313b161 100644
--- a/kernel/time/ntp.c
+++ b/kernel/time/ntp.c
@@ -15,6 +15,7 @@
 #include <linux/time.h>
 #include <linux/mm.h>
 #include <linux/module.h>
+#include <linux/rtc.h>
 
 #include "tick-internal.h"
 
@@ -483,8 +484,7 @@ out:
 	return leap;
 }
 
-#ifdef CONFIG_GENERIC_CMOS_UPDATE
-
+#if defined(CONFIG_GENERIC_CMOS_UPDATE) || defined(CONFIG_RTC_SYSTOHC)
 static void sync_cmos_clock(struct work_struct *work);
 
 static DECLARE_DELAYED_WORK(sync_cmos_work, sync_cmos_clock);
@@ -510,14 +510,22 @@ static void sync_cmos_clock(struct work_struct *work)
 	}
 
 	getnstimeofday(&now);
-	if (abs(now.tv_nsec - (NSEC_PER_SEC / 2)) <= tick_nsec / 2)
+	if (abs(now.tv_nsec - (NSEC_PER_SEC / 2)) <= tick_nsec / 2) {
+		fail = -ENODEV;
+#ifdef CONFIG_GENERIC_CMOS_UPDATE
 		fail = update_persistent_clock(now);
+#endif
+#ifdef CONFIG_RTC_SYSTOHC
+		if (fail == -ENODEV)
+			fail = rtc_set_ntp_time(now);
+#endif
+	}
 
 	next.tv_nsec = (NSEC_PER_SEC / 2) - now.tv_nsec - (TICK_NSEC / 2);
 	if (next.tv_nsec <= 0)
 		next.tv_nsec += NSEC_PER_SEC;
 
-	if (!fail)
+	if (!fail || fail == -ENODEV)
 		next.tv_sec = 659;
 	else
 		next.tv_sec = 0;
-- 
1.7.5.4

^ permalink raw reply related

* Re: linux-next: build warning after merge of the final tree
From: Andrew Morton @ 2012-12-17 20:59 UTC (permalink / raw)
  To: Stephen Rothwell
  Cc: Paul Thompson, linux-kernel, linux-next, Paul Mackerras,
	linuxppc-dev
In-Reply-To: <20121217143415.252a2f60076d1ba03807df55@canb.auug.org.au>

On Mon, 17 Dec 2012 14:34:15 +1100
Stephen Rothwell <sfr@canb.auug.org.au> wrote:

> Hi all,
> 
> On Mon, 17 Dec 2012 14:22:38 +1100 Stephen Rothwell <sfr@canb.auug.org.au> wrote:
> >
> > After merging the final tree, today's linux-next build (powerpc allnoconfig)
> > produced this warning:
> > 
> > warning: (PPC) selects SPARSE_IRQ which has unmet direct dependencies (HAVE_GENERIC_HARDIRQS && (IRQ_DOMAIN && DEBUG_FS || MAY_HAVE_SPARSE_IRQ))
> > 
> > I don't know what introduced that.
> 
> Actually probably caused by commit a1eaa3bc8247 ("Kconfig: fix Irq
> Subsystem menu") from the akpm tree.

kconfig-fix-irq-subsystem-menu.patch was causing various problems so I
have dropped it.

^ permalink raw reply

* [PATCH] PPC: Add support for CTS-1000 GPIO controlled system poweroff
From: Ben Collins @ 2012-12-17 14:19 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Vihar Rai, Jack Smith

CTS-1000 is based on P4080. GPIO 27 is used to signal the FPGA to
switch off power, and also associates IRQ 8 with front-panel button
press (which we use to call orderly_poweroff()).

The relevant device-tree looks like this:

	gpio0: gpio@130000 {
		compatible =3D "fsl,qoriq-gpio";
		reg =3D <0x130000 0x1000>;
		interrupts =3D <55 2 0 0>;
		#gpio-cells =3D <2>;
		gpio-controller;

		/* Allows powering off the system via GPIO signal. */
		gpio-halt@27 {
			compatible =3D "sgy,gpio-halt";
			gpios =3D <&gpio0 27 0>;
			interrupts =3D <8 1 0 0>;
		};
	};

Because the driver cannot match on sgy,gpio-halt (because the node is =
never
processed through of_platform), it matches on fsl,qoriq-gpio and then
checks child nodes for the matching sgy,gpio-halt. This also ensures =
that
the GPIO controller is detected prior to sgy_cts1000's probe callback,
since that node wont match via of_platform until the controller is
registered.

Also, because the GPIO handler for triggering system poweroff might =
sleep,
the IRQ uses a workqueue to call orderly_poweroff().

As a final note, this driver may be expanded for other features specific =
to
the CTS-1000.

Signed-off-by: Ben Collins <ben.c@servergy.com>
Cc: Jack Smith <jack.s@servergy.com>
Cc: Vihar Rai <vihar.r@servergy.com>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
 arch/powerpc/platforms/85xx/Kconfig       |    8 ++
 arch/powerpc/platforms/85xx/Makefile      |    1 +
 arch/powerpc/platforms/85xx/sgy_cts1000.c |  176 =
+++++++++++++++++++++++++++++
 3 files changed, 185 insertions(+)
 create mode 100644 arch/powerpc/platforms/85xx/sgy_cts1000.c

diff --git a/arch/powerpc/platforms/85xx/Kconfig =
b/arch/powerpc/platforms/85xx/Kconfig
index 02d02a0..651788c 100644
--- a/arch/powerpc/platforms/85xx/Kconfig
+++ b/arch/powerpc/platforms/85xx/Kconfig
@@ -245,6 +245,14 @@ config P4080_DS
 	help
 	  This option enables support for the P4080 DS board
=20
+config SGY_CTS1000
+	tristate "Servergy CTS-1000 support"
+	select GPIOLIB
+	select OF_GPIO
+	depends on P4080_DS
+	help
+	  Enable this to support functionality in Servergy's CTS-1000 =
systems.
+
 endif # PPC32
=20
 config P5020_DS
diff --git a/arch/powerpc/platforms/85xx/Makefile =
b/arch/powerpc/platforms/85xx/Makefile
index 76f679c..9db31dc 100644
--- a/arch/powerpc/platforms/85xx/Makefile
+++ b/arch/powerpc/platforms/85xx/Makefile
@@ -30,3 +30,4 @@ obj-$(CONFIG_KSI8560)	  +=3D ksi8560.o
 obj-$(CONFIG_XES_MPC85xx) +=3D xes_mpc85xx.o
 obj-$(CONFIG_GE_IMP3A)	  +=3D ge_imp3a.o
 obj-$(CONFIG_PPC_QEMU_E500) +=3D qemu_e500.o
+obj-$(CONFIG_SGY_CTS1000) +=3D sgy_cts1000.o
diff --git a/arch/powerpc/platforms/85xx/sgy_cts1000.c =
b/arch/powerpc/platforms/85xx/sgy_cts1000.c
new file mode 100644
index 0000000..611e92f
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/sgy_cts1000.c
@@ -0,0 +1,176 @@
+/*
+ * Servergy CTS-1000 Setup
+ *
+ * Maintained by Ben Collins <ben.c@servergy.com>
+ *
+ * Copyright 2012 by Servergy, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or =
modify it
+ * under  the terms of  the GNU General  Public License as published by =
the
+ * Free Software Foundation;  either version 2 of the  License, or (at =
your
+ * option) any later version.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/of_gpio.h>
+#include <linux/workqueue.h>
+#include <linux/reboot.h>
+#include <linux/interrupt.h>
+
+#include <asm/machdep.h>
+
+static struct device_node *halt_node;
+
+static struct of_device_id child_match[] =3D {
+	{
+		.compatible =3D "sgy,gpio-halt",
+	},
+	{},
+};
+
+static void gpio_halt_wfn(struct work_struct *work)
+{
+	/* Likely wont return */
+	orderly_poweroff(true);
+}
+static DECLARE_WORK(gpio_halt_wq, gpio_halt_wfn);
+
+static void gpio_halt_cb(void)
+{
+	enum of_gpio_flags flags;
+	int trigger, gpio;
+
+	if (!halt_node)
+		return;
+
+	gpio =3D of_get_gpio_flags(halt_node, 0, &flags);
+
+	if (!gpio_is_valid(gpio))
+		return;
+
+	trigger =3D (flags =3D=3D OF_GPIO_ACTIVE_LOW);
+
+	printk(KERN_INFO "gpio-halt: triggering GPIO.\n");
+
+	/* Probably wont return */
+	gpio_set_value(gpio, trigger);
+}
+
+/* This IRQ means someone pressed the power button and it is waiting =
for us
+ * to handle the shutdown/poweroff. */
+static irqreturn_t gpio_halt_irq(int irq, void *__data)
+{
+	printk(KERN_INFO "gpio-halt: shutdown due to power button =
IRQ.\n");
+	schedule_work(&gpio_halt_wq);
+
+        return IRQ_HANDLED;
+};
+
+static int __devinit gpio_halt_probe(struct platform_device *pdev)
+{
+	enum of_gpio_flags flags;
+	struct device_node *node =3D pdev->dev.of_node;
+	int gpio, err, irq;
+	int trigger;
+
+	if (!node)
+		return -ENODEV;
+
+	/* If there's no matching child, this isn't really an error */
+	halt_node =3D of_find_matching_node(node, child_match);
+	if (!halt_node)
+		return 0;
+
+	/* Technically we could just read the first one, but punish
+	 * DT writers for invalid form. */
+	if (of_gpio_count(halt_node) !=3D 1)
+		return -EINVAL;
+
+	/* Get the gpio number relative to the dynamic base. */
+	gpio =3D of_get_gpio_flags(halt_node, 0, &flags);
+	if (!gpio_is_valid(gpio))
+		return -EINVAL;
+
+	err =3D gpio_request(gpio, "gpio-halt");
+	if (err) {
+		printk(KERN_ERR "gpio-halt: error requesting GPIO =
%d.\n",
+		       gpio);
+		halt_node =3D NULL;
+		return err;
+	}
+
+	trigger =3D (flags =3D=3D OF_GPIO_ACTIVE_LOW);
+
+	gpio_direction_output(gpio, !trigger);
+
+	/* Now get the IRQ which tells us when the power button is hit =
*/
+	irq =3D irq_of_parse_and_map(halt_node, 0);
+	err =3D request_irq(irq, gpio_halt_irq, IRQF_TRIGGER_RISING |
+			  IRQF_TRIGGER_FALLING, "gpio-halt", halt_node);
+	if (err) {
+		printk(KERN_ERR "gpio-halt: error requesting IRQ %d for =
"
+		       "GPIO %d.\n", irq, gpio);
+		gpio_free(gpio);
+		halt_node =3D NULL;
+		return err;
+	}
+
+	/* Register our halt function */
+	ppc_md.halt =3D gpio_halt_cb;
+	ppc_md.power_off =3D gpio_halt_cb;
+
+	printk(KERN_INFO "gpio-halt: registered GPIO %d (%d trigger, %d"
+	       " irq).\n", gpio, trigger, irq);
+
+	return 0;
+}
+
+static int __devexit gpio_halt_remove(struct platform_device *pdev)
+{
+	if (halt_node) {
+		int gpio =3D of_get_gpio(halt_node, 0);
+		int irq =3D irq_of_parse_and_map(halt_node, 0);
+
+		free_irq(irq, halt_node);
+
+		ppc_md.halt =3D NULL;
+		ppc_md.power_off =3D NULL;
+
+		gpio_free(gpio);
+
+		halt_node =3D NULL;
+	}
+
+	return 0;
+}
+
+static struct of_device_id gpio_halt_match[] =3D {
+	/* We match on the gpio bus itself and scan the children since =
they
+	 * wont be matched against us. We know the bus wont match until =
it
+	 * has been registered too. */
+	{
+		.compatible =3D "fsl,qoriq-gpio",
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, gpio_halt_match);
+
+static struct platform_driver gpio_halt_driver =3D {
+	.driver =3D {
+		.name		=3D "gpio-halt",
+		.owner		=3D THIS_MODULE,
+		.of_match_table =3D gpio_halt_match,
+	},
+	.probe		=3D gpio_halt_probe,
+	.remove		=3D __devexit_p(gpio_halt_remove),
+};
+
+module_platform_driver(gpio_halt_driver);
+
+MODULE_DESCRIPTION("Driver to support GPIO triggered system halt for =
Servergy CTS-1000 Systems.");
+MODULE_VERSION("1.0");
+MODULE_AUTHOR("Ben Collins <ben.c@servergy.com>");
+MODULE_LICENSE("GPL");
--=20
1.7.10.4

^ permalink raw reply related

* Re: [PATCH] powerpc: POWER7 optimised memcpy using VMX and enhanced prefetch
From: Anton Blanchard @ 2012-12-17 11:33 UTC (permalink / raw)
  To: Jimi Xenidis; +Cc: Kumar Gala, paulus, linuxppc-dev
In-Reply-To: <D5CF6D4A-8F60-4853-9F7C-EFE5133CEB33@pobox.com>


Hi Jimi,

> I know this is a little late, but shouldn't these power7 specific
> thingies be in "obj-$(CONFIG_PPC_BOOK3S_64)". The reason I ask is
> that my compiler pukes on "dcbtst" and as I deal with that I wanted
> to point this out.

I guess we could do that. It's a bit strange your assembler is
complaining about the dcbtst instructions since we wrap them with
power4:

.machine push
.machine "power4"
        dcbt    r0,r4,0b01000
        dcbt    r0,r7,0b01010
        dcbtst  r0,r9,0b01000
        dcbtst  r0,r10,0b01010
        eieio
        dcbt    r0,r8,0b01010   /* GO */
.machine pop

Anton

^ permalink raw reply

* Re: [git pull] Please pull powerpc.git next branch
From: Anatolij Gustschin @ 2012-12-17 10:15 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev list, Linux Kernel list
In-Reply-To: <1355738785.5397.17.camel@pasglop>

On Mon, 17 Dec 2012 21:06:25 +1100
Benjamin Herrenschmidt <benh@kernel.crashing.org> wrote:
...
> Last week is a bit late :-) However, I think your tree was in -next
> before that wasn't it ? In which case it's ok, I can include it tomorrow
> and ask Linus to pick it up.

yes, 5xxx tree was in -next before that.

Thanks,
Anatolij

^ permalink raw reply

* Re: [git pull] Please pull powerpc.git next branch
From: Benjamin Herrenschmidt @ 2012-12-17 10:06 UTC (permalink / raw)
  To: Anatolij Gustschin; +Cc: linuxppc-dev list, Linux Kernel list
In-Reply-To: <20121217093036.65cb7cef@wker>

On Mon, 2012-12-17 at 09:30 +0100, Anatolij Gustschin wrote:
> > Overall it's pretty quiet, or rather I've been pretty poor at
> > picking things up from patchwork and reviewing them this time
> > around and Kumar no better on the FSL side it seems...
> 
> Could you please also include some 5xxx patches for v3.8 in your pull
> request? I've submitted a pull request for them last week
> 
>   http://patchwork.ozlabs.org/patch/205138 

Last week is a bit late :-) However, I think your tree was in -next
before that wasn't it ? In which case it's ok, I can include it tomorrow
and ask Linus to pick it up.

Cheers,
Ben

^ permalink raw reply

* Re: [git pull] Please pull powerpc.git next branch
From: Anatolij Gustschin @ 2012-12-17  8:30 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev list, Linux Kernel list
In-Reply-To: <1355517897.19932.136.camel@pasglop>

Hi Ben,

On Sat, 15 Dec 2012 07:44:57 +1100
Benjamin Herrenschmidt <benh@kernel.crashing.org> wrote:
...
> Overall it's pretty quiet, or rather I've been pretty poor at
> picking things up from patchwork and reviewing them this time
> around and Kumar no better on the FSL side it seems...

Could you please also include some 5xxx patches for v3.8 in your pull
request? I've submitted a pull request for them last week

  http://patchwork.ozlabs.org/patch/205138

Thanks,
Anatolij

^ permalink raw reply

* [PATCH][RFC] mmc, sd: do not read switch, if the host do not support high speed
From: Heiko Schocher @ 2012-12-17  7:27 UTC (permalink / raw)
  To: linux-mmc; +Cc: Heiko Schocher, linuxppc-dev, Wolfgang Denk, Dieter Schaffner

If the host controller do not support high speed, do not send the
read switch CMD 6. Same as done in mmc_sd_switch_hs().

Signed-off-by: Heiko Schocher <hs@denx.de>
Cc: Wolfgang Denk <wd@denx.de>
Cc: Dieter Schaffner <Dieter.Schaffner@ids.de>
Cc: linuxppc-dev@lists.ozlabs.org
Cc: linux-mmc@vger.kernel.org

---
 drivers/mmc/core/sd.c |    4 ++++
 1 files changed, 4 insertions(+), 0 deletions(-)

Found this on a MPC8313 based system with mmc over spi and a Transcend
2 GB SD card running a 2.6.37.6 kernel. Without this patch I get this
when reading the CMD6:

mmc1: starting CMD6 arg 00fffff1 flags 000000b5
mmc1:     blksz 64 blocks 1 flags 00000200 tsac 100 ms nsac 0
mmc_spi spi1.2:   mmc_spi: CMD6, resp R1
mmc_spi spi1.2:     mmc_spi: read block, 64 bytes
mmc_spi spi1.2: read error ffffff92 (-110)
mmc_spi spi1.2: read status -110
mmc1: req done (CMD6): 0: 00000000 00000000 00000000 00000000
mmc1:     0 bytes transferred: -110

Adding for example a longer timeout for the CMD6 did not helped.

With this patch the transcend card gets detected and can be used
fine. Here the infos from the card, shown in the sysfs:

-bash-3.2# cat /sys/bus/mmc/devices/mmc0\:0000/cid 
1b534d3030303030100bc3874c00c10b
-bash-3.2# cat /sys/bus/mmc/devices/mmc0\:0000/csd 
007fff325b5a83baf6dbdfff0e8000b5
-bash-3.2# cat /sys/bus/mmc/devices/mmc0\:0000/date 
01/2012
-bash-3.2# cat /sys/bus/mmc/devices/mmc0\:0000/erase_size 
512
-bash-3.2# cat /sys/bus/mmc/devices/mmc0\:0000/fwrev      
0x0
-bash-3.2# cat /sys/bus/mmc/devices/mmc0\:0000/hwrev 
0x1
-bash-3.2# cat /sys/bus/mmc/devices/mmc0\:0000/manfid 
0x00001b
-bash-3.2# cat /sys/bus/mmc/devices/mmc0\:0000/name   
00000
-bash-3.2# cat /sys/bus/mmc/devices/mmc0\:0000/oemid 
0x534d
-bash-3.2# cat /sys/bus/mmc/devices/mmc0\:0000/preferred_erase_size 
4194304
-bash-3.2# cat /sys/bus/mmc/devices/mmc0\:0000/scr                  
0225800000000000
-bash-3.2# cat /sys/bus/mmc/devices/mmc0\:0000/serial 
0x0bc3874c
-bash-3.2# cat /sys/bus/mmc/devices/mmc0\:0000/type 
SD

So the question raises, is this a known bug and/or a valid patch?
Other patches known to help here?

diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 49da4df..3142df0 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -268,6 +268,10 @@ static int mmc_read_switch(struct mmc_card *card)
 		return 0;
 	}
 
+	/* no need, if the host do not support high speed */
+	if (!(card->host->caps & MMC_CAP_SD_HIGHSPEED))
+		return 0;
+
 	err = -EIO;
 
 	status = kmalloc(64, GFP_KERNEL);
-- 
1.7.7.6

^ permalink raw reply related

* Re: linux-next: build warning after merge of the final tree
From: Stephen Rothwell @ 2012-12-17  3:34 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Paul Thompson, linux-kernel, linux-next, Paul Mackerras,
	linuxppc-dev
In-Reply-To: <20121217142238.a0840563304419bb345ac25f@canb.auug.org.au>

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

Hi all,

On Mon, 17 Dec 2012 14:22:38 +1100 Stephen Rothwell <sfr@canb.auug.org.au> wrote:
>
> After merging the final tree, today's linux-next build (powerpc allnoconfig)
> produced this warning:
> 
> warning: (PPC) selects SPARSE_IRQ which has unmet direct dependencies (HAVE_GENERIC_HARDIRQS && (IRQ_DOMAIN && DEBUG_FS || MAY_HAVE_SPARSE_IRQ))
> 
> I don't know what introduced that.

Actually probably caused by commit a1eaa3bc8247 ("Kconfig: fix Irq
Subsystem menu") from the akpm tree.

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

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

^ permalink raw reply

* linux-next: build warning after merge of the final tree
From: Stephen Rothwell @ 2012-12-17  3:22 UTC (permalink / raw)
  To: Benjamin Herrenschmidt, Paul Mackerras, linuxppc-dev
  Cc: linux-next, linux-kernel

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

Hi all,

After merging the final tree, today's linux-next build (powerpc allnoconfig)
produced this warning:

warning: (PPC) selects SPARSE_IRQ which has unmet direct dependencies (HAVE_GENERIC_HARDIRQS && (IRQ_DOMAIN && DEBUG_FS || MAY_HAVE_SPARSE_IRQ))

I don't know what introduced that.
-- 
Cheers,
Stephen Rothwell                    sfr@canb.auug.org.au

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

^ permalink raw reply

* Re: [git pull] Please pull powerpc.git next branch
From: Benjamin Herrenschmidt @ 2012-12-16 22:24 UTC (permalink / raw)
  To: linuxppc-dev list; +Cc: Linux Kernel list
In-Reply-To: <1355517897.19932.136.camel@pasglop>

On Sat, 2012-12-15 at 07:44 +1100, Benjamin Herrenschmidt wrote:
> Finally managed to get my head away from some other distractions
> to put this pull request together, sorry for the lateness :-)
> 
> The main highlight is probably some base POWER8 support. There's
> more to come such as transactional memory support but that will
> wait for the next one.

To clear up some misunderstanding, here I meant next merge window.

> Overall it's pretty quiet, or rather I've been pretty poor at
> picking things up from patchwork and reviewing them this time
> around and Kumar no better on the FSL side it seems... 

Cheers,
Ben.

^ permalink raw reply

* Re: [PATCH] pci: Provide support for parsing PCI DT ranges property
From: Grant Likely @ 2012-12-15  1:06 UTC (permalink / raw)
  To: Andrew Murray
  Cc: Michal Simek, linux-pci, devicetree-discuss, Thierry Reding,
	Liviu Dudau, Rob Herring, Rob Herring, linuxppc-dev
In-Reply-To: <20121212163749.GA17371@arm.com>

On Wed, Dec 12, 2012 at 4:37 PM, Andrew Murray <Andrew.Murray@arm.com> wrote:
> DT bindings for PCI host bridges often use the ranges property to describe
> memory and IO ranges - this binding tends to be the same across architectures
> yet several parsing implementations exist, e.g. arch/mips/pci/pci.c,
> arch/powerpc/kernel/pci-common.c, arch/sparc/kernel/pci.c and
> arch/microblaze/pci/pci-common.c (clone of PPC). Some of these duplicate
> functionality provided by drivers/of/address.c.

Hi Andrew,

Thanks for looking into this. This definitely needs to be done.

However, I cannot merge this patch as-is because it actually makes
things worse by adding yet another implementation of the parsing code.
Plus it doesn't actually have any users.  :-)

Instead, move the existing code that you need out of
arch/powerpc/kernel/pci-common.c into a shared place and add in the
features you need. Bonus points if you fixup microblaze or others at
the same time.

g.

^ permalink raw reply

* [PATCH v2] NTP: Add a CONFIG_RTC_SYSTOHC configuration
From: Jason Gunthorpe @ 2012-12-14 23:19 UTC (permalink / raw)
  To: John Stultz
  Cc: Alessandro Zummo, rtc-linux, linux-kernel, Thomas Gleixner,
	linuxppc-dev, linux-arm-kernel

The purpose of this option is to allow ARM/etc systems that rely on the
class RTC subsystem to have the same kind of automatic NTP based
synchronization that we have on PC platforms. Today ARM does not
implement update_persistent_clock and makes extensive use of the class
RTC system.

When enabled CONFIG_RTC_SYSTOHC will provide a generic
rtc_update_persistent_clock that stores the current time in the RTC and
is intended complement the existing CONFIG_RTC_HCTOSYS option that loads
the RTC at boot.

Like with RTC_HCTOSYS the platform's update_persistent_clock is used
first, if it works. Platforms with mixed class RTC and non-RTC drivers
need to return ENODEV when class RTC should be used. Such an update for
PPC is included in this patch.

Long term, implementations of update_persistent_clock should migrate to
proper class RTC drivers and use CONFIG_RTC_SYSTOHC instead.

Tested on ARM kirkwood and PPC405

Signed-off-by: Jason Gunthorpe <jgunthorpe@obsidianresearch.com>
---
 arch/powerpc/kernel/time.c |    2 +-
 drivers/rtc/Kconfig        |    9 +++++++++
 drivers/rtc/Makefile       |    1 +
 drivers/rtc/systohc.c      |   44 ++++++++++++++++++++++++++++++++++++++++++++
 include/linux/time.h       |    1 +
 kernel/time/ntp.c          |   15 +++++++++++----
 6 files changed, 67 insertions(+), 5 deletions(-)
 create mode 100644 drivers/rtc/systohc.c

v2 updates:
 - Be very careful to return ENODEV from rtc_update_persistent_clock,
   we don't want to loop on the fast retry path of sync_cmos_clock
   if there is no RTC set support available
 - Call the platform update_persistent_clock first. Only try
   the RTC version if it is compiled out, or explicitly returns ENODEV
 - Added 'depends on RTC_SYSTOHC = y' to KConfig
 - Don't fast rety in sync_cmos_clock if ENODEV is returned
 - Update PPC to return ENODEV if there is no mach specific function
   available in ppc_md. This will give rtc_update_persistent_clock
   a chance.
 - Use rtc_set_time not mms since rtc_hctosys assumes UTC.

diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index ce4cb77..bc844a8 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -667,7 +667,7 @@ int update_persistent_clock(struct timespec now)
 	struct rtc_time tm;
 
 	if (!ppc_md.set_rtc_time)
-		return 0;
+		return -ENODEV;
 
 	to_tm(now.tv_sec + 1 + timezone_offset, &tm);
 	tm.tm_year -= 1900;
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 19c03ab..7b3702b 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -28,6 +28,7 @@ config RTC_HCTOSYS
 config RTC_HCTOSYS_DEVICE
 	string "RTC used to set the system time"
 	depends on RTC_HCTOSYS = y
+	depends on RTC_SYSTOHC = y
 	default "rtc0"
 	help
 	  The RTC device that will be used to (re)initialize the system
@@ -48,6 +49,14 @@ config RTC_HCTOSYS_DEVICE
 	  sleep states. Do not specify an RTC here unless it stays powered
 	  during all this system's supported sleep states.
 
+config RTC_SYSTOHC
+	bool "Set the RTC time based on NTP synchronization"
+	default y
+	help
+	  If you say yes here, the system time (wall clock) will be stored
+          in the RTC specified by RTC_HCTOSYS_DEVICE approximately every 11
+  	  minutes if userspace reports synchronized NTP status.
+
 config RTC_DEBUG
 	bool "RTC debug support"
 	help
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 56297f0..69d11f1 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -6,6 +6,7 @@ ccflags-$(CONFIG_RTC_DEBUG)	:= -DDEBUG
 
 obj-$(CONFIG_RTC_LIB)		+= rtc-lib.o
 obj-$(CONFIG_RTC_HCTOSYS)	+= hctosys.o
+obj-$(CONFIG_RTC_SYSTOHC)	+= systohc.o
 obj-$(CONFIG_RTC_CLASS)		+= rtc-core.o
 rtc-core-y			:= class.o interface.o
 
diff --git a/drivers/rtc/systohc.c b/drivers/rtc/systohc.c
new file mode 100644
index 0000000..a625740
--- /dev/null
+++ b/drivers/rtc/systohc.c
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ *
+ */
+#include <linux/rtc.h>
+#include <linux/time.h>
+
+/**
+ * rtc_update_persistent_clock - Save NTP synchronized time to the RTC
+ * @now: Current time of day
+ *
+ * Replacement for the NTP platform function update_persistent_clock
+ * that stores time for later retrieval by rtc_hctosys
+ *
+ * Returns 0 on successful RTC update, -ENODEV if a RTC update is not
+ * possible at all, and various other -errno for specific temporary failure
+ * cases.
+ *
+ * If temporary failure is indicated the caller should try again 'soon'
+ */
+int rtc_update_persistent_clock(struct timespec now)
+{
+	struct rtc_device *rtc;
+	struct rtc_time tm;
+	int err = -ENODEV;
+
+	if (now.tv_nsec < (NSEC_PER_SEC >> 1))
+		rtc_time_to_tm(now.tv_sec, &tm);
+	else
+		rtc_time_to_tm(now.tv_sec + 1, &tm);
+
+	rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
+	if (rtc) {
+		/* rtc_hctosys exclusively uses UTC, so we call set_time here,
+		 * not set_mmss. */
+		if (rtc->ops && (rtc->ops->set_time && rtc->ops->set_mmss))
+			err = rtc_set_time(rtc, &tm);
+		rtc_class_close(rtc);
+	}
+
+	return err;
+}
diff --git a/include/linux/time.h b/include/linux/time.h
index 4d358e9..d668f9c 100644
--- a/include/linux/time.h
+++ b/include/linux/time.h
@@ -118,6 +118,7 @@ static inline bool timespec_valid_strict(const struct timespec *ts)
 extern void read_persistent_clock(struct timespec *ts);
 extern void read_boot_clock(struct timespec *ts);
 extern int update_persistent_clock(struct timespec now);
+extern int rtc_update_persistent_clock(struct timespec now);
 void timekeeping_init(void);
 extern int timekeeping_suspended;
 
diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c
index 24174b4..0c5d1a1 100644
--- a/kernel/time/ntp.c
+++ b/kernel/time/ntp.c
@@ -483,8 +483,7 @@ out:
 	return leap;
 }
 
-#ifdef CONFIG_GENERIC_CMOS_UPDATE
-
+#if defined(CONFIG_GENERIC_CMOS_UPDATE) || defined(CONFIG_RTC_SYSTOHC)
 static void sync_cmos_clock(struct work_struct *work);
 
 static DECLARE_DELAYED_WORK(sync_cmos_work, sync_cmos_clock);
@@ -510,14 +509,22 @@ static void sync_cmos_clock(struct work_struct *work)
 	}
 
 	getnstimeofday(&now);
-	if (abs(now.tv_nsec - (NSEC_PER_SEC / 2)) <= tick_nsec / 2)
+	if (abs(now.tv_nsec - (NSEC_PER_SEC / 2)) <= tick_nsec / 2) {
+		fail = -ENODEV;
+#ifdef CONFIG_GENERIC_CMOS_UPDATE
 		fail = update_persistent_clock(now);
+#endif
+#ifdef CONFIG_RTC_SYSTOHC
+		if (fail == -ENODEV)
+			fail = rtc_update_persistent_clock(now);
+#endif
+	}
 
 	next.tv_nsec = (NSEC_PER_SEC / 2) - now.tv_nsec - (TICK_NSEC / 2);
 	if (next.tv_nsec <= 0)
 		next.tv_nsec += NSEC_PER_SEC;
 
-	if (!fail)
+	if (!fail || fail == -ENODEV)
 		next.tv_sec = 659;
 	else
 		next.tv_sec = 0;
-- 
1.7.5.4

^ permalink raw reply related

* Re: [PATCH v2] NTP: Add a CONFIG_RTC_SYSTOHC configuration
From: John Stultz @ 2012-12-14 23:41 UTC (permalink / raw)
  To: Jason Gunthorpe
  Cc: Alessandro Zummo, rtc-linux, linux-kernel, Thomas Gleixner,
	linuxppc-dev, linux-arm-kernel
In-Reply-To: <20121214231933.GA15796@obsidianresearch.com>

On 12/14/2012 03:19 PM, Jason Gunthorpe wrote:
> The purpose of this option is to allow ARM/etc systems that rely on the
> class RTC subsystem to have the same kind of automatic NTP based
> synchronization that we have on PC platforms. Today ARM does not
> implement update_persistent_clock and makes extensive use of the class
> RTC system.
>
> When enabled CONFIG_RTC_SYSTOHC will provide a generic
> rtc_update_persistent_clock that stores the current time in the RTC and
> is intended complement the existing CONFIG_RTC_HCTOSYS option that loads
> the RTC at boot.
>
> Like with RTC_HCTOSYS the platform's update_persistent_clock is used
> first, if it works. Platforms with mixed class RTC and non-RTC drivers
> need to return ENODEV when class RTC should be used. Such an update for
> PPC is included in this patch.
>
> Long term, implementations of update_persistent_clock should migrate to
> proper class RTC drivers and use CONFIG_RTC_SYSTOHC instead.

Ok. This all sounds good.


Still one minor question below.
> diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
> index 19c03ab..7b3702b 100644
> --- a/drivers/rtc/Kconfig
> +++ b/drivers/rtc/Kconfig
> @@ -28,6 +28,7 @@ config RTC_HCTOSYS
>   config RTC_HCTOSYS_DEVICE
>   	string "RTC used to set the system time"
>   	depends on RTC_HCTOSYS = y
> +	depends on RTC_SYSTOHC = y

Is this right?

This should probably be a depends on RTC_HCTOSYS OR RTC_SYSTOCH.. 
Otherwise you have to select both in order to change the default device.

> diff --git a/drivers/rtc/systohc.c b/drivers/rtc/systohc.c
> new file mode 100644
> index 0000000..a625740
> --- /dev/null
> +++ b/drivers/rtc/systohc.c
> @@ -0,0 +1,44 @@
> +/*
> + * 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.
> + *
> + */
> +#include <linux/rtc.h>
> +#include <linux/time.h>
> +
> +/**
> + * rtc_update_persistent_clock - Save NTP synchronized time to the RTC
> + * @now: Current time of day
> + *
> + * Replacement for the NTP platform function update_persistent_clock
> + * that stores time for later retrieval by rtc_hctosys
> + *
> + * Returns 0 on successful RTC update, -ENODEV if a RTC update is not
> + * possible at all, and various other -errno for specific temporary failure
> + * cases.
> + *
> + * If temporary failure is indicated the caller should try again 'soon'
> + */
> +int rtc_update_persistent_clock(struct timespec now)

If we're going to move away from update_persistent_clock across the 
board (and as the update path doesn't have the same constraints of the 
read_persistent_clock interface), might it be better just to name this: 
rtc_update_clock()  (or something similar)?

That way if/when we do finally remove the other users of 
update_persistent_clock() and move them to an RTC driver, we will avoid 
any confusion between read/update.

This is in the similar vein of your suggestion of changing 
update_persistent_clock to platform_save_ntp_time_to_rtc()..

Sorry for the last minute nit! Other then these two issues, I'm happy to 
queue this (if Alessandro doesn't object).  Although with the merge 
window already open it may have to wait to 3.9, but I'll see what Thomas 
says.

thanks
-john

^ permalink raw reply

* [git pull] Please pull powerpc.git next branch
From: Benjamin Herrenschmidt @ 2012-12-14 20:44 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev list, Linux Kernel list

Hi Linus !

Finally managed to get my head away from some other distractions
to put this pull request together, sorry for the lateness :-)

The main highlight is probably some base POWER8 support. There's
more to come such as transactional memory support but that will
wait for the next one.

Overall it's pretty quiet, or rather I've been pretty poor at
picking things up from patchwork and reviewing them this time
around and Kumar no better on the FSL side it seems...

Cheers,
Ben.

The following changes since commit d6dc24613c222f9057131ccbd5264a10bcba9f97:

  Merge remote-tracking branch 'agust/merge' into merge (2012-11-21 13:24:49 +1100)

are available in the git repository at:


  git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc.git next

for you to fetch changes up to d526e85f60fce9aa2a1432cbd06e3cf20c1644c8:

  powerpc+of: Rename and fix OF reconfig notifier error inject module (2012-12-14 10:32:52 +1100)

----------------------------------------------------------------
Akinobu Mita (3):
      powerpc/iommu: Use bitmap library
      powerpc: Remove BITOP_MASK and BITOP_WORD from asm/bitops.h
      powerpc: Use asm-generic/bitops/le.h

Alexey Kardashevskiy (1):
      powerpc/pseries: Fix oops with MSIs when missing EEH PEs

Andreas Schwab (1):
      powerpc/powermac/cpufreq_32: Set non-infinite transition time for 7447A driver

Anton Blanchard (3):
      powerpc: Move most of setup.h out of uapi
      powerpc: Remove stale function prototypes from setup.h
      powerpc: Fix CONFIG_RELOCATABLE=y CONFIG_CRASH_DUMP=n build

Aravinda Prasad (1):
      powerpc/ptrace: Enable hardware breakpoint upon re-registering

Benjamin Herrenschmidt (5):
      powerpc/powernv: Fix OPAL debug entry
      Merge branch 'dt' into next
      Merge branch 'merge' into next
      Merge remote-tracking branch 'kumar/next' into next
      powerpc+of: Rename and fix OF reconfig notifier error inject module

Dan Horák (1):
      fbdev: Add GXT4000P and GXT6500P support to the gxt4500 driver

Gavin Shan (2):
      powerpc/pnv: Avoid bogus output
      powerpc/eeh: Do not invalidate PE properly

Ian Munsie (5):
      powerpc: Add set_mode hcall
      powerpc: Add wrappers to enable/disable relocation on exceptions
      powerpc: Move get_longbusy_msecs into hvcall.h and remove duplicate function
      powerpc: Enable relocation on during exceptions at boot
      powerpc: Disable relocation on exceptions when kexecing

Jia Hongtao (1):
      powerpc/fsl-pci: Add PCI controller ATMU PM support

JoonSoo Kim (1):
      powerpc: Change free_bootmem() to kfree()

Julia Lawall (1):
      powerpc/rtas_flash: Eliminate possible double free

K.Prasad (1):
      powerpc/hw-breakpoint: Use generic hw-breakpoint interfaces for new PPC ptrace flags

Li Zhong (1):
      powerpc: Fix MAX_STACK_TRACE_ENTRIES too low warning !

Matthew McClintock (1):
      powerpc: dtc is required to build dtb files

Michael Ellerman (12):
      powerpc/udbg: Remove unused udbg_read()
      powerpc/xmon: Remove unused xmon_expect() & xmon_read_poll()
      powerpc/xmon: Remove empty xmon_map_scc()
      powerpc/xmon: Make xmon_getchar() static
      powerpc/xmon: Merge start.c into nonstdio.c
      powerpc/xmon: Remove renaming #defines of scanhex() and skipbl()
      powerpc/xmon: Remove unused #defines
      powerpc/xmon: Use STACK_FRAME_OVERHEAD in xmon_show_stack()
      powerpc/xmon: Fiddle xmon_depth_to_print logic in xmon_show_stack()
      powerpc/xmon: Fallback to printk() in xmon_printf() if udbg is not setup
      powerpc: Remove no longer used ppc_md.idle_loop()
      powerpc/perf: Add missing L2 constraint handling in Power7 PMU

Michael Neuling (16):
      powerpc/ptrace: Fix spelling mistake
      powerpc/ptrace: Remove unused addr parameter in ppc_del_hwdebug()
      powerpc: make POWER7 setup code name generic
      powerpc: Add POWER8 setup code
      powerpc: POWER8 cputable entry
      powerpc: Fix denorm symbol name
      powerpc/pseries: Update ibm,architecture.vec for PAPR 2.7/POWER8
      powerpc: Add POWER8 architected mode to cputable
      powerpc: Whitespace changes in exception64s.S
      powerpc: Remove unessessary 0x3000 location enforcement
      powerpc: Make load_hander handle upto 64k offset
      powerpc: Turn syscall handler into macros
      powerpc: Add new macros needed for relocation on exceptions
      powerpc: Add relocation on exception vector handlers
      powerpc: Move initial mfspr LPCR out of __init_LPCR
      powerpc: Setup relocation on exceptions for bare metal systems

Nathan Fontenot (6):
      powerpc+of: Add /proc device tree updating to of node add/remove
      powerpc+of: Move of_drconf_cell struct definition to asm/prom.h
      powerpc+of: Add of node/property notification chain for adds and removes
      powerpc+of: Rename the drivers/of prom_* functions to of_*
      powerpc+of: Remove the pSeries_reconfig.h file
      powerpc+of: Export of_reconfig_notifier_[register,unregister]

Nishanth Aravamudan (1):
      powerpc/pseries: Double NR_CPUS in defconfig

Srinivas Kandagatla (1):
      powerpc/sysdev: Use module_platform_driver macro

Sukadev Bhattiprolu (1):
      powerpc/perf: Use uapi/unistd.h to fix build error

Timur Tabi (2):
      drivers/virt: the Freescale hypervisor driver doesn't need to check MSR[GS]
      powerpc/86xx: fsl_pcibios_fixup_bus requires CONFIG_PCI

Tony Breeds (2):
      powerpc/47x: Use the new ppc-opcode infrastructure
      powerpc: Add asm/debug.h to get powerpc_debugfs_root

Tushar Behera (1):
      powerpc/85xx: p1022ds: Use NULL instead of 0 for pointers

Varun Sethi (1):
      powerpc/iommu/fsl: Add PAMU bypass enable register to ccsr_guts struct

Wei Yongjun (1):
      powerpc/windfarm: Use module_i2c_driver to simplify the code

Xuelin Shi (1):
      powerpc/dma/raidengine: add raidengine device

Yang Li (1):
      powerpc: Fix typos in Freescale copyright claims

York Sun (1):
      powerpc/mpc85xx: Change spin table to cached memory

 .../devicetree/bindings/powerpc/fsl/raideng.txt    |   81 +++++
 Documentation/powerpc/ptrace.txt                   |   16 +
 arch/arm/mach-mxs/mach-mxs.c                       |    2 +-
 arch/powerpc/Makefile                              |    2 +-
 arch/powerpc/boot/dts/fsl/p5020si-post.dtsi        |    1 +
 arch/powerpc/boot/dts/fsl/p5020si-pre.dtsi         |    6 +
 arch/powerpc/boot/dts/fsl/qoriq-raid1.0-0.dtsi     |   85 ++++++
 arch/powerpc/configs/pseries_defconfig             |    2 +-
 arch/powerpc/include/asm/bitops.h                  |   75 +----
 arch/powerpc/include/asm/cputable.h                |   12 +-
 arch/powerpc/include/asm/dbell.h                   |    2 +-
 arch/powerpc/include/asm/exception-64s.h           |   97 +++++-
 arch/powerpc/include/asm/firmware.h                |    4 +-
 arch/powerpc/include/asm/fsl_gtm.h                 |    2 +-
 arch/powerpc/include/asm/fsl_guts.h                |    4 +-
 arch/powerpc/include/asm/hvcall.h                  |   23 +-
 arch/powerpc/include/asm/immap_qe.h                |    2 +-
 arch/powerpc/include/asm/machdep.h                 |    3 -
 arch/powerpc/include/asm/mmu.h                     |    1 +
 arch/powerpc/include/asm/pSeries_reconfig.h        |   47 ---
 arch/powerpc/include/asm/ppc-opcode.h              |    6 +-
 arch/powerpc/include/asm/prom.h                    |   16 +
 arch/powerpc/include/asm/qe.h                      |    2 +-
 arch/powerpc/include/asm/qe_ic.h                   |    2 +-
 arch/powerpc/include/asm/reg.h                     |    3 +
 arch/powerpc/include/asm/rtas.h                    |    5 +
 arch/powerpc/include/asm/setup.h                   |   29 ++
 arch/powerpc/include/asm/ucc.h                     |    2 +-
 arch/powerpc/include/asm/ucc_fast.h                |    2 +-
 arch/powerpc/include/asm/ucc_slow.h                |    2 +-
 arch/powerpc/include/asm/udbg.h                    |    1 -
 arch/powerpc/include/uapi/asm/setup.h              |   31 --
 arch/powerpc/kernel/Makefile                       |    2 +-
 .../{cpu_setup_power7.S => cpu_setup_power.S}      |   32 +-
 arch/powerpc/kernel/cputable.c                     |   38 +++
 arch/powerpc/kernel/entry_64.S                     |    2 +
 arch/powerpc/kernel/exceptions-64s.S               |  308 ++++++++++++++++----
 arch/powerpc/kernel/head_64.S                      |    6 +-
 arch/powerpc/kernel/idle.c                         |    3 -
 arch/powerpc/kernel/iommu.c                        |   16 +-
 arch/powerpc/kernel/machine_kexec.c                |   14 +-
 arch/powerpc/kernel/machine_kexec_64.c             |    8 +-
 arch/powerpc/kernel/pci_32.c                       |    2 +-
 arch/powerpc/kernel/prom.c                         |    7 +-
 arch/powerpc/kernel/prom_init.c                    |   11 +-
 arch/powerpc/kernel/ptrace.c                       |   90 +++++-
 arch/powerpc/kernel/rtas.c                         |    1 -
 arch/powerpc/kernel/rtas_flash.c                   |    4 +-
 arch/powerpc/kernel/setup_64.c                     |    5 +
 arch/powerpc/kernel/udbg.c                         |   23 --
 arch/powerpc/mm/numa.c                             |   12 -
 arch/powerpc/mm/tlb_nohash_low.S                   |   15 +-
 arch/powerpc/perf/power7-pmu.c                     |   17 +-
 arch/powerpc/platforms/52xx/lite5200.c             |    2 +-
 arch/powerpc/platforms/82xx/pq2ads-pci-pic.c       |    8 +-
 arch/powerpc/platforms/83xx/mpc832x_mds.c          |    2 +-
 arch/powerpc/platforms/83xx/mpc836x_mds.c          |    2 +-
 arch/powerpc/platforms/83xx/mpc836x_rdk.c          |    2 +-
 arch/powerpc/platforms/83xx/mpc837x_rdb.c          |    2 +-
 arch/powerpc/platforms/85xx/mpc85xx_mds.c          |    2 +-
 arch/powerpc/platforms/85xx/p1022_ds.c             |    8 +-
 arch/powerpc/platforms/85xx/smp.c                  |   49 +++-
 arch/powerpc/platforms/86xx/mpc8610_hpcd.c         |    2 +
 arch/powerpc/platforms/powermac/cpufreq_32.c       |    5 +-
 arch/powerpc/platforms/powernv/pci-ioda.c          |   25 +-
 arch/powerpc/platforms/ps3/os-area.c               |    6 +-
 arch/powerpc/platforms/pseries/dlpar.c             |   34 +--
 arch/powerpc/platforms/pseries/eeh_pe.c            |    2 +-
 arch/powerpc/platforms/pseries/firmware.c          |    1 +
 arch/powerpc/platforms/pseries/hotplug-cpu.c       |    8 +-
 arch/powerpc/platforms/pseries/hotplug-memory.c    |   60 ++--
 arch/powerpc/platforms/pseries/iommu.c             |   10 +-
 arch/powerpc/platforms/pseries/mobility.c          |    4 +-
 arch/powerpc/platforms/pseries/msi.c               |    3 +-
 arch/powerpc/platforms/pseries/plpar_wrappers.h    |   31 ++
 arch/powerpc/platforms/pseries/reconfig.c          |  119 +-------
 arch/powerpc/platforms/pseries/setup.c             |   77 ++++-
 arch/powerpc/platforms/pseries/smp.c               |    1 -
 arch/powerpc/sysdev/fsl_gtm.c                      |    2 +-
 arch/powerpc/sysdev/fsl_pci.c                      |   37 ++-
 arch/powerpc/sysdev/pmi.c                          |   13 +-
 arch/powerpc/sysdev/qe_lib/qe.c                    |    2 +-
 arch/powerpc/sysdev/qe_lib/qe_ic.c                 |    2 +-
 arch/powerpc/sysdev/qe_lib/qe_ic.h                 |    2 +-
 arch/powerpc/sysdev/qe_lib/qe_io.c                 |    2 +-
 arch/powerpc/sysdev/qe_lib/ucc.c                   |    2 +-
 arch/powerpc/sysdev/qe_lib/ucc_fast.c              |    2 +-
 arch/powerpc/sysdev/qe_lib/ucc_slow.c              |    2 +-
 arch/powerpc/sysdev/qe_lib/usb.c                   |    2 +-
 arch/powerpc/xmon/Makefile                         |    2 +-
 arch/powerpc/xmon/nonstdio.c                       |   53 ++--
 arch/powerpc/xmon/nonstdio.h                       |    6 -
 arch/powerpc/xmon/start.c                          |   34 ---
 arch/powerpc/xmon/xmon.c                           |   26 +-
 drivers/crypto/nx/nx-842.c                         |   20 +-
 drivers/crypto/nx/nx.c                             |    1 -
 drivers/infiniband/hw/ehca/hcp_if.c                |   20 --
 drivers/macintosh/smu.c                            |    2 +-
 drivers/macintosh/windfarm_fcu_controls.c          |   14 +-
 drivers/macintosh/windfarm_lm75_sensor.c           |   14 +-
 drivers/macintosh/windfarm_max6690_sensor.c        |   13 +-
 drivers/macintosh/windfarm_smu_sat.c               |   13 +-
 drivers/net/ethernet/ibm/ehea/ehea_phyp.h          |   20 --
 drivers/of/base.c                                  |  142 ++++++++-
 drivers/video/Kconfig                              |    8 +-
 drivers/video/gxt4500.c                            |   15 +-
 drivers/virt/fsl_hypervisor.c                      |    3 -
 include/linux/of.h                                 |   29 +-
 lib/Kconfig.debug                                  |   10 +-
 lib/Makefile                                       |    4 +-
 ...nject.c => of-reconfig-notifier-error-inject.c} |   22 +-
 tools/perf/perf.h                                  |    2 +-
 112 files changed, 1387 insertions(+), 803 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/powerpc/fsl/raideng.txt
 create mode 100644 arch/powerpc/boot/dts/fsl/qoriq-raid1.0-0.dtsi
 delete mode 100644 arch/powerpc/include/asm/pSeries_reconfig.h
 create mode 100644 arch/powerpc/include/asm/setup.h
 rename arch/powerpc/kernel/{cpu_setup_power7.S => cpu_setup_power.S} (80%)
 delete mode 100644 arch/powerpc/xmon/start.c
 rename lib/{pSeries-reconfig-notifier-error-inject.c => of-reconfig-notifier-error-inject.c} (51%)

^ permalink raw reply

* [PATCH 2/4] iommu/fsl: Add PAMU bypass enable register to ccsr_guts structure.
From: Varun Sethi @ 2012-12-14 13:53 UTC (permalink / raw)
  To: joerg.roedel, iommu, linuxppc-dev, linux-kernel, timur, scottwood
  Cc: Varun Sethi

PAMU bypass enable register added to the ccsr_guts structure.

(This patch has already been applied by Kumar Gala in the linuxppc tree next branch)

Signed-off-by: Timur Tabi <timur@freescale.com>
Signed-off-by: Varun Sethi <Varun.Sethi@freescale.com>
---
 arch/powerpc/include/asm/fsl_guts.h |    4 +++-
 1 files changed, 3 insertions(+), 1 deletions(-)

diff --git a/arch/powerpc/include/asm/fsl_guts.h b/arch/powerpc/include/asm/fsl_guts.h
index dd5ba2c..77ced0b 100644
--- a/arch/powerpc/include/asm/fsl_guts.h
+++ b/arch/powerpc/include/asm/fsl_guts.h
@@ -71,7 +71,9 @@ struct ccsr_guts {
 	u8	res0c4[0x224 - 0xc4];
 	__be32  iodelay1;	/* 0x.0224 - IO delay control register 1 */
 	__be32  iodelay2;	/* 0x.0228 - IO delay control register 2 */
-	u8	res22c[0x800 - 0x22c];
+	u8	res22c[0x604 - 0x22c];
+	__be32	pamubypenr; 	/* 0x.604 - PAMU bypass enable register */
+	u8	res608[0x800 - 0x608];
 	__be32	clkdvdr;	/* 0x.0800 - Clock Divide Register */
 	u8	res804[0x900 - 0x804];
 	__be32	ircr;		/* 0x.0900 - Infrared Control Register */
-- 
1.7.4.1

^ permalink raw reply related

* [PATCH 4/4 v7] iommu/fsl: Freescale PAMU driver and IOMMU API implementation.
From: Varun Sethi @ 2012-12-14 13:51 UTC (permalink / raw)
  To: joerg.roedel, iommu, linuxppc-dev, linux-kernel, timur, scottwood
  Cc: Varun Sethi
In-Reply-To: <1355493114-21776-1-git-send-email-Varun.Sethi@freescale.com>

Following is a brief description of the PAMU hardware:
PAMU determines what action to take and whether to authorize the action on
the basis of the memory address, a Logical IO Device Number (LIODN), and
PAACT table (logically) indexed by LIODN and address. Hardware devices which
need to access memory must provide an LIODN in addition to the memory address.

Peripheral Access Authorization and Control Tables (PAACTs) are the primary
data structures used by PAMU. A PAACT is a table of peripheral access
authorization and control entries (PAACE).Each PAACE defines the range of
I/O bus address space that is accessible by the LIOD and the associated access
capabilities.

There are two types of PAACTs: primary PAACT (PPAACT) and secondary PAACT 
(SPAACT).A given physical I/O device may be able to act as one or more
independent logical I/O devices (LIODs). Each such logical I/O device is
assigned an identifier called logical I/O device number (LIODN). A LIODN is
allocated a contiguous portion of the I/O bus address space called the DSA window
for performing DSA operations. The DSA window may optionally be divided into
multiple sub-windows, each of which may be used to map to a region in system
storage space. The first sub-window is referred to as the primary sub-window
and the remaining are called secondary sub-windows.

This patch provides the PAMU driver (fsl_pamu.c) and the corresponding IOMMU
API implementation (fsl_pamu_domain.c). The PAMU hardware driver (fsl_pamu.c)
has been derived from the work done by Ashish Kalra and Timur Tabi
(timur@freescale.com).

Signed-off-by: Timur Tabi <timur@freescale.com>
Signed-off-by: Varun Sethi <Varun.Sethi@freescale.com>
---
changes in v7:
- Set max_subwidows in the geometry attribute.
- Add checking for maximum supported LIODN value.
- Use upper_32_bits and lower_32_bits macros while
  intializing PAMU data structures.
changes in v6:
- Simplified complex conditional statements.
- Fixed indentation issues.
- Added comments for IOMMU API implementation.
changes in v5:
- Addressed comments from Timur.
changes in v4:
- Addressed comments from Timur and Scott.
changes in v3:
- Addressed comments by Kumar Gala
- dynamic fspi allocation
- fixed alignment check in map and unmap
 drivers/iommu/Kconfig           |    8 +
 drivers/iommu/Makefile          |    1 +
 drivers/iommu/fsl_pamu.c        | 1152 +++++++++++++++++++++++++++++++++++++++
 drivers/iommu/fsl_pamu.h        |  398 ++++++++++++++
 drivers/iommu/fsl_pamu_domain.c | 1033 +++++++++++++++++++++++++++++++++++
 drivers/iommu/fsl_pamu_domain.h |   96 ++++
 6 files changed, 2688 insertions(+), 0 deletions(-)
 create mode 100644 drivers/iommu/fsl_pamu.c
 create mode 100644 drivers/iommu/fsl_pamu.h
 create mode 100644 drivers/iommu/fsl_pamu_domain.c
 create mode 100644 drivers/iommu/fsl_pamu_domain.h

diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index e39f9db..f712da2 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -17,6 +17,14 @@ config OF_IOMMU
        def_bool y
        depends on OF
 
+config FSL_PAMU
+	bool "Freescale IOMMU support"
+	depends on PPC_E500MC
+	select IOMMU_API
+	select GENERIC_ALLOCATOR
+	help
+	  Freescale PAMU support.
+
 # MSM IOMMU support
 config MSM_IOMMU
 	bool "MSM IOMMU Support"
diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile
index f66b816..4bc664e 100644
--- a/drivers/iommu/Makefile
+++ b/drivers/iommu/Makefile
@@ -13,3 +13,4 @@ obj-$(CONFIG_OMAP_IOMMU_DEBUG) += omap-iommu-debug.o
 obj-$(CONFIG_TEGRA_IOMMU_GART) += tegra-gart.o
 obj-$(CONFIG_TEGRA_IOMMU_SMMU) += tegra-smmu.o
 obj-$(CONFIG_EXYNOS_IOMMU) += exynos-iommu.o
+obj-$(CONFIG_FSL_PAMU) += fsl_pamu.o fsl_pamu_domain.o
diff --git a/drivers/iommu/fsl_pamu.c b/drivers/iommu/fsl_pamu.c
new file mode 100644
index 0000000..9142aee
--- /dev/null
+++ b/drivers/iommu/fsl_pamu.c
@@ -0,0 +1,1152 @@
+/*
+ * 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 (C) 2012 Freescale Semiconductor, Inc.
+ *
+ */
+
+#define pr_fmt(fmt)    "fsl-pamu: %s: " fmt, __func__
+
+#include <linux/init.h>
+#include <linux/iommu.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/of_platform.h>
+#include <linux/bootmem.h>
+#include <linux/genalloc.h>
+#include <asm/io.h>
+#include <asm/bitops.h>
+#include <asm/fsl_guts.h>
+
+#include "fsl_pamu.h"
+
+/* define indexes for each operation mapping scenario */
+#define OMI_QMAN        0x00
+#define OMI_FMAN        0x01
+#define OMI_QMAN_PRIV   0x02
+#define OMI_CAAM        0x03
+
+static struct paace *ppaact;
+static struct paace *spaact;
+static struct ome *omt;
+unsigned int max_subwindow_count;
+
+struct gen_pool *spaace_pool;
+
+/** 
+ * pamu_get_ppaace() - Return the primary PACCE
+ * @liodn: liodn PAACT index for desired PAACE
+ *
+ * Returns the ppace pointer upon success else return
+ * null.
+ */
+static struct paace *pamu_get_ppaace(int liodn)
+{
+	if (!ppaact || liodn > PAACE_NUMBER_ENTRIES) {
+		pr_err("PPAACT doesn't exist\n");
+		return NULL;
+	}
+
+	return &ppaact[liodn];
+}
+
+/** 
+ * pamu_enable_liodn() - Set valid bit of PACCE
+ * @liodn: liodn PAACT index for desired PAACE
+ *
+ * Returns 0 upon success else error code < 0 returned
+ */
+int pamu_enable_liodn(int liodn)
+{
+	struct paace *ppaace;
+
+	ppaace = pamu_get_ppaace(liodn);
+	if (!ppaace) {
+		pr_err("Invalid primary paace entry\n");
+		return -ENOENT;
+	}
+
+	if (!get_bf(ppaace->addr_bitfields, PPAACE_AF_WSE)) {
+		pr_err("liodn %d not configured\n", liodn);
+		return -EINVAL;
+	}
+
+	/* Ensure that all other stores to the ppaace complete first */
+	mb();
+
+	ppaace->addr_bitfields |= PAACE_V_VALID;
+	mb();
+
+	return 0;
+}
+
+/** 
+ * pamu_disable_liodn() - Clears valid bit of PACCE
+ * @liodn: liodn PAACT index for desired PAACE
+ *
+ * Returns 0 upon success else error code < 0 returned
+ */
+int pamu_disable_liodn(int liodn)
+{
+	struct paace *ppaace;
+
+	ppaace = pamu_get_ppaace(liodn);
+	if (!ppaace) {
+		pr_err("Invalid primary paace entry\n");
+		return -ENOENT;
+	}
+
+	set_bf(ppaace->addr_bitfields, PAACE_AF_V, PAACE_V_INVALID);
+	mb();
+
+	return 0;
+}
+
+/* Derive the window size encoding for a particular PAACE entry */
+static unsigned int map_addrspace_size_to_wse(phys_addr_t addrspace_size)
+{
+	/* Bug if not a power of 2 */
+	BUG_ON((addrspace_size & (addrspace_size - 1)));
+
+	/* window size is 2^(WSE+1) bytes */
+	return __ffs(addrspace_size >> PAMU_PAGE_SHIFT) + PAMU_PAGE_SHIFT - 1;
+}
+
+/* Derive the PAACE window count encoding for the subwindow count */
+static unsigned int map_subwindow_cnt_to_wce(u32 subwindow_cnt)
+{
+       /* window count is 2^(WCE+1) bytes */
+       return __ffs(subwindow_cnt) - 1;
+}
+
+/* 
+ * Set the PAACE type as primary and set the coherency required domain
+ * attribute
+ */
+static void pamu_setup_default_xfer_to_host_ppaace(struct paace *ppaace)
+{
+	set_bf(ppaace->addr_bitfields, PAACE_AF_PT, PAACE_PT_PRIMARY);
+
+	set_bf(ppaace->domain_attr.to_host.coherency_required, PAACE_DA_HOST_CR,
+	       PAACE_M_COHERENCE_REQ);
+}
+
+/*
+ * Set the PAACE type as secondary and set the coherency required domain
+ * attribute.
+ */
+static void pamu_setup_default_xfer_to_host_spaace(struct paace *spaace)
+{
+	set_bf(spaace->addr_bitfields, PAACE_AF_PT, PAACE_PT_SECONDARY);
+	set_bf(spaace->domain_attr.to_host.coherency_required, PAACE_DA_HOST_CR,
+	       PAACE_M_COHERENCE_REQ);
+}
+
+/*
+ * Return the spaace (corresponding to the secondary window index)
+ * for a particular ppaace.
+ */
+static struct paace *pamu_get_spaace(struct paace *paace, u32 wnum)
+{
+	u32 subwin_cnt;
+	struct paace *spaace = NULL;
+
+	subwin_cnt = 1UL << (get_bf(paace->impl_attr, PAACE_IA_WCE) + 1);
+
+	if (wnum < subwin_cnt)
+		spaace = &spaact[paace->fspi + wnum];
+	else
+		pr_err("secondary paace out of bounds\n");
+
+	return spaace;
+}
+
+/**
+ * pamu_get_fspi_and_allocate() - Allocates fspi index and reserves subwindows
+ *                                required for primary PAACE in the secondary
+ *                                PAACE table.
+ * @subwin_cnt: Number of subwindows to be reserved.
+ *
+ * A PPAACE entry may have a number of associated subwindows. A subwindow
+ * corresponds to a SPAACE entry in the SPAACT table. Each PAACE entry stores
+ * the index (fspi) of the first SPAACE entry in the SPAACT table. This
+ * function returns the index of the first SPAACE entry. The remaining
+ * SPAACE entries are reserved contiguously from that index.
+ *
+ * Returns a valid fspi index in the range of 0 - SPAACE_NUMBER_ENTRIES on success.
+ * If no SPAACE entry is available or the allocator can not reserve the required
+ * number of contiguous entries function returns ULONG_MAX indicating a failure.
+ *
+*/
+static unsigned long pamu_get_fspi_and_allocate(u32 subwin_cnt)
+{
+	unsigned long spaace_addr;
+
+	spaace_addr = gen_pool_alloc(spaace_pool, subwin_cnt * sizeof(struct paace));
+	if (!spaace_addr)
+		return ULONG_MAX;
+
+	return (spaace_addr - (unsigned long)spaact) / (sizeof(struct paace));
+}
+
+/* Release the subwindows reserved for a particular LIODN */
+void pamu_free_subwins(int liodn)
+{
+	struct paace *ppaace;
+	u32 subwin_cnt, size;
+
+	ppaace = pamu_get_ppaace(liodn);
+	if (!ppaace) {
+		pr_err("Invalid liodn entry\n");
+		return;
+	}
+
+	if (get_bf(ppaace->addr_bitfields, PPAACE_AF_MW)) {
+		subwin_cnt = 1UL << (get_bf(ppaace->impl_attr, PAACE_IA_WCE) + 1);
+		size = (subwin_cnt - 1) * sizeof(struct paace);
+		gen_pool_free(spaace_pool, (unsigned long)&spaact[ppaace->fspi], size);
+		set_bf(ppaace->addr_bitfields, PPAACE_AF_MW, 0);
+	}
+}
+
+/* 
+ * Function used for updating stash destination for the coressponding
+ * LIODN.
+ */
+int  pamu_update_paace_stash(int liodn, u32 subwin, u32 value)
+{
+	struct paace *paace;
+
+	paace = pamu_get_ppaace(liodn);
+	if (!paace) {
+		pr_err("Invalid liodn entry\n");
+		return -ENOENT;
+	}
+	if (subwin) {
+		paace = pamu_get_spaace(paace, subwin - 1);
+		if (!paace) {
+			return -ENOENT;
+		}
+	}
+	set_bf(paace->impl_attr, PAACE_IA_CID, value);
+
+	return 0;
+}
+
+/** 
+ * pamu_config_paace() - Sets up PPAACE entry for specified liodn
+ *
+ * @liodn: Logical IO device number
+ * @win_addr: starting address of DSA window
+ * @win-size: size of DSA window
+ * @omi: Operation mapping index -- if ~omi == 0 then omi not defined
+ * @rpn: real (true physical) page number
+ * @stashid: cache stash id for associated cpu -- if ~stashid == 0 then
+ *	     stashid not defined
+ * @snoopid: snoop id for hardware coherency -- if ~snoopid == 0 then
+ *	     snoopid not defined
+ * @subwin_cnt: number of sub-windows
+ * @prot: window permissions
+ *
+ * Returns 0 upon success else error code < 0 returned
+ */
+int pamu_config_ppaace(int liodn, phys_addr_t win_addr, phys_addr_t win_size,
+		       u32 omi, unsigned long rpn, u32 snoopid, u32 stashid,
+		       u32 subwin_cnt, int prot)
+{
+	struct paace *ppaace;
+	unsigned long fspi;
+
+	if ((win_size & (win_size - 1)) || win_size < PAMU_PAGE_SIZE) {
+		pr_err("window size too small or not a power of two %llx\n", win_size);
+		return -EINVAL;
+	}
+
+	if (win_addr & (win_size - 1)) {
+		pr_err("window address is not aligned with window size\n");
+		return -EINVAL;
+	}
+
+	ppaace = pamu_get_ppaace(liodn);
+	if (!ppaace) {
+		return -ENOENT;
+	}
+
+	/* window size is 2^(WSE+1) bytes */
+	set_bf(ppaace->addr_bitfields, PPAACE_AF_WSE,
+           map_addrspace_size_to_wse(win_size));
+
+	pamu_setup_default_xfer_to_host_ppaace(ppaace);
+
+	ppaace->wbah = win_addr >> (PAMU_PAGE_SHIFT + 20);
+	set_bf(ppaace->addr_bitfields, PPAACE_AF_WBAL,
+	       (win_addr >> PAMU_PAGE_SHIFT));
+
+	/* set up operation mapping if it's configured */
+	if (omi < OME_NUMBER_ENTRIES) {
+		set_bf(ppaace->impl_attr, PAACE_IA_OTM, PAACE_OTM_INDEXED);
+		ppaace->op_encode.index_ot.omi = omi;
+	} else if (~omi != 0) {
+		pr_err("bad operation mapping index: %d\n", omi);
+		return -EINVAL;
+	}
+
+	/* configure stash id */
+	if (~stashid != 0)
+		set_bf(ppaace->impl_attr, PAACE_IA_CID, stashid);
+
+	/* configure snoop id */
+	if (~snoopid != 0)
+		ppaace->domain_attr.to_host.snpid = snoopid;
+
+	if (subwin_cnt) {
+		/* The first entry is in the primary PAACE instead */
+		fspi = pamu_get_fspi_and_allocate(subwin_cnt - 1);
+		if (fspi == ULONG_MAX) {
+			pr_err("spaace indexes exhausted\n");
+			return -EINVAL;
+		}
+
+		/* window count is 2^(WCE+1) bytes */
+		set_bf(ppaace->impl_attr, PAACE_IA_WCE,
+		       map_subwindow_cnt_to_wce(subwin_cnt));
+		set_bf(ppaace->addr_bitfields, PPAACE_AF_MW, 0x1);
+		ppaace->fspi = fspi;
+	} else {
+		set_bf(ppaace->impl_attr, PAACE_IA_ATM, PAACE_ATM_WINDOW_XLATE);
+		ppaace->twbah = rpn >> 20;
+		set_bf(ppaace->win_bitfields, PAACE_WIN_TWBAL, rpn);
+		set_bf(ppaace->addr_bitfields, PAACE_AF_AP, prot);
+		set_bf(ppaace->impl_attr, PAACE_IA_WCE, 0);
+		set_bf(ppaace->addr_bitfields, PPAACE_AF_MW, 0);
+	}
+	mb();
+
+	return 0;
+}
+
+/**
+ * pamu_config_spaace() - Sets up SPAACE entry for specified subwindow
+ *
+ * @liodn:  Logical IO device number
+ * @subwin_cnt:  number of sub-windows associated with dma-window
+ * @subwin_addr: starting address of subwindow
+ * @subwin_size: size of subwindow
+ * @omi: Operation mapping index
+ * @rpn: real (true physical) page number
+ * @snoopid: snoop id for hardware coherency -- if ~snoopid == 0 then
+ *			  snoopid not defined
+ * @stashid: cache stash id for associated cpu
+ * @enable: enable/disable subwindow after reconfiguration
+ * @prot: sub window permissions
+ *
+ * Returns 0 upon success else error code < 0 returned
+ */
+int pamu_config_spaace(int liodn, u32 subwin_cnt, u32 subwin_addr,
+		       phys_addr_t subwin_size, u32 omi, unsigned long rpn,
+		       u32 snoopid, u32 stashid, int enable, int prot)
+{
+	struct paace *paace;
+
+	/* setup sub-windows */
+	if (!subwin_cnt) {
+		pr_err("Invalid subwindow count\n");
+		return -EINVAL;
+	}
+
+	paace = pamu_get_ppaace(liodn);
+	if (subwin_addr > 0 && subwin_addr < subwin_cnt && paace) {
+		paace = pamu_get_spaace(paace, subwin_addr - 1);
+
+		if (paace && !(paace->addr_bitfields & PAACE_V_VALID)) {
+			pamu_setup_default_xfer_to_host_spaace(paace);
+			set_bf(paace->addr_bitfields, SPAACE_AF_LIODN, liodn);
+		}
+	}
+
+	if (!paace) {
+		pr_err("Invalid liodn entry\n");
+		return -ENOENT;
+	}
+
+	if (!enable && prot == PAACE_AP_PERMS_DENIED) {
+		if (subwin_addr > 0)
+			set_bf(paace->addr_bitfields, PAACE_AF_V,
+				 PAACE_V_INVALID);
+		else
+			set_bf(paace->addr_bitfields, PAACE_AF_AP,
+				 prot);
+		mb();
+		return 0;
+	}
+
+	if (subwin_size & (subwin_size - 1) || subwin_size < PAMU_PAGE_SIZE) {
+		pr_err("subwindow size out of range, or not a power of 2\n");
+		return -EINVAL;
+	}
+
+	if (rpn == ULONG_MAX) {
+		pr_err("real page number out of range\n");
+		return -EINVAL;
+	}
+
+	/* window size is 2^(WSE+1) bytes */
+	set_bf(paace->win_bitfields, PAACE_WIN_SWSE,
+	       map_addrspace_size_to_wse(subwin_size));
+
+	set_bf(paace->impl_attr, PAACE_IA_ATM, PAACE_ATM_WINDOW_XLATE);
+	paace->twbah = rpn >> 20;
+	set_bf(paace->win_bitfields, PAACE_WIN_TWBAL, rpn);
+	set_bf(paace->addr_bitfields, PAACE_AF_AP, prot);
+
+	/* configure snoop id */
+	if (~snoopid != 0)
+		paace->domain_attr.to_host.snpid = snoopid;
+
+	/* set up operation mapping if it's configured */
+	if (omi < OME_NUMBER_ENTRIES) {
+		set_bf(paace->impl_attr, PAACE_IA_OTM, PAACE_OTM_INDEXED);
+		paace->op_encode.index_ot.omi = omi;
+	} else if (~omi != 0) {
+		pr_err("bad operation mapping index: %d\n", omi);
+		return -EINVAL;
+	}
+
+	if (~stashid != 0)
+		set_bf(paace->impl_attr, PAACE_IA_CID, stashid);
+
+	smp_wmb();
+
+	if (enable)
+		paace->addr_bitfields |= PAACE_V_VALID;
+
+	mb();
+
+	return 0;
+}
+
+/**
+* get_ome_index() - Returns the index in the operation mapping table
+*                   for device.
+* @*omi_index: pointer for storing the index value
+*
+*/
+void get_ome_index(u32 *omi_index, struct device *dev)
+{
+	if (of_device_is_compatible(dev->of_node, "fsl,qman-portal"))
+		*omi_index = OMI_QMAN;
+	if (of_device_is_compatible(dev->of_node, "fsl,qman"))
+		*omi_index = OMI_QMAN_PRIV;
+}
+
+/**
+ * get_stash_id - Returns stash destination id corresponding to a
+ *                cache type and vcpu.
+ * @stash_dest_hint: L1, L2 or L3
+ * @vcpu: vpcu target for a particular cache type.  
+ *
+ * Returs stash on success or ~(u32)0 on failure.
+ *
+ */
+u32 get_stash_id(u32 stash_dest_hint, u32 vcpu)
+{
+	const u32 *prop;
+	struct device_node *node;
+	u32 cache_level;
+	int len;
+
+	/* Fastpath, exit early if L3/CPC cache is target for stashing */
+	if (stash_dest_hint == IOMMU_ATTR_CACHE_L3) {
+		node = of_find_compatible_node(NULL, NULL,
+				"fsl,p4080-l3-cache-controller");
+		if (node) {
+			prop = of_get_property(node, "cache-stash-id", 0);
+			if (!prop) {
+				pr_err("missing cache-stash-id at %s\n", node->full_name);
+				of_node_put(node);
+				return ~(u32)0;
+			}
+			of_node_put(node);
+			return be32_to_cpup(prop);
+		}
+		return ~(u32)0;
+	}
+
+	for_each_node_by_type(node, "cpu") {
+		prop = of_get_property(node, "reg", &len);
+		if (be32_to_cpup(prop) == vcpu)
+			break;
+	}
+
+	/* find the hwnode that represents the cache */
+	for (cache_level = IOMMU_ATTR_CACHE_L1; cache_level < IOMMU_ATTR_CACHE_L3; cache_level++) {
+		if (stash_dest_hint == cache_level) {
+			prop = of_get_property(node, "cache-stash-id", 0);
+			if (!prop) {
+				pr_err("missing cache-stash-id at %s\n", node->full_name);
+				of_node_put(node);
+				return ~(u32)0;
+			}
+			of_node_put(node);
+			return be32_to_cpup(prop);
+		}
+
+		prop = of_get_property(node, "next-level-cache", 0);
+		if (!prop) {
+			pr_err("can't find next-level-cache at %s\n",
+			          node->full_name);
+			of_node_put(node);
+			return ~(u32)0;  /* can't traverse any further */
+		}
+		of_node_put(node);
+
+		/* advance to next node in cache hierarchy */
+		node = of_find_node_by_phandle(*prop);
+		if (!node) {
+			pr_err("Invalid node for cache hierarchy %s\n",
+				node->full_name);
+			return ~(u32)0;
+		}
+	}
+
+	pr_err("stash dest not found for %d on vcpu %d\n",
+	          stash_dest_hint, vcpu);
+	return ~(u32)0;
+}
+
+/* Identify if the PAACT table entry belongs to QMAN, BMAN or QMAN Portal */
+#define QMAN_PAACE 1
+#define QMAN_PORTAL_PAACE 2
+#define BMAN_PAACE 3
+
+/**
+ * Setup operation mapping and stash destinations for QMAN and QMAN portal.
+ * Memory accesses to QMAN and BMAN private memory need not be coherent, so
+ * clear the PAACE entry coherency attribute for them.
+ */
+static void setup_qbman_paace(struct paace *ppaace, int  paace_type)
+{
+	switch(paace_type) {
+		case QMAN_PAACE:
+			set_bf(ppaace->impl_attr, PAACE_IA_OTM, PAACE_OTM_INDEXED);
+			ppaace->op_encode.index_ot.omi = OMI_QMAN_PRIV;
+			/* setup QMAN Private data stashing for the L3 cache */
+			set_bf(ppaace->impl_attr, PAACE_IA_CID, get_stash_id(IOMMU_ATTR_CACHE_L3, 0));
+			set_bf(ppaace->domain_attr.to_host.coherency_required, PAACE_DA_HOST_CR,
+			       0);
+			break;
+		case QMAN_PORTAL_PAACE:
+			set_bf(ppaace->impl_attr, PAACE_IA_OTM, PAACE_OTM_INDEXED);
+			ppaace->op_encode.index_ot.omi = OMI_QMAN;
+			/*Set DQRR and Frame stashing for the L3 cache */
+			set_bf(ppaace->impl_attr, PAACE_IA_CID, get_stash_id(IOMMU_ATTR_CACHE_L3, 0));
+			break;
+		case BMAN_PAACE:
+			set_bf(ppaace->domain_attr.to_host.coherency_required, PAACE_DA_HOST_CR,
+			       0);
+			break;
+	}
+}
+
+/**
+ * Setup the operation mapping table for various devices. This is a static
+ * table where each table index corresponds to a particular device. PAMU uses
+ * this table to translate device transaction to appropriate corenet
+ * transaction.
+ */
+static void __init setup_omt(struct ome *omt)
+{
+	struct ome *ome;
+
+	/* Configure OMI_QMAN */
+	ome = &omt[OMI_QMAN];
+
+	ome->moe[IOE_READ_IDX] = EOE_VALID | EOE_READ;
+	ome->moe[IOE_EREAD0_IDX] = EOE_VALID | EOE_RSA;
+	ome->moe[IOE_WRITE_IDX] = EOE_VALID | EOE_WRITE;
+	ome->moe[IOE_EWRITE0_IDX] = EOE_VALID | EOE_WWSAO;
+
+	ome->moe[IOE_DIRECT0_IDX] = EOE_VALID | EOE_LDEC;
+	ome->moe[IOE_DIRECT1_IDX] = EOE_VALID | EOE_LDECPE;
+
+	/* Configure OMI_FMAN */
+	ome = &omt[OMI_FMAN];
+	ome->moe[IOE_READ_IDX]  = EOE_VALID | EOE_READI;
+	ome->moe[IOE_WRITE_IDX] = EOE_VALID | EOE_WRITE;
+
+	/* Configure OMI_QMAN private */
+	ome = &omt[OMI_QMAN_PRIV];
+	ome->moe[IOE_READ_IDX]  = EOE_VALID | EOE_READ;
+	ome->moe[IOE_WRITE_IDX] = EOE_VALID | EOE_WRITE;
+	ome->moe[IOE_EREAD0_IDX] = EOE_VALID | EOE_RSA;
+	ome->moe[IOE_EWRITE0_IDX] = EOE_VALID | EOE_WWSA;
+
+	/* Configure OMI_CAAM */
+	ome = &omt[OMI_CAAM];
+	ome->moe[IOE_READ_IDX]  = EOE_VALID | EOE_READI;
+	ome->moe[IOE_WRITE_IDX] = EOE_VALID | EOE_WRITE;
+}
+
+/* Setup PAMU registers pointing to PAACT, SPAACT and OMT */
+int setup_one_pamu(unsigned long pamu_reg_base, unsigned long pamu_reg_size,
+	           phys_addr_t ppaact_phys, phys_addr_t spaact_phys,
+		   phys_addr_t omt_phys)
+{
+	u32 *pc;
+	struct pamu_mmap_regs *pamu_regs;
+	u32 pc3_val;
+
+	pc3_val = in_be32((u32 *)(pamu_reg_base + PAMU_PC3));
+	max_subwindow_count = 1 << (1 + PAMU_PC3_MWCE(pc3_val));
+
+	pc = (u32 *) (pamu_reg_base + PAMU_PC);
+	pamu_regs = (struct pamu_mmap_regs *)
+		(pamu_reg_base + PAMU_MMAP_REGS_BASE);
+
+	/* set up pointers to corenet control blocks */
+
+	out_be32(&pamu_regs->ppbah, upper_32_bits(ppaact_phys));
+	out_be32(&pamu_regs->ppbal, lower_32_bits(ppaact_phys));
+	ppaact_phys = ppaact_phys + PAACT_SIZE;
+	out_be32(&pamu_regs->pplah, upper_32_bits(ppaact_phys));
+	out_be32(&pamu_regs->pplal, lower_32_bits(ppaact_phys));
+
+	out_be32(&pamu_regs->spbah, upper_32_bits(spaact_phys));
+	out_be32(&pamu_regs->spbal, lower_32_bits(spaact_phys));
+	spaact_phys = spaact_phys + SPAACT_SIZE;
+	out_be32(&pamu_regs->splah, upper_32_bits(spaact_phys));
+	out_be32(&pamu_regs->splal, lower_32_bits(spaact_phys));
+
+	out_be32(&pamu_regs->obah, upper_32_bits(omt_phys));
+	out_be32(&pamu_regs->obal, lower_32_bits(omt_phys));
+	omt_phys = omt_phys + OMT_SIZE;
+	out_be32(&pamu_regs->olah, upper_32_bits(omt_phys));
+	out_be32(&pamu_regs->olal, lower_32_bits(omt_phys));
+
+	/*
+	 * set PAMU enable bit,
+	 * allow ppaact & omt to be cached
+	 * & enable PAMU access violation interrupts.
+	 */
+
+	out_be32((u32 *)(pamu_reg_base + PAMU_PICS),
+			PAMU_ACCESS_VIOLATION_ENABLE);
+	out_be32(pc, PAMU_PC_PE | PAMU_PC_OCE | PAMU_PC_SPCC | PAMU_PC_PPCC);
+	return 0;
+}
+
+/* Enable all device LIODNS */
+static void __init setup_liodns(void)
+{
+	int i, len;
+	struct paace *ppaace;
+	struct device_node *node = NULL;
+	const u32 *prop;
+
+	for_each_node_with_property(node, "fsl,liodn") {
+		prop = of_get_property(node, "fsl,liodn", &len);
+		for (i = 0; i < len / sizeof(u32); i++) {
+			int liodn;
+
+			liodn = be32_to_cpup(&prop[i]);
+			ppaace = pamu_get_ppaace(liodn);
+			pamu_setup_default_xfer_to_host_ppaace(ppaace);
+			/* window size is 2^(WSE+1) bytes */
+			set_bf(ppaace->addr_bitfields, PPAACE_AF_WSE, 35);
+			ppaace->wbah = 0;
+			set_bf(ppaace->addr_bitfields, PPAACE_AF_WBAL, 0);
+			set_bf(ppaace->impl_attr, PAACE_IA_ATM,
+				PAACE_ATM_NO_XLATE);
+			set_bf(ppaace->addr_bitfields, PAACE_AF_AP, 
+				PAACE_AP_PERMS_ALL);
+			if (of_device_is_compatible(node, "fsl,qman-portal"))
+				setup_qbman_paace(ppaace, QMAN_PORTAL_PAACE);
+			if (of_device_is_compatible(node, "fsl,qman"))
+				setup_qbman_paace(ppaace, QMAN_PAACE);
+			if (of_device_is_compatible(node, "fsl,bman"))
+				setup_qbman_paace(ppaace, BMAN_PAACE);
+			mb();
+			pamu_enable_liodn(liodn);
+		}
+	}
+}
+
+/* TBD: PAMU access violation interrupt handler */
+irqreturn_t pamu_av_isr(int irq, void *arg)
+{
+	panic("FSL_PAMU: access violation interrupt\n");
+	/* NOTREACHED */
+
+	return IRQ_HANDLED;
+}
+
+#define LAWAR_EN		0x80000000
+#define LAWAR_TARGET_MASK	0x0FF00000
+#define LAWAR_TARGET_SHIFT	20
+#define LAWAR_SIZE_MASK		0x0000003F
+#define LAWAR_CSDID_MASK	0x000FF000
+#define LAWAR_CSDID_SHIFT	12
+
+#define LAW_SIZE_4K		0xb
+
+struct ccsr_law {
+	u32	lawbarh;	/* LAWn base address high */
+	u32	lawbarl;	/* LAWn base address low */
+	u32	lawar;		/* LAWn attributes */
+	u32	reserved;
+};
+
+#define make64(high, low) (((u64)(high) << 32) | (low))
+
+/*
+ * Create a coherence subdomain for a given memory block.
+ */
+static int __init create_csd(phys_addr_t phys, size_t size, u32 csd_port_id)
+{
+	struct device_node *np;
+	const __be32 *iprop;
+	void __iomem *lac = NULL;	/* Local Access Control registers */
+	struct ccsr_law __iomem *law;
+	void __iomem *ccm = NULL;
+	u32 __iomem *csdids;
+	unsigned int i, num_laws, num_csds;
+	u32 law_target = 0;
+	u32 csd_id = 0;
+	int ret = 0;
+
+	np = of_find_compatible_node(NULL, NULL, "fsl,corenet-law");
+	if (!np)
+		return -ENODEV;
+
+	iprop = of_get_property(np, "fsl,num-laws", NULL);
+	if (!iprop) {
+		ret = -ENODEV;
+		goto error;
+	}
+
+	num_laws = be32_to_cpup(iprop);
+	if (!num_laws) {
+		ret = -ENODEV;
+		goto error;
+	}
+
+	lac = of_iomap(np, 0);
+	if (!lac) {
+		ret = -ENODEV;
+		goto error;
+	}
+
+	/* LAW registers are at offset 0xC00 */
+	law = lac + 0xC00;
+
+	of_node_put(np);
+
+	np = of_find_compatible_node(NULL, NULL, "fsl,corenet-cf");
+	if (!np) {
+		ret = -ENODEV;
+		goto error;
+	}
+
+	iprop = of_get_property(np, "fsl,ccf-num-csdids", NULL);
+	if (!iprop) {
+		ret = -ENODEV;
+		goto error;
+	}
+
+	num_csds = be32_to_cpup(iprop);
+	if (!num_csds) {
+		ret = -ENODEV;
+		goto error;
+	}
+
+	ccm = of_iomap(np, 0);
+	if (!ccm) {
+		ret = -ENOMEM;
+		goto error;
+	}
+
+	/* The undocumented CSDID registers are at offset 0x600 */
+	csdids = ccm + 0x600;
+
+	of_node_put(np);
+	np = NULL;
+
+	/* Find an unused coherence subdomain ID */
+	for (csd_id = 0; csd_id < num_csds; csd_id++) {
+		if (!csdids[csd_id])
+			break;
+	}
+
+	/* Store the Port ID in the (undocumented) proper CIDMRxx register */
+	csdids[csd_id] = csd_port_id;
+
+	/* Find the DDR LAW that maps to our buffer. */
+	for (i = 0; i < num_laws; i++) {
+		if (law[i].lawar & LAWAR_EN) {
+			phys_addr_t law_start, law_end;
+
+			law_start = make64(law[i].lawbarh, law[i].lawbarl);
+			law_end = law_start +
+				(2ULL << (law[i].lawar & LAWAR_SIZE_MASK));
+
+			if (law_start <= phys && phys < law_end) {
+				law_target = law[i].lawar & LAWAR_TARGET_MASK;
+				break;
+			}
+		}
+	}
+
+	if (i == 0 || i == num_laws) {
+		/* This should never happen*/
+		ret = -ENOENT;
+		goto error;
+	}
+
+	/* Find a free LAW entry */
+	while (law[--i].lawar & LAWAR_EN) {
+		if (i == 0) {
+			/* No higher priority LAW slots available */
+			ret = -ENOENT;
+			goto error;
+		}
+	}
+
+	law[i].lawbarh = upper_32_bits(phys);
+	law[i].lawbarl = lower_32_bits(phys);
+	wmb();
+	law[i].lawar = LAWAR_EN | law_target | (csd_id << LAWAR_CSDID_SHIFT) |
+		(LAW_SIZE_4K + get_order(size));
+	wmb();
+
+error:
+	if (ccm)
+		iounmap(ccm);
+
+	if (lac)
+		iounmap(lac);
+
+	if (np)
+		of_node_put(np);
+
+	return ret;
+}
+
+/*
+ * Table of SVRs and the corresponding PORT_ID values.
+ *
+ * All future CoreNet-enabled SOCs will have this erratum fixed, so this table
+ * should never need to be updated.  SVRs are guaranteed to be unique, so
+ * there is no worry that a future SOC will inadvertently have one of these
+ * values.
+ */
+static const struct {
+	u32 svr;
+	u32 port_id;
+} port_id_map[] = {
+	{0x82100010, 0xFF000000},	/* P2040 1.0 */
+	{0x82100011, 0xFF000000},	/* P2040 1.1 */
+	{0x82100110, 0xFF000000},	/* P2041 1.0 */
+	{0x82100111, 0xFF000000},	/* P2041 1.1 */
+	{0x82110310, 0xFF000000},	/* P3041 1.0 */
+	{0x82110311, 0xFF000000},	/* P3041 1.1 */
+	{0x82010020, 0xFFF80000},	/* P4040 2.0 */
+	{0x82000020, 0xFFF80000},	/* P4080 2.0 */
+	{0x82210010, 0xFC000000},       /* P5010 1.0 */
+	{0x82210020, 0xFC000000},       /* P5010 2.0 */
+	{0x82200010, 0xFC000000},	/* P5020 1.0 */
+	{0x82050010, 0xFF800000},	/* P5021 1.0 */
+	{0x82040010, 0xFF800000},	/* P5040 1.0 */
+};
+
+#define SVR_SECURITY	0x80000	/* The Security (E) bit */
+
+static int __init fsl_pamu_probe(struct platform_device *pdev)
+{
+	void __iomem *pamu_regs = NULL;
+	struct ccsr_guts __iomem *guts_regs = NULL;
+	u32 pamubypenr, pamu_counter;
+	unsigned long pamu_reg_off;
+	unsigned long pamu_reg_base;
+	struct device_node *guts_node;
+	u64 size;
+	struct page *p;
+	int ret = 0;
+	int irq;
+	phys_addr_t ppaact_phys;
+	phys_addr_t spaact_phys;
+	phys_addr_t omt_phys;
+	size_t mem_size = 0;
+	unsigned int order = 0;
+	u32 csd_port_id = 0;
+	unsigned i;
+	/*
+	 * enumerate all PAMUs and allocate and setup PAMU tables
+	 * for each of them,
+	 * NOTE : All PAMUs share the same LIODN tables.
+	 */
+
+	pamu_regs = of_iomap(pdev->dev.of_node, 0);
+	if (!pamu_regs) {
+		dev_err(&pdev->dev, "ioremap of PAMU node failed\n");
+		return -ENOMEM;
+	}
+	of_get_address(pdev->dev.of_node, 0, &size, NULL);
+
+	irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
+	if (irq == NO_IRQ) {
+		dev_warn(&pdev->dev, "no interrupts listed in PAMU node\n");
+		goto error;
+	}
+
+	ret = request_irq(irq, pamu_av_isr, IRQF_DISABLED, "pamu", NULL);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "error %i installing ISR for irq %i\n",
+			ret, irq);
+		goto error;
+	}
+
+	guts_node = of_find_compatible_node(NULL, NULL,
+			"fsl,qoriq-device-config-1.0");
+	if (!guts_node) {
+		dev_err(&pdev->dev, "could not find GUTS node %s\n",
+			pdev->dev.of_node->full_name);
+		ret = -ENODEV;
+		goto error;
+	}
+
+	guts_regs = of_iomap(guts_node, 0);
+	of_node_put(guts_node);
+	if (!guts_regs) {
+		dev_err(&pdev->dev, "ioremap of GUTS node failed\n");
+		ret = -ENODEV;
+		goto error;
+	}
+
+	/*
+	 * To simplify the allocation of a coherency domain, we allocate the
+	 * PAACT and the OMT in the same memory buffer.  Unfortunately, this
+	 * wastes more memory compared to allocating the buffers separately.
+	 */
+
+	/* Determine how much memory we need */
+	mem_size = (PAGE_SIZE << get_order(PAACT_SIZE)) +
+		(PAGE_SIZE << get_order(SPAACT_SIZE)) +
+		(PAGE_SIZE << get_order(OMT_SIZE));
+	order = get_order(mem_size);
+
+	p = alloc_pages(GFP_KERNEL | __GFP_ZERO, order);
+	if (!p) {
+		dev_err(&pdev->dev, "unable to allocate PAACT/SPAACT/OMT block\n");
+		ret = -ENOMEM;
+		goto error;
+	}
+
+	ppaact = page_address(p);
+	ppaact_phys = page_to_phys(p);
+
+	/* Make sure the memory is naturally aligned */
+	if (ppaact_phys & ((PAGE_SIZE << order) - 1)) {
+		dev_err(&pdev->dev, "PAACT/OMT block is unaligned\n");
+		ret = -ENOMEM;
+		goto error;
+	}
+
+	spaact = (void *)ppaact + (PAGE_SIZE << get_order(PAACT_SIZE));
+	omt = (void *)spaact + (PAGE_SIZE << get_order(SPAACT_SIZE));
+
+	dev_dbg(&pdev->dev, "ppaact virt=%p phys=0x%llx\n", ppaact,
+		(unsigned long long) ppaact_phys);
+
+	/* Check to see if we need to implement the work-around on this SOC */
+
+	/* Determine the Port ID for our coherence subdomain */
+	for (i = 0; i < ARRAY_SIZE(port_id_map); i++) {
+		if (port_id_map[i].svr == (mfspr(SPRN_SVR) & ~SVR_SECURITY)) {
+			csd_port_id = port_id_map[i].port_id;
+			dev_dbg(&pdev->dev, "found matching SVR %08x\n",
+				port_id_map[i].svr);
+			break;
+		}
+	}
+
+	if (csd_port_id) {
+		dev_dbg(&pdev->dev, "creating coherency subdomain at address "
+			"0x%llx, size %zu, port id 0x%08x", ppaact_phys,
+			mem_size, csd_port_id);
+
+		ret = create_csd(ppaact_phys, mem_size, csd_port_id);
+		if (ret) {
+			dev_err(&pdev->dev, "could not create coherence "
+				"subdomain\n");
+			return ret;
+		}
+	}
+
+	spaact_phys = virt_to_phys(spaact);
+	omt_phys = virt_to_phys(omt);
+
+	spaace_pool = gen_pool_create(ilog2(sizeof(struct paace)), -1);
+	if (!spaace_pool) {
+		ret = -ENOMEM;
+		dev_err(&pdev->dev, "PAMU : failed to allocate spaace gen pool\n");
+		goto error;
+	}
+
+	ret = gen_pool_add(spaace_pool, (unsigned long)spaact, SPAACT_SIZE, -1);
+	if (ret)
+		goto error_genpool;
+
+	pamubypenr = in_be32(&guts_regs->pamubypenr);
+
+	for (pamu_reg_off = 0, pamu_counter = 0x80000000; pamu_reg_off < size;
+	     pamu_reg_off += PAMU_OFFSET, pamu_counter >>= 1) {
+
+		pamu_reg_base = (unsigned long) pamu_regs + pamu_reg_off;
+		setup_one_pamu(pamu_reg_base, pamu_reg_off, ppaact_phys,
+				 spaact_phys, omt_phys);
+		/* Disable PAMU bypass for this PAMU */
+		pamubypenr &= ~pamu_counter;
+	}
+
+	setup_omt(omt);
+
+	/* Enable all relevant PAMU(s) */
+	out_be32(&guts_regs->pamubypenr, pamubypenr);
+
+	iounmap(pamu_regs);
+	iounmap(guts_regs);
+
+	/* Enable DMA for the LIODNs in the device tree*/
+
+	setup_liodns();
+
+	return 0;
+
+error_genpool:
+	gen_pool_destroy(spaace_pool);
+
+error:
+	if (irq != NO_IRQ)
+		free_irq(irq, 0);
+
+	if (pamu_regs)
+		iounmap(pamu_regs);
+
+	if (guts_regs)
+		iounmap(guts_regs);
+
+	if (ppaact)
+		free_pages((unsigned long)ppaact, order);
+
+	ppaact = NULL;
+
+	return ret;
+}
+
+static const struct of_device_id fsl_of_pamu_ids[] = {
+	{
+		.compatible = "fsl,p4080-pamu",
+	},
+	{
+		.compatible = "fsl,pamu",
+	},
+	{},
+};
+
+static struct platform_driver fsl_of_pamu_driver = {
+	.driver = {
+		.name = "fsl-of-pamu",
+		.owner = THIS_MODULE,
+	},
+	.probe = fsl_pamu_probe,
+};
+
+static __init int fsl_pamu_init(void)
+{
+	struct platform_device *pdev = NULL;
+	struct device_node *np;
+	int ret;
+
+	/*
+	 * The normal OF process calls the probe function at some
+	 * indeterminate later time, after most drivers have loaded.  This is
+	 * too late for us, because PAMU clients (like the Qman driver)
+	 * depend on PAMU being initialized early.
+	 *
+	 * So instead, we "manually" call our probe function by creating the
+	 * platform devices ourselves.
+	 */
+
+	/*
+	 * We assume that there is only one PAMU node in the device tree.  A
+	 * single PAMU node represents all of the PAMU devices in the SOC
+	 * already.   Everything else already makes that assumption, and the
+	 * binding for the PAMU nodes doesn't allow for any parent-child
+	 * relationships anyway.  In other words, support for more than one
+	 * PAMU node would require significant changes to a lot of code.
+	 */
+
+	np = of_find_compatible_node(NULL, NULL, "fsl,pamu");
+	if (!np) {
+		pr_err("fsl-pamu: could not find a PAMU node\n");
+		return -ENODEV;
+	}
+
+	ret = platform_driver_register(&fsl_of_pamu_driver);
+	if (ret) {
+		pr_err("fsl-pamu: could not register driver (err=%i)\n", ret);
+		goto error_driver_register;
+	}
+
+	pdev = platform_device_alloc("fsl-of-pamu", 0);
+	if (!pdev) {
+		pr_err("fsl-pamu: could not allocate device %s\n",
+		       np->full_name);
+		ret = -ENOMEM;
+		goto error_device_alloc;
+	}
+	pdev->dev.of_node = of_node_get(np);
+
+	ret = pamu_domain_init();
+	if (ret)
+		goto error_device_add;
+
+	ret = platform_device_add(pdev);
+	if (ret) {
+		pr_err("fsl-pamu: could not add device %s (err=%i)\n",
+		       np->full_name, ret);
+		goto error_device_add;
+	}
+
+	return 0;
+
+error_device_add:
+	of_node_put(pdev->dev.of_node);
+	pdev->dev.of_node = NULL;
+
+	platform_device_put(pdev);
+
+error_device_alloc:
+	platform_driver_unregister(&fsl_of_pamu_driver);
+
+error_driver_register:
+	of_node_put(np);
+
+	return ret;
+}
+subsys_initcall(fsl_pamu_init);
diff --git a/drivers/iommu/fsl_pamu.h b/drivers/iommu/fsl_pamu.h
new file mode 100644
index 0000000..6d32fb5
--- /dev/null
+++ b/drivers/iommu/fsl_pamu.h
@@ -0,0 +1,398 @@
+/*
+ * 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 (C) 2012 Freescale Semiconductor, Inc.
+ *
+ */
+
+#ifndef __FSL_PAMU_H
+#define __FSL_PAMU_H
+
+/* Bit Field macros
+ * 	v = bit field variable; m = mask, m##_SHIFT = shift, x = value to load
+ */
+#define set_bf(v, m, x)		(v = ((v) & ~(m)) | (((x) << (m##_SHIFT)) & (m)))
+#define get_bf(v, m)		(((v) & (m)) >> (m##_SHIFT))
+
+/* PAMU CCSR space */
+#define PAMU_PGC 0x00000000     /* Allows all peripheral accesses */
+#define PAMU_PE 0x40000000      /* enable PAMU                    */
+
+/* PAMU_OFFSET to the next pamu space in ccsr */
+#define PAMU_OFFSET 0x1000
+
+#define PAMU_MMAP_REGS_BASE 0
+
+struct pamu_mmap_regs {
+	u32 ppbah;
+	u32 ppbal;
+	u32 pplah;
+	u32 pplal;
+	u32 spbah;
+	u32 spbal;
+	u32 splah;
+	u32 splal;
+	u32 obah;
+	u32 obal;
+	u32 olah;
+	u32 olal;
+};
+
+/* PAMU Error Registers */
+#define PAMU_POES1 0x0040
+#define PAMU_POES2 0x0044
+#define PAMU_POEAH 0x0048
+#define PAMU_POEAL 0x004C
+#define PAMU_AVS1  0x0050
+#define PAMU_AVS1_AV    0x1
+#define PAMU_AVS1_OTV   0x6
+#define PAMU_AVS1_APV   0x78
+#define PAMU_AVS1_WAV   0x380
+#define PAMU_AVS1_LAV   0x1c00
+#define PAMU_AVS1_GCV   0x2000
+#define PAMU_AVS1_PDV   0x4000
+#define PAMU_AV_MASK    (PAMU_AVS1_AV | PAMU_AVS1_OTV | PAMU_AVS1_APV | PAMU_AVS1_WAV \
+			| PAMU_AVS1_LAV | PAMU_AVS1_GCV | PAMU_AVS1_PDV)
+#define PAMU_AVS1_LIODN_SHIFT 16
+#define PAMU_LAV_LIODN_NOT_IN_PPAACT 0x400
+
+#define PAMU_AVS2  0x0054
+#define PAMU_AVAH  0x0058
+#define PAMU_AVAL  0x005C
+#define PAMU_EECTL 0x0060
+#define PAMU_EEDIS 0x0064
+#define PAMU_EEINTEN 0x0068
+#define PAMU_EEDET 0x006C
+#define PAMU_EEATTR 0x0070
+#define PAMU_EEAHI 0x0074
+#define PAMU_EEALO 0x0078
+#define PAMU_EEDHI 0X007C
+#define PAMU_EEDLO 0x0080
+#define PAMU_EECC  0x0084
+
+/* PAMU Revision Registers */
+#define PAMU_PR1 0x0BF8
+#define PAMU_PR2 0x0BFC
+
+/* PAMU Capabilities Registers */
+#define PAMU_PC1 0x0C00
+#define PAMU_PC2 0x0C04
+#define PAMU_PC3 0x0C08
+#define PAMU_PC4 0x0C0C
+
+/* PAMU Control Register */
+#define PAMU_PC 0x0C10
+
+/* PAMU control defs */
+#define PAMU_CONTROL 0x0C10
+#define PAMU_PC_PGC 0x80000000  /* PAMU gate closed bit */
+#define PAMU_PC_PE   0x40000000 /* PAMU enable bit */
+#define PAMU_PC_SPCC 0x00000010 /* sPAACE cache enable */
+#define PAMU_PC_PPCC 0x00000001 /* pPAACE cache enable */
+#define PAMU_PC_OCE  0x00001000 /* OMT cache enable */
+
+#define PAMU_PFA1 0x0C14
+#define PAMU_PFA2 0x0C18
+
+#define PAMU_PC3_MWCE(X) (((X) >> 21) & 0xf)
+
+/* PAMU Interrupt control and Status Register */
+#define PAMU_PICS 0x0C1C
+#define PAMU_ACCESS_VIOLATION_STAT   0x8
+#define PAMU_ACCESS_VIOLATION_ENABLE 0x4
+
+/* PAMU Debug Registers */
+#define PAMU_PD1 0x0F00
+#define PAMU_PD2 0x0F04
+#define PAMU_PD3 0x0F08
+#define PAMU_PD4 0x0F0C
+
+#define PAACE_AP_PERMS_DENIED  0x0
+#define PAACE_AP_PERMS_QUERY   0x1
+#define PAACE_AP_PERMS_UPDATE  0x2
+#define PAACE_AP_PERMS_ALL     0x3
+
+#define PAACE_DD_TO_HOST       0x0
+#define PAACE_DD_TO_IO         0x1
+#define PAACE_PT_PRIMARY       0x0
+#define PAACE_PT_SECONDARY     0x1
+#define PAACE_V_INVALID        0x0
+#define PAACE_V_VALID          0x1
+#define PAACE_MW_SUBWINDOWS    0x1
+
+#define PAACE_WSE_4K           0xB
+#define PAACE_WSE_8K           0xC
+#define PAACE_WSE_16K          0xD
+#define PAACE_WSE_32K          0xE
+#define PAACE_WSE_64K          0xF
+#define PAACE_WSE_128K         0x10
+#define PAACE_WSE_256K         0x11
+#define PAACE_WSE_512K         0x12
+#define PAACE_WSE_1M           0x13
+#define PAACE_WSE_2M           0x14
+#define PAACE_WSE_4M           0x15
+#define PAACE_WSE_8M           0x16
+#define PAACE_WSE_16M          0x17
+#define PAACE_WSE_32M          0x18
+#define PAACE_WSE_64M          0x19
+#define PAACE_WSE_128M         0x1A
+#define PAACE_WSE_256M         0x1B
+#define PAACE_WSE_512M         0x1C
+#define PAACE_WSE_1G           0x1D
+#define PAACE_WSE_2G           0x1E
+#define PAACE_WSE_4G           0x1F
+
+#define PAACE_DID_PCI_EXPRESS_1 0x00
+#define PAACE_DID_PCI_EXPRESS_2 0x01
+#define PAACE_DID_PCI_EXPRESS_3 0x02
+#define PAACE_DID_PCI_EXPRESS_4 0x03
+#define PAACE_DID_LOCAL_BUS     0x04
+#define PAACE_DID_SRIO          0x0C
+#define PAACE_DID_MEM_1         0x10
+#define PAACE_DID_MEM_2         0x11
+#define PAACE_DID_MEM_3         0x12
+#define PAACE_DID_MEM_4         0x13
+#define PAACE_DID_MEM_1_2       0x14
+#define PAACE_DID_MEM_3_4       0x15
+#define PAACE_DID_MEM_1_4       0x16
+#define PAACE_DID_BM_SW_PORTAL  0x18
+#define PAACE_DID_PAMU          0x1C
+#define PAACE_DID_CAAM          0x21
+#define PAACE_DID_QM_SW_PORTAL  0x3C
+#define PAACE_DID_CORE0_INST    0x80
+#define PAACE_DID_CORE0_DATA    0x81
+#define PAACE_DID_CORE1_INST    0x82
+#define PAACE_DID_CORE1_DATA    0x83
+#define PAACE_DID_CORE2_INST    0x84
+#define PAACE_DID_CORE2_DATA    0x85
+#define PAACE_DID_CORE3_INST    0x86
+#define PAACE_DID_CORE3_DATA    0x87
+#define PAACE_DID_CORE4_INST    0x88
+#define PAACE_DID_CORE4_DATA    0x89
+#define PAACE_DID_CORE5_INST    0x8A
+#define PAACE_DID_CORE5_DATA    0x8B
+#define PAACE_DID_CORE6_INST    0x8C
+#define PAACE_DID_CORE6_DATA    0x8D
+#define PAACE_DID_CORE7_INST    0x8E
+#define PAACE_DID_CORE7_DATA    0x8F
+#define PAACE_DID_BROADCAST     0xFF
+
+#define PAACE_ATM_NO_XLATE      0x00
+#define PAACE_ATM_WINDOW_XLATE  0x01
+#define PAACE_ATM_PAGE_XLATE    0x02
+#define PAACE_ATM_WIN_PG_XLATE  \
+                ( PAACE_ATM_WINDOW_XLATE | PAACE_ATM_PAGE_XLATE )
+#define PAACE_OTM_NO_XLATE      0x00
+#define PAACE_OTM_IMMEDIATE     0x01
+#define PAACE_OTM_INDEXED       0x02
+#define PAACE_OTM_RESERVED      0x03
+
+#define PAACE_M_COHERENCE_REQ   0x01
+
+#define PAACE_PID_0             0x0
+#define PAACE_PID_1             0x1
+#define PAACE_PID_2             0x2
+#define PAACE_PID_3             0x3
+#define PAACE_PID_4             0x4
+#define PAACE_PID_5             0x5
+#define PAACE_PID_6             0x6
+#define PAACE_PID_7             0x7
+
+#define PAACE_TCEF_FORMAT0_8B   0x00
+#define PAACE_TCEF_FORMAT1_RSVD 0x01
+
+#define PAACE_NUMBER_ENTRIES    0xFF
+
+#define	OME_NUMBER_ENTRIES      16
+
+#define SPAACE_NUMBER_ENTRIES   0x8000
+
+/* PAACE Bit Field Defines */
+#define PPAACE_AF_WBAL			0xfffff000
+#define PPAACE_AF_WBAL_SHIFT		12
+#define PPAACE_AF_WSE			0x00000fc0
+#define PPAACE_AF_WSE_SHIFT		6
+#define PPAACE_AF_MW			0x00000020
+#define PPAACE_AF_MW_SHIFT		5
+
+#define SPAACE_AF_LIODN			0xffff0000
+#define SPAACE_AF_LIODN_SHIFT		16
+
+#define PAACE_AF_AP			0x00000018
+#define PAACE_AF_AP_SHIFT		3
+#define PAACE_AF_DD			0x00000004
+#define PAACE_AF_DD_SHIFT		2
+#define PAACE_AF_PT			0x00000002
+#define PAACE_AF_PT_SHIFT		1
+#define PAACE_AF_V			0x00000001
+#define PAACE_AF_V_SHIFT		0
+
+#define PAACE_DA_HOST_CR		0x80
+#define PAACE_DA_HOST_CR_SHIFT		7
+
+#define PAACE_IA_CID			0x00FF0000
+#define PAACE_IA_CID_SHIFT		16
+#define PAACE_IA_WCE			0x000000F0
+#define PAACE_IA_WCE_SHIFT		4
+#define PAACE_IA_ATM			0x0000000C
+#define PAACE_IA_ATM_SHIFT		2
+#define PAACE_IA_OTM			0x00000003
+#define PAACE_IA_OTM_SHIFT		0
+
+#define PAACE_WIN_TWBAL			0xfffff000
+#define PAACE_WIN_TWBAL_SHIFT		12
+#define PAACE_WIN_SWSE			0x00000fc0
+#define PAACE_WIN_SWSE_SHIFT		6
+
+/* PAMU Data Structures */
+/* primary / secondary paact structure */
+struct paace {
+	/* PAACE Offset 0x00 */
+	u32 wbah;				/* only valid for Primary PAACE */
+	u32 addr_bitfields;		/* See P/S PAACE_AF_* */
+
+	/* PAACE Offset 0x08 */
+	/* Interpretation of first 32 bits dependent on DD above */
+	union {
+		struct {
+			/* Destination ID, see PAACE_DID_* defines */
+			u8 did;
+			/* Partition ID */
+			u8 pid;
+			/* Snoop ID */
+			u8 snpid;
+			/* coherency_required : 1 reserved : 7 */
+			u8 coherency_required; /* See PAACE_DA_* */
+		} to_host;
+		struct {
+			/* Destination ID, see PAACE_DID_* defines */
+			u8  did;
+			u8  reserved1;
+			u16 reserved2;
+		} to_io;
+	} domain_attr;
+
+	/* Implementation attributes + window count + address & operation translation modes */
+	u32 impl_attr;			/* See PAACE_IA_* */
+
+	/* PAACE Offset 0x10 */
+	/* Translated window base address */
+	u32 twbah;
+	u32 win_bitfields;			/* See PAACE_WIN_* */
+
+	/* PAACE Offset 0x18 */
+	/* first secondary paace entry */
+	u32 fspi;				/* only valid for Primary PAACE */
+	union {
+		struct {
+			u8 ioea;
+			u8 moea;
+			u8 ioeb;
+			u8 moeb;
+		} immed_ot;
+		struct {
+			u16 reserved;
+			u16 omi;
+		} index_ot;
+	} op_encode;
+
+	/* PAACE Offsets 0x20-0x38 */
+	u32 reserved[8];			/* not currently implemented */
+};
+
+/* OME : Operation mapping entry
+ * MOE : Mapped Operation Encodings
+ * The operation mapping table is table containing operation mapping entries (OME).
+ * The index of a particular OME is programmed in the PAACE entry for translation
+ * in bound I/O operations corresponding to an LIODN. The OMT is used for translation
+ * specifically in case of the indexed translation mode. Each OME contains a 128
+ * byte mapped operation encoding (MOE), where each byte represents an MOE. 
+ */
+#define NUM_MOE 128
+struct ome {
+	u8 moe[NUM_MOE];
+} __attribute__((packed));
+
+#define PAACT_SIZE              (sizeof(struct paace) * PAACE_NUMBER_ENTRIES)
+#define OMT_SIZE                (sizeof(struct ome) * OME_NUMBER_ENTRIES)
+#define SPAACT_SIZE             (sizeof(struct paace) * SPAACE_NUMBER_ENTRIES)
+
+#define PAMU_PAGE_SHIFT 12
+#define PAMU_PAGE_SIZE  4096ULL
+
+#define IOE_READ        0x00
+#define IOE_READ_IDX    0x00
+#define IOE_WRITE       0x81
+#define IOE_WRITE_IDX   0x01
+#define IOE_EREAD0      0x82    /* Enhanced read type 0 */
+#define IOE_EREAD0_IDX  0x02    /* Enhanced read type 0 */
+#define IOE_EWRITE0     0x83    /* Enhanced write type 0 */
+#define IOE_EWRITE0_IDX 0x03    /* Enhanced write type 0 */
+#define IOE_DIRECT0     0x84    /* Directive type 0 */
+#define IOE_DIRECT0_IDX 0x04    /* Directive type 0 */
+#define IOE_EREAD1      0x85    /* Enhanced read type 1 */
+#define IOE_EREAD1_IDX  0x05    /* Enhanced read type 1 */
+#define IOE_EWRITE1     0x86    /* Enhanced write type 1 */
+#define IOE_EWRITE1_IDX 0x06    /* Enhanced write type 1 */
+#define IOE_DIRECT1     0x87    /* Directive type 1 */
+#define IOE_DIRECT1_IDX 0x07    /* Directive type 1 */
+#define IOE_RAC         0x8c    /* Read with Atomic clear */
+#define IOE_RAC_IDX     0x0c    /* Read with Atomic clear */
+#define IOE_RAS         0x8d    /* Read with Atomic set */
+#define IOE_RAS_IDX     0x0d    /* Read with Atomic set */
+#define IOE_RAD         0x8e    /* Read with Atomic decrement */
+#define IOE_RAD_IDX     0x0e    /* Read with Atomic decrement */
+#define IOE_RAI         0x8f    /* Read with Atomic increment */
+#define IOE_RAI_IDX     0x0f    /* Read with Atomic increment */
+
+#define EOE_READ        0x00
+#define EOE_WRITE       0x01
+#define EOE_RAC         0x0c    /* Read with Atomic clear */
+#define EOE_RAS         0x0d    /* Read with Atomic set */
+#define EOE_RAD         0x0e    /* Read with Atomic decrement */
+#define EOE_RAI         0x0f    /* Read with Atomic increment */
+#define EOE_LDEC        0x10    /* Load external cache */
+#define EOE_LDECL       0x11    /* Load external cache with stash lock */
+#define EOE_LDECPE      0x12    /* Load external cache with preferred exclusive */
+#define EOE_LDECPEL     0x13    /* Load external cache with preferred exclusive and lock */
+#define EOE_LDECFE      0x14    /* Load external cache with forced exclusive */
+#define EOE_LDECFEL     0x15    /* Load external cache with forced exclusive and lock */
+#define EOE_RSA         0x16    /* Read with stash allocate */
+#define EOE_RSAU        0x17    /* Read with stash allocate and unlock */
+#define EOE_READI       0x18    /* Read with invalidate */
+#define EOE_RWNITC      0x19    /* Read with no intention to cache */
+#define EOE_WCI         0x1a    /* Write cache inhibited */
+#define EOE_WWSA        0x1b    /* Write with stash allocate */
+#define EOE_WWSAL       0x1c    /* Write with stash allocate and lock */
+#define EOE_WWSAO       0x1d    /* Write with stash allocate only */
+#define EOE_WWSAOL      0x1e    /* Write with stash allocate only and lock */
+#define EOE_VALID       0x80
+
+/* Function prototypes */
+int pamu_domain_init(void);
+int pamu_enable_liodn(int liodn);
+int pamu_disable_liodn(int liodn);
+void pamu_free_subwins(int liodn);
+int pamu_config_ppaace(int liodn, phys_addr_t win_addr, phys_addr_t win_size,
+		       u32 omi, unsigned long rpn, u32 snoopid, uint32_t stashid,
+		       u32 subwin_cnt, int prot);
+int pamu_config_spaace(int liodn, u32 subwin_cnt, u32 subwin_addr,
+		       phys_addr_t subwin_size, u32 omi, unsigned long rpn,
+		       uint32_t snoopid, u32 stashid, int enable, int prot);
+
+u32 get_stash_id(u32 stash_dest_hint, u32 vcpu);
+void get_ome_index(u32 *omi_index, struct device *dev);
+int  pamu_update_paace_stash(int liodn, u32 subwin, u32 value);
+
+#endif  /* __FSL_PAMU_H */
diff --git a/drivers/iommu/fsl_pamu_domain.c b/drivers/iommu/fsl_pamu_domain.c
new file mode 100644
index 0000000..dd80373
--- /dev/null
+++ b/drivers/iommu/fsl_pamu_domain.c
@@ -0,0 +1,1033 @@
+/*
+ * 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 (C) 2012 Freescale Semiconductor, Inc.
+ * Author: Varun Sethi <varun.sethi@freescale.com>
+ *
+ */
+
+#define pr_fmt(fmt)    "fsl-pamu-domain: %s: " fmt, __func__
+
+#include <linux/init.h>
+#include <linux/iommu.h>
+#include <linux/notifier.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/of_platform.h>
+#include <linux/bootmem.h>
+#include <linux/err.h>
+#include <asm/io.h>
+#include <asm/bitops.h>
+
+#include "fsl_pamu_domain.h"
+
+/* This bitmap advertises the page sizes supported by PAMU hardware
+ * to the IOMMU API.
+ */
+#define FSL_PAMU_PGSIZES	(~0xFFFUL)
+
+/* global spinlock that needs to be held while
+ * configuring PAMU.
+ */
+static DEFINE_SPINLOCK(iommu_lock);
+
+static struct kmem_cache *fsl_pamu_domain_cache;
+static struct kmem_cache *iommu_devinfo_cache;
+static DEFINE_SPINLOCK(device_domain_lock);
+
+int __init iommu_init_mempool(void)
+{
+
+	fsl_pamu_domain_cache = kmem_cache_create("fsl_pamu_domain",
+					 sizeof(struct fsl_dma_domain),
+					 0,
+					 SLAB_HWCACHE_ALIGN,
+
+					 NULL);
+	if (!fsl_pamu_domain_cache) {
+		pr_err("Couldn't create fsl iommu_domain cache\n");
+		return -ENOMEM;
+	}
+
+	iommu_devinfo_cache = kmem_cache_create("iommu_devinfo",
+					 sizeof(struct device_domain_info),
+					 0,
+					 SLAB_HWCACHE_ALIGN,
+					 NULL);
+	if (!iommu_devinfo_cache) {
+		pr_err("Couldn't create devinfo cache\n");
+		kmem_cache_destroy(fsl_pamu_domain_cache);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+/* Update the domain sub window mappings */
+static void update_domain_subwin(struct fsl_dma_domain *dma_domain,
+				unsigned long iova, size_t size,
+				phys_addr_t paddr, int prot, int status)
+{
+	struct iommu_domain *domain = dma_domain->iommu_domain;
+	u32 subwin_cnt = dma_domain->subwin_cnt;
+	dma_addr_t geom_size = dma_domain->geom_size;
+	u32 subwin_size;
+	u32 mapped_subwin;
+	u32 mapped_subwin_cnt;
+	struct dma_subwindow *sub_win_ptr;
+	int i;
+
+	subwin_size = geom_size >> ilog2(subwin_cnt);
+	mapped_subwin = (iova - domain->geometry.aperture_start)
+				 >> ilog2(subwin_size);
+	sub_win_ptr = &dma_domain->sub_win_arr[mapped_subwin];
+	mapped_subwin_cnt = (size < subwin_size) ? 1 :
+				size >> ilog2(subwin_size);
+	for (i = 0; i < mapped_subwin_cnt; i++) {
+		if (status) {
+			sub_win_ptr[i].paddr = paddr;
+			sub_win_ptr[i].size = (size < subwin_size) ?
+						 size : subwin_size;
+			paddr += subwin_size;
+			sub_win_ptr[i].iova = iova;
+			iova += subwin_size;
+		}
+		sub_win_ptr[i].valid = status;
+		sub_win_ptr[i].prot = prot;
+	}
+
+	dma_domain->mapped_subwin = mapped_subwin;
+	dma_domain->mapped_subwin_cnt =  mapped_subwin_cnt;
+}
+
+static int reconfig_subwin(int liodn, struct fsl_dma_domain *dma_domain)
+{
+	u32 subwin_cnt = dma_domain->subwin_cnt;
+	int ret = 0;
+	u32 mapped_subwin;
+	u32 mapped_subwin_cnt;
+	struct dma_subwindow *sub_win_ptr;
+	unsigned long rpn;
+	int i;
+	bool enabled = 0;
+
+	mapped_subwin = dma_domain->mapped_subwin;
+	mapped_subwin_cnt = dma_domain->mapped_subwin_cnt;
+	sub_win_ptr = &dma_domain->sub_win_arr[mapped_subwin];
+
+	for (i = 0; i < mapped_subwin_cnt; i++) {
+		rpn = sub_win_ptr[i].paddr >> PAMU_PAGE_SHIFT;
+
+		if (mapped_subwin != 0 || dma_domain->enabled)
+			enabled = sub_win_ptr[i].valid;
+			
+	
+		spin_lock(&iommu_lock);
+		ret = pamu_config_spaace(liodn, subwin_cnt, mapped_subwin,
+					 sub_win_ptr[i].size,
+					 ~(u32)0, 
+					 rpn, dma_domain->snoop_id,
+					 dma_domain->stash_id, 
+					 enabled,
+					 sub_win_ptr[i].prot);
+		spin_unlock(&iommu_lock);
+		if (ret) {
+			pr_err("PAMU SPAACE configuration failed for liodn %d\n",liodn);
+			return ret;
+		}
+		mapped_subwin++;
+	}
+
+	return ret;
+}
+
+static phys_addr_t get_phys_addr(struct fsl_dma_domain *dma_domain, unsigned long iova)
+{
+	u32 subwin_cnt = dma_domain->subwin_cnt;
+
+	if (subwin_cnt) {
+		int i;
+		struct dma_subwindow *sub_win_ptr = 
+					&dma_domain->sub_win_arr[0];
+
+		for (i = 0; i < subwin_cnt; i++) {
+			if (sub_win_ptr[i].valid &&
+			    iova >= sub_win_ptr[i].iova &&
+			    iova < (sub_win_ptr[i].iova +
+			    sub_win_ptr[i].size - 1))
+				return (sub_win_ptr[i].paddr + (iova &
+					(sub_win_ptr[i].size - 1)));
+		}
+	} else {
+		return (dma_domain->paddr + (iova & (dma_domain->mapped_size - 1)));
+	}
+
+	return 0;
+}
+
+static int map_liodn_subwins(int liodn, struct fsl_dma_domain *dma_domain, u32 subwin_cnt)
+{
+	struct dma_subwindow *sub_win_ptr = 
+				&dma_domain->sub_win_arr[0];
+	int i, ret;
+	unsigned long rpn;
+
+	for (i = 0; i < subwin_cnt; i++) {
+		if (sub_win_ptr[i].valid) {
+			rpn = sub_win_ptr[i].paddr >>
+				 PAMU_PAGE_SHIFT;
+			spin_lock(&iommu_lock);
+			ret = pamu_config_spaace(liodn, subwin_cnt, i,
+						 sub_win_ptr[i].size,
+						 ~(u32)0,
+						 rpn,
+						 dma_domain->snoop_id,
+						 dma_domain->stash_id,
+						 (i > 0) ? 1 : 0,
+						 sub_win_ptr[i].prot);
+			spin_unlock(&iommu_lock);
+			if (ret) {
+				pr_err("PAMU SPAACE configuration failed for liodn %d\n",
+					 liodn);
+				return ret;
+			}
+		}
+	}
+
+	return ret;
+}
+
+static int map_liodn_win(int liodn, struct fsl_dma_domain *dma_domain)
+{
+	unsigned long rpn;
+	int ret;
+
+	rpn = dma_domain->paddr >> PAMU_PAGE_SHIFT;
+	spin_lock(&iommu_lock);
+	ret = pamu_config_ppaace(liodn, dma_domain->mapped_iova,
+				 dma_domain->mapped_size,
+				 ~(u32)0,
+				 rpn,
+				 dma_domain->snoop_id, dma_domain->stash_id,
+				 0, dma_domain->prot);
+	spin_unlock(&iommu_lock);
+	if (ret)
+		pr_err("PAMU PAACE configuration failed for liodn %d\n",
+			liodn);
+
+	return ret;
+}
+
+/* Map the DMA window corresponding to the LIODN */
+static int map_liodn(int liodn, struct fsl_dma_domain *dma_domain)
+{
+	u32 subwin_cnt = dma_domain->subwin_cnt;
+
+	if (subwin_cnt)
+		return map_liodn_subwins(liodn, dma_domain, subwin_cnt);
+	else
+		return map_liodn_win(liodn, dma_domain);
+
+}
+
+/* Update window/subwindow mapping for the LIODN */
+static int update_liodn(int liodn, struct fsl_dma_domain *dma_domain)
+{
+	int ret;
+
+	if (dma_domain->subwin_cnt) {
+		ret = reconfig_subwin(liodn, dma_domain);
+		if (ret)
+			pr_err("Subwindow reconfiguration failed for liodn %d\n", liodn);
+	} else {
+		ret = map_liodn_win(liodn, dma_domain);
+		if (ret)
+			pr_err("Window reconfiguration failed for liodn %d\n", liodn);
+	}
+
+	return ret;
+}
+
+static int update_liodn_stash(int liodn, struct fsl_dma_domain *dma_domain,
+				 u32 val)
+{
+	int ret = 0, i;
+
+	spin_lock(&iommu_lock);
+	if (!dma_domain->subwin_cnt) {
+		ret = pamu_update_paace_stash(liodn, 0, val);
+		if (ret) {
+			pr_err("Failed to update PAACE field for liodn %d\n ", liodn);
+			spin_unlock(&iommu_lock);
+			return ret;
+		}
+	} else {
+		for (i = 0; i < dma_domain->subwin_cnt; i++) {
+			ret = pamu_update_paace_stash(liodn, i, val);
+			if (ret) {
+				pr_err("Failed to update SPAACE %d field for liodn %d\n ", i, liodn);
+				spin_unlock(&iommu_lock);
+				return ret;
+			}
+		}
+	}
+	spin_unlock(&iommu_lock);
+
+	return ret;
+}
+
+/* Set the geometry parameters for a LIODN */
+static int configure_liodn(int liodn, struct device *dev,
+			   struct fsl_dma_domain *dma_domain,
+			   struct iommu_domain_geometry *geom_attr,
+			   u32 subwin_cnt)
+{
+	phys_addr_t window_addr, window_size;
+	phys_addr_t subwin_size;
+	int ret = 0, i;
+	u32 omi_index = ~(u32)0;
+
+	/* 
+	 * Configure the omi_index at the geometry setup time.
+	 * This is a static value which depends on the type of
+	 * device and would not change thereafter.
+	 */
+	get_ome_index(&omi_index, dev);
+
+	window_addr = geom_attr->aperture_start;
+	window_size = geom_attr->aperture_end - geom_attr->aperture_start;
+
+	spin_lock(&iommu_lock);
+	ret = pamu_disable_liodn(liodn);
+	if (!ret)
+		ret = pamu_config_ppaace(liodn, window_addr, window_size, omi_index,
+					 0, dma_domain->snoop_id,
+					 dma_domain->stash_id, subwin_cnt, 0);
+	spin_unlock(&iommu_lock);
+	if (ret) {
+		pr_err("PAMU PAACE configuration failed for liodn %d\n", liodn);
+		return ret;
+	}
+
+	if (subwin_cnt) {
+		subwin_size = window_size >> ilog2(subwin_cnt);
+		for (i = 0; i < subwin_cnt; i++) {
+			spin_lock(&iommu_lock);
+			ret = pamu_config_spaace(liodn, subwin_cnt, i, subwin_size,
+						 omi_index, 0,
+						 dma_domain->snoop_id,
+						 dma_domain->stash_id, 0, 0);
+			spin_unlock(&iommu_lock);
+			if (ret) {
+				pr_err("PAMU SPAACE configuration failed for liodn %d\n", liodn);
+				return ret;
+			}
+		}
+	}
+
+	return ret;
+}
+
+static int check_size(u64 size, unsigned long iova)
+{
+	/*
+	 * Size must be a power of two and at least be equal
+	 * to PAMU page size.
+	 */
+	if ((size & (size - 1)) || size < PAMU_PAGE_SIZE) {
+		pr_err("%s: size too small or not a power of two\n", __func__);
+		return -EINVAL;
+	}
+
+	/* iova must be page size aligned*/
+	if (iova & (size - 1)) {
+		pr_err("%s: address is not aligned with window size\n", __func__);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static inline int check_size_align(u64 size, u64 subwin_size)
+{
+	/* Ensure that the size is aligned to the subwindow size*/
+	return (size > subwin_size) ? (size & (subwin_size -1)) : 0;
+}
+
+
+static struct fsl_dma_domain *iommu_alloc_dma_domain(void)
+{
+	struct fsl_dma_domain *domain;
+
+	domain = kmem_cache_zalloc(fsl_pamu_domain_cache, GFP_KERNEL);
+	if (!domain)
+		return NULL;
+
+	domain->stash_id = ~(u32)0;
+	domain->snoop_id = ~(u32)0;
+
+	INIT_LIST_HEAD(&domain->devices);
+
+	spin_lock_init(&domain->domain_lock);
+
+	return domain;
+}
+
+static inline struct device_domain_info *find_domain(struct device *dev)
+{
+	return dev->archdata.iommu_domain;
+}
+
+static void remove_domain_ref(struct device_domain_info *info, u32 subwin_cnt)
+{
+		list_del(&info->link);
+		spin_lock(&iommu_lock);
+		if (subwin_cnt)
+			pamu_free_subwins(info->liodn);
+		pamu_disable_liodn(info->liodn);
+		spin_unlock(&iommu_lock);
+		spin_lock(&device_domain_lock);
+		info->dev->archdata.iommu_domain = NULL;
+		kmem_cache_free(iommu_devinfo_cache, info);
+		spin_unlock(&device_domain_lock);
+}
+
+static void destroy_domain(struct fsl_dma_domain *dma_domain)
+{
+	struct device_domain_info *info;
+
+	/* Dissociate all the devices from this domain */
+	while (!list_empty(&dma_domain->devices)) {
+		info = list_entry(dma_domain->devices.next,
+			struct device_domain_info, link);
+		remove_domain_ref(info, dma_domain->subwin_cnt);
+	}
+}
+
+static void detach_domain(struct device *dev, struct fsl_dma_domain *dma_domain)
+{
+	struct device_domain_info *info;
+	struct list_head *entry, *tmp;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dma_domain->domain_lock, flags);
+	/* Remove the device from the domain device list */
+	if (!list_empty(&dma_domain->devices)) {
+		list_for_each_safe(entry, tmp, &dma_domain->devices) {
+			info = list_entry(entry, struct device_domain_info, link);
+			if (info->dev == dev)
+				remove_domain_ref(info, dma_domain->subwin_cnt);
+		}
+	}
+	spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
+}
+
+static void attach_domain(struct fsl_dma_domain *dma_domain, int liodn, struct device *dev)
+{
+	struct device_domain_info *info, *old_domain_info;
+
+	spin_lock(&device_domain_lock);
+	/* 
+	 * Check here if the device is already attached to domain or not.
+	 * If the device is already attached to a domain detach it.
+	 */
+	old_domain_info = find_domain(dev);
+	if (old_domain_info && old_domain_info->domain != dma_domain) {
+		spin_unlock(&device_domain_lock);
+		detach_domain(dev, old_domain_info->domain);
+		spin_lock(&device_domain_lock);
+	}
+
+	info = kmem_cache_zalloc(iommu_devinfo_cache, GFP_KERNEL);
+
+	info->dev = dev;
+	info->liodn = liodn;
+	info->domain = dma_domain;
+
+	list_add(&info->link, &dma_domain->devices);
+	/* 
+	 * In case of devices with multiple LIODNs just store
+	 * the info for the first LIODN as all
+	 * LIODNs share the same domain
+	 */
+	if (!old_domain_info)
+		dev->archdata.iommu_domain = info;
+	spin_unlock(&device_domain_lock);
+
+}
+
+static phys_addr_t fsl_pamu_iova_to_phys(struct iommu_domain *domain,
+					    unsigned long iova)
+{
+	struct fsl_dma_domain *dma_domain = domain->priv;
+
+	if ((iova < domain->geometry.aperture_start) ||
+		iova > (domain->geometry.aperture_end))
+		return 0;
+
+	return get_phys_addr(dma_domain, iova);
+}
+
+static int fsl_pamu_domain_has_cap(struct iommu_domain *domain,
+				      unsigned long cap)
+{
+	return cap == IOMMU_CAP_CACHE_COHERENCY;
+}
+
+static void fsl_pamu_domain_destroy(struct iommu_domain *domain)
+{
+	struct fsl_dma_domain *dma_domain = domain->priv;
+
+	domain->priv = NULL;
+
+	destroy_domain(dma_domain);
+
+	dma_domain->enabled = 0;
+	dma_domain->valid = 0;
+	dma_domain->mapped = 0;
+
+	kmem_cache_free(fsl_pamu_domain_cache, dma_domain);
+}
+
+static int fsl_pamu_domain_init(struct iommu_domain *domain)
+{
+	struct fsl_dma_domain *dma_domain;
+
+	dma_domain = iommu_alloc_dma_domain();
+	if (!dma_domain) {
+		pr_err("dma_domain allocation failed\n");
+		return -ENOMEM;
+	}
+	domain->priv = dma_domain;
+	dma_domain->iommu_domain = domain;
+	/* defaul geometry = 1MB */
+	domain->geometry.aperture_start = 0;
+	domain->geometry.aperture_end = max_subwindow_count * PAMU_PAGE_SIZE;
+	domain->geometry.subwindows = 0;
+	domain->geometry.max_subwindows = max_subwindow_count;
+	domain->geometry.force_aperture = true;
+
+	return 0;
+}
+
+/* Configure geometry settings for all LIODNs associated with domain */
+static int configure_domain(struct fsl_dma_domain *dma_domain,
+			    struct iommu_domain_geometry *geom_attr,
+			    u32 subwin_cnt)
+{
+	struct device_domain_info *info;
+	int ret = 0;
+
+	list_for_each_entry(info, &dma_domain->devices, link) {
+		ret = configure_liodn(info->liodn, info->dev, dma_domain,
+				      geom_attr, subwin_cnt);
+		if (ret)
+			break;
+	}
+
+	return ret;
+}
+
+/* Update stash destination for all LIODNs associated with the domain */
+static int update_domain_stash(struct fsl_dma_domain *dma_domain, u32 val)
+{
+	struct device_domain_info *info;
+	int ret = 0;
+
+	list_for_each_entry(info, &dma_domain->devices, link) {
+		ret = update_liodn_stash(info->liodn, dma_domain, val);
+		if (ret)
+			break;
+	}
+
+	return ret;
+}
+
+/* Update domain mappings for all LIODNs associated with the domain */
+static int update_domain_mapping(struct fsl_dma_domain *domain)
+{
+	struct device_domain_info *info;
+	int ret = 0;
+
+	list_for_each_entry(info, &domain->devices, link) {
+		ret = update_liodn(info->liodn, domain);
+		if (ret)
+			break;
+	}
+	return ret;
+}
+
+static int fsl_pamu_map(struct iommu_domain *domain,
+			   unsigned long iova, phys_addr_t paddr,
+			   size_t size, int iommu_prot)
+{
+	struct fsl_dma_domain *dma_domain = domain->priv;
+	struct iommu_domain_geometry *geom_attr = &domain->geometry;
+	int prot = 0;
+	unsigned long flags;
+	int ret = 0;
+
+
+	if (iommu_prot & IOMMU_READ)
+		prot |= PAACE_AP_PERMS_QUERY;
+	if (iommu_prot & IOMMU_WRITE)
+		prot |= PAACE_AP_PERMS_UPDATE;
+
+	spin_lock_irqsave(&dma_domain->domain_lock, flags);
+	if (dma_domain->valid) {
+		/* 
+		 * Mapping consists of subwindows. If the mapping size
+		 * spans multiple subwindows, then it must be aligned to
+		 * the subwindow size.
+		 * It's also possible to create a partial subwindow mapping,
+		 * where mapping size < the subwindowsize. But in that
+		 * case overall mapping size can not exceed the subwindow
+		 * size.
+		 */
+		if (dma_domain->subwin_cnt) {
+			u32 align_check, subwin_size;
+			dma_addr_t geom_size = dma_domain->geom_size;
+
+			subwin_size = geom_size >> ilog2(dma_domain->subwin_cnt);
+			align_check = check_size(subwin_size, iova) ||
+					check_size_align(size, subwin_size);
+			/*
+			 * Ensure that the window being mapped fits in the
+			 * geometry. Also, check for the iova and size
+			 * alignment.
+			 */
+			if ((iova >= geom_attr->aperture_start &&
+				iova < geom_attr->aperture_end - 1 &&
+				size <= geom_size) &&
+				!align_check) {
+				update_domain_subwin(dma_domain, iova, size, paddr, prot, 1);
+			} else {
+				pr_err("Mismatch between geometry and mapping\n");
+				ret = -EINVAL;
+			}
+		} else {
+			ret = check_size(size, iova);
+			if (!ret && !dma_domain->enabled) {
+				dma_domain->mapped_iova = iova;
+				dma_domain->mapped_size = size;
+				dma_domain->paddr = paddr;
+				dma_domain->prot = prot;
+			} else {
+				pr_err("Can't create mapping, %s\n",
+					 (ret) ? "Invalid size" : "DMA enabled");
+				ret = ret ? ret : -EBUSY;
+			}
+		}
+
+		if (!ret) {
+			ret = update_domain_mapping(dma_domain);
+			if (!ret)
+				dma_domain->mapped = 1;
+		}
+	} else {
+		pr_err("Set domain geometry before creating the mapping\n");
+		ret = -ENODEV;
+	}
+	spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
+
+	return ret;
+}
+
+static size_t fsl_pamu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size)
+{
+	struct fsl_dma_domain *dma_domain = domain->priv;
+	struct iommu_domain_geometry *geom_attr = &domain->geometry;
+	size_t ret = size;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dma_domain->domain_lock, flags);
+	if (dma_domain->valid && dma_domain->mapped) {
+		if (dma_domain->subwin_cnt) {
+			u32 align_check, subwin_size;
+			dma_addr_t geom_size = dma_domain->geom_size;
+
+			subwin_size = geom_size >> ilog2(dma_domain->subwin_cnt);
+			align_check = check_size(subwin_size, iova) ||
+					check_size_align(size, subwin_size);
+			/*
+			 * Ensure that the window being mapped fits in the
+			 * geometry. Also, check for iova and size alignment.
+			 *
+			 */
+			if ((iova >= geom_attr->aperture_start &&
+				iova < geom_attr->aperture_end - 1 &&
+				size <= geom_size) &&
+				!align_check) {
+				update_domain_subwin(dma_domain, iova, size, 0,
+						      PAACE_AP_PERMS_DENIED, 0);
+			} else {
+				pr_err("Invalid address/size alignment\n");
+				ret = -EINVAL;
+			}
+		} else {
+			if (!dma_domain->enabled) {
+				u64 max_addr, unmap_range;
+				size_t domain_size;
+				unsigned long domain_iova;
+
+				unmap_range = iova + size;
+				domain_iova = dma_domain->mapped_iova;
+				domain_size = dma_domain->mapped_size;
+				max_addr = domain_iova + domain_size;
+
+				if ((domain_iova != iova &&
+					(max_addr < unmap_range ||
+					 max_addr > unmap_range)) ||
+					 size > domain_size ||
+					 iova < domain_iova) {
+					/*
+					 * We can not have holes in case of a single
+					 * window mapping.
+					 */
+					pr_err("Invalid size/address parameters for unmap\n");
+					ret = -EINVAL;
+				} else {
+					domain_size -= size;
+					if (iova == domain_iova)
+						domain_iova += size;
+					ret = check_size(domain_size, domain_iova);
+					if (!ret) {
+						dma_domain->mapped_iova = domain_iova;
+						dma_domain->mapped_size = domain_size;
+						if (!domain_size)
+							dma_domain->mapped = 0;
+					}
+				}
+			} else {
+				pr_err("Can't update mapping with DMA enabled\n");
+				ret = -EBUSY;
+			}
+		}
+		if (ret == size)
+			update_domain_mapping(dma_domain);
+	} else {
+		pr_err("Can't unmap an invalid domain\n");
+		ret = -ENODEV;
+	}
+	spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
+
+	return ret;
+}
+
+/*
+ * Attach the LIODN to the DMA domain and configure the geometry
+ * and window mappings.
+ */
+static int handle_attach_device(struct fsl_dma_domain *dma_domain,
+				 struct device *dev, const u32 *liodn,
+				 int num)
+{
+	unsigned long flags;
+	struct iommu_domain *domain = dma_domain->iommu_domain;
+	int ret = 0;
+	int i;
+
+	spin_lock_irqsave(&dma_domain->domain_lock, flags);
+	for (i = 0; i < num; i++) {
+
+		/* Ensure that LIODN value is valid */
+		if (liodn[i] > PAACE_NUMBER_ENTRIES) {
+			pr_err("Invalid liodn %d, attach device failed for %s\n",
+		          	liodn[i], dev->of_node->full_name);
+			ret = -EINVAL;
+			break;
+		} 
+
+		attach_domain(dma_domain, liodn[i], dev);
+		/*
+		 * Check if geometry has already been configured
+		 * for the domain. If yes, set the geometry for
+		 * the LIODN.
+		 */
+		if (dma_domain->valid) {
+			ret = configure_liodn(liodn[i], dev, dma_domain,
+					      &domain->geometry,
+					      dma_domain->subwin_cnt);
+			if (ret)
+				break;
+			if (dma_domain->mapped) {
+				/*
+				 * Create window/subwindow mapping for
+				 * the LIODN.
+				 */
+				ret = map_liodn(liodn[i], dma_domain);
+				if (ret)
+					break;
+			}
+		}
+	}
+	spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
+
+	return ret;
+}
+
+static int fsl_pamu_attach_device(struct iommu_domain *domain,
+				  struct device *dev)
+{
+	struct fsl_dma_domain *dma_domain = domain->priv;
+	const u32 *prop;
+	u32 prop_cnt;
+	int len, ret = 0;
+
+	prop = of_get_property(dev->of_node, "fsl,liodn", &len);
+	if (prop) {
+		prop_cnt = len / sizeof(u32);
+		ret = handle_attach_device(dma_domain, dev,
+					 prop, prop_cnt);
+	} else {
+		pr_err("missing fsl,liodn property at %s\n",
+		          dev->of_node->full_name);
+			ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static void fsl_pamu_detach_device(struct iommu_domain *domain,
+				      struct device *dev)
+{
+	struct fsl_dma_domain *dma_domain = domain->priv;
+	const u32 *prop;
+	int len;
+
+	prop = of_get_property(dev->of_node, "fsl,liodn", &len);
+	if (prop)
+		detach_domain(dev, dma_domain);
+	else
+		pr_err("missing fsl,liodn property at %s\n",
+		          dev->of_node->full_name);
+}
+
+static int get_subwin_cnt(dma_addr_t geom_size, u32 subwin, u32 *subwin_cnt)
+{
+	switch (subwin) {
+		case 0:
+			/* We can't support geometry size > 1MB*/
+			if (geom_size != (max_subwindow_count * PAMU_PAGE_SIZE))
+				return 0;
+			*subwin_cnt = max_subwindow_count;
+			break;
+		case 1:
+			/* No subwindows only a single PAMU window */
+			*subwin_cnt = 0;
+			break;
+		default:
+			if (subwin > max_subwindow_count ||
+			   (subwin & (subwin - 1)))
+				return 0;
+			*subwin_cnt = subwin;
+	}
+	return 1;
+} 
+
+static  int configure_domain_geometry(struct iommu_domain *domain, void *data)
+{
+	int ret;
+	struct iommu_domain_geometry *geom_attr = data;
+	struct fsl_dma_domain *dma_domain = domain->priv;
+	dma_addr_t geom_size;
+	u32 subwin_cnt;
+	unsigned long flags;
+
+	geom_size = geom_attr->aperture_end - geom_attr->aperture_start;
+	/*
+	 * Sanity check the geometry size and subwindows
+	 * attribute. Also, we do not support DMA outside
+	 * of the geometry.
+	 */
+	if (check_size(geom_size, geom_attr->aperture_start) ||
+		!geom_attr->force_aperture ||
+		!get_subwin_cnt(geom_size, geom_attr->subwindows,
+		&subwin_cnt)) {
+			pr_err("Invalid PAMU geometry attributes\n");
+			return -EINVAL;
+		}
+
+	spin_lock_irqsave(&dma_domain->domain_lock, flags);
+	if (dma_domain->enabled) {
+		pr_err("Can't set geometry attributes as domain is active\n");
+		spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
+		return  -EBUSY;
+	}
+
+	ret = configure_domain(dma_domain, geom_attr, subwin_cnt);
+	if (!ret) {
+		if (subwin_cnt) {
+			if (dma_domain->sub_win_arr)
+				kfree(dma_domain->sub_win_arr);
+			dma_domain->sub_win_arr = kmalloc(sizeof(struct dma_subwindow) *
+							  subwin_cnt, GFP_KERNEL);
+			if (!dma_domain->sub_win_arr) {
+				spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
+				return -ENOMEM;
+			}
+		}
+
+		/* set the new geometry attributes */
+		domain->geometry.aperture_start = geom_attr->aperture_start;
+		domain->geometry.aperture_end = geom_attr->aperture_end;
+		domain->geometry.subwindows = geom_attr->subwindows;
+
+		dma_domain->geom_size = geom_size;
+		dma_domain->subwin_cnt = subwin_cnt;
+		dma_domain->valid = 1;
+	}
+	spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
+
+	return ret;
+}
+
+/* Set the domain stash attribute */
+static int configure_domain_stash(struct fsl_dma_domain *dma_domain, void *data)
+{
+	struct iommu_stash_attribute *stash_attr = data;
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&dma_domain->domain_lock, flags);
+
+	memcpy(&dma_domain->dma_stash, stash_attr,
+		 sizeof(struct iommu_stash_attribute));
+
+	dma_domain->stash_id = get_stash_id(stash_attr->cache,
+					    stash_attr->cpu);
+	if (dma_domain->stash_id == ~(u32)0) {
+		pr_err("Invalid stash attributes\n");
+		spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
+		return -EINVAL;
+	}
+
+	ret = update_domain_stash(dma_domain, dma_domain->stash_id);
+
+	spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
+
+	return ret;
+}
+
+/* Configure domain dma state i.e. enable/disable DMA*/
+static int configure_domain_dma_state(struct fsl_dma_domain *dma_domain, bool enable)
+{
+	struct device_domain_info *info;
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&dma_domain->domain_lock, flags);
+
+	if (enable && !dma_domain->mapped) {
+		pr_err("Can't enable DMA domain without valid mapping\n");
+		spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
+		return -ENODEV;
+	}
+
+	dma_domain->enabled = enable;
+	if (!list_empty(&dma_domain->devices)) {
+		list_for_each_entry(info, &dma_domain->devices,
+					 link) {
+			ret = (enable) ? pamu_enable_liodn(info->liodn):
+				pamu_disable_liodn(info->liodn);
+			if (ret)
+				pr_err("Unable to set dma state for liodn %d",
+					 info->liodn);
+		}
+	}
+	spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
+
+	return 0;
+}
+
+int fsl_pamu_set_domain_attr(struct iommu_domain *domain,
+				 enum iommu_attr attr_type, void *data)
+{
+	struct fsl_dma_domain *dma_domain = domain->priv;
+	int ret = 0;
+
+
+	switch(attr_type) {
+	case DOMAIN_ATTR_GEOMETRY:
+		ret = configure_domain_geometry(domain, data);
+		break;
+	case DOMAIN_ATTR_STASH:
+		ret = configure_domain_stash(dma_domain, data);
+		break;
+	case DOMAIN_ATTR_ENABLE:
+		ret = configure_domain_dma_state(dma_domain, *(int *)data);
+		break;
+	default:
+		pr_err("Unsupported attribute type\n");
+		ret = -EINVAL;
+		break;
+	};
+
+	return ret;
+}
+
+int fsl_pamu_get_domain_attr(struct iommu_domain *domain,
+				 enum iommu_attr attr_type, void *data)
+{
+	struct fsl_dma_domain *dma_domain = domain->priv;
+	int ret = 0;
+
+
+	switch(attr_type) {
+	case DOMAIN_ATTR_STASH:
+		memcpy((struct iommu_stash_attribute *) data, &dma_domain->dma_stash,
+				 sizeof(struct iommu_stash_attribute));
+		break;
+	case DOMAIN_ATTR_ENABLE:
+		*(int *)data = dma_domain->enabled;
+		break;
+	default:
+		pr_err("Unsupported attribute type\n");
+		ret = -EINVAL;
+		break;
+	};
+
+	return ret;
+}
+
+static struct iommu_ops fsl_pamu_ops = {
+	.domain_init	= fsl_pamu_domain_init,
+	.domain_destroy = fsl_pamu_domain_destroy,
+	.attach_dev	= fsl_pamu_attach_device,
+	.detach_dev	= fsl_pamu_detach_device,
+	.map		= fsl_pamu_map,
+	.unmap		= fsl_pamu_unmap,
+	.iova_to_phys	= fsl_pamu_iova_to_phys,
+	.domain_has_cap = fsl_pamu_domain_has_cap,
+	.domain_set_attr = fsl_pamu_set_domain_attr,
+	.domain_get_attr = fsl_pamu_get_domain_attr,
+	.pgsize_bitmap	= FSL_PAMU_PGSIZES,
+};
+
+int pamu_domain_init()
+{
+	int ret = 0;
+
+	ret = iommu_init_mempool();
+	if (ret)
+		return ret;
+
+	bus_set_iommu(&platform_bus_type, &fsl_pamu_ops);
+
+	return ret;
+}
diff --git a/drivers/iommu/fsl_pamu_domain.h b/drivers/iommu/fsl_pamu_domain.h
new file mode 100644
index 0000000..840e5b6
--- /dev/null
+++ b/drivers/iommu/fsl_pamu_domain.h
@@ -0,0 +1,96 @@
+/*
+ * 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 (C) 2012 Freescale Semiconductor, Inc.
+ *
+ */
+
+#ifndef __FSL_PAMU_DOMAIN_H
+#define __FSL_PAMU_DOMAIN_H
+
+#include "fsl_pamu.h"
+
+struct dma_subwindow {
+	unsigned long iova;
+	phys_addr_t paddr;
+	size_t size;
+	int valid;
+	int prot;
+};
+
+struct fsl_dma_domain {
+	/* mapped_iova and mapped_size are used in case there are
+	 * no subwindows associated with the domain. These are
+	 * updated on each iommu_map/iommu_unmap call. Based
+	 * on these values the corresponding PPAACE entry is
+	 * updated.
+	 */
+	unsigned long			mapped_iova;
+	size_t	 			mapped_size;
+	/* physical address mapping */
+	u64				paddr;
+	/* mapped_subwin/mapped_subwin_cnt are only valid if
+	 * the domain geometry has subwindows. These fields
+	 * are updated on each iommu_map/iommu_unmap call.
+	 * Based on these values the corresponding SPAACE
+	 * entries are updated.
+	 */
+	u32 				mapped_subwin;
+	u32				mapped_subwin_cnt;
+	/* Access permission associated with the domain */
+	int				prot;
+	/* number of subwindows assocaited with this domain */
+	u32				subwin_cnt;
+	/* sub_win_arr contains information of the configured
+	 * subwindows for a domain.
+	 */
+	struct dma_subwindow		*sub_win_arr;
+	/* list of devices associated with the domain */
+	struct list_head 		devices;
+	/* dma_domain states:
+	 * valid - Geometry attribute has been configured.
+	 * mapped - A particular mapping has been created
+	 * within the configured geometry. Domain has to
+	 * be in the valid state before any DMA mapping
+	 * can be created in it.
+	 * enabled - DMA has been enabled for the given
+	 * domain. This translates to setting of the
+	 * valid bit for the primary PAACE in the PAMU
+	 * PAACT table. Domain should be valid and have
+	 * a valid mapping before DMA can be enabled for it.
+	 *
+	 */
+	int				valid;
+	int				mapped;
+	int				enabled;
+	/* stash_id obtained from the stash attribute details */
+	u32				stash_id;
+	struct iommu_stash_attribute	dma_stash;
+	u32				snoop_id;
+	dma_addr_t			geom_size;
+	struct iommu_domain		*iommu_domain;
+	spinlock_t			domain_lock;
+};
+
+/* domain-device relationship */
+struct device_domain_info {
+	struct list_head link;	/* link to domain siblings */
+	struct device *dev;
+	u32 liodn;
+	struct fsl_dma_domain *domain; /* pointer to domain */
+};
+
+extern unsigned int max_subwindow_count;
+
+#endif  /* __FSL_PAMU_DOMAIN_H */
-- 
1.7.4.1

^ permalink raw reply related

* [PATCH 3/4 v7] iommu/fsl: Add iommu domain attributes required by fsl PAMU driver.
From: Varun Sethi @ 2012-12-14 13:51 UTC (permalink / raw)
  To: joerg.roedel, iommu, linuxppc-dev, linux-kernel, timur, scottwood
  Cc: Varun Sethi
In-Reply-To: <1355493114-21776-1-git-send-email-Varun.Sethi@freescale.com>

Added the following domain attributes required by FSL PAMU driver:
1. Subwindows field added to the iommu domain geometry attribute.
2. Added new iommu stash attribute, which allows setting of the
   LIODN specific stash id parameter through IOMMU API.
3. Added an attribute for enabling/disabling DMA to a particular
   memory window.
4. Added max_subwindows field to the geometry attribute. This is
   used to determine the maximum number sub windows available
   for the geometry.

Signed-off-by: Varun Sethi <Varun.Sethi@freescale.com>
---
changes in v7:
- Added max_subwindows field to the geometry attribute.
changes in v5:
- Updated description of the subwindows field.
changes in v4:
- Updated comment explaining subwindows(as mentioned by Scott).
change in v3:
-renamed the stash attribute targets
 include/linux/iommu.h |   49 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 49 insertions(+), 0 deletions(-)

diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index f3b99e1..01ca1de 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -44,6 +44,47 @@ struct iommu_domain_geometry {
 	dma_addr_t aperture_start; /* First address that can be mapped    */
 	dma_addr_t aperture_end;   /* Last address that can be mapped     */
 	bool force_aperture;       /* DMA only allowed in mappable range? */
+
+	/*
+	 * A geometry mapping can be created in one of the following ways
+	 * for an IOMMU:
+	 * 1. A single contiguous window
+	 * 2. Through arbritary paging throughout the aperture.
+	 * 3. Using multiple subwindows
+	 *
+	 * In absence of arbritary paging, subwindows allow for supporting
+	 * physically discontiguous mappings.
+	 *
+	 * This attribute indicates number of DMA subwindows supported by
+	 * the geometry. If there is a single window that maps the entire
+	 * geometry, attribute must be set to "1". A value of "0" implies
+	 * that this mechanism is not used at all(normal paging is used).
+	 * Value other than* "0" or "1" indicates the actual number of
+	 * subwindows.
+	 */
+	u32 subwindows;
+	/*
+	 * This is a read only field and indicates the maximum number of
+	 * subwindows that are permitted for the geometry. The user is
+	 * not allowed to write to this field.
+	 */
+	u32 max_subwindows;
+};
+
+/* cache stash targets */
+#define IOMMU_ATTR_CACHE_L1 1
+#define IOMMU_ATTR_CACHE_L2 2
+#define IOMMU_ATTR_CACHE_L3 3
+
+/* This attribute corresponds to IOMMUs capable of generating
+ * a stash transaction. A stash transaction is typically a
+ * hardware initiated prefetch of data from memory to cache.
+ * This attribute allows configuring stashig specific parameters
+ * in the IOMMU hardware.
+ */
+struct iommu_stash_attribute {
+	u32 	cpu;	/* cpu number */
+	u32 	cache;	/* cache to stash to: L1,L2,L3 */
 };
 
 struct iommu_domain {
@@ -60,6 +101,14 @@ struct iommu_domain {
 enum iommu_attr {
 	DOMAIN_ATTR_MAX,
 	DOMAIN_ATTR_GEOMETRY,
+	/* Set the IOMMU hardware stashing
+	 * parameters.
+	 */
+	DOMAIN_ATTR_STASH,
+	/* Explicity enable/disable DMA for a
+         * particular memory window.
+         */
+	DOMAIN_ATTR_ENABLE,
 };
 
 #ifdef CONFIG_IOMMU_API
-- 
1.7.4.1

^ permalink raw reply related

* [PATCH 0/4] iommu/fsl: Freescale PAMU driver and IOMMU API implementation.
From: Varun Sethi @ 2012-12-14 13:51 UTC (permalink / raw)
  To: joerg.roedel, iommu, linuxppc-dev, linux-kernel, timur, scottwood
  Cc: Varun Sethi

This patchset provides the Freescale PAMU (Peripheral Access Management Unit) driver
and the corresponding IOMMU API implementation. PAMU is the IOMMU present on Freescale
QorIQ platforms. PAMU can authorize memory access, remap the memory address, and remap 
the I/O transaction type.

This set consists of the following patches:
1. Addition of new field in the device (powerpc) archdata structure for storing iommu domain information
   pointer. This pointer is stored when the device is attached to a particular iommu domain.
2. Add PAMU bypass enable register to the ccsr_guts structure.
3. Addition of domain attributes required by the PAMU driver IOMMU API.
4. PAMU driver and IOMMU API implementation.

This patch set is based on the next branch of the iommu git tree maintained by Joerg.

Varun Sethi (4):
  store iommu domain info in device arch data.
  add pamu bypass enable register to guts.
  Add iommu attributes for PAMU
  FSL PAMU driver.

 arch/powerpc/include/asm/device.h   |    4 +
 arch/powerpc/include/asm/fsl_guts.h |    4 +-
 drivers/iommu/Kconfig               |    8 +
 drivers/iommu/Makefile              |    1 +
 drivers/iommu/fsl_pamu.c            | 1152 +++++++++++++++++++++++++++++++++++
 drivers/iommu/fsl_pamu.h            |  398 ++++++++++++
 drivers/iommu/fsl_pamu_domain.c     | 1033 +++++++++++++++++++++++++++++++
 drivers/iommu/fsl_pamu_domain.h     |   96 +++
 include/linux/iommu.h               |   49 ++
 9 files changed, 2744 insertions(+), 1 deletions(-)
 create mode 100644 drivers/iommu/fsl_pamu.c
 create mode 100644 drivers/iommu/fsl_pamu.h
 create mode 100644 drivers/iommu/fsl_pamu_domain.c
 create mode 100644 drivers/iommu/fsl_pamu_domain.h

-- 
1.7.4.1

^ permalink raw reply

* [PATCH 1/4 v7] iommu/fsl: Store iommu domain information pointer in archdata.
From: Varun Sethi @ 2012-12-14 13:51 UTC (permalink / raw)
  To: joerg.roedel, iommu, linuxppc-dev, linux-kernel, timur, scottwood
  Cc: Varun Sethi
In-Reply-To: <1355493114-21776-1-git-send-email-Varun.Sethi@freescale.com>

Add a new field in the device (powerpc) archdata structure for storing iommu domain
information pointer. This pointer is stored when the device is attached to a particular
domain.

Signed-off-by: Varun Sethi <Varun.Sethi@freescale.com>
---
- no change in this version
 arch/powerpc/include/asm/device.h |    4 ++++
 1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/arch/powerpc/include/asm/device.h b/arch/powerpc/include/asm/device.h
index 77e97dd..6dc79fe 100644
--- a/arch/powerpc/include/asm/device.h
+++ b/arch/powerpc/include/asm/device.h
@@ -28,6 +28,10 @@ struct dev_archdata {
 		void		*iommu_table_base;
 	} dma_data;
 
+	/* IOMMU domain information pointer. This would be set
+	 * when this device is attached to an iommu_domain.
+	 */
+	void			*iommu_domain;
 #ifdef CONFIG_SWIOTLB
 	dma_addr_t		max_direct_dma_addr;
 #endif
-- 
1.7.4.1

^ permalink raw reply related

* PS3 platform is broken on Linux 3.7.0
From: Phileas Fogg @ 2012-12-14 12:35 UTC (permalink / raw)
  To: linuxppc-dev

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

 Hi,

I wanted to bring to your attention the fact that the PS3 platform is broken on Linux 3.7.0.

i'm not able to boot Linux 3.7.0 on my PS3 slim. Linux 3.6.10 boots just fine but not 3.7.0
When i try to boot Linux 3.7.0 then my PS3  shuts down.

So i cloned the Linux powerpc GIT repository and tried to find out which commits broke the PS3 platform.
After some time I tracked it down to 2 commits:

---------------------------------------------------------------------------------------------

commit 407821a34fce89b4f0b031dbab5cec7d059f46bc
Author: Michael Ellerman <michael@ellerman.id.au>
Date:   Fri Sep 7 15:31:44 2012 +0000

    powerpc: Initialise paca.data_offset with poison
    
    It's possible for the cpu_possible_mask to change between the time we
    initialise the pacas and the time we setup per_cpu areas.
    
    Obviously impossible cpus shouldn't ever be running, but stranger things
    have happened. So be paranoid and initialise data_offset with a poison
    value in case we don't set it up later.
    
    Based on a patch from Anton Blanchard.
    
    Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
    Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>


------------------------------------------------------------------------------------------------

commit 048ee0993ec8360abb0b51bdf8f8721e9ed62ec4
Author: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Date:   Mon Sep 10 02:52:55 2012 +0000

    powerpc/mm: Add 64TB support
    
    Increase max addressable range to 64TB. This is not tested on
    real hardware yet.
    
    Reviewed-by: Paul Mackerras <paulus@samba.org>
    Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
    Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

----------------------------------------------------------------------------------------------------------

The first commit causes my PS3 to shut down. If i revert it then i'm able to boot Linux 3.7.0 and even see some boot messages
on my screen. But then it hangs. The second commit is the reason for the hang as i figured it out.

I reverted both commits in current Linux 3.7.0 and was able to boot Linux 3.7.0 on my PS3 slim successfully.

Regards


[-- Attachment #2: Type: text/html, Size: 2829 bytes --]

^ permalink raw reply

* Re: [RFC PATCH 00/11] Hot-plug and Online/Offline framework
From: Toshi Kani @ 2012-12-14  1:51 UTC (permalink / raw)
  To: Greg KH
  Cc: linux-s390, jiang.liu@huawei.com, wency@cn.fujitsu.com,
	linux-mm@kvack.org, linuxppc-dev, linux-kernel@vger.kernel.org,
	rjw@sisk.pl, linux-acpi@vger.kernel.org,
	isimatu.yasuaki@jp.fujitsu.com, srivatsa.bhat@linux.vnet.ibm.com,
	guohanjun@huawei.com, bhelgaas@google.com,
	akpm@linux-foundation.org, yinghai@kernel.org, lenb@kernel.org
In-Reply-To: <20121213183021.GC9606@kroah.com>

On Thu, 2012-12-13 at 10:30 -0800, Greg KH wrote:
> On Thu, Dec 13, 2012 at 09:03:54AM -0700, Toshi Kani wrote:
> > On Thu, 2012-12-13 at 04:16 +0000, Greg KH wrote:
> > > On Wed, Dec 12, 2012 at 08:37:44PM -0700, Toshi Kani wrote:
> > > > On Wed, 2012-12-12 at 16:55 -0800, Greg KH wrote:
> > > > > On Wed, Dec 12, 2012 at 05:39:36PM -0700, Toshi Kani wrote:
> > > > > > On Wed, 2012-12-12 at 15:56 -0800, Greg KH wrote:
> > > > > > > On Wed, Dec 12, 2012 at 04:17:12PM -0700, Toshi Kani wrote:
> > > > > > > > This patchset is an initial prototype of proposed hot-plug framework
> > > > > > > > for design review.  The hot-plug framework is designed to provide 
> > > > > > > > the common framework for hot-plugging and online/offline operations
> > > > > > > > of system devices, such as CPU, Memory and Node.  While this patchset
> > > > > > > > only supports ACPI-based hot-plug operations, the framework itself is
> > > > > > > > designed to be platform-neural and can support other FW architectures
> > > > > > > > as necessary.
> > > > > > > > 
> > > > > > > > The patchset has not been fully tested yet, esp. for memory hot-plug.
> > > > > > > > Any help for testing will be very appreciated since my test setup
> > > > > > > > is limited.
> > > > > > > > 
> > > > > > > > The patchset is based on the linux-next branch of linux-pm.git tree.
> > > > > > > > 
> > > > > > > > Overview of the Framework
> > > > > > > > =========================
> > > > > > > 
> > > > > > > <snip>
> > > > > > > 
> > > > > > > Why all the new framework, doesn't the existing bus infrastructure
> > > > > > > provide everything you need here?  Shouldn't you just be putting your
> > > > > > > cpus and memory sticks on a bus and handle stuff that way?  What makes
> > > > > > > these types of devices so unique from all other devices that Linux has
> > > > > > > been handling in a dynamic manner (i.e. hotplugging them) for many many
> > > > > > > years?
> > > > > > > 
> > > > > > > Why are you reinventing the wheel?
> > > > > > 
> > > > > > Good question.  Yes, USB and PCI hotplug operate based on their bus
> > > > > > structures.  USB and PCI cards only work under USB and PCI bus
> > > > > > controllers.  So, their framework can be composed within the bus
> > > > > > structures as you pointed out.
> > > > > > 
> > > > > > However, system devices such CPU and memory do not have their standard
> > > > > > bus.  ACPI allows these system devices to be enumerated, but it does not
> > > > > > make ACPI as the HW bus hierarchy for CPU and memory, unlike PCI and
> > > > > > USB.  Therefore, CPU and memory modules manage CPU and memory outside of
> > > > > > ACPI.  This makes sense because CPU and memory can be used without ACPI.
> > > > > > 
> > > > > > This leads us an issue when we try to manage system device hotplug
> > > > > > within ACPI, because ACPI does not control everything.  This patchset
> > > > > > provides a common hotplug framework for system devices, which both ACPI
> > > > > > and non-ACPI modules (i.e. CPU and memory modules) can participate and
> > > > > > are coordinated for their hotplug operations.  This is analogous to the
> > > > > > boot-up sequence, which ACPI and non-ACPI modules can participate to
> > > > > > enable CPU and memory.
> > > > > 
> > > > > Then create a "virtual" bus and put the devices you wish to control on
> > > > > that.  That is what the "system bus" devices were supposed to be, it's
> > > > > about time someone took that code and got it all working properly in
> > > > > this way, that is why it was created oh so long ago.
> > > > 
> > > > It may be the ideal, but it will take us great effort to make such
> > > > things to happen based on where we are now.  It is going to be a long
> > > > way.  I believe the first step is to make the boot-up flow and hot-plug
> > > > flow consistent for system devices.  This is what this patchset is
> > > > trying to do.
> > > 
> > > If you use the system "bus" for this, the "flow" will be identical, that
> > > is what the driver core provides for you.  I don't see why you need to
> > > implement something that sits next to it and not just use what we
> > > already have here.
> > 
> > Here is very brief boot-up flow.  
> > 
> > start_kernel()
> >   boot_cpu_init()         // init cpu0
> >   setup_arch()
> >     x86_init.paging.pagetable_init() // init mem pagetable
> >   :
> > kernel_init()
> >   kernel_init_freeable()
> >     smp_init()            // init other CPUs
> >       :
> >     do_basic_setup()
> >       driver_init()
> >         cpu_dev_init()    // build system/cpu tree
> >         memory_dev_init() // build system/memory tree
> >       do_initcalls()
> >         acpi_init()       // build ACPI device tree
> > 
> > CPU and memory are initialized at early boot.  The system device tree is
> > built at the last step of the boot sequence and is only used for
> > providing sysfs interfaces.
> 
> Then fix that and create the system device tree earlier.

# I added ppc and s390 to the list as you suggested... and because
# I may be wrong in my code reading...  This thread is:
# https://lkml.org/lkml/2012/12/13/452

I looked at s390 and powerpc hotplug code.  Their boot flow is
consistent as above since most of the funcs above are actually common.

For hotplug, pSeries (powerpc) supports CPU, Memory and I/O hotplug.
s390 seems to support less capability, so I looked at pSeries mostly.

pSeries supports DLPAR, and all hotplug code is put under
pSeries-specific code, such as arch/powerpc/platforms/pseries/dlpar.c.
The code is implemented outside of the OF module.  Therefore, I think
the OF module itself works consistently at boot and hot-add.  It has its
own hotplug framework with pSeries_reconfig_chain, which calls all
registered handlers for reconfig events.

So, it looks to me that pSeries has somewhat a similar framework, but
put everything under pSeries specific code.  pSeries and s390 hotplug
implementations do not use the bus structure you suggested, either.


> > That is, the system bus structure has nothing to do with the actual
> > CPU and memory initialization at boot.
> 
> Then that should be fixed, right?

The boot-up sequence is shared by all architectures, and it is nearly
impossible to make such changes to work on all architectures.


> > Similarly, ACPI drivers do not initialize actual CPU and memory at boot
> > as they are also called at the last step.
> 
> That should also probably be fixed, right?

Since the boot flow is consistent for all architectures, I do not think
other FW modules initialize CPU and memory, either.


> > Further, the ACPI device tree and system bus tree are separate
> > entities.
> 
> That's because ACPI seems to be getting crazy these days, and creating
> lots of different devices and tieing it back into the existing device
> trees.  Which is fine, see how it's being done with USB for one example
> of how this can be done correctly, _if_ you want to keep them separate
> (doing so is your own choice, nothing that I'm saying is necessary.)
> 
> > Hotplug events are sent to ACPI.
> 
> Your hotplug events are being sent there, that's your decision to do so,
> it doesn't happen that way with other subsystems that get hotplug events
> from ACPI (i.e. PCI hotplug, right?)

ACPICA sends a notification to an ACPI notify handler, so it has to go
with ACPI.  The "system/cpu" and "system/memory" sysfs drivers are
platform neutral and do not depend on ACPI.  PCIe hotplug is based on
PCIe spec, and does not use ACPI.  ACPI PCI hotplug (for PCIx) uses ACPI
and its notification is sent to an ACPI notify handler. 


> > In order to keep the boot flow and hotplug flow consistent, I believe
> > the first step is to keep the role of modules consistent between boot
> > and hotplug.
> 
> I agree, see above for how to resolve that :)
>
> > For instance, acpi_init() only builds ACPI tree at boot, so ACPI
> > should only build ACPI tree at hot-add as well.  This keeps ACPI
> > drivers to do the same for both boot and hot-add.
> 
> Agreed.

Great!  Yes, we just need to agree on a solution. :)


> > The framework is designed to provide the consistency along with other
> > high-availability features such as rollback.
> 
> I want my tiny, USB-powered device to have "high-availability", don't
> think of that type of functionality as somehow being special, it's what
> we have been doing with other subsystems for _years_ now.
> 
> Again, I think if you properly tie the system bus code into the CPU work
> at the correct location, you can achieve everything you need.  I base
> this on the fact that this is what other subsystems and architectures
> have been doing for years.  Just because this is ACPI is no reason to
> think that it needs to be done differently.
> 
> Odds are, s390 has been doing this for 10+ years and none of us realize
> this, they are usually that far ahead of the curve if history is any
> lesson.

I looked at pSeries and s390, and they have their own framework.  Their
cases are also unique because their implementations are tied with
specific platforms / products.  In high-level, however, their approach
is similar to mine.  I have also worked on hotplug for years on other
OS, so I am not coming from nowhere, either. :)

If your concern is having a common hotplug framework, I can try to
address it by putting this framework under ACPI.  This makes it less
capable/cleaner, but it keeps it within ACPI.  That makes it more
similar to how pSeries and s390 did.

Thanks,
-Toshi

^ permalink raw reply

* Re: Understanding how kernel updates MMU hash table
From: Benjamin Herrenschmidt @ 2012-12-13 21:48 UTC (permalink / raw)
  To: pegasus; +Cc: linuxppc-dev
In-Reply-To: <1355388520814-67313.post@n7.nabble.com>

On Thu, 2012-12-13 at 00:48 -0800, pegasus wrote:

> 1. Linux page table structure (PGD, PUD, PMD and PTE) is directly used in
> case of architecture that lend themselves to such a tree structure for
> maintaining virtual memory information. Otherwise Linux needs to maintain
> two seperate constructs like it does in case of PowerPC. Right? 

Linux always maintains a tree structure, it can be 2, 3 or 4 levels, and
there's some flexibility on the actual details of the structure and PTE
format. If that can be made to match a HW construct, then it's used
directly (x86, ARM), else, there's some other mechanism to load the HW
construct.

I believe some sparcs have some kind of hash table as well (though a
different one).

> 2. PowerPC's hash table as you said is pretty large. However isn't it still
> smaller than Linux's VM infrastructure such that the chances of it being
> 'FULL' are a lot more. It is also possible that there could be two entries
> in the table that points to the same Real address. Like a page being shared
> by two processes? 

Yes and yes.

> My main concern here is to understand if having such an inverted page table
> aka the hash table helps us in any way when doing TLB flushes. You mentioned
> and I also read  in a paper by Paul Mackerras that every Linux PTE (LPTE) in
> case of ppc64 contains 4 extra bits that help us to get to the very slot in
> the hash table that houses the corresponding hashtable PTE (HPTE). Now this
> (at least to me) is smartness on the part of the kernel and I do not think
> the architecture per se is doing us any favor by having that hash table
> right? Or am I missing something here? 

Right.

> His paper is (or rather was) on how one can optimize the Linux ppc kernel
> and time and again he mentions the fact that one can first record the LPTEs
> being invalidated and then remove the corresponding HPTEs in a batched
> format. In his own words "Alternatively, it would be possible to make a list
> of virtual addresses when LPTEs are changed and then use that list in the
> TLB flush routines to avoid the search through the Linux page tables". So do
> we skip looking for the corresponding LPTEs or perhaps we've already
> invalidated them and we remove the corresponding HPTEs in a batch as you
> mentioned earlier?? Could you shed some light on how this optimization
> actually developed over time?

Currently we batch within arch_lazy_mmu sections. We do that because we
require a batch to be fully contained within a page table spinlock
section, ie, we must guarantee that we have performed the hash
invalidations before there's a chance that a new PTE for that same VA
gets faulted in (or we would run the risk of creating duplicates in the
hash which is fatal).

For the details, I'd say look at the code (and not 2.6.10, that's quite
uninteresting).

>  He had results for an "immediate update"
> kernel 
> and "batched update" kernel for both ppc32 and ppc64. For ppc32 the batched
> update is actually a bit worse than immediate update however for ppc64, the
> batched update performs better than immediate update. What exactly is
> helping ppc64 perform better with the so called "batched update"? Is it the
> encoding of the HPTE address in the LPTE as mentioned above? Or some aspect
> of ppc64 that I am unaware of? 

Possibly the fact that we know which slot which means we don't search.

> Also on a generic note, how come we have 4 spare bits in the PTE for 64bit
> address space? Large pages perhaps? 

We don't exploit the entire 64-bit address space. Up until recently we
only gave 16T to processes though we just bumped that a bit.

Cheers,
Ben.
> 
> 
> --
> View this message in context: http://linuxppc.10917.n7.nabble.com/Understanding-how-kernel-updates-MMU-hash-table-tp59509p67313.html
> Sent from the linuxppc-dev mailing list archive at Nabble.com.
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev

^ permalink raw reply

* Re: Build regressions/improvements in v3.7
From: Geert Uytterhoeven @ 2012-12-13 19:27 UTC (permalink / raw)
  To: linux-kernel; +Cc: the arch/x86 maintainers, linuxppc-dev
In-Reply-To: <1355426667-3060-1-git-send-email-geert@linux-m68k.org>

On Thu, Dec 13, 2012 at 8:24 PM, Geert Uytterhoeven
<geert@linux-m68k.org> wrote:
> JFYI, when comparing v3.7 to v3.7-rc8[3], the summaries are:
>   - build errors: +2/-0

  + error: No rule to make target include/config/auto.conf:  => N/A

x86_64-randconfig

  + error: vga16fb.c: undefined reference to `vgacon_remap_base':  =>
.devinit.text+0x16b52), .devinit.text+0x16b5a)

powerpc-randconfig

> [1] http://kisskb.ellerman.id.au/kisskb/head/5700/ (all 117 configs)
> [3] http://kisskb.ellerman.id.au/kisskb/head/5670/ (all 117 configs)

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply

* Re: [RFC PATCH] powerpc/fsl: add timer wakeup source
From: Tabi Timur-B04825 @ 2012-12-13 15:51 UTC (permalink / raw)
  To: Wang Dongsheng
  Cc: Wood Scott-B07421, Wang Dongsheng-B40534,
	linuxppc-dev@lists.ozlabs.org
In-Reply-To: <1349260948-15828-1-git-send-email-dongsheng.wds@gmail.com>

On Wed, Oct 3, 2012 at 5:42 AM, Wang Dongsheng <dongsheng.wds@gmail.com> wr=
ote:
>
>
> Signed-off-by: Wang Dongsheng <dongsheng.wang@freescale.com>

Wang,

Your patches must always have a From: line of your Freescale email
address.  Do not use your gmail.com address to send patches.

This needs to be fixed when this patch is applied.

--=20
Timur Tabi
Linux kernel developer at Freescale=

^ 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