Commit f2a77abd authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc

Pull powerpc fixes from Ben Herrenschmidt:
 "Here are some more powerpc fixes for 3.14

  The main one is a nasty issue with the NUMA balancing support which
  requires a small generic change and the addition of a new accessor to
  set _PAGE_NUMA.  Both have been reviewed and acked by Mel and Rik.

  The changelog should have plenty of details but basically, without
  this fix, we get random user segfaults and/or corruptions due to
  missing TLB/hash flushes.  Aneesh series of 3 patches fixes it.

  We have some vDSO vs.  perf fixes from Anton, some small EEH fixes
  from Gavin, a ppc32 regression vs the stack overflow detector, and a
  fix for the way we handle PCIe host bridge speed settings on pseries
  (which is needed for proper operations of AMD graphics cards on
  Power8)"

* 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc:
  powerpc/eeh: Disable EEH on reboot
  powerpc/eeh: Cleanup on eeh_subsystem_enabled
  powerpc/powernv: Rework EEH reset
  powerpc: Use unstripped VDSO image for more accurate profiling data
  powerpc: Link VDSOs at 0x0
  mm: Use ptep/pmdp_set_numa() for updating _PAGE_NUMA bit
  mm: Dirty accountable change only apply to non prot numa case
  powerpc/mm: Add new "set" flag argument to pte/pmd update function
  powerpc/pseries: Add Gen3 definitions for PCIE link speed
  powerpc/pseries: Fix regression on PCI link speed
  powerpc: Set the correct ksp_limit on ppc32 when switching to irq stack
