mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 14:11:52 +00:00
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:
commit
f2a77abdb8
@ -172,10 +172,20 @@ struct 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 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_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()
|
||||
* 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
|
||||
@ -257,6 +267,13 @@ void eeh_remove_device(struct pci_dev *);
|
||||
|
||||
#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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
#ifdef CONFIG_PPC64
|
||||
return __pte(pte_update(mm, addr, ptep, ~0UL, 1));
|
||||
return __pte(pte_update(mm, addr, ptep, ~0UL, 0, 1));
|
||||
#else
|
||||
return __pte(pte_update(ptep, ~0UL, 0));
|
||||
#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,
|
||||
unsigned long addr,
|
||||
pte_t *ptep, unsigned long clr,
|
||||
unsigned long set,
|
||||
int huge)
|
||||
{
|
||||
#ifdef PTE_ATOMIC_UPDATES
|
||||
@ -205,14 +206,15 @@ static inline unsigned long pte_update(struct mm_struct *mm,
|
||||
andi. %1,%0,%6\n\
|
||||
bne- 1b \n\
|
||||
andc %1,%0,%4 \n\
|
||||
or %1,%1,%7\n\
|
||||
stdcx. %1,0,%3 \n\
|
||||
bne- 1b"
|
||||
: "=&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" );
|
||||
#else
|
||||
unsigned long old = pte_val(*ptep);
|
||||
*ptep = __pte(old & ~clr);
|
||||
*ptep = __pte((old & ~clr) | set);
|
||||
#endif
|
||||
/* huge pages use the old page table lock */
|
||||
if (!huge)
|
||||
@ -231,9 +233,9 @@ static inline int __ptep_test_and_clear_young(struct mm_struct *mm,
|
||||
{
|
||||
unsigned long old;
|
||||
|
||||
if ((pte_val(*ptep) & (_PAGE_ACCESSED | _PAGE_HASHPTE)) == 0)
|
||||
if ((pte_val(*ptep) & (_PAGE_ACCESSED | _PAGE_HASHPTE)) == 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;
|
||||
}
|
||||
#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)
|
||||
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,
|
||||
@ -261,7 +263,7 @@ static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
|
||||
if ((pte_val(*ptep) & _PAGE_RW) == 0)
|
||||
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,
|
||||
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);
|
||||
}
|
||||
|
||||
static inline void pte_clear(struct mm_struct *mm, unsigned long addr,
|
||||
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,
|
||||
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,
|
||||
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)
|
||||
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);
|
||||
}
|
||||
|
||||
@ -542,7 +546,7 @@ static inline void pmdp_set_wrprotect(struct mm_struct *mm, unsigned long addr,
|
||||
if ((pmd_val(*pmdp) & _PAGE_RW) == 0)
|
||||
return;
|
||||
|
||||
pmd_hugepage_update(mm, addr, pmdp, _PAGE_RW);
|
||||
pmd_hugepage_update(mm, addr, pmdp, _PAGE_RW, 0);
|
||||
}
|
||||
|
||||
#define __HAVE_ARCH_PMDP_SPLITTING_FLUSH
|
||||
|
@ -75,12 +75,34 @@ static inline pte_t pte_mknuma(pte_t 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
|
||||
static inline int pmd_numa(pmd_t 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
|
||||
static inline pmd_t pmd_mknonnuma(pmd_t pmd)
|
||||
{
|
||||
|
@ -4,11 +4,11 @@
|
||||
#ifdef __KERNEL__
|
||||
|
||||
/* Default link addresses for the vDSOs */
|
||||
#define VDSO32_LBASE 0x100000
|
||||
#define VDSO64_LBASE 0x100000
|
||||
#define VDSO32_LBASE 0x0
|
||||
#define VDSO64_LBASE 0x0
|
||||
|
||||
/* Default map addresses for 32bit vDSO */
|
||||
#define VDSO32_MBASE VDSO32_LBASE
|
||||
#define VDSO32_MBASE 0x100000
|
||||
|
||||
#define VDSO_VERSION_STRING LINUX_2.6.15
|
||||
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include <linux/pci.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/rbtree.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/export.h>
|
||||
@ -89,7 +90,7 @@
|
||||
/* Platform dependent EEH operations */
|
||||
struct eeh_ops *eeh_ops = NULL;
|
||||
|
||||
int eeh_subsystem_enabled;
|
||||
bool eeh_subsystem_enabled = false;
|
||||
EXPORT_SYMBOL(eeh_subsystem_enabled);
|
||||
|
||||
/*
|
||||
@ -364,7 +365,7 @@ int eeh_dev_check_failure(struct eeh_dev *edev)
|
||||
|
||||
eeh_stats.total_mmio_ffs++;
|
||||
|
||||
if (!eeh_subsystem_enabled)
|
||||
if (!eeh_enabled())
|
||||
return 0;
|
||||
|
||||
if (!edev) {
|
||||
@ -747,6 +748,17 @@ int __exit eeh_ops_unregister(const char *name)
|
||||
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
|
||||
*
|
||||
@ -778,6 +790,14 @@ int eeh_init(void)
|
||||
if (machine_is(powernv) && cnt++ <= 0)
|
||||
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 */
|
||||
if (!eeh_ops) {
|
||||
pr_warning("%s: Platform EEH operation not found\n",
|
||||
@ -822,7 +842,7 @@ int eeh_init(void)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (eeh_subsystem_enabled)
|
||||
if (eeh_enabled())
|
||||
pr_info("EEH: PCI Enhanced I/O Error Handling Enabled\n");
|
||||
else
|
||||
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 eeh_dev *edev;
|
||||
|
||||
if (!dev || !eeh_subsystem_enabled)
|
||||
if (!dev || !eeh_enabled())
|
||||
return;
|
||||
|
||||
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;
|
||||
|
||||
if (!dev || !eeh_subsystem_enabled)
|
||||
if (!dev || !eeh_enabled())
|
||||
return;
|
||||
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)
|
||||
{
|
||||
if (0 == eeh_subsystem_enabled) {
|
||||
if (!eeh_enabled()) {
|
||||
seq_printf(m, "EEH Subsystem is globally disabled\n");
|
||||
seq_printf(m, "eeh_total_mmio_ffs=%llu\n", eeh_stats.total_mmio_ffs);
|
||||
} else {
|
||||
|
@ -57,11 +57,14 @@ _GLOBAL(call_do_softirq)
|
||||
mtlr r0
|
||||
blr
|
||||
|
||||
/*
|
||||
* void call_do_irq(struct pt_regs *regs, struct thread_info *irqtp);
|
||||
*/
|
||||
_GLOBAL(call_do_irq)
|
||||
mflr r0
|
||||
stw r0,4(r1)
|
||||
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)
|
||||
mr r1,r4
|
||||
stw r10,8(r1)
|
||||
|
@ -6,7 +6,7 @@
|
||||
.globl vdso32_start, vdso32_end
|
||||
.balign PAGE_SIZE
|
||||
vdso32_start:
|
||||
.incbin "arch/powerpc/kernel/vdso32/vdso32.so"
|
||||
.incbin "arch/powerpc/kernel/vdso32/vdso32.so.dbg"
|
||||
.balign PAGE_SIZE
|
||||
vdso32_end:
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
.globl vdso64_start, vdso64_end
|
||||
.balign PAGE_SIZE
|
||||
vdso64_start:
|
||||
.incbin "arch/powerpc/kernel/vdso64/vdso64.so"
|
||||
.incbin "arch/powerpc/kernel/vdso64/vdso64.so.dbg"
|
||||
.balign PAGE_SIZE
|
||||
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,
|
||||
pmd_t *pmdp, unsigned long clr)
|
||||
pmd_t *pmdp, unsigned long clr,
|
||||
unsigned long set)
|
||||
{
|
||||
|
||||
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\
|
||||
bne- 1b \n\
|
||||
andc %1,%0,%4 \n\
|
||||
or %1,%1,%7\n\
|
||||
stdcx. %1,0,%3 \n\
|
||||
bne- 1b"
|
||||
: "=&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" );
|
||||
#else
|
||||
old = pmd_val(*pmdp);
|
||||
*pmdp = __pmd(old & ~clr);
|
||||
*pmdp = __pmd((old & ~clr) | set);
|
||||
#endif
|
||||
if (old & _PAGE_HASHPTE)
|
||||
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,
|
||||
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;
|
||||
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);
|
||||
/*
|
||||
* 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);
|
||||
arch_enter_lazy_mmu_mode();
|
||||
for (; npages > 0; --npages) {
|
||||
pte_update(mm, addr, pte, 0, 0);
|
||||
pte_update(mm, addr, pte, 0, 0, 0);
|
||||
addr += PAGE_SIZE;
|
||||
++pte;
|
||||
}
|
||||
|
@ -44,7 +44,8 @@ static int ioda_eeh_event(struct notifier_block *nb,
|
||||
|
||||
/* We simply send special EEH event */
|
||||
if ((changed_evts & OPAL_EVENT_PCI_ERROR) &&
|
||||
(events & OPAL_EVENT_PCI_ERROR))
|
||||
(events & OPAL_EVENT_PCI_ERROR) &&
|
||||
eeh_enabled())
|
||||
eeh_send_failure_event(NULL);
|
||||
|
||||
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)
|
||||
{
|
||||
struct pci_controller *hose = pe->phb;
|
||||
struct eeh_dev *edev;
|
||||
struct pci_dev *dev;
|
||||
struct pci_bus *bus;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
@ -519,31 +519,11 @@ static int ioda_eeh_reset(struct eeh_pe *pe, int option)
|
||||
if (pe->type & EEH_PE_PHB) {
|
||||
ret = ioda_eeh_phb_reset(hose, option);
|
||||
} else {
|
||||
if (pe->type & EEH_PE_DEVICE) {
|
||||
/*
|
||||
* 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)
|
||||
bus = eeh_pe_bus_get(pe);
|
||||
if (pci_is_root_bus(bus))
|
||||
ret = ioda_eeh_root_reset(hose, option);
|
||||
else
|
||||
ret = ioda_eeh_bridge_reset(hose, dev, option);
|
||||
ret = ioda_eeh_bridge_reset(hose, bus->self, option);
|
||||
}
|
||||
|
||||
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
|
||||
* while accessing I/O stuff
|
||||
*/
|
||||
eeh_subsystem_enabled = 1;
|
||||
eeh_set_enable(true);
|
||||
|
||||
/* Save memory bars */
|
||||
eeh_save_bars(edev);
|
||||
|
@ -265,7 +265,7 @@ static void *pseries_eeh_of_probe(struct device_node *dn, void *flag)
|
||||
enable = 1;
|
||||
|
||||
if (enable) {
|
||||
eeh_subsystem_enabled = 1;
|
||||
eeh_set_enable(true);
|
||||
eeh_add_to_parent_pe(edev);
|
||||
|
||||
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 pci_bus *bus;
|
||||
const __be32 *pcie_link_speed_stats;
|
||||
u32 pcie_link_speed_stats[2];
|
||||
int rc;
|
||||
|
||||
bus = bridge->bus;
|
||||
|
||||
@ -122,38 +123,45 @@ int pseries_root_bridge_prepare(struct pci_host_bridge *bridge)
|
||||
return 0;
|
||||
|
||||
for (pdn = dn; pdn != NULL; pdn = of_get_next_parent(pdn)) {
|
||||
pcie_link_speed_stats = of_get_property(pdn,
|
||||
"ibm,pcie-link-speed-stats", NULL);
|
||||
if (pcie_link_speed_stats)
|
||||
rc = of_property_read_u32_array(pdn,
|
||||
"ibm,pcie-link-speed-stats",
|
||||
&pcie_link_speed_stats[0], 2);
|
||||
if (!rc)
|
||||
break;
|
||||
}
|
||||
|
||||
of_node_put(pdn);
|
||||
|
||||
if (!pcie_link_speed_stats) {
|
||||
if (rc) {
|
||||
pr_err("no ibm,pcie-link-speed-stats property\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (be32_to_cpup(pcie_link_speed_stats)) {
|
||||
switch (pcie_link_speed_stats[0]) {
|
||||
case 0x01:
|
||||
bus->max_bus_speed = PCIE_SPEED_2_5GT;
|
||||
break;
|
||||
case 0x02:
|
||||
bus->max_bus_speed = PCIE_SPEED_5_0GT;
|
||||
break;
|
||||
case 0x04:
|
||||
bus->max_bus_speed = PCIE_SPEED_8_0GT;
|
||||
break;
|
||||
default:
|
||||
bus->max_bus_speed = PCI_SPEED_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (be32_to_cpup(pcie_link_speed_stats)) {
|
||||
switch (pcie_link_speed_stats[1]) {
|
||||
case 0x01:
|
||||
bus->cur_bus_speed = PCIE_SPEED_2_5GT;
|
||||
break;
|
||||
case 0x02:
|
||||
bus->cur_bus_speed = PCIE_SPEED_5_0GT;
|
||||
break;
|
||||
case 0x04:
|
||||
bus->cur_bus_speed = PCIE_SPEED_8_0GT;
|
||||
break;
|
||||
default:
|
||||
bus->cur_bus_speed = PCI_SPEED_UNKNOWN;
|
||||
break;
|
||||
|
@ -701,6 +701,18 @@ static inline pte_t pte_mknuma(pte_t pte)
|
||||
}
|
||||
#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
|
||||
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);
|
||||
}
|
||||
#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
|
||||
extern int pte_numa(pte_t pte);
|
||||
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 pte_t pte_mknuma(pte_t pte);
|
||||
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 */
|
||||
#else
|
||||
static inline int pmd_numa(pmd_t pmd)
|
||||
@ -742,10 +768,23 @@ static inline pte_t pte_mknuma(pte_t 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)
|
||||
{
|
||||
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_MMU */
|
||||
|
@ -1545,6 +1545,7 @@ int change_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,
|
||||
entry = pmd_mknonnuma(entry);
|
||||
entry = pmd_modify(entry, newprot);
|
||||
ret = HPAGE_PMD_NR;
|
||||
set_pmd_at(mm, addr, pmd, entry);
|
||||
BUG_ON(pmd_write(entry));
|
||||
} else {
|
||||
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) &&
|
||||
!pmd_numa(*pmd)) {
|
||||
entry = *pmd;
|
||||
entry = pmd_mknuma(entry);
|
||||
pmdp_set_numa(mm, addr, pmd);
|
||||
ret = HPAGE_PMD_NR;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set PMD if cleared earlier */
|
||||
if (ret == HPAGE_PMD_NR)
|
||||
set_pmd_at(mm, addr, pmd, entry);
|
||||
|
||||
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))
|
||||
ptent = pte_mknonnuma(ptent);
|
||||
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;
|
||||
} else {
|
||||
struct page *page;
|
||||
|
||||
ptent = *pte;
|
||||
page = vm_normal_page(vma, addr, oldpte);
|
||||
if (page && !PageKsm(page)) {
|
||||
if (!pte_numa(oldpte)) {
|
||||
ptent = pte_mknuma(ptent);
|
||||
set_pte_at(mm, addr, pte, ptent);
|
||||
ptep_set_numa(mm, addr, pte);
|
||||
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)
|
||||
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)) {
|
||||
swp_entry_t entry = pte_to_swp_entry(oldpte);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user