LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [RFC PATCH v2 3/4] powerpc: Don't bolt the hpte in kernel_map_linear_page()
From: Li Zhong @ 2013-04-16  2:51 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev, Paul Mackerras
In-Reply-To: <1366025246.24994.35.camel@pasglop>

On Mon, 2013-04-15 at 13:27 +0200, Benjamin Herrenschmidt wrote:
> On Mon, 2013-04-15 at 16:15 +0800, Li Zhong wrote:
> 
> > So the code is implemented in ppc_md.hpte_remove(), may be called by
> > __hash_huge_page(), and asm code htab_call_hpte_remove?
> > 
> > > This is why the linear mapping (and the vmemmap) must be bolted.
> > 
> > If not, it would result the infinite recursion like above?
> 
> Potentially, we don't expect to fault linear mapping or vmemmap entries
> on demand. We aren't equipped to do it and we occasionally have code
> path that access the linear mapping and cannot afford to have SRR0 and
> SRR1 clobbered by a page fault.

Thank you for the education :)

Thanks, Zhong

> 
> Cheers,
> Ben.
> 
> 

^ permalink raw reply

* [RFC PATCH v3 1/3] powerpc: Move the setting of rflags out of loop in __hash_page_huge
From: Li Zhong @ 2013-04-16  2:53 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: paulus, Li Zhong

It seems that new_pte and rflags don't get changed in the repeating loop, so
move their assignment out of the loop.

Signed-off-by: Li Zhong <zhong@linux.vnet.ibm.com>
---
 arch/powerpc/mm/hugetlbpage-hash64.c |    8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/arch/powerpc/mm/hugetlbpage-hash64.c b/arch/powerpc/mm/hugetlbpage-hash64.c
index cecad34..edb4129 100644
--- a/arch/powerpc/mm/hugetlbpage-hash64.c
+++ b/arch/powerpc/mm/hugetlbpage-hash64.c
@@ -87,10 +87,6 @@ int __hash_page_huge(unsigned long ea, unsigned long access, unsigned long vsid,
 
 		pa = pte_pfn(__pte(old_pte)) << PAGE_SHIFT;
 
-repeat:
-		hpte_group = ((hash & htab_hash_mask) *
-			      HPTES_PER_GROUP) & ~0x7UL;
-
 		/* clear HPTE slot informations in new PTE */
 #ifdef CONFIG_PPC_64K_PAGES
 		new_pte = (new_pte & ~_PAGE_HPTEFLAGS) | _PAGE_HPTE_SUB0;
@@ -101,6 +97,10 @@ repeat:
 		rflags |= (new_pte & (_PAGE_WRITETHRU | _PAGE_NO_CACHE |
 				      _PAGE_COHERENT | _PAGE_GUARDED));
 
+repeat:
+		hpte_group = ((hash & htab_hash_mask) *
+			      HPTES_PER_GROUP) & ~0x7UL;
+
 		/* Insert into the hash table, primary slot */
 		slot = ppc_md.hpte_insert(hpte_group, vpn, pa, rflags, 0,
 					  mmu_psize, ssize);
-- 
1.7.9.5

^ permalink raw reply related

* [RFC PATCH v3 2/3] powerpc: Split the code trying to insert hpte repeatedly as an helper function
From: Li Zhong @ 2013-04-16  2:53 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: paulus, Li Zhong
In-Reply-To: <1366080800-27885-1-git-send-email-zhong@linux.vnet.ibm.com>

Move the logic trying to insert hpte in __hash_page_huge() to an helper
function, so it could also be used by others.

Signed-off-by: Li Zhong <zhong@linux.vnet.ibm.com>
---
 arch/powerpc/mm/hash_utils_64.c      |   35 ++++++++++++++++++++++++++++++++++
 arch/powerpc/mm/hugetlbpage-hash64.c |   31 ++++++------------------------
 2 files changed, 41 insertions(+), 25 deletions(-)

diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
index f410c3e..ead9fa8 100644
--- a/arch/powerpc/mm/hash_utils_64.c
+++ b/arch/powerpc/mm/hash_utils_64.c
@@ -1230,6 +1230,41 @@ void low_hash_fault(struct pt_regs *regs, unsigned long address, int rc)
 		bad_page_fault(regs, address, SIGBUS);
 }
 