parents e4178d80 66f9af83
...@@ -172,10 +172,20 @@ struct eeh_ops { ...@@ -172,10 +172,20 @@ struct eeh_ops {
}; };
extern struct eeh_ops *eeh_ops; extern struct eeh_ops *eeh_ops;
extern int eeh_subsystem_enabled; extern bool eeh_subsystem_enabled;
extern raw_spinlock_t confirm_error_lock; extern raw_spinlock_t confirm_error_lock;
extern int eeh_probe_mode; extern int eeh_probe_mode;
static inline bool eeh_enabled(void)
{
return eeh_subsystem_enabled;
}
static inline void eeh_set_enable(bool mode)
{
eeh_subsystem_enabled = mode;
}
#define EEH_PROBE_MODE_DEV (1<<0) /* From PCI device */ #define EEH_PROBE_MODE_DEV (1<<0) /* From PCI device */
#define EEH_PROBE_MODE_DEVTREE (1<<1) /* From device tree */ #define EEH_PROBE_MODE_DEVTREE (1<<1) /* From device tree */
...@@ -246,7 +256,7 @@ void eeh_remove_device(struct pci_dev *); ...@@ -246,7 +256,7 @@ void eeh_remove_device(struct pci_dev *);
* If this macro yields TRUE, the caller relays to eeh_check_failure() * If this macro yields TRUE, the caller relays to eeh_check_failure()
* which does further tests out of line. * which does further tests out of line.
*/ */
#define EEH_POSSIBLE_ERROR(val, type) ((val) == (type)~0 && eeh_subsystem_enabled) #define EEH_POSSIBLE_ERROR(val, type) ((val) == (type)~0 && eeh_enabled())
/* /*
* Reads from a device which has been isolated by EEH will return * Reads from a device which has been isolated by EEH will return
...@@ -257,6 +267,13 @@ void eeh_remove_device(struct pci_dev *); ...@@ -257,6 +267,13 @@ void eeh_remove_device(struct pci_dev *);
#else /* !CONFIG_EEH */ #else /* !CONFIG_EEH */
static inline bool eeh_enabled(void)
{
return false;
}
static inline void eeh_set_enable(bool mode) { }
static inline int eeh_init(void) static inline int eeh_init(void)
{ {
return 0; return 0;
......
...@@ -127,7 +127,7 @@ static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm, ...@@ -127,7 +127,7 @@ static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
unsigned long addr, pte_t *ptep) unsigned long addr, pte_t *ptep)
{ {
#ifdef CONFIG_PPC64 #ifdef CONFIG_PPC64
return __pte(pte_update(mm, addr, ptep, ~0UL, 1)); return __pte(pte_update(mm, addr, ptep, ~0UL, 0, 1));
#else #else
return __pte(pte_update(ptep, ~0UL, 0)); return __pte(pte_update(ptep, ~0UL, 0));
#endif #endif
......
...@@ -195,6 +195,7 @@ extern void hpte_need_flush(struct mm_struct *mm, unsigned long addr, ...@@ -195,6 +195,7 @@ extern void hpte_need_flush(struct mm_struct *mm, unsigned long addr,
static inline unsigned long pte_update(struct mm_struct *mm, static inline unsigned long pte_update(struct mm_struct *mm,
unsigned long addr, unsigned long addr,
pte_t *ptep, unsigned long clr, pte_t *ptep, unsigned long clr,
unsigned long set,
int huge) int huge)
{ {
#ifdef PTE_ATOMIC_UPDATES #ifdef PTE_ATOMIC_UPDATES
...@@ -205,14 +206,15 @@ static inline unsigned long pte_update(struct mm_struct *mm, ...@@ -205,14 +206,15 @@ static inline unsigned long pte_update(struct mm_struct *mm,
andi. %1,%0,%6\n\ andi. %1,%0,%6\n\
bne- 1b \n\ bne- 1b \n\
andc %1,%0,%4 \n\ andc %1,%0,%4 \n\
or %1,%1,%7\n\
stdcx. %1,0,%3 \n\ stdcx. %1,0,%3 \n\
bne- 1b" bne- 1b"
: "=&r" (old), "=&r" (tmp), "=m" (*ptep) : "=&r" (old), "=&r" (tmp), "=m" (*ptep)
: "r" (ptep), "r" (clr), "m" (*ptep), "i" (_PAGE_BUSY) : "r" (ptep), "r" (clr), "m" (*ptep), "i" (_PAGE_BUSY), "r" (set)
: "cc" ); : "cc" );
#else #else
unsigned long old = pte_val(*ptep); unsigned long old = pte_val(*ptep);
*ptep = __pte(old & ~clr); *ptep = __pte((old & ~clr) | set);
#endif #endif
/* huge pages use the old page table lock */ /* huge pages use the old page table lock */
if (!huge) if (!huge)
...@@ -233,7 +235,7 @@ static inline int __ptep_test_and_clear_young(struct mm_struct *mm, ...@@ -233,7 +235,7 @@ static inline int __ptep_test_and_clear_young(struct mm_struct *mm,
if ((pte_val(*ptep) & (_PAGE_ACCESSED | _PAGE_HASHPTE)) == 0) if ((pte_val(*ptep) & (_PAGE_ACCESSED | _PAGE_HASHPTE)) == 0)
return 0; return 0;
old = pte_update(mm, addr, ptep, _PAGE_ACCESSED, 0); old = pte_update(mm, addr, ptep, _PAGE_ACCESSED, 0, 0);
return (old & _PAGE_ACCESSED) != 0; return (old & _PAGE_ACCESSED) != 0;
} }
#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
...@@ -252,7 +254,7 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, ...@@ -252,7 +254,7 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
if ((pte_val(*ptep) & _PAGE_RW) == 0) if ((pte_val(*ptep) & _PAGE_RW) == 0)
return; return;
pte_update(mm, addr, ptep, _PAGE_RW, 0); pte_update(mm, addr, ptep, _PAGE_RW, 0, 0);
} }
static inline void huge_ptep_set_wrprotect(struct mm_struct *mm, static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
...@@ -261,7 +263,7 @@ static inline void huge_ptep_set_wrprotect(struct mm_struct *mm, ...@@ -261,7 +263,7 @@ static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
if ((pte_val(*ptep) & _PAGE_RW) == 0) if ((pte_val(*ptep) & _PAGE_RW) == 0)
return; return;
pte_update(mm, addr, ptep, _PAGE_RW, 1); pte_update(mm, addr, ptep, _PAGE_RW, 0, 1);
} }
/* /*
...@@ -284,14 +286,14 @@ static inline void huge_ptep_set_wrprotect(struct mm_struct *mm, ...@@ -284,14 +286,14 @@ static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
static inline pte_t ptep_get_and_clear(struct mm_struct *mm, static inline pte_t ptep_get_and_clear(struct mm_struct *mm,
unsigned long addr, pte_t *ptep) unsigned long addr, pte_t *ptep)
{ {
unsigned long old = pte_update(mm, addr, ptep, ~0UL, 0); unsigned long old = pte_update(mm, addr, ptep, ~0UL, 0, 0);
return __pte(old); return __pte(old);
} }
static inline void pte_clear(struct mm_struct *mm, unsigned long addr, static inline void pte_clear(struct mm_struct *mm, unsigned long addr,
pte_t * ptep) pte_t * ptep)
{ {
pte_update(mm, addr, ptep, ~0UL, 0); pte_update(mm, addr, ptep, ~0UL, 0, 0);
} }
...@@ -506,7 +508,9 @@ extern int pmdp_set_access_flags(struct vm_area_struct *vma, ...@@ -506,7 +508,9 @@ extern int pmdp_set_access_flags(struct vm_area_struct *vma,
extern unsigned long pmd_hugepage_update(struct mm_struct *mm, extern unsigned long pmd_hugepage_update(struct mm_struct *mm,
unsigned long addr, unsigned long addr,
pmd_t *pmdp, unsigned long clr); pmd_t *pmdp,
unsigned long clr,
unsigned long set);
static inline int __pmdp_test_and_clear_young(struct mm_struct *mm, static inline int __pmdp_test_and_clear_young(struct mm_struct *mm,
unsigned long addr, pmd_t *pmdp) unsigned long addr, pmd_t *pmdp)
...@@ -515,7 +519,7 @@ static inline int __pmdp_test_and_clear_young(struct mm_struct *mm, ...@@ -515,7 +519,7 @@ static inline int __pmdp_test_and_clear_young(struct mm_struct *mm,
if ((pmd_val(*pmdp) & (_PAGE_ACCESSED | _PAGE_HASHPTE)) == 0) if ((pmd_val(*pmdp) & (_PAGE_ACCESSED | _PAGE_HASHPTE)) == 0)
return 0; return 0;
old = pmd_hugepage_update(mm, addr, pmdp, _PAGE_ACCESSED); old = pmd_hugepage_update(mm, addr, pmdp, _PAGE_ACCESSED, 0);
return ((old & _PAGE_ACCESSED) != 0); return ((old & _PAGE_ACCESSED) != 0);
} }
...@@ -542,7 +546,7 @@ static inline void pmdp_set_wrprotect(struct mm_struct *mm, unsigned long addr, ...@@ -542,7 +546,7 @@ static inline void pmdp_set_wrprotect(struct mm_struct *mm, unsigned long addr,
if ((pmd_val(*pmdp) & _PAGE_RW) == 0) if ((pmd_val(*pmdp) & _PAGE_RW) == 0)
return; return;
pmd_hugepage_update(mm, addr, pmdp, _PAGE_RW); pmd_hugepage_update(mm, addr, pmdp, _PAGE_RW, 0);
} }
#define __HAVE_ARCH_PMDP_SPLITTING_FLUSH #define __HAVE_ARCH_PMDP_SPLITTING_FLUSH
......
...@@ -75,12 +75,34 @@ static inline pte_t pte_mknuma(pte_t pte) ...@@ -75,12 +75,34 @@ static inline pte_t pte_mknuma(pte_t pte)
return pte; return pte;
} }
#define ptep_set_numa ptep_set_numa
static inline void ptep_set_numa(struct mm_struct *mm, unsigned long addr,
pte_t *ptep)
{
if ((pte_val(*ptep) & _PAGE_PRESENT) == 0)
VM_BUG_ON(1);
pte_update(mm, addr, ptep, _PAGE_PRESENT, _PAGE_NUMA, 0);
return;
}
#define pmd_numa pmd_numa #define pmd_numa pmd_numa
static inline int pmd_numa(pmd_t pmd) static inline int pmd_numa(pmd_t pmd)
{ {
return pte_numa(pmd_pte(pmd)); return pte_numa(pmd_pte(pmd));
} }
#define pmdp_set_numa pmdp_set_numa
static inline void pmdp_set_numa(struct mm_struct *mm, unsigned long addr,
pmd_t *pmdp)
{
if ((pmd_val(*pmdp) & _PAGE_PRESENT) == 0)
VM_BUG_ON(1);
pmd_hugepage_update(mm, addr, pmdp, _PAGE_PRESENT, _PAGE_NUMA);
return;
}
#define pmd_mknonnuma pmd_mknonnuma #define pmd_mknonnuma pmd_mknonnuma
static inline pmd_t pmd_mknonnuma(pmd_t pmd) static inline pmd_t pmd_mknonnuma(pmd_t pmd)
{ {
......
...@@ -4,11 +4,11 @@ ...@@ -4,11 +4,11 @@
#ifdef __KERNEL__ #ifdef __KERNEL__
/* Default link addresses for the vDSOs */ /* Default link addresses for the vDSOs */
#define VDSO32_LBASE 0x100000 #define VDSO32_LBASE 0x0
#define VDSO64_LBASE 0x100000 #define VDSO64_LBASE 0x0
/* Default map addresses for 32bit vDSO */ /* Default map addresses for 32bit vDSO */
#define VDSO32_MBASE VDSO32_LBASE #define VDSO32_MBASE 0x100000
#define VDSO_VERSION_STRING LINUX_2.6.15 #define VDSO_VERSION_STRING LINUX_2.6.15
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/rbtree.h> #include <linux/rbtree.h>
#include <linux/reboot.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/export.h> #include <linux/export.h>
...@@ -89,7 +90,7 @@ ...@@ -89,7 +90,7 @@
/* Platform dependent EEH operations */ /* Platform dependent EEH operations */
struct eeh_ops *eeh_ops = NULL; struct eeh_ops *eeh_ops = NULL;
int eeh_subsystem_enabled; bool eeh_subsystem_enabled = false;
EXPORT_SYMBOL(eeh_subsystem_enabled); EXPORT_SYMBOL(eeh_subsystem_enabled);
/* /*
...@@ -364,7 +365,7 @@ int eeh_dev_check_failure(struct eeh_dev *edev) ...@@ -364,7 +365,7 @@ int eeh_dev_check_failure(struct eeh_dev *edev)
eeh_stats.total_mmio_ffs++; eeh_stats.total_mmio_ffs++;
if (!eeh_subsystem_enabled) if (!eeh_enabled())
return 0; return 0;
if (!edev) { if (!edev) {
...@@ -747,6 +748,17 @@ int __exit eeh_ops_unregister(const char *name) ...@@ -747,6 +748,17 @@ int __exit eeh_ops_unregister(const char *name)
return -EEXIST; return -EEXIST;
} }
static int eeh_reboot_notifier(struct notifier_block *nb,
unsigned long action, void *unused)
{
eeh_set_enable(false);
return NOTIFY_DONE;
}
static struct notifier_block eeh_reboot_nb = {
.notifier_call = eeh_reboot_notifier,
};
/** /**
* eeh_init - EEH initialization * eeh_init - EEH initialization
* *
...@@ -778,6 +790,14 @@ int eeh_init(void) ...@@ -778,6 +790,14 @@ int eeh_init(void)
if (machine_is(powernv) && cnt++ <= 0) if (machine_is(powernv) && cnt++ <= 0)
return ret; return ret;
/* Register reboot notifier */
ret = register_reboot_notifier(&eeh_reboot_nb);
if (ret) {
pr_warn("%s: Failed to register notifier (%d)\n",
__func__, ret);
return ret;
}
/* call platform initialization function */ /* call platform initialization function */
if (!eeh_ops) { if (!eeh_ops) {
pr_warning("%s: Platform EEH operation not found\n", pr_warning("%s: Platform EEH operation not found\n",
...@@ -822,7 +842,7 @@ int eeh_init(void) ...@@ -822,7 +842,7 @@ int eeh_init(void)
return ret; return ret;
} }
if (eeh_subsystem_enabled) if (eeh_enabled())
pr_info("EEH: PCI Enhanced I/O Error Handling Enabled\n"); pr_info("EEH: PCI Enhanced I/O Error Handling Enabled\n");
else else
pr_warning("EEH: No capable adapters found\n"); pr_warning("EEH: No capable adapters found\n");
...@@ -897,7 +917,7 @@ void eeh_add_device_late(struct pci_dev *dev) ...@@ -897,7 +917,7 @@ void eeh_add_device_late(struct pci_dev *dev)
struct device_node *dn; struct device_node *dn;
struct eeh_dev *edev; struct eeh_dev *edev;
if (!dev || !eeh_subsystem_enabled) if (!dev || !eeh_enabled())
return; return;
pr_debug("EEH: Adding device %s\n", pci_name(dev)); pr_debug("EEH: Adding device %s\n", pci_name(dev));
...@@ -1005,7 +1025,7 @@ void eeh_remove_device(struct pci_dev *dev) ...@@ -1005,7 +1025,7 @@ void eeh_remove_device(struct pci_dev *dev)
{ {
struct eeh_dev *edev; struct eeh_dev *edev;
if (!dev || !eeh_subsystem_enabled) if (!dev || !eeh_enabled())
return; return;
edev = pci_dev_to_eeh_dev(dev); edev = pci_dev_to_eeh_dev(dev);
...@@ -1045,7 +1065,7 @@ void eeh_remove_device(struct pci_dev *dev) ...@@ -1045,7 +1065,7 @@ void eeh_remove_device(struct pci_dev *dev)
static int proc_eeh_show(struct seq_file *m, void *v) static int proc_eeh_show(struct seq_file *m, void *v)
{ {
if (0 == eeh_subsystem_enabled) { if (!eeh_enabled()) {
seq_printf(m, "EEH Subsystem is globally disabled\n"); seq_printf(m, "EEH Subsystem is globally disabled\n");
seq_printf(m, "eeh_total_mmio_ffs=%llu\n", eeh_stats.total_mmio_ffs); seq_printf(m, "eeh_total_mmio_ffs=%llu\n", eeh_stats.total_mmio_ffs);
} else { } else {
......
...@@ -57,11 +57,14 @@ _GLOBAL(call_do_softirq) ...@@ -57,11 +57,14 @@ _GLOBAL(call_do_softirq)
mtlr r0 mtlr r0
blr blr
/*
* void call_do_irq(struct pt_regs *regs, struct thread_info *irqtp);
*/
_GLOBAL(call_do_irq) _GLOBAL(call_do_irq)
mflr r0 mflr r0
stw r0,4(r1) stw r0,4(r1)
lwz r10,THREAD+KSP_LIMIT(r2) lwz r10,THREAD+KSP_LIMIT(r2)
addi r11,r3,THREAD_INFO_GAP addi r11,r4,THREAD_INFO_GAP
stwu r1,THREAD_SIZE-STACK_FRAME_OVERHEAD(r4) stwu r1,THREAD_SIZE-STACK_FRAME_OVERHEAD(r4)
mr r1,r4 mr r1,r4
stw r10,8(r1) stw r10,8(r1)
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
.globl vdso32_start, vdso32_end .globl vdso32_start, vdso32_end
.balign PAGE_SIZE .balign PAGE_SIZE
vdso32_start: vdso32_start:
.incbin "arch/powerpc/kernel/vdso32/vdso32.so" .incbin "arch/powerpc/kernel/vdso32/vdso32.so.dbg"
.balign PAGE_SIZE .balign PAGE_SIZE
vdso32_end: vdso32_end:
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
.globl vdso64_start, vdso64_end .globl vdso64_start, vdso64_end
.balign PAGE_SIZE .balign PAGE_SIZE
vdso64_start: vdso64_start:
.incbin "arch/powerpc/kernel/vdso64/vdso64.so" .incbin "arch/powerpc/kernel/vdso64/vdso64.so.dbg"
.balign PAGE_SIZE .balign PAGE_SIZE
vdso64_end: vdso64_end:
......
...@@ -510,7 +510,8 @@ int pmdp_set_access_flags(struct vm_area_struct *vma, unsigned long address, ...@@ -510,7 +510,8 @@ int pmdp_set_access_flags(struct vm_area_struct *vma, unsigned long address,
} }
unsigned long pmd_hugepage_update(struct mm_struct *mm, unsigned long addr, unsigned long pmd_hugepage_update(struct mm_struct *mm, unsigned long addr,
pmd_t *pmdp, unsigned long clr) pmd_t *pmdp, unsigned long clr,
unsigned long set)
{ {
unsigned long old, tmp; unsigned long old, tmp;
...@@ -526,14 +527,15 @@ unsigned long pmd_hugepage_update(struct mm_struct *mm, unsigned long addr, ...@@ -526,14 +527,15 @@ unsigned long pmd_hugepage_update(struct mm_struct *mm, unsigned long addr,
andi. %1,%0,%6\n\ andi. %1,%0,%6\n\
bne- 1b \n\ bne- 1b \n\
andc %1,%0,%4 \n\ andc %1,%0,%4 \n\
or %1,%1,%7\n\
stdcx. %1,0,%3 \n\ stdcx. %1,0,%3 \n\
bne- 1b" bne- 1b"
: "=&r" (old), "=&r" (tmp), "=m" (*pmdp) : "=&r" (old), "=&r" (tmp), "=m" (*pmdp)
: "r" (pmdp), "r" (clr), "m" (*pmdp), "i" (_PAGE_BUSY) : "r" (pmdp), "r" (clr), "m" (*pmdp), "i" (_PAGE_BUSY), "r" (set)
: "cc" ); : "cc" );
#else #else
old = pmd_val(*pmdp); old = pmd_val(*pmdp);
*pmdp = __pmd(old & ~clr); *pmdp = __pmd((old & ~clr) | set);
#endif #endif
if (old & _PAGE_HASHPTE) if (old & _PAGE_HASHPTE)
hpte_do_hugepage_flush(mm, addr, pmdp); hpte_do_hugepage_flush(mm, addr, pmdp);
...@@ -708,7 +710,7 @@ void set_pmd_at(struct mm_struct *mm, unsigned long addr, ...@@ -708,7 +710,7 @@ void set_pmd_at(struct mm_struct *mm, unsigned long addr,
void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address, void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address,
pmd_t *pmdp) pmd_t *pmdp)
{ {
pmd_hugepage_update(vma->vm_mm, address, pmdp, _PAGE_PRESENT); pmd_hugepage_update(vma->vm_mm, address, pmdp, _PAGE_PRESENT, 0);
} }
/* /*
...@@ -835,7 +837,7 @@ pmd_t pmdp_get_and_clear(struct mm_struct *mm, ...@@ -835,7 +837,7 @@ pmd_t pmdp_get_and_clear(struct mm_struct *mm,
unsigned long old; unsigned long old;
pgtable_t *pgtable_slot; pgtable_t *pgtable_slot;
old = pmd_hugepage_update(mm, addr, pmdp, ~0UL); old = pmd_hugepage_update(mm, addr, pmdp, ~0UL, 0);
old_pmd = __pmd(old); old_pmd = __pmd(old);
/* /*
* We have pmd == none and we are holding page_table_lock. * We have pmd == none and we are holding page_table_lock.
......
...@@ -78,7 +78,7 @@ static void hpte_flush_range(struct mm_struct *mm, unsigned long addr, ...@@ -78,7 +78,7 @@ static void hpte_flush_range(struct mm_struct *mm, unsigned long addr,
pte = pte_offset_map_lock(mm, pmd, addr, &ptl); pte = pte_offset_map_lock(mm, pmd, addr, &ptl);
arch_enter_lazy_mmu_mode(); arch_enter_lazy_mmu_mode();
for (; npages > 0; --npages) { for (; npages > 0; --npages) {
pte_update(mm, addr, pte, 0, 0); pte_update(mm, addr, pte, 0, 0, 0);
addr += PAGE_SIZE; addr += PAGE_SIZE;
++pte; ++pte;
} }
......
...@@ -44,7 +44,8 @@ static int ioda_eeh_event(struct notifier_block *nb, ...@@ -44,7 +44,8 @@ static int ioda_eeh_event(struct notifier_block *nb,
/* We simply send special EEH event */ /* We simply send special EEH event */
if ((changed_evts & OPAL_EVENT_PCI_ERROR) && if ((changed_evts & OPAL_EVENT_PCI_ERROR) &&
(events & OPAL_EVENT_PCI_ERROR)) (events & OPAL_EVENT_PCI_ERROR) &&
eeh_enabled())
eeh_send_failure_event(NULL); eeh_send_failure_event(NULL);
return 0; return 0;
...@@ -489,8 +490,7 @@ static int ioda_eeh_bridge_reset(struct pci_controller *hose, ...@@ -489,8 +490,7 @@ static int ioda_eeh_bridge_reset(struct pci_controller *hose,
static int ioda_eeh_reset(struct eeh_pe *pe, int option) static int ioda_eeh_reset(struct eeh_pe *pe, int option)
{ {
struct pci_controller *hose = pe->phb; struct pci_controller *hose = pe->phb;
struct eeh_dev *edev; struct pci_bus *bus;
struct pci_dev *dev;
int ret; int ret;
/* /*
...@@ -519,31 +519,11 @@ static int ioda_eeh_reset(struct eeh_pe *pe, int option) ...@@ -519,31 +519,11 @@ static int ioda_eeh_reset(struct eeh_pe *pe, int option)
if (pe->type & EEH_PE_PHB) { if (pe->type & EEH_PE_PHB) {
ret = ioda_eeh_phb_reset(hose, option); ret = ioda_eeh_phb_reset(hose, option);
} else { } else {
if (pe->type & EEH_PE_DEVICE) { bus = eeh_pe_bus_get(pe);
/* if (pci_is_root_bus(bus))
* If it's device PE, we didn't refer to the parent
* PCI bus yet. So we have to figure it out indirectly.
*/
edev = list_first_entry(&pe->edevs,
struct eeh_dev, list);
dev = eeh_dev_to_pci_dev(edev);
dev = dev->bus->self;
} else {
/*
* If it's bus PE, the parent PCI bus is already there
* and just pick it up.
*/
dev = pe->bus->self;
}
/*
* Do reset based on the fact that the direct upstream bridge
* is root bridge (port) or not.
*/
if (dev->bus->number == 0)
ret = ioda_eeh_root_reset(hose, option); ret = ioda_eeh_root_reset(hose, option);
else else
ret = ioda_eeh_bridge_reset(hose, dev, option); ret = ioda_eeh_bridge_reset(hose, bus->self, option);
} }
return ret; return ret;
......
...@@ -145,7 +145,7 @@ static int powernv_eeh_dev_probe(struct pci_dev *dev, void *flag) ...@@ -145,7 +145,7 @@ static int powernv_eeh_dev_probe(struct pci_dev *dev, void *flag)
* Enable EEH explicitly so that we will do EEH check * Enable EEH explicitly so that we will do EEH check
* while accessing I/O stuff * while accessing I/O stuff
*/ */
eeh_subsystem_enabled = 1; eeh_set_enable(true);
/* Save memory bars */ /* Save memory bars */
eeh_save_bars(edev); eeh_save_bars(edev);
......
...@@ -265,7 +265,7 @@ static void *pseries_eeh_of_probe(struct device_node *dn, void *flag) ...@@ -265,7 +265,7 @@ static void *pseries_eeh_of_probe(struct device_node *dn, void *flag)
enable = 1; enable = 1;
if (enable) { if (enable) {
eeh_subsystem_enabled = 1; eeh_set_enable(true);
eeh_add_to_parent_pe(edev); eeh_add_to_parent_pe(edev);
pr_debug("%s: EEH enabled on %s PHB#%d-PE#%x, config addr#%x\n", pr_debug("%s: EEH enabled on %s PHB#%d-PE#%x, config addr#%x\n",
......
...@@ -113,7 +113,8 @@ int pseries_root_bridge_prepare(struct pci_host_bridge *bridge) ...@@ -113,7 +113,8 @@ int pseries_root_bridge_prepare(struct pci_host_bridge *bridge)
{ {
struct device_node *dn, *pdn; struct device_node *dn, *pdn;
struct pci_bus *bus; struct pci_bus *bus;
const __be32 *pcie_link_speed_stats; u32 pcie_link_speed_stats[2];
int rc;
bus = bridge->bus; bus = bridge->bus;
...@@ -122,38 +123,45 @@ int pseries_root_bridge_prepare(struct pci_host_bridge *bridge) ...@@ -122,38 +123,45 @@ int pseries_root_bridge_prepare(struct pci_host_bridge *bridge)
return 0; return 0;
for (pdn = dn; pdn != NULL; pdn = of_get_next_parent(pdn)) { for (pdn = dn; pdn != NULL; pdn = of_get_next_parent(pdn)) {
pcie_link_speed_stats = of_get_property(pdn, rc = of_property_read_u32_array(pdn,
"ibm,pcie-link-speed-stats", NULL); "ibm,pcie-link-speed-stats",
if (pcie_link_speed_stats) &pcie_link_speed_stats[0], 2);
if (!rc)
break; break;
} }
of_node_put(pdn); of_node_put(pdn);
if (!pcie_link_speed_stats) { if (rc) {
pr_err("no ibm,pcie-link-speed-stats property\n"); pr_err("no ibm,pcie-link-speed-stats property\n");
return 0; return 0;
} }
switch (be32_to_cpup(pcie_link_speed_stats)) { switch (pcie_link_speed_stats[0]) {
case 0x01: case 0x01:
bus->max_bus_speed = PCIE_SPEED_2_5GT; bus->max_bus_speed = PCIE_SPEED_2_5GT;
break; break;
case 0x02: case 0x02:
bus->max_bus_speed = PCIE_SPEED_5_0GT; bus->max_bus_speed = PCIE_SPEED_5_0GT;
break; break;
case 0x04:
bus->max_bus_speed = PCIE_SPEED_8_0GT;
break;
default: default:
bus->max_bus_speed = PCI_SPEED_UNKNOWN; bus->max_bus_speed = PCI_SPEED_UNKNOWN;
break; break;
} }
switch (be32_to_cpup(pcie_link_speed_stats)) { switch (pcie_link_speed_stats[1]) {
case 0x01: case 0x01:
bus->cur_bus_speed = PCIE_SPEED_2_5GT; bus->cur_bus_speed = PCIE_SPEED_2_5GT;
break; break;
case 0x02: case 0x02:
bus->cur_bus_speed = PCIE_SPEED_5_0GT; bus->cur_bus_speed = PCIE_SPEED_5_0GT;
break; break;
case 0x04:
bus->cur_bus_speed = PCIE_SPEED_8_0GT;
break;
default: default:
bus->cur_bus_speed = PCI_SPEED_UNKNOWN; bus->cur_bus_speed = PCI_SPEED_UNKNOWN;
break; break;
......
...@@ -701,6 +701,18 @@ static inline pte_t pte_mknuma(pte_t pte) ...@@ -701,6 +701,18 @@ static inline pte_t pte_mknuma(pte_t pte)
} }
#endif #endif
#ifndef ptep_set_numa
static inline void ptep_set_numa(struct mm_struct *mm, unsigned long addr,
pte_t *ptep)
{
pte_t ptent = *ptep;
ptent = pte_mknuma(ptent);
set_pte_at(mm, addr, ptep, ptent);
return;
}
#endif
#ifndef pmd_mknuma #ifndef pmd_mknuma
static inline pmd_t pmd_mknuma(pmd_t pmd) static inline pmd_t pmd_mknuma(pmd_t pmd)
{ {
...@@ -708,6 +720,18 @@ static inline pmd_t pmd_mknuma(pmd_t pmd) ...@@ -708,6 +720,18 @@ static inline pmd_t pmd_mknuma(pmd_t pmd)
return pmd_clear_flags(pmd, _PAGE_PRESENT); return pmd_clear_flags(pmd, _PAGE_PRESENT);
} }
#endif #endif
#ifndef pmdp_set_numa
static inline void pmdp_set_numa(struct mm_struct *mm, unsigned long addr,
pmd_t *pmdp)
{
pmd_t pmd = *pmdp;
pmd = pmd_mknuma(pmd);
set_pmd_at(mm, addr, pmdp, pmd);
return;
}
#endif
#else #else
extern int pte_numa(pte_t pte); extern int pte_numa(pte_t pte);
extern int pmd_numa(pmd_t pmd); extern int pmd_numa(pmd_t pmd);
...@@ -715,6 +739,8 @@ extern pte_t pte_mknonnuma(pte_t pte); ...@@ -715,6 +739,8 @@ extern pte_t pte_mknonnuma(pte_t pte);
extern pmd_t pmd_mknonnuma(pmd_t pmd); extern pmd_t pmd_mknonnuma(pmd_t pmd);
extern pte_t pte_mknuma(pte_t pte); extern pte_t pte_mknuma(pte_t pte);
extern pmd_t pmd_mknuma(pmd_t pmd); extern pmd_t pmd_mknuma(pmd_t pmd);
extern void ptep_set_numa(struct mm_struct *mm, unsigned long addr, pte_t *ptep);
extern void pmdp_set_numa(struct mm_struct *mm, unsigned long addr, pmd_t *pmdp);
#endif /* CONFIG_ARCH_USES_NUMA_PROT_NONE */ #endif /* CONFIG_ARCH_USES_NUMA_PROT_NONE */
#else #else
static inline int pmd_numa(pmd_t pmd) static inline int pmd_numa(pmd_t pmd)
...@@ -742,10 +768,23 @@ static inline pte_t pte_mknuma(pte_t pte) ...@@ -742,10 +768,23 @@ static inline pte_t pte_mknuma(pte_t pte)
return pte; return pte;
} }
static inline void ptep_set_numa(struct mm_struct *mm, unsigned long addr,
pte_t *ptep)
{
return;
}
static inline pmd_t pmd_mknuma(pmd_t pmd) static inline pmd_t pmd_mknuma(pmd_t pmd)
{ {
return pmd; return pmd;
} }
static inline void pmdp_set_numa(struct mm_struct *mm, unsigned long addr,
pmd_t *pmdp)
{
return ;
}
#endif /* CONFIG_NUMA_BALANCING */ #endif /* CONFIG_NUMA_BALANCING */
#endif /* CONFIG_MMU */ #endif /* CONFIG_MMU */
......
...@@ -1545,6 +1545,7 @@ int change_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd, ...@@ -1545,6 +1545,7 @@ int change_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,
entry = pmd_mknonnuma(entry); entry = pmd_mknonnuma(entry);
entry = pmd_modify(entry, newprot); entry = pmd_modify(entry, newprot);
ret = HPAGE_PMD_NR; ret = HPAGE_PMD_NR;
set_pmd_at(mm, addr, pmd, entry);
BUG_ON(pmd_write(entry)); BUG_ON(pmd_write(entry));
} else { } else {
struct page *page = pmd_page(*pmd); struct page *page = pmd_page(*pmd);
...@@ -1557,16 +1558,10 @@ int change_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd, ...@@ -1557,16 +1558,10 @@ int change_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,
*/ */
if (!is_huge_zero_page(page) && if (!is_huge_zero_page(page) &&
!pmd_numa(*pmd)) { !pmd_numa(*pmd)) {
entry = *pmd; pmdp_set_numa(mm, addr, pmd);
entry = pmd_mknuma(entry);
ret = HPAGE_PMD_NR; ret = HPAGE_PMD_NR;
} }
} }
/* Set PMD if cleared earlier */
if (ret == HPAGE_PMD_NR)
set_pmd_at(mm, addr, pmd, entry);
spin_unlock(ptl); spin_unlock(ptl);
} }
......
...@@ -58,36 +58,27 @@ static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd, ...@@ -58,36 +58,27 @@ static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
if (pte_numa(ptent)) if (pte_numa(ptent))
ptent = pte_mknonnuma(ptent); ptent = pte_mknonnuma(ptent);
ptent = pte_modify(ptent, newprot); ptent = pte_modify(ptent, newprot);
/*
* Avoid taking write faults for pages we
* know to be dirty.
*/
if (dirty_accountable && pte_dirty(ptent))
ptent = pte_mkwrite(ptent);
ptep_modify_prot_commit(mm, addr, pte, ptent);
updated = true; updated = true;
} else { } else {
struct page *page; struct page *page;
ptent = *pte;
page = vm_normal_page(vma, addr, oldpte); page = vm_normal_page(vma, addr, oldpte);
if (page && !PageKsm(page)) { if (page && !PageKsm(page)) {
if (!pte_numa(oldpte)) { if (!pte_numa(oldpte)) {
ptent = pte_mknuma(ptent); ptep_set_numa(mm, addr, pte);
set_pte_at(mm, addr, pte, ptent);
updated = true; updated = true;
} }
} }
} }
/*
* Avoid taking write faults for pages we know to be
* dirty.
*/
if (dirty_accountable && pte_dirty(ptent)) {
ptent = pte_mkwrite(ptent);
updated = true;
}
if (updated) if (updated)
pages++; pages++;
/* Only !prot_numa always clears the pte */
if (!prot_numa)
ptep_modify_prot_commit(mm, addr, pte, ptent);
} else if (IS_ENABLED(CONFIG_MIGRATION) && !pte_file(oldpte)) { } else if (IS_ENABLED(CONFIG_MIGRATION) && !pte_file(oldpte)) {
swp_entry_t entry = pte_to_swp_entry(oldpte); swp_entry_t entry = pte_to_swp_entry(oldpte);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment