From 6cfd8990e27d3a491c1c605d6cbc18a46ae51fef Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Wed, 9 Jul 2008 10:03:28 -0500 Subject: powerpc: rework FSL Book-E PTE access and TLB miss This converts the FSL Book-E PTE access and TLB miss handling to match with the recent changes to 44x that introduce support for non-atomic PTE operations in pgtable-ppc32.h and removes write back to the PTE from the TLB miss handlers. In addition, the DSI interrupt code no longer tries to fixup write permission, this is left to generic code, and _PAGE_HWWRITE is gone. Signed-off-by: Kumar Gala --- arch/powerpc/kernel/head_fsl_booke.S | 168 +++++++++-------------------------- 1 file changed, 44 insertions(+), 124 deletions(-) (limited to 'arch/powerpc/kernel') diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S index c4268500e85..7d554968b63 100644 --- a/arch/powerpc/kernel/head_fsl_booke.S +++ b/arch/powerpc/kernel/head_fsl_booke.S @@ -483,90 +483,16 @@ interrupt_base: /* Data Storage Interrupt */ START_EXCEPTION(DataStorage) - mtspr SPRN_SPRG0, r10 /* Save some working registers */ - mtspr SPRN_SPRG1, r11 - mtspr SPRN_SPRG4W, r12 - mtspr SPRN_SPRG5W, r13 - mfcr r11 - mtspr SPRN_SPRG7W, r11 - - /* - * Check if it was a store fault, if not then bail - * because a user tried to access a kernel or - * read-protected page. Otherwise, get the - * offending address and handle it. - */ - mfspr r10, SPRN_ESR - andis. r10, r10, ESR_ST@h - beq 2f - - mfspr r10, SPRN_DEAR /* Get faulting address */ - - /* If we are faulting a kernel address, we have to use the - * kernel page tables. - */ - lis r11, PAGE_OFFSET@h - cmplw 0, r10, r11 - bge 2f - - /* Get the PGD for the current thread */ -3: - mfspr r11,SPRN_SPRG3 - lwz r11,PGDIR(r11) -4: - FIND_PTE - - /* Are _PAGE_USER & _PAGE_RW set & _PAGE_HWWRITE not? */ - andi. r13, r11, _PAGE_RW|_PAGE_USER|_PAGE_HWWRITE - cmpwi 0, r13, _PAGE_RW|_PAGE_USER - bne 2f /* Bail if not */ - - /* Update 'changed'. */ - ori r11, r11, _PAGE_DIRTY|_PAGE_ACCESSED|_PAGE_HWWRITE - stw r11, PTE_FLAGS_OFFSET(r12) /* Update Linux page table */ - - /* MAS2 not updated as the entry does exist in the tlb, this - fault taken to detect state transition (eg: COW -> DIRTY) - */ - andi. r11, r11, _PAGE_HWEXEC - rlwimi r11, r11, 31, 27, 27 /* SX <- _PAGE_HWEXEC */ - ori r11, r11, (MAS3_UW|MAS3_SW|MAS3_UR|MAS3_SR)@l /* set static perms */ - - /* update search PID in MAS6, AS = 0 */ - mfspr r12, SPRN_PID0 - slwi r12, r12, 16 - mtspr SPRN_MAS6, r12 - - /* find the TLB index that caused the fault. It has to be here. */ - tlbsx 0, r10 - - /* only update the perm bits, assume the RPN is fine */ - mfspr r12, SPRN_MAS3 - rlwimi r12, r11, 0, 20, 31 - mtspr SPRN_MAS3,r12 - tlbwe - - /* Done...restore registers and get out of here. */ - mfspr r11, SPRN_SPRG7R - mtcr r11 - mfspr r13, SPRN_SPRG5R - mfspr r12, SPRN_SPRG4R - mfspr r11, SPRN_SPRG1 - mfspr r10, SPRN_SPRG0 - rfi /* Force context change */ - -2: - /* - * The bailout. Restore registers to pre-exception conditions - * and call the heavyweights to help us out. - */ - mfspr r11, SPRN_SPRG7R - mtcr r11 - mfspr r13, SPRN_SPRG5R - mfspr r12, SPRN_SPRG4R - mfspr r11, SPRN_SPRG1 - mfspr r10, SPRN_SPRG0 - b data_access + NORMAL_EXCEPTION_PROLOG + mfspr r5,SPRN_ESR /* Grab the ESR, save it, pass arg3 */ + stw r5,_ESR(r11) + mfspr r4,SPRN_DEAR /* Grab the DEAR, save it, pass arg2 */ + andis. r10,r5,(ESR_ILK|ESR_DLK)@h + bne 1f + EXC_XFER_EE_LITE(0x0300, handle_page_fault) +1: + addi r3,r1,STACK_FRAME_OVERHEAD + EXC_XFER_EE_LITE(0x0300, CacheLockingException) /* Instruction Storage Interrupt */ INSTRUCTION_STORAGE_EXCEPTION @@ -645,15 +571,30 @@ interrupt_base: lwz r11,PGDIR(r11) 4: + /* Mask of required permission bits. Note that while we + * do copy ESR:ST to _PAGE_RW position as trying to write + * to an RO page is pretty common, we don't do it with + * _PAGE_DIRTY. We could do it, but it's a fairly rare + * event so I'd rather take the overhead when it happens + * rather than adding an instruction here. We should measure + * whether the whole thing is worth it in the first place + * as we could avoid loading SPRN_ESR completely in the first + * place... + * + * TODO: Is it worth doing that mfspr & rlwimi in the first + * place or can we save a couple of instructions here ? + */ + mfspr r12,SPRN_ESR + li r13,_PAGE_PRESENT|_PAGE_ACCESSED + rlwimi r13,r12,11,29,29 + FIND_PTE - andi. r13, r11, _PAGE_PRESENT /* Is the page present? */ - beq 2f /* Bail if not present */ + andc. r13,r13,r11 /* Check permission */ + bne 2f /* Bail if permission mismach */ #ifdef CONFIG_PTE_64BIT lwz r13, 0(r12) #endif - ori r11, r11, _PAGE_ACCESSED - stw r11, PTE_FLAGS_OFFSET(r12) /* Jump to common tlb load */ b finish_tlb_load @@ -667,7 +608,7 @@ interrupt_base: mfspr r12, SPRN_SPRG4R mfspr r11, SPRN_SPRG1 mfspr r10, SPRN_SPRG0 - b data_access + b DataStorage /* Instruction TLB Error Interrupt */ /* @@ -705,15 +646,16 @@ interrupt_base: lwz r11,PGDIR(r11) 4: + /* Make up the required permissions */ + li r13,_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_HWEXEC + FIND_PTE - andi. r13, r11, _PAGE_PRESENT /* Is the page present? */ - beq 2f /* Bail if not present */ + andc. r13,r13,r11 /* Check permission */ + bne 2f /* Bail if permission mismach */ #ifdef CONFIG_PTE_64BIT lwz r13, 0(r12) #endif - ori r11, r11, _PAGE_ACCESSED - stw r11, PTE_FLAGS_OFFSET(r12) /* Jump to common TLB load point */ b finish_tlb_load @@ -768,29 +710,13 @@ interrupt_base: * Local functions */ - /* - * Data TLB exceptions will bail out to this point - * if they can't resolve the lightweight TLB fault. - */ -data_access: - NORMAL_EXCEPTION_PROLOG - mfspr r5,SPRN_ESR /* Grab the ESR, save it, pass arg3 */ - stw r5,_ESR(r11) - mfspr r4,SPRN_DEAR /* Grab the DEAR, save it, pass arg2 */ - andis. r10,r5,(ESR_ILK|ESR_DLK)@h - bne 1f - EXC_XFER_EE_LITE(0x0300, handle_page_fault) -1: - addi r3,r1,STACK_FRAME_OVERHEAD - EXC_XFER_EE_LITE(0x0300, CacheLockingException) - /* - * Both the instruction and data TLB miss get to this * point to load the TLB. * r10 - EA of fault * r11 - TLB (info from Linux PTE) - * r12, r13 - available to use + * r12 - available to use + * r13 - upper bits of PTE (if PTE_64BIT) or available to use * CR5 - results of addr >= PAGE_OFFSET * MAS0, MAS1 - loaded with proper value when we get here * MAS2, MAS3 - will need additional info from Linux PTE @@ -812,20 +738,14 @@ finish_tlb_load: #endif mtspr SPRN_MAS2, r12 - bge 5, 1f - - /* is user addr */ - andi. r12, r11, (_PAGE_USER | _PAGE_HWWRITE | _PAGE_HWEXEC) + li r10, (_PAGE_HWEXEC | _PAGE_PRESENT) + rlwimi r10, r11, 31, 29, 29 /* extract _PAGE_DIRTY into SW */ + and r12, r11, r10 andi. r10, r11, _PAGE_USER /* Test for _PAGE_USER */ - srwi r10, r12, 1 - or r12, r12, r10 /* Copy user perms into supervisor */ - iseleq r12, 0, r12 - b 2f - - /* is kernel addr */ -1: rlwinm r12, r11, 31, 29, 29 /* Extract _PAGE_HWWRITE into SW */ - ori r12, r12, (MAS3_SX | MAS3_SR) - + slwi r10, r12, 1 + or r10, r10, r12 + iseleq r12, r12, r10 + #ifdef CONFIG_PTE_64BIT 2: rlwimi r12, r13, 24, 0, 7 /* grab RPN[32:39] */ rlwimi r12, r11, 24, 8, 19 /* grab RPN[40:51] */ -- cgit v1.2.3-70-g09d2 From 0332f000cd010e9db0a04181284b9ac91dac5ea7 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Fri, 11 Jul 2008 14:31:35 -0500 Subject: powerpc/fsl: Minor TLBSYNC cleanup for FSL Book-E Use the TLBSYNC macro defined in ppc_asm.h rather than our own ifdefs. Signed-off-by: Kumar Gala --- arch/powerpc/kernel/head_fsl_booke.S | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) (limited to 'arch/powerpc/kernel') diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S index 7d554968b63..3cb52fa0eda 100644 --- a/arch/powerpc/kernel/head_fsl_booke.S +++ b/arch/powerpc/kernel/head_fsl_booke.S @@ -151,16 +151,11 @@ skpinv: addi r6,r6,1 /* Increment */ /* Invalidate TLB0 */ li r6,0x04 tlbivax 0,r6 -#ifdef CONFIG_SMP - tlbsync -#endif + TLBSYNC /* Invalidate TLB1 */ li r6,0x0c tlbivax 0,r6 -#ifdef CONFIG_SMP - tlbsync -#endif - msync + TLBSYNC /* 3. Setup a temp mapping and jump to it */ andi. r5, r3, 0x1 /* Find an entry not used and is non-zero */ @@ -238,10 +233,7 @@ skpinv: addi r6,r6,1 /* Increment */ /* Invalidate TLB1 */ li r9,0x0c tlbivax 0,r9 -#ifdef CONFIG_SMP - tlbsync -#endif - msync + TLBSYNC /* 6. Setup KERNELBASE mapping in TLB1[0] */ lis r6,0x1000 /* Set MAS0(TLBSEL) = TLB1(1), ESEL = 0 */ @@ -283,10 +275,7 @@ skpinv: addi r6,r6,1 /* Increment */ /* Invalidate TLB1 */ li r9,0x0c tlbivax 0,r9 -#ifdef CONFIG_SMP - tlbsync -#endif - msync + TLBSYNC /* Establish the interrupt vector offsets */ SET_IVOR(0, CriticalInput); -- cgit v1.2.3-70-g09d2 From 4f3dd8a06239c0a19d772a27c2f618dc2faadf4a Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Wed, 16 Jul 2008 05:51:47 +1000 Subject: powerpc/dma: Use the struct dma_attrs in iommu code Update iommu_alloc() to take the struct dma_attrs and pass them on to tce_build(). This change propagates down to the tce_build functions of all the platforms. Signed-off-by: Mark Nelson Signed-off-by: Arnd Bergmann Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/iommu.c | 13 ++++++++----- arch/powerpc/platforms/cell/iommu.c | 5 +++-- arch/powerpc/platforms/iseries/iommu.c | 3 ++- arch/powerpc/platforms/pasemi/iommu.c | 3 ++- arch/powerpc/platforms/pseries/iommu.c | 14 +++++++++----- arch/powerpc/sysdev/dart_iommu.c | 3 ++- include/asm-powerpc/machdep.h | 3 ++- 7 files changed, 28 insertions(+), 16 deletions(-) (limited to 'arch/powerpc/kernel') diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c index 8c68ee9e5d1..2385f68c175 100644 --- a/arch/powerpc/kernel/iommu.c +++ b/arch/powerpc/kernel/iommu.c @@ -186,7 +186,8 @@ static unsigned long iommu_range_alloc(struct device *dev, static dma_addr_t iommu_alloc(struct device *dev, struct iommu_table *tbl, void *page, unsigned int npages, enum dma_data_direction direction, - unsigned long mask, unsigned int align_order) + unsigned long mask, unsigned int align_order, + struct dma_attrs *attrs) { unsigned long entry, flags; dma_addr_t ret = DMA_ERROR_CODE; @@ -205,7 +206,7 @@ static dma_addr_t iommu_alloc(struct device *dev, struct iommu_table *tbl, /* Put the TCEs in the HW table */ ppc_md.tce_build(tbl, entry, npages, (unsigned long)page & IOMMU_PAGE_MASK, - direction); + direction, attrs); /* Flush/invalidate TLB caches if necessary */ @@ -336,7 +337,8 @@ int iommu_map_sg(struct device *dev, struct iommu_table *tbl, npages, entry, dma_addr); /* Insert into HW table */ - ppc_md.tce_build(tbl, entry, npages, vaddr & IOMMU_PAGE_MASK, direction); + ppc_md.tce_build(tbl, entry, npages, vaddr & IOMMU_PAGE_MASK, + direction, attrs); /* If we are in an open segment, try merging */ if (segstart != s) { @@ -573,7 +575,8 @@ dma_addr_t iommu_map_single(struct device *dev, struct iommu_table *tbl, align = PAGE_SHIFT - IOMMU_PAGE_SHIFT; dma_handle = iommu_alloc(dev, tbl, vaddr, npages, direction, - mask >> IOMMU_PAGE_SHIFT, align); + mask >> IOMMU_PAGE_SHIFT, align, + attrs); if (dma_handle == DMA_ERROR_CODE) { if (printk_ratelimit()) { printk(KERN_INFO "iommu_alloc failed, " @@ -642,7 +645,7 @@ void *iommu_alloc_coherent(struct device *dev, struct iommu_table *tbl, nio_pages = size >> IOMMU_PAGE_SHIFT; io_order = get_iommu_order(size); mapping = iommu_alloc(dev, tbl, ret, nio_pages, DMA_BIDIRECTIONAL, - mask >> IOMMU_PAGE_SHIFT, io_order); + mask >> IOMMU_PAGE_SHIFT, io_order, NULL); if (mapping == DMA_ERROR_CODE) { free_pages((unsigned long)ret, order); return NULL; diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c index eeacb3a52ca..3b7078453e7 100644 --- a/arch/powerpc/platforms/cell/iommu.c +++ b/arch/powerpc/platforms/cell/iommu.c @@ -173,7 +173,8 @@ static void invalidate_tce_cache(struct cbe_iommu *iommu, unsigned long *pte, } static void tce_build_cell(struct iommu_table *tbl, long index, long npages, - unsigned long uaddr, enum dma_data_direction direction) + unsigned long uaddr, enum dma_data_direction direction, + struct dma_attrs *attrs) { int i; unsigned long *io_pte, base_pte; @@ -519,7 +520,7 @@ cell_iommu_setup_window(struct cbe_iommu *iommu, struct device_node *np, __set_bit(0, window->table.it_map); tce_build_cell(&window->table, window->table.it_offset, 1, - (unsigned long)iommu->pad_page, DMA_TO_DEVICE); + (unsigned long)iommu->pad_page, DMA_TO_DEVICE, NULL); window->table.it_hint = window->table.it_blocksize; return window; diff --git a/arch/powerpc/platforms/iseries/iommu.c b/arch/powerpc/platforms/iseries/iommu.c index ab5d8687c3c..bc818e4e203 100644 --- a/arch/powerpc/platforms/iseries/iommu.c +++ b/arch/powerpc/platforms/iseries/iommu.c @@ -42,7 +42,8 @@ #include static void tce_build_iSeries(struct iommu_table *tbl, long index, long npages, - unsigned long uaddr, enum dma_data_direction direction) + unsigned long uaddr, enum dma_data_direction direction, + struct dma_attrs *attrs) { u64 rc; u64 tce, rpn; diff --git a/arch/powerpc/platforms/pasemi/iommu.c b/arch/powerpc/platforms/pasemi/iommu.c index 86967bdd877..70541b7a501 100644 --- a/arch/powerpc/platforms/pasemi/iommu.c +++ b/arch/powerpc/platforms/pasemi/iommu.c @@ -85,7 +85,8 @@ static int iommu_table_iobmap_inited; static void iobmap_build(struct iommu_table *tbl, long index, long npages, unsigned long uaddr, - enum dma_data_direction direction) + enum dma_data_direction direction, + struct dma_attrs *attrs) { u32 *ip; u32 rpn; diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c index 9a12908510f..5377dd4b849 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c @@ -50,7 +50,8 @@ static void tce_build_pSeries(struct iommu_table *tbl, long index, long npages, unsigned long uaddr, - enum dma_data_direction direction) + enum dma_data_direction direction, + struct dma_attrs *attrs) { u64 proto_tce; u64 *tcep; @@ -95,7 +96,8 @@ static unsigned long tce_get_pseries(struct iommu_table *tbl, long index) static void tce_build_pSeriesLP(struct iommu_table *tbl, long tcenum, long npages, unsigned long uaddr, - enum dma_data_direction direction) + enum dma_data_direction direction, + struct dma_attrs *attrs) { u64 rc; u64 proto_tce, tce; @@ -127,7 +129,8 @@ static DEFINE_PER_CPU(u64 *, tce_page) = NULL; static void tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum, long npages, unsigned long uaddr, - enum dma_data_direction direction) + enum dma_data_direction direction, + struct dma_attrs *attrs) { u64 rc; u64 proto_tce; @@ -136,7 +139,8 @@ static void tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum, long l, limit; if (npages == 1) { - tce_build_pSeriesLP(tbl, tcenum, npages, uaddr, direction); + tce_build_pSeriesLP(tbl, tcenum, npages, uaddr, + direction, attrs); return; } @@ -150,7 +154,7 @@ static void tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum, /* If allocation fails, fall back to the loop implementation */ if (!tcep) { tce_build_pSeriesLP(tbl, tcenum, npages, uaddr, - direction); + direction, attrs); return; } __get_cpu_var(tce_page) = tcep; diff --git a/arch/powerpc/sysdev/dart_iommu.c b/arch/powerpc/sysdev/dart_iommu.c index 005c2ecf976..de8c8b542cf 100644 --- a/arch/powerpc/sysdev/dart_iommu.c +++ b/arch/powerpc/sysdev/dart_iommu.c @@ -149,7 +149,8 @@ static void dart_flush(struct iommu_table *tbl) static void dart_build(struct iommu_table *tbl, long index, long npages, unsigned long uaddr, - enum dma_data_direction direction) + enum dma_data_direction direction, + struct dma_attrs *attrs) { unsigned int *dp; unsigned int rpn; diff --git a/include/asm-powerpc/machdep.h b/include/asm-powerpc/machdep.h index 989922621e3..1233d735fd2 100644 --- a/include/asm-powerpc/machdep.h +++ b/include/asm-powerpc/machdep.h @@ -80,7 +80,8 @@ struct machdep_calls { long index, long npages, unsigned long uaddr, - enum dma_data_direction direction); + enum dma_data_direction direction, + struct dma_attrs *attrs); void (*tce_free)(struct iommu_table *tbl, long index, long npages); -- cgit v1.2.3-70-g09d2 From 6fdc9f5076e0f6018e1d9250c6673f812b556d90 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 17 Jul 2008 08:12:25 +1000 Subject: powerpc: Fix support for latencytop We need to pass the kernel stack pointer instead of the user space stack pointer in save_stack_trace_tsk(). Signed-off-by: Arnd Bergmann Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/stacktrace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/powerpc/kernel') diff --git a/arch/powerpc/kernel/stacktrace.c b/arch/powerpc/kernel/stacktrace.c index 071bee3ec74..f2589645870 100644 --- a/arch/powerpc/kernel/stacktrace.c +++ b/arch/powerpc/kernel/stacktrace.c @@ -59,6 +59,6 @@ EXPORT_SYMBOL_GPL(save_stack_trace); void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) { - save_context_stack(trace, tsk->thread.regs->gpr[1], tsk, 0); + save_context_stack(trace, tsk->thread.ksp, tsk, 0); } EXPORT_SYMBOL_GPL(save_stack_trace_tsk); -- cgit v1.2.3-70-g09d2 From 67260ac9a397eb7c9e2980be2865912d3840b042 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Thu, 17 Jul 2008 15:53:31 +1000 Subject: powerpc: Fix OF parsing of 64 bits PCI addresses The OF parsing code for PCI addresses isn't always treating properly the address space indication 0b11 (ie. 0x3) as meaning 64 bits memory space. This means that it fails to parse addresses for PCI BARs that have this encoding set by the firmware, which happens on some SLOF versions and breaks offb palette handling on Powerstation. Signed-off-by: Benjamin Herrenschmidt Acked-by: Segher Boessenkool --- arch/powerpc/kernel/pci-common.c | 1 + arch/powerpc/kernel/prom_parse.c | 44 ++++++++++++++++++++++------------------ 2 files changed, 25 insertions(+), 20 deletions(-) (limited to 'arch/powerpc/kernel') diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c index 063cdd41304..224e9a11765 100644 --- a/arch/powerpc/kernel/pci-common.c +++ b/arch/powerpc/kernel/pci-common.c @@ -598,6 +598,7 @@ void __devinit pci_process_bridge_OF_ranges(struct pci_controller *hose, 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, diff --git a/arch/powerpc/kernel/prom_parse.c b/arch/powerpc/kernel/prom_parse.c index 90eb3a3e383..bc1fb27368a 100644 --- a/arch/powerpc/kernel/prom_parse.c +++ b/arch/powerpc/kernel/prom_parse.c @@ -128,12 +128,35 @@ static void of_bus_pci_count_cells(struct device_node *np, *sizec = 2; } +static unsigned int of_bus_pci_get_flags(const u32 *addr) +{ + unsigned int flags = 0; + u32 w = addr[0]; + + switch((w >> 24) & 0x03) { + case 0x01: + flags |= IORESOURCE_IO; + break; + case 0x02: /* 32 bits */ + case 0x03: /* 64 bits */ + flags |= IORESOURCE_MEM; + break; + } + if (w & 0x40000000) + flags |= IORESOURCE_PREFETCH; + return flags; +} + static u64 of_bus_pci_map(u32 *addr, const u32 *range, int na, int ns, int pna) { u64 cp, s, da; + unsigned int af, rf; + + af = of_bus_pci_get_flags(addr); + rf = of_bus_pci_get_flags(range); /* Check address type match */ - if ((addr[0] ^ range[0]) & 0x03000000) + if ((af ^ rf) & (IORESOURCE_MEM | IORESOURCE_IO)) return OF_BAD_ADDR; /* Read address values, skipping high cell */ @@ -153,25 +176,6 @@ static int of_bus_pci_translate(u32 *addr, u64 offset, int na) return of_bus_default_translate(addr + 1, offset, na - 1); } -static unsigned int of_bus_pci_get_flags(const u32 *addr) -{ - unsigned int flags = 0; - u32 w = addr[0]; - - switch((w >> 24) & 0x03) { - case 0x01: - flags |= IORESOURCE_IO; - break; - case 0x02: /* 32 bits */ - case 0x03: /* 64 bits */ - flags |= IORESOURCE_MEM; - break; - } - if (w & 0x40000000) - flags |= IORESOURCE_PREFETCH; - return flags; -} - const u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size, unsigned int *flags) { -- cgit v1.2.3-70-g09d2 From 79e25bac124a7d1d7bf966f06dd9398a1b5f3d20 Mon Sep 17 00:00:00 2001 From: Torez Smith Date: Fri, 18 Jul 2008 06:42:07 +1000 Subject: powerpc: Indicate which oprofile counters to use while in compat mode While running on a system with new hardware and a kernel where the cpu_specs[] table does not recognize the new hardware, the identify_cpu() routine will select the default case as it searches through cpu_specs[] in an attempt to match the real PVR. Once the default case is selected, non of the oprofile counters and/or fields have been set up or defined. When identify_cpu() is called once more with the logical PVR, some of the cpu specific fields are replaced with the exception of the oprofile related ones. However, in the case where we have actually taken the default case while searching for the real PVR, we need to tell oprofile that we are now running in compatibility mode so it can pick up the correct counters. We do this by setting the oprofile_cpu_type field to be that taken from the cpu_specs[] for the cpu we are now emulating. This change will detect that we are now altering the real PVR and determine if we also need to update the oprofile_cpu_type field. Signed-off-by: Torez Smith Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/cputable.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'arch/powerpc/kernel') diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index f7f3c215d06..b936a1dd0a5 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -355,6 +355,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .icache_bsize = 128, .dcache_bsize = 128, .machine_check = machine_check_generic, + .oprofile_cpu_type = "ppc64/compat-power5+", .platform = "power5+", }, { /* Power6 */ @@ -386,6 +387,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .icache_bsize = 128, .dcache_bsize = 128, .machine_check = machine_check_generic, + .oprofile_cpu_type = "ppc64/compat-power6", .platform = "power6", }, { /* 2.06-compliant processor, i.e. Power7 "architected" mode */ @@ -397,6 +399,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .icache_bsize = 128, .dcache_bsize = 128, .machine_check = machine_check_generic, + .oprofile_cpu_type = "ppc64/compat-power7", .platform = "power7", }, { /* Power7 */ @@ -1629,6 +1632,23 @@ struct cpu_spec * __init identify_cpu(unsigned long offset, unsigned int pvr) t->cpu_setup = s->cpu_setup; t->cpu_restore = s->cpu_restore; t->platform = s->platform; + /* + * If we have passed through this logic once + * before and have pulled the default case + * because the real PVR was not found inside + * cpu_specs[], then we are possibly running in + * compatibility mode. In that case, let the + * oprofiler know which set of compatibility + * counters to pull from by making sure the + * oprofile_cpu_type string is set to that of + * compatibility mode. If the oprofile_cpu_type + * already has a value, then we are possibly + * overriding a real PVR with a logical one, and, + * in that case, keep the current value for + * oprofile_cpu_type. + */ + if (t->oprofile_cpu_type == NULL) + t->oprofile_cpu_type = s->oprofile_cpu_type; } else *t = *s; *PTRRELOC(&cur_cpu_spec) = &the_cpu_spec; -- cgit v1.2.3-70-g09d2 From c69cccc95fe4b90dde5fe33e6a3b77880b534fa4 Mon Sep 17 00:00:00 2001 From: Segher Boessenkool Date: Tue, 22 Jul 2008 09:03:45 +1000 Subject: powerpc: Fix build bug with binutils < 2.18 and GCC < 4.2 binutils < 2.18 has a bug that makes it misbehave when taking an ELF file with all segments at load address 0 as input. This happens when running "strip" on vmlinux, because of the AT() magic in this linker script. People using GCC >= 4.2 won't run into this problem, because the "build-id" support will put some data into the "notes" segment (at a non-zero load address). To work around this, we force some data into both the "dummy" segment and the kernel segment, so the dummy segment will get a non-zero load address. It's not enough to always create the "notes" segment, since if nothing gets assigned to it, its load address will be zero. Signed-off-by: Segher Boessenkool Tested-By: Milton Miller Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/vmlinux.lds.S | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) (limited to 'arch/powerpc/kernel') diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S index 87a72c66ce2..a914411bced 100644 --- a/arch/powerpc/kernel/vmlinux.lds.S +++ b/arch/powerpc/kernel/vmlinux.lds.S @@ -9,6 +9,25 @@ ENTRY(_stext) +PHDRS { + kernel PT_LOAD FLAGS(7); /* RWX */ + notes PT_NOTE FLAGS(0); + dummy PT_NOTE FLAGS(0); + + /* binutils < 2.18 has a bug that makes it misbehave when taking an + ELF file with all segments at load address 0 as input. This + happens when running "strip" on vmlinux, because of the AT() magic + in this linker script. People using GCC >= 4.2 won't run into + this problem, because the "build-id" support will put some data + into the "notes" segment (at a non-zero load address). + + To work around this, we force some data into both the "dummy" + segment and the kernel segment, so the dummy segment will get a + non-zero load address. It's not enough to always create the + "notes" segment, since if nothing gets assigned to it, its load + address will be zero. */ +} + #ifdef CONFIG_PPC64 OUTPUT_ARCH(powerpc:common64) jiffies = jiffies_64; @@ -50,7 +69,7 @@ SECTIONS . = ALIGN(PAGE_SIZE); _etext = .; PROVIDE32 (etext = .); - } + } :kernel /* Read-only data */ RODATA @@ -62,7 +81,13 @@ SECTIONS __stop___ex_table = .; } - NOTES + NOTES :kernel :notes + + /* The dummy segment contents for the bug workaround mentioned above + near PHDRS. */ + .dummy : { + LONG(0xf177) + } :kernel :dummy /* * Init sections discarded at runtime @@ -74,7 +99,7 @@ SECTIONS _sinittext = .; INIT_TEXT _einittext = .; - } + } :kernel /* .exit.text is discarded at runtime, not link time, * to deal with references from __bug_table -- cgit v1.2.3-70-g09d2