summaryrefslogtreecommitdiffstats
path: root/kernel/arch/powerpc
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/arch/powerpc')
-rw-r--r--kernel/arch/powerpc/boot/Makefile3
-rw-r--r--kernel/arch/powerpc/include/asm/pgtable-ppc64.h14
-rw-r--r--kernel/arch/powerpc/include/asm/rtas.h1
-rw-r--r--kernel/arch/powerpc/include/asm/switch_to.h1
-rw-r--r--kernel/arch/powerpc/kernel/eeh.c27
-rw-r--r--kernel/arch/powerpc/kernel/process.c3
-rw-r--r--kernel/arch/powerpc/kernel/rtas.c17
-rw-r--r--kernel/arch/powerpc/kvm/book3s_hv_rm_mmu.c18
-rw-r--r--kernel/arch/powerpc/kvm/book3s_hv_rmhandlers.S1
-rw-r--r--kernel/arch/powerpc/mm/hugepage-hash64.c3
-rw-r--r--kernel/arch/powerpc/platforms/pseries/ras.c3
-rw-r--r--kernel/arch/powerpc/platforms/pseries/setup.c5
12 files changed, 78 insertions, 18 deletions
diff --git a/kernel/arch/powerpc/boot/Makefile b/kernel/arch/powerpc/boot/Makefile
index 73eddda53..4eec430d8 100644
--- a/kernel/arch/powerpc/boot/Makefile
+++ b/kernel/arch/powerpc/boot/Makefile
@@ -28,6 +28,9 @@ BOOTCFLAGS += -m64
endif
ifdef CONFIG_CPU_BIG_ENDIAN
BOOTCFLAGS += -mbig-endian
+else
+BOOTCFLAGS += -mlittle-endian
+BOOTCFLAGS += $(call cc-option,-mabi=elfv2)
endif
BOOTAFLAGS := -D__ASSEMBLY__ $(BOOTCFLAGS) -traditional -nostdinc
diff --git a/kernel/arch/powerpc/include/asm/pgtable-ppc64.h b/kernel/arch/powerpc/include/asm/pgtable-ppc64.h
index 43e6ad424..88d27e325 100644
--- a/kernel/arch/powerpc/include/asm/pgtable-ppc64.h
+++ b/kernel/arch/powerpc/include/asm/pgtable-ppc64.h
@@ -135,7 +135,19 @@
#define pte_iterate_hashed_end() } while(0)
#ifdef CONFIG_PPC_HAS_HASH_64K
-#define pte_pagesize_index(mm, addr, pte) get_slice_psize(mm, addr)
+/*
+ * We expect this to be called only for user addresses or kernel virtual
+ * addresses other than the linear mapping.
+ */
+#define pte_pagesize_index(mm, addr, pte) \
+ ({ \
+ unsigned int psize; \
+ if (is_kernel_addr(addr)) \
+ psize = MMU_PAGE_4K; \
+ else \
+ psize = get_slice_psize(mm, addr); \
+ psize; \
+ })
#else
#define pte_pagesize_index(mm, addr, pte) MMU_PAGE_4K
#endif
diff --git a/kernel/arch/powerpc/include/asm/rtas.h b/kernel/arch/powerpc/include/asm/rtas.h
index 7a4ede16b..b77ef369c 100644
--- a/kernel/arch/powerpc/include/asm/rtas.h
+++ b/kernel/arch/powerpc/include/asm/rtas.h
@@ -343,6 +343,7 @@ extern void rtas_power_off(void);
extern void rtas_halt(void);
extern void rtas_os_term(char *str);
extern int rtas_get_sensor(int sensor, int index, int *state);
+extern int rtas_get_sensor_fast(int sensor, int index, int *state);
extern int rtas_get_power_level(int powerdomain, int *level);
extern int rtas_set_power_level(int powerdomain, int level, int *setlevel);
extern bool rtas_indicator_present(int token, int *maxindex);
diff --git a/kernel/arch/powerpc/include/asm/switch_to.h b/kernel/arch/powerpc/include/asm/switch_to.h
index 58abeda64..15cca17cb 100644
--- a/kernel/arch/powerpc/include/asm/switch_to.h
+++ b/kernel/arch/powerpc/include/asm/switch_to.h
@@ -29,6 +29,7 @@ static inline void save_early_sprs(struct thread_struct *prev) {}
extern void enable_kernel_fp(void);
extern void enable_kernel_altivec(void);
+extern void enable_kernel_vsx(void);
extern int emulate_altivec(struct pt_regs *);
extern void __giveup_vsx(struct task_struct *);
extern void giveup_vsx(struct task_struct *);
diff --git a/kernel/arch/powerpc/kernel/eeh.c b/kernel/arch/powerpc/kernel/eeh.c
index 9ee61d156..cb565ad0a 100644
--- a/kernel/arch/powerpc/kernel/eeh.c
+++ b/kernel/arch/powerpc/kernel/eeh.c
@@ -310,11 +310,26 @@ void eeh_slot_error_detail(struct eeh_pe *pe, int severity)
if (!(pe->type & EEH_PE_PHB)) {
if (eeh_has_flag(EEH_ENABLE_IO_FOR_LOG))
eeh_pci_enable(pe, EEH_OPT_THAW_MMIO);
+
+ /*
+ * The config space of some PCI devices can't be accessed
+ * when their PEs are in frozen state. Otherwise, fenced
+ * PHB might be seen. Those PEs are identified with flag
+ * EEH_PE_CFG_RESTRICTED, indicating EEH_PE_CFG_BLOCKED
+ * is set automatically when the PE is put to EEH_PE_ISOLATED.
+ *
+ * Restoring BARs possibly triggers PCI config access in
+ * (OPAL) firmware and then causes fenced PHB. If the
+ * PCI config is blocked with flag EEH_PE_CFG_BLOCKED, it's
+ * pointless to restore BARs and dump config space.
+ */
eeh_ops->configure_bridge(pe);
- eeh_pe_restore_bars(pe);
+ if (!(pe->state & EEH_PE_CFG_BLOCKED)) {
+ eeh_pe_restore_bars(pe);
- pci_regs_buf[0] = 0;
- eeh_pe_traverse(pe, eeh_dump_pe_log, &loglen);
+ pci_regs_buf[0] = 0;
+ eeh_pe_traverse(pe, eeh_dump_pe_log, &loglen);
+ }
}
eeh_ops->get_log(pe, severity, pci_regs_buf, loglen);
@@ -1118,9 +1133,6 @@ void eeh_add_device_late(struct pci_dev *dev)
return;
}
- if (eeh_has_flag(EEH_PROBE_MODE_DEV))
- eeh_ops->probe(pdn, NULL);
-
/*
* The EEH cache might not be removed correctly because of
* unbalanced kref to the device during unplug time, which
@@ -1144,6 +1156,9 @@ void eeh_add_device_late(struct pci_dev *dev)
dev->dev.archdata.edev = NULL;
}
+ if (eeh_has_flag(EEH_PROBE_MODE_DEV))
+ eeh_ops->probe(pdn, NULL);
+
edev->pdev = dev;
dev->dev.archdata.edev = edev;
diff --git a/kernel/arch/powerpc/kernel/process.c b/kernel/arch/powerpc/kernel/process.c
index febb50dd5..0596373cd 100644
--- a/kernel/arch/powerpc/kernel/process.c
+++ b/kernel/arch/powerpc/kernel/process.c
@@ -204,8 +204,6 @@ EXPORT_SYMBOL_GPL(flush_altivec_to_thread);
#endif /* CONFIG_ALTIVEC */
#ifdef CONFIG_VSX
-#if 0
-/* not currently used, but some crazy RAID module might want to later */
void enable_kernel_vsx(void)
{
WARN_ON(preemptible());
@@ -220,7 +218,6 @@ void enable_kernel_vsx(void)
#endif /* CONFIG_SMP */
}
EXPORT_SYMBOL(enable_kernel_vsx);
-#endif
void giveup_vsx(struct task_struct *tsk)
{
diff --git a/kernel/arch/powerpc/kernel/rtas.c b/kernel/arch/powerpc/kernel/rtas.c
index 7a488c108..caffb10e7 100644
--- a/kernel/arch/powerpc/kernel/rtas.c
+++ b/kernel/arch/powerpc/kernel/rtas.c
@@ -584,6 +584,23 @@ int rtas_get_sensor(int sensor, int index, int *state)
}
EXPORT_SYMBOL(rtas_get_sensor);
+int rtas_get_sensor_fast(int sensor, int index, int *state)
+{
+ int token = rtas_token("get-sensor-state");
+ int rc;
+
+ if (token == RTAS_UNKNOWN_SERVICE)
+ return -ENOENT;
+
+ rc = rtas_call(token, 2, 2, state, sensor, index);
+ WARN_ON(rc == RTAS_BUSY || (rc >= RTAS_EXTENDED_DELAY_MIN &&
+ rc <= RTAS_EXTENDED_DELAY_MAX));
+
+ if (rc < 0)
+ return rtas_error_rc(rc);
+ return rc;
+}
+
bool rtas_indicator_present(int token, int *maxindex)
{
int proplen, count, i;
diff --git a/kernel/arch/powerpc/kvm/book3s_hv_rm_mmu.c b/kernel/arch/powerpc/kvm/book3s_hv_rm_mmu.c
index b027a8973..c6d601cc9 100644
--- a/kernel/arch/powerpc/kvm/book3s_hv_rm_mmu.c
+++ b/kernel/arch/powerpc/kvm/book3s_hv_rm_mmu.c
@@ -421,14 +421,20 @@ long kvmppc_do_h_remove(struct kvm *kvm, unsigned long flags,
rev = real_vmalloc_addr(&kvm->arch.revmap[pte_index]);
v = pte & ~HPTE_V_HVLOCK;
if (v & HPTE_V_VALID) {
- u64 pte1;
-
- pte1 = be64_to_cpu(hpte[1]);
hpte[0] &= ~cpu_to_be64(HPTE_V_VALID);
- rb = compute_tlbie_rb(v, pte1, pte_index);
+ rb = compute_tlbie_rb(v, be64_to_cpu(hpte[1]), pte_index);
do_tlbies(kvm, &rb, 1, global_invalidates(kvm, flags), true);
- /* Read PTE low word after tlbie to get final R/C values */
- remove_revmap_chain(kvm, pte_index, rev, v, pte1);
+ /*
+ * The reference (R) and change (C) bits in a HPT
+ * entry can be set by hardware at any time up until
+ * the HPTE is invalidated and the TLB invalidation
+ * sequence has completed. This means that when
+ * removing a HPTE, we need to re-read the HPTE after
+ * the invalidation sequence has completed in order to
+ * obtain reliable values of R and C.
+ */
+ remove_revmap_chain(kvm, pte_index, rev, v,
+ be64_to_cpu(hpte[1]));
}
r = rev->guest_rpte & ~HPTE_GR_RESERVED;
note_hpte_modification(kvm, rev);
diff --git a/kernel/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/kernel/arch/powerpc/kvm/book3s_hv_rmhandlers.S
index 4d70df26c..3b2d2c5b6 100644
--- a/kernel/arch/powerpc/kvm/book3s_hv_rmhandlers.S
+++ b/kernel/arch/powerpc/kvm/book3s_hv_rmhandlers.S
@@ -1127,6 +1127,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
cmpwi r12, BOOK3S_INTERRUPT_H_DOORBELL
bne 3f
lbz r0, HSTATE_HOST_IPI(r13)
+ cmpwi r0, 0
beq 4f
b guest_exit_cont
3:
diff --git a/kernel/arch/powerpc/mm/hugepage-hash64.c b/kernel/arch/powerpc/mm/hugepage-hash64.c
index 43dafb9d6..4d87122cf 100644
--- a/kernel/arch/powerpc/mm/hugepage-hash64.c
+++ b/kernel/arch/powerpc/mm/hugepage-hash64.c
@@ -85,7 +85,6 @@ int __hash_page_thp(unsigned long ea, unsigned long access, unsigned long vsid,
BUG_ON(index >= 4096);
vpn = hpt_vpn(ea, vsid, ssize);
- hash = hpt_hash(vpn, shift, ssize);
hpte_slot_array = get_hpte_slot_array(pmdp);
if (psize == MMU_PAGE_4K) {
/*
@@ -101,6 +100,7 @@ int __hash_page_thp(unsigned long ea, unsigned long access, unsigned long vsid,
valid = hpte_valid(hpte_slot_array, index);
if (valid) {
/* update the hpte bits */
+ hash = hpt_hash(vpn, shift, ssize);
hidx = hpte_hash_index(hpte_slot_array, index);
if (hidx & _PTEIDX_SECONDARY)
hash = ~hash;
@@ -126,6 +126,7 @@ int __hash_page_thp(unsigned long ea, unsigned long access, unsigned long vsid,
if (!valid) {
unsigned long hpte_group;
+ hash = hpt_hash(vpn, shift, ssize);
/* insert new entry */
pa = pmd_pfn(__pmd(old_pmd)) << PAGE_SHIFT;
new_pmd |= _PAGE_HASHPTE;
diff --git a/kernel/arch/powerpc/platforms/pseries/ras.c b/kernel/arch/powerpc/platforms/pseries/ras.c
index 02e4a1745..3b6647e57 100644
--- a/kernel/arch/powerpc/platforms/pseries/ras.c
+++ b/kernel/arch/powerpc/platforms/pseries/ras.c
@@ -189,7 +189,8 @@ static irqreturn_t ras_epow_interrupt(int irq, void *dev_id)
int state;
int critical;
- status = rtas_get_sensor(EPOW_SENSOR_TOKEN, EPOW_SENSOR_INDEX, &state);
+ status = rtas_get_sensor_fast(EPOW_SENSOR_TOKEN, EPOW_SENSOR_INDEX,
+ &state);
if (state > 3)
critical = 1; /* Time Critical */
diff --git a/kernel/arch/powerpc/platforms/pseries/setup.c b/kernel/arch/powerpc/platforms/pseries/setup.c
index df6a70419..e6e8b241d 100644
--- a/kernel/arch/powerpc/platforms/pseries/setup.c
+++ b/kernel/arch/powerpc/platforms/pseries/setup.c
@@ -268,6 +268,11 @@ static int pci_dn_reconfig_notifier(struct notifier_block *nb, unsigned long act
eeh_dev_init(PCI_DN(np), pci->phb);
}
break;
+ case OF_RECONFIG_DETACH_NODE:
+ pci = PCI_DN(np);
+ if (pci)
+ list_del(&pci->list);
+ break;
default:
err = NOTIFY_DONE;
break;