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
This commit is contained in:
@ -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 *);
|
|||||||
* 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 *);
|
|||||||
|
|
||||||
#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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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)
|
||||||
@ -231,9 +233,9 @@ static inline int __ptep_test_and_clear_young(struct mm_struct *mm,
|
|||||||
{
|
{
|
||||||
unsigned long old;
|
unsigned long old;
|
||||||
|
|
||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
|
|
||||||
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,
|
|||||||
|
|
||||||
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,
|
|||||||
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)
|
|||||||
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 @@
|
|||||||
#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 @@
|
|||||||
#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 @@
|
|||||||
/* 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)
|
|||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
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 @@
|
|||||||
.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 @@
|
|||||||
.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,
|
|||||||
}
|
}
|
||||||
|
|
||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
|
|
||||||
/* 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,
|
|||||||
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)
|
|||||||
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)
|
|||||||
* 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)
|
|||||||
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)
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
#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)
|
|||||||
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);
|
|||||||
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)
|
|||||||
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,
|
|||||||
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,
|
|||||||
*/
|
*/
|
||||||
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,
|
|||||||
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);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user