Do the plumbing needed for memory hotplug on systems using radix pagetables,
borrowing from existing vmemmap and x86 code.
This passes basic verification of plugging and removing memory, but this
stuff is tricky and I'd appreciate extra scrutiny of the series for
correctness--in particular, the adaptation of remove_pagetable() from x86.
Former patch 1 is now a separate fix. This set still depends on it:
https://lkml.kernel.org/r/1483475991-16999-1-git-send-email-arbab@linux.vnet.ibm.com
/* changelog */
v5:
* Retain pr_info() of the size used to map each address range.
* flush_tlb_kernel_range() -> radix__flush_tlb_kernel_range()
v4:
* https://lkml.kernel.org/r/1483476218-17271-1-git-send-email-arbab@linux.vnet.ibm.com
* Sent patch 1 as a standalone fix.
* Extract a common function that can be used by both radix_init_pgtable() and
radix__create_section_mapping().
* Reduce tlb flushing to one flush_tlb_kernel_range() per section, and do
less granular locking of init_mm->page_table_lock.
v3:
* https://lkml.kernel.org/r/1481831443-22761-1-git-send-email-arbab@linux.vnet.ibm.com
* Port remove_pagetable() et al. from x86 for unmapping.
* [RFC] -> [PATCH]
v2:
* https://lkml.kernel.org/r/1471449083-15931-1-git-send-email-arbab@linux.vnet.ibm.com
* Do not simply fall through to vmemmap_{create,remove}_mapping(). As Aneesh
and Michael pointed out, they are tied to CONFIG_SPARSEMEM_VMEMMAP and only
did what I needed by luck anyway.
v1:
* https://lkml.kernel.org/r/1466699962-22412-1-git-send-email-arbab@linux.vnet.ibm.com
Reza Arbab (4):
powerpc/mm: refactor radix physical page mapping
powerpc/mm: add radix__create_section_mapping()
powerpc/mm: add radix__remove_section_mapping()
powerpc/mm: unstub radix__vmemmap_remove_mapping()
arch/powerpc/include/asm/book3s/64/radix.h | 5 +
arch/powerpc/mm/pgtable-book3s64.c | 4 +-
arch/powerpc/mm/pgtable-radix.c | 257 ++++++++++++++++++++++++-----
3 files changed, 225 insertions(+), 41 deletions(-)
--
1.8.3.1
Move the page mapping code in radix_init_pgtable() into a separate
function that will also be used for memory hotplug.
The current goto loop progressively decreases its mapping size as it
covers the tail of a range whose end is unaligned. Change this to a for
loop which can do the same for both ends of the range.
Signed-off-by: Reza Arbab <redacted>
---
arch/powerpc/mm/pgtable-radix.c | 88 +++++++++++++++++++++++------------------
1 file changed, 50 insertions(+), 38 deletions(-)
@@ -107,54 +107,66 @@ int radix__map_kernel_page(unsigned long ea, unsigned long pa,return0;}+staticinlinevoid__meminitprint_mapping(unsignedlongstart,+unsignedlongend,+unsignedlongsize)+{+if(end<=start)+return;++pr_info("Mapped range 0x%lx - 0x%lx with 0x%lx\n",start,end,size);+}++staticint__meminitcreate_physical_mapping(unsignedlongstart,+unsignedlongend)+{+unsignedlongaddr,mapping_size;++start=_ALIGN_UP(start,PAGE_SIZE);+for(addr=start;addr<end;addr+=mapping_size){+unsignedlonggap,previous_size;+intrc;++gap=end-addr;+previous_size=mapping_size;++if(IS_ALIGNED(addr,PUD_SIZE)&&gap>=PUD_SIZE&&+mmu_psize_defs[MMU_PAGE_1G].shift)+mapping_size=PUD_SIZE;+elseif(IS_ALIGNED(addr,PMD_SIZE)&&gap>=PMD_SIZE&&+mmu_psize_defs[MMU_PAGE_2M].shift)+mapping_size=PMD_SIZE;+else+mapping_size=PAGE_SIZE;++if(mapping_size!=previous_size){+print_mapping(start,addr,previous_size);+start=addr;+}++rc=radix__map_kernel_page((unsignedlong)__va(addr),addr,+PAGE_KERNEL_X,mapping_size);+if(rc)+returnrc;+}++print_mapping(start,addr,mapping_size);+return0;+}+staticvoid__initradix_init_pgtable(void){-intloop_count;-u64base,end,start_addr;unsignedlongrts_field;structmemblock_region*reg;-unsignedlonglinear_page_size;/* We don't support slb for radix */mmu_slb_size=0;/**Createthelinearmapping,usingstandardpagesizefornow*/-loop_count=0;-for_each_memblock(memory,reg){--start_addr=reg->base;--redo:-if(loop_count<1&&mmu_psize_defs[MMU_PAGE_1G].shift)-linear_page_size=PUD_SIZE;-elseif(loop_count<2&&mmu_psize_defs[MMU_PAGE_2M].shift)-linear_page_size=PMD_SIZE;-else-linear_page_size=PAGE_SIZE;--base=_ALIGN_UP(start_addr,linear_page_size);-end=_ALIGN_DOWN(reg->base+reg->size,linear_page_size);--pr_info("Mapping range 0x%lx - 0x%lx with 0x%lx\n",-(unsignedlong)base,(unsignedlong)end,-linear_page_size);--while(base<end){-radix__map_kernel_page((unsignedlong)__va(base),-base,PAGE_KERNEL_X,-linear_page_size);-base+=linear_page_size;-}-/*-*maptherestusinglowerpagesize-*/-if(end<reg->base+reg->size){-start_addr=end;-loop_count++;-gotoredo;-}-}+for_each_memblock(memory,reg)+WARN_ON(create_physical_mapping(reg->base,+reg->base+reg->size));/**AllocatePartitiontableandprocesstableforthe*host.
Use remove_pagetable() and friends for radix vmemmap removal.
We do not require the special-case handling of vmemmap done in the x86
versions of these functions. This is because vmemmap_free() has already
freed the mapped pages, and calls us with an aligned address range.
So, add a few failsafe WARNs, but otherwise the code to remove physical
mappings is already sufficient for vmemmap.
Signed-off-by: Reza Arbab <redacted>
---
arch/powerpc/mm/pgtable-radix.c | 29 ++++++++++++++++++++++++++++-
1 file changed, 28 insertions(+), 1 deletion(-)
@@ -591,6 +612,12 @@ static void remove_pagetable(unsigned long start, unsigned long end)continue;if(pgd_huge(*pgd)){+if(!IS_ALIGNED(addr,PGDIR_SIZE)||+!IS_ALIGNED(next,PGDIR_SIZE)){+WARN_ONCE(1,"%s: unaligned range\n",__func__);+continue;+}+pte_clear(&init_mm,addr,(pte_t*)pgd);continue;}
@@ -630,7 +657,7 @@ int __meminit radix__vmemmap_create_mapping(unsigned long start,#ifdef CONFIG_MEMORY_HOTPLUGvoidradix__vmemmap_remove_mapping(unsignedlongstart,unsignedlongpage_size){-/* FIXME!! intel does more. We should free page tables mapping vmemmap ? */+remove_pagetable(start,start+page_size);}#endif#endif
Tear down and free the four-level page tables of physical mappings
during memory hotremove.
Borrow the basic structure of remove_pagetable() and friends from the
identically-named x86 functions. Reduce the frequency of tlb flushes and
page_table_lock spinlocks by only doing them in the outermost function.
There was some question as to whether the locking is needed at all.
Leave it for now, but we could consider dropping it.
Memory must be offline to be removed, thus not in use. So there
shouldn't be the sort of concurrent page walking activity here that
might prompt us to use RCU.
Signed-off-by: Reza Arbab <redacted>
---
arch/powerpc/include/asm/book3s/64/radix.h | 1 +
arch/powerpc/mm/pgtable-book3s64.c | 2 +-
arch/powerpc/mm/pgtable-radix.c | 133 +++++++++++++++++++++++++++++
3 files changed, 135 insertions(+), 1 deletion(-)
@@ -139,7 +139,7 @@ int create_section_mapping(unsigned long start, unsigned long end)intremove_section_mapping(unsignedlongstart,unsignedlongend){if(radix_enabled())-return-ENODEV;+returnradix__remove_section_mapping(start,end);returnhash__remove_section_mapping(start,end);}
On Mon, Jan 16, 2017 at 01:07:43PM -0600, Reza Arbab wrote:
quoted hunk
Move the page mapping code in radix_init_pgtable() into a separate
function that will also be used for memory hotplug.
The current goto loop progressively decreases its mapping size as it
covers the tail of a range whose end is unaligned. Change this to a for
loop which can do the same for both ends of the range.
Signed-off-by: Reza Arbab <redacted>
---
arch/powerpc/mm/pgtable-radix.c | 88 +++++++++++++++++++++++------------------
1 file changed, 50 insertions(+), 38 deletions(-)
@@ -107,54 +107,66 @@ int radix__map_kernel_page(unsigned long ea, unsigned long pa,return0;}+staticinlinevoid__meminitprint_mapping(unsignedlongstart,+unsignedlongend,+unsignedlongsize)+{+if(end<=start)+return;
Should we pr_err for start > end?
quoted hunk
++ pr_info("Mapped range 0x%lx - 0x%lx with 0x%lx\n", start, end, size);+}++static int __meminit create_physical_mapping(unsigned long start,+ unsigned long end)+{+ unsigned long addr, mapping_size;++ start = _ALIGN_UP(start, PAGE_SIZE);+ for (addr = start; addr < end; addr += mapping_size) {+ unsigned long gap, previous_size;+ int rc;++ gap = end - addr;+ previous_size = mapping_size;++ if (IS_ALIGNED(addr, PUD_SIZE) && gap >= PUD_SIZE &&+ mmu_psize_defs[MMU_PAGE_1G].shift)+ mapping_size = PUD_SIZE;+ else if (IS_ALIGNED(addr, PMD_SIZE) && gap >= PMD_SIZE &&+ mmu_psize_defs[MMU_PAGE_2M].shift)+ mapping_size = PMD_SIZE;+ else+ mapping_size = PAGE_SIZE;++ if (mapping_size != previous_size) {+ print_mapping(start, addr, previous_size);+ start = addr;+ }++ rc = radix__map_kernel_page((unsigned long)__va(addr), addr,+ PAGE_KERNEL_X, mapping_size);+ if (rc)+ return rc;
Should we try a lower page size if map_kernel_page fails for this mapping_size?
I like the cleanup very much, BTW
Balbir Singh.
On Mon, Jan 16, 2017 at 01:07:44PM -0600, Reza Arbab wrote:
Wire up memory hotplug page mapping for radix. Share the mapping
function already used by radix_init_pgtable().
Signed-off-by: Reza Arbab <redacted>
---
On Mon, Jan 16, 2017 at 01:07:45PM -0600, Reza Arbab wrote:
quoted hunk
Tear down and free the four-level page tables of physical mappings
during memory hotremove.
Borrow the basic structure of remove_pagetable() and friends from the
identically-named x86 functions. Reduce the frequency of tlb flushes and
page_table_lock spinlocks by only doing them in the outermost function.
There was some question as to whether the locking is needed at all.
Leave it for now, but we could consider dropping it.
Memory must be offline to be removed, thus not in use. So there
shouldn't be the sort of concurrent page walking activity here that
might prompt us to use RCU.
Signed-off-by: Reza Arbab <redacted>
---
arch/powerpc/include/asm/book3s/64/radix.h | 1 +
arch/powerpc/mm/pgtable-book3s64.c | 2 +-
arch/powerpc/mm/pgtable-radix.c | 133 +++++++++++++++++++++++++++++
3 files changed, 135 insertions(+), 1 deletion(-)
@@ -139,7 +139,7 @@ int create_section_mapping(unsigned long start, unsigned long end)intremove_section_mapping(unsignedlongstart,unsignedlongend){if(radix_enabled())-return-ENODEV;+returnradix__remove_section_mapping(start,end);returnhash__remove_section_mapping(start,end);}
#ifdef CONFIG_MEMORY_HOTPLUG+static void free_pte_table(pte_t *pte_start, pmd_t *pmd)+{+ pte_t *pte;+ int i;++ for (i = 0; i < PTRS_PER_PTE; i++) {+ pte = pte_start + i;+ if (!pte_none(*pte))+ return;
If !pte_none() we fail the hotplug? Or silently
leave the allocated pte's around. I guess this is
the same as x86
quoted hunk
+ }++ pte_free_kernel(&init_mm, pte_start);+ pmd_clear(pmd);+}++static void free_pmd_table(pmd_t *pmd_start, pud_t *pud)+{+ pmd_t *pmd;+ int i;++ for (i = 0; i < PTRS_PER_PMD; i++) {+ pmd = pmd_start + i;+ if (!pmd_none(*pmd))+ return;+ }++ pmd_free(&init_mm, pmd_start);+ pud_clear(pud);+}++static void remove_pte_table(pte_t *pte_start, unsigned long addr,+ unsigned long end)+{+ unsigned long next;+ pte_t *pte;++ pte = pte_start + pte_index(addr);+ for (; addr < end; addr = next, pte++) {+ next = (addr + PAGE_SIZE) & PAGE_MASK;+ if (next > end)+ next = end;++ if (!pte_present(*pte))+ continue;++ pte_clear(&init_mm, addr, pte);+ }+}++static void remove_pmd_table(pmd_t *pmd_start, unsigned long addr,+ unsigned long end)+{+ unsigned long next;+ pte_t *pte_base;+ pmd_t *pmd;++ pmd = pmd_start + pmd_index(addr);+ for (; addr < end; addr = next, pmd++) {+ next = pmd_addr_end(addr, end);++ if (!pmd_present(*pmd))+ continue;++ if (pmd_huge(*pmd)) {+ pte_clear(&init_mm, addr, (pte_t *)pmd);
pmd_clear()?
quoted hunk
+ continue;+ }++ pte_base = (pte_t *)pmd_page_vaddr(*pmd);+ remove_pte_table(pte_base, addr, next);+ free_pte_table(pte_base, pmd);+ }+}++static void remove_pud_table(pud_t *pud_start, unsigned long addr,+ unsigned long end)+{+ unsigned long next;+ pmd_t *pmd_base;+ pud_t *pud;++ pud = pud_start + pud_index(addr);+ for (; addr < end; addr = next, pud++) {+ next = pud_addr_end(addr, end);++ if (!pud_present(*pud))+ continue;++ if (pud_huge(*pud)) {+ pte_clear(&init_mm, addr, (pte_t *)pud);
pud_clear()?
quoted hunk
+ continue;+ }++ pmd_base = (pmd_t *)pud_page_vaddr(*pud);+ remove_pmd_table(pmd_base, addr, next);+ free_pmd_table(pmd_base, pud);+ }+}++static void remove_pagetable(unsigned long start, unsigned long end)+{+ unsigned long addr, next;+ pud_t *pud_base;+ pgd_t *pgd;++ spin_lock(&init_mm.page_table_lock);+
x86 does more granular lock acquisition only during
clearing the relevant entries. I suppose we don't have
to worry about it since its not fast path and frequent.
Balbir Singh.
On Mon, Jan 16, 2017 at 01:07:46PM -0600, Reza Arbab wrote:
Use remove_pagetable() and friends for radix vmemmap removal.
We do not require the special-case handling of vmemmap done in the x86
versions of these functions. This is because vmemmap_free() has already
freed the mapped pages, and calls us with an aligned address range.
So, add a few failsafe WARNs, but otherwise the code to remove physical
mappings is already sufficient for vmemmap.
@@ -107,54 +107,66 @@ int radix__map_kernel_page(unsigned long ea, unsigned long pa,return0;}+staticinlinevoid__meminitprint_mapping(unsignedlongstart,+unsignedlongend,+unsignedlongsize)+{+if(end<=start)+return;
Should we pr_err for start > end?
I think that would be overkill. The way this little inline is called, start > end is not possible. The real point is not to print anything if start == end. Using <= just seemed better in context.
quoted
+static int __meminit create_physical_mapping(unsigned long start,+ unsigned long end)+{+ unsigned long addr, mapping_size;++ start = _ALIGN_UP(start, PAGE_SIZE);+ for (addr = start; addr < end; addr += mapping_size) {+ unsigned long gap, previous_size;+ int rc;++ gap = end - addr;+ previous_size = mapping_size;++ if (IS_ALIGNED(addr, PUD_SIZE) && gap >= PUD_SIZE &&+ mmu_psize_defs[MMU_PAGE_1G].shift)+ mapping_size = PUD_SIZE;+ else if (IS_ALIGNED(addr, PMD_SIZE) && gap >= PMD_SIZE &&+ mmu_psize_defs[MMU_PAGE_2M].shift)+ mapping_size = PMD_SIZE;+ else+ mapping_size = PAGE_SIZE;++ if (mapping_size != previous_size) {+ print_mapping(start, addr, previous_size);+ start = addr;+ }++ rc = radix__map_kernel_page((unsigned long)__va(addr), addr,+ PAGE_KERNEL_X, mapping_size);+ if (rc)+ return rc;
Should we try a lower page size if map_kernel_page fails for this mapping_size?
The only way map_kernel_page can fail is -ENOMEM. If that's the case,
there's no way we're going to be able to map this range at all. Better to fail fast here, I would think.
--
Reza Arbab
On Tue, Jan 17, 2017 at 12:52:51PM +0530, Balbir Singh wrote:
Shouldn't most of these functions have __meminit?
I don't think so. The mapping functions are __meminit, but the unmapping functions are completely within #ifdef CONFIG_MEMORY_HOTPLUG already.
On Mon, Jan 16, 2017 at 01:07:45PM -0600, Reza Arbab wrote:
quoted
#ifdef CONFIG_MEMORY_HOTPLUG+static void free_pte_table(pte_t *pte_start, pmd_t *pmd)+{+ pte_t *pte;+ int i;++ for (i = 0; i < PTRS_PER_PTE; i++) {+ pte = pte_start + i;+ if (!pte_none(*pte))+ return;
If !pte_none() we fail the hotplug? Or silently
leave the allocated pte's around. I guess this is
the same as x86
The latter--it's not a failure. If you provided remove_pagetable() an unaligned address range, there could be a pte left unremoved at either end.
quoted
+static void remove_pmd_table(pmd_t *pmd_start, unsigned long addr,+ unsigned long end)+{+ unsigned long next;+ pte_t *pte_base;+ pmd_t *pmd;++ pmd = pmd_start + pmd_index(addr);+ for (; addr < end; addr = next, pmd++) {+ next = pmd_addr_end(addr, end);++ if (!pmd_present(*pmd))+ continue;++ if (pmd_huge(*pmd)) {+ pte_clear(&init_mm, addr, (pte_t *)pmd);
pmd_clear()?
I used pte_clear() to mirror what happens in radix__map_kernel_page():
if (map_page_size == PMD_SIZE) {
ptep = (pte_t *)pmdp;
goto set_the_pte;
}
[...]
set_the_pte:
set_pte_at(&init_mm, ea, ptep, pfn_pte(pa >> PAGE_SHIFT, flags));
Would pmd_clear() be equivalent, since the pointer got set like a pte?
quoted
+static void remove_pagetable(unsigned long start, unsigned long end)+{+ unsigned long addr, next;+ pud_t *pud_base;+ pgd_t *pgd;++ spin_lock(&init_mm.page_table_lock);+
x86 does more granular lock acquisition only during
clearing the relevant entries. I suppose we don't have
to worry about it since its not fast path and frequent.
Yep. Ben thought the locking in remove_pte_table() was actually too granular, and Aneesh questioned what was being protected in the first place. So I left one lock/unlock in the outermost function for now.
--
Reza Arbab
On Tue, Jan 17, 2017 at 12:55:13PM +0530, Balbir Singh wrote:
On Mon, Jan 16, 2017 at 01:07:46PM -0600, Reza Arbab wrote:
quoted
Use remove_pagetable() and friends for radix vmemmap removal.
We do not require the special-case handling of vmemmap done in the x86
versions of these functions. This is because vmemmap_free() has already
freed the mapped pages, and calls us with an aligned address range.
So, add a few failsafe WARNs, but otherwise the code to remove physical
mappings is already sufficient for vmemmap.
I wonder if we really need them?
Not sure what the guideline is for a "this shouldn't happen" WARN. It could save us some grief, should our vmemmap code ever start calling with an unaligned range, like it does on x86.
--
Reza Arbab
@@ -107,54 +107,66 @@ int radix__map_kernel_page(unsigned long ea, unsigned long pa,return0;}+staticinlinevoid__meminitprint_mapping(unsignedlongstart,+unsignedlongend,+unsignedlongsize)+{+if(end<=start)+return;
Should we pr_err for start > end?
I think that would be overkill. The way this little inline is called, start
quoted
end is not possible. The real point is not to print anything if start ==
end. Using <= just seemed better in context.
Agreed
<snip>
quoted
Should we try a lower page size if map_kernel_page fails for this mapping_size?
The only way map_kernel_page can fail is -ENOMEM. If that's the case,
there's no way we're going to be able to map this range at all. Better to
fail fast here, I would think.
I think I am OK with this implementation for now.
Balbir Singh.
On Tue, Jan 17, 2017 at 12:36:21PM -0600, Reza Arbab wrote:
On Tue, Jan 17, 2017 at 12:52:51PM +0530, Balbir Singh wrote:
quoted
Shouldn't most of these functions have __meminit?
I don't think so. The mapping functions are __meminit, but the unmapping
functions are completely within #ifdef CONFIG_MEMORY_HOTPLUG already.
quoted
On Mon, Jan 16, 2017 at 01:07:45PM -0600, Reza Arbab wrote:
quoted
#ifdef CONFIG_MEMORY_HOTPLUG+static void free_pte_table(pte_t *pte_start, pmd_t *pmd)+{+ pte_t *pte;+ int i;++ for (i = 0; i < PTRS_PER_PTE; i++) {+ pte = pte_start + i;+ if (!pte_none(*pte))+ return;
If !pte_none() we fail the hotplug? Or silently
leave the allocated pte's around. I guess this is
the same as x86
The latter--it's not a failure. If you provided remove_pagetable() an
unaligned address range, there could be a pte left unremoved at either end.
OK.
quoted
quoted
+static void remove_pmd_table(pmd_t *pmd_start, unsigned long addr,+ unsigned long end)+{+ unsigned long next;+ pte_t *pte_base;+ pmd_t *pmd;++ pmd = pmd_start + pmd_index(addr);+ for (; addr < end; addr = next, pmd++) {+ next = pmd_addr_end(addr, end);++ if (!pmd_present(*pmd))+ continue;++ if (pmd_huge(*pmd)) {+ pte_clear(&init_mm, addr, (pte_t *)pmd);
pmd_clear()?
I used pte_clear() to mirror what happens in radix__map_kernel_page():
if (map_page_size == PMD_SIZE) {
ptep = (pte_t *)pmdp;
goto set_the_pte;
}
[...]
set_the_pte:
set_pte_at(&init_mm, ea, ptep, pfn_pte(pa >> PAGE_SHIFT, flags));
Would pmd_clear() be equivalent, since the pointer got set like a pte?
But we are still setting a pmdp. pmd_clear() will set the pmd to 0,
pte_clear() will go through the pte_update() mechanism which is expensive
IMHO and we may not need to do it.
quoted
quoted
+static void remove_pagetable(unsigned long start, unsigned long end)+{+ unsigned long addr, next;+ pud_t *pud_base;+ pgd_t *pgd;++ spin_lock(&init_mm.page_table_lock);+
x86 does more granular lock acquisition only during
clearing the relevant entries. I suppose we don't have
to worry about it since its not fast path and frequent.
Yep. Ben thought the locking in remove_pte_table() was actually too
granular, and Aneesh questioned what was being protected in the first place.
So I left one lock/unlock in the outermost function for now.
On Tue, Jan 17, 2017 at 12:36:53PM -0600, Reza Arbab wrote:
On Tue, Jan 17, 2017 at 12:55:13PM +0530, Balbir Singh wrote:
quoted
On Mon, Jan 16, 2017 at 01:07:46PM -0600, Reza Arbab wrote:
quoted
Use remove_pagetable() and friends for radix vmemmap removal.
We do not require the special-case handling of vmemmap done in the x86
versions of these functions. This is because vmemmap_free() has already
freed the mapped pages, and calls us with an aligned address range.
So, add a few failsafe WARNs, but otherwise the code to remove physical
mappings is already sufficient for vmemmap.
I wonder if we really need them?
Not sure what the guideline is for a "this shouldn't happen" WARN. It could
save us some grief, should our vmemmap code ever start calling with an
unaligned range, like it does on x86.
@@ -107,54 +107,66 @@ int radix__map_kernel_page(unsigned long ea, unsign=
ed long pa,
return 0;
}
=20=20
+static inline void __meminit print_mapping(unsigned long start,
+ unsigned long end,
+ unsigned long size)
+{
+ if (end <=3D start)
+ return;
+
+ pr_info("Mapped range 0x%lx - 0x%lx with 0x%lx\n", start, end, size);
+}
+
+static int __meminit create_physical_mapping(unsigned long start,
+ unsigned long end)
+{
+ unsigned long addr, mapping_size;
+
+ start =3D _ALIGN_UP(start, PAGE_SIZE);
+ for (addr =3D start; addr < end; addr +=3D mapping_size) {
+ unsigned long gap, previous_size;
+ int rc;
+
+ gap =3D end - addr;
+ previous_size =3D mapping_size;
+
+ if (IS_ALIGNED(addr, PUD_SIZE) && gap >=3D PUD_SIZE &&
+ mmu_psize_defs[MMU_PAGE_1G].shift)
+ mapping_size =3D PUD_SIZE;
+ else if (IS_ALIGNED(addr, PMD_SIZE) && gap >=3D PMD_SIZE &&
+ mmu_psize_defs[MMU_PAGE_2M].shift)
+ mapping_size =3D PMD_SIZE;
+ else
+ mapping_size =3D PAGE_SIZE;
+
+ if (mapping_size !=3D previous_size) {
+ print_mapping(start, addr, previous_size);
+ start =3D addr;
+ }
+
+ rc =3D radix__map_kernel_page((unsigned long)__va(addr), addr,
+ PAGE_KERNEL_X, mapping_size);
+ if (rc)
+ return rc;
+ }
+
+ print_mapping(start, addr, mapping_size);
Doesn't build.
In file included from ../include/linux/kernel.h:13:0,
from ../include/linux/sched.h:17,
from ../arch/powerpc/mm/pgtable-radix.c:11:
../arch/powerpc/mm/pgtable-radix.c: In function =E2=80=98create_physical_ma=
pping=E2=80=99:
../include/linux/printk.h:299:2: error: =E2=80=98mapping_size=E2=80=99 may =
be used uninitialized in this function [-Werror=3Dmaybe-uninitialized]
printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
^~~~~~
../arch/powerpc/mm/pgtable-radix.c:123:22: note: =E2=80=98mapping_size=E2=
=80=99 was declared here
unsigned long addr, mapping_size;
^~~~~~~~~~~~
cheers
On Mon, Jan 30, 2017 at 07:38:18PM +1100, Michael Ellerman wrote:
Doesn't build.
In file included from ../include/linux/kernel.h:13:0,
from ../include/linux/sched.h:17,
from ../arch/powerpc/mm/pgtable-radix.c:11:
../arch/powerpc/mm/pgtable-radix.c: In function ‘create_physical_mapping’:
../include/linux/printk.h:299:2: error: ‘mapping_size’ may be used uninitialized in this function [-Werror=maybe-uninitialized]
printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
^~~~~~
../arch/powerpc/mm/pgtable-radix.c:123:22: note: ‘mapping_size’ was declared here
unsigned long addr, mapping_size;
Doh. Could you please do the following for now?
- unsigned long addr, mapping_size;
+ unsigned long addr, mapping_size = 0;
I'd like to delay spinning v6 with this until I see any input you might have on the rest of the set.
And for future reference, how are you ending up with -Werror=maybe-uninitialized? On powerpc/next, with pseries_le_defconfig, I get -Wno-maybe-uninitialized.
--
Reza Arbab
From: Michael Ellerman <mpe@ellerman.id.au> Date: 2017-01-30 21:58:37
Reza Arbab [off-list ref] writes:
On Mon, Jan 30, 2017 at 07:38:18PM +1100, Michael Ellerman wrote:
quoted
Doesn't build.
In file included from ../include/linux/kernel.h:13:0,
from ../include/linux/sched.h:17,
from ../arch/powerpc/mm/pgtable-radix.c:11:
../arch/powerpc/mm/pgtable-radix.c: In function =E2=80=98create_physical_=
Doh. Could you please do the following for now?
- unsigned long addr, mapping_size;
+ unsigned long addr, mapping_size =3D 0;
Thanks.
I'd like to delay spinning v6 with this until I see any input you might=20
have on the rest of the set.
I don't think I have any at the moment. So I'll just fold the above into
v5.
And for future reference, how are you ending up with=20
-Werror=3Dmaybe-uninitialized? On powerpc/next, with pseries_le_defconfig=
,=20
I get -Wno-maybe-uninitialized.
By default. Probably you're not getting it because your compiler is too
old. If I'm reading Makefile correctly it's enabled for GCC 4.9 or later:
KBUILD_CFLAGS +=3D $(call cc-ifversion, -lt, 0409, \
$(call cc-disable-warning,maybe-uninitialized,))
I'm using GCC 6.2.0.
cheers
From: Michael Ellerman <hidden> Date: 2017-02-01 01:05:30
On Mon, 2017-01-16 at 19:07:43 UTC, Reza Arbab wrote:
Move the page mapping code in radix_init_pgtable() into a separate
function that will also be used for memory hotplug.
The current goto loop progressively decreases its mapping size as it
covers the tail of a range whose end is unaligned. Change this to a for
loop which can do the same for both ends of the range.
Signed-off-by: Reza Arbab <redacted>