* [git pull] Please pull powerpc.git merge branch
From: Benjamin Herrenschmidt @ 2012-10-18 9:23 UTC (permalink / raw)
To: Linus Torvalds; +Cc: linuxppc-dev list, Andrew Morton, Linux Kernel list
Hi Linus !
Here are a handful of powerpc related fixes for you to pull.
Cheers,
Ben.
The following changes since commit 18673533256a2953ccefded52df2679de8640685:
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net (2012-10-17 12:41:18 -0700)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc.git merge
for you to fetch changes up to 83dac59409387789b88bed40b1be86a8abc572be:
cpuidle/powerpc: Fix snooze state problem in the cpuidle design on pseries. (2012-10-18 10:57:25 +1100)
----------------------------------------------------------------
Aneesh Kumar K.V (1):
powerpc: Build fix for powerpc KVM
Benjamin Herrenschmidt (1):
Revert "powerpc/perf: Use pmc_overflow() to detect rolled back events"
Deepthi Dharwar (3):
cpuidle/powerpc: Fix target residency initialisation in pseries cpuidle
cpuidle/powerpc: Fix smt_snooze_delay functionality.
cpuidle/powerpc: Fix snooze state problem in the cpuidle design on pseries.
arch/powerpc/include/asm/kvm_book3s_32.h | 1 +
arch/powerpc/include/asm/processor.h | 4 +-
arch/powerpc/kernel/sysfs.c | 2 +-
arch/powerpc/kvm/book3s_32_mmu_host.c | 4 +-
arch/powerpc/perf/core-book3s.c | 2 +-
arch/powerpc/platforms/pseries/processor_idle.c | 62 +++++++++++------------
6 files changed, 36 insertions(+), 39 deletions(-)
^ permalink raw reply
* Re: [RFC PATCH powerpc] Fix a lazy irq related WARING in arch_local_irq_restore()
From: Li Zhong @ 2012-10-18 7:30 UTC (permalink / raw)
To: Benjamin Herrenschmidt
Cc: Paul Mackerras, Paul E. McKenney, PowerPC email list
In-Reply-To: <1350518056.4678.113.camel@pasglop>
On Thu, 2012-10-18 at 10:54 +1100, Benjamin Herrenschmidt wrote:
> On Wed, 2012-09-26 at 18:10 +0800, Li Zhong wrote:
>
> ../...
>
> Sorry got distracted, got back on this patch today:
>
> > > We might need to "sanitize" the enable state in the PACA before we
> > > actually enter NAP or in the return from NAP code, like we do for normal
> > > idle code...
> >
> > Hi Ben,
> >
> > After some further reading of the code, I updated the code as following,
> > but I'm not very sure, and guess it most probably has some issues ...
> > Could you please help to review and give your comments?
Hi Ben,
> I think it's still not right, see below
As expected :)
> > In extended_cede_processor(), if there is still lazy irq pending, I used
> > local_irq_enable() to make sure the irq replayed and flags cleared, but
> > I'm not sure whether it is a proper way.
>
> Right but that will break things for idle. In idle, if you have
> re-enabled interrupts, you need to return and essentially abort the
> attempt at going to nap mode, because the interrupt might have set need
> resched. That's why we normally just check if something's pending and
> return, letting the upper levels re-enable interrupts and do all the
> dirty work for us.
It seems that extended_cede_processor() is only called in hotplug, and
idle calls check_and_cede_processor().
> Now, hotplug might differ here in what it needs, but in any case,
> extended_cede_processor doesn't seem to be the right place to handle it,
> at best that function should return if it thinks there's something that
> needs to be done and let the upper layers deal with it appropriately.
OK, so can I move the while loop into pseries_mach_cpu_die(), before
calling extended_cede_processor() ? - as in the attached code.
> > In pseries_mach_cpu_die(), I added local_irq_disable() after cede, and
> > prepare for the start_secondary_resume(), but I'm not sure whether we
> > also need a hard_irq_disable() here.
>
> You probably do if it's going to go back to the start secondary path. It
> shouldn't hurt in any case as long as start_secondary_resume()
> eventually does a local_irq_enable().
OK, I added it. Could you please to take a look at the updated code?
thanks.
=======================
diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c
index 64c97d8..9b9394e 100644
--- a/arch/powerpc/platforms/pseries/hotplug-cpu.c
+++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c
@@ -127,9 +127,16 @@ static void pseries_mach_cpu_die(void)
get_lppaca()->donate_dedicated_cpu = 1;
while (get_preferred_offline_state(cpu) == CPU_STATE_INACTIVE) {
+ while (!prep_irq_for_idle()) {
+ local_irq_enable();
+ local_irq_disable();
+ }
+
extended_cede_processor(cede_latency_hint);
}
+ local_irq_disable();
+
if (!get_lppaca()->shared_proc)
get_lppaca()->donate_dedicated_cpu = 0;
get_lppaca()->idle = 0;
@@ -137,6 +144,7 @@ static void pseries_mach_cpu_die(void)
if (get_preferred_offline_state(cpu) == CPU_STATE_ONLINE) {
unregister_slb_shadow(hwcpu);
+ hard_irq_disable();
/*
* Call to start_secondary_resume() will not return.
* Kernel stack will be reset and start_secondary()
diff --git a/arch/powerpc/platforms/pseries/plpar_wrappers.h b/arch/powerpc/platforms/pseries/plpar_wrappers.h
index 13e8cc4..caed0d1 100644
--- a/arch/powerpc/platforms/pseries/plpar_wrappers.h
+++ b/arch/powerpc/platforms/pseries/plpar_wrappers.h
@@ -2,6 +2,7 @@
#define _PSERIES_PLPAR_WRAPPERS_H
#include <linux/string.h>
+#include <linux/irqflags.h>
#include <asm/hvcall.h>
#include <asm/paca.h>
@@ -41,7 +42,14 @@ static inline long extended_cede_processor(unsigned long latency_hint)
u8 old_latency_hint = get_cede_latency_hint();
set_cede_latency_hint(latency_hint);
+
rc = cede_processor();
+#ifdef CONFIG_TRACE_IRQFLAGS
+ /* Ensure that H_CEDE returns with IRQs on */
+ if (WARN_ON(!(mfmsr() & MSR_EE)))
+ __hard_irq_enable();
+#endif
+
set_cede_latency_hint(old_latency_hint);
return rc;
=======================
> > I'm still a little confused by the meaning of PACA_IRQ_HARD_DIS in
> > irq_happened. From the checking at the warning point, it seems only
> > irq_happened equaling 0x1(PACA_IRQ_HARD_DIS) means hard irqs are
> > disabled.
>
> No. They are disabled if any bit in there corresponding to a "level"
> interrupt is set as well. Only the "edge" interrupts (and decrementer
> which we treat as edge and reset to a high value when it kicks) are
> ignored for the sake of HW irq state.
>
> The reason we have this IRQ_HARD_DIS bit is to indicate that a 'manual'
> hard disabling occurred (by opposition to one happening as a result of
> an external interrupt).
>
> We need that so we can avoid doing an mfspr() in local_irq_enable() and
> entirely rely on the content of irq_happened to know whether interrupts
> are hard enabled or hard disabled.
>
> We do that because mfspr is a fairly expensive instruction. But that
> means that we need to make sure we always have a consistent content in
> irq_happened. That's also why I've added all those sanity checks if you
> enable IRQ tracing.
>
> > Is it possible to set this bit at anyplace the hard irqs are disabled,
> > so then we could check whether this bit is set to know whether hard irqs
> > are disabled? Then it seems that in MASKED_INTERRUPT, we need set this
> > bit where MSR_EE is cleared for something other than decrementer. Maybe
> > I missed too much things?
>
> Either that bit or PACA_IRQ_EE. Both indicate that interrupts are hard
> disabled.
>
> There are some rare cases where do do change MSR:EE without touching
> those bits, only when we're going to restore it shortly afterward in the
> kernel asm exception entry/exit path for example.
Thank you very much for the detailed education. I'll reread the code,
and might bother you again if have further questions.
Thanks, Zhong
> Cheers,
> Ben.
>
> > Thanks, Zhong
> >
> > ===================
> > diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c
> > index 64c97d8..b5f7597 100644
> > --- a/arch/powerpc/platforms/pseries/hotplug-cpu.c
> > +++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c
> > @@ -130,6 +130,8 @@ static void pseries_mach_cpu_die(void)
> > extended_cede_processor(cede_latency_hint);
> > }
> >
> > + local_irq_disable();
> > +
> > if (!get_lppaca()->shared_proc)
> > get_lppaca()->donate_dedicated_cpu = 0;
> > get_lppaca()->idle = 0;
> > diff --git a/arch/powerpc/platforms/pseries/plpar_wrappers.h b/arch/powerpc/platforms/pseries/plpar_wrappers.h
> > index 13e8cc4..07560d8 100644
> > --- a/arch/powerpc/platforms/pseries/plpar_wrappers.h
> > +++ b/arch/powerpc/platforms/pseries/plpar_wrappers.h
> > @@ -2,6 +2,7 @@
> > #define _PSERIES_PLPAR_WRAPPERS_H
> >
> > #include <linux/string.h>
> > +#include <linux/irqflags.h>
> >
> > #include <asm/hvcall.h>
> > #include <asm/paca.h>
> > @@ -41,7 +42,19 @@ static inline long extended_cede_processor(unsigned long latency_hint)
> > u8 old_latency_hint = get_cede_latency_hint();
> >
> > set_cede_latency_hint(latency_hint);
> > +
> > + while (!prep_irq_for_idle()) {
> > + local_irq_enable();
> > + local_irq_disable();
> > + }
> > +
> > rc = cede_processor();
> > +#ifdef CONFIG_TRACE_IRQFLAGS
> > + /* Ensure that H_CEDE returns with IRQs on */
> > + if (WARN_ON(!(mfmsr() & MSR_EE)))
> > + __hard_irq_enable();
> > +#endif
> > +
> > set_cede_latency_hint(old_latency_hint);
> >
> > return rc;
> > ===================
> >
> >
> > >
> > > Cheers,
> > > Ben.
> > >
> > > > [ 56.618846] WARNING: at arch/powerpc/kernel/irq.c:240
> > > > [ 56.618851] Modules linked in: rcutorture ipv6 dm_mod ext3 jbd mbcache sg sd_mod crc_t10dif ibmvscsic scsi_transport_srp scsi_tgt ibmveth
> > > > [ 56.618883] NIP: c00000000000ff94 LR: c00000000067a5e0 CTR: 0000000000000001
> > > > [ 56.618889] REGS: c0000001fef6bbe0 TRAP: 0700 Not tainted (3.6.0-rc1-autokern1)
> > > > [ 56.618894] MSR: 8000000000029032 <SF,EE,ME,IR,DR,RI> CR: 42000082 XER: 20000000
> > > > [ 56.618913] SOFTE: 1
> > > > [ 56.618916] CFAR: c00000000067a5dc
> > > > [ 56.618920] TASK = c0000001feed79a0[0] 'swapper/5' THREAD: c0000001fef68000 CPU: 5
> > > > GPR00: 0000000000000001 c0000001fef6be60 c000000000f9ca08 0000000000000001
> > > > GPR04: 0000000000000001 0000000000000008 0000000000000001 0000000000000000
> > > > GPR08: 0000000000000000 c0000001feed79a0 0008a80000000000 0000000000000000
> > > > GPR12: 0000000022000082 c00000000f330f00 c0000001fef6bf90 000000000f394b4c
> > > > GPR16: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
> > > > GPR20: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
> > > > GPR24: c000000000fe8f80 0000000000000008 0000000000000028 0000000000000000
> > > > GPR28: 0000000000000000 0000000000000020 c000000000f1ab40 0000000000000001
> > > > [ 56.619014] NIP [c00000000000ff94] .arch_local_irq_restore+0x34/0xa0
> > > > [ 56.619020] LR [c00000000067a5e0] .start_secondary+0x368/0x37c
> > > > [ 56.619025] Call Trace:
> > > > [ 56.619030] [c0000001fef6be60] [c000000001ba0500] 0xc000000001ba0500 (unreliable)
> > > > [ 56.619038] [c0000001fef6bed0] [c00000000067a5e0] .start_secondary+0x368/0x37c
> > > > [ 56.619046] [c0000001fef6bf90] [c000000000009380] .start_secondary_resume+0x10/0x14
> > > > [ 56.619052] Instruction dump:
> > > > [ 56.619056] f8010010 f821ff91 986d022a 2fa30000 419e0054 880d022b 78000621 41820048
> > > > [ 56.619071] 2f800001 40de0064 7c0000a6 78008fe2 <0b000000> 2fa00000 40de0050 38000000
> > > > [ 56.619088] ---[ end trace 0199c0d783d7f9ba ]---
> > > >
> > > > Reported-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
> > > > Signed-off-by: Li Zhong <zhong@linux.vnet.ibm.com>
> > > > ---
> > > > arch/powerpc/platforms/pseries/hotplug-cpu.c | 2 ++
> > > > 1 files changed, 2 insertions(+), 0 deletions(-)
> > > >
> > > > diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c
> > > > index 64c97d8..8de539a 100644
> > > > --- a/arch/powerpc/platforms/pseries/hotplug-cpu.c
> > > > +++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c
> > > > @@ -137,6 +137,8 @@ static void pseries_mach_cpu_die(void)
> > > > if (get_preferred_offline_state(cpu) == CPU_STATE_ONLINE) {
> > > > unregister_slb_shadow(hwcpu);
> > > >
> > > > + __hard_irq_disable();
> > > > +
> > > > /*
> > > > * Call to start_secondary_resume() will not return.
> > > > * Kernel stack will be reset and start_secondary()
> > >
> > >
> >
>
>
^ permalink raw reply related
* Re: [PATCH] powerpc/pnv: Avoid bogus output
From: Gavin Shan @ 2012-10-18 5:53 UTC (permalink / raw)
To: Gavin Shan; +Cc: linuxppc-dev
In-Reply-To: <1350528404-8009-1-git-send-email-shangw@linux.vnet.ibm.com>
[-- Attachment #1: Type: text/plain, Size: 2439 bytes --]
On Thu, Oct 18, 2012 at 10:46:44AM +0800, Gavin Shan wrote:
>There're couples of functions defined to print debugging messages
>during initializing P7IOC. However, we got bogus output from those
>functions like pe_info(). The problem here is that the message
>level (the first parameter to printk()) isn't printable and that
>caused the bogus output.
>
>The patch fixes the issue by merging __pe_printk() to the macro
>define_pe_printk_level() so that we can pass the message level
>directly to printk().
>
>Reported-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
>Signed-off-by: Gavin Shan <shangw@linux.vnet.ibm.com>
>---
> arch/powerpc/platforms/powernv/pci-ioda.c | 25 +++++++++++--------------
> 1 files changed, 11 insertions(+), 14 deletions(-)
>
>diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c
>index 07ce33c..ff7e7a1 100644
>--- a/arch/powerpc/platforms/powernv/pci-ioda.c
>+++ b/arch/powerpc/platforms/powernv/pci-ioda.c
>@@ -34,24 +34,12 @@
> #include "powernv.h"
> #include "pci.h"
>
>-static int __pe_printk(const char *level, const struct pnv_ioda_pe *pe,
>- struct va_format *vaf)
>-{
>- char pfix[32];
>-
>- if (pe->pdev)
>- strlcpy(pfix, dev_name(&pe->pdev->dev), sizeof(pfix));
>- else
>- sprintf(pfix, "%04x:%02x ",
>- pci_domain_nr(pe->pbus), pe->pbus->number);
>- return printk("pci %s%s: [PE# %.3d] %pV", level, pfix, pe->pe_number, vaf);
>-}
>-
> #define define_pe_printk_level(func, kern_level) \
> static int func(const struct pnv_ioda_pe *pe, const char *fmt, ...) \
> { \
> struct va_format vaf; \
> va_list args; \
>+ char pfix[32]; \
> int r; \
> \
> va_start(args, fmt); \
>@@ -59,7 +47,16 @@ static int func(const struct pnv_ioda_pe *pe, const char *fmt, ...) \
> vaf.fmt = fmt; \
> vaf.va = &args; \
> \
>- r = __pe_printk(kern_level, pe, &vaf); \
>+ if (pe->pdev) \
>+ strlcpy(pfix, dev_name(&pe->pdev->dev), \
>+ sizeof(pfix)); \
>+ else \
>+ sprintf(pfix, "%04x:%02x ", \
>+ pci_domain_nr(pe->pbus), \
The space before sprintf() should be replaced by "tab" as
the attached patch :-)
>+ pe->pbus->number); \
>+ r = printk(kern_level "pci %s: [PE# %.3d] %pV", \
>+ pfix, pe->pe_number, &vaf); \
>+ \
> va_end(args); \
> \
> return r; \
Thanks,
Gavin
[-- Attachment #2: 0001-powerpc-pnv-Avoid-bogus-output.patch --]
[-- Type: text/x-diff, Size: 2392 bytes --]
>From 4ee539b85676c986122087fe84d59e3b764396d5 Mon Sep 17 00:00:00 2001
From: Gavin Shan <shangw@linux.vnet.ibm.com>
Date: Thu, 18 Oct 2012 10:09:12 +0800
Subject: [PATCH] powerpc/pnv: Avoid bogus output
There're couples of functions defined to print debugging messages
during initializing P7IOC. However, we got bogus output from those
functions like pe_info(). The problem here is that the message
level (the first parameter to printk()) isn't printable and that
caused the bogus output.
The patch fixes the issue by merging __pe_printk() to the macro
define_pe_printk_level() so that we can pass the message level
directly to printk().
Reported-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Gavin Shan <shangw@linux.vnet.ibm.com>
---
arch/powerpc/platforms/powernv/pci-ioda.c | 25 +++++++++++--------------
1 files changed, 11 insertions(+), 14 deletions(-)
diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c
index 07ce33c..7687778 100644
--- a/arch/powerpc/platforms/powernv/pci-ioda.c
+++ b/arch/powerpc/platforms/powernv/pci-ioda.c
@@ -34,24 +34,12 @@
#include "powernv.h"
#include "pci.h"
-static int __pe_printk(const char *level, const struct pnv_ioda_pe *pe,
- struct va_format *vaf)
-{
- char pfix[32];
-
- if (pe->pdev)
- strlcpy(pfix, dev_name(&pe->pdev->dev), sizeof(pfix));
- else
- sprintf(pfix, "%04x:%02x ",
- pci_domain_nr(pe->pbus), pe->pbus->number);
- return printk("pci %s%s: [PE# %.3d] %pV", level, pfix, pe->pe_number, vaf);
-}
-
#define define_pe_printk_level(func, kern_level) \
static int func(const struct pnv_ioda_pe *pe, const char *fmt, ...) \
{ \
struct va_format vaf; \
va_list args; \
+ char pfix[32]; \
int r; \
\
va_start(args, fmt); \
@@ -59,7 +47,16 @@ static int func(const struct pnv_ioda_pe *pe, const char *fmt, ...) \
vaf.fmt = fmt; \
vaf.va = &args; \
\
- r = __pe_printk(kern_level, pe, &vaf); \
+ if (pe->pdev) \
+ strlcpy(pfix, dev_name(&pe->pdev->dev), \
+ sizeof(pfix)); \
+ else \
+ sprintf(pfix, "%04x:%02x ", \
+ pci_domain_nr(pe->pbus), \
+ pe->pbus->number); \
+ r = printk(kern_level "pci %s: [PE# %.3d] %pV", \
+ pfix, pe->pe_number, &vaf); \
+ \
va_end(args); \
\
return r; \
--
1.7.5.4
^ permalink raw reply related
* [v2][PATCH 1/2] powerpc/kgdb: Fix a single stgep case of lazy IRQ
From: Tiejun Chen @ 2012-10-18 2:47 UTC (permalink / raw)
To: benh; +Cc: linuxppc-dev, jason.wessel
When we're in kgdb_singlestep(), we have to work around to get
thread_info by copying from the kernel stack before calling
kgdb_handle_exception(), then copying it back afterwards.
But for PPC64, we have a lazy interrupt implementation. So after
copying thread info frome kernle stack, if we need to replay an
interrupt, we shouldn't restore that previous backup thread info
to make sure we can replay an interrupt lately with a proper
thread info.
This patch use __check_irq_replay() to guarantee this process.
Signed-off-by: Tiejun Chen <tiejun.chen@windriver.com>
---
arch/powerpc/kernel/irq.c | 12 +++++++++++-
arch/powerpc/kernel/kgdb.c | 7 ++++---
2 files changed, 15 insertions(+), 4 deletions(-)
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index 71413f4..a773789 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -332,7 +332,17 @@ bool prep_irq_for_idle(void)
return true;
}
-#endif /* CONFIG_PPC64 */
+notrace unsigned int check_irq_replay(void)
+{
+ return __check_irq_replay();
+}
+#else /* CONFIG_PPC64 */
+notrace unsigned int check_irq_replay(void)
+{
+ return 0;
+}
+#endif /* !CONFIG_PPC64 */
+EXPORT_SYMBOL(check_irq_replay);
int arch_show_interrupts(struct seq_file *p, int prec)
{
diff --git a/arch/powerpc/kernel/kgdb.c b/arch/powerpc/kernel/kgdb.c
index c470a40..c4af341 100644
--- a/arch/powerpc/kernel/kgdb.c
+++ b/arch/powerpc/kernel/kgdb.c
@@ -151,6 +151,7 @@ static int kgdb_handle_breakpoint(struct pt_regs *regs)
return 1;
}
+extern notrace unsigned int check_irq_replay(void);
static int kgdb_singlestep(struct pt_regs *regs)
{
struct thread_info *thread_info, *exception_thread_info;
@@ -181,9 +182,9 @@ static int kgdb_singlestep(struct pt_regs *regs)
kgdb_handle_exception(0, SIGTRAP, 0, regs);
- if (thread_info != exception_thread_info)
- /* Restore current_thread_info lastly. */
- memcpy(exception_thread_info, backup_current_thread_info, sizeof *thread_info);
+ if ((thread_info != exception_thread_info) && (!check_irq_replay()))
+ /* Restore current_thread_info lastly only if we don't replay interrupt. */
+ memcpy(exception_thread_info, backup_current_thread_info, sizeof *thread_info);
return 1;
}
--
1.7.9.5
^ permalink raw reply related
* [v2][PATCH 2/2] PPC_BOOK3E/KGDB: support kgdb kernel space
From: Tiejun Chen @ 2012-10-18 2:47 UTC (permalink / raw)
To: benh; +Cc: linuxppc-dev, jason.wessel
In-Reply-To: <1350528455-4751-1-git-send-email-tiejun.chen@windriver.com>
We can support KGDB with current debug exception for BOOK3E, so we
should initial specific dbg_kstack to avoid overwriting other thing.
Signed-off-by: Tiejun Chen <tiejun.chen@windriver.com>
---
v2:
Move the label before the conditional
arch/powerpc/kernel/exceptions-64e.S | 5 ++++-
arch/powerpc/kernel/paca.c | 10 ++++++++++
2 files changed, 14 insertions(+), 1 deletion(-)
diff --git a/arch/powerpc/kernel/exceptions-64e.S b/arch/powerpc/kernel/exceptions-64e.S
index 4684e33..73ce1a7 100644
--- a/arch/powerpc/kernel/exceptions-64e.S
+++ b/arch/powerpc/kernel/exceptions-64e.S
@@ -538,12 +538,15 @@ kernel_dbg_exc:
mfspr r13,SPRN_SPRG_DBG_SCRATCH
rfdi
+1:
/* Normal debug exception */
+#ifndef CONFIG_KGDB
/* XXX We only handle coming from userspace for now since we can't
* quite save properly an interrupted kernel state yet
*/
-1: andi. r14,r11,MSR_PR; /* check for userspace again */
+ andi. r14,r11,MSR_PR; /* check for userspace again */
beq kernel_dbg_exc; /* if from kernel mode */
+#endif
/* Now we mash up things to make it look like we are coming on a
* normal exception
diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c
index cd6da85..28a5141 100644
--- a/arch/powerpc/kernel/paca.c
+++ b/arch/powerpc/kernel/paca.c
@@ -122,6 +122,13 @@ EXPORT_SYMBOL(paca);
struct paca_struct boot_paca;
+void *debug_kstack;
+static void allocate_dbg_kstack(unsigned long limit)
+{
+ debug_kstack = __va(memblock_alloc_base(THREAD_SIZE,
+ THREAD_SIZE, limit));
+}
+
void __init initialise_paca(struct paca_struct *new_paca, int cpu)
{
/* The TOC register (GPR2) points 32kB into the TOC, so that 64kB
@@ -133,6 +140,7 @@ void __init initialise_paca(struct paca_struct *new_paca, int cpu)
new_paca->lppaca_ptr = new_lppaca(cpu);
#else
new_paca->kernel_pgd = swapper_pg_dir;
+ new_paca->dbg_kstack = debug_kstack;
#endif
new_paca->lock_token = 0x8000;
new_paca->paca_index = cpu;
@@ -192,6 +200,8 @@ void __init allocate_pacas(void)
allocate_lppacas(nr_cpu_ids, limit);
+ allocate_dbg_kstack(limit);
+
/* Can't use for_each_*_cpu, as they aren't functional yet */
for (cpu = 0; cpu < nr_cpu_ids; cpu++)
initialise_paca(&paca[cpu], cpu);
--
1.7.9.5
^ permalink raw reply related
* [PATCH] powerpc/pnv: Avoid bogus output
From: Gavin Shan @ 2012-10-18 2:46 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Gavin Shan
There're couples of functions defined to print debugging messages
during initializing P7IOC. However, we got bogus output from those
functions like pe_info(). The problem here is that the message
level (the first parameter to printk()) isn't printable and that
caused the bogus output.
The patch fixes the issue by merging __pe_printk() to the macro
define_pe_printk_level() so that we can pass the message level
directly to printk().
Reported-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Gavin Shan <shangw@linux.vnet.ibm.com>
---
arch/powerpc/platforms/powernv/pci-ioda.c | 25 +++++++++++--------------
1 files changed, 11 insertions(+), 14 deletions(-)
diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c
index 07ce33c..ff7e7a1 100644
--- a/arch/powerpc/platforms/powernv/pci-ioda.c
+++ b/arch/powerpc/platforms/powernv/pci-ioda.c
@@ -34,24 +34,12 @@
#include "powernv.h"
#include "pci.h"
-static int __pe_printk(const char *level, const struct pnv_ioda_pe *pe,
- struct va_format *vaf)
-{
- char pfix[32];
-
- if (pe->pdev)
- strlcpy(pfix, dev_name(&pe->pdev->dev), sizeof(pfix));
- else
- sprintf(pfix, "%04x:%02x ",
- pci_domain_nr(pe->pbus), pe->pbus->number);
- return printk("pci %s%s: [PE# %.3d] %pV", level, pfix, pe->pe_number, vaf);
-}
-
#define define_pe_printk_level(func, kern_level) \
static int func(const struct pnv_ioda_pe *pe, const char *fmt, ...) \
{ \
struct va_format vaf; \
va_list args; \
+ char pfix[32]; \
int r; \
\
va_start(args, fmt); \
@@ -59,7 +47,16 @@ static int func(const struct pnv_ioda_pe *pe, const char *fmt, ...) \
vaf.fmt = fmt; \
vaf.va = &args; \
\
- r = __pe_printk(kern_level, pe, &vaf); \
+ if (pe->pdev) \
+ strlcpy(pfix, dev_name(&pe->pdev->dev), \
+ sizeof(pfix)); \
+ else \
+ sprintf(pfix, "%04x:%02x ", \
+ pci_domain_nr(pe->pbus), \
+ pe->pbus->number); \
+ r = printk(kern_level "pci %s: [PE# %.3d] %pV", \
+ pfix, pe->pe_number, &vaf); \
+ \
va_end(args); \
\
return r; \
--
1.7.5.4
^ permalink raw reply related
* Re: [PATCH 2/2] PPC_BOOK3E/KGDB: support kgdb kernel space
From: tiejun.chen @ 2012-10-18 1:47 UTC (permalink / raw)
To: Andreas Schwab; +Cc: linuxppc-dev, jason.wessel
In-Reply-To: <m28vb5s3o4.fsf@igel.home>
On 10/17/2012 08:07 PM, Andreas Schwab wrote:
> Tiejun Chen <tiejun.chen@windriver.com> writes:
>
>> diff --git a/arch/powerpc/kernel/exceptions-64e.S b/arch/powerpc/kernel/exceptions-64e.S
>> index 4684e33..ed5862d 100644
>> --- a/arch/powerpc/kernel/exceptions-64e.S
>> +++ b/arch/powerpc/kernel/exceptions-64e.S
>> @@ -539,11 +539,15 @@ kernel_dbg_exc:
>> rfdi
>>
>> /* Normal debug exception */
>> +#ifndef CONFIG_KGDB
>> /* XXX We only handle coming from userspace for now since we can't
>> * quite save properly an interrupted kernel state yet
>> */
>> 1: andi. r14,r11,MSR_PR; /* check for userspace again */
>> beq kernel_dbg_exc; /* if from kernel mode */
>> +#else
>> +1:
>> +#endif
>
> You could move the label before the conditional.
Okay.
diff --git a/arch/powerpc/kernel/exceptions-64e.S
b/arch/powerpc/kernel/exceptions-64e.S
index 4684e33..73ce1a7 100644
--- a/arch/powerpc/kernel/exceptions-64e.S
+++ b/arch/powerpc/kernel/exceptions-64e.S
@@ -538,12 +538,15 @@ kernel_dbg_exc:
mfspr r13,SPRN_SPRG_DBG_SCRATCH
rfdi
+1:
/* Normal debug exception */
+#ifndef CONFIG_KGDB
/* XXX We only handle coming from userspace for now since we can't
* quite save properly an interrupted kernel state yet
*/
-1: andi. r14,r11,MSR_PR; /* check for userspace again */
+ andi. r14,r11,MSR_PR; /* check for userspace again */
beq kernel_dbg_exc; /* if from kernel mode */
+#endif
/* Now we mash up things to make it look like we are coming on a
* normal exception
...
Tiejun
^ permalink raw reply related
* Re: [RFC PATCH powerpc] Fix a lazy irq related WARING in arch_local_irq_restore()
From: Benjamin Herrenschmidt @ 2012-10-17 23:54 UTC (permalink / raw)
To: Li Zhong; +Cc: Paul Mackerras, Paul E. McKenney, PowerPC email list
In-Reply-To: <1348654234.2635.31.camel@ThinkPad-T420>
On Wed, 2012-09-26 at 18:10 +0800, Li Zhong wrote:
../...
Sorry got distracted, got back on this patch today:
> > We might need to "sanitize" the enable state in the PACA before we
> > actually enter NAP or in the return from NAP code, like we do for normal
> > idle code...
>
> Hi Ben,
>
> After some further reading of the code, I updated the code as following,
> but I'm not very sure, and guess it most probably has some issues ...
> Could you please help to review and give your comments?
I think it's still not right, see below
> In extended_cede_processor(), if there is still lazy irq pending, I used
> local_irq_enable() to make sure the irq replayed and flags cleared, but
> I'm not sure whether it is a proper way.
Right but that will break things for idle. In idle, if you have
re-enabled interrupts, you need to return and essentially abort the
attempt at going to nap mode, because the interrupt might have set need
resched. That's why we normally just check if something's pending and
return, letting the upper levels re-enable interrupts and do all the
dirty work for us.
Now, hotplug might differ here in what it needs, but in any case,
extended_cede_processor doesn't seem to be the right place to handle it,
at best that function should return if it thinks there's something that
needs to be done and let the upper layers deal with it appropriately.
> In pseries_mach_cpu_die(), I added local_irq_disable() after cede, and
> prepare for the start_secondary_resume(), but I'm not sure whether we
> also need a hard_irq_disable() here.
You probably do if it's going to go back to the start secondary path. It
shouldn't hurt in any case as long as start_secondary_resume()
eventually does a local_irq_enable().
> I'm still a little confused by the meaning of PACA_IRQ_HARD_DIS in
> irq_happened. From the checking at the warning point, it seems only
> irq_happened equaling 0x1(PACA_IRQ_HARD_DIS) means hard irqs are
> disabled.
No. They are disabled if any bit in there corresponding to a "level"
interrupt is set as well. Only the "edge" interrupts (and decrementer
which we treat as edge and reset to a high value when it kicks) are
ignored for the sake of HW irq state.
The reason we have this IRQ_HARD_DIS bit is to indicate that a 'manual'
hard disabling occurred (by opposition to one happening as a result of
an external interrupt).
We need that so we can avoid doing an mfspr() in local_irq_enable() and
entirely rely on the content of irq_happened to know whether interrupts
are hard enabled or hard disabled.
We do that because mfspr is a fairly expensive instruction. But that
means that we need to make sure we always have a consistent content in
irq_happened. That's also why I've added all those sanity checks if you
enable IRQ tracing.
> Is it possible to set this bit at anyplace the hard irqs are disabled,
> so then we could check whether this bit is set to know whether hard irqs
> are disabled? Then it seems that in MASKED_INTERRUPT, we need set this
> bit where MSR_EE is cleared for something other than decrementer. Maybe
> I missed too much things?
Either that bit or PACA_IRQ_EE. Both indicate that interrupts are hard
disabled.
There are some rare cases where do do change MSR:EE without touching
those bits, only when we're going to restore it shortly afterward in the
kernel asm exception entry/exit path for example.
Cheers,
Ben.
> Thanks, Zhong
>
> ===================
> diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c
> index 64c97d8..b5f7597 100644
> --- a/arch/powerpc/platforms/pseries/hotplug-cpu.c
> +++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c
> @@ -130,6 +130,8 @@ static void pseries_mach_cpu_die(void)
> extended_cede_processor(cede_latency_hint);
> }
>
> + local_irq_disable();
> +
> if (!get_lppaca()->shared_proc)
> get_lppaca()->donate_dedicated_cpu = 0;
> get_lppaca()->idle = 0;
> diff --git a/arch/powerpc/platforms/pseries/plpar_wrappers.h b/arch/powerpc/platforms/pseries/plpar_wrappers.h
> index 13e8cc4..07560d8 100644
> --- a/arch/powerpc/platforms/pseries/plpar_wrappers.h
> +++ b/arch/powerpc/platforms/pseries/plpar_wrappers.h
> @@ -2,6 +2,7 @@
> #define _PSERIES_PLPAR_WRAPPERS_H
>
> #include <linux/string.h>
> +#include <linux/irqflags.h>
>
> #include <asm/hvcall.h>
> #include <asm/paca.h>
> @@ -41,7 +42,19 @@ static inline long extended_cede_processor(unsigned long latency_hint)
> u8 old_latency_hint = get_cede_latency_hint();
>
> set_cede_latency_hint(latency_hint);
> +
> + while (!prep_irq_for_idle()) {
> + local_irq_enable();
> + local_irq_disable();
> + }
> +
> rc = cede_processor();
> +#ifdef CONFIG_TRACE_IRQFLAGS
> + /* Ensure that H_CEDE returns with IRQs on */
> + if (WARN_ON(!(mfmsr() & MSR_EE)))
> + __hard_irq_enable();
> +#endif
> +
> set_cede_latency_hint(old_latency_hint);
>
> return rc;
> ===================
>
>
> >
> > Cheers,
> > Ben.
> >
> > > [ 56.618846] WARNING: at arch/powerpc/kernel/irq.c:240
> > > [ 56.618851] Modules linked in: rcutorture ipv6 dm_mod ext3 jbd mbcache sg sd_mod crc_t10dif ibmvscsic scsi_transport_srp scsi_tgt ibmveth
> > > [ 56.618883] NIP: c00000000000ff94 LR: c00000000067a5e0 CTR: 0000000000000001
> > > [ 56.618889] REGS: c0000001fef6bbe0 TRAP: 0700 Not tainted (3.6.0-rc1-autokern1)
> > > [ 56.618894] MSR: 8000000000029032 <SF,EE,ME,IR,DR,RI> CR: 42000082 XER: 20000000
> > > [ 56.618913] SOFTE: 1
> > > [ 56.618916] CFAR: c00000000067a5dc
> > > [ 56.618920] TASK = c0000001feed79a0[0] 'swapper/5' THREAD: c0000001fef68000 CPU: 5
> > > GPR00: 0000000000000001 c0000001fef6be60 c000000000f9ca08 0000000000000001
> > > GPR04: 0000000000000001 0000000000000008 0000000000000001 0000000000000000
> > > GPR08: 0000000000000000 c0000001feed79a0 0008a80000000000 0000000000000000
> > > GPR12: 0000000022000082 c00000000f330f00 c0000001fef6bf90 000000000f394b4c
> > > GPR16: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
> > > GPR20: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
> > > GPR24: c000000000fe8f80 0000000000000008 0000000000000028 0000000000000000
> > > GPR28: 0000000000000000 0000000000000020 c000000000f1ab40 0000000000000001
> > > [ 56.619014] NIP [c00000000000ff94] .arch_local_irq_restore+0x34/0xa0
> > > [ 56.619020] LR [c00000000067a5e0] .start_secondary+0x368/0x37c
> > > [ 56.619025] Call Trace:
> > > [ 56.619030] [c0000001fef6be60] [c000000001ba0500] 0xc000000001ba0500 (unreliable)
> > > [ 56.619038] [c0000001fef6bed0] [c00000000067a5e0] .start_secondary+0x368/0x37c
> > > [ 56.619046] [c0000001fef6bf90] [c000000000009380] .start_secondary_resume+0x10/0x14
> > > [ 56.619052] Instruction dump:
> > > [ 56.619056] f8010010 f821ff91 986d022a 2fa30000 419e0054 880d022b 78000621 41820048
> > > [ 56.619071] 2f800001 40de0064 7c0000a6 78008fe2 <0b000000> 2fa00000 40de0050 38000000
> > > [ 56.619088] ---[ end trace 0199c0d783d7f9ba ]---
> > >
> > > Reported-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
> > > Signed-off-by: Li Zhong <zhong@linux.vnet.ibm.com>
> > > ---
> > > arch/powerpc/platforms/pseries/hotplug-cpu.c | 2 ++
> > > 1 files changed, 2 insertions(+), 0 deletions(-)
> > >
> > > diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c
> > > index 64c97d8..8de539a 100644
> > > --- a/arch/powerpc/platforms/pseries/hotplug-cpu.c
> > > +++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c
> > > @@ -137,6 +137,8 @@ static void pseries_mach_cpu_die(void)
> > > if (get_preferred_offline_state(cpu) == CPU_STATE_ONLINE) {
> > > unregister_slb_shadow(hwcpu);
> > >
> > > + __hard_irq_disable();
> > > +
> > > /*
> > > * Call to start_secondary_resume() will not return.
> > > * Kernel stack will be reset and start_secondary()
> >
> >
>
^ permalink raw reply
* ELDK 4.2/kilauea/3.5+ kernel broken
From: Robert Berger @ 2012-10-17 18:15 UTC (permalink / raw)
To: linuxppc-dev
[-- Attachment #1: Type: text/plain, Size: 3240 bytes --]
Hi,
The attached patch from here:
http://thread.gmane.org/gmane.linux.ports.ppc.embedded/49637/focus=49903
works as far as I can say from > 3.2 kernels until 3.4.12 and applies
happily even on 3.5.
Unfortunately the last kernel version which boots on a kilauea with ELDK
4.2 is v3.4.12 (with the attached patch applied). BTW v3.6 does not need
the patch anymore, but exposes the same behavior as described below.
A default config with PPC_EARLY_DEBUG_40x makes the board stuck instead
of rebooting, which happens from v3.5 onwards (with patch applied):
U-Boot 2012.10-classic-rber-dirty (Oct 17 2012 - 11:35:47)
CPU: AMCC PowerPC 405EX Rev. A at 533.333 MHz (PLB=177 OPB=88 EBC=88)
Security support
Bootstrap Option H - Boot ROM Location I2C (Addr 0x52)
16 kB I-Cache 16 kB D-Cache
Board: Kilauea - AMCC PPC405EX Evaluation Board (CPLD rev. 0)
I2C: ready
DRAM: 256 MiB (ECC not enabled, 355 MHz, CL4)
Reserving 16384k for kernel logbuffer at 0fffb000
Top of RAM usable for U-Boot at: 0fffb000
Reserving 432k for U-Boot at: 0ff8e000
Reserving 1040k for malloc() at: 0fe8a000
Reserving 132 Bytes for Board Info at: 0fe89f7c
Reserving 104 Bytes for Global Data at: 0fe89f14
Stack Pointer at: 0fe89f00
New Stack Pointer is: 0fe89f00
Now running in RAM - U-Boot at: 0ff8e000
Flash: 64 MiB
NAND: 64 MiB
PCI: Bus Dev VenId DevId Class Int
PCIE0: link is not up.
PCIE1: link is not up.
U-Boot relocated to 0ff8e000
Net: ppc_4xx_eth0, ppc_4xx_eth1
Hit any key to stop autoboot: 0
=> run rootfs_nfs
Waiting for PHY auto negotiation to complete... done
ENET Speed is 1000 Mbps - FULL duplex connection (EMAC0)
Using ppc_4xx_eth0 device
TFTP from server 192.168.5.5; our IP address is 192.168.5.11
Filename 'kilauea/uImage'.
Load address: 0x400000
Loading: #################################################################
######################################################
done
Bytes transferred = 1738410 (1a86aa hex)
Using ppc_4xx_eth0 device
TFTP from server 192.168.5.5; our IP address is 192.168.5.11
Filename 'kilauea/kilauea.dtb'.
Load address: 0x800000
Loading: #
done
Bytes transferred = 8667 (21db hex)
## Booting kernel from Legacy Image at 00400000 ...
Image Name: Linux-3.5.0-classic-rber-dirty
Created: 2012-10-17 16:48:39 UTC
Image Type: PowerPC Linux Kernel Image (gzip compressed)
Data Size: 1738346 Bytes = 1.7 MiB
Load Address: 00000000
Entry Point: 00000000
Verifying Checksum ... OK
## Flattened Device Tree blob at 00800000
Booting using the fdt blob at 0x00800000
Uncompressing Kernel Image ... OK
Loading Device Tree to 00ffa000, end 00fff1da ... OK
---> here the board reboots into u-boot <---
U-Boot 2012.10-classic-rber-dirty (Oct 17 2012 - 11:35:47)
CPU: AMCC PowerPC 405EX Rev. A at 533.333 MHz (PLB=177 OPB=88 EBC=88)
Security support
Bootstrap Option H - Boot ROM Location I2C (Addr 0x52)
16 kB I-Cache 16 kB D-Cache
Board: Kilauea - AMCC PPC405EX Evaluation Board (CPLD rev. 0)
...
Please advise.
Regards,
Robert
..."Teaching of beginners should be done by a master, not by a
hack." - Deming
My public pgp key is available,at:
http://pgp.mit.edu:11371/pks/lookup?op=get&search=0x90320BF1
[-- Attachment #2: bake-your-noodle.patch --]
[-- Type: text/x-patch, Size: 3327 bytes --]
>From e0b1ac84bfd539482bc88b943724e577e6b8dfb3 Mon Sep 17 00:00:00 2001
From: Tony Breeds <tony@bakeyournoodle.com>
Date: Mon, 2 Apr 2012 16:20:35 +1000
Subject: [PATCH] powerpc/boot: Only build board support files when required.
Currently we build all board files regardless of the final zImage
target. This is sub-optimal (in terms on compilation) and leads to
problems in one platform needlessly causing failures for other
platforms.
Use the Kconfig variables to selectively construct this board files to
build.
Signed-off-by: Tony Breeds <tony@bakeyournoodle.com>
---
arch/powerpc/boot/Makefile | 56 +++++++++++++++++++++++++++++++++----------
1 files changed, 43 insertions(+), 13 deletions(-)
diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
index e8461cb..a3c4ae0 100644
--- a/arch/powerpc/boot/Makefile
+++ b/arch/powerpc/boot/Makefile
@@ -69,19 +69,49 @@ src-wlib := string.S crt0.S crtsavres.S stdio.c main.c \
4xx.c ebony.c mv64x60.c mpsc.c mv64x60_i2c.c cuboot.c bamboo.c \
cpm-serial.c stdlib.c mpc52xx-psc.c planetcore.c uartlite.c \
fsl-soc.c mpc8xx.c pq2.c ugecon.c
-src-plat := of.c cuboot-52xx.c cuboot-824x.c cuboot-83xx.c cuboot-85xx.c holly.c \
- cuboot-ebony.c cuboot-hotfoot.c epapr.c treeboot-ebony.c \
- prpmc2800.c \
- ps3-head.S ps3-hvcall.S ps3.c treeboot-bamboo.c cuboot-8xx.c \
- cuboot-pq2.c cuboot-sequoia.c treeboot-walnut.c \
- cuboot-bamboo.c cuboot-mpc7448hpc2.c cuboot-taishan.c \
- fixed-head.S ep88xc.c ep405.c cuboot-c2k.c \
- cuboot-katmai.c cuboot-rainier.c redboot-8xx.c ep8248e.c \
- cuboot-warp.c cuboot-85xx-cpm2.c cuboot-yosemite.c simpleboot.c \
- virtex405-head.S virtex.c redboot-83xx.c cuboot-sam440ep.c \
- cuboot-acadia.c cuboot-amigaone.c cuboot-kilauea.c \
- gamecube-head.S gamecube.c wii-head.S wii.c treeboot-iss4xx.c \
- treeboot-currituck.c
+src-plat := of.c
+ifeq ($(CONFIG_40x),y)
+src-plat += fixed-head.S ep405.c cuboot-hotfoot.c treeboot-walnut.c \
+ cuboot-acadia.c cuboot-kilauea.c \
+ simpleboot.c virtex405-head.S virtex.c
+endif
+ifeq ($(CONFIG_44x),y)
+src-plat += treeboot-ebony cuboot-ebony treeboot-bamboo cuboot-bamboo \
+ cuboot-sam440ep.c cuboot-sequoia.c cuboot-rainier.c \
+ cuboot-taishan.c cuboot-katmai.c cuboot-warp.c \
+ cuboot-yosemite.c treeboot-iss4xx.c treeboot-currituck.c \
+ simpleboot.c fixed-head.S virtex.c
+endif
+ifeq ($(CONFIG_8xx),y)
+src-plat += cuboot-8xx.c fixed-head.S ep88xc.c redboot-8xx.c
+endif
+ifeq ($(CONFIG_PPC_MPC52xx),y)
+src-plat += cuboot-52xx.c
+endif
+ifeq ($(CONFIG_PPC_82xx),y)
+src-plat += cuboot-pq2.c fixed-head.S ep8248e.c cuboot-824x.c
+endif
+ifeq ($(CONFIG_PPC_82xx),y)
+src-plat += cuboot-83xx.c fixed-head.S redboot-83xx.c
+endif
+ifeq ($(CONFIG_FSL_SOC_BOOKE),y)
+src-plat += cuboot-85xx.c cuboot-85xx-cpm2.c
+endif
+ifeq ($(CONFIG_EMBEDDED6xx),y)
+src-plat += cuboot-pq2.c cuboot-mpc7448hpc2.c cuboot-c2k.c \
+ gamecube-head.S gamecube.c wii-head.S wii.c holly.c \
+ prpmc2800.c
+endif
+ifeq ($(CONFIG_AMIGAONE),y)
+src-plat += cuboot-amigaone.c
+endif
+ifeq ($(CONFIG_PPC_PS3),y)
+src-plat += ps3-head.S ps3-hvcall.S ps3.c
+endif
+ifeq ($(CONFIG_EPAPR_BOOT),y)
+src-plat += epapr.c
+endif
+src-plat := $(sort $(src-plat))
src-boot := $(src-wlib) $(src-plat) empty.c
src-boot := $(addprefix $(obj)/, $(src-boot))
-- 1.7.7.6
^ permalink raw reply related
* [PATCH 3/3 v3] iommu/fsl: Freescale PAMU driver and IOMMU API implementation.
From: Varun Sethi @ 2012-10-17 17:32 UTC (permalink / raw)
To: joerg.roedel, iommu, linuxppc-dev, linux-kernel; +Cc: Varun Sethi
In-Reply-To: <1350495170-4593-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: Varun Sethi <Varun.Sethi@freescale.com>
---
changes in v3:
- Addressed comments by Kumar Gala
- dynamic fspi allocation
- fixed alignment check in map and unmap
operations.
drivers/iommu/Kconfig | 8 +
drivers/iommu/Makefile | 1 +
drivers/iommu/fsl_pamu.c | 1063 +++++++++++++++++++++++++++++++++++++++
drivers/iommu/fsl_pamu.h | 401 +++++++++++++++
drivers/iommu/fsl_pamu_domain.c | 996 ++++++++++++++++++++++++++++++++++++
drivers/iommu/fsl_pamu_domain.h | 96 ++++
6 files changed, 2565 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 14a4d5f..a565ebe 100644
--- a/drivers/iommu/Makefile
+++ b/drivers/iommu/Makefile
@@ -12,3 +12,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..3d9dd43
--- /dev/null
+++ b/drivers/iommu/fsl_pamu.c
@@ -0,0 +1,1063 @@
+/*
+ * 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.
+ *
+ */
+
+#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 "fsl_pamu.h"
+
+/* PAMU bypass enbale register contains control bits for
+ * enabling bypass mode on each PAMU.
+ */
+#define PAMUBYPENR 0x604
+
+/* 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 paace_t *ppaact;
+static paace_t *spaact;
+static struct ome *omt;
+unsigned int max_subwindow_count;
+
+struct gen_pool *spaace_pool;
+
+static paace_t *pamu_get_ppaace(int liodn)
+{
+ if (!ppaact) {
+ pr_err("PPAACT doesn't exist\n");
+ return NULL;
+ }
+
+ return &ppaact[liodn];
+}
+
+/** Sets validation bit of PACCE
+ *
+ * @parm[in] liodn PAACT index for desired PAACE
+ *
+ * @return Returns 0 upon success else error code < 0 returned
+ */
+int pamu_enable_liodn(int liodn)
+{
+ paace_t *ppaace;
+
+ ppaace = pamu_get_ppaace(liodn);
+ if (!ppaace)
+ 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;
+}
+
+/** Clears validation bit of PACCE
+ *
+ * @parm[in] liodn PAACT index for desired PAACE
+ *
+ * @return Returns 0 upon success else error code < 0 returned
+ */
+int pamu_disable_liodn(int liodn)
+{
+ paace_t *ppaace;
+
+ ppaace = pamu_get_ppaace(liodn);
+ if (!ppaace)
+ return -ENOENT;
+
+ set_bf(ppaace->addr_bitfields, PAACE_AF_V, PAACE_V_INVALID);
+ mb();
+
+ return 0;
+}
+
+
+static unsigned int map_addrspace_size_to_wse(phys_addr_t addrspace_size)
+{
+ 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;
+}
+
+static unsigned int map_subwindow_cnt_to_wce(u32 subwindow_cnt)
+{
+ /* window count is 2^(WCE+1) bytes */
+ return __ffs(subwindow_cnt) - 1;
+}
+
+static void pamu_setup_default_xfer_to_host_ppaace(paace_t *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);
+}
+
+static void pamu_setup_default_xfer_to_host_spaace(paace_t *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);
+}
+
+static paace_t *pamu_get_spaace(u32 fspi_index, u32 wnum)
+{
+ return &spaact[fspi_index + wnum];
+}
+
+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(paace_t));
+ if (!spaace_addr)
+ return ULONG_MAX;
+
+ return (spaace_addr - (unsigned long)spaact) / (sizeof(paace_t));
+}
+
+void pamu_free_subwins(int liodn)
+{
+ paace_t *ppaace;
+ u32 subwin_cnt, size;
+
+ ppaace = pamu_get_ppaace(liodn);
+ if (!ppaace)
+ 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(paace_t);
+ 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 coresspong LIODN.
+ */
+int pamu_update_paace_stash(int liodn, u32 subwin, u32 value)
+{
+ paace_t *paace;
+
+ paace = pamu_get_ppaace(liodn);
+ if (!paace) {
+ return -ENOENT;
+ }
+ if (subwin) {
+ paace = pamu_get_spaace(paace->fspi, subwin - 1);
+ if (!paace) {
+ return -ENOENT;
+ }
+ }
+ set_bf(paace->impl_attr, PAACE_IA_CID, value);
+
+ return 0;
+}
+
+/** Sets up PPAACE entry for specified liodn
+ *
+ * @param[in] liodn Logical IO device number
+ * @param[in] win_addr starting address of DSA window
+ * @param[in] win-size size of DSA window
+ * @param[in] omi Operation mapping index -- if ~omi == 0 then omi not defined
+ * @param[in] rpn real (true physical) page number
+ * @param[in] stashid cache stash id for associated cpu -- if ~stashid == 0 then
+ * stashid not defined
+ * @param[in] snoopid snoop id for hardware coherency -- if ~snoopid == 0 then
+ * snoopid not defined
+ * @param[in] subwin_cnt number of sub-windows
+ * @param[in] prot window permissions
+ *
+ * @return 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)
+{
+ paace_t *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;
+}
+
+/** Sets up SPAACE entry for specified subwindow
+ *
+ * @param[in] liodn Logical IO device number
+ * @param[in] subwin_cnt number of sub-windows associated with dma-window
+ * @param[in] subwin_addr starting address of subwindow
+ * @param[in] subwin_size size of subwindow
+ * @param[in] omi Operation mapping index
+ * @param[in] rpn real (true physical) page number
+ * @param[in] snoopid snoop id for hardware coherency -- if ~snoopid == 0 then
+ * snoopid not defined
+ * @param[in] stashid cache stash id for associated cpu
+ * @param[in] enable enable/disable subwindow after reconfiguration
+ * @param[in] prot sub window permissions
+ *
+ * @return 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)
+{
+ paace_t *paace;
+ unsigned long fspi;
+
+ /* setup sub-windows */
+ if (!subwin_cnt) {
+ pr_err("Invalid subwindow count\n");
+ return -EINVAL;
+ }
+
+ paace = pamu_get_ppaace(liodn);
+ if (subwin_addr > 0 && paace) {
+ fspi = paace->fspi;
+ paace = pamu_get_spaace(fspi, 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)
+ 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;
+}
+
+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;
+}
+
+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("bad cpu reference %d\n", vcpu);
+ return ~(u32)0;
+ }
+ }
+
+ pr_err("stash dest not found for %d on vcpu %d\n",
+ stash_dest_hint, vcpu);
+ return ~(u32)0;
+}
+
+#define QMAN_PAACE 1
+#define QMAN_PORTAL_PAACE 2
+#define BMAN_PAACE 3
+
+static void setup_qbman_paace(paace_t *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;
+ }
+}
+
+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;
+}
+
+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, ((u64)ppaact_phys) >> 32);
+ out_be32(&pamu_regs->ppbal, ppaact_phys);
+ ppaact_phys = ppaact_phys + PAACT_SIZE;
+ out_be32(&pamu_regs->pplah, ((u64)ppaact_phys) >> 32);
+ out_be32(&pamu_regs->pplal, ppaact_phys);
+
+ out_be32(&pamu_regs->spbah, ((u64)spaact_phys) >> 32);
+ out_be32(&pamu_regs->spbal, spaact_phys);
+ spaact_phys = spaact_phys + SPAACT_SIZE;
+ out_be32(&pamu_regs->splah, ((u64)spaact_phys) >> 32);
+ out_be32(&pamu_regs->splal, spaact_phys);
+
+ out_be32(&pamu_regs->obah, ((u64)omt_phys) >> 32);
+ out_be32(&pamu_regs->obal, omt_phys);
+ omt_phys = omt_phys + OMT_SIZE;
+ out_be32(&pamu_regs->olah, ((u64)omt_phys) >> 32);
+ out_be32(&pamu_regs->olal, 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;
+}
+
+static void __init setup_liodns(void)
+{
+ int i, len;
+ paace_t *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);
+ }
+ }
+}
+
+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;
+ void __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(paace_t)), -1);
+ if (!spaace_pool) {
+ ret = -ENOMEM;
+ pr_err("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..81eb9af
--- /dev/null
+++ b/drivers/iommu/fsl_pamu.h
@@ -0,0 +1,401 @@
+/*
+ * 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 /* 1 = PAMU Gate Closed : block all
+peripheral access, 0 : may allow peripheral access */
+
+#define PAMU_PC_PE 0x40000000 /* 0 = PAMU disabled, 1 = PAMU enabled */
+#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 */
+typedef struct paace_t {
+ /* 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 */
+} paace_t;
+
+/* 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(paace_t) * PAACE_NUMBER_ENTRIES)
+#define OMT_SIZE (sizeof(struct ome) * OME_NUMBER_ENTRIES)
+#define SPAACT_SIZE (sizeof(paace_t) * 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..16f1b78
--- /dev/null
+++ b/drivers/iommu/fsl_pamu_domain.c
@@ -0,0 +1,996 @@
+/*
+ * 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>
+ *
+ */
+
+#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.
+ */
+DEFINE_SPINLOCK(iommu_lock);
+
+struct kmem_cache *fsl_pamu_domain_cache;
+struct kmem_cache *iommu_devinfo_cache;
+DEFINE_SPINLOCK(device_domain_lock);
+
+static inline void free_devinfo_mem(void *vaddr)
+{
+ kmem_cache_free(iommu_devinfo_cache, vaddr);
+}
+
+static inline int iommu_devinfo_cache_init(void)
+{
+ int ret = 0;
+
+ 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");
+ ret = -ENOMEM;
+ }
+
+ return ret;
+}
+
+static inline int iommu_domain_cache_init(void)
+{
+ int ret = 0;
+
+ 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");
+ ret = -ENOMEM;
+ }
+
+ return ret;
+}
+
+int __init iommu_init_mempool(void)
+{
+ int ret;
+
+ ret = iommu_domain_cache_init();
+ if (ret)
+ return ret;
+
+ ret = iommu_devinfo_cache_init();
+ if (!ret)
+ return ret;
+
+ kmem_cache_destroy(fsl_pamu_domain_cache);
+
+ return 0;
+}
+
+
+static int reconfig_win(int liodn, struct fsl_dma_domain *domain)
+{
+ int ret;
+
+ spin_lock(&iommu_lock);
+ ret = pamu_config_ppaace(liodn, domain->mapped_iova,
+ domain->mapped_size,
+ -1,
+ domain->paddr >> PAMU_PAGE_SHIFT,
+ domain->snoop_id, domain->stash_id,
+ 0, domain->prot);
+ spin_unlock(&iommu_lock);
+ if (ret) {
+ pr_err("PAMU PAACE configuration failed for liodn %d\n",
+ liodn);
+ }
+ return ret;
+}
+
+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;
+
+ 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,
+
+ spin_lock(&iommu_lock);
+ ret = pamu_config_spaace(liodn, subwin_cnt, mapped_subwin,
+ sub_win_ptr[i].size,
+ -1,
+ rpn, dma_domain->snoop_id,
+ dma_domain->stash_id,
+ (mapped_subwin == 0 &&
+ !dma_domain->enabled) ?
+ 0 : sub_win_ptr[i].valid,
+ 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(int liodn, struct fsl_dma_domain *dma_domain)
+{
+ u32 subwin_cnt = dma_domain->subwin_cnt;
+ unsigned long rpn;
+ int ret = 0, i;
+
+ if (subwin_cnt) {
+ 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) {
+ 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,
+ -1,
+ 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;
+ }
+ }
+ }
+ } else {
+
+ rpn = dma_domain->paddr >> PAMU_PAGE_SHIFT;
+ spin_lock(&iommu_lock);
+ ret = pamu_config_ppaace(liodn, dma_domain->mapped_iova,
+ dma_domain->mapped_size,
+ -1,
+ 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;
+ }
+ }
+
+ return ret;
+}
+
+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 = reconfig_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;
+}
+
+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 = -1;
+
+ /* 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)
+{
+ if ((size & (size - 1)) || size < PAMU_PAGE_SIZE) {
+ pr_err("%s: size too small or not a power of two\n", __func__);
+ return -EINVAL;
+ }
+
+ 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)
+{
+ return ((size < subwin_size) ? ((size & (size - 1)) ||
+ size < PAMU_PAGE_SIZE) :
+ (size & (subwin_size -1)));
+}
+
+
+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 = -1;
+ domain->snoop_id = -1;
+
+ INIT_LIST_HEAD(&domain->devices);
+
+ spin_lock_init(&domain->domain_lock);
+
+ return domain;
+}
+
+static inline struct fsl_dma_domain *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;
+ free_devinfo_mem(info);
+ spin_unlock(&device_domain_lock);
+}
+
+static void destroy_domain(struct fsl_dma_domain *dma_domain)
+{
+ struct device_domain_info *info;
+
+ 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);
+ 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;
+ struct fsl_dma_domain *old_domain;
+
+ 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 = find_domain(dev);
+ if (old_domain && old_domain != dma_domain) {
+ spin_unlock(&device_domain_lock);
+ detach_domain(dev, old_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 && old_domain != dma_domain)
+ 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)
+{
+ if (cap == IOMMU_CAP_CACHE_COHERENCY)
+ return 1;
+
+ return 0;
+}
+
+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 = 0x100000;
+ domain->geometry.subwindows = 0;
+ domain->geometry.force_aperture = true;
+
+ return 0;
+}
+
+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;
+}
+
+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;
+}
+
+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) {
+ 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);
+ 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);
+ 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) {
+ 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;
+}
+
+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++) {
+ attach_domain(dma_domain, liodn[i], dev);
+ 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) {
+ 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 != 1024 * 1024)
+ return 0;
+ *subwin_cnt = 256;
+ 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 = 0;
+ 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;
+
+ 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;
+ }
+ }
+ memcpy(&domain->geometry, geom_attr,
+ sizeof(struct iommu_domain_geometry));
+ 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;
+}
+
+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;
+}
+
+static int configure_domain_dma_state(struct fsl_dma_domain *dma_domain, int 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 2/3 v3] iommu/fsl: Add iommu domain attributes required by fsl PAMU driver.
From: Varun Sethi @ 2012-10-17 17:32 UTC (permalink / raw)
To: joerg.roedel, iommu, linuxppc-dev, linux-kernel; +Cc: Varun Sethi
In-Reply-To: <1350495170-4593-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.
Signed-off-by: Varun Sethi <Varun.Sethi@freescale.com>
---
change in v3:
-renamed the stash attribute targets
include/linux/iommu.h | 35 +++++++++++++++++++++++++++++++++++
1 files changed, 35 insertions(+), 0 deletions(-)
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index f3b99e1..c3b9d73 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -44,6 +44,33 @@ 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? */
+
+ /* The subwindows field indicates number of DMA subwindows supported
+ * by the geometry. Following is the interpretation of
+ * values for this field:
+ * 0 : This implies that the supported geometry size is 1 MB
+ * with each subwindow size being 4KB. Thus number of subwindows
+ * being = 1MB/4KB = 256.
+ * 1 : Only one DMA window i.e. no subwindows.
+ * value other than 0 or 1 would indicate actual number of subwindows.
+ */
+ u32 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 +87,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/3] iommu/fsl: Freescale PAMU driver and IOMMU API implementation.
From: Varun Sethi @ 2012-10-17 17:32 UTC (permalink / raw)
To: joerg.roedel, iommu, linuxppc-dev, linux-kernel; +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. Addition of domain attributes required by the PAMU driver IOMMU API.
3. 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 (3):
Store iommu domain information pointer in archdata.
Add iommu domain attributes required by fsl PAMU driver.
FSL PAMU driver and IOMMU API implementation.
arch/powerpc/include/asm/device.h | 4 +
drivers/iommu/Kconfig | 7 +
drivers/iommu/Makefile | 1 +
drivers/iommu/fsl_pamu.c | 1033 +++++++++++++++++++++++++++++++++++++
drivers/iommu/fsl_pamu.h | 377 ++++++++++++++
drivers/iommu/fsl_pamu_domain.c | 990 +++++++++++++++++++++++++++++++++++
drivers/iommu/fsl_pamu_domain.h | 94 ++++
drivers/iommu/fsl_pamu_proto.h | 49 ++
include/linux/iommu.h | 30 ++
9 files changed, 2585 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
create mode 100644 drivers/iommu/fsl_pamu_proto.h
--
1.7.4.1
^ permalink raw reply
* [PATCH 1/3 v2] iommu/fsl: Store iommu domain information pointer in archdata.
From: Varun Sethi @ 2012-10-17 17:32 UTC (permalink / raw)
To: joerg.roedel, iommu, linuxppc-dev, linux-kernel; +Cc: Varun Sethi
In-Reply-To: <1350495170-4593-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>
---
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
* Re: [PATCH 2/2] PPC_BOOK3E/KGDB: support kgdb kernel space
From: Andreas Schwab @ 2012-10-17 12:07 UTC (permalink / raw)
To: Tiejun Chen; +Cc: linuxppc-dev, jason.wessel
In-Reply-To: <1350471011-2478-2-git-send-email-tiejun.chen__24766.2045098425$1350471081$gmane$org@windriver.com>
Tiejun Chen <tiejun.chen@windriver.com> writes:
> diff --git a/arch/powerpc/kernel/exceptions-64e.S b/arch/powerpc/kernel/exceptions-64e.S
> index 4684e33..ed5862d 100644
> --- a/arch/powerpc/kernel/exceptions-64e.S
> +++ b/arch/powerpc/kernel/exceptions-64e.S
> @@ -539,11 +539,15 @@ kernel_dbg_exc:
> rfdi
>
> /* Normal debug exception */
> +#ifndef CONFIG_KGDB
> /* XXX We only handle coming from userspace for now since we can't
> * quite save properly an interrupted kernel state yet
> */
> 1: andi. r14,r11,MSR_PR; /* check for userspace again */
> beq kernel_dbg_exc; /* if from kernel mode */
> +#else
> +1:
> +#endif
You could move the label before the conditional.
Andreas.
--
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756 01D3 44D5 214B 8276 4ED5
"And now for something completely different."
^ permalink raw reply
* [PATCH 1/2] powerpc/kgdb: Fix a single stgep case of lazy IRQ
From: Tiejun Chen @ 2012-10-17 10:50 UTC (permalink / raw)
To: benh; +Cc: linuxppc-dev, jason.wessel
When we're in kgdb_singlestep(), we have to work around to get
thread_info by copying from the kernel stack before calling
kgdb_handle_exception(), then copying it back afterwards.
But for PPC64, we have a lazy interrupt implementation. So after
copying thread info frome kernle stack, if we need to replay an
interrupt, we shouldn't restore that previous backup thread info
to make sure we can replay an interrupt lately with a proper
thread info.
This patch use __check_irq_replay() to guarantee this process.
Signed-off-by: Tiejun Chen <tiejun.chen@windriver.com>
---
arch/powerpc/kernel/irq.c | 12 +++++++++++-
arch/powerpc/kernel/kgdb.c | 7 ++++---
2 files changed, 15 insertions(+), 4 deletions(-)
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index 71413f4..a773789 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -332,7 +332,17 @@ bool prep_irq_for_idle(void)
return true;
}
-#endif /* CONFIG_PPC64 */
+notrace unsigned int check_irq_replay(void)
+{
+ return __check_irq_replay();
+}
+#else /* CONFIG_PPC64 */
+notrace unsigned int check_irq_replay(void)
+{
+ return 0;
+}
+#endif /* !CONFIG_PPC64 */
+EXPORT_SYMBOL(check_irq_replay);
int arch_show_interrupts(struct seq_file *p, int prec)
{
diff --git a/arch/powerpc/kernel/kgdb.c b/arch/powerpc/kernel/kgdb.c
index c470a40..c4af341 100644
--- a/arch/powerpc/kernel/kgdb.c
+++ b/arch/powerpc/kernel/kgdb.c
@@ -151,6 +151,7 @@ static int kgdb_handle_breakpoint(struct pt_regs *regs)
return 1;
}
+extern notrace unsigned int check_irq_replay(void);
static int kgdb_singlestep(struct pt_regs *regs)
{
struct thread_info *thread_info, *exception_thread_info;
@@ -181,9 +182,9 @@ static int kgdb_singlestep(struct pt_regs *regs)
kgdb_handle_exception(0, SIGTRAP, 0, regs);
- if (thread_info != exception_thread_info)
- /* Restore current_thread_info lastly. */
- memcpy(exception_thread_info, backup_current_thread_info, sizeof *thread_info);
+ if ((thread_info != exception_thread_info) && (!check_irq_replay()))
+ /* Restore current_thread_info lastly only if we don't replay interrupt. */
+ memcpy(exception_thread_info, backup_current_thread_info, sizeof *thread_info);
return 1;
}
--
1.7.9.5
^ permalink raw reply related
* [PATCH 2/2] PPC_BOOK3E/KGDB: support kgdb kernel space
From: Tiejun Chen @ 2012-10-17 10:50 UTC (permalink / raw)
To: benh; +Cc: linuxppc-dev, jason.wessel
In-Reply-To: <1350471011-2478-1-git-send-email-tiejun.chen@windriver.com>
We can support KGDB with current debug exception for BOOK3E, so we
should initial specific dbg_kstack to avoid overwriting other thing.
Signed-off-by: Tiejun Chen <tiejun.chen@windriver.com>
---
arch/powerpc/kernel/exceptions-64e.S | 4 ++++
arch/powerpc/kernel/paca.c | 10 ++++++++++
2 files changed, 14 insertions(+)
diff --git a/arch/powerpc/kernel/exceptions-64e.S b/arch/powerpc/kernel/exceptions-64e.S
index 4684e33..ed5862d 100644
--- a/arch/powerpc/kernel/exceptions-64e.S
+++ b/arch/powerpc/kernel/exceptions-64e.S
@@ -539,11 +539,15 @@ kernel_dbg_exc:
rfdi
/* Normal debug exception */
+#ifndef CONFIG_KGDB
/* XXX We only handle coming from userspace for now since we can't
* quite save properly an interrupted kernel state yet
*/
1: andi. r14,r11,MSR_PR; /* check for userspace again */
beq kernel_dbg_exc; /* if from kernel mode */
+#else
+1:
+#endif
/* Now we mash up things to make it look like we are coming on a
* normal exception
diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c
index cd6da85..28a5141 100644
--- a/arch/powerpc/kernel/paca.c
+++ b/arch/powerpc/kernel/paca.c
@@ -122,6 +122,13 @@ EXPORT_SYMBOL(paca);
struct paca_struct boot_paca;
+void *debug_kstack;
+static void allocate_dbg_kstack(unsigned long limit)
+{
+ debug_kstack = __va(memblock_alloc_base(THREAD_SIZE,
+ THREAD_SIZE, limit));
+}
+
void __init initialise_paca(struct paca_struct *new_paca, int cpu)
{
/* The TOC register (GPR2) points 32kB into the TOC, so that 64kB
@@ -133,6 +140,7 @@ void __init initialise_paca(struct paca_struct *new_paca, int cpu)
new_paca->lppaca_ptr = new_lppaca(cpu);
#else
new_paca->kernel_pgd = swapper_pg_dir;
+ new_paca->dbg_kstack = debug_kstack;
#endif
new_paca->lock_token = 0x8000;
new_paca->paca_index = cpu;
@@ -192,6 +200,8 @@ void __init allocate_pacas(void)
allocate_lppacas(nr_cpu_ids, limit);
+ allocate_dbg_kstack(limit);
+
/* Can't use for_each_*_cpu, as they aren't functional yet */
for (cpu = 0; cpu < nr_cpu_ids; cpu++)
initialise_paca(&paca[cpu], cpu);
--
1.7.9.5
^ permalink raw reply related
* [PATCH -V2] powerpc: Build fix for powerpc KVM
From: Aneesh Kumar K.V @ 2012-10-17 8:25 UTC (permalink / raw)
To: benh, paulus, schwab, mikey; +Cc: linuxppc-dev, Aneesh Kumar K.V
From: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com>
Fix build failure for powerpc KVM by adding missing VPN_SHIFT definition
and the ';'
arch/powerpc/kvm/book3s_32_mmu_host.c: In function 'kvmppc_mmu_map_page':
arch/powerpc/kvm/book3s_32_mmu_host.c:176: error: 'VPN_SHIFT' undeclared (first use in this function)
arch/powerpc/kvm/book3s_32_mmu_host.c:176: error: (Each undeclared identifier is reported only once
arch/powerpc/kvm/book3s_32_mmu_host.c:176: error: for each function it appears in.)
arch/powerpc/kvm/book3s_32_mmu_host.c:178: error: expected ';' before 'next_pteg'
arch/powerpc/kvm/book3s_32_mmu_host.c:190: error: label 'next_pteg' used but not defined
make[1]: *** [arch/powerpc/kvm/book3s_32_mmu_host.o] Error 1
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/kvm_book3s_32.h | 1 +
arch/powerpc/kvm/book3s_32_mmu_host.c | 4 ++--
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/arch/powerpc/include/asm/kvm_book3s_32.h b/arch/powerpc/include/asm/kvm_book3s_32.h
index 38040ff..ce0ef6c 100644
--- a/arch/powerpc/include/asm/kvm_book3s_32.h
+++ b/arch/powerpc/include/asm/kvm_book3s_32.h
@@ -42,5 +42,6 @@ static inline void svcpu_put(struct kvmppc_book3s_shadow_vcpu *svcpu)
#define SID_SHIFT 28
#define ESID_MASK 0xf0000000
#define VSID_MASK 0x00fffffff0000000ULL
+#define VPN_SHIFT 12
#endif /* __ASM_KVM_BOOK3S_32_H__ */
diff --git a/arch/powerpc/kvm/book3s_32_mmu_host.c b/arch/powerpc/kvm/book3s_32_mmu_host.c
index 00aa612..b0f625a 100644
--- a/arch/powerpc/kvm/book3s_32_mmu_host.c
+++ b/arch/powerpc/kvm/book3s_32_mmu_host.c
@@ -173,8 +173,8 @@ int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte)
BUG_ON(!map);
vsid = map->host_vsid;
- vpn = (vsid << (SID_SHIFT - VPN_SHIFT)) | ((eaddr & ~ESID_MASK) >> VPN_SHIFT)
-
+ vpn = (vsid << (SID_SHIFT - VPN_SHIFT)) |
+ ((eaddr & ~ESID_MASK) >> VPN_SHIFT);
next_pteg:
if (rr == 16) {
primary = !primary;
--
1.7.10
^ permalink raw reply related
* Re: [PATCH] kvm/powerpc: Handle errors in secondary thread grabbing
From: Alexander Graf @ 2012-10-17 6:25 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: linuxppc-dev, Paul Mackerras, kvm-ppc
In-Reply-To: <1350416012.4678.54.camel@pasglop>
On 16.10.2012, at 21:33, Benjamin Herrenschmidt wrote:
> On Tue, 2012-10-16 at 17:00 +1100, Michael Ellerman wrote:
>>> Thanks for looking at this - but in fact this is fixed by my patch
>>> entitled "KVM: PPC: Book3S HV: Fix some races in starting secondary
>>> threads" submitted back on August 28.
>>=20
>> OK thanks. It seems that patch didn't make 3.7 ?
>>=20
>> I don't see it in kvm-ppc-next either.
>=20
> Alex, WTF ?
Hrm. Not sure what happened there. I think I waited for your ack, but =
never actually applied things when it came. My bad :)
Alex
^ permalink raw reply
* Re: [PATCH] powerpc: Build fix for powerpc KVM
From: Michael Neuling @ 2012-10-17 5:22 UTC (permalink / raw)
To: Aneesh Kumar K.V; +Cc: schwab, paulus, linuxppc-dev
In-Reply-To: <87fw5dhe70.fsf@linux.vnet.ibm.com>
Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> wrote:
> Michael Neuling <mikey@neuling.org> writes:
>
> > Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> wrote:
> >
> >> From: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com>
> >>
> >> Fix build failure for powerpc KVM
> >
> > What was the failure?
>
>
> arch/powerpc/kvm/book3s_32_mmu_host.c: In function 'kvmppc_mmu_map_page':
> arch/powerpc/kvm/book3s_32_mmu_host.c:176: error: 'VPN_SHIFT' undeclared (first use in this function)
> arch/powerpc/kvm/book3s_32_mmu_host.c:176: error: (Each undeclared identifier is reported only once
> arch/powerpc/kvm/book3s_32_mmu_host.c:176: error: for each function it appears in.)
> arch/powerpc/kvm/book3s_32_mmu_host.c:178: error: expected ';' before 'next_pteg'
> arch/powerpc/kvm/book3s_32_mmu_host.c:190: error: label 'next_pteg' used but not defined
> make[1]: *** [arch/powerpc/kvm/book3s_32_mmu_host.o] Error 1
OK, can you repost with this and what changed too (added VPN_SHIFT and
missing ';') in the comment.
Mikey
>
>
> >
> >>
> >> Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
> >> ---
> >> arch/powerpc/include/asm/kvm_book3s_32.h | 1 +
> >> arch/powerpc/kvm/book3s_32_mmu_host.c | 4 ++--
> >> 2 files changed, 3 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/arch/powerpc/include/asm/kvm_book3s_32.h b/arch/powerpc/include/asm/kvm_book3s_32.h
> >> index 38040ff..ce0ef6c 100644
> >> --- a/arch/powerpc/include/asm/kvm_book3s_32.h
> >> +++ b/arch/powerpc/include/asm/kvm_book3s_32.h
> >> @@ -42,5 +42,6 @@ static inline void svcpu_put(struct kvmppc_book3s_shadow_vcpu *svcpu)
> >> #define SID_SHIFT 28
> >> #define ESID_MASK 0xf0000000
> >> #define VSID_MASK 0x00fffffff0000000ULL
> >> +#define VPN_SHIFT 12
> >
> > Is this the fix?
> >
> >>
> >> #endif /* __ASM_KVM_BOOK3S_32_H__ */
> >> diff --git a/arch/powerpc/kvm/book3s_32_mmu_host.c b/arch/powerpc/kvm/book3s_32_mmu_host.c
> >> index 00aa612..b0f625a 100644
> >> --- a/arch/powerpc/kvm/book3s_32_mmu_host.c
> >> +++ b/arch/powerpc/kvm/book3s_32_mmu_host.c
> >> @@ -173,8 +173,8 @@ int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte)
> >> BUG_ON(!map);
> >>
> >> vsid = map->host_vsid;
> >> - vpn = (vsid << (SID_SHIFT - VPN_SHIFT)) | ((eaddr & ~ESID_MASK) >> VPN_SHIFT)
> >> -
> >> + vpn = (vsid << (SID_SHIFT - VPN_SHIFT)) |
> >> + ((eaddr & ~ESID_MASK) >> VPN_SHIFT);
> >
> > This just seems to be a white space change.
>
> There is a missing ';'
>
>
> -aneesh
>
^ permalink raw reply
* Re: [PATCH] powerpc: Build fix for powerpc KVM
From: Aneesh Kumar K.V @ 2012-10-17 5:15 UTC (permalink / raw)
To: Michael Neuling; +Cc: schwab, paulus, linuxppc-dev
In-Reply-To: <26771.1350425721@neuling.org>
Michael Neuling <mikey@neuling.org> writes:
> Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> wrote:
>
>> From: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com>
>>
>> Fix build failure for powerpc KVM
>
> What was the failure?
arch/powerpc/kvm/book3s_32_mmu_host.c: In function 'kvmppc_mmu_map_page':
arch/powerpc/kvm/book3s_32_mmu_host.c:176: error: 'VPN_SHIFT' undeclared (first use in this function)
arch/powerpc/kvm/book3s_32_mmu_host.c:176: error: (Each undeclared identifier is reported only once
arch/powerpc/kvm/book3s_32_mmu_host.c:176: error: for each function it appears in.)
arch/powerpc/kvm/book3s_32_mmu_host.c:178: error: expected ';' before 'next_pteg'
arch/powerpc/kvm/book3s_32_mmu_host.c:190: error: label 'next_pteg' used but not defined
make[1]: *** [arch/powerpc/kvm/book3s_32_mmu_host.o] Error 1
>
>>
>> Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
>> ---
>> arch/powerpc/include/asm/kvm_book3s_32.h | 1 +
>> arch/powerpc/kvm/book3s_32_mmu_host.c | 4 ++--
>> 2 files changed, 3 insertions(+), 2 deletions(-)
>>
>> diff --git a/arch/powerpc/include/asm/kvm_book3s_32.h b/arch/powerpc/include/asm/kvm_book3s_32.h
>> index 38040ff..ce0ef6c 100644
>> --- a/arch/powerpc/include/asm/kvm_book3s_32.h
>> +++ b/arch/powerpc/include/asm/kvm_book3s_32.h
>> @@ -42,5 +42,6 @@ static inline void svcpu_put(struct kvmppc_book3s_shadow_vcpu *svcpu)
>> #define SID_SHIFT 28
>> #define ESID_MASK 0xf0000000
>> #define VSID_MASK 0x00fffffff0000000ULL
>> +#define VPN_SHIFT 12
>
> Is this the fix?
>
>>
>> #endif /* __ASM_KVM_BOOK3S_32_H__ */
>> diff --git a/arch/powerpc/kvm/book3s_32_mmu_host.c b/arch/powerpc/kvm/book3s_32_mmu_host.c
>> index 00aa612..b0f625a 100644
>> --- a/arch/powerpc/kvm/book3s_32_mmu_host.c
>> +++ b/arch/powerpc/kvm/book3s_32_mmu_host.c
>> @@ -173,8 +173,8 @@ int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte)
>> BUG_ON(!map);
>>
>> vsid = map->host_vsid;
>> - vpn = (vsid << (SID_SHIFT - VPN_SHIFT)) | ((eaddr & ~ESID_MASK) >> VPN_SHIFT)
>> -
>> + vpn = (vsid << (SID_SHIFT - VPN_SHIFT)) |
>> + ((eaddr & ~ESID_MASK) >> VPN_SHIFT);
>
> This just seems to be a white space change.
There is a missing ';'
-aneesh
^ permalink raw reply
* Re: [PATCH] powerpc: Build fix for powerpc KVM
From: Michael Neuling @ 2012-10-16 22:15 UTC (permalink / raw)
To: Aneesh Kumar K.V; +Cc: schwab, paulus, linuxppc-dev
In-Reply-To: <1350389744-24627-1-git-send-email-aneesh.kumar@linux.vnet.ibm.com>
Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> wrote:
> From: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com>
>
> Fix build failure for powerpc KVM
What was the failure?
>
> Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
> ---
> arch/powerpc/include/asm/kvm_book3s_32.h | 1 +
> arch/powerpc/kvm/book3s_32_mmu_host.c | 4 ++--
> 2 files changed, 3 insertions(+), 2 deletions(-)
>
> diff --git a/arch/powerpc/include/asm/kvm_book3s_32.h b/arch/powerpc/include/asm/kvm_book3s_32.h
> index 38040ff..ce0ef6c 100644
> --- a/arch/powerpc/include/asm/kvm_book3s_32.h
> +++ b/arch/powerpc/include/asm/kvm_book3s_32.h
> @@ -42,5 +42,6 @@ static inline void svcpu_put(struct kvmppc_book3s_shadow_vcpu *svcpu)
> #define SID_SHIFT 28
> #define ESID_MASK 0xf0000000
> #define VSID_MASK 0x00fffffff0000000ULL
> +#define VPN_SHIFT 12
Is this the fix?
>
> #endif /* __ASM_KVM_BOOK3S_32_H__ */
> diff --git a/arch/powerpc/kvm/book3s_32_mmu_host.c b/arch/powerpc/kvm/book3s_32_mmu_host.c
> index 00aa612..b0f625a 100644
> --- a/arch/powerpc/kvm/book3s_32_mmu_host.c
> +++ b/arch/powerpc/kvm/book3s_32_mmu_host.c
> @@ -173,8 +173,8 @@ int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte)
> BUG_ON(!map);
>
> vsid = map->host_vsid;
> - vpn = (vsid << (SID_SHIFT - VPN_SHIFT)) | ((eaddr & ~ESID_MASK) >> VPN_SHIFT)
> -
> + vpn = (vsid << (SID_SHIFT - VPN_SHIFT)) |
> + ((eaddr & ~ESID_MASK) >> VPN_SHIFT);
This just seems to be a white space change.
Mikey
> next_pteg:
> if (rr == 16) {
> primary = !primary;
> --
> 1.7.10
>
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev
>
^ permalink raw reply
* Re: [PATCH] kvm/powerpc: Handle errors in secondary thread grabbing
From: Benjamin Herrenschmidt @ 2012-10-16 19:33 UTC (permalink / raw)
To: Alexander Graf; +Cc: linuxppc-dev, Paul Mackerras, agraf, kvm-ppc
In-Reply-To: <1350367235.32704.1.camel@concordia>
On Tue, 2012-10-16 at 17:00 +1100, Michael Ellerman wrote:
> > Thanks for looking at this - but in fact this is fixed by my patch
> > entitled "KVM: PPC: Book3S HV: Fix some races in starting secondary
> > threads" submitted back on August 28.
>
> OK thanks. It seems that patch didn't make 3.7 ?
>
> I don't see it in kvm-ppc-next either.
Alex, WTF ?
Ben.
^ permalink raw reply
* Re: [RFC][PATCH] perf: Add a few generic stalled-cycles events
From: Sukadev Bhattiprolu @ 2012-10-16 18:31 UTC (permalink / raw)
To: Robert Richter
Cc: peterz, Anton Blanchard, linux-kernel, eranian, acme,
linuxppc-dev, paulus, mpjohn, mingo, asharma
In-Reply-To: <20121016100809.GS8285@erda.amd.com>
Robert Richter [robert.richter@amd.com] wrote:
| Sukadev,
|
| On 15.10.12 17:55:34, Robert Richter wrote:
| > On 11.10.12 18:28:39, Sukadev Bhattiprolu wrote:
| > > + { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_FIXED_POINT },
| > > + { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_LOAD_STORE },
| > > + { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_INSTRUCTION_FETCH },
| > > + { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_BRANCH },
| >
| > Instead of adding new hardware event types I would prefer to use raw
| > events in conjunction with sysfs, see e.g. the intel-uncore
| > implementation. Something like:
| >
| > $ find /sys/bus/event_source/devices/cpu/events/
| > ...
| > /sys/bus/event_source/devices/cpu/events/stalled-cycles-fixed-point
| > /sys/bus/event_source/devices/cpu/events/stalled-cycles-load-store
| > /sys/bus/event_source/devices/cpu/events/stalled-cycles-instruction-fetch
| > /sys/bus/event_source/devices/cpu/events/stalled-cycles-branch
| > ...
| > $ cat /sys/bus/event_source/devices/cpu/events/stalled-cycles-fixed-point
| > event=0xff,umask=0x00
| >
| > Perf tool works then out-of-the-box with:
| >
| > $ perf record -e cpu/stalled-cycles-fixed-point/ ...
|
| I refer here to arch/x86/kernel/cpu/perf_event_intel_uncore.c (should
| be in v3.7-rc1 or tip:perf/core). See the INTEL_UNCORE_EVENT_DESC()
| macro and 'if (type->event_descs) ...' in uncore_type_init(). The code
| should be reworked to be non-architectural.
Ok. I will look through that code. Does that mean we are trying to avoid
any more new hardware generic events ?
Also a broader question - is the sysfs approach intended for all raw events
or just for the generic events supported in the kernel ?
If it is intended for all events a CPU supports, isn't there a chance of
bloating kernel code ? Power7 has 530 events and Intel Nehalem (in libpfm)
seems to have 370 events. Would that mean we would need to represent all these
events in the kernel so they are available in sysfs ?
On a side note, how does the kernel on x86 use the 'config' information in
say /sys/bus/event_source/devices/cpu/format/cccr ? On Power7, the raw
code encodes the information such as the PMC to use for the event. Is that
how the 'config' info in Intel is used ?
Does the 'config' info change from system to system or is it static for
a given event on a given CPU ?
I guess I am trying to understand if this mapping between event-name (event
code) and the config info is something the kernel needs/uses or is it something
the kernel simply passes through from userspace to CPU ?
AFAICT, on the Power we use the raw codes to determine which PMC to select
and which bits to set in some registers. That selection is static for a given
CPU type such as Power7. If it is static, is it worth adding all this static
mapping (for 530 events) into the kernel ?
If we don't add to the kernel, we don't seem to have a way to specify the
events symbolically.
Thanks for you detailed comments.
|
| PMU registration is implemented for a longer time already for all
| architectures and pmu types:
|
| /sys/bus/event_source/devices/*
Yes I see this.
|
| But
|
| /sys/bus/event_source/devices/*/events/
Thanks for clarifying. I was looking to see if this was implemented too :-)
Sukadev
|
| exists only for a small number of pmus. Perf tool support of this was
| implemented with:
|
| a6146d5 perf/tool: Add PMU event alias support
|
| -Robert
|
| --
| Advanced Micro Devices, Inc.
| Operating System Research Center
^ permalink raw reply
* Re: [PATCH 1/9] powerpc: 83xx: use module_i2c_driver macro
From: Kim Phillips @ 2012-10-16 18:06 UTC (permalink / raw)
To: Devendra Naga; +Cc: linuxppc-dev, Paul Mackerras
In-Reply-To: <1350155142-1629-1-git-send-email-devendra.aaru@gmail.com>
On Sat, 13 Oct 2012 15:05:42 -0400
Devendra Naga <devendra.aaru@gmail.com> wrote:
> replace the module init and exit calls containing the
> i2c_add_driver and i2c_del_driver with the module_i2c_driver
> macro as it does the same things as the code that is removed
>
> Signed-off-by: Devendra Naga <devendra.aaru@gmail.com>
> ---
>
> Not compile tested,
Tested-by: Kim Phillips <kim.phillips@freescale.com>
> because i dont have a ppc cross toolchain
fyi, ppc and more cross compilers are available here:
http://kernel.org/pub/tools/crosstool/
Kim
^ permalink raw reply
* Re: [RFC][PATCH] perf: Add a few generic stalled-cycles events
From: Stephane Eranian @ 2012-10-16 12:21 UTC (permalink / raw)
To: Robert Richter
Cc: Peter Zijlstra, Anton Blanchard, LKML, Arnaldo Carvalho de Melo,
linuxppc-dev, Paul Mackerras, mpjohn, Sukadev Bhattiprolu,
Ingo Molnar, Arun Sharma
In-Reply-To: <20121016100809.GS8285@erda.amd.com>
On Tue, Oct 16, 2012 at 12:08 PM, Robert Richter <robert.richter@amd.com> wrote:
> Sukadev,
>
> On 15.10.12 17:55:34, Robert Richter wrote:
>> On 11.10.12 18:28:39, Sukadev Bhattiprolu wrote:
>> > + { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_FIXED_POINT },
>> > + { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_LOAD_STORE },
>> > + { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_INSTRUCTION_FETCH },
>> > + { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_BRANCH },
>>
>> Instead of adding new hardware event types I would prefer to use raw
>> events in conjunction with sysfs, see e.g. the intel-uncore
>> implementation. Something like:
>>
In general, I don't like generic events and especially stall events. I
have not seen a clear definition of
what they mean. Without it, there is no way to understand how to map
them across architecture. If
the definition is too precise, you may not be able to find an exact
mapping. If the definition is to loose
then it is unclear what you are measuring.
Also this opens another can of worms which is that on some processors,
you may need more than
one event to encapsulate what the generic event is supposed to
measure. That means developing
a lot of code in the kernel to express and manage that. And of course,
you would not be able
to sample on those events (you cannot sample on a difference, for
instance). So all in all, I think
this is not a very good idea. You have to put this into the tool or a
library that auto-detects the
host CPU and programs the right set of events.
We've had that discussion many times. Just reiterating my personal
opinion on this.
>> $ find /sys/bus/event_source/devices/cpu/events/
>> ...
>> /sys/bus/event_source/devices/cpu/events/stalled-cycles-fixed-point
>> /sys/bus/event_source/devices/cpu/events/stalled-cycles-load-store
>> /sys/bus/event_source/devices/cpu/events/stalled-cycles-instruction-fetch
>> /sys/bus/event_source/devices/cpu/events/stalled-cycles-branch
>> ...
>> $ cat /sys/bus/event_source/devices/cpu/events/stalled-cycles-fixed-point
>> event=0xff,umask=0x00
>>
>> Perf tool works then out-of-the-box with:
>>
>> $ perf record -e cpu/stalled-cycles-fixed-point/ ...
>
> I refer here to arch/x86/kernel/cpu/perf_event_intel_uncore.c (should
> be in v3.7-rc1 or tip:perf/core). See the INTEL_UNCORE_EVENT_DESC()
> macro and 'if (type->event_descs) ...' in uncore_type_init(). The code
> should be reworked to be non-architectural.
>
> PMU registration is implemented for a longer time already for all
> architectures and pmu types:
>
> /sys/bus/event_source/devices/*
>
> But
>
> /sys/bus/event_source/devices/*/events/
>
> exists only for a small number of pmus. Perf tool support of this was
> implemented with:
>
> a6146d5 perf/tool: Add PMU event alias support
>
> -Robert
>
> --
> Advanced Micro Devices, Inc.
> Operating System Research Center
>
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox