Skip to content

Commit 86c65a7

Browse files
committed
Merge branch 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc
* 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc: vmlinux.lds: fix .data..init_task output section (fix popwerpc boot) powerpc: Fix erroneous lmb->memblock conversions powerpc/mm: Add some debug output when hash insertion fails powerpc/mm: Fix bugs in huge page hashing powerpc/mm: Move around testing of _PAGE_PRESENT in hash code powerpc/mm: Handle hypervisor pte insert failure in __hash_page_huge powerpc/kexec: Fix boundary case for book-e kexec memory limits
2 parents 20a52d4 + 7ffb65f commit 86c65a7

File tree

9 files changed

+93
-69
lines changed

9 files changed

+93
-69
lines changed

arch/powerpc/include/asm/kexec.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88
* On FSL-BookE we setup a 1:1 mapping which covers the first 2GiB of memory
99
* and therefore we can only deal with memory within this range
1010
*/
11-
#define KEXEC_SOURCE_MEMORY_LIMIT (2 * 1024 * 1024 * 1024UL)
12-
#define KEXEC_DESTINATION_MEMORY_LIMIT (2 * 1024 * 1024 * 1024UL)
13-
#define KEXEC_CONTROL_MEMORY_LIMIT (2 * 1024 * 1024 * 1024UL)
11+
#define KEXEC_SOURCE_MEMORY_LIMIT (2 * 1024 * 1024 * 1024UL - 1)
12+
#define KEXEC_DESTINATION_MEMORY_LIMIT (2 * 1024 * 1024 * 1024UL - 1)
13+
#define KEXEC_CONTROL_MEMORY_LIMIT (2 * 1024 * 1024 * 1024UL - 1)
1414

1515
#else
1616

arch/powerpc/include/asm/mmu-hash64.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,9 @@ extern int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
250250
int __hash_page_huge(unsigned long ea, unsigned long access, unsigned long vsid,
251251
pte_t *ptep, unsigned long trap, int local, int ssize,
252252
unsigned int shift, unsigned int mmu_psize);
253-
253+
extern void hash_failure_debug(unsigned long ea, unsigned long access,
254+
unsigned long vsid, unsigned long trap,
255+
int ssize, int psize, unsigned long pte);
254256
extern int htab_bolt_mapping(unsigned long vstart, unsigned long vend,
255257
unsigned long pstart, unsigned long prot,
256258
int psize, int ssize);

arch/powerpc/kernel/prom.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,7 @@ static int __init early_init_dt_scan_drconf_memory(unsigned long node)
414414
u64 base, size, memblock_size;
415415
unsigned int is_kexec_kdump = 0, rngs;
416416

417-
ls = of_get_flat_dt_prop(node, "ibm,memblock-size", &l);
417+
ls = of_get_flat_dt_prop(node, "ibm,lmb-size", &l);
418418
if (ls == NULL || l < dt_root_size_cells * sizeof(__be32))
419419
return 0;
420420
memblock_size = dt_mem_next_cell(dt_root_size_cells, &ls);

arch/powerpc/mm/hash_low_64.S

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,6 @@ _GLOBAL(__hash_page_4K)
6868
std r8,STK_PARM(r8)(r1)
6969
std r9,STK_PARM(r9)(r1)
7070

71-
/* Add _PAGE_PRESENT to access */
72-
ori r4,r4,_PAGE_PRESENT
73-
7471
/* Save non-volatile registers.
7572
* r31 will hold "old PTE"
7673
* r30 is "new PTE"
@@ -347,9 +344,6 @@ _GLOBAL(__hash_page_4K)
347344
std r8,STK_PARM(r8)(r1)
348345
std r9,STK_PARM(r9)(r1)
349346

350-
/* Add _PAGE_PRESENT to access */
351-
ori r4,r4,_PAGE_PRESENT
352-
353347
/* Save non-volatile registers.
354348
* r31 will hold "old PTE"
355349
* r30 is "new PTE"
@@ -687,9 +681,6 @@ _GLOBAL(__hash_page_64K)
687681
std r8,STK_PARM(r8)(r1)
688682
std r9,STK_PARM(r9)(r1)
689683

690-
/* Add _PAGE_PRESENT to access */
691-
ori r4,r4,_PAGE_PRESENT
692-
693684
/* Save non-volatile registers.
694685
* r31 will hold "old PTE"
695686
* r30 is "new PTE"

arch/powerpc/mm/hash_utils_64.c

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -871,6 +871,18 @@ static inline int subpage_protection(struct mm_struct *mm, unsigned long ea)
871871
}
872872
#endif
873873

874+
void hash_failure_debug(unsigned long ea, unsigned long access,
875+
unsigned long vsid, unsigned long trap,
876+
int ssize, int psize, unsigned long pte)
877+
{
878+
if (!printk_ratelimit())
879+
return;
880+
pr_info("mm: Hashing failure ! EA=0x%lx access=0x%lx current=%s\n",
881+
ea, access, current->comm);
882+
pr_info(" trap=0x%lx vsid=0x%lx ssize=%d psize=%d pte=0x%lx\n",
883+
trap, vsid, ssize, psize, pte);
884+
}
885+
874886
/* Result code is:
875887
* 0 - handled
876888
* 1 - normal page fault
@@ -955,6 +967,17 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
955967
return 1;
956968
}
957969

970+
/* Add _PAGE_PRESENT to the required access perm */
971+
access |= _PAGE_PRESENT;
972+
973+
/* Pre-check access permissions (will be re-checked atomically
974+
* in __hash_page_XX but this pre-check is a fast path
975+
*/
976+
if (access & ~pte_val(*ptep)) {
977+
DBG_LOW(" no access !\n");
978+
return 1;
979+
}
980+
958981
#ifdef CONFIG_HUGETLB_PAGE
959982
if (hugeshift)
960983
return __hash_page_huge(ea, access, vsid, ptep, trap, local,
@@ -967,14 +990,6 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
967990
DBG_LOW(" i-pte: %016lx %016lx\n", pte_val(*ptep),
968991
pte_val(*(ptep + PTRS_PER_PTE)));
969992
#endif
970-
/* Pre-check access permissions (will be re-checked atomically
971-
* in __hash_page_XX but this pre-check is a fast path
972-
*/
973-
if (access & ~pte_val(*ptep)) {
974-
DBG_LOW(" no access !\n");
975-
return 1;
976-
}
977-
978993
/* Do actual hashing */
979994
#ifdef CONFIG_PPC_64K_PAGES
980995
/* If _PAGE_4K_PFN is set, make sure this is a 4k segment */
@@ -1033,6 +1048,12 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
10331048
local, ssize, spp);
10341049
}
10351050

1051+
/* Dump some info in case of hash insertion failure, they should
1052+
* never happen so it is really useful to know if/when they do
1053+
*/
1054+
if (rc == -1)
1055+
hash_failure_debug(ea, access, vsid, trap, ssize, psize,
1056+
pte_val(*ptep));
10361057
#ifndef CONFIG_PPC_64K_PAGES
10371058
DBG_LOW(" o-pte: %016lx\n", pte_val(*ptep));
10381059
#else
@@ -1051,8 +1072,7 @@ void hash_preload(struct mm_struct *mm, unsigned long ea,
10511072
void *pgdir;
10521073
pte_t *ptep;
10531074
unsigned long flags;
1054-
int local = 0;
1055-
int ssize;
1075+
int rc, ssize, local = 0;
10561076

10571077
BUG_ON(REGION_ID(ea) != USER_REGION_ID);
10581078

@@ -1098,11 +1118,18 @@ void hash_preload(struct mm_struct *mm, unsigned long ea,
10981118
/* Hash it in */
10991119
#ifdef CONFIG_PPC_HAS_HASH_64K
11001120
if (mm->context.user_psize == MMU_PAGE_64K)
1101-
__hash_page_64K(ea, access, vsid, ptep, trap, local, ssize);
1121+
rc = __hash_page_64K(ea, access, vsid, ptep, trap, local, ssize);
11021122
else
11031123
#endif /* CONFIG_PPC_HAS_HASH_64K */
1104-
__hash_page_4K(ea, access, vsid, ptep, trap, local, ssize,
1105-
subpage_protection(pgdir, ea));
1124+
rc = __hash_page_4K(ea, access, vsid, ptep, trap, local, ssize,
1125+
subpage_protection(pgdir, ea));
1126+
1127+
/* Dump some info in case of hash insertion failure, they should
1128+
* never happen so it is really useful to know if/when they do
1129+
*/
1130+
if (rc == -1)
1131+
hash_failure_debug(ea, access, vsid, trap, ssize,
1132+
mm->context.user_psize, pte_val(*ptep));
11061133

11071134
local_irq_restore(flags);
11081135
}

arch/powerpc/mm/hugetlbpage-hash64.c

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -21,21 +21,13 @@ int __hash_page_huge(unsigned long ea, unsigned long access, unsigned long vsid,
2121
unsigned long old_pte, new_pte;
2222
unsigned long va, rflags, pa, sz;
2323
long slot;
24-
int err = 1;
2524

2625
BUG_ON(shift != mmu_psize_defs[mmu_psize].shift);
2726

2827
/* Search the Linux page table for a match with va */
2928
va = hpt_va(ea, vsid, ssize);
3029

31-
/*
32-
* Check the user's access rights to the page. If access should be
33-
* prevented then send the problem up to do_page_fault.
34-
*/
35-
if (unlikely(access & ~pte_val(*ptep)))
36-
goto out;
37-
/*
38-
* At this point, we have a pte (old_pte) which can be used to build
30+
/* At this point, we have a pte (old_pte) which can be used to build
3931
* or update an HPTE. There are 2 cases:
4032
*
4133
* 1. There is a valid (present) pte with no associated HPTE (this is
@@ -49,9 +41,17 @@ int __hash_page_huge(unsigned long ea, unsigned long access, unsigned long vsid,
4941

5042
do {
5143
old_pte = pte_val(*ptep);
52-
if (old_pte & _PAGE_BUSY)
53-
goto out;
44+
/* If PTE busy, retry the access */
45+
if (unlikely(old_pte & _PAGE_BUSY))
46+
return 0;
47+
/* If PTE permissions don't match, take page fault */
48+
if (unlikely(access & ~old_pte))
49+
return 1;
50+
/* Try to lock the PTE, add ACCESSED and DIRTY if it was
51+
* a write access */
5452
new_pte = old_pte | _PAGE_BUSY | _PAGE_ACCESSED;
53+
if (access & _PAGE_RW)
54+
new_pte |= _PAGE_DIRTY;
5555
} while(old_pte != __cmpxchg_u64((unsigned long *)ptep,
5656
old_pte, new_pte));
5757

@@ -121,8 +121,16 @@ int __hash_page_huge(unsigned long ea, unsigned long access, unsigned long vsid,
121121
}
122122
}
123123

124-
if (unlikely(slot == -2))
125-
panic("hash_huge_page: pte_insert failed\n");
124+
/*
125+
* Hypervisor failure. Restore old pte and return -1
126+
* similar to __hash_page_*
127+
*/
128+
if (unlikely(slot == -2)) {
129+
*ptep = __pte(old_pte);
130+
hash_failure_debug(ea, access, vsid, trap, ssize,
131+
mmu_psize, old_pte);
132+
return -1;
133+
}
126134

127135
new_pte |= (slot << 12) & (_PAGE_F_SECOND | _PAGE_F_GIX);
128136
}
@@ -131,9 +139,5 @@ int __hash_page_huge(unsigned long ea, unsigned long access, unsigned long vsid,
131139
* No need to use ldarx/stdcx here
132140
*/
133141
*ptep = __pte(new_pte & ~_PAGE_BUSY);
134-
135-
err = 0;
136-
137-
out:
138-
return err;
142+
return 0;
139143
}

arch/powerpc/mm/numa.c

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -398,15 +398,15 @@ static int of_get_drconf_memory(struct device_node *memory, const u32 **dm)
398398
}
399399

400400
/*
401-
* Retreive and validate the ibm,memblock-size property for drconf memory
401+
* Retreive and validate the ibm,lmb-size property for drconf memory
402402
* from the device tree.
403403
*/
404-
static u64 of_get_memblock_size(struct device_node *memory)
404+
static u64 of_get_lmb_size(struct device_node *memory)
405405
{
406406
const u32 *prop;
407407
u32 len;
408408

409-
prop = of_get_property(memory, "ibm,memblock-size", &len);
409+
prop = of_get_property(memory, "ibm,lmb-size", &len);
410410
if (!prop || len < sizeof(unsigned int))
411411
return 0;
412412

@@ -562,7 +562,7 @@ static unsigned long __init numa_enforce_memory_limit(unsigned long start,
562562
static inline int __init read_usm_ranges(const u32 **usm)
563563
{
564564
/*
565-
* For each memblock in ibm,dynamic-memory a corresponding
565+
* For each lmb in ibm,dynamic-memory a corresponding
566566
* entry in linux,drconf-usable-memory property contains
567567
* a counter followed by that many (base, size) duple.
568568
* read the counter from linux,drconf-usable-memory
@@ -578,16 +578,16 @@ static void __init parse_drconf_memory(struct device_node *memory)
578578
{
579579
const u32 *dm, *usm;
580580
unsigned int n, rc, ranges, is_kexec_kdump = 0;
581-
unsigned long memblock_size, base, size, sz;
581+
unsigned long lmb_size, base, size, sz;
582582
int nid;
583583
struct assoc_arrays aa;
584584

585585
n = of_get_drconf_memory(memory, &dm);
586586
if (!n)
587587
return;
588588

589-
memblock_size = of_get_memblock_size(memory);
590-
if (!memblock_size)
589+
lmb_size = of_get_lmb_size(memory);
590+
if (!lmb_size)
591591
return;
592592

593593
rc = of_get_assoc_arrays(memory, &aa);
@@ -611,7 +611,7 @@ static void __init parse_drconf_memory(struct device_node *memory)
611611
continue;
612612

613613
base = drmem.base_addr;
614-
size = memblock_size;
614+
size = lmb_size;
615615
ranges = 1;
616616

617617
if (is_kexec_kdump) {
@@ -1072,16 +1072,16 @@ static int hot_add_drconf_scn_to_nid(struct device_node *memory,
10721072
{
10731073
const u32 *dm;
10741074
unsigned int drconf_cell_cnt, rc;
1075-
unsigned long memblock_size;
1075+
unsigned long lmb_size;
10761076
struct assoc_arrays aa;
10771077
int nid = -1;
10781078

10791079
drconf_cell_cnt = of_get_drconf_memory(memory, &dm);
10801080
if (!drconf_cell_cnt)
10811081
return -1;
10821082

1083-
memblock_size = of_get_memblock_size(memory);
1084-
if (!memblock_size)
1083+
lmb_size = of_get_lmb_size(memory);
1084+
if (!lmb_size)
10851085
return -1;
10861086

10871087
rc = of_get_assoc_arrays(memory, &aa);
@@ -1100,7 +1100,7 @@ static int hot_add_drconf_scn_to_nid(struct device_node *memory,
11001100
continue;
11011101

11021102
if ((scn_addr < drmem.base_addr)
1103-
|| (scn_addr >= (drmem.base_addr + memblock_size)))
1103+
|| (scn_addr >= (drmem.base_addr + lmb_size)))
11041104
continue;
11051105

11061106
nid = of_drconf_to_nid_single(&drmem, &aa);

arch/powerpc/platforms/pseries/hotplug-memory.c

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ static int pseries_remove_memory(struct device_node *np)
6969
const char *type;
7070
const unsigned int *regs;
7171
unsigned long base;
72-
unsigned int memblock_size;
72+
unsigned int lmb_size;
7373
int ret = -EINVAL;
7474

7575
/*
@@ -87,9 +87,9 @@ static int pseries_remove_memory(struct device_node *np)
8787
return ret;
8888

8989
base = *(unsigned long *)regs;
90-
memblock_size = regs[3];
90+
lmb_size = regs[3];
9191

92-
ret = pseries_remove_memblock(base, memblock_size);
92+
ret = pseries_remove_memblock(base, lmb_size);
9393
return ret;
9494
}
9595

@@ -98,7 +98,7 @@ static int pseries_add_memory(struct device_node *np)
9898
const char *type;
9999
const unsigned int *regs;
100100
unsigned long base;
101-
unsigned int memblock_size;
101+
unsigned int lmb_size;
102102
int ret = -EINVAL;
103103

104104
/*
@@ -116,36 +116,36 @@ static int pseries_add_memory(struct device_node *np)
116116
return ret;
117117

118118
base = *(unsigned long *)regs;
119-
memblock_size = regs[3];
119+
lmb_size = regs[3];
120120

121121
/*
122122
* Update memory region to represent the memory add
123123
*/
124-
ret = memblock_add(base, memblock_size);
124+
ret = memblock_add(base, lmb_size);
125125
return (ret < 0) ? -EINVAL : 0;
126126
}
127127

128128
static int pseries_drconf_memory(unsigned long *base, unsigned int action)
129129
{
130130
struct device_node *np;
131-
const unsigned long *memblock_size;
131+
const unsigned long *lmb_size;
132132
int rc;
133133

134134
np = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory");
135135
if (!np)
136136
return -EINVAL;
137137

138-
memblock_size = of_get_property(np, "ibm,memblock-size", NULL);
139-
if (!memblock_size) {
138+
lmb_size = of_get_property(np, "ibm,lmb-size", NULL);
139+
if (!lmb_size) {
140140
of_node_put(np);
141141
return -EINVAL;
142142
}
143143

144144
if (action == PSERIES_DRCONF_MEM_ADD) {
145-
rc = memblock_add(*base, *memblock_size);
145+
rc = memblock_add(*base, *lmb_size);
146146
rc = (rc < 0) ? -EINVAL : 0;
147147
} else if (action == PSERIES_DRCONF_MEM_REMOVE) {
148-
rc = pseries_remove_memblock(*base, *memblock_size);
148+
rc = pseries_remove_memblock(*base, *lmb_size);
149149
} else {
150150
rc = -EINVAL;
151151
}

0 commit comments

Comments
 (0)