* [PATCH 1/2] powerpc: thp: don't recompute vsid and ssize in loop on invalidate
@ 2014-07-15 14:52 Aneesh Kumar K.V
2014-07-15 14:52 ` [PATCH 2/2] powerpc: thp: invalidate old 64K based hash page mapping before insert Aneesh Kumar K.V
0 siblings, 1 reply; 4+ messages in thread
From: Aneesh Kumar K.V @ 2014-07-15 14:52 UTC (permalink / raw)
To: benh, paulus; +Cc: linuxppc-dev, Aneesh Kumar K.V
The segment identifier and segment size will remain the same in
the loop, So we can compute it outside. We also change the
hugepage_invalidate interface so that we can use it the later patch
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/machdep.h | 6 +++---
arch/powerpc/mm/hash_native_64.c | 19 +++++--------------
arch/powerpc/mm/pgtable_64.c | 24 ++++++++++++------------
arch/powerpc/platforms/pseries/lpar.c | 20 ++++++--------------
4 files changed, 26 insertions(+), 43 deletions(-)
diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h
index f92b0b54e921..8dcb721d03d8 100644
--- a/arch/powerpc/include/asm/machdep.h
+++ b/arch/powerpc/include/asm/machdep.h
@@ -57,10 +57,10 @@ struct machdep_calls {
void (*hpte_removebolted)(unsigned long ea,
int psize, int ssize);
void (*flush_hash_range)(unsigned long number, int local);
- void (*hugepage_invalidate)(struct mm_struct *mm,
+ void (*hugepage_invalidate)(unsigned long vsid,
+ unsigned long addr,
unsigned char *hpte_slot_array,
- unsigned long addr, int psize);
-
+ int psize, int ssize);
/* special for kexec, to be called in real mode, linear mapping is
* destroyed as well */
void (*hpte_clear_all)(void);
diff --git a/arch/powerpc/mm/hash_native_64.c b/arch/powerpc/mm/hash_native_64.c
index cf1d325eae8b..fb89d7695a9a 100644
--- a/arch/powerpc/mm/hash_native_64.c
+++ b/arch/powerpc/mm/hash_native_64.c
@@ -412,18 +412,18 @@ static void native_hpte_invalidate(unsigned long slot, unsigned long vpn,
local_irq_restore(flags);
}
-static void native_hugepage_invalidate(struct mm_struct *mm,
+static void native_hugepage_invalidate(unsigned long vsid,
+ unsigned long addr,
unsigned char *hpte_slot_array,
- unsigned long addr, int psize)
+ int psize, int ssize)
{
- int ssize = 0, i;
- int lock_tlbie;
+ int i, lock_tlbie;
struct hash_pte *hptep;
int actual_psize = MMU_PAGE_16M;
unsigned int max_hpte_count, valid;
unsigned long flags, s_addr = addr;
unsigned long hpte_v, want_v, shift;
- unsigned long hidx, vpn = 0, vsid, hash, slot;
+ unsigned long hidx, vpn = 0, hash, slot;
shift = mmu_psize_defs[psize].shift;
max_hpte_count = 1U << (PMD_SHIFT - shift);
@@ -437,15 +437,6 @@ static void native_hugepage_invalidate(struct mm_struct *mm,
/* get the vpn */
addr = s_addr + (i * (1ul << shift));
- if (!is_kernel_addr(addr)) {
- ssize = user_segment_size(addr);
- vsid = get_vsid(mm->context.id, addr, ssize);
- WARN_ON(vsid == 0);
- } else {
- vsid = get_kernel_vsid(addr, mmu_kernel_ssize);
- ssize = mmu_kernel_ssize;
- }
-
vpn = hpt_vpn(addr, vsid, ssize);
hash = hpt_hash(vpn, shift, ssize);
if (hidx & _PTEIDX_SECONDARY)
diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c
index f6ce1f111f5b..ac8c0754a4e9 100644
--- a/arch/powerpc/mm/pgtable_64.c
+++ b/arch/powerpc/mm/pgtable_64.c
@@ -745,12 +745,21 @@ void hpte_do_hugepage_flush(struct mm_struct *mm, unsigned long addr,
if (!hpte_slot_array)
return;
- /* get the base page size */
+ /* get the base page size,vsid and segment size */
psize = get_slice_psize(mm, s_addr);
+ if (!is_kernel_addr(s_addr)) {
+ ssize = user_segment_size(s_addr);
+ vsid = get_vsid(mm->context.id, s_addr, ssize);
+ WARN_ON(vsid == 0);
+ } else {
+ vsid = get_kernel_vsid(s_addr, mmu_kernel_ssize);
+ ssize = mmu_kernel_ssize;
+ }
if (ppc_md.hugepage_invalidate)
- return ppc_md.hugepage_invalidate(mm, hpte_slot_array,
- s_addr, psize);
+ return ppc_md.hugepage_invalidate(vsid, s_addr,
+ hpte_slot_array,
+ psize, ssize);
/*
* No bluk hpte removal support, invalidate each entry
*/
@@ -768,15 +777,6 @@ void hpte_do_hugepage_flush(struct mm_struct *mm, unsigned long addr,
/* get the vpn */
addr = s_addr + (i * (1ul << shift));
- if (!is_kernel_addr(addr)) {
- ssize = user_segment_size(addr);
- vsid = get_vsid(mm->context.id, addr, ssize);
- WARN_ON(vsid == 0);
- } else {
- vsid = get_kernel_vsid(addr, mmu_kernel_ssize);
- ssize = mmu_kernel_ssize;
- }
-
vpn = hpt_vpn(addr, vsid, ssize);
hash = hpt_hash(vpn, shift, ssize);
if (hidx & _PTEIDX_SECONDARY)
diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c
index b02af9ef3ff6..ccf6f162f69c 100644
--- a/arch/powerpc/platforms/pseries/lpar.c
+++ b/arch/powerpc/platforms/pseries/lpar.c
@@ -430,16 +430,17 @@ static void __pSeries_lpar_hugepage_invalidate(unsigned long *slot,
spin_unlock_irqrestore(&pSeries_lpar_tlbie_lock, flags);
}
-static void pSeries_lpar_hugepage_invalidate(struct mm_struct *mm,
- unsigned char *hpte_slot_array,
- unsigned long addr, int psize)
+static void pSeries_lpar_hugepage_invalidate(unsigned long vsid,
+ unsigned long addr,
+ unsigned char *hpte_slot_array,
+ int psize, int ssize)
{
- int ssize = 0, i, index = 0;
+ int i, index = 0;
unsigned long s_addr = addr;
unsigned int max_hpte_count, valid;
unsigned long vpn_array[PPC64_HUGE_HPTE_BATCH];
unsigned long slot_array[PPC64_HUGE_HPTE_BATCH];
- unsigned long shift, hidx, vpn = 0, vsid, hash, slot;
+ unsigned long shift, hidx, vpn = 0, hash, slot;
shift = mmu_psize_defs[psize].shift;
max_hpte_count = 1U << (PMD_SHIFT - shift);
@@ -452,15 +453,6 @@ static void pSeries_lpar_hugepage_invalidate(struct mm_struct *mm,
/* get the vpn */
addr = s_addr + (i * (1ul << shift));
- if (!is_kernel_addr(addr)) {
- ssize = user_segment_size(addr);
- vsid = get_vsid(mm->context.id, addr, ssize);
- WARN_ON(vsid == 0);
- } else {
- vsid = get_kernel_vsid(addr, mmu_kernel_ssize);
- ssize = mmu_kernel_ssize;
- }
-
vpn = hpt_vpn(addr, vsid, ssize);
hash = hpt_hash(vpn, shift, ssize);
if (hidx & _PTEIDX_SECONDARY)
--
1.9.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH 2/2] powerpc: thp: invalidate old 64K based hash page mapping before insert
2014-07-15 14:52 [PATCH 1/2] powerpc: thp: don't recompute vsid and ssize in loop on invalidate Aneesh Kumar K.V
@ 2014-07-15 14:52 ` Aneesh Kumar K.V
2014-07-22 5:32 ` Benjamin Herrenschmidt
0 siblings, 1 reply; 4+ messages in thread
From: Aneesh Kumar K.V @ 2014-07-15 14:52 UTC (permalink / raw)
To: benh, paulus; +Cc: linuxppc-dev, Aneesh Kumar K.V
If we changed base page size of the segment, either via sub_page_protect
or via remap_4k_pfn, we do a demote_segment which doesn't flush the hash
table entries. We do that when inserting a new hash pte by checking the
_PAGE_COMBO flag. We missed to do that when inserting hash for a new 16MB
page. Add the same. This patch mark the 4k base page size 16MB hugepage
via _PAGE_COMBO.
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
---
arch/powerpc/mm/hugepage-hash64.c | 66 +++++++++++++++++++++++++++++++++++++++
1 file changed, 66 insertions(+)
diff --git a/arch/powerpc/mm/hugepage-hash64.c b/arch/powerpc/mm/hugepage-hash64.c
index 826893fcb3a7..28d1b8b93674 100644
--- a/arch/powerpc/mm/hugepage-hash64.c
+++ b/arch/powerpc/mm/hugepage-hash64.c
@@ -18,6 +18,56 @@
#include <linux/mm.h>
#include <asm/machdep.h>
+static void flush_hash_hugepage(unsigned long vsid, unsigned long addr,
+ pmd_t *pmdp, unsigned int psize, int ssize)
+{
+ int i, max_hpte_count, valid;
+ unsigned long s_addr = addr;
+ unsigned char *hpte_slot_array;
+ unsigned long hidx, shift, vpn, hash, slot;
+
+ hpte_slot_array = get_hpte_slot_array(pmdp);
+ /*
+ * IF we try to do a HUGE PTE update after a withdraw is done.
+ * we will find the below NULL. This happens when we do
+ * split_huge_page_pmd
+ */
+ if (!hpte_slot_array)
+ return;
+
+ if (ppc_md.hugepage_invalidate)
+ return ppc_md.hugepage_invalidate(vsid, addr, hpte_slot_array,
+ psize, ssize);
+ /*
+ * No bluk hpte removal support, invalidate each entry
+ */
+ shift = mmu_psize_defs[psize].shift;
+ max_hpte_count = HPAGE_PMD_SIZE >> shift;
+ for (i = 0; i < max_hpte_count; i++) {
+ /*
+ * 8 bits per each hpte entries
+ * 000| [ secondary group (one bit) | hidx (3 bits) | valid bit]
+ */
+ valid = hpte_valid(hpte_slot_array, i);
+ if (!valid)
+ continue;
+ hidx = hpte_hash_index(hpte_slot_array, i);
+
+ /* get the vpn */
+ addr = s_addr + (i * (1ul << shift));
+ vpn = hpt_vpn(addr, vsid, ssize);
+ hash = hpt_hash(vpn, shift, ssize);
+ if (hidx & _PTEIDX_SECONDARY)
+ hash = ~hash;
+
+ slot = (hash & htab_hash_mask) * HPTES_PER_GROUP;
+ slot += hidx & _PTEIDX_GROUP_IX;
+ ppc_md.hpte_invalidate(slot, vpn, psize,
+ MMU_PAGE_16M, ssize, 0);
+ }
+}
+
+
int __hash_page_thp(unsigned long ea, unsigned long access, unsigned long vsid,
pmd_t *pmdp, unsigned long trap, int local, int ssize,
unsigned int psize)
@@ -85,6 +135,15 @@ int __hash_page_thp(unsigned long ea, unsigned long access, unsigned long vsid,
vpn = hpt_vpn(ea, vsid, ssize);
hash = hpt_hash(vpn, shift, ssize);
hpte_slot_array = get_hpte_slot_array(pmdp);
+ if (psize == MMU_PAGE_4K) {
+ /*
+ * invalidate the old hpte entry if we have that mapped via 64K
+ * base page size. This is because demote_segment won't flush
+ * hash page table entries.
+ */
+ if (!(old_pmd & _PAGE_COMBO))
+ flush_hash_hugepage(vsid, ea, pmdp, MMU_PAGE_64K, ssize);
+ }
valid = hpte_valid(hpte_slot_array, index);
if (valid) {
@@ -172,6 +231,13 @@ repeat:
mark_hpte_slot_valid(hpte_slot_array, index, slot);
}
/*
+ * Mark the pte with _PAGE_COMBO, if we are trying to hash it with
+ * base page size 4k.
+ */
+ if (psize == MMU_PAGE_4K)
+ new_pmd |= _PAGE_COMBO;
+
+ /*
* No need to use ldarx/stdcx here
*/
*pmdp = __pmd(new_pmd & ~_PAGE_BUSY);
--
1.9.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH 2/2] powerpc: thp: invalidate old 64K based hash page mapping before insert
2014-07-15 14:52 ` [PATCH 2/2] powerpc: thp: invalidate old 64K based hash page mapping before insert Aneesh Kumar K.V
@ 2014-07-22 5:32 ` Benjamin Herrenschmidt
2014-07-22 18:55 ` Aneesh Kumar K.V
0 siblings, 1 reply; 4+ messages in thread
From: Benjamin Herrenschmidt @ 2014-07-22 5:32 UTC (permalink / raw)
To: Aneesh Kumar K.V; +Cc: linuxppc-dev, paulus
On Tue, 2014-07-15 at 20:22 +0530, Aneesh Kumar K.V wrote:
> If we changed base page size of the segment, either via sub_page_protect
> or via remap_4k_pfn, we do a demote_segment which doesn't flush the hash
> table entries. We do that when inserting a new hash pte by checking the
> _PAGE_COMBO flag. We missed to do that when inserting hash for a new 16MB
> page. Add the same. This patch mark the 4k base page size 16MB hugepage
> via _PAGE_COMBO.
please improve the above, I don't understand it.
> Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
> ---
> arch/powerpc/mm/hugepage-hash64.c | 66 +++++++++++++++++++++++++++++++++++++++
> 1 file changed, 66 insertions(+)
>
> diff --git a/arch/powerpc/mm/hugepage-hash64.c b/arch/powerpc/mm/hugepage-hash64.c
> index 826893fcb3a7..28d1b8b93674 100644
> --- a/arch/powerpc/mm/hugepage-hash64.c
> +++ b/arch/powerpc/mm/hugepage-hash64.c
> @@ -18,6 +18,56 @@
> #include <linux/mm.h>
> #include <asm/machdep.h>
>
> +static void flush_hash_hugepage(unsigned long vsid, unsigned long addr,
> + pmd_t *pmdp, unsigned int psize, int ssize)
> +{
What do that function do ? From the name of it, it would be used
whenever one wants to flush a huge page out of the hash, and thus would
be rather generic, but you only use it in a fairly narrow special
case...
> + int i, max_hpte_count, valid;
> + unsigned long s_addr = addr;
> + unsigned char *hpte_slot_array;
> + unsigned long hidx, shift, vpn, hash, slot;
> +
> + hpte_slot_array = get_hpte_slot_array(pmdp);
> + /*
> + * IF we try to do a HUGE PTE update after a withdraw is done.
> + * we will find the below NULL. This happens when we do
> + * split_huge_page_pmd
> + */
> + if (!hpte_slot_array)
> + return;
Can I assume we proper synchronization here ? (Interrupt off vs. IPIs on
the withdraw side or something similar ?)
> + if (ppc_md.hugepage_invalidate)
> + return ppc_md.hugepage_invalidate(vsid, addr, hpte_slot_array,
> + psize, ssize);
> + /*
> + * No bluk hpte removal support, invalidate each entry
> + */
> + shift = mmu_psize_defs[psize].shift;
> + max_hpte_count = HPAGE_PMD_SIZE >> shift;
> + for (i = 0; i < max_hpte_count; i++) {
> + /*
> + * 8 bits per each hpte entries
> + * 000| [ secondary group (one bit) | hidx (3 bits) | valid bit]
> + */
> + valid = hpte_valid(hpte_slot_array, i);
> + if (!valid)
> + continue;
> + hidx = hpte_hash_index(hpte_slot_array, i);
> +
> + /* get the vpn */
> + addr = s_addr + (i * (1ul << shift));
> + vpn = hpt_vpn(addr, vsid, ssize);
> + hash = hpt_hash(vpn, shift, ssize);
> + if (hidx & _PTEIDX_SECONDARY)
> + hash = ~hash;
> +
> + slot = (hash & htab_hash_mask) * HPTES_PER_GROUP;
> + slot += hidx & _PTEIDX_GROUP_IX;
> + ppc_md.hpte_invalidate(slot, vpn, psize,
> + MMU_PAGE_16M, ssize, 0);
> + }
> +}
> +
> +
> int __hash_page_thp(unsigned long ea, unsigned long access, unsigned long vsid,
> pmd_t *pmdp, unsigned long trap, int local, int ssize,
> unsigned int psize)
> @@ -85,6 +135,15 @@ int __hash_page_thp(unsigned long ea, unsigned long access, unsigned long vsid,
> vpn = hpt_vpn(ea, vsid, ssize);
> hash = hpt_hash(vpn, shift, ssize);
> hpte_slot_array = get_hpte_slot_array(pmdp);
> + if (psize == MMU_PAGE_4K) {
> + /*
> + * invalidate the old hpte entry if we have that mapped via 64K
> + * base page size. This is because demote_segment won't flush
> + * hash page table entries.
> + */
Please provide a better explanation of the scenario, this is really not
clear to me.
> + if (!(old_pmd & _PAGE_COMBO))
> + flush_hash_hugepage(vsid, ea, pmdp, MMU_PAGE_64K, ssize);
> + }
>
> valid = hpte_valid(hpte_slot_array, index);
> if (valid) {
> @@ -172,6 +231,13 @@ repeat:
> mark_hpte_slot_valid(hpte_slot_array, index, slot);
> }
> /*
> + * Mark the pte with _PAGE_COMBO, if we are trying to hash it with
> + * base page size 4k.
> + */
> + if (psize == MMU_PAGE_4K)
> + new_pmd |= _PAGE_COMBO;
> +
> +
Why ? Please explain.
Ben.
> /*
> * No need to use ldarx/stdcx here
> */
> *pmdp = __pmd(new_pmd & ~_PAGE_BUSY);
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH 2/2] powerpc: thp: invalidate old 64K based hash page mapping before insert
2014-07-22 5:32 ` Benjamin Herrenschmidt
@ 2014-07-22 18:55 ` Aneesh Kumar K.V
0 siblings, 0 replies; 4+ messages in thread
From: Aneesh Kumar K.V @ 2014-07-22 18:55 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: paulus, linuxppc-dev
Benjamin Herrenschmidt <benh@kernel.crashing.org> writes:
> On Tue, 2014-07-15 at 20:22 +0530, Aneesh Kumar K.V wrote:
>> If we changed base page size of the segment, either via sub_page_protect
>> or via remap_4k_pfn, we do a demote_segment which doesn't flush the hash
>> table entries. We do that when inserting a new hash pte by checking the
>> _PAGE_COMBO flag. We missed to do that when inserting hash for a new 16MB
>> page. Add the same. This patch mark the 4k base page size 16MB hugepage
>> via _PAGE_COMBO.
>
> please improve the above, I don't understand it.
I have reworked this patch and will send an updated version. We also
need to handle _PAGE_COMBO condition on hugepage_flush. I will add more
comments in the next update.
-aneesh
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2014-07-22 18:55 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-07-15 14:52 [PATCH 1/2] powerpc: thp: don't recompute vsid and ssize in loop on invalidate Aneesh Kumar K.V
2014-07-15 14:52 ` [PATCH 2/2] powerpc: thp: invalidate old 64K based hash page mapping before insert Aneesh Kumar K.V
2014-07-22 5:32 ` Benjamin Herrenschmidt
2014-07-22 18:55 ` Aneesh Kumar K.V
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.