diff options
Diffstat (limited to 'arch/ppc64/kernel')
-rw-r--r-- | arch/ppc64/kernel/LparData.c | 79 | ||||
-rw-r--r-- | arch/ppc64/kernel/Makefile | 5 | ||||
-rw-r--r-- | arch/ppc64/kernel/head.S | 8 | ||||
-rw-r--r-- | arch/ppc64/kernel/iommu.c | 7 | ||||
-rw-r--r-- | arch/ppc64/kernel/lparmap.c | 31 | ||||
-rw-r--r-- | arch/ppc64/kernel/machine_kexec.c | 12 | ||||
-rw-r--r-- | arch/ppc64/kernel/misc.S | 6 | ||||
-rw-r--r-- | arch/ppc64/kernel/mpic.c | 4 | ||||
-rw-r--r-- | arch/ppc64/kernel/mpic.h | 2 | ||||
-rw-r--r-- | arch/ppc64/kernel/pci.c | 20 | ||||
-rw-r--r-- | arch/ppc64/kernel/prom.c | 2 | ||||
-rw-r--r-- | arch/ppc64/kernel/prom_init.c | 2 | ||||
-rw-r--r-- | arch/ppc64/kernel/setup.c | 2 | ||||
-rw-r--r-- | arch/ppc64/kernel/xics.c | 31 |
14 files changed, 106 insertions, 105 deletions
diff --git a/arch/ppc64/kernel/LparData.c b/arch/ppc64/kernel/LparData.c index 76cfd1449d52..1c11031c838e 100644 --- a/arch/ppc64/kernel/LparData.c +++ b/arch/ppc64/kernel/LparData.c @@ -32,32 +32,12 @@ /* The HvReleaseData is the root of the information shared between * the hypervisor and Linux. */ - -/* - * WARNING - magic here - * - * Ok, this is a horrid hack below, but marginally better than the - * alternatives. What we really want is just to initialize - * hvReleaseData in C as in the #if 0 section here. However, gcc - * refuses to believe that (u32)&x is a constant expression, so will - * not allow the xMsNucDataOffset field to be properly initialized. - * So, we declare hvReleaseData in inline asm instead. We use inline - * asm, rather than a .S file, because the assembler won't generate - * the necessary relocation for the LparMap either, unless that symbol - * is declared in the same source file. Finally, we put the asm in a - * dummy, attribute-used function, instead of at file scope, because - * file scope asms don't allow contraints. We want to use the "i" - * constraints to put sizeof() and offsetof() expressions in there, - * because including asm/offsets.h in C code then stringifying causes - * all manner of warnings. - */ -#if 0 struct HvReleaseData hvReleaseData = { .xDesc = 0xc8a5d9c4, /* "HvRD" ebcdic */ .xSize = sizeof(struct HvReleaseData), .xVpdAreasPtrOffset = offsetof(struct naca_struct, xItVpdAreas), .xSlicNacaAddr = &naca, /* 64-bit Naca address */ - .xMsNucDataOffset = (u32)((unsigned long)&xLparMap - KERNELBASE), + .xMsNucDataOffset = LPARMAP_PHYS, .xFlags = HVREL_TAGSINACTIVE /* tags inactive */ /* 64 bit */ /* shared processors */ @@ -70,63 +50,6 @@ struct HvReleaseData hvReleaseData = { 0xa7, 0x40, 0xf2, 0x4b, 0xf4, 0x4b, 0xf6, 0xf4 }, }; -#endif - - -extern struct HvReleaseData hvReleaseData; - -static void __attribute_used__ hvReleaseData_wrapper(void) -{ - /* This doesn't appear to need any alignment (even 4 byte) */ - asm volatile ( - " lparMapPhys = xLparMap - %3\n" - " .data\n" - " .globl hvReleaseData\n" - "hvReleaseData:\n" - " .long 0xc8a5d9c4\n" /* xDesc */ - /* "HvRD" in ebcdic */ - " .short %0\n" /* xSize */ - " .short %1\n" /* xVpdAreasPtrOffset */ - " .llong naca\n" /* xSlicNacaAddr */ - " .long lparMapPhys\n" /* xMsNucDataOffset */ - " .long 0\n" /* xRsvd1 */ - " .short %2\n" /* xFlags */ - " .short 4\n" /* xVrmIndex - v5r2m0 */ - " .short 3\n" /* xMinSupportedPlicVrmIndex - v5r1m0 */ - " .short 3\n" /* xMinCompatablePlicVrmIndex - v5r1m0 */ - " .long 0xd38995a4\n" /* xVrmName */ - " .long 0xa740f24b\n" /* "Linux 2.4.64" ebcdic */ - " .long 0xf44bf6f4\n" - " . = hvReleaseData + %0\n" - " .previous\n" - : : "i"(sizeof(hvReleaseData)), - "i"(offsetof(struct naca_struct, xItVpdAreas)), - "i"(HVREL_TAGSINACTIVE /* tags inactive, 64 bit, */ - /* shared processors, HMT allowed */ - | 6), /* TEMP: This allows non-GA drivers */ - "i"(KERNELBASE) - ); -} - -struct LparMap __attribute__((aligned (16))) xLparMap = { - .xNumberEsids = HvEsidsToMap, - .xNumberRanges = HvRangesToMap, - .xSegmentTableOffs = STAB0_PAGE, - - .xEsids = { - { .xKernelEsid = GET_ESID(KERNELBASE), - .xKernelVsid = KERNEL_VSID(KERNELBASE), }, - { .xKernelEsid = GET_ESID(VMALLOCBASE), - .xKernelVsid = KERNEL_VSID(VMALLOCBASE), }, - }, - - .xRanges = { - { .xPages = HvPagesToMap, - .xOffset = 0, - .xVPN = KERNEL_VSID(KERNELBASE) << (SID_SHIFT - PAGE_SHIFT), - }, - }, -}; extern void system_reset_iSeries(void); extern void machine_check_iSeries(void); diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index d9b2660ef221..2ecccb6b4f8c 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -73,3 +73,8 @@ obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o obj-$(CONFIG_KPROBES) += kprobes.o CFLAGS_ioctl32.o += -Ifs/ + +ifeq ($(CONFIG_PPC_ISERIES),y) +arch/ppc64/kernel/head.o: arch/ppc64/kernel/lparmap.s +AFLAGS_head.o += -Iarch/ppc64/kernel +endif diff --git a/arch/ppc64/kernel/head.S b/arch/ppc64/kernel/head.S index 74fc3bc68604..accaa052d31f 100644 --- a/arch/ppc64/kernel/head.S +++ b/arch/ppc64/kernel/head.S @@ -38,6 +38,7 @@ #include <asm/cputable.h> #include <asm/setup.h> #include <asm/hvcall.h> +#include <asm/iSeries/LparMap.h> #ifdef CONFIG_PPC_ISERIES #define DO_SOFT_DISABLE @@ -679,6 +680,11 @@ hardware_interrupt_iSeries_masked: .globl fwnmi_data_area fwnmi_data_area: +#ifdef CONFIG_PPC_ISERIES + . = LPARMAP_PHYS +#include "lparmap.s" +#endif /* CONFIG_PPC_ISERIES */ + /* * Vectors for the FWNMI option. Share common code. */ @@ -2071,7 +2077,7 @@ _GLOBAL(hmt_start_secondary) blr #endif -#if defined(CONFIG_SMP) && !defined(CONFIG_PPC_ISERIES) +#if defined(CONFIG_KEXEC) || (defined(CONFIG_SMP) && !defined(CONFIG_PPC_ISERIES)) _GLOBAL(smp_release_cpus) /* All secondary cpus are spinning on a common * spinloop, release them all now so they can start diff --git a/arch/ppc64/kernel/iommu.c b/arch/ppc64/kernel/iommu.c index 8316426ccaf6..845eebd1e28d 100644 --- a/arch/ppc64/kernel/iommu.c +++ b/arch/ppc64/kernel/iommu.c @@ -242,7 +242,7 @@ int iommu_map_sg(struct device *dev, struct iommu_table *tbl, dma_addr_t dma_next = 0, dma_addr; unsigned long flags; struct scatterlist *s, *outs, *segstart; - int outcount; + int outcount, incount; unsigned long handle; BUG_ON(direction == DMA_NONE); @@ -252,6 +252,7 @@ int iommu_map_sg(struct device *dev, struct iommu_table *tbl, outs = s = segstart = &sglist[0]; outcount = 1; + incount = nelems; handle = 0; /* Init first segment length for backout at failure */ @@ -338,10 +339,10 @@ int iommu_map_sg(struct device *dev, struct iommu_table *tbl, DBG("mapped %d elements:\n", outcount); - /* For the sake of iommu_free_sg, we clear out the length in the + /* For the sake of iommu_unmap_sg, we clear out the length in the * next entry of the sglist if we didn't fill the list completely */ - if (outcount < nelems) { + if (outcount < incount) { outs++; outs->dma_address = DMA_ERROR_CODE; outs->dma_length = 0; diff --git a/arch/ppc64/kernel/lparmap.c b/arch/ppc64/kernel/lparmap.c new file mode 100644 index 000000000000..b81de286df5e --- /dev/null +++ b/arch/ppc64/kernel/lparmap.c @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2005 Stephen Rothwell IBM Corp. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include <asm/mmu.h> +#include <asm/page.h> +#include <asm/iSeries/LparMap.h> + +const struct LparMap __attribute__((__section__(".text"))) xLparMap = { + .xNumberEsids = HvEsidsToMap, + .xNumberRanges = HvRangesToMap, + .xSegmentTableOffs = STAB0_PAGE, + + .xEsids = { + { .xKernelEsid = GET_ESID(KERNELBASE), + .xKernelVsid = KERNEL_VSID(KERNELBASE), }, + { .xKernelEsid = GET_ESID(VMALLOCBASE), + .xKernelVsid = KERNEL_VSID(VMALLOCBASE), }, + }, + + .xRanges = { + { .xPages = HvPagesToMap, + .xOffset = 0, + .xVPN = KERNEL_VSID(KERNELBASE) << (SID_SHIFT - PAGE_SHIFT), + }, + }, +}; diff --git a/arch/ppc64/kernel/machine_kexec.c b/arch/ppc64/kernel/machine_kexec.c index fdb2fc649d72..4775f12a013c 100644 --- a/arch/ppc64/kernel/machine_kexec.c +++ b/arch/ppc64/kernel/machine_kexec.c @@ -185,7 +185,7 @@ void kexec_copy_flush(struct kimage *image) void kexec_smp_down(void *arg) { if (ppc_md.cpu_irq_down) - ppc_md.cpu_irq_down(); + ppc_md.cpu_irq_down(1); local_irq_disable(); kexec_smp_wait(); @@ -232,7 +232,7 @@ static void kexec_prepare_cpus(void) /* after we tell the others to go down */ if (ppc_md.cpu_irq_down) - ppc_md.cpu_irq_down(); + ppc_md.cpu_irq_down(0); put_cpu(); @@ -243,15 +243,19 @@ static void kexec_prepare_cpus(void) static void kexec_prepare_cpus(void) { + extern void smp_release_cpus(void); /* * move the secondarys to us so that we can copy * the new kernel 0-0x100 safely * * do this if kexec in setup.c ? + * + * We need to release the cpus if we are ever going from an + * UP to an SMP kernel. */ - smp_relase_cpus(); + smp_release_cpus(); if (ppc_md.cpu_irq_down) - ppc_md.cpu_irq_down(); + ppc_md.cpu_irq_down(0); local_irq_disable(); } diff --git a/arch/ppc64/kernel/misc.S b/arch/ppc64/kernel/misc.S index 59f4f9973818..a05b50b738e9 100644 --- a/arch/ppc64/kernel/misc.S +++ b/arch/ppc64/kernel/misc.S @@ -1129,6 +1129,9 @@ _GLOBAL(sys_call_table32) .llong .compat_sys_waitid .llong .sys32_ioprio_set .llong .sys32_ioprio_get + .llong .sys_inotify_init /* 275 */ + .llong .sys_inotify_add_watch + .llong .sys_inotify_rm_watch .balign 8 _GLOBAL(sys_call_table) @@ -1407,3 +1410,6 @@ _GLOBAL(sys_call_table) .llong .sys_waitid .llong .sys_ioprio_set .llong .sys_ioprio_get + .llong .sys_inotify_init /* 275 */ + .llong .sys_inotify_add_watch + .llong .sys_inotify_rm_watch diff --git a/arch/ppc64/kernel/mpic.c b/arch/ppc64/kernel/mpic.c index e8fbab1df37f..cc262a05ddb4 100644 --- a/arch/ppc64/kernel/mpic.c +++ b/arch/ppc64/kernel/mpic.c @@ -794,10 +794,10 @@ void mpic_setup_this_cpu(void) /* * XXX: someone who knows mpic should check this. - * do we need to eoi the ipi here (see xics comments)? + * do we need to eoi the ipi including for kexec cpu here (see xics comments)? * or can we reset the mpic in the new kernel? */ -void mpic_teardown_this_cpu(void) +void mpic_teardown_this_cpu(int secondary) { struct mpic *mpic = mpic_primary; unsigned long flags; diff --git a/arch/ppc64/kernel/mpic.h b/arch/ppc64/kernel/mpic.h index 99fbbc9a084c..ca78a7f10528 100644 --- a/arch/ppc64/kernel/mpic.h +++ b/arch/ppc64/kernel/mpic.h @@ -256,7 +256,7 @@ extern unsigned int mpic_irq_get_priority(unsigned int irq); extern void mpic_setup_this_cpu(void); /* Clean up for kexec (or cpu offline or ...) */ -extern void mpic_teardown_this_cpu(void); +extern void mpic_teardown_this_cpu(int secondary); /* Request IPIs on primary mpic */ extern void mpic_request_ipis(void); diff --git a/arch/ppc64/kernel/pci.c b/arch/ppc64/kernel/pci.c index ae6f579d3fa0..d0d55c7908ef 100644 --- a/arch/ppc64/kernel/pci.c +++ b/arch/ppc64/kernel/pci.c @@ -108,8 +108,28 @@ void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region region->end = res->end - offset; } +void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res, + struct pci_bus_region *region) +{ + unsigned long offset = 0; + struct pci_controller *hose = pci_bus_to_host(dev->bus); + + if (!hose) + return; + + if (res->flags & IORESOURCE_IO) + offset = (unsigned long)hose->io_base_virt - pci_io_base; + + if (res->flags & IORESOURCE_MEM) + offset = hose->pci_mem_offset; + + res->start = region->start + offset; + res->end = region->end + offset; +} + #ifdef CONFIG_HOTPLUG EXPORT_SYMBOL(pcibios_resource_to_bus); +EXPORT_SYMBOL(pcibios_bus_to_resource); #endif /* diff --git a/arch/ppc64/kernel/prom.c b/arch/ppc64/kernel/prom.c index 47727a6f7346..5aca01ddd81f 100644 --- a/arch/ppc64/kernel/prom.c +++ b/arch/ppc64/kernel/prom.c @@ -916,6 +916,7 @@ static int __init early_init_dt_scan_cpus(unsigned long node, } } +#ifdef CONFIG_ALTIVEC /* Check if we have a VMX and eventually update CPU features */ prop = (u32 *)get_flat_dt_prop(node, "ibm,vmx", NULL); if (prop && (*prop) > 0) { @@ -929,6 +930,7 @@ static int __init early_init_dt_scan_cpus(unsigned long node, cur_cpu_spec->cpu_features |= CPU_FTR_ALTIVEC; cur_cpu_spec->cpu_user_features |= PPC_FEATURE_HAS_ALTIVEC; } +#endif /* CONFIG_ALTIVEC */ /* * Check for an SMT capable CPU and set the CPU feature. We do diff --git a/arch/ppc64/kernel/prom_init.c b/arch/ppc64/kernel/prom_init.c index e248a7950aeb..dbbe6c79d8da 100644 --- a/arch/ppc64/kernel/prom_init.c +++ b/arch/ppc64/kernel/prom_init.c @@ -1803,7 +1803,7 @@ static void __init fixup_device_tree(void) if (prom_getprop(u3, "device-rev", &u3_rev, sizeof(u3_rev)) == PROM_ERROR) return; - if (u3_rev != 0x35) + if (u3_rev != 0x35 && u3_rev != 0x37) return; /* does it need fixup ? */ if (prom_getproplen(i2c, "interrupts") > 0) diff --git a/arch/ppc64/kernel/setup.c b/arch/ppc64/kernel/setup.c index 687e85595208..e9c24d2dbd91 100644 --- a/arch/ppc64/kernel/setup.c +++ b/arch/ppc64/kernel/setup.c @@ -706,6 +706,8 @@ void machine_power_off(void) local_irq_disable(); while (1) ; } +/* Used by the G5 thermal driver */ +EXPORT_SYMBOL_GPL(machine_power_off); void machine_halt(void) { diff --git a/arch/ppc64/kernel/xics.c b/arch/ppc64/kernel/xics.c index 677c4450984a..d9dc6f28d050 100644 --- a/arch/ppc64/kernel/xics.c +++ b/arch/ppc64/kernel/xics.c @@ -647,29 +647,30 @@ static void xics_set_affinity(unsigned int virq, cpumask_t cpumask) } } -void xics_teardown_cpu(void) +void xics_teardown_cpu(int secondary) { int cpu = smp_processor_id(); - int status; ops->cppr_info(cpu, 0x00); iosync(); /* - * we need to EOI the IPI if we got here from kexec down IPI - * - * xics doesn't care if we duplicate an EOI as long as we - * don't EOI and raise priority. - * - * probably need to check all the other interrupts too - * should we be flagging idle loop instead? - * or creating some task to be scheduled? + * Some machines need to have at least one cpu in the GIQ, + * so leave the master cpu in the group. */ - ops->xirr_info_set(cpu, XICS_IPI); - - status = rtas_set_indicator(GLOBAL_INTERRUPT_QUEUE, - (1UL << interrupt_server_size) - 1 - default_distrib_server, 0); - WARN_ON(status != 0); + if (secondary) { + /* + * we need to EOI the IPI if we got here from kexec down IPI + * + * probably need to check all the other interrupts too + * should we be flagging idle loop instead? + * or creating some task to be scheduled? + */ + ops->xirr_info_set(cpu, XICS_IPI); + rtas_set_indicator(GLOBAL_INTERRUPT_QUEUE, + (1UL << interrupt_server_size) - 1 - + default_distrib_server, 0); + } } #ifdef CONFIG_HOTPLUG_CPU |