+long hpte_insert_repeating(unsigned long hash, unsigned long vpn,
+			   unsigned long pa, unsigned long rflags,
+			   unsigned long vflags, int psize, int ssize)
+{
+	unsigned long hpte_group;
+	long slot;
+
+repeat:
+	hpte_group = ((hash & htab_hash_mask) *
+		       HPTES_PER_GROUP) & ~0x7UL;
+
+	/* Insert into the hash table, primary slot */
+	slot = ppc_md.hpte_insert(hpte_group, vpn, pa, rflags, vflags,
+				  psize, ssize);
+
+	/* Primary is full, try the secondary */
+	if (unlikely(slot == -1)) {
+		hpte_group = ((~hash & htab_hash_mask) *
+			      HPTES_PER_GROUP) & ~0x7UL;
+		slot = ppc_md.hpte_insert(hpte_group, vpn, pa, rflags,
+					  vflags | HPTE_V_SECONDARY,
+					  psize, ssize);
+		if (slot == -1) {
+			if (mftb() & 0x1)
+				hpte_group = ((hash & htab_hash_mask) *
+					      HPTES_PER_GROUP)&~0x7UL;
+
+			ppc_md.hpte_remove(hpte_group);
+			goto repeat;
+		}
+	}
+
+	return slot;
+}
+
 #ifdef CONFIG_DEBUG_PAGEALLOC
 static void kernel_map_linear_page(unsigned long vaddr, unsigned long lmi)
 {
diff --git a/arch/powerpc/mm/hugetlbpage-hash64.c b/arch/powerpc/mm/hugetlbpage-hash64.c
index edb4129..b913f41 100644
--- a/arch/powerpc/mm/hugetlbpage-hash64.c
+++ b/arch/powerpc/mm/hugetlbpage-hash64.c
@@ -14,6 +14,10 @@
 #include <asm/cacheflush.h>
 #include <asm/machdep.h>
 
+extern long hpte_insert_repeating(unsigned long hash, unsigned long vpn,
+				  unsigned long pa, unsigned long rlags,
+				  unsigned long vflags, int psize, int ssize);
+
 int __hash_page_huge(unsigned long ea, unsigned long access, unsigned long vsid,
 		     pte_t *ptep, unsigned long trap, int local, int ssize,
 		     unsigned int shift, unsigned int mmu_psize)
@@ -83,7 +87,6 @@ int __hash_page_huge(unsigned long ea, unsigned long access, unsigned long vsid,
 
 	if (likely(!(old_pte & _PAGE_HASHPTE))) {
 		unsigned long hash = hpt_hash(vpn, shift, ssize);
-		unsigned long hpte_group;
 
 		pa = pte_pfn(__pte(old_pte)) << PAGE_SHIFT;
 
@@ -97,30 +100,8 @@ int __hash_page_huge(unsigned long ea, unsigned long access, unsigned long vsid,
 		rflags |= (new_pte & (_PAGE_WRITETHRU | _PAGE_NO_CACHE |
 				      _PAGE_COHERENT | _PAGE_GUARDED));
 
-repeat:
-		hpte_group = ((hash & htab_hash_mask) *
-			      HPTES_PER_GROUP) & ~0x7UL;
-
-		/* Insert into the hash table, primary slot */
-		slot = ppc_md.hpte_insert(hpte_group, vpn, pa, rflags, 0,
-					  mmu_psize, ssize);
-
-		/* Primary is full, try the secondary */
-		if (unlikely(slot == -1)) {
-			hpte_group = ((~hash & htab_hash_mask) *
-				      HPTES_PER_GROUP) & ~0x7UL;
-			slot = ppc_md.hpte_insert(hpte_group, vpn, pa, rflags,
-						  HPTE_V_SECONDARY,
-						  mmu_psize, ssize);
-			if (slot == -1) {
-				if (mftb() & 0x1)
-					hpte_group = ((hash & htab_hash_mask) *
-						      HPTES_PER_GROUP)&~0x7UL;
-
-				ppc_md.hpte_remove(hpte_group);
-				goto repeat;
-                        }
-		}
+		slot = hpte_insert_repeating(hash, vpn, pa, rflags, 0,
+					     mmu_psize, ssize);
 
 		/*
 		 * Hypervisor failure. Restore old pte and return -1
-- 
1.7.9.5

^ permalink raw reply related

* [RFC PATCH v3 3/3] powerpc: Try to insert the hptes repeatedly in kernel_map_linear_page()
From: Li Zhong @ 2013-04-16  2:53 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: paulus, Li Zhong
In-Reply-To: <1366080800-27885-1-git-send-email-zhong@linux.vnet.ibm.com>

This patch fixes the following oops, which could be trigged by build the kernel
with many concurrent threads, under CONFIG_DEBUG_PAGEALLOC.

hpte_insert() might return -1, indicating that the bucket (primary here)
is full. We are not necessarily reporting a BUG in this case. Instead, we could
try repeatedly (try secondary, remove and try again) until we find a slot.

[  543.075675] ------------[ cut here ]------------
[  543.075701] kernel BUG at arch/powerpc/mm/hash_utils_64.c:1239!
[  543.075714] Oops: Exception in kernel mode, sig: 5 [#1]
[  543.075722] PREEMPT SMP NR_CPUS=16 DEBUG_PAGEALLOC NUMA pSeries
[  543.075741] Modules linked in: binfmt_misc ehea
[  543.075759] NIP: c000000000036eb0 LR: c000000000036ea4 CTR: c00000000005a594
[  543.075771] REGS: c0000000a90832c0 TRAP: 0700   Not tainted  (3.8.0-next-20130222)
[  543.075781] MSR: 8000000000029032 <SF,EE,ME,IR,DR,RI>  CR: 22224482  XER: 00000000
[  543.075816] SOFTE: 0
[  543.075823] CFAR: c00000000004c200
[  543.075830] TASK = c0000000e506b750[23934] 'cc1' THREAD: c0000000a9080000 CPU: 1
GPR00: 0000000000000001 c0000000a9083540 c000000000c600a8 ffffffffffffffff
GPR04: 0000000000000050 fffffffffffffffa c0000000a90834e0 00000000004ff594
GPR08: 0000000000000001 0000000000000000 000000009592d4d8 c000000000c86854
GPR12: 0000000000000002 c000000006ead300 0000000000a51000 0000000000000001
GPR16: f000000003354380 ffffffffffffffff ffffffffffffff80 0000000000000000
GPR20: 0000000000000001 c000000000c600a8 0000000000000001 0000000000000001
GPR24: 0000000003354380 c000000000000000 0000000000000000 c000000000b65950
GPR28: 0000002000000000 00000000000cd50e 0000000000bf50d9 c000000000c7c230
[  543.076005] NIP [c000000000036eb0] .kernel_map_pages+0x1e0/0x3f8
[  543.076016] LR [c000000000036ea4] .kernel_map_pages+0x1d4/0x3f8
[  543.076025] Call Trace:
[  543.076033] [c0000000a9083540] [c000000000036ea4] .kernel_map_pages+0x1d4/0x3f8 (unreliable)
[  543.076053] [c0000000a9083640] [c000000000167638] .get_page_from_freelist+0x6cc/0x8dc
[  543.076067] [c0000000a9083800] [c000000000167a48] .__alloc_pages_nodemask+0x200/0x96c
[  543.076082] [c0000000a90839c0] [c0000000001ade44] .alloc_pages_vma+0x160/0x1e4
[  543.076098] [c0000000a9083a80] [c00000000018ce04] .handle_pte_fault+0x1b0/0x7e8
[  543.076113] [c0000000a9083b50] [c00000000018d5a8] .handle_mm_fault+0x16c/0x1a0
[  543.076129] [c0000000a9083c00] [c0000000007bf1dc] .do_page_fault+0x4d0/0x7a4
[  543.076144] [c0000000a9083e30] [c0000000000090e8] handle_page_fault+0x10/0x30
[  543.076155] Instruction dump:
[  543.076163] 7c630038 78631d88 e80a0000 f8410028 7c0903a6 e91f01de e96a0010 e84a0008
[  543.076192] 4e800421 e8410028 7c7107b4 7a200fe0 <0b000000> 7f63db78 48785781 60000000
[  543.076224] ---[ end trace bd5807e8d6ae186b ]---

Signed-off-by: Li Zhong <zhong@linux.vnet.ibm.com>
---
 arch/powerpc/mm/hash_utils_64.c |   13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
index ead9fa8..1ed4419 100644
--- a/arch/powerpc/mm/hash_utils_64.c
+++ b/arch/powerpc/mm/hash_utils_64.c
@@ -1268,21 +1268,22 @@ repeat:
 #ifdef CONFIG_DEBUG_PAGEALLOC
 static void kernel_map_linear_page(unsigned long vaddr, unsigned long lmi)
 {
-	unsigned long hash, hpteg;
+	unsigned long hash;
 	unsigned long vsid = get_kernel_vsid(vaddr, mmu_kernel_ssize);
 	unsigned long vpn = hpt_vpn(vaddr, vsid, mmu_kernel_ssize);
 	unsigned long mode = htab_convert_pte_flags(PAGE_KERNEL);
-	int ret;
+	long ret;
 
 	hash = hpt_hash(vpn, PAGE_SHIFT, mmu_kernel_ssize);
-	hpteg = ((hash & htab_hash_mask) * HPTES_PER_GROUP);
 
 	/* Don't create HPTE entries for bad address */
 	if (!vsid)
 		return;
-	ret = ppc_md.hpte_insert(hpteg, vpn, __pa(vaddr),
-				 mode, HPTE_V_BOLTED,
-				 mmu_linear_psize, mmu_kernel_ssize);
+
+	ret = hpte_insert_repeating(hash, vpn, __pa(vaddr), mode,
+				    HPTE_V_BOLTED,
+				    mmu_linear_psize, mmu_kernel_ssize);
+
 	BUG_ON (ret < 0);
 	spin_lock(&linear_map_hash_lock);
 	BUG_ON(linear_map_hash_slots[lmi] & 0x80);
-- 
1.7.9.5

^ permalink raw reply related

* Re: [PATCHv3 2/2] radeon: use max_bus_speed to activate gen2 speeds
From: Dave Airlie @ 2013-04-16  3:17 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: DRI mailing list, Kleber Sacilotto de Souza, Brian King,
	Jerome Glisse, Thadeu Lima de Souza Cascardo,
	Lucas Kannebley Tavares, Alex Deucher, linuxppc-dev
In-Reply-To: <CAErSpo7vxSJix83DQcsARPWYWbx8UGxQ9FN61OtEJrEv7GhK=g@mail.gmail.com>

>>
>> diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
>> index 305a657..3291f62 100644
>> --- a/drivers/gpu/drm/radeon/evergreen.c
>> +++ b/drivers/gpu/drm/radeon/evergreen.c
>> @@ -3855,8 +3855,7 @@ void evergreen_fini(struct radeon_device *rdev)
>>
>>  void evergreen_pcie_gen2_enable(struct radeon_device *rdev)
>>  {
>> -       u32 link_width_cntl, speed_cntl, mask;
>> -       int ret;
>> +       u32 link_width_cntl, speed_cntl;
>>
>>         if (radeon_pcie_gen2 == 0)
>>                 return;
>> @@ -3871,11 +3870,7 @@ void evergreen_pcie_gen2_enable(struct radeon_device *rdev)
>>         if (ASIC_IS_X2(rdev))
>>                 return;
>>
>> -       ret = drm_pcie_get_speed_cap_mask(rdev->ddev, &mask);
>> -       if (ret != 0)
>> -               return;
>> -
>> -       if (!(mask & DRM_PCIE_SPEED_50))
>> +       if (rdev->pdev->bus->max_bus_speed < PCIE_SPEED_5_0GT)
>
> For devices on a root bus, we previously dereferenced a NULL pointer
> in drm_pcie_get_speed_cap_mask() because pdev->bus->self is NULL on a
> root bus.  (I think this is the original problem you tripped over,
> Lucas.)
>
> These patches fix that problem.  On pseries, where the device *is* on
> a root bus, your patches set max_bus_speed so this will work as
> expected.  On most other systems, max_bus_speed for root buses will be
> PCI_SPEED_UNKNOWN (set in pci_alloc_bus() and never updated because
> most arches don't have code like the pseries code you're adding).
>
> PCI_SPEED_UNKNOWN = 0xff, so if we see another machine with a GPU on
> the root bus, we'll attempt to enable Gen2 on the device even though
> we have no idea what the bus will support.
>
> That's why I originally suggested skipping the Gen2 stuff if
> "max_bus_speed == PCI_SPEED_UNKNOWN".  I was just being conservative,
> thinking that it's better to have a functional but slow GPU rather
> than the unknown (to me) effects of enabling Gen2 on a link that might
> not support it.  But I'm fine with this being either way.
>
> It would be nice if we could get rid of drm_pcie_get_speed_cap_mask()
> altogether.  It is exported, but I have no idea of anybody else uses
> it.  Maybe it could at least be marked __deprecated now?
>
> I don't know who should take these patches.  They don't touch
> drivers/pci, but I'd be happy to push them, given the appropriate ACKs
> from DRM and powerpc folks.
>

Acked-by: Dave Airlie <airlied@redhat.com>

I'm happy to see these go via pci tree to avoid interdependent trees.

Dave.

^ permalink raw reply

* Re: [PATCH] powerpc: Fix audit crash due to save/restore PPR changes
From: Haren Myneni @ 2013-04-16  5:38 UTC (permalink / raw)
  To: Alistair Popple; +Cc: sfr, mikey, linuxppc-dev
In-Reply-To: <18949a6b246ced7268c2d2831f931f01.squirrel@mignight.com>

On 04/14/2013 06:44 PM, Alistair Popple wrote:
> The current mainline crashes when hitting userspace with the following:
> 
> kernel BUG at /home/alistair/Source/linux-stable/kernel/auditsc.c:1769!
> cpu 0x1: Vector: 700 (Program Check) at [c000000023883a60]
>     pc: c0000000001047a8: .__audit_syscall_entry+0x38/0x130
>     lr: c00000000000ed64: .do_syscall_trace_enter+0xc4/0x270
>     sp: c000000023883ce0
>    msr: 8000000000029032
>   current = 0xc000000023800000
>   paca    = 0xc00000000f080380   softe: 0        irq_happened: 0x01
>     pid   = 1629, comm = start_udev
> kernel BUG at /home/alistair/Source/linux-stable/kernel/auditsc.c:1769!
> enter ? for help
> [c000000023883d80] c00000000000ed64 .do_syscall_trace_enter+0xc4/0x270
> [c000000023883e30] c000000000009b08 syscall_dotrace+0xc/0x38
> --- Exception: c00 (System Call) at 0000008010ec50dc
> 
> Bisecting found the following patch caused it:
> 
> commit 44e9309f1f357794b7ae93d5f3e3e6f11d2b8a7f
> Author: Haren Myneni <haren@linux.vnet.ibm.com>
> powerpc: Implement PPR save/restore
> 
> It was found this patch corrupted r9 when calling
> SET_DEFAULT_THREAD_PPR()
> 
> Using r10 as a scratch register instead of r9 solved the problem.

Thanks for fixing. Sorry I missed it

Acked-by: Haren Myneni <haren@us.ibm.com>

> 
> Signed-off-by: Alistair Popple <alistair@popple.id.au>
> Acked-by: Michael Neuling <mikey@neuling.org>
> ---
> 
> diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
> index 256c5bf..3acb1a0 100644
> --- a/arch/powerpc/kernel/entry_64.S
> +++ b/arch/powerpc/kernel/entry_64.S
> @@ -304,7 +304,7 @@ syscall_exit_work:
>  	subi	r12,r12,TI_FLAGS
> 
>  4:	/* Anything else left to do? */
> -	SET_DEFAULT_THREAD_PPR(r3, r9)		/* Set thread.ppr = 3 */
> +	SET_DEFAULT_THREAD_PPR(r3, r10)		/* Set thread.ppr = 3 */
>  	andi.	r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP)
>  	beq	.ret_from_except_lite
> 
> 
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev
> 

^ permalink raw reply

* Re: [PATCH 4/8] Read/Write oops nvram partition via pstore
From: Aruna Balakrishnaiah @ 2013-04-16  6:20 UTC (permalink / raw)
  To: Michael Ellerman
  Cc: jkenisto, mahesh, linux-kernel, linuxppc-dev, paulus, anton
In-Reply-To: <20130415075555.GE30156@concordia>

Hi Michael,

Thanks for reviewing my patches.

On Monday 15 April 2013 01:25 PM, Michael Ellerman wrote:
> On Wed, Apr 10, 2013 at 12:53:03PM +0530, Aruna Balakrishnaiah wrote:
>> This patch exploits pstore infrastructure in power systems.
>> IBM's system p machines provide persistent storage for LPARs
> In the kernel we use "pseries" instead of "system p".
>

Sure, will change it.

>> through NVRAM. NVRAM's lnx,oops-log partition is used to log
>> oops messages. In case pstore registration fails it will
>> fall back to kmsg_dump mechanism.
> What are the implications of falling back to kmsg_dump()?
>

Logging oops messages to nvram should not fail in case pstore registration
fails. So it falls back to existing kmsg_dump infrastructure where
oops_to_nvram will be called. The users would need to use existing tools
to read nvram data as it is now.

> Is there any reason we would not want to enable CONFIG_PSTORE ? ie.
> should the pseries platform just select it?

Since current patchset does not support compression, selecting PSTORE by
default will lose the existing compression feature.
Once the compression feature for PSTORE is in place we can make PSTORE as
default on power.

I will post the compression patches soon. The reason for posting it
separately is stated below.

>> diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c
>> index 6701b71..82d32a2 100644
>> --- a/arch/powerpc/platforms/pseries/nvram.c
>> +++ b/arch/powerpc/platforms/pseries/nvram.c
>> @@ -18,6 +18,7 @@
>>   #include <linux/spinlock.h>
>>   #include <linux/slab.h>
>>   #include <linux/kmsg_dump.h>
>> +#include <linux/pstore.h>
>>   #include <linux/ctype.h>
>>   #include <linux/zlib.h>
>>   #include <asm/uaccess.h>
>> @@ -87,6 +88,25 @@ static struct kmsg_dumper nvram_kmsg_dumper = {
>>   	.dump = oops_to_nvram
>>   };
>>   
>> +static int nvram_pstore_open(struct pstore_info *psi);
>> +
>> +static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type,
>> +				int *count, struct timespec *time, char **buf,
>> +				struct pstore_info *psi);
>> +
>> +static int nvram_pstore_write(enum pstore_type_id type,
>> +				enum kmsg_dump_reason reason, u64 *id,
>> +				unsigned int part, int count, size_t size,
>> +				struct pstore_info *psi);
> I think you should be able to rearrange this so that you don't need the
> forward declarations.

Sure. This would result in moving the callback functions just before pstore
registration for which I need to move clobbering_unread_rtas_event() which
is used by nvram_pstore_write.

>> +
>> +static struct pstore_info nvram_pstore_info = {
>> +	.owner = THIS_MODULE,
>> +	.name = "nvram",
>> +	.open = nvram_pstore_open,
>> +	.read = nvram_pstore_read,
>> +	.write = nvram_pstore_write,
>> +};
>> +
>>   /* See clobbering_unread_rtas_event() */
>>   #define NVRAM_RTAS_READ_TIMEOUT 5		/* seconds */
>>   static unsigned long last_unread_rtas_event;	/* timestamp */
>> @@ -121,6 +141,13 @@ static char *big_oops_buf, *oops_buf;
>>   static char *oops_data;
>>   static size_t oops_data_sz;
>>   
>> +#ifdef CONFIG_PSTORE
> If we are going to have CONFIG_PSTORE #ifdefs in this file, I don't see
> why there can't be just a single block of code that is #ifdef'ed, rather
> than several like you have.

Sure. I will have one #ifdef for declarations and one for function
definitions.

>> +static enum pstore_type_id nvram_type_ids[] = {
>> +	PSTORE_TYPE_DMESG,
>> +	-1
>> +};
>> +static int read_type;
> I don't understand what you're doing with read_type. It looks fishy.

read_type is an iterator to traverse the partition types. It is to know
which partition we need to read.

>> +#endif
>>   /* Compression parameters */
>>   #define COMPR_LEVEL 6
>>   #define WINDOW_BITS 12
>> @@ -455,6 +482,23 @@ static void __init nvram_init_oops_partition(int rtas_partition_exists)
>>   	oops_data = oops_buf + sizeof(struct oops_log_info);
>>   	oops_data_sz = oops_log_partition.size - sizeof(struct oops_log_info);
>>   
>> +	nvram_pstore_info.buf = oops_data;
>> +	nvram_pstore_info.bufsize = oops_data_sz;
>> +
>> +	rc = pstore_register(&nvram_pstore_info);
>> +
>> +	if (rc != 0) {
>> +		pr_err("nvram: pstore_register() failed, defaults to "
>> +				"kmsg_dump; returned %d\n", rc);
>> +		goto kmsg_dump;
> You don't need the goto.

Yeah, my bad. Will fix it.

>> +	} else {
>> +		/*TODO: Support compression when pstore is configured */
> What is the issue here?
>

Currently with this patchset, pstore is not supporting compression of oops-messages
since it involves some changes in the pstore framework.

big_oops_buf will hold the large part of oops data which will be compressed and put
to oops_buf.

big_oops_buf: (1.45 of oops_partition_size)
_________________________
|  header |   oops-text |
|_________|_____________|

<header> is added by the pstore.

So in case compression fails:

we would need to log the header + last few bytes of big_oops_buf to oops_buf.
oops_buf: (this is of oops_partition_size)

we need last few bytes of big_oops_buf as we need to log the recent messages of
printk buffer. For which we need to know the header size and it involves some
changes in the pstore framework.

I have the compression patches ready, will be posting it soon as a separate set.

>> +		pr_info("nvram: Compression of oops text supported only when "
>> +				"pstore is not configured");
>> +		return;
>> +	}
>> +
>> +kmsg_dump:
>>   	/*
>>   	 * Figure compression (preceded by elimination of each line's <n>
>>   	 * severity prefix) will reduce the oops/panic report to at most
>> @@ -663,3 +707,104 @@ static void oops_to_nvram(struct kmsg_dumper *dumper,
>>   
>>   	spin_unlock_irqrestore(&lock, flags);
>>   }
>> +
>> +#ifdef CONFIG_PSTORE
> Same comment about too many ifdefs.
>

I will reduce some of the #ifdefs, but its necessary to have one for
declarations and one for function definitions.

For instance: nvram_pstore_write calls nvram_write_os_partition.
So callback function definitions should be after some of the function
definitions which it will make use of.

>> +static int nvram_pstore_open(struct pstore_info *psi)
>> +{
>> +	read_type = -1;
> Locking?

We need to reset read_type for a remount case. When a umount and mount
is done nvram_pstore_read needs to know that it has to start reading
the partitions again. So we reset the iterator.

>> +	return 0;
>> +}
>> +
>> +/*
> Make it a kernel-doc style comment.

Sure.

>> + * Called by pstore_dump() when an oops or panic report is logged to the printk
>> + * buffer. @size bytes have been written to oops_buf, starting after the
>> + * oops_log_info header.
> "@size bytes have", or "@size bytes should be written"?

Sure.

>> + */
>> +static int nvram_pstore_write(enum pstore_type_id type,
>> +				enum kmsg_dump_reason reason,
>> +				u64 *id, unsigned int part, int count,
>> +				size_t size, struct pstore_info *psi)
>> +{
>> +	struct oops_log_info *oops_hdr = (struct oops_log_info *) oops_buf;
>> +
>> +	/* part 1 has the recent messages from printk buffer */
>> +	if (part > 1 || clobbering_unread_rtas_event())
>> +		return -1;
>> +
>> +	BUG_ON(type != PSTORE_TYPE_DMESG);
>> +	BUG_ON(sizeof(*oops_hdr) + size > oops_log_partition.size);
> Why would we be called with the wrong type? Would it be better to just
> return an error, rather than causing another oops while we're trying to
> write the oops?
>
> And couldn't we just clamp the size, rather than BUG'ing.

Yeah right. Will return  an error instead of bugging here.

>> +	oops_hdr->version = OOPS_HDR_VERSION;
>> +	oops_hdr->report_length = (u16) size;
>> +	oops_hdr->timestamp = get_seconds();
>> +	(void) nvram_write_os_partition(&oops_log_partition, oops_buf,
>> +		(int) (sizeof(*oops_hdr) + size), ERR_TYPE_KERNEL_PANIC,
>> +		count);
> You definitely don't need the (void). But more to the point why aren't
> you checking the return value?

I will check for the return value here.

>> +	*id = part;
> What is this? Part of the API?

Yeah this is part of the API.

>> +	return 0;
>> +}
>> +
>> +/*
>> + * Reads the oops/panic report.
>> + * Returns the length of the data we read from each partition.
>> + * Returns 0 if we've been called before.
>> + */
>> +static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type,
>> +				int *count, struct timespec *time, char **buf,
>> +				struct pstore_info *psi)
>> +{
>> +	struct oops_log_info *oops_hdr;
>> +	unsigned int err_type, id_no;
>> +	struct nvram_os_partition *part = NULL;
>> +	char *buff = NULL;
>> +
>> +	read_type++;
>> +
>> +	switch (nvram_type_ids[read_type]) {
>> +	case PSTORE_TYPE_DMESG:
>> +		part = &oops_log_partition;
>> +		*type = PSTORE_TYPE_DMESG;
>> +		break;
>> +	default:
>> +		return 0;
>> +	}
>> +
>> +	buff = kmalloc(part->size, GFP_KERNEL);
>> +
>> +	if (!buff)
>> +		return -ENOMEM;
>> +
>> +	if (nvram_read_partition(part, buff, part->size, &err_type, &id_no)) {
>> +		kfree(buff);
>> +		return 0;
>> +	}
>> +
>> +	*count = 0;
>> +	*id = id_no;
> Can't you just cast in the call to nvram_read_partition() ?

Thats right, my bad will fix it.

>> +	oops_hdr = (struct oops_log_info *)buff;
>> +	*buf = buff + sizeof(*oops_hdr);
>> +	time->tv_sec = oops_hdr->timestamp;
>> +	time->tv_nsec = 0;
>> +	return oops_hdr->report_length;
>> +}
>> +#else
>> +static int nvram_pstore_open(struct pstore_info *psi)
>> +{
>> +	return 0;
>> +}
>> +
>> +static int nvram_pstore_write(enum pstore_type_id type,
>> +				enum kmsg_dump_reason reason, u64 *id,
>> +				unsigned int part, int count, size_t size,
>> +				struct pstore_info *psi)
>> +{
>> +	return 0;
>> +}
>> +
>> +static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type,
>> +				int *count, struct timespec *time, char **buf,
>> +				struct pstore_info *psi)
>> +{
>> +	return 0;
>> +}
>> +#endif
> I don't understand why we have empty versions of these. If CONFIG_PSTORE
> is disabled we should just not register with pstore at all.

Since pstore handles the case by returning an error code when pstore is not
configured I thought of avoiding one more #ifdef during registration.
I will remove empty callbacks and add a #ifdef during registration itself.

> cheers
>

^ permalink raw reply

* Re: [PATCH 5/8] Read rtas partition via pstore
From: Aruna Balakrishnaiah @ 2013-04-16  6:21 UTC (permalink / raw)
  To: Michael Ellerman
  Cc: jkenisto, mahesh, linux-kernel, linuxppc-dev, paulus, anton
In-Reply-To: <20130415080101.GF30156@concordia>

On Monday 15 April 2013 01:31 PM, Michael Ellerman wrote:
> On Wed, Apr 10, 2013 at 12:53:27PM +0530, Aruna Balakrishnaiah wrote:
>> This patch exploits pstore infrastructure to read the details
>> from NVRAM's rtas partition.
> Does that mean it's exposed in the pstore filesystem?

Yeah thats right.

>> Signed-off-by: Aruna Balakrishnaiah <aruna@linux.vnet.ibm.com>
>> Reviewed-by: Jim Keniston <jkenisto@us.ibm.com>
>> ---
>>   arch/powerpc/platforms/pseries/nvram.c |   33 +++++++++++++++++++++++++-------
>>   fs/pstore/inode.c                      |    3 +++
>>   include/linux/pstore.h                 |    2 ++
>>   3 files changed, 31 insertions(+), 7 deletions(-)
>>
>> diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c
>> index 82d32a2..d420b1d 100644
>> --- a/arch/powerpc/platforms/pseries/nvram.c
>> +++ b/arch/powerpc/platforms/pseries/nvram.c
>> @@ -144,9 +144,11 @@ static size_t oops_data_sz;
>>   #ifdef CONFIG_PSTORE
>>   static enum pstore_type_id nvram_type_ids[] = {
>>   	PSTORE_TYPE_DMESG,
>> +	PSTORE_TYPE_RTAS,
>>   	-1
>>   };
>>   static int read_type;
>> +static unsigned long last_rtas_event;
>>   #endif
>>   /* Compression parameters */
>>   #define COMPR_LEVEL 6
>> @@ -315,8 +317,13 @@ int nvram_write_error_log(char * buff, int length,
>>   {
>>   	int rc = nvram_write_os_partition(&rtas_log_partition, buff, length,
>>   						err_type, error_log_cnt);
>> -	if (!rc)
>> +	if (!rc) {
>>   		last_unread_rtas_event = get_seconds();
>> +#ifdef CONFIG_PSTORE
>> +		last_rtas_event = get_seconds();
>> +#endif
>> +	}
>> +
>>   	return rc;
>>   }
>>   
>> @@ -745,7 +752,7 @@ static int nvram_pstore_write(enum pstore_type_id type,
>>   }
>>   
>>   /*
>> - * Reads the oops/panic report.
>> + * Reads the oops/panic report and ibm,rtas-log partition.
>>    * Returns the length of the data we read from each partition.
>>    * Returns 0 if we've been called before.
>>    */
>> @@ -765,6 +772,12 @@ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type,
>>   		part = &oops_log_partition;
>>   		*type = PSTORE_TYPE_DMESG;
>>   		break;
>> +	case PSTORE_TYPE_RTAS:
>> +		part = &rtas_log_partition;
>> +		*type = PSTORE_TYPE_RTAS;
>> +		time->tv_sec = last_rtas_event;
>> +		time->tv_nsec = 0;
>> +		break;
>>   	default:
>>   		return 0;
>>   	}
>> @@ -781,11 +794,17 @@ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type,
>>   
>>   	*count = 0;
>>   	*id = id_no;
>> -	oops_hdr = (struct oops_log_info *)buff;
>> -	*buf = buff + sizeof(*oops_hdr);
>> -	time->tv_sec = oops_hdr->timestamp;
>> -	time->tv_nsec = 0;
>> -	return oops_hdr->report_length;
>> +
>> +	if (nvram_type_ids[read_type] == PSTORE_TYPE_DMESG) {
>> +		oops_hdr = (struct oops_log_info *)buff;
>> +		*buf = buff + sizeof(*oops_hdr);
>> +		time->tv_sec = oops_hdr->timestamp;
>> +		time->tv_nsec = 0;
>> +		return oops_hdr->report_length;
>> +	}
>> +
>> +	*buf = buff;
>> +	return part->size;
>>   }
>>   #else
>>   static int nvram_pstore_open(struct pstore_info *psi)
>> diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c
>> index e4bcb2c..59b1454 100644
>> --- a/fs/pstore/inode.c
>> +++ b/fs/pstore/inode.c
>> @@ -324,6 +324,9 @@ int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id, int count,
>>   	case PSTORE_TYPE_MCE:
>>   		sprintf(name, "mce-%s-%lld", psname, id);
>>   		break;
>> +	case PSTORE_TYPE_RTAS:
>> +		sprintf(name, "rtas-%s-%lld", psname, id);
>> +		break;
>>   	case PSTORE_TYPE_UNKNOWN:
>>   		sprintf(name, "unknown-%s-%lld", psname, id);
>>   		break;
>> diff --git a/include/linux/pstore.h b/include/linux/pstore.h
>> index 75d0176..4eb94c9 100644
>> --- a/include/linux/pstore.h
>> +++ b/include/linux/pstore.h
>> @@ -35,6 +35,8 @@ enum pstore_type_id {
>>   	PSTORE_TYPE_MCE		= 1,
>>   	PSTORE_TYPE_CONSOLE	= 2,
>>   	PSTORE_TYPE_FTRACE	= 3,
>> +	/* PPC64 partition types */
>> +	PSTORE_TYPE_RTAS	= 10,
>>   	PSTORE_TYPE_UNKNOWN	= 255
> I think you should probably just continue at 4, and call it
> PSTORE_TYPE_PPC_RTAS. But you must get an ACK from the pstore
> maintainers for this and the previous hunk, and I don't see them on CC.

Sure, will add them on cc in my next version of the patches.

>
> cheers
>

^ permalink raw reply

* [PATCH] powerpc: Fix build errors with UP configs in HV-style KVM
From: Paul Mackerras @ 2013-04-16  6:28 UTC (permalink / raw)
  To: linuxppc-dev

This fixes these errors when building UP with CONFIG_KVM_BOOK3S_64_HV=y:

arch/powerpc/kvm/book3s_hv.c:1855:2: error: implicit declaration of function 'inhibit_secondary_onlining' [-Werror=implicit-function-declaration]
arch/powerpc/kvm/book3s_hv.c:1862:2: error: implicit declaration of function 'uninhibit_secondary_onlining' [-Werror=implicit-function-declaration]
cc1: all warnings being treated as errors

and this error (with CONFIG_KVM_BOOK3S_64=m, or a vmlinux link error
with CONFIG_KVM_BOOK3S_64=y):

ERROR: "smp_send_reschedule" [arch/powerpc/kvm/kvm.ko] undefined!
make[2]: *** [__modpost] Error 1

The fix for the link error is suboptimal; ideally we want a self_ipi()
function from irq.c, connected at least to the MPIC code, to initiate
an IPI to this cpu.  The fix here at least lets the code build, and it
will work, just with interrupts being delayed sometimes.

Signed-off-by: Paul Mackerras <paulus@samba.org>
---
 arch/powerpc/include/asm/smp.h          |    2 ++
 arch/powerpc/kvm/book3s_hv_interrupts.S |    6 ++++++
 2 files changed, 8 insertions(+)

diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h
index 195ce2a..ffbaabe 100644
--- a/arch/powerpc/include/asm/smp.h
+++ b/arch/powerpc/include/asm/smp.h
@@ -143,6 +143,8 @@ extern void __cpu_die(unsigned int cpu);
 /* for UP */
 #define hard_smp_processor_id()		get_hard_smp_processor_id(0)
 #define smp_setup_cpu_maps()
+static inline void inhibit_secondary_onlining(void) {}
+static inline void uninhibit_secondary_onlining(void) {}
 
 #endif /* CONFIG_SMP */
 
diff --git a/arch/powerpc/kvm/book3s_hv_interrupts.S b/arch/powerpc/kvm/book3s_hv_interrupts.S
index 84035a5..37f1cc4 100644
--- a/arch/powerpc/kvm/book3s_hv_interrupts.S
+++ b/arch/powerpc/kvm/book3s_hv_interrupts.S
@@ -122,11 +122,16 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
 	add	r8,r8,r7
 	std	r8,HSTATE_DECEXP(r13)
 
+#ifdef CONFIG_SMP
 	/*
 	 * On PPC970, if the guest vcpu has an external interrupt pending,
 	 * send ourselves an IPI so as to interrupt the guest once it
 	 * enables interrupts.  (It must have interrupts disabled,
 	 * otherwise we would already have delivered the interrupt.)
+	 *
+	 * XXX If this is a UP build, smp_send_reschedule is not available,
+	 * so the interrupt will be delayed until the next time the vcpu
+	 * enters the guest with interrupts enabled.
 	 */
 BEGIN_FTR_SECTION
 	ld	r0, VCPU_PENDING_EXC(r4)
@@ -141,6 +146,7 @@ BEGIN_FTR_SECTION
 	mr	r4, r31
 32:
 END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
+#endif /* CONFIG_SMP */
 
 	/* Jump to partition switch code */
 	bl	.kvmppc_hv_entry_trampoline
-- 
1.7.10.4

^ permalink raw reply related

* RE: [PATCH v2] of/base: release the node correctly in of_parse_phandle_with_args()
From: Tang Yuantian-B29983 @ 2013-04-16  6:54 UTC (permalink / raw)
  To: Tang Yuantian-B29983, grant.likely@secretlab.ca
  Cc: devicetree-discuss@lists.ozlabs.org,
	linuxppc-dev@lists.ozlabs.org, linux-kernel@vger.kernel.org,
	rob.herring@calxeda.com
In-Reply-To: <1365564999-24427-1-git-send-email-Yuantian.Tang@freescale.com>

SGkgR3JhbnQubGlrZWx5LA0KDQpJIHJlYWxseSBwcmVjaWF0ZSBpZiB5b3UgY2FuIHNwZW5kIHNv
bWUgdGltZXMgdG8gcmV2aWV3IHRoaXMgcGF0Y2guDQoNClRoYW5rcywNCll1YW50aWFuDQoNCj4g
LS0tLS1PcmlnaW5hbCBNZXNzYWdlLS0tLS0NCj4gRnJvbTogVGFuZyBZdWFudGlhbi1CMjk5ODMN
Cj4gU2VudDogMjAxM8TqNNTCMTDI1SAxMTozNw0KPiBUbzogZ3JhbnQubGlrZWx5QHNlY3JldGxh
Yi5jYQ0KPiBDYzogcm9iLmhlcnJpbmdAY2FseGVkYS5jb207IGRldmljZXRyZWUtZGlzY3Vzc0Bs
aXN0cy5vemxhYnMub3JnOyBsaW51eC0NCj4ga2VybmVsQHZnZXIua2VybmVsLm9yZzsgbGludXhw
cGMtZGV2QGxpc3RzLm96bGFicy5vcmc7IFRhbmcgWXVhbnRpYW4tDQo+IEIyOTk4MzsgVGFuZyBZ
dWFudGlhbi1CMjk5ODMNCj4gU3ViamVjdDogW1BBVENIIHYyXSBvZi9iYXNlOiByZWxlYXNlIHRo
ZSBub2RlIGNvcnJlY3RseSBpbg0KPiBvZl9wYXJzZV9waGFuZGxlX3dpdGhfYXJncygpDQo+IA0K
PiBGcm9tOiBUYW5nIFl1YW50aWFuIDx5dWFudGlhbi50YW5nQGZyZWVzY2FsZS5jb20+DQo+IA0K
PiBDYWxsIG9mX25vZGVfcHV0KCkgb25seSB3aGVuIHRoZSBvdXRfYXJncyBpcyBOVUxMIG9uIHN1
Y2Nlc3MsIG9yIHRoZQ0KPiBub2RlJ3MgcmVmZXJlbmNlIGNvdW50IHdpbGwgbm90IGJlIGNvcnJl
Y3QgYmVjYXVzZSB0aGUgY2FsbGVyIHdpbGwgY2FsbA0KPiBvZl9ub2RlX3B1dCgpIGFnYWluLg0K
PiANCj4gU2lnbmVkLW9mZi1ieTogVGFuZyBZdWFudGlhbiA8WXVhbnRpYW4uVGFuZ0BmcmVlc2Nh
bGUuY29tPg0KPiAtLS0NCj4gdjI6DQo+IAktIG1vZGlmaWVkIHRoZSB0aXRsZSBhbmQgZGVzY3Jp
cHRpb24uIHRoZSAxc3QgcGF0Y2ggdGl0bGUgaXM6DQo+IAkgIG9mOiByZW1vdmUgdGhlIHVubmVj
ZXNzYXJ5IG9mX25vZGVfcHV0IGZvcg0KPiBvZl9wYXJzZV9waGFuZGxlX3dpdGhfYXJncygpDQo+
IAkgIHRoZSAxc3QgcGF0Y2ggaXMgbm90IGdvb2QgZW5vdWdoLg0KPiANCj4gIGRyaXZlcnMvb2Yv
YmFzZS5jIHwgNiArKystLS0NCj4gIDEgZmlsZSBjaGFuZ2VkLCAzIGluc2VydGlvbnMoKyksIDMg
ZGVsZXRpb25zKC0pDQo+IA0KPiBkaWZmIC0tZ2l0IGEvZHJpdmVycy9vZi9iYXNlLmMgYi9kcml2
ZXJzL29mL2Jhc2UuYyBpbmRleCAzMjFkM2VmLi5lZTk0ZjY0DQo+IDEwMDY0NA0KPiAtLS0gYS9k
cml2ZXJzL29mL2Jhc2UuYw0KPiArKysgYi9kcml2ZXJzL29mL2Jhc2UuYw0KPiBAQCAtMTE1OCw2
ICsxMTU4LDcgQEAgc3RhdGljIGludCBfX29mX3BhcnNlX3BoYW5kbGVfd2l0aF9hcmdzKGNvbnN0
DQo+IHN0cnVjdCBkZXZpY2Vfbm9kZSAqbnAsDQo+ICAJCQlpZiAoIXBoYW5kbGUpDQo+ICAJCQkJ
Z290byBlcnI7DQo+IA0KPiArCQkJLyogRm91bmQgaXQhIHJldHVybiBzdWNjZXNzICovDQo+ICAJ
CQlpZiAob3V0X2FyZ3MpIHsNCj4gIAkJCQlpbnQgaTsNCj4gIAkJCQlpZiAoV0FSTl9PTihjb3Vu
dCA+IE1BWF9QSEFORExFX0FSR1MpKSBAQCAtDQo+IDExNjYsMTEgKzExNjcsMTAgQEAgc3RhdGlj
IGludCBfX29mX3BhcnNlX3BoYW5kbGVfd2l0aF9hcmdzKGNvbnN0IHN0cnVjdA0KPiBkZXZpY2Vf
bm9kZSAqbnAsDQo+ICAJCQkJb3V0X2FyZ3MtPmFyZ3NfY291bnQgPSBjb3VudDsNCj4gIAkJCQlm
b3IgKGkgPSAwOyBpIDwgY291bnQ7IGkrKykNCj4gIAkJCQkJb3V0X2FyZ3MtPmFyZ3NbaV0gPSBi
ZTMyX3RvX2NwdXAobGlzdCsrKTsNCj4gKwkJCX0gZWxzZSBpZiAobm9kZSkgew0KPiArCQkJCW9m
X25vZGVfcHV0KG5vZGUpOw0KPiAgCQkJfQ0KPiANCj4gLQkJCS8qIEZvdW5kIGl0ISByZXR1cm4g
c3VjY2VzcyAqLw0KPiAtCQkJaWYgKG5vZGUpDQo+IC0JCQkJb2Zfbm9kZV9wdXQobm9kZSk7DQo+
ICAJCQlyZXR1cm4gMDsNCj4gIAkJfQ0KPiANCj4gLS0NCj4gMS44LjANCg0K

^ permalink raw reply

* RE: [PATCH v3] clk: add PowerPC corenet clock driver support
From: Tang Yuantian-B29983 @ 2013-04-16  6:59 UTC (permalink / raw)
  To: Tang Yuantian-B29983, mturquette@linaro.org
  Cc: ulf.hansson@linaro.org, Li Yang-R58472, linux-doc@vger.kernel.org,
	viresh.kumar@linaro.org, devicetree-discuss@lists.ozlabs.org,
	linux-kernel@vger.kernel.org, shawn.guo@linaro.org,
	linuxppc-dev@lists.ozlabs.org, linus.walleij@linaro.org
In-Reply-To: <1365497187-8305-1-git-send-email-Yuantian.Tang@freescale.com>

SGkgTWlrZSwNCg0KSSByZWFsbHkgYXBwcmVjaWF0ZSBpZiB5b3UgY2FuIHNwZW5kIHNvbWUgdGlt
ZXMgdG8gcmV2aWV3IHRoaXMgcGF0Y2guDQoNClRoYW5rcywNCll1YW50aWFuDQoNCg0KPiAtLS0t
LU9yaWdpbmFsIE1lc3NhZ2UtLS0tLQ0KPiBGcm9tOiBUYW5nIFl1YW50aWFuLUIyOTk4Mw0KPiBT
ZW50OiAyMDEzxOo01MI5yNUgMTY6NDYNCj4gVG86IG10dXJxdWV0dGVAbGluYXJvLm9yZw0KPiBD
YzogbGludXMud2FsbGVpakBsaW5hcm8ub3JnOyB2aXJlc2gua3VtYXJAbGluYXJvLm9yZzsNCj4g
c2hhd24uZ3VvQGxpbmFyby5vcmc7IHVsZi5oYW5zc29uQGxpbmFyby5vcmc7IGxpbnV4LQ0KPiBr
ZXJuZWxAdmdlci5rZXJuZWwub3JnOyBkZXZpY2V0cmVlLWRpc2N1c3NAbGlzdHMub3psYWJzLm9y
ZzsgbGludXhwcGMtDQo+IGRldkBsaXN0cy5vemxhYnMub3JnOyBsaW51eC1kb2NAdmdlci5rZXJu
ZWwub3JnOyBUYW5nIFl1YW50aWFuLUIyOTk4MzsNCj4gVGFuZyBZdWFudGlhbi1CMjk5ODM7IExp
IFlhbmctUjU4NDcyDQo+IFN1YmplY3Q6IFtQQVRDSCB2M10gY2xrOiBhZGQgUG93ZXJQQyBjb3Jl
bmV0IGNsb2NrIGRyaXZlciBzdXBwb3J0DQo+IA0KPiBGcm9tOiBUYW5nIFl1YW50aWFuIDx5dWFu
dGlhbi50YW5nQGZyZWVzY2FsZS5jb20+DQo+IA0KPiBUaGlzIGFkZHMgdGhlIGNsb2NrIGRyaXZl
ciBmb3IgRnJlZXNjYWxlIFBvd2VyUEMgY29yZW5ldCBzZXJpZXMgU29Dcw0KPiB1c2luZyBjb21t
b24gY2xvY2sgaW5mcmFzdHJ1Y3R1cmUuDQo+IA0KPiBTaWduZWQtb2ZmLWJ5OiBUYW5nIFl1YW50
aWFuIDxZdWFudGlhbi5UYW5nQGZyZWVzY2FsZS5jb20+DQo+IFNpZ25lZC1vZmYtYnk6IExpIFlh
bmcgPGxlb2xpQGZyZWVzY2FsZS5jb20+DQo+IC0tLQ0KPiB2MzoNCj4gCS0gcmVtb3ZlIHRoZSBt
b2R1bGUgYXV0aG9yIGFuZCBkZXNjcmlwdGlvbg0KPiB2MjoNCj4gCS0gYWRkIHRoZSBkb2N1bWVu
dCBmb3IgZGV2aWNlIHRyZWUgY2xvY2sgYmluZGluZ3MNCj4gDQo+ICBhcmNoL3Bvd2VycGMvcGxh
dGZvcm1zL0tjb25maWcuY3B1dHlwZSB8ICAgMSArDQo+ICBkcml2ZXJzL2Nsay9LY29uZmlnICAg
ICAgICAgICAgICAgICAgICB8ICAgNyArDQo+ICBkcml2ZXJzL2Nsay9NYWtlZmlsZSAgICAgICAg
ICAgICAgICAgICB8ICAgMSArDQo+ICBkcml2ZXJzL2Nsay9jbGstcHBjLWNvcmVuZXQuYyAgICAg
ICAgICB8IDI4MA0KPiArKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysNCj4gIDQgZmls
ZXMgY2hhbmdlZCwgMjg5IGluc2VydGlvbnMoKykNCj4gIGNyZWF0ZSBtb2RlIDEwMDY0NCBkcml2
ZXJzL2Nsay9jbGstcHBjLWNvcmVuZXQuYw0KPiANCj4gZGlmZiAtLWdpdCBhL2FyY2gvcG93ZXJw
Yy9wbGF0Zm9ybXMvS2NvbmZpZy5jcHV0eXBlDQo+IGIvYXJjaC9wb3dlcnBjL3BsYXRmb3Jtcy9L
Y29uZmlnLmNwdXR5cGUNCj4gaW5kZXggMThlM2I3Ni4uY2YwNjViOCAxMDA2NDQNCj4gLS0tIGEv
YXJjaC9wb3dlcnBjL3BsYXRmb3Jtcy9LY29uZmlnLmNwdXR5cGUNCj4gKysrIGIvYXJjaC9wb3dl
cnBjL3BsYXRmb3Jtcy9LY29uZmlnLmNwdXR5cGUNCj4gQEAgLTE1OCw2ICsxNTgsNyBAQCBjb25m
aWcgRTUwMA0KPiAgY29uZmlnIFBQQ19FNTAwTUMNCj4gIAlib29sICJlNTAwbWMgU3VwcG9ydCIN
Cj4gIAlzZWxlY3QgUFBDX0ZQVQ0KPiArCXNlbGVjdCBDT01NT05fQ0xLDQo+ICAJZGVwZW5kcyBv
biBFNTAwDQo+ICAJaGVscA0KPiAgCSAgVGhpcyBtdXN0IGJlIGVuYWJsZWQgZm9yIHJ1bm5pbmcg
b24gZTUwMG1jIChhbmQgZGVyaXZhdGl2ZXMgZGlmZg0KPiAtLWdpdCBhL2RyaXZlcnMvY2xrL0tj
b25maWcgYi9kcml2ZXJzL2Nsay9LY29uZmlnIGluZGV4IGE0N2U2ZWUuLjZlMmZkOWMNCj4gMTAw
NjQ0DQo+IC0tLSBhL2RyaXZlcnMvY2xrL0tjb25maWcNCj4gKysrIGIvZHJpdmVycy9jbGsvS2Nv
bmZpZw0KPiBAQCAtNjMsNiArNjMsMTMgQEAgY29uZmlnIENMS19UV0w2MDQwDQo+ICAJICBNY1BE
TS4gTWNQRE0gbW9kdWxlIGlzIHVzaW5nIHRoZSBleHRlcm5hbCBiaXQgY2xvY2sgb24gdGhlIE1j
UERNDQo+IGJ1cw0KPiAgCSAgYXMgZnVuY3Rpb25hbCBjbG9jay4NCj4gDQo+ICtjb25maWcgQ0xL
X1BQQ19DT1JFTkVUDQo+ICsJYm9vbCAiQ2xvY2sgZHJpdmVyIGZvciBQb3dlclBDIGNvcmVuZXQg
cGxhdGZvcm1zIg0KPiArCWRlcGVuZHMgb24gUFBDX0U1MDBNQyAmJiBPRg0KPiArCS0tLWhlbHAt
LS0NCj4gKwkgIFRoaXMgYWRkcyB0aGUgY2xvY2sgZHJpdmVyIHN1cHBvcnQgZm9yIEZyZWVzY2Fs
ZSBQb3dlclBDIGNvcmVuZXQNCj4gKwkgIHBsYXRmb3JtcyB1c2luZyBjb21tb24gY2xvY2sgZnJh
bWV3b3JrLg0KPiArDQo+ICBlbmRtZW51DQo+IA0KPiAgc291cmNlICJkcml2ZXJzL2Nsay9tdmVi
dS9LY29uZmlnIg0KPiBkaWZmIC0tZ2l0IGEvZHJpdmVycy9jbGsvTWFrZWZpbGUgYi9kcml2ZXJz
L2Nsay9NYWtlZmlsZSBpbmRleA0KPiAzMDBkNDc3Li42NzIwMzE5IDEwMDY0NA0KPiAtLS0gYS9k
cml2ZXJzL2Nsay9NYWtlZmlsZQ0KPiArKysgYi9kcml2ZXJzL2Nsay9NYWtlZmlsZQ0KPiBAQCAt
MzQsMyArMzQsNCBAQCBvYmotJChDT05GSUdfWDg2KQkJKz0geDg2Lw0KPiAgb2JqLSQoQ09ORklH
X0NPTU1PTl9DTEtfV004MzFYKSArPSBjbGstd204MzF4Lm8NCj4gIG9iai0kKENPTkZJR19DT01N
T05fQ0xLX01BWDc3Njg2KSArPSBjbGstbWF4Nzc2ODYubw0KPiAgb2JqLSQoQ09ORklHX0NMS19U
V0w2MDQwKQkrPSBjbGstdHdsNjA0MC5vDQo+ICtvYmotJChDT05GSUdfQ0xLX1BQQ19DT1JFTkVU
KQkrPSBjbGstcHBjLWNvcmVuZXQubw0KPiBkaWZmIC0tZ2l0IGEvZHJpdmVycy9jbGsvY2xrLXBw
Yy1jb3JlbmV0LmMgYi9kcml2ZXJzL2Nsay9jbGstcHBjLQ0KPiBjb3JlbmV0LmMgbmV3IGZpbGUg
bW9kZSAxMDA2NDQgaW5kZXggMDAwMDAwMC4uYTJkNDgzZg0KPiAtLS0gL2Rldi9udWxsDQo+ICsr
KyBiL2RyaXZlcnMvY2xrL2Nsay1wcGMtY29yZW5ldC5jDQo+IEBAIC0wLDAgKzEsMjgwIEBADQo+
ICsvKg0KPiArICogQ29weXJpZ2h0IDIwMTMgRnJlZXNjYWxlIFNlbWljb25kdWN0b3IsIEluYy4N
Cj4gKyAqDQo+ICsgKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRp
c3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeQ0KPiArICogaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRo
ZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSB2ZXJzaW9uIDIgYXMNCj4gKyAqIHB1Ymxpc2hl
ZCBieSB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLg0KPiArICoNCj4gKyAqIGNsb2NrIGRy
aXZlciBmb3IgRnJlZXNjYWxlIFBvd2VyUEMgY29yZW5ldCBTb0NzLg0KPiArICovDQo+ICsjaW5j
bHVkZSA8bGludXgvY2xrLXByb3ZpZGVyLmg+DQo+ICsjaW5jbHVkZSA8bGludXgvaW8uaD4NCj4g
KyNpbmNsdWRlIDxsaW51eC9rZXJuZWwuaD4NCj4gKyNpbmNsdWRlIDxsaW51eC9tb2R1bGUuaD4N
Cj4gKyNpbmNsdWRlIDxsaW51eC9vZl9wbGF0Zm9ybS5oPg0KPiArI2luY2x1ZGUgPGxpbnV4L29m
Lmg+DQo+ICsjaW5jbHVkZSA8bGludXgvc2xhYi5oPg0KPiArDQo+ICtzdHJ1Y3QgY211eF9jbGsg
ew0KPiArCXN0cnVjdCBjbGtfaHcgaHc7DQo+ICsJdm9pZCBfX2lvbWVtICpyZWc7DQo+ICsJdTMy
IGZsYWdzOw0KPiArfTsNCj4gKw0KPiArI2RlZmluZSBQTExfS0lMTAkJCUJJVCgzMSkNCj4gKyNk
ZWZpbmUJQ0xLU0VMX1NISUZUCQkyNw0KPiArI2RlZmluZSBDTEtTRUxfQURKVVNUCQlCSVQoMCkN
Cj4gKyNkZWZpbmUgdG9fY211eF9jbGsocCkJCWNvbnRhaW5lcl9vZihwLCBzdHJ1Y3QgY211eF9j
bGssIGh3KQ0KPiArDQo+ICtzdGF0aWMgdm9pZCBfX2lvbWVtICpiYXNlOw0KPiArc3RhdGljIHVu
c2lnbmVkIGludCBjbG9ja3NfcGVyX3BsbDsNCj4gKw0KPiArc3RhdGljIGludCBjbXV4X3NldF9w
YXJlbnQoc3RydWN0IGNsa19odyAqaHcsIHU4IGlkeCkgew0KPiArCXN0cnVjdCBjbXV4X2NsayAq
Y2xrID0gdG9fY211eF9jbGsoaHcpOw0KPiArCXUzMiBjbGtzZWw7DQo+ICsNCj4gKwljbGtzZWwg
PSAoKGlkeCAvIGNsb2Nrc19wZXJfcGxsKSA8PCAyKSArIGlkeCAlIGNsb2Nrc19wZXJfcGxsOw0K
PiArCWlmIChjbGstPmZsYWdzICYgQ0xLU0VMX0FESlVTVCkNCj4gKwkJY2xrc2VsICs9IDg7DQo+
ICsJY2xrc2VsID0gKGNsa3NlbCAmIDB4ZikgPDwgQ0xLU0VMX1NISUZUOw0KPiArCWlvd3JpdGUz
MmJlKGNsa3NlbCwgY2xrLT5yZWcpOw0KPiArDQo+ICsJcmV0dXJuIDA7DQo+ICt9DQo+ICsNCj4g
K3N0YXRpYyB1OCBjbXV4X2dldF9wYXJlbnQoc3RydWN0IGNsa19odyAqaHcpIHsNCj4gKwlzdHJ1
Y3QgY211eF9jbGsgKmNsayA9IHRvX2NtdXhfY2xrKGh3KTsNCj4gKwl1MzIgY2xrc2VsOw0KPiAr
DQo+ICsJY2xrc2VsID0gaW9yZWFkMzJiZShjbGstPnJlZyk7DQo+ICsJY2xrc2VsID0gKGNsa3Nl
bCA+PiBDTEtTRUxfU0hJRlQpICYgMHhmOw0KPiArCWlmIChjbGstPmZsYWdzICYgQ0xLU0VMX0FE
SlVTVCkNCj4gKwkJY2xrc2VsIC09IDg7DQo+ICsJY2xrc2VsID0gKGNsa3NlbCA+PiAyKSAqIGNs
b2Nrc19wZXJfcGxsICsgY2xrc2VsICUgNDsNCj4gKw0KPiArCXJldHVybiBjbGtzZWw7DQo+ICt9
DQo+ICsNCj4gK2NvbnN0IHN0cnVjdCBjbGtfb3BzIGNtdXhfb3BzID0gew0KPiArCS5nZXRfcGFy
ZW50ID0gY211eF9nZXRfcGFyZW50LA0KPiArCS5zZXRfcGFyZW50ID0gY211eF9zZXRfcGFyZW50
LA0KPiArfTsNCj4gKw0KPiArc3RhdGljIHZvaWQgX19pbml0IGNvcmVfbXV4X2luaXQoc3RydWN0
IGRldmljZV9ub2RlICpucCkgew0KPiArCXN0cnVjdCBjbGsgKmNsazsNCj4gKwlzdHJ1Y3QgY2xr
X2luaXRfZGF0YSBpbml0Ow0KPiArCXN0cnVjdCBjbXV4X2NsayAqY211eF9jbGs7DQo+ICsJc3Ry
dWN0IGRldmljZV9ub2RlICpub2RlOw0KPiArCWludCByYywgY291bnQsIGk7DQo+ICsJdTMyCW9m
ZnNldDsNCj4gKwljb25zdCBjaGFyICpjbGtfbmFtZTsNCj4gKwljb25zdCBjaGFyICoqcGFyZW50
X25hbWVzOw0KPiArDQo+ICsJcmMgPSBvZl9wcm9wZXJ0eV9yZWFkX3UzMihucCwgInJlZyIsICZv
ZmZzZXQpOw0KPiArCWlmIChyYykgew0KPiArCQlwcl9lcnIoIiVzOiBjb3VsZCBub3QgZ2V0IHJl
ZyBwcm9wZXJ0eVxuIiwgbnAtPm5hbWUpOw0KPiArCQlyZXR1cm47DQo+ICsJfQ0KPiArDQo+ICsJ
LyogZ2V0IHRoZSBpbnB1dCBjbG9jayBzb3VyY2UgY291bnQgKi8NCj4gKwljb3VudCA9IG9mX3By
b3BlcnR5X2NvdW50X3N0cmluZ3MobnAsICJjbG9jay1uYW1lcyIpOw0KPiArCWlmIChjb3VudCA8
IDApIHsNCj4gKwkJcHJfZXJyKCIlczogZ2V0IGNsb2NrIGNvdW50IGVycm9yXG4iLCBucC0+bmFt
ZSk7DQo+ICsJCXJldHVybjsNCj4gKwl9DQo+ICsJcGFyZW50X25hbWVzID0ga3phbGxvYygoc2l6
ZW9mKGNoYXIgKikgKiBjb3VudCksIEdGUF9LRVJORUwpOw0KPiArCWlmICghcGFyZW50X25hbWVz
KSB7DQo+ICsJCXByX2VycigiJXM6IGNvdWxkIG5vdCBhbGxvY2F0ZSBwYXJlbnRfbmFtZXNcbiIs
IF9fZnVuY19fKTsNCj4gKwkJcmV0dXJuOw0KPiArCX0NCj4gKw0KPiArCWZvciAoaSA9IDA7IGkg
PCBjb3VudDsgaSsrKQ0KPiArCQlwYXJlbnRfbmFtZXNbaV0gPSBvZl9jbGtfZ2V0X3BhcmVudF9u
YW1lKG5wLCBpKTsNCj4gKw0KPiArCWNtdXhfY2xrID0ga3phbGxvYyhzaXplb2Yoc3RydWN0IGNt
dXhfY2xrKSwgR0ZQX0tFUk5FTCk7DQo+ICsJaWYgKCFjbXV4X2Nsaykgew0KPiArCQlwcl9lcnIo
IiVzOiBjb3VsZCBub3QgYWxsb2NhdGUgY211eF9jbGtcbiIsIF9fZnVuY19fKTsNCj4gKwkJZ290
byBlcnJfbmFtZTsNCj4gKwl9DQo+ICsJY211eF9jbGstPnJlZyA9IGJhc2UgKyBvZmZzZXQ7DQo+
ICsNCj4gKwlub2RlID0gb2ZfZmluZF9jb21wYXRpYmxlX25vZGUoTlVMTCwgTlVMTCwgImZzbCxw
NDA4MC1jbG9ja2dlbiIpOw0KPiArCWlmIChub2RlICYmIChvZmZzZXQgPj0gMHg4MCkpDQo+ICsJ
CWNtdXhfY2xrLT5mbGFncyA9IENMS1NFTF9BREpVU1Q7DQo+ICsNCj4gKwlyYyA9IG9mX3Byb3Bl
cnR5X3JlYWRfc3RyaW5nX2luZGV4KG5wLCAiY2xvY2stb3V0cHV0LW5hbWVzIiwNCj4gKwkJCTAs
ICZjbGtfbmFtZSk7DQo+ICsJaWYgKHJjKSB7DQo+ICsJCXByX2VycigiJXM6IHJlYWQgY2xvY2sg
bmFtZXMgZXJyb3JcbiIsIG5wLT5uYW1lKTsNCj4gKwkJZ290byBlcnJfY2xrOw0KPiArCX0NCj4g
Kw0KPiArCWluaXQubmFtZSA9IGNsa19uYW1lOw0KPiArCWluaXQub3BzID0gJmNtdXhfb3BzOw0K
PiArCWluaXQucGFyZW50X25hbWVzID0gcGFyZW50X25hbWVzOw0KPiArCWluaXQubnVtX3BhcmVu
dHMgPSBjb3VudDsNCj4gKwlpbml0LmZsYWdzID0gMDsNCj4gKwljbXV4X2Nsay0+aHcuaW5pdCA9
ICZpbml0Ow0KPiArDQo+ICsJY2xrID0gY2xrX3JlZ2lzdGVyKE5VTEwsICZjbXV4X2Nsay0+aHcp
Ow0KPiArCWlmIChJU19FUlIoY2xrKSkgew0KPiArCQlwcl9lcnIoIiVzOiBjb3VsZCBub3QgcmVn
aXN0ZXIgY2xvY2tcbiIsIGNsa19uYW1lKTsNCj4gKwkJZ290byBlcnJfY2xrOw0KPiArCX0NCj4g
Kw0KPiArCXJjID0gb2ZfY2xrX2FkZF9wcm92aWRlcihucCwgb2ZfY2xrX3NyY19zaW1wbGVfZ2V0
LCBjbGspOw0KPiArCWlmIChyYykgew0KPiArCQlwcl9lcnIoIkNvdWxkIG5vdCByZWdpc3RlciBj
bG9jayBwcm92aWRlciBmb3Igbm9kZTolc1xuIiwNCj4gKwkJCSBucC0+bmFtZSk7DQo+ICsJCWdv
dG8gZXJyX2NsazsNCj4gKwl9DQo+ICsJZ290byBlcnJfbmFtZTsNCj4gKw0KPiArZXJyX2NsazoN
Cj4gKwlrZnJlZShjbXV4X2Nsayk7DQo+ICtlcnJfbmFtZToNCj4gKwkvKiBmcmVlICpfbmFtZXMg
YmVjYXVzZSB0aGV5IGFyZSByZWFsbG9jYXRlZCB3aGVuIHJlZ2lzdGVyZWQgKi8NCj4gKwlrZnJl
ZShwYXJlbnRfbmFtZXMpOw0KPiArfQ0KPiArDQo+ICtzdGF0aWMgdm9pZCBfX2luaXQgY29yZV9w
bGxfaW5pdChzdHJ1Y3QgZGV2aWNlX25vZGUgKm5wKSB7DQo+ICsJdTMyIG9mZnNldCwgbXVsdDsN
Cj4gKwlpbnQgaSwgcmMsIGNvdW50Ow0KPiArCWNvbnN0IGNoYXIgKmNsa19uYW1lLCAqcGFyZW50
X25hbWU7DQo+ICsJc3RydWN0IGNsa19vbmVjZWxsX2RhdGEgKm9uZWNlbGxfZGF0YTsNCj4gKwlz
dHJ1Y3QgY2xrICAgICAgKipzdWJjbGtzOw0KPiArDQo+ICsJcmMgPSBvZl9wcm9wZXJ0eV9yZWFk
X3UzMihucCwgInJlZyIsICZvZmZzZXQpOw0KPiArCWlmIChyYykgew0KPiArCQlwcl9lcnIoIiVz
OiBjb3VsZCBub3QgZ2V0IHJlZyBwcm9wZXJ0eVxuIiwgbnAtPm5hbWUpOw0KPiArCQlyZXR1cm47
DQo+ICsJfQ0KPiArDQo+ICsJLyogZ2V0IHRoZSBtdWx0aXBsZSBvZiBQTEwgKi8NCj4gKwltdWx0
ID0gaW9yZWFkMzJiZShiYXNlICsgb2Zmc2V0KTsNCj4gKw0KPiArCS8qIGNoZWNrIGlmIHRoaXMg
UExMIGlzIGRpc2FibGVkICovDQo+ICsJaWYgKG11bHQgJiBQTExfS0lMTCkgew0KPiArCQlwcl9k
ZWJ1ZygiUExMOiVzIGlzIGRpc2FibGVkXG4iLCBucC0+bmFtZSk7DQo+ICsJCXJldHVybjsNCj4g
Kwl9DQo+ICsJbXVsdCA9IChtdWx0ID4+IDEpICYgMHgzZjsNCj4gKw0KPiArCXBhcmVudF9uYW1l
ID0gb2ZfY2xrX2dldF9wYXJlbnRfbmFtZShucCwgMCk7DQo+ICsJaWYgKCFwYXJlbnRfbmFtZSkg
ew0KPiArCQlwcl9lcnIoIlBMTDogJXMgbXVzdCBoYXZlIGEgcGFyZW50XG4iLCBucC0+bmFtZSk7
DQo+ICsJCXJldHVybjsNCj4gKwl9DQo+ICsNCj4gKwljb3VudCA9IG9mX3Byb3BlcnR5X2NvdW50
X3N0cmluZ3MobnAsICJjbG9jay1vdXRwdXQtbmFtZXMiKTsNCj4gKwlpZiAoY291bnQgPCAwIHx8
IGNvdW50ID4gNCkgew0KPiArCQlwcl9lcnIoIiVzOiBjbG9jayBpcyBub3Qgc3VwcG9ydGVkXG4i
LCBucC0+bmFtZSk7DQo+ICsJCXJldHVybjsNCj4gKwl9DQo+ICsNCj4gKwkvKiBvdXRwdXQgY2xv
Y2sgbnVtYmVyIHBlciBQTEwgKi8NCj4gKwljbG9ja3NfcGVyX3BsbCA9IGNvdW50Ow0KPiArDQo+
ICsJc3ViY2xrcyA9IGt6YWxsb2Moc2l6ZW9mKHN0cnVjdCBjbGsgKikgKiBjb3VudCwgR0ZQX0tF
Uk5FTCk7DQo+ICsJaWYgKCFzdWJjbGtzKSB7DQo+ICsJCXByX2VycigiJXM6IGNvdWxkIG5vdCBh
bGxvY2F0ZSBzdWJjbGtzXG4iLCBfX2Z1bmNfXyk7DQo+ICsJCXJldHVybjsNCj4gKwl9DQo+ICsN
Cj4gKwlvbmVjZWxsX2RhdGEgPSBremFsbG9jKHNpemVvZihzdHJ1Y3QgY2xrX29uZWNlbGxfZGF0
YSksIEdGUF9LRVJORUwpOw0KPiArCWlmICghb25lY2VsbF9kYXRhKSB7DQo+ICsJCXByX2Vycigi
JXM6IGNvdWxkIG5vdCBhbGxvY2F0ZSBvbmVjZWxsX2RhdGFcbiIsIF9fZnVuY19fKTsNCj4gKwkJ
Z290byBlcnJfY2xrczsNCj4gKwl9DQo+ICsNCj4gKwlmb3IgKGkgPSAwOyBpIDwgY291bnQ7IGkr
Kykgew0KPiArCQlyYyA9IG9mX3Byb3BlcnR5X3JlYWRfc3RyaW5nX2luZGV4KG5wLCAiY2xvY2st
b3V0cHV0LW5hbWVzIiwNCj4gKwkJCQlpLCAmY2xrX25hbWUpOw0KPiArCQlpZiAocmMpIHsNCj4g
KwkJCXByX2VycigiJXM6IGNvdWxkIG5vdCBnZXQgY2xvY2sgbmFtZXNcbiIsIG5wLT5uYW1lKTsN
Cj4gKwkJCWdvdG8gZXJyX2NlbGw7DQo+ICsJCX0NCj4gKw0KPiArCQkvKg0KPiArCQkgKiB3aGVu
IGNvdW50ID09IDQsIHRoZXJlIGFyZSA0IG91dHB1dCBjbG9ja3M6DQo+ICsJCSAqIC8xLCAvMiwg
LzMsIC80IHJlc3BlY3RpdmVseQ0KPiArCQkgKiB3aGVuIGNvdW50IDwgNCwgdGhlcmUgYXJlIGF0
IGxlYXN0IDIgb3V0cHV0IGNsb2NrczoNCj4gKwkJICogLzEsIC8yLCAoLzQsIGlmIGNvdW50ID09
IDMpIHJlc3BlY3RpdmVseS4NCj4gKwkJICovDQo+ICsJCWlmIChjb3VudCA9PSA0KQ0KPiArCQkJ
c3ViY2xrc1tpXSA9IGNsa19yZWdpc3Rlcl9maXhlZF9mYWN0b3IoTlVMTCwgY2xrX25hbWUsDQo+
ICsJCQkJCXBhcmVudF9uYW1lLCAwLCBtdWx0LCAxICsgaSk7DQo+ICsJCWVsc2UNCj4gKw0KPiAr
CQkJc3ViY2xrc1tpXSA9IGNsa19yZWdpc3Rlcl9maXhlZF9mYWN0b3IoTlVMTCwgY2xrX25hbWUs
DQo+ICsJCQkJCXBhcmVudF9uYW1lLCAwLCBtdWx0LCAxIDw8IGkpOw0KPiArDQo+ICsJCWlmIChJ
U19FUlIoc3ViY2xrc1tpXSkpIHsNCj4gKwkJCXByX2VycigiJXM6IGNvdWxkIG5vdCByZWdpc3Rl
ciBjbG9ja1xuIiwgY2xrX25hbWUpOw0KPiArCQkJZ290byBlcnJfY2VsbDsNCj4gKwkJfQ0KPiAr
CX0NCj4gKw0KPiArCW9uZWNlbGxfZGF0YS0+Y2xrcyA9IHN1YmNsa3M7DQo+ICsJb25lY2VsbF9k
YXRhLT5jbGtfbnVtID0gY291bnQ7DQo+ICsNCj4gKwlyYyA9IG9mX2Nsa19hZGRfcHJvdmlkZXIo
bnAsIG9mX2Nsa19zcmNfb25lY2VsbF9nZXQsIG9uZWNlbGxfZGF0YSk7DQo+ICsJaWYgKHJjKSB7
DQo+ICsJCXByX2VycigiQ291bGQgbm90IHJlZ2lzdGVyIGNsayBwcm92aWRlciBmb3Igbm9kZTol
c1xuIiwNCj4gKwkJCSBucC0+bmFtZSk7DQo+ICsJCWdvdG8gZXJyX2NlbGw7DQo+ICsJfQ0KPiAr
DQo+ICsJcmV0dXJuOw0KPiArZXJyX2NlbGw6DQo+ICsJa2ZyZWUob25lY2VsbF9kYXRhKTsNCj4g
K2Vycl9jbGtzOg0KPiArCWtmcmVlKHN1YmNsa3MpOw0KPiArfQ0KPiArDQo+ICtzdGF0aWMgY29u
c3Qgc3RydWN0IG9mX2RldmljZV9pZCBjbGtfbWF0Y2hbXSBfX2luaXRjb25zdCA9IHsNCj4gKwl7
IC5jb21wYXRpYmxlID0gImZpeGVkLWNsb2NrIiwgLmRhdGEgPSBvZl9maXhlZF9jbGtfc2V0dXAs
IH0sDQo+ICsJeyAuY29tcGF0aWJsZSA9ICJmc2wsY29yZS1wbGwtY2xvY2siLCAuZGF0YSA9IGNv
cmVfcGxsX2luaXQsIH0sDQo+ICsJeyAuY29tcGF0aWJsZSA9ICJmc2wsY29yZS1tdXgtY2xvY2si
LCAuZGF0YSA9IGNvcmVfbXV4X2luaXQsIH0sDQo+ICsJe30NCj4gK307DQo+ICsNCj4gK3N0YXRp
YyBpbnQgX19pbml0IHBwY19jb3JlbmV0X2Nsa19wcm9iZShzdHJ1Y3QgcGxhdGZvcm1fZGV2aWNl
ICpwZGV2KSB7DQo+ICsJc3RydWN0IGRldmljZV9ub2RlICpucDsNCj4gKw0KPiArCW5wID0gcGRl
di0+ZGV2Lm9mX25vZGU7DQo+ICsJYmFzZSA9IG9mX2lvbWFwKG5wLCAwKTsNCj4gKwlpZiAoIWJh
c2UpIHsNCj4gKwkJZGV2X2VycigmcGRldi0+ZGV2LCAiaW9tYXAgZXJyb3JcbiIpOw0KPiArCQly
ZXR1cm4gLUVOT01FTTsNCj4gKwl9DQo+ICsJb2ZfY2xrX2luaXQoY2xrX21hdGNoKTsNCj4gKw0K
PiArCXJldHVybiAwOw0KPiArfQ0KPiArDQo+ICtzdGF0aWMgY29uc3Qgc3RydWN0IG9mX2Rldmlj
ZV9pZCBwcGNfY2xrX2lkc1tdIF9faW5pdGNvbnN0ID0gew0KPiArCXsgLmNvbXBhdGlibGUgPSAi
ZnNsLHFvcmlxLWNsb2NrZ2VuLTEuMCIsIH0sDQo+ICsJeyAuY29tcGF0aWJsZSA9ICJmc2wscW9y
aXEtY2xvY2tnZW4tMiIsIH0sDQo+ICsJe30NCj4gK307DQo+ICsNCj4gK3N0YXRpYyBzdHJ1Y3Qg
cGxhdGZvcm1fZHJpdmVyIHBwY19jb3JlbmV0X2Nsa19kcml2ZXIgPSB7DQo+ICsJLmRyaXZlciA9
IHsNCj4gKwkJLm5hbWUgPSAicHBjX2NvcmVuZXRfY2xvY2siLA0KPiArCQkub3duZXIgPSBUSElT
X01PRFVMRSwNCj4gKwkJLm9mX21hdGNoX3RhYmxlID0gcHBjX2Nsa19pZHMsDQo+ICsJfSwNCj4g
KwkucHJvYmUgPSBwcGNfY29yZW5ldF9jbGtfcHJvYmUsDQo+ICt9Ow0KPiArDQo+ICtzdGF0aWMg
aW50IF9faW5pdCBwcGNfY29yZW5ldF9jbGtfaW5pdCh2b2lkKSB7DQo+ICsJcmV0dXJuIHBsYXRm
b3JtX2RyaXZlcl9yZWdpc3RlcigmcHBjX2NvcmVuZXRfY2xrX2RyaXZlcik7DQo+ICt9DQo+ICtz
dWJzeXNfaW5pdGNhbGwocHBjX2NvcmVuZXRfY2xrX2luaXQpOw0KPiAtLQ0KPiAxLjguMA0KDQo=

^ permalink raw reply

* Re: [PATCH 4/8] Read/Write oops nvram partition via pstore
From: Benjamin Herrenschmidt @ 2013-04-16  7:14 UTC (permalink / raw)
  To: Aruna Balakrishnaiah
  Cc: jkenisto, mahesh, linux-kernel, linuxppc-dev, paulus, anton
In-Reply-To: <516CEDB4.9090005@linux.vnet.ibm.com>

On Tue, 2013-04-16 at 11:50 +0530, Aruna Balakrishnaiah wrote:
> 
> Sure. I will have one #ifdef for declarations and one for function
> definitions.

Declarations generally don't need #ifdef's

Cheers,
Ben.
 

^ permalink raw reply

* Re: [PATCH 4/8] Read/Write oops nvram partition via pstore
From: Aruna Balakrishnaiah @ 2013-04-16  7:59 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: jkenisto, mahesh, linux-kernel, linuxppc-dev, paulus, anton
In-Reply-To: <1366096475.24994.50.camel@pasglop>

On Tuesday 16 April 2013 12:44 PM, Benjamin Herrenschmidt wrote:
> On Tue, 2013-04-16 at 11:50 +0530, Aruna Balakrishnaiah wrote:
>> Sure. I will have one #ifdef for declarations and one for function
>> definitions.
> Declarations generally don't need #ifdef's

Sorry by declarations I meant variable declarations (used by pstore) not function
declarations.

> Cheers,
> Ben.
>
>

^ permalink raw reply

* [git pull] Please pull one last set of fixes for powerpc for v3.9
From: Stephen Rothwell @ 2013-04-16  8:08 UTC (permalink / raw)
  To: Linus; +Cc: Michael Neuling, Kevin Hao, Tiejun Chen, Alistair Popple, ppc-dev

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

Hi Linus,

The following changes since commit e8f2b548de7ae65e17ee911e54712a3f26f69c60:

  Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs (2013-04-09 12:22:49 -0700)

are available in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/sfr/next-fixes.git tags/for-linus

for you to fetch changes up to d8b92292408831d86ff7b781e66bf79301934b99:

  powerpc: add a missing label in resume_kernel (2013-04-15 17:29:48 +1000)

----------------------------------------------------------------
Three regresions in the PowerPC code.  One from v3.7 the others from
this merge window.

Please pull - thanks a lot.

----------------------------------------------------------------
Alistair Popple (1):
      powerpc: Fix audit crash due to save/restore PPR changes

Kevin Hao (1):
      powerpc: add a missing label in resume_kernel

Michael Neuling (1):
      powerpc: fix compiling CONFIG_PPC_TRANSACTIONAL_MEM when CONFIG_ALTIVEC=n

 arch/powerpc/kernel/entry_64.S  | 4 ++--
 arch/powerpc/kernel/process.c   | 2 ++
 arch/powerpc/kernel/signal_32.c | 2 ++
 arch/powerpc/kernel/signal_64.c | 2 ++
 arch/powerpc/kernel/tm.S        | 2 ++
 5 files changed, 10 insertions(+), 2 deletions(-)

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

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

^ permalink raw reply

* Re: [PATCH 1/2] powerpc: remove section changes from _GLOBAL() and friends
From: Michael Ellerman @ 2013-04-16  8:33 UTC (permalink / raw)
  To: Stephen Rothwell; +Cc: Alan Modra, ppc-dev
In-Reply-To: <20130416021747.a9608ca92eb68495493e061b@canb.auug.org.au>

On Tue, Apr 16, 2013 at 02:17:47AM +1000, Stephen Rothwell wrote:
> Hi Michael,
> 
> On Mon, 15 Apr 2013 23:30:40 +1000 Stephen Rothwell <sfr@canb.auug.org.au> wrote:
> >
> > On Mon, 15 Apr 2013 22:00:17 +1000 Michael Ellerman <michael@ellerman.id.au> wrote:
> > >
> > > On Thu, Nov 29, 2012 at 10:55:25AM +1100, Stephen Rothwell wrote:
> > > > These sometimes produce unexpected results and make it hard to put the
> > > > start up code (for 64 bit) into the .head.text section.
> > > 
> > > ...
> > > 
> > > > diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S
> > > > index 6f62a73..4ec5625 100644
> > > > --- a/arch/powerpc/kernel/head_fsl_booke.S
> > > > +++ b/arch/powerpc/kernel/head_fsl_booke.S
> > > > @@ -776,6 +776,8 @@ tlb_write_entry:
> > > >  	mfspr	r10, SPRN_SPRG_RSCRATCH0
> > > >  	rfi					/* Force context change */
> > > >  
> > > > +	,text
> > > > +
> > > 
> > > I'm assuming this should be .text ?
> > 
> > Indeed.  Oops :-)
> 
> BTW, those patches are almost certainly stale by now and would need to be
> redone before be included on the kernel proper.

Now you tell me. It's in my tree, and building, but potentially missing
some .text annotations I guess. I'll rip it out until you send me a new
version.

cheers

^ permalink raw reply

* [PATCH v7 0/3] of/pci: Provide common support for PCI DT parsing
From: Andrew Murray @ 2013-04-16 10:18 UTC (permalink / raw)
  To: linux-mips, linuxppc-dev
  Cc: siva.kallam, linux-pci, linus.walleij, thierry.reding,
	Liviu.Dudau, paulus, linux-samsung-soc, linux, jg1.han,
	jgunthorpe, thomas.abraham, arnd, devicetree-discuss, rob.herring,
	kgene.kim, bhelgaas, linux-arm-kernel, thomas.petazzoni, monstr,
	linux-kernel, suren.reddy, Andrew Murray

This patchset factors out duplicated code associated with parsing PCI
DT "ranges" properties across the architectures and introduces a
"ranges" parser. This parser "of_pci_range_parser" can be used directly
by ARM host bridge drivers enabling them to obtain ranges from device
trees.

I've included the Reviewed-by and Tested-by's received from v5/v6 in this
patchset, earlier versions of this patchset (v3) have been tested-by:

Thierry Reding <thierry.reding@avionic-design.de>
Jingoo Han <jg1.han@samsung.com>

I've tested that this patchset builds and runs on ARM and that it builds on
PowerPC and x86_64.

Compared to the v6 sent by Andrew Murray, the following changes have
been made in response to build errors/warnings:

 * Inclusion of linux/of_address.h in of_pci.c as suggested by Michal
   Simek to prevent compilation failures on Microblaze (and others) and his
   ack.

 * Use of externs, static inlines and a typo in linux/of_address.h in response
   to linker errors (multiple defination) on x86_64 as spotted by a kbuild test
   robot on (jcooper/linux.git mvebu/drivers)

 * Add EXPORT_SYMBOL_GPL to of_pci_range_parser function to be consistent
   with of_pci_process_ranges function

Compared to the v5 sent by Andrew Murray, the following changes have
been made:

 * Use of CONFIG_64BIT instead of CONFIG_[a32bitarch] as suggested by
   Rob Herring in drivers/of/of_pci.c

 * Added forward declaration of struct pci_controller in linux/of_pci.h
   to prevent compiler warning as suggested by Thomas Petazzoni

 * Improved error checking (!range check), removal of unnecessary be32_to_cpup
   call, improved formatting of struct of_pci_range_parser layout and
   replacement of macro with a static inline. All suggested by Rob Herring.

Compared to the v4 (incorrectly labelled v3) sent by Andrew Murray,
the following changes have been made:

 * Split the patch as suggested by Rob Herring

Compared to the v3 sent by Andrew Murray, the following changes have
been made:

 * Unify and move duplicate pci_process_bridge_OF_ranges functions to
   drivers/of/of_pci.c as suggested by Rob Herring

 * Fix potential build errors with Microblaze/MIPS

Compared to "[PATCH v5 01/17] of/pci: Provide support for parsing PCI DT
ranges property", the following changes have been made:

 * Correct use of IORESOURCE_* as suggested by Russell King

 * Improved interface and naming as suggested by Thierry Reding

Compared to the v2 sent by Andrew Murray, Thomas Petazzoni did:

 * Add a memset() on the struct of_pci_range_iter when starting the
   for loop in for_each_pci_range(). Otherwise, with an uninitialized
   of_pci_range_iter, of_pci_process_ranges() may crash.

 * Add parenthesis around 'res', 'np' and 'iter' in the
   for_each_of_pci_range macro definitions. Otherwise, passing
   something like &foobar as 'res' didn't work.

 * Rebased on top of 3.9-rc2, which required fixing a few conflicts in
   the Microblaze code.

v2:
  This follows on from suggestions made by Grant Likely
  (marc.info/?l=linux-kernel&m=136079602806328)

Andrew Murray (3):
  of/pci: Unify pci_process_bridge_OF_ranges from Microblaze and
    PowerPC
  of/pci: Provide support for parsing PCI DT ranges property
  of/pci: mips: convert to common of_pci_range_parser

 arch/microblaze/include/asm/pci-bridge.h |    5 +-
 arch/microblaze/pci/pci-common.c         |  192 ------------------------------
 arch/mips/pci/pci.c                      |   50 +++------
 arch/powerpc/include/asm/pci-bridge.h    |    5 +-
 arch/powerpc/kernel/pci-common.c         |  192 ------------------------------
 drivers/of/address.c                     |   67 +++++++++++
 drivers/of/of_pci.c                      |  169 ++++++++++++++++++++++++++
 include/linux/of_address.h               |   46 +++++++
 include/linux/of_pci.h                   |    4 +
 9 files changed, 304 insertions(+), 426 deletions(-)

^ permalink raw reply

* [PATCH v7 1/3] of/pci: Unify pci_process_bridge_OF_ranges from Microblaze and PowerPC
From: Andrew Murray @ 2013-04-16 10:18 UTC (permalink / raw)
  To: linux-mips, linuxppc-dev
  Cc: siva.kallam, linux-pci, linus.walleij, thierry.reding,
	Liviu.Dudau, paulus, linux-samsung-soc, linux, jg1.han,
	jgunthorpe, thomas.abraham, arnd, devicetree-discuss, rob.herring,
	kgene.kim, bhelgaas, linux-arm-kernel, thomas.petazzoni, monstr,
	linux-kernel, suren.reddy, Andrew Murray
In-Reply-To: <1366107508-12672-1-git-send-email-Andrew.Murray@arm.com>

The pci_process_bridge_OF_ranges function, used to parse the "ranges"
property of a PCI host device, is found in both Microblaze and PowerPC
architectures. These implementations are nearly identical. This patch
moves this common code to a common place.

Signed-off-by: Andrew Murray <Andrew.Murray@arm.com>
Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
Reviewed-by: Rob Herring <rob.herring@calxeda.com>
Tested-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Tested-by: Linus Walleij <linus.walleij@linaro.org>
Acked-by: Michal Simek <monstr@monstr.eu>
---
 arch/microblaze/include/asm/pci-bridge.h |    5 +-
 arch/microblaze/pci/pci-common.c         |  192 ----------------------------
 arch/powerpc/include/asm/pci-bridge.h    |    5 +-
 arch/powerpc/kernel/pci-common.c         |  192 ----------------------------
 drivers/of/of_pci.c                      |  200 ++++++++++++++++++++++++++++++
 include/linux/of_pci.h                   |    4 +
 6 files changed, 206 insertions(+), 392 deletions(-)

diff --git a/arch/microblaze/include/asm/pci-bridge.h b/arch/microblaze/include/asm/pci-bridge.h
index cb5d397..5783cd6 100644
--- a/arch/microblaze/include/asm/pci-bridge.h
+++ b/arch/microblaze/include/asm/pci-bridge.h
@@ -10,6 +10,7 @@
 #include <linux/pci.h>
 #include <linux/list.h>
 #include <linux/ioport.h>
+#include <linux/of_pci.h>
 
 struct device_node;
 
@@ -132,10 +133,6 @@ extern void setup_indirect_pci(struct pci_controller *hose,
 extern struct pci_controller *pci_find_hose_for_OF_device(
 			struct device_node *node);
 
-/* Fill up host controller resources from the OF node */
-extern void pci_process_bridge_OF_ranges(struct pci_controller *hose,
-			struct device_node *dev, int primary);
-
 /* Allocate & free a PCI host bridge structure */
 extern struct pci_controller *pcibios_alloc_controller(struct device_node *dev);
 extern void pcibios_free_controller(struct pci_controller *phb);
diff --git a/arch/microblaze/pci/pci-common.c b/arch/microblaze/pci/pci-common.c
index 9ea521e..2735ad9 100644
--- a/arch/microblaze/pci/pci-common.c
+++ b/arch/microblaze/pci/pci-common.c
@@ -622,198 +622,6 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar,
 	*end = rsrc->end - offset;
 }
 
-/**
- * pci_process_bridge_OF_ranges - Parse PCI bridge resources from device tree
- * @hose: newly allocated pci_controller to be setup
- * @dev: device node of the host bridge
- * @primary: set if primary bus (32 bits only, soon to be deprecated)
- *
- * This function will parse the "ranges" property of a PCI host bridge device
- * node and setup the resource mapping of a pci controller based on its
- * content.
- *
- * Life would be boring if it wasn't for a few issues that we have to deal
- * with here:
- *
- *   - We can only cope with one IO space range and up to 3 Memory space
- *     ranges. However, some machines (thanks Apple !) tend to split their
- *     space into lots of small contiguous ranges. So we have to coalesce.
- *
- *   - We can only cope with all memory ranges having the same offset
- *     between CPU addresses and PCI addresses. Unfortunately, some bridges
- *     are setup for a large 1:1 mapping along with a small "window" which
- *     maps PCI address 0 to some arbitrary high address of the CPU space in
- *     order to give access to the ISA memory hole.
- *     The way out of here that I've chosen for now is to always set the
- *     offset based on the first resource found, then override it if we
- *     have a different offset and the previous was set by an ISA hole.
- *
- *   - Some busses have IO space not starting at 0, which causes trouble with
- *     the way we do our IO resource renumbering. The code somewhat deals with
- *     it for 64 bits but I would expect problems on 32 bits.
- *
- *   - Some 32 bits platforms such as 4xx can have physical space larger than
- *     32 bits so we need to use 64 bits values for the parsing
- */
-void pci_process_bridge_OF_ranges(struct pci_controller *hose,
-				  struct device_node *dev, int primary)
-{
-	const u32 *ranges;
-	int rlen;
-	int pna = of_n_addr_cells(dev);
-	int np = pna + 5;
-	int memno = 0, isa_hole = -1;
-	u32 pci_space;
-	unsigned long long pci_addr, cpu_addr, pci_next, cpu_next, size;
-	unsigned long long isa_mb = 0;
-	struct resource *res;
-
-	pr_info("PCI host bridge %s %s ranges:\n",
-	       dev->full_name, primary ? "(primary)" : "");
-
-	/* Get ranges property */
-	ranges = of_get_property(dev, "ranges", &rlen);
-	if (ranges == NULL)
-		return;
-
-	/* Parse it */
-	pr_debug("Parsing ranges property...\n");
-	while ((rlen -= np * 4) >= 0) {
-		/* Read next ranges element */
-		pci_space = ranges[0];
-		pci_addr = of_read_number(ranges + 1, 2);
-		cpu_addr = of_translate_address(dev, ranges + 3);
-		size = of_read_number(ranges + pna + 3, 2);
-
-		pr_debug("pci_space: 0x%08x pci_addr:0x%016llx ",
-				pci_space, pci_addr);
-		pr_debug("cpu_addr:0x%016llx size:0x%016llx\n",
-					cpu_addr, size);
-
-		ranges += np;
-
-		/* If we failed translation or got a zero-sized region
-		 * (some FW try to feed us with non sensical zero sized regions
-		 * such as power3 which look like some kind of attempt
-		 * at exposing the VGA memory hole)
-		 */
-		if (cpu_addr == OF_BAD_ADDR || size == 0)
-			continue;
-
-		/* Now consume following elements while they are contiguous */
-		for (; rlen >= np * sizeof(u32);
-		     ranges += np, rlen -= np * 4) {
-			if (ranges[0] != pci_space)
-				break;
-			pci_next = of_read_number(ranges + 1, 2);
-			cpu_next = of_translate_address(dev, ranges + 3);
-			if (pci_next != pci_addr + size ||
-			    cpu_next != cpu_addr + size)
-				break;
-			size += of_read_number(ranges + pna + 3, 2);
-		}
-
-		/* Act based on address space type */
-		res = NULL;
-		switch ((pci_space >> 24) & 0x3) {
-		case 1:		/* PCI IO space */
-			pr_info("  IO 0x%016llx..0x%016llx -> 0x%016llx\n",
-			       cpu_addr, cpu_addr + size - 1, pci_addr);
-
-			/* We support only one IO range */
-			if (hose->pci_io_size) {
-				pr_info(" \\--> Skipped (too many) !\n");
-				continue;
-			}
-			/* On 32 bits, limit I/O space to 16MB */
-			if (size > 0x01000000)
-				size = 0x01000000;
-
-			/* 32 bits needs to map IOs here */
-			hose->io_base_virt = ioremap(cpu_addr, size);
-
-			/* Expect trouble if pci_addr is not 0 */
-			if (primary)
-				isa_io_base =
-					(unsigned long)hose->io_base_virt;
-			/* pci_io_size and io_base_phys always represent IO
-			 * space starting at 0 so we factor in pci_addr
-			 */
-			hose->pci_io_size = pci_addr + size;
-			hose->io_base_phys = cpu_addr - pci_addr;
-
-			/* Build resource */
-			res = &hose->io_resource;
-			res->flags = IORESOURCE_IO;
-			res->start = pci_addr;
-			break;
-		case 2:		/* PCI Memory space */
-		case 3:		/* PCI 64 bits Memory space */
-			pr_info(" MEM 0x%016llx..0x%016llx -> 0x%016llx %s\n",
-			       cpu_addr, cpu_addr + size - 1, pci_addr,
-			       (pci_space & 0x40000000) ? "Prefetch" : "");
-
-			/* We support only 3 memory ranges */
-			if (memno >= 3) {
-				pr_info(" \\--> Skipped (too many) !\n");
-				continue;
-			}
-			/* Handles ISA memory hole space here */
-			if (pci_addr == 0) {
-				isa_mb = cpu_addr;
-				isa_hole = memno;
-				if (primary || isa_mem_base == 0)
-					isa_mem_base = cpu_addr;
-				hose->isa_mem_phys = cpu_addr;
-				hose->isa_mem_size = size;
-			}
-
-			/* We get the PCI/Mem offset from the first range or
-			 * the, current one if the offset came from an ISA
-			 * hole. If they don't match, bugger.
-			 */
-			if (memno == 0 ||
-			    (isa_hole >= 0 && pci_addr != 0 &&
-			     hose->pci_mem_offset == isa_mb))
-				hose->pci_mem_offset = cpu_addr - pci_addr;
-			else if (pci_addr != 0 &&
-				 hose->pci_mem_offset != cpu_addr - pci_addr) {
-				pr_info(" \\--> Skipped (offset mismatch) !\n");
-				continue;
-			}
-
-			/* Build resource */
-			res = &hose->mem_resources[memno++];
-			res->flags = IORESOURCE_MEM;
-			if (pci_space & 0x40000000)
-				res->flags |= IORESOURCE_PREFETCH;
-			res->start = cpu_addr;
-			break;
-		}
-		if (res != NULL) {
-			res->name = dev->full_name;
-			res->end = res->start + size - 1;
-			res->parent = NULL;
-			res->sibling = NULL;
-			res->child = NULL;
-		}
-	}
-
-	/* If there's an ISA hole and the pci_mem_offset is -not- matching
-	 * the ISA hole offset, then we need to remove the ISA hole from
-	 * the resource list for that brige
-	 */
-	if (isa_hole >= 0 && hose->pci_mem_offset != isa_mb) {
-		unsigned int next = isa_hole + 1;
-		pr_info(" Removing ISA hole at 0x%016llx\n", isa_mb);
-		if (next < memno)
-			memmove(&hose->mem_resources[isa_hole],
-				&hose->mem_resources[next],
-				sizeof(struct resource) * (memno - next));
-		hose->mem_resources[--memno].flags = 0;
-	}
-}
-
 /* Decide whether to display the domain number in /proc */
 int pci_proc_domain(struct pci_bus *bus)
 {
diff --git a/arch/powerpc/include/asm/pci-bridge.h b/arch/powerpc/include/asm/pci-bridge.h
index 025a130..205bfba 100644
--- a/arch/powerpc/include/asm/pci-bridge.h
+++ b/arch/powerpc/include/asm/pci-bridge.h
@@ -10,6 +10,7 @@
 #include <linux/pci.h>
 #include <linux/list.h>
 #include <linux/ioport.h>
+#include <linux/of_pci.h>
 #include <asm-generic/pci-bridge.h>
 
 struct device_node;
@@ -231,10 +232,6 @@ extern int pcibios_map_io_space(struct pci_bus *bus);
 extern struct pci_controller *pci_find_hose_for_OF_device(
 			struct device_node* node);
 
-/* Fill up host controller resources from the OF node */
-extern void pci_process_bridge_OF_ranges(struct pci_controller *hose,
-			struct device_node *dev, int primary);
-
 /* Allocate & free a PCI host bridge structure */
 extern struct pci_controller *pcibios_alloc_controller(struct device_node *dev);
 extern void pcibios_free_controller(struct pci_controller *phb);
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index fa12ae4..6edf396 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -640,198 +640,6 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar,
 	*end = rsrc->end - offset;
 }
 
-/**
- * pci_process_bridge_OF_ranges - Parse PCI bridge resources from device tree
- * @hose: newly allocated pci_controller to be setup
- * @dev: device node of the host bridge
- * @primary: set if primary bus (32 bits only, soon to be deprecated)
- *
- * This function will parse the "ranges" property of a PCI host bridge device
- * node and setup the resource mapping of a pci controller based on its
- * content.
- *
- * Life would be boring if it wasn't for a few issues that we have to deal
- * with here:
- *
- *   - We can only cope with one IO space range and up to 3 Memory space
- *     ranges. However, some machines (thanks Apple !) tend to split their
- *     space into lots of small contiguous ranges. So we have to coalesce.
- *
- *   - We can only cope with all memory ranges having the same offset
- *     between CPU addresses and PCI addresses. Unfortunately, some bridges
- *     are setup for a large 1:1 mapping along with a small "window" which
- *     maps PCI address 0 to some arbitrary high address of the CPU space in
- *     order to give access to the ISA memory hole.
- *     The way out of here that I've chosen for now is to always set the
- *     offset based on the first resource found, then override it if we
- *     have a different offset and the previous was set by an ISA hole.
- *
- *   - Some busses have IO space not starting at 0, which causes trouble with
- *     the way we do our IO resource renumbering. The code somewhat deals with
- *     it for 64 bits but I would expect problems on 32 bits.
- *
- *   - Some 32 bits platforms such as 4xx can have physical space larger than
- *     32 bits so we need to use 64 bits values for the parsing
- */
-void pci_process_bridge_OF_ranges(struct pci_controller *hose,
-				  struct device_node *dev, int primary)
-{
-	const u32 *ranges;
-	int rlen;
-	int pna = of_n_addr_cells(dev);
-	int np = pna + 5;
-	int memno = 0, isa_hole = -1;
-	u32 pci_space;
-	unsigned long long pci_addr, cpu_addr, pci_next, cpu_next, size;
-	unsigned long long isa_mb = 0;
-	struct resource *res;
-
-	printk(KERN_INFO "PCI host bridge %s %s ranges:\n",
-	       dev->full_name, primary ? "(primary)" : "");
-
-	/* Get ranges property */
-	ranges = of_get_property(dev, "ranges", &rlen);
-	if (ranges == NULL)
-		return;
-
-	/* Parse it */
-	while ((rlen -= np * 4) >= 0) {
-		/* Read next ranges element */
-		pci_space = ranges[0];
-		pci_addr = of_read_number(ranges + 1, 2);
-		cpu_addr = of_translate_address(dev, ranges + 3);
-		size = of_read_number(ranges + pna + 3, 2);
-		ranges += np;
-
-		/* If we failed translation or got a zero-sized region
-		 * (some FW try to feed us with non sensical zero sized regions
-		 * such as power3 which look like some kind of attempt at exposing
-		 * the VGA memory hole)
-		 */
-		if (cpu_addr == OF_BAD_ADDR || size == 0)
-			continue;
-
-		/* Now consume following elements while they are contiguous */
-		for (; rlen >= np * sizeof(u32);
-		     ranges += np, rlen -= np * 4) {
-			if (ranges[0] != pci_space)
-				break;
-			pci_next = of_read_number(ranges + 1, 2);
-			cpu_next = of_translate_address(dev, ranges + 3);
-			if (pci_next != pci_addr + size ||
-			    cpu_next != cpu_addr + size)
-				break;
-			size += of_read_number(ranges + pna + 3, 2);
-		}
-
-		/* Act based on address space type */
-		res = NULL;
-		switch ((pci_space >> 24) & 0x3) {
-		case 1:		/* PCI IO space */
-			printk(KERN_INFO
-			       "  IO 0x%016llx..0x%016llx -> 0x%016llx\n",
-			       cpu_addr, cpu_addr + size - 1, pci_addr);
-
-			/* We support only one IO range */
-			if (hose->pci_io_size) {
-				printk(KERN_INFO
-				       " \\--> Skipped (too many) !\n");
-				continue;
-			}
-#ifdef CONFIG_PPC32
-			/* On 32 bits, limit I/O space to 16MB */
-			if (size > 0x01000000)
-				size = 0x01000000;
-
-			/* 32 bits needs to map IOs here */
-			hose->io_base_virt = ioremap(cpu_addr, size);
-
-			/* Expect trouble if pci_addr is not 0 */
-			if (primary)
-				isa_io_base =
-					(unsigned long)hose->io_base_virt;
-#endif /* CONFIG_PPC32 */
-			/* pci_io_size and io_base_phys always represent IO
-			 * space starting at 0 so we factor in pci_addr
-			 */
-			hose->pci_io_size = pci_addr + size;
-			hose->io_base_phys = cpu_addr - pci_addr;
-
-			/* Build resource */
-			res = &hose->io_resource;
-			res->flags = IORESOURCE_IO;
-			res->start = pci_addr;
-			break;
-		case 2:		/* PCI Memory space */
-		case 3:		/* PCI 64 bits Memory space */
-			printk(KERN_INFO
-			       " MEM 0x%016llx..0x%016llx -> 0x%016llx %s\n",
-			       cpu_addr, cpu_addr + size - 1, pci_addr,
-			       (pci_space & 0x40000000) ? "Prefetch" : "");
-
-			/* We support only 3 memory ranges */
-			if (memno >= 3) {
-				printk(KERN_INFO
-				       " \\--> Skipped (too many) !\n");
-				continue;
-			}
-			/* Handles ISA memory hole space here */
-			if (pci_addr == 0) {
-				isa_mb = cpu_addr;
-				isa_hole = memno;
-				if (primary || isa_mem_base == 0)
-					isa_mem_base = cpu_addr;
-				hose->isa_mem_phys = cpu_addr;
-				hose->isa_mem_size = size;
-			}
-
-			/* We get the PCI/Mem offset from the first range or
-			 * the, current one if the offset came from an ISA
-			 * hole. If they don't match, bugger.
-			 */
-			if (memno == 0 ||
-			    (isa_hole >= 0 && pci_addr != 0 &&
-			     hose->pci_mem_offset == isa_mb))
-				hose->pci_mem_offset = cpu_addr - pci_addr;
-			else if (pci_addr != 0 &&
-				 hose->pci_mem_offset != cpu_addr - pci_addr) {
-				printk(KERN_INFO
-				       " \\--> Skipped (offset mismatch) !\n");
-				continue;
-			}
-
-			/* Build resource */
-			res = &hose->mem_resources[memno++];
-			res->flags = IORESOURCE_MEM;
-			if (pci_space & 0x40000000)
-				res->flags |= IORESOURCE_PREFETCH;
-			res->start = cpu_addr;
-			break;
-		}
-		if (res != NULL) {
-			res->name = dev->full_name;
-			res->end = res->start + size - 1;
-			res->parent = NULL;
-			res->sibling = NULL;
-			res->child = NULL;
-		}
-	}
-
-	/* If there's an ISA hole and the pci_mem_offset is -not- matching
-	 * the ISA hole offset, then we need to remove the ISA hole from
-	 * the resource list for that brige
-	 */
-	if (isa_hole >= 0 && hose->pci_mem_offset != isa_mb) {
-		unsigned int next = isa_hole + 1;
-		printk(KERN_INFO " Removing ISA hole at 0x%016llx\n", isa_mb);
-		if (next < memno)
-			memmove(&hose->mem_resources[isa_hole],
-				&hose->mem_resources[next],
-				sizeof(struct resource) * (memno - next));
-		hose->mem_resources[--memno].flags = 0;
-	}
-}
-
 /* Decide whether to display the domain number in /proc */
 int pci_proc_domain(struct pci_bus *bus)
 {
diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c
index 13e37e2..1626172 100644
--- a/drivers/of/of_pci.c
+++ b/drivers/of/of_pci.c
@@ -4,6 +4,10 @@
 #include <linux/of_pci.h>
 #include <asm/prom.h>
 
+#if defined(CONFIG_PPC32) || defined(CONFIG_PPC64) || defined(CONFIG_MICROBLAZE)
+#include <asm/pci-bridge.h>
+#endif
+
 static inline int __of_pci_pci_compare(struct device_node *node,
 				       unsigned int devfn)
 {
@@ -40,3 +44,199 @@ struct device_node *of_pci_find_child_device(struct device_node *parent,
 	return NULL;
 }
 EXPORT_SYMBOL_GPL(of_pci_find_child_device);
+
+/**
+ * pci_process_bridge_OF_ranges - Parse PCI bridge resources from device tree
+ * @hose: newly allocated pci_controller to be setup
+ * @dev: device node of the host bridge
+ * @primary: set if primary bus (32 bits only, soon to be deprecated)
+ *
+ * This function will parse the "ranges" property of a PCI host bridge device
+ * node and setup the resource mapping of a pci controller based on its
+ * content.
+ *
+ * Life would be boring if it wasn't for a few issues that we have to deal
+ * with here:
+ *
+ *   - We can only cope with one IO space range and up to 3 Memory space
+ *     ranges. However, some machines (thanks Apple !) tend to split their
+ *     space into lots of small contiguous ranges. So we have to coalesce.
+ *
+ *   - We can only cope with all memory ranges having the same offset
+ *     between CPU addresses and PCI addresses. Unfortunately, some bridges
+ *     are setup for a large 1:1 mapping along with a small "window" which
+ *     maps PCI address 0 to some arbitrary high address of the CPU space in
+ *     order to give access to the ISA memory hole.
+ *     The way out of here that I've chosen for now is to always set the
+ *     offset based on the first resource found, then override it if we
+ *     have a different offset and the previous was set by an ISA hole.
+ *
+ *   - Some busses have IO space not starting at 0, which causes trouble with
+ *     the way we do our IO resource renumbering. The code somewhat deals with
+ *     it for 64 bits but I would expect problems on 32 bits.
+ *
+ *   - Some 32 bits platforms such as 4xx can have physical space larger than
+ *     32 bits so we need to use 64 bits values for the parsing
+ */
+#if defined(CONFIG_PPC32) || defined(CONFIG_PPC64) || defined(CONFIG_MICROBLAZE)
+void pci_process_bridge_OF_ranges(struct pci_controller *hose,
+				  struct device_node *dev, int primary)
+{
+	const u32 *ranges;
+	int rlen;
+	int pna = of_n_addr_cells(dev);
+	int np = pna + 5;
+	int memno = 0, isa_hole = -1;
+	u32 pci_space;
+	unsigned long long pci_addr, cpu_addr, pci_next, cpu_next, size;
+	unsigned long long isa_mb = 0;
+	struct resource *res;
+
+	pr_info("PCI host bridge %s %s ranges:\n",
+	       dev->full_name, primary ? "(primary)" : "");
+
+	/* Get ranges property */
+	ranges = of_get_property(dev, "ranges", &rlen);
+	if (ranges == NULL)
+		return;
+
+	/* Parse it */
+	pr_debug("Parsing ranges property...\n");
+	while ((rlen -= np * 4) >= 0) {
+		/* Read next ranges element */
+		pci_space = ranges[0];
+		pci_addr = of_read_number(ranges + 1, 2);
+		cpu_addr = of_translate_address(dev, ranges + 3);
+		size = of_read_number(ranges + pna + 3, 2);
+
+		pr_debug("pci_space: 0x%08x pci_addr:0x%016llx ",
+				pci_space, pci_addr);
+		pr_debug("cpu_addr:0x%016llx size:0x%016llx\n",
+					cpu_addr, size);
+
+		ranges += np;
+
+		/* If we failed translation or got a zero-sized region
+		 * (some FW try to feed us with non sensical zero sized regions
+		 * such as power3 which look like some kind of attempt
+		 * at exposing the VGA memory hole)
+		 */
+		if (cpu_addr == OF_BAD_ADDR || size == 0)
+			continue;
+
+		/* Now consume following elements while they are contiguous */
+		for (; rlen >= np * sizeof(u32);
+		     ranges += np, rlen -= np * 4) {
+			if (ranges[0] != pci_space)
+				break;
+			pci_next = of_read_number(ranges + 1, 2);
+			cpu_next = of_translate_address(dev, ranges + 3);
+			if (pci_next != pci_addr + size ||
+			    cpu_next != cpu_addr + size)
+				break;
+			size += of_read_number(ranges + pna + 3, 2);
+		}
+
+		/* Act based on address space type */
+		res = NULL;
+		switch ((pci_space >> 24) & 0x3) {
+		case 1:		/* PCI IO space */
+			pr_info("  IO 0x%016llx..0x%016llx -> 0x%016llx\n",
+			       cpu_addr, cpu_addr + size - 1, pci_addr);
+
+			/* We support only one IO range */
+			if (hose->pci_io_size) {
+				pr_info(" \\--> Skipped (too many) !\n");
+				continue;
+			}
+#if (!IS_ENABLED(CONFIG_64BIT))
+			/* On 32 bits, limit I/O space to 16MB */
+			if (size > 0x01000000)
+				size = 0x01000000;
+
+			/* 32 bits needs to map IOs here */
+			hose->io_base_virt = ioremap(cpu_addr, size);
+
+			/* Expect trouble if pci_addr is not 0 */
+			if (primary)
+				isa_io_base =
+					(unsigned long)hose->io_base_virt;
+#endif /* !CONFIG_64BIT */
+			/* pci_io_size and io_base_phys always represent IO
+			 * space starting at 0 so we factor in pci_addr
+			 */
+			hose->pci_io_size = pci_addr + size;
+			hose->io_base_phys = cpu_addr - pci_addr;
+
+			/* Build resource */
+			res = &hose->io_resource;
+			res->flags = IORESOURCE_IO;
+			res->start = pci_addr;
+			break;
+		case 2:		/* PCI Memory space */
+		case 3:		/* PCI 64 bits Memory space */
+			pr_info(" MEM 0x%016llx..0x%016llx -> 0x%016llx %s\n",
+			       cpu_addr, cpu_addr + size - 1, pci_addr,
+			       (pci_space & 0x40000000) ? "Prefetch" : "");
+
+			/* We support only 3 memory ranges */
+			if (memno >= 3) {
+				pr_info(" \\--> Skipped (too many) !\n");
+				continue;
+			}
+			/* Handles ISA memory hole space here */
+			if (pci_addr == 0) {
+				isa_mb = cpu_addr;
+				isa_hole = memno;
+				if (primary || isa_mem_base == 0)
+					isa_mem_base = cpu_addr;
+				hose->isa_mem_phys = cpu_addr;
+				hose->isa_mem_size = size;
+			}
+
+			/* We get the PCI/Mem offset from the first range or
+			 * the, current one if the offset came from an ISA
+			 * hole. If they don't match, bugger.
+			 */
+			if (memno == 0 ||
+			    (isa_hole >= 0 && pci_addr != 0 &&
+			     hose->pci_mem_offset == isa_mb))
+				hose->pci_mem_offset = cpu_addr - pci_addr;
+			else if (pci_addr != 0 &&
+				 hose->pci_mem_offset != cpu_addr - pci_addr) {
+				pr_info(" \\--> Skipped (offset mismatch) !\n");
+				continue;
+			}
+
+			/* Build resource */
+			res = &hose->mem_resources[memno++];
+			res->flags = IORESOURCE_MEM;
+			if (pci_space & 0x40000000)
+				res->flags |= IORESOURCE_PREFETCH;
+			res->start = cpu_addr;
+			break;
+		}
+		if (res != NULL) {
+			res->name = dev->full_name;
+			res->end = res->start + size - 1;
+			res->parent = NULL;
+			res->sibling = NULL;
+			res->child = NULL;
+		}
+	}
+
+	/* If there's an ISA hole and the pci_mem_offset is -not- matching
+	 * the ISA hole offset, then we need to remove the ISA hole from
+	 * the resource list for that brige
+	 */
+	if (isa_hole >= 0 && hose->pci_mem_offset != isa_mb) {
+		unsigned int next = isa_hole + 1;
+		pr_info(" Removing ISA hole at 0x%016llx\n", isa_mb);
+		if (next < memno)
+			memmove(&hose->mem_resources[isa_hole],
+				&hose->mem_resources[next],
+				sizeof(struct resource) * (memno - next));
+		hose->mem_resources[--memno].flags = 0;
+	}
+}
+#endif
diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h
index bb115de..33e8ead 100644
--- a/include/linux/of_pci.h
+++ b/include/linux/of_pci.h
@@ -11,4 +11,8 @@ struct device_node;
 struct device_node *of_pci_find_child_device(struct device_node *parent,
 					     unsigned int devfn);
 
+struct pci_controller;
+void pci_process_bridge_OF_ranges(struct pci_controller *hose,
+			struct device_node *dev, int primary);
+
 #endif
-- 
1.7.0.4

^ permalink raw reply related

* [PATCH v7 2/3] of/pci: Provide support for parsing PCI DT ranges property
From: Andrew Murray @ 2013-04-16 10:18 UTC (permalink / raw)
  To: linux-mips, linuxppc-dev
  Cc: siva.kallam, linux-pci, linus.walleij, thierry.reding,
	Liviu.Dudau, paulus, linux-samsung-soc, linux, jg1.han,
	jgunthorpe, thomas.abraham, arnd, devicetree-discuss, rob.herring,
	kgene.kim, bhelgaas, linux-arm-kernel, thomas.petazzoni, monstr,
	linux-kernel, suren.reddy, Andrew Murray
In-Reply-To: <1366107508-12672-1-git-send-email-Andrew.Murray@arm.com>

This patch factors out common implementation patterns to reduce overall kernel
code and provide a means for host bridge drivers to directly obtain struct
resources from the DT's ranges property without relying on architecture specific
DT handling. This will make it easier to write archiecture independent host bridge
drivers and mitigate against further duplication of DT parsing code.

This patch can be used in the following way:

	struct of_pci_range_parser parser;
	struct of_pci_range range;

	if (of_pci_range_parser(&parser, np))
		; //no ranges property

	for_each_of_pci_range(&parser, &range) {

		/*
			directly access properties of the address range, e.g.:
			range.pci_space, range.pci_addr, range.cpu_addr,
			range.size, range.flags

			alternatively obtain a struct resource, e.g.:
			struct resource res;
			of_pci_range_to_resource(&range, np, &res);
		*/
	}

Additionally the implementation takes care of adjacent ranges and merges them
into a single range (as was the case with powerpc and microblaze).

Signed-off-by: Andrew Murray <Andrew.Murray@arm.com>
Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Reviewed-by: Rob Herring <rob.herring@calxeda.com>
Tested-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Tested-by: Linus Walleij <linus.walleij@linaro.org>
---
 drivers/of/address.c       |   67 ++++++++++++++++++++++++++
 drivers/of/of_pci.c        |  113 ++++++++++++++++----------------------------
 include/linux/of_address.h |   46 ++++++++++++++++++
 3 files changed, 154 insertions(+), 72 deletions(-)

diff --git a/drivers/of/address.c b/drivers/of/address.c
index 04da786..6eec70c 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -227,6 +227,73 @@ int of_pci_address_to_resource(struct device_node *dev, int bar,
 	return __of_address_to_resource(dev, addrp, size, flags, NULL, r);
 }
 EXPORT_SYMBOL_GPL(of_pci_address_to_resource);
+
+int of_pci_range_parser(struct of_pci_range_parser *parser,
+			struct device_node *node)
+{
+	const int na = 3, ns = 2;
+	int rlen;
+
+	parser->node = node;
+	parser->pna = of_n_addr_cells(node);
+	parser->np = parser->pna + na + ns;
+
+	parser->range = of_get_property(node, "ranges", &rlen);
+	if (parser->range == NULL)
+		return -ENOENT;
+
+	parser->end = parser->range + rlen / sizeof(__be32);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(of_pci_range_parser);
+
+struct of_pci_range *of_pci_process_ranges(struct of_pci_range_parser *parser,
+						struct of_pci_range *range)
+{
+	const int na = 3, ns = 2;
+
+	if (!range)
+		return NULL;
+
+	if (!parser->range || parser->range + parser->np > parser->end)
+		return NULL;
+
+	range->pci_space = parser->range[0];
+	range->flags = of_bus_pci_get_flags(parser->range);
+	range->pci_addr = of_read_number(parser->range + 1, ns);
+	range->cpu_addr = of_translate_address(parser->node,
+				parser->range + na);
+	range->size = of_read_number(parser->range + parser->pna + na, ns);
+
+	parser->range += parser->np;
+
+	/* Now consume following elements while they are contiguous */
+	while (parser->range + parser->np <= parser->end) {
+		u32 flags, pci_space;
+		u64 pci_addr, cpu_addr, size;
+
+		pci_space = be32_to_cpup(parser->range);
+		flags = of_bus_pci_get_flags(parser->range);
+		pci_addr = of_read_number(parser->range + 1, ns);
+		cpu_addr = of_translate_address(parser->node,
+				parser->range + na);
+		size = of_read_number(parser->range + parser->pna + na, ns);
+
+		if (flags != range->flags)
+			break;
+		if (pci_addr != range->pci_addr + range->size ||
+		    cpu_addr != range->cpu_addr + range->size)
+			break;
+
+		range->size += size;
+		parser->range += parser->np;
+	}
+
+	return range;
+}
+EXPORT_SYMBOL_GPL(of_pci_process_ranges);
+
 #endif /* CONFIG_PCI */
 
 /*
diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c
index 1626172..e5ab604 100644
--- a/drivers/of/of_pci.c
+++ b/drivers/of/of_pci.c
@@ -2,6 +2,7 @@
 #include <linux/export.h>
 #include <linux/of.h>
 #include <linux/of_pci.h>
+#include <linux/of_address.h>
 #include <asm/prom.h>
 
 #if defined(CONFIG_PPC32) || defined(CONFIG_PPC64) || defined(CONFIG_MICROBLAZE)
@@ -82,67 +83,43 @@ EXPORT_SYMBOL_GPL(of_pci_find_child_device);
 void pci_process_bridge_OF_ranges(struct pci_controller *hose,
 				  struct device_node *dev, int primary)
 {
-	const u32 *ranges;
-	int rlen;
-	int pna = of_n_addr_cells(dev);
-	int np = pna + 5;
 	int memno = 0, isa_hole = -1;
-	u32 pci_space;
-	unsigned long long pci_addr, cpu_addr, pci_next, cpu_next, size;
 	unsigned long long isa_mb = 0;
 	struct resource *res;
+	struct of_pci_range range;
+	struct of_pci_range_parser parser;
+	u32 res_type;
 
 	pr_info("PCI host bridge %s %s ranges:\n",
 	       dev->full_name, primary ? "(primary)" : "");
 
-	/* Get ranges property */
-	ranges = of_get_property(dev, "ranges", &rlen);
-	if (ranges == NULL)
+	/* Check for ranges property */
+	if (of_pci_range_parser(&parser, dev))
 		return;
 
-	/* Parse it */
 	pr_debug("Parsing ranges property...\n");
-	while ((rlen -= np * 4) >= 0) {
+	for_each_of_pci_range(&parser, &range) {
 		/* Read next ranges element */
-		pci_space = ranges[0];
-		pci_addr = of_read_number(ranges + 1, 2);
-		cpu_addr = of_translate_address(dev, ranges + 3);
-		size = of_read_number(ranges + pna + 3, 2);
-
-		pr_debug("pci_space: 0x%08x pci_addr:0x%016llx ",
-				pci_space, pci_addr);
-		pr_debug("cpu_addr:0x%016llx size:0x%016llx\n",
-					cpu_addr, size);
-
-		ranges += np;
+		pr_debug("pci_space: 0x%08x pci_addr: 0x%016llx ",
+				range.pci_space, range.pci_addr);
+		pr_debug("cpu_addr: 0x%016llx size: 0x%016llx\n",
+				range.cpu_addr, range.size);
 
 		/* If we failed translation or got a zero-sized region
 		 * (some FW try to feed us with non sensical zero sized regions
 		 * such as power3 which look like some kind of attempt
 		 * at exposing the VGA memory hole)
 		 */
-		if (cpu_addr == OF_BAD_ADDR || size == 0)
+		if (range.cpu_addr == OF_BAD_ADDR || range.size == 0)
 			continue;
 
-		/* Now consume following elements while they are contiguous */
-		for (; rlen >= np * sizeof(u32);
-		     ranges += np, rlen -= np * 4) {
-			if (ranges[0] != pci_space)
-				break;
-			pci_next = of_read_number(ranges + 1, 2);
-			cpu_next = of_translate_address(dev, ranges + 3);
-			if (pci_next != pci_addr + size ||
-			    cpu_next != cpu_addr + size)
-				break;
-			size += of_read_number(ranges + pna + 3, 2);
-		}
-
 		/* Act based on address space type */
 		res = NULL;
-		switch ((pci_space >> 24) & 0x3) {
-		case 1:		/* PCI IO space */
+		res_type = range.flags & IORESOURCE_TYPE_BITS;
+		if (res_type == IORESOURCE_IO) {
 			pr_info("  IO 0x%016llx..0x%016llx -> 0x%016llx\n",
-			       cpu_addr, cpu_addr + size - 1, pci_addr);
+				range.cpu_addr, range.cpu_addr + range.size - 1,
+				range.pci_addr);
 
 			/* We support only one IO range */
 			if (hose->pci_io_size) {
@@ -151,11 +128,12 @@ void pci_process_bridge_OF_ranges(struct pci_controller *hose,
 			}
 #if (!IS_ENABLED(CONFIG_64BIT))
 			/* On 32 bits, limit I/O space to 16MB */
-			if (size > 0x01000000)
-				size = 0x01000000;
+			if (range.size > 0x01000000)
+				range.size = 0x01000000;
 
 			/* 32 bits needs to map IOs here */
-			hose->io_base_virt = ioremap(cpu_addr, size);
+			hose->io_base_virt = ioremap(range.cpu_addr,
+						range.size);
 
 			/* Expect trouble if pci_addr is not 0 */
 			if (primary)
@@ -165,19 +143,18 @@ void pci_process_bridge_OF_ranges(struct pci_controller *hose,
 			/* pci_io_size and io_base_phys always represent IO
 			 * space starting at 0 so we factor in pci_addr
 			 */
-			hose->pci_io_size = pci_addr + size;
-			hose->io_base_phys = cpu_addr - pci_addr;
+			hose->pci_io_size = range.pci_addr + range.size;
+			hose->io_base_phys = range.cpu_addr - range.pci_addr;
 
 			/* Build resource */
 			res = &hose->io_resource;
-			res->flags = IORESOURCE_IO;
-			res->start = pci_addr;
-			break;
-		case 2:		/* PCI Memory space */
-		case 3:		/* PCI 64 bits Memory space */
+			range.cpu_addr = range.pci_addr;
+		} else if (res_type == IORESOURCE_MEM) {
 			pr_info(" MEM 0x%016llx..0x%016llx -> 0x%016llx %s\n",
-			       cpu_addr, cpu_addr + size - 1, pci_addr,
-			       (pci_space & 0x40000000) ? "Prefetch" : "");
+				range.cpu_addr, range.cpu_addr + range.size - 1,
+				range.pci_addr,
+				(range.pci_space & 0x40000000) ?
+				"Prefetch" : "");
 
 			/* We support only 3 memory ranges */
 			if (memno >= 3) {
@@ -185,13 +162,13 @@ void pci_process_bridge_OF_ranges(struct pci_controller *hose,
 				continue;
 			}
 			/* Handles ISA memory hole space here */
-			if (pci_addr == 0) {
-				isa_mb = cpu_addr;
+			if (range.pci_addr == 0) {
+				isa_mb = range.cpu_addr;
 				isa_hole = memno;
 				if (primary || isa_mem_base == 0)
-					isa_mem_base = cpu_addr;
-				hose->isa_mem_phys = cpu_addr;
-				hose->isa_mem_size = size;
+					isa_mem_base = range.cpu_addr;
+				hose->isa_mem_phys = range.cpu_addr;
+				hose->isa_mem_size = range.size;
 			}
 
 			/* We get the PCI/Mem offset from the first range or
@@ -199,30 +176,22 @@ void pci_process_bridge_OF_ranges(struct pci_controller *hose,
 			 * hole. If they don't match, bugger.
 			 */
 			if (memno == 0 ||
-			    (isa_hole >= 0 && pci_addr != 0 &&
+			(isa_hole >= 0 && range.pci_addr != 0 &&
 			     hose->pci_mem_offset == isa_mb))
-				hose->pci_mem_offset = cpu_addr - pci_addr;
-			else if (pci_addr != 0 &&
-				 hose->pci_mem_offset != cpu_addr - pci_addr) {
+				hose->pci_mem_offset = range.cpu_addr -
+							range.pci_addr;
+			else if (range.pci_addr != 0 &&
+				hose->pci_mem_offset != range.cpu_addr -
+							range.pci_addr) {
 				pr_info(" \\--> Skipped (offset mismatch) !\n");
 				continue;
 			}
 
 			/* Build resource */
 			res = &hose->mem_resources[memno++];
-			res->flags = IORESOURCE_MEM;
-			if (pci_space & 0x40000000)
-				res->flags |= IORESOURCE_PREFETCH;
-			res->start = cpu_addr;
-			break;
-		}
-		if (res != NULL) {
-			res->name = dev->full_name;
-			res->end = res->start + size - 1;
-			res->parent = NULL;
-			res->sibling = NULL;
-			res->child = NULL;
 		}
+		if (res != NULL)
+			of_pci_range_to_resource(&range, dev, res);
 	}
 
 	/* If there's an ISA hole and the pci_mem_offset is -not- matching
diff --git a/include/linux/of_address.h b/include/linux/of_address.h
index 0506eb5..1cfb779 100644
--- a/include/linux/of_address.h
+++ b/include/linux/of_address.h
@@ -4,6 +4,36 @@
 #include <linux/errno.h>
 #include <linux/of.h>
 
+struct of_pci_range_parser {
+	struct device_node *node;
+	const __be32 *range;
+	const __be32 *end;
+	int np;
+	int pna;
+};
+
+struct of_pci_range {
+	u32 pci_space;
+	u64 pci_addr;
+	u64 cpu_addr;
+	u64 size;
+	u32 flags;
+};
+
+#define for_each_of_pci_range(parser, range) \
+	for (; of_pci_process_ranges(parser, range);)
+
+static inline void of_pci_range_to_resource(struct of_pci_range *range,
+					    struct device_node *np,
+					    struct resource *res)
+{
+	res->flags = range->flags;
+	res->start = range->cpu_addr;
+	res->end = range->cpu_addr + range->size - 1;
+	res->parent = res->child = res->sibling = NULL;
+	res->name = np->full_name;
+}
+
 #ifdef CONFIG_OF_ADDRESS
 extern u64 of_translate_address(struct device_node *np, const __be32 *addr);
 extern bool of_can_translate_address(struct device_node *dev);
@@ -27,6 +57,10 @@ static inline unsigned long pci_address_to_pio(phys_addr_t addr) { return -1; }
 #define pci_address_to_pio pci_address_to_pio
 #endif
 
+extern int of_pci_range_parser(struct of_pci_range_parser *parser,
+			struct device_node *node);
+extern struct of_pci_range *of_pci_process_ranges(struct of_pci_range_parser *parser,
+						struct of_pci_range *range);
 #else /* CONFIG_OF_ADDRESS */
 #ifndef of_address_to_resource
 static inline int of_address_to_resource(struct device_node *dev, int index,
@@ -53,6 +87,18 @@ static inline const __be32 *of_get_address(struct device_node *dev, int index,
 {
 	return NULL;
 }
+
+static inline int of_pci_range_parser(struct of_pci_range_parser *parser,
+			struct device_node *node)
+{
+	return -1;
+}
+
+static inline struct of_pci_range *of_pci_process_ranges(struct of_pci_range_parser *parser,
+						struct of_pci_range *range)
+{
+	return NULL;
+}
 #endif /* CONFIG_OF_ADDRESS */
 
 
-- 
1.7.0.4

^ permalink raw reply related

* [PATCH v7 3/3] of/pci: mips: convert to common of_pci_range_parser
From: Andrew Murray @ 2013-04-16 10:18 UTC (permalink / raw)
  To: linux-mips, linuxppc-dev
  Cc: siva.kallam, linux-pci, linus.walleij, thierry.reding,
	Liviu.Dudau, paulus, linux-samsung-soc, linux, jg1.han,
	jgunthorpe, thomas.abraham, arnd, devicetree-discuss, rob.herring,
	kgene.kim, bhelgaas, linux-arm-kernel, thomas.petazzoni, monstr,
	linux-kernel, suren.reddy, Andrew Murray
In-Reply-To: <1366107508-12672-1-git-send-email-Andrew.Murray@arm.com>

This patch converts the pci_load_of_ranges function to use the new common
of_pci_range_parser.

Signed-off-by: Andrew Murray <Andrew.Murray@arm.com>
Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
Reviewed-by: Rob Herring <rob.herring@calxeda.com>
---
 arch/mips/pci/pci.c |   50 ++++++++++++++++----------------------------------
 1 files changed, 16 insertions(+), 34 deletions(-)

diff --git a/arch/mips/pci/pci.c b/arch/mips/pci/pci.c
index 0872f12..bee49a4 100644
--- a/arch/mips/pci/pci.c
+++ b/arch/mips/pci/pci.c
@@ -122,51 +122,33 @@ static void pcibios_scanbus(struct pci_controller *hose)
 #ifdef CONFIG_OF
 void pci_load_of_ranges(struct pci_controller *hose, struct device_node *node)
 {
-	const __be32 *ranges;
-	int rlen;
-	int pna = of_n_addr_cells(node);
-	int np = pna + 5;
+	struct of_pci_range_range range;
+	struct of_pci_range_parser parser;
+	u32 res_type;
 
 	pr_info("PCI host bridge %s ranges:\n", node->full_name);
-	ranges = of_get_property(node, "ranges", &rlen);
-	if (ranges == NULL)
-		return;
 	hose->of_node = node;
 
-	while ((rlen -= np * 4) >= 0) {
-		u32 pci_space;
+	if (of_pci_range_parser(&parser, node))
+		return;
+
+	for_each_of_pci_range(&parser, &range) {
 		struct resource *res = NULL;
-		u64 addr, size;
-
-		pci_space = be32_to_cpup(&ranges[0]);
-		addr = of_translate_address(node, ranges + 3);
-		size = of_read_number(ranges + pna + 3, 2);
-		ranges += np;
-		switch ((pci_space >> 24) & 0x3) {
-		case 1:		/* PCI IO space */
+
+		res_type = range.flags & IORESOURCE_TYPE_BITS;
+		if (res_type == IORESOURCE_IO) {
 			pr_info("  IO 0x%016llx..0x%016llx\n",
-					addr, addr + size - 1);
+				range.addr, range.addr + range.size - 1);
 			hose->io_map_base =
-				(unsigned long)ioremap(addr, size);
+				(unsigned long)ioremap(range.addr, range.size);
 			res = hose->io_resource;
-			res->flags = IORESOURCE_IO;
-			break;
-		case 2:		/* PCI Memory space */
-		case 3:		/* PCI 64 bits Memory space */
+		} else if (res_type == IORESOURCE_MEM) {
 			pr_info(" MEM 0x%016llx..0x%016llx\n",
-					addr, addr + size - 1);
+				range.addr, range.addr + range.size - 1);
 			res = hose->mem_resource;
-			res->flags = IORESOURCE_MEM;
-			break;
-		}
-		if (res != NULL) {
-			res->start = addr;
-			res->name = node->full_name;
-			res->end = res->start + size - 1;
-			res->parent = NULL;
-			res->sibling = NULL;
-			res->child = NULL;
 		}
+		if (res != NULL)
+			of_pci_range_to_resource(&range, node, res);
 	}
 }
 #endif
-- 
1.7.0.4

^ permalink raw reply related

* Re: [PATCH v7 1/3] of/pci: Unify pci_process_bridge_OF_ranges from Microblaze and PowerPC
From: Andrew Murray @ 2013-04-16 10:30 UTC (permalink / raw)
  To: linux-mips@linux-mips.org, linuxppc-dev@lists.ozlabs.org
  Cc: siva.kallam@samsung.com, linux-pci@vger.kernel.org,
	linus.walleij@linaro.org, thierry.reding@avionic-design.de,
	Liviu Dudau, paulus@samba.org, linux-samsung-soc@vger.kernel.org,
	linux@arm.linux.org.uk, jg1.han@samsung.com,
	jgunthorpe@obsidianresearch.com, thomas.abraham@linaro.org,
	arnd@arndb.de, devicetree-discuss@lists.ozlabs.org,
	rob.herring@calxeda.com, kgene.kim@samsung.com,
	bhelgaas@google.com, linux-arm-kernel@lists.infradead.org,
	thomas.petazzoni@free-electrons.com, monstr@monstr.eu,
	linux-kernel@vger.kernel.org, suren.reddy@samsung.com
In-Reply-To: <1366107508-12672-2-git-send-email-Andrew.Murray@arm.com>

On Tue, Apr 16, 2013 at 11:18:26AM +0100, Andrew Murray wrote:
> The pci_process_bridge_OF_ranges function, used to parse the "ranges"
> property of a PCI host device, is found in both Microblaze and PowerPC
> architectures. These implementations are nearly identical. This patch
> moves this common code to a common place.
> 
> Signed-off-by: Andrew Murray <Andrew.Murray@arm.com>
> Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
> Reviewed-by: Rob Herring <rob.herring@calxeda.com>
> Tested-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
> Tested-by: Linus Walleij <linus.walleij@linaro.org>
> Acked-by: Michal Simek <monstr@monstr.eu>
> ---
>  arch/microblaze/include/asm/pci-bridge.h |    5 +-
>  arch/microblaze/pci/pci-common.c         |  192 ----------------------------
>  arch/powerpc/include/asm/pci-bridge.h    |    5 +-
>  arch/powerpc/kernel/pci-common.c         |  192 ----------------------------

Is there anyone on linuxppc-dev/linux-mips that can help test this patchset?

I've tested that it builds on powerpc with a variety of configs (some which
include fsl_pci.c implementation). Though I don't have hardware to verify that
it works.

I haven't tested this builds or runs on MIPS.

You shouldn't see any difference in behaviour or new warnings and PCI devices
should continue to operate as before.

Andrew Murray

^ permalink raw reply

* RE: [PATCH v3 1/4] powerpc/mpic: add irq_set_wake support
From: Wang Dongsheng-B40534 @ 2013-04-16 10:58 UTC (permalink / raw)
  To: Wood Scott-B07421; +Cc: linuxppc-dev@lists.ozlabs.org
In-Reply-To: <1365474152-21524-1-git-send-email-dongsheng.wang@freescale.com>

Hi scott,

Could you ACK these patches?

[PATCH v3 2/4] powerpc/mpic: add global timer support
[PATCH v3 3/4] powerpc/mpic: create mpic subsystem object
[PATCH v3 4/4] powerpc/fsl: add MPIC timer wakeup support

Thanks.

> -----Original Message-----
> From: Wang Dongsheng-B40534
> Sent: Tuesday, April 09, 2013 10:22 AM
> To: Wood Scott-B07421
> Cc: linuxppc-dev@lists.ozlabs.org; Wang Dongsheng-B40534
> Subject: [PATCH v3 1/4] powerpc/mpic: add irq_set_wake support
>=20
> Add irq_set_wake support. Just add IRQF_NO_SUSPEND to desc->action->flag.
> So the wake up interrupt will not be disable in suspend_device_irqs.
>=20
> Signed-off-by: Wang Dongsheng <dongsheng.wang@freescale.com>
> ---
> v3:
> * Modify: Change "EINVAL" to "ENXIO" in mpic_irq_set_wake()
>=20
> v2:
> * Add: Check freescale chip in mpic_irq_set_wake().
> * Remove: Support mpic_irq_set_wake() in ht_chip.
>=20
>  arch/powerpc/sysdev/mpic.c | 18 ++++++++++++++++++
>  1 file changed, 18 insertions(+)
>=20
> diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
> index 3b2efd4..ae709d2 100644
> --- a/arch/powerpc/sysdev/mpic.c
> +++ b/arch/powerpc/sysdev/mpic.c
> @@ -920,6 +920,22 @@ int mpic_set_irq_type(struct irq_data *d, unsigned
> int flow_type)
>  	return IRQ_SET_MASK_OK_NOCOPY;
>  }
>=20
> +static int mpic_irq_set_wake(struct irq_data *d, unsigned int on) {
> +	struct irq_desc *desc =3D container_of(d, struct irq_desc, irq_data);
> +	struct mpic *mpic =3D mpic_from_irq_data(d);
> +
> +	if (!(mpic->flags & MPIC_FSL))
> +		return -ENXIO;
> +
> +	if (on)
> +		desc->action->flags |=3D IRQF_NO_SUSPEND;
> +	else
> +		desc->action->flags &=3D ~IRQF_NO_SUSPEND;
> +
> +	return 0;
> +}
> +
>  void mpic_set_vector(unsigned int virq, unsigned int vector)  {
>  	struct mpic *mpic =3D mpic_from_irq(virq); @@ -957,6 +973,7 @@ static
> struct irq_chip mpic_irq_chip =3D {
>  	.irq_unmask	=3D mpic_unmask_irq,
>  	.irq_eoi	=3D mpic_end_irq,
>  	.irq_set_type	=3D mpic_set_irq_type,
> +	.irq_set_wake	=3D mpic_irq_set_wake,
>  };
>=20
>  #ifdef CONFIG_SMP
> @@ -971,6 +988,7 @@ static struct irq_chip mpic_tm_chip =3D {
>  	.irq_mask	=3D mpic_mask_tm,
>  	.irq_unmask	=3D mpic_unmask_tm,
>  	.irq_eoi	=3D mpic_end_irq,
> +	.irq_set_wake	=3D mpic_irq_set_wake,
>  };
>=20
>  #ifdef CONFIG_MPIC_U3_HT_IRQS
> --
> 1.8.0

^ permalink raw reply

* Re: [PATCH v2] of/base: release the node correctly in of_parse_phandle_with_args()
From: Timur Tabi @ 2013-04-16 11:37 UTC (permalink / raw)
  To: Yuantian.Tang
  Cc: devicetree-discuss, linuxppc-dev@lists.ozlabs.org, lkml,
	Rob Herring
In-Reply-To: <1365564999-24427-1-git-send-email-Yuantian.Tang@freescale.com>

On Tue, Apr 9, 2013 at 10:36 PM,  <Yuantian.Tang@freescale.com> wrote:
>
> +                       /* Found it! return success */

I'm pretty sure this comment is in the wrong place.

^ permalink raw reply

* [PATCH 0/5] powerpc, perf: BHRB based branch stack enablement on POWER8
From: Anshuman Khandual @ 2013-04-16 12:56 UTC (permalink / raw)
  To: linuxppc-dev, linux-kernel; +Cc: mikey

		Branch History Rolling Buffer (BHRB) is a new PMU feaure in IBM
POWER8 processor which records the branch instructions inside the execution
pipeline. This patchset enables the basic functionality of the feature through
generic perf branch stack sampling framework.

Sample output
-------------
$./perf record -b top
$./perf report

Overhead  Command  Source Shared Object                           Source Symbol  Target Shared Object                        Target Symbol
# ........  .......  ....................  ......................................  ....................  ...................................
#

     7.82%      top  libc-2.11.2.so        [k] _IO_vfscanf                         libc-2.11.2.so        [k] _IO_vfscanf                    
     6.17%      top  libc-2.11.2.so        [k] _IO_vfscanf                         [unknown]             [k] 00000000                       
     2.37%      top  [unknown]             [k] 0xf7aafb30                          [unknown]             [k] 00000000                       
     1.80%      top  [unknown]             [k] 0x0fe07978                          libc-2.11.2.so        [k] _IO_vfscanf                    
     1.60%      top  libc-2.11.2.so        [k] _IO_vfscanf                         [kernel.kallsyms]     [k] .do_task_stat                  
     1.20%      top  [kernel.kallsyms]     [k] .do_task_stat                       [kernel.kallsyms]     [k] .do_task_stat                  
     1.02%      top  libc-2.11.2.so        [k] vfprintf                            libc-2.11.2.so        [k] vfprintf                       
     0.92%      top  top                   [k] _init                               [unknown]             [k] 0x0fe037f4                     

Anshuman Khandual (5):
  powerpc, perf: Add new BHRB related instructions on POWER8
  powerpc, perf: Add basic assembly code to read BHRB entries on POWER8
  powerpc, perf: Add new BHRB related generic functions, data and flags
  powerpc, perf: Define BHRB generic functions, data and flags for POWER8
  powerpc, perf: Enable branch stack sampling framework support with BHRB

 arch/powerpc/include/asm/perf_event_server.h |  6 ++
 arch/powerpc/include/asm/ppc-opcode.h        |  7 ++
 arch/powerpc/perf/Makefile                   |  2 +-
 arch/powerpc/perf/bhrb.S                     | 34 ++++++++++
 arch/powerpc/perf/core-book3s.c              | 96 +++++++++++++++++++++++++++-
 arch/powerpc/perf/perf_event_bhrb.c          | 75 ++++++++++++++++++++++
 arch/powerpc/perf/power8-pmu.c               | 57 ++++++++++++++++-
 7 files changed, 272 insertions(+), 5 deletions(-)
 create mode 100644 arch/powerpc/perf/bhrb.S
 create mode 100644 arch/powerpc/perf/perf_event_bhrb.c

-- 
1.7.11.7

^ permalink raw reply

* [PATCH 4/5] powerpc, perf: Define BHRB generic functions, data and flags for POWER8
From: Anshuman Khandual @ 2013-04-16 12:56 UTC (permalink / raw)
  To: linuxppc-dev, linux-kernel; +Cc: mikey
In-Reply-To: <1366117000-10979-1-git-send-email-khandual@linux.vnet.ibm.com>

Signed-off-by: Anshuman Khandual <khandual@linux.vnet.ibm.com>
---
 arch/powerpc/perf/power8-pmu.c | 57 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 56 insertions(+), 1 deletion(-)

diff --git a/arch/powerpc/perf/power8-pmu.c b/arch/powerpc/perf/power8-pmu.c
index 106ae0b..153408c 100644
--- a/arch/powerpc/perf/power8-pmu.c
+++ b/arch/powerpc/perf/power8-pmu.c
@@ -109,6 +109,16 @@
 #define EVENT_IS_MARKED		(EVENT_MARKED_MASK << EVENT_MARKED_SHIFT)
 #define EVENT_PSEL_MASK		0xff	/* PMCxSEL value */
 
+/* MMCRA IFM bits - POWER8 */
+#define	POWER8_MMCRA_IFM1		0x0000000040000000UL
+#define	POWER8_MMCRA_IFM2		0x0000000080000000UL
+#define	POWER8_MMCRA_IFM3		0x00000000C0000000UL
+
+#define ONLY_PLM \
+	(PERF_SAMPLE_BRANCH_USER        |\
+	 PERF_SAMPLE_BRANCH_KERNEL      |\
+	 PERF_SAMPLE_BRANCH_HV)
+
 /*
  * Layout of constraint bits:
  *
@@ -428,6 +438,48 @@ static int power8_generic_events[] = {
 	[PERF_COUNT_HW_BRANCH_MISSES] =			PM_BR_MPRED_CMPL,
 };
 
+static u64 power8_bhrb_filter_map(u64 branch_sample_type)
+{
+	u64 pmu_bhrb_filter = 0;
+	u64 br_privilege = branch_sample_type & ONLY_PLM;
+
+	/* BHRB and regular PMU events share the same prvillege state
+	 * filter configuration. BHRB is always recorded along with a
+	 * regular PMU event. So privilege state filter criteria for BHRB
+	 * and the companion PMU events has to be the same. As a default
+	 * "perf record" tool sets all privillege bits ON when no filter
+	 * criteria is provided in the command line. So as along as all
+	 * privillege bits are ON or they are OFF, we are good to go.
+	 */
+	if ((br_privilege != 7) && (br_privilege != 0))
+		return -1;
+
+	/* No branch filter requested */
+	if (branch_sample_type & PERF_SAMPLE_BRANCH_ANY)
+		return pmu_bhrb_filter;
+
+	/* Invalid branch filter options - HW does not support */
+	if (branch_sample_type & PERF_SAMPLE_BRANCH_ANY_RETURN)
+		return -1;
+
+	if (branch_sample_type & PERF_SAMPLE_BRANCH_IND_CALL)
+		return -1;
+
+	if (branch_sample_type & PERF_SAMPLE_BRANCH_ANY_CALL) {
+		pmu_bhrb_filter |= POWER8_MMCRA_IFM1;
+		return pmu_bhrb_filter;
+	}
+
+	/* Every thing else is unsupported */
+	return -1;
+}
+
+static void power8_config_bhrb(u64 pmu_bhrb_filter)
+{
+	/* Enable BHRB filter in PMU */
+	mtspr(SPRN_MMCRA, (mfspr(SPRN_MMCRA) | pmu_bhrb_filter));
+}
+
 static struct power_pmu power8_pmu = {
 	.name			= "POWER8",
 	.n_counter		= 6,
@@ -435,12 +487,15 @@ static struct power_pmu power8_pmu = {
 	.add_fields		= POWER8_ADD_FIELDS,
 	.test_adder		= POWER8_TEST_ADDER,
 	.compute_mmcr		= power8_compute_mmcr,
+	.config_bhrb		= power8_config_bhrb,
+	.bhrb_filter_map	= power8_bhrb_filter_map,
 	.get_constraint		= power8_get_constraint,
 	.disable_pmc		= power8_disable_pmc,
-	.flags			= PPMU_HAS_SSLOT | PPMU_HAS_SIER,
+	.flags			= PPMU_HAS_SSLOT | PPMU_HAS_SIER | PPMU_BHRB,
 	.n_generic		= ARRAY_SIZE(power8_generic_events),
 	.generic_events		= power8_generic_events,
 	.attr_groups		= power8_pmu_attr_groups,
+	.bhrb_nr		= 32,
 };
 
 static int __init init_power8_pmu(void)
-- 
1.7.11.7

^ permalink raw reply related

* [PATCH 5/5] powerpc, perf: Enable branch stack sampling framework support with BHRB
From: Anshuman Khandual @ 2013-04-16 12:56 UTC (permalink / raw)
  To: linuxppc-dev, linux-kernel; +Cc: mikey
In-Reply-To: <1366117000-10979-1-git-send-email-khandual@linux.vnet.ibm.com>

This patch provides basic enablement for perf branch stack sampling framework
on POWER8 processor with a new PMU feature called BHRB (Branch History Rolling
Buffer).

Signed-off-by: Anshuman Khandual <khandual@linux.vnet.ibm.com>
---
 arch/powerpc/perf/core-book3s.c     | 96 +++++++++++++++++++++++++++++++++++--
 arch/powerpc/perf/perf_event_bhrb.c | 75 +++++++++++++++++++++++++++++
 2 files changed, 168 insertions(+), 3 deletions(-)
 create mode 100644 arch/powerpc/perf/perf_event_bhrb.c

diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c
index 4ac6e64..f4d1347 100644
--- a/arch/powerpc/perf/core-book3s.c
+++ b/arch/powerpc/perf/core-book3s.c
@@ -19,6 +19,8 @@
 #include <asm/firmware.h>
 #include <asm/ptrace.h>
 
+#define BHRB_MAX_ENTRIES	32
+
 struct cpu_hw_events {
 	int n_events;
 	int n_percpu;
@@ -38,11 +40,21 @@ struct cpu_hw_events {
 
 	unsigned int group_flag;
 	int n_txn_start;
+
+	/* BHRB bits */
+	u64				bhrb_filter;	/* BHRB HW branch filter */
+	int				bhrb_users;
+	void				*bhrb_context;
+	struct	perf_branch_stack	bhrb_stack;
+	struct	perf_branch_entry	bhrb_entries[BHRB_MAX_ENTRIES];
 };
+
 DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events);
 
 struct power_pmu *ppmu;
 
+#include "perf_event_bhrb.c"
+
 /*
  * Normally, to ignore kernel events we set the FCS (freeze counters
  * in supervisor mode) bit in MMCR0, but if the kernel runs with the
@@ -858,6 +870,9 @@ static void power_pmu_enable(struct pmu *pmu)
 	}
 
  out:
+	if (cpuhw->bhrb_users)
+		ppmu->config_bhrb(cpuhw->bhrb_filter);
+
 	local_irq_restore(flags);
 }
 
@@ -888,6 +903,47 @@ static int collect_events(struct perf_event *group, int max_count,
 	return n;
 }
 
+/* Reset all possible BHRB entries */
+static void power_pmu_bhrb_reset(void)
+{
+	asm volatile(PPC_CLRBHRB);
+}
+
+void power_pmu_bhrb_enable(struct perf_event *event)
+{
+	struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
+
+	if (!ppmu->bhrb_nr)
+		return;
+
+	/* Clear BHRB if we changed task context to avoid data leaks */
+	if (event->ctx->task && cpuhw->bhrb_context != event->ctx) {
+		power_pmu_bhrb_reset();
+		cpuhw->bhrb_context = event->ctx;
+	}
+	cpuhw->bhrb_users++;
+}
+
+void power_pmu_bhrb_disable(struct perf_event *event)
+{
+	struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
+
+	if (!ppmu->bhrb_nr)
+		return;
+
+	cpuhw->bhrb_users--;
+	WARN_ON_ONCE(cpuhw->bhrb_users < 0);
+
+	if (!cpuhw->disabled && !cpuhw->bhrb_users) {
+		/* BHRB cannot be turned off when other
+		 * events are active on the PMU.
+		 */
+
+		/* avoid stale pointer */
+		cpuhw->bhrb_context = NULL;
+	}
+}
+
 /*
  * Add a event to the PMU.
  * If all events are not already frozen, then we disable and
@@ -947,6 +1003,9 @@ nocheck:
 
 	ret = 0;
  out:
+	if (has_branch_stack(event))
+		power_pmu_bhrb_enable(event);
+
 	perf_pmu_enable(event->pmu);
 	local_irq_restore(flags);
 	return ret;
@@ -999,6 +1058,9 @@ static void power_pmu_del(struct perf_event *event, int ef_flags)
 		cpuhw->mmcr[0] &= ~(MMCR0_PMXE | MMCR0_FCECE);
 	}
 
+	if (has_branch_stack(event))
+		power_pmu_bhrb_disable(event);
+
 	perf_pmu_enable(event->pmu);
 	local_irq_restore(flags);
 }
@@ -1117,6 +1179,15 @@ int power_pmu_commit_txn(struct pmu *pmu)
 	return 0;
 }
 
+/* Called from ctxsw to prevent one process's branch entries to
+ * mingle with the other process's entries during context switch.
+ */
+void power_pmu_flush_branch_stack(void)
+{
+	if (ppmu->bhrb_nr)
+		power_pmu_bhrb_reset();
+}
+
 /*
  * Return 1 if we might be able to put event on a limited PMC,
  * or 0 if not.
@@ -1231,9 +1302,11 @@ static int power_pmu_event_init(struct perf_event *event)
 	if (!ppmu)
 		return -ENOENT;
 
-	/* does not support taken branch sampling */
-	if (has_branch_stack(event))
-		return -EOPNOTSUPP;
+	if (has_branch_stack(event)) {
+	        /* PMU has BHRB enabled */
+		if (!(ppmu->flags & PPMU_BHRB))
+			return -EOPNOTSUPP;
+	}
 
 	switch (event->attr.type) {
 	case PERF_TYPE_HARDWARE:
@@ -1314,6 +1387,15 @@ static int power_pmu_event_init(struct perf_event *event)
 
 	cpuhw = &get_cpu_var(cpu_hw_events);
 	err = power_check_constraints(cpuhw, events, cflags, n + 1);
+
+	if (has_branch_stack(event)) {
+		cpuhw->bhrb_filter = ppmu->bhrb_filter_map(
+					event->attr.branch_sample_type);
+
+		if(cpuhw->bhrb_filter == -1)
+			return -EOPNOTSUPP;
+	}
+
 	put_cpu_var(cpu_hw_events);
 	if (err)
 		return -EINVAL;
@@ -1372,6 +1454,7 @@ struct pmu power_pmu = {
 	.cancel_txn	= power_pmu_cancel_txn,
 	.commit_txn	= power_pmu_commit_txn,
 	.event_idx	= power_pmu_event_idx,
+	.flush_branch_stack = power_pmu_flush_branch_stack,
 };
 
 
@@ -1433,6 +1516,13 @@ static void record_and_restart(struct perf_event *event, unsigned long val,
 		if (event->attr.sample_type & PERF_SAMPLE_ADDR)
 			perf_get_data_addr(regs, &data.addr);
 
+		if (event->attr.sample_type & PERF_SAMPLE_BRANCH_STACK) {
+			struct cpu_hw_events *cpuhw;
+			cpuhw = &__get_cpu_var(cpu_hw_events);
+			power_pmu_bhrb_read(cpuhw);
+			data.br_stack = &cpuhw->bhrb_stack;
+		}
+
 		if (perf_event_overflow(event, &data, regs))
 			power_pmu_stop(event, 0);
 	}
diff --git a/arch/powerpc/perf/perf_event_bhrb.c b/arch/powerpc/perf/perf_event_bhrb.c
new file mode 100644
index 0000000..5beddef
--- /dev/null
+++ b/arch/powerpc/perf/perf_event_bhrb.c
@@ -0,0 +1,75 @@
+#define BHRB_TARGET		0x0000000000000002
+#define	BHRB_PREDICTION		0x0000000000000001
+#define	BHRB_EA			0xFFFFFFFFFFFFFFFC
+
+extern unsigned long int read_bhrb(int n);
+
+void power_pmu_bhrb_read(struct cpu_hw_events *cpuhw)
+{
+	u64 val;
+	u64 addr;
+	int r_index, u_index, target, pred;
+
+	r_index = 0;
+	u_index = 0;
+	while (r_index < ppmu->bhrb_nr) {
+		/* Assembly read function */
+		val = read_bhrb(r_index);
+
+		/* Terminal marker: End of valid BHRB entries */
+		if (val == 0) {
+			break;
+		} else {
+			/* BHRB field break up */
+			addr = val & BHRB_EA;
+			pred = val & BHRB_PREDICTION;
+			target = val & BHRB_TARGET;
+
+			/* Probable Missed entry: Not applicable for POWER8 */
+			if ((addr == 0) && (target == 0) && (pred == 1)) {
+				r_index++;
+				continue;
+			}
+
+			/* Real Missed entry: Power8 based missed entry */
+			if ((addr == 0) && (target == 1) && (pred == 1)) {
+				r_index++;
+				continue;
+			}
+
+			/* Reserved condition: Not a valid entry  */
+			if ((addr == 0) && (target == 1) && (pred == 0)) {
+				r_index++;
+				continue;
+			}
+
+			/* Is a target address */
+			if (val & BHRB_TARGET) {
+				/* First address cannot be a target address */
+				if (r_index == 0) {
+					r_index++;
+					continue;
+				}
+
+				/* Update target address for the previous entry */
+				cpuhw->bhrb_entries[u_index - 1].to = addr;
+				cpuhw->bhrb_entries[u_index - 1].mispred = pred;
+				cpuhw->bhrb_entries[u_index - 1].predicted = ~pred;
+
+				/* Dont increment u_index */
+				r_index++;
+			} else {
+				/* Update address, flags for current entry */
+				cpuhw->bhrb_entries[u_index].from = addr;
+				cpuhw->bhrb_entries[u_index].mispred = pred;
+				cpuhw->bhrb_entries[u_index].predicted = ~pred;
+
+				/* Successfully popullated one entry */
+				u_index++;
+				r_index++;
+			}
+		}
+	}
+	cpuhw->bhrb_stack.nr = u_index;
+	return;
+}
-- 
1.7.11.7

^ permalink raw reply related


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