2007-04-30 13:30:56 +07:00
|
|
|
#ifndef _ASM_POWERPC_PGTABLE_PPC64_H_
|
|
|
|
#define _ASM_POWERPC_PGTABLE_PPC64_H_
|
|
|
|
/*
|
|
|
|
* This file contains the functions and defines necessary to modify and use
|
|
|
|
* the ppc64 hashed page table.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef __ASSEMBLY__
|
|
|
|
#include <linux/stddef.h>
|
|
|
|
#include <asm/tlbflush.h>
|
|
|
|
#endif /* __ASSEMBLY__ */
|
|
|
|
|
|
|
|
#ifdef CONFIG_PPC_64K_PAGES
|
2009-03-11 00:53:29 +07:00
|
|
|
#include <asm/pgtable-ppc64-64k.h>
|
2007-04-30 13:30:56 +07:00
|
|
|
#else
|
2009-03-11 00:53:29 +07:00
|
|
|
#include <asm/pgtable-ppc64-4k.h>
|
2007-04-30 13:30:56 +07:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#define FIRST_USER_ADDRESS 0
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Size of EA range mapped by our pagetables.
|
|
|
|
*/
|
|
|
|
#define PGTABLE_EADDR_SIZE (PTE_INDEX_SIZE + PMD_INDEX_SIZE + \
|
|
|
|
PUD_INDEX_SIZE + PGD_INDEX_SIZE + PAGE_SHIFT)
|
[POWERPC] Rewrite IO allocation & mapping on powerpc64
This rewrites pretty much from scratch the handling of MMIO and PIO
space allocations on powerpc64. The main goals are:
- Get rid of imalloc and use more common code where possible
- Simplify the current mess so that PIO space is allocated and
mapped in a single place for PCI bridges
- Handle allocation constraints of PIO for all bridges including
hot plugged ones within the 2GB space reserved for IO ports,
so that devices on hotplugged busses will now work with drivers
that assume IO ports fit in an int.
- Cleanup and separate tracking of the ISA space in the reserved
low 64K of IO space. No ISA -> Nothing mapped there.
I booted a cell blade with IDE on PIO and MMIO and a dual G5 so
far, that's it :-)
With this patch, all allocations are done using the code in
mm/vmalloc.c, though we use the low level __get_vm_area with
explicit start/stop constraints in order to manage separate
areas for vmalloc/vmap, ioremap, and PCI IOs.
This greatly simplifies a lot of things, as you can see in the
diffstat of that patch :-)
A new pair of functions pcibios_map/unmap_io_space() now replace
all of the previous code that used to manipulate PCI IOs space.
The allocation is done at mapping time, which is now called from
scan_phb's, just before the devices are probed (instead of after,
which is by itself a bug fix). The only other caller is the PCI
hotplug code for hot adding PCI-PCI bridges (slots).
imalloc is gone, as is the "sub-allocation" thing, but I do beleive
that hotplug should still work in the sense that the space allocation
is always done by the PHB, but if you unmap a child bus of this PHB
(which seems to be possible), then the code should properly tear
down all the HPTE mappings for that area of the PHB allocated IO space.
I now always reserve the first 64K of IO space for the bridge with
the ISA bus on it. I have moved the code for tracking ISA in a separate
file which should also make it smarter if we ever are capable of
hot unplugging or re-plugging an ISA bridge.
This should have a side effect on platforms like powermac where VGA IOs
will no longer work. This is done on purpose though as they would have
worked semi-randomly before. The idea at this point is to isolate drivers
that might need to access those and fix them by providing a proper
function to obtain an offset to the legacy IOs of a given bus.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
2007-06-04 12:15:36 +07:00
|
|
|
#define PGTABLE_RANGE (ASM_CONST(1) << PGTABLE_EADDR_SIZE)
|
2007-04-30 13:30:56 +07:00
|
|
|
|
2009-03-11 00:53:29 +07:00
|
|
|
|
|
|
|
/* Some sanity checking */
|
2007-04-30 13:30:56 +07:00
|
|
|
#if TASK_SIZE_USER64 > PGTABLE_RANGE
|
|
|
|
#error TASK_SIZE_USER64 exceeds pagetable range
|
|
|
|
#endif
|
|
|
|
|
2009-06-03 04:17:45 +07:00
|
|
|
#ifdef CONFIG_PPC_STD_MMU_64
|
2007-04-30 13:30:56 +07:00
|
|
|
#if TASK_SIZE_USER64 > (1UL << (USER_ESID_BITS + SID_SHIFT))
|
|
|
|
#error TASK_SIZE_USER64 exceeds user VSID range
|
|
|
|
#endif
|
2009-06-03 04:17:45 +07:00
|
|
|
#endif
|
2007-04-30 13:30:56 +07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Define the address range of the vmalloc VM area.
|
|
|
|
*/
|
|
|
|
#define VMALLOC_START ASM_CONST(0xD000000000000000)
|
[POWERPC] Rewrite IO allocation & mapping on powerpc64
This rewrites pretty much from scratch the handling of MMIO and PIO
space allocations on powerpc64. The main goals are:
- Get rid of imalloc and use more common code where possible
- Simplify the current mess so that PIO space is allocated and
mapped in a single place for PCI bridges
- Handle allocation constraints of PIO for all bridges including
hot plugged ones within the 2GB space reserved for IO ports,
so that devices on hotplugged busses will now work with drivers
that assume IO ports fit in an int.
- Cleanup and separate tracking of the ISA space in the reserved
low 64K of IO space. No ISA -> Nothing mapped there.
I booted a cell blade with IDE on PIO and MMIO and a dual G5 so
far, that's it :-)
With this patch, all allocations are done using the code in
mm/vmalloc.c, though we use the low level __get_vm_area with
explicit start/stop constraints in order to manage separate
areas for vmalloc/vmap, ioremap, and PCI IOs.
This greatly simplifies a lot of things, as you can see in the
diffstat of that patch :-)
A new pair of functions pcibios_map/unmap_io_space() now replace
all of the previous code that used to manipulate PCI IOs space.
The allocation is done at mapping time, which is now called from
scan_phb's, just before the devices are probed (instead of after,
which is by itself a bug fix). The only other caller is the PCI
hotplug code for hot adding PCI-PCI bridges (slots).
imalloc is gone, as is the "sub-allocation" thing, but I do beleive
that hotplug should still work in the sense that the space allocation
is always done by the PHB, but if you unmap a child bus of this PHB
(which seems to be possible), then the code should properly tear
down all the HPTE mappings for that area of the PHB allocated IO space.
I now always reserve the first 64K of IO space for the bridge with
the ISA bus on it. I have moved the code for tracking ISA in a separate
file which should also make it smarter if we ever are capable of
hot unplugging or re-plugging an ISA bridge.
This should have a side effect on platforms like powermac where VGA IOs
will no longer work. This is done on purpose though as they would have
worked semi-randomly before. The idea at this point is to isolate drivers
that might need to access those and fix them by providing a proper
function to obtain an offset to the legacy IOs of a given bus.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
2007-06-04 12:15:36 +07:00
|
|
|
#define VMALLOC_SIZE (PGTABLE_RANGE >> 1)
|
2007-04-30 13:30:56 +07:00
|
|
|
#define VMALLOC_END (VMALLOC_START + VMALLOC_SIZE)
|
|
|
|
|
|
|
|
/*
|
[POWERPC] Rewrite IO allocation & mapping on powerpc64
This rewrites pretty much from scratch the handling of MMIO and PIO
space allocations on powerpc64. The main goals are:
- Get rid of imalloc and use more common code where possible
- Simplify the current mess so that PIO space is allocated and
mapped in a single place for PCI bridges
- Handle allocation constraints of PIO for all bridges including
hot plugged ones within the 2GB space reserved for IO ports,
so that devices on hotplugged busses will now work with drivers
that assume IO ports fit in an int.
- Cleanup and separate tracking of the ISA space in the reserved
low 64K of IO space. No ISA -> Nothing mapped there.
I booted a cell blade with IDE on PIO and MMIO and a dual G5 so
far, that's it :-)
With this patch, all allocations are done using the code in
mm/vmalloc.c, though we use the low level __get_vm_area with
explicit start/stop constraints in order to manage separate
areas for vmalloc/vmap, ioremap, and PCI IOs.
This greatly simplifies a lot of things, as you can see in the
diffstat of that patch :-)
A new pair of functions pcibios_map/unmap_io_space() now replace
all of the previous code that used to manipulate PCI IOs space.
The allocation is done at mapping time, which is now called from
scan_phb's, just before the devices are probed (instead of after,
which is by itself a bug fix). The only other caller is the PCI
hotplug code for hot adding PCI-PCI bridges (slots).
imalloc is gone, as is the "sub-allocation" thing, but I do beleive
that hotplug should still work in the sense that the space allocation
is always done by the PHB, but if you unmap a child bus of this PHB
(which seems to be possible), then the code should properly tear
down all the HPTE mappings for that area of the PHB allocated IO space.
I now always reserve the first 64K of IO space for the bridge with
the ISA bus on it. I have moved the code for tracking ISA in a separate
file which should also make it smarter if we ever are capable of
hot unplugging or re-plugging an ISA bridge.
This should have a side effect on platforms like powermac where VGA IOs
will no longer work. This is done on purpose though as they would have
worked semi-randomly before. The idea at this point is to isolate drivers
that might need to access those and fix them by providing a proper
function to obtain an offset to the legacy IOs of a given bus.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
2007-06-04 12:15:36 +07:00
|
|
|
* Define the address ranges for MMIO and IO space :
|
|
|
|
*
|
|
|
|
* ISA_IO_BASE = VMALLOC_END, 64K reserved area
|
|
|
|
* PHB_IO_BASE = ISA_IO_BASE + 64K to ISA_IO_BASE + 2G, PHB IO spaces
|
|
|
|
* IOREMAP_BASE = ISA_IO_BASE + 2G to VMALLOC_START + PGTABLE_RANGE
|
2007-04-30 13:30:56 +07:00
|
|
|
*/
|
[POWERPC] Rewrite IO allocation & mapping on powerpc64
This rewrites pretty much from scratch the handling of MMIO and PIO
space allocations on powerpc64. The main goals are:
- Get rid of imalloc and use more common code where possible
- Simplify the current mess so that PIO space is allocated and
mapped in a single place for PCI bridges
- Handle allocation constraints of PIO for all bridges including
hot plugged ones within the 2GB space reserved for IO ports,
so that devices on hotplugged busses will now work with drivers
that assume IO ports fit in an int.
- Cleanup and separate tracking of the ISA space in the reserved
low 64K of IO space. No ISA -> Nothing mapped there.
I booted a cell blade with IDE on PIO and MMIO and a dual G5 so
far, that's it :-)
With this patch, all allocations are done using the code in
mm/vmalloc.c, though we use the low level __get_vm_area with
explicit start/stop constraints in order to manage separate
areas for vmalloc/vmap, ioremap, and PCI IOs.
This greatly simplifies a lot of things, as you can see in the
diffstat of that patch :-)
A new pair of functions pcibios_map/unmap_io_space() now replace
all of the previous code that used to manipulate PCI IOs space.
The allocation is done at mapping time, which is now called from
scan_phb's, just before the devices are probed (instead of after,
which is by itself a bug fix). The only other caller is the PCI
hotplug code for hot adding PCI-PCI bridges (slots).
imalloc is gone, as is the "sub-allocation" thing, but I do beleive
that hotplug should still work in the sense that the space allocation
is always done by the PHB, but if you unmap a child bus of this PHB
(which seems to be possible), then the code should properly tear
down all the HPTE mappings for that area of the PHB allocated IO space.
I now always reserve the first 64K of IO space for the bridge with
the ISA bus on it. I have moved the code for tracking ISA in a separate
file which should also make it smarter if we ever are capable of
hot unplugging or re-plugging an ISA bridge.
This should have a side effect on platforms like powermac where VGA IOs
will no longer work. This is done on purpose though as they would have
worked semi-randomly before. The idea at this point is to isolate drivers
that might need to access those and fix them by providing a proper
function to obtain an offset to the legacy IOs of a given bus.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
2007-06-04 12:15:36 +07:00
|
|
|
#define FULL_IO_SIZE 0x80000000ul
|
|
|
|
#define ISA_IO_BASE (VMALLOC_END)
|
|
|
|
#define ISA_IO_END (VMALLOC_END + 0x10000ul)
|
|
|
|
#define PHB_IO_BASE (ISA_IO_END)
|
|
|
|
#define PHB_IO_END (VMALLOC_END + FULL_IO_SIZE)
|
|
|
|
#define IOREMAP_BASE (PHB_IO_END)
|
|
|
|
#define IOREMAP_END (VMALLOC_START + PGTABLE_RANGE)
|
2007-04-30 13:30:56 +07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Region IDs
|
|
|
|
*/
|
|
|
|
#define REGION_SHIFT 60UL
|
|
|
|
#define REGION_MASK (0xfUL << REGION_SHIFT)
|
|
|
|
#define REGION_ID(ea) (((unsigned long)(ea)) >> REGION_SHIFT)
|
|
|
|
|
|
|
|
#define VMALLOC_REGION_ID (REGION_ID(VMALLOC_START))
|
|
|
|
#define KERNEL_REGION_ID (REGION_ID(PAGE_OFFSET))
|
[POWERPC] vmemmap fixes to use smaller pages
This changes vmemmap to use a different region (region 0xf) of the
address space, and to configure the page size of that region
dynamically at boot.
The problem with the current approach of always using 16M pages is that
it's not well suited to machines that have small amounts of memory such
as small partitions on pseries, or PS3's.
In fact, on the PS3, failure to allocate the 16M page backing vmmemmap
tends to prevent hotplugging the HV's "additional" memory, thus limiting
the available memory even more, from my experience down to something
like 80M total, which makes it really not very useable.
The logic used by my match to choose the vmemmap page size is:
- If 16M pages are available and there's 1G or more RAM at boot,
use that size.
- Else if 64K pages are available, use that
- Else use 4K pages
I've tested on a POWER6 (16M pages) and on an iSeries POWER3 (4K pages)
and it seems to work fine.
Note that I intend to change the way we organize the kernel regions &
SLBs so the actual region will change from 0xf back to something else at
one point, as I simplify the SLB miss handler, but that will be for a
later patch.
Signed-off-by: Paul Mackerras <paulus@samba.org>
2008-04-30 12:41:48 +07:00
|
|
|
#define VMEMMAP_REGION_ID (0xfUL)
|
2007-04-30 13:30:56 +07:00
|
|
|
#define USER_REGION_ID (0UL)
|
|
|
|
|
2007-10-16 15:24:17 +07:00
|
|
|
/*
|
[POWERPC] vmemmap fixes to use smaller pages
This changes vmemmap to use a different region (region 0xf) of the
address space, and to configure the page size of that region
dynamically at boot.
The problem with the current approach of always using 16M pages is that
it's not well suited to machines that have small amounts of memory such
as small partitions on pseries, or PS3's.
In fact, on the PS3, failure to allocate the 16M page backing vmmemmap
tends to prevent hotplugging the HV's "additional" memory, thus limiting
the available memory even more, from my experience down to something
like 80M total, which makes it really not very useable.
The logic used by my match to choose the vmemmap page size is:
- If 16M pages are available and there's 1G or more RAM at boot,
use that size.
- Else if 64K pages are available, use that
- Else use 4K pages
I've tested on a POWER6 (16M pages) and on an iSeries POWER3 (4K pages)
and it seems to work fine.
Note that I intend to change the way we organize the kernel regions &
SLBs so the actual region will change from 0xf back to something else at
one point, as I simplify the SLB miss handler, but that will be for a
later patch.
Signed-off-by: Paul Mackerras <paulus@samba.org>
2008-04-30 12:41:48 +07:00
|
|
|
* Defines the address of the vmemap area, in its own region
|
2007-10-16 15:24:17 +07:00
|
|
|
*/
|
[POWERPC] vmemmap fixes to use smaller pages
This changes vmemmap to use a different region (region 0xf) of the
address space, and to configure the page size of that region
dynamically at boot.
The problem with the current approach of always using 16M pages is that
it's not well suited to machines that have small amounts of memory such
as small partitions on pseries, or PS3's.
In fact, on the PS3, failure to allocate the 16M page backing vmmemmap
tends to prevent hotplugging the HV's "additional" memory, thus limiting
the available memory even more, from my experience down to something
like 80M total, which makes it really not very useable.
The logic used by my match to choose the vmemmap page size is:
- If 16M pages are available and there's 1G or more RAM at boot,
use that size.
- Else if 64K pages are available, use that
- Else use 4K pages
I've tested on a POWER6 (16M pages) and on an iSeries POWER3 (4K pages)
and it seems to work fine.
Note that I intend to change the way we organize the kernel regions &
SLBs so the actual region will change from 0xf back to something else at
one point, as I simplify the SLB miss handler, but that will be for a
later patch.
Signed-off-by: Paul Mackerras <paulus@samba.org>
2008-04-30 12:41:48 +07:00
|
|
|
#define VMEMMAP_BASE (VMEMMAP_REGION_ID << REGION_SHIFT)
|
|
|
|
#define vmemmap ((struct page *)VMEMMAP_BASE)
|
|
|
|
|
2007-10-16 15:24:17 +07:00
|
|
|
|
2007-04-30 13:30:56 +07:00
|
|
|
/*
|
2009-03-11 00:53:29 +07:00
|
|
|
* Include the PTE bits definitions
|
2007-04-30 13:30:56 +07:00
|
|
|
*/
|
2009-03-11 00:53:29 +07:00
|
|
|
#include <asm/pte-hash64.h>
|
2009-03-20 02:34:09 +07:00
|
|
|
#include <asm/pte-common.h>
|
2009-03-11 00:53:29 +07:00
|
|
|
|
2007-04-30 13:30:56 +07:00
|
|
|
|
2008-09-03 10:12:05 +07:00
|
|
|
#ifdef CONFIG_PPC_MM_SLICES
|
2007-04-30 13:30:56 +07:00
|
|
|
#define HAVE_ARCH_UNMAPPED_AREA
|
|
|
|
#define HAVE_ARCH_UNMAPPED_AREA_TOPDOWN
|
2008-09-03 10:12:05 +07:00
|
|
|
#endif /* CONFIG_PPC_MM_SLICES */
|
2007-04-30 13:30:56 +07:00
|
|
|
|
|
|
|
#ifndef __ASSEMBLY__
|
|
|
|
|
2009-03-11 00:53:29 +07:00
|
|
|
/*
|
|
|
|
* This is the default implementation of various PTE accessors, it's
|
|
|
|
* used in all cases except Book3S with 64K pages where we have a
|
|
|
|
* concept of sub-pages
|
|
|
|
*/
|
|
|
|
#ifndef __real_pte
|
|
|
|
|
|
|
|
#ifdef STRICT_MM_TYPECHECKS
|
|
|
|
#define __real_pte(e,p) ((real_pte_t){(e)})
|
|
|
|
#define __rpte_to_pte(r) ((r).pte)
|
|
|
|
#else
|
|
|
|
#define __real_pte(e,p) (e)
|
|
|
|
#define __rpte_to_pte(r) (__pte(r))
|
|
|
|
#endif
|
|
|
|
#define __rpte_to_hidx(r,index) (pte_val(__rpte_to_pte(r)) >> 12)
|
|
|
|
|
|
|
|
#define pte_iterate_hashed_subpages(rpte, psize, va, index, shift) \
|
|
|
|
do { \
|
|
|
|
index = 0; \
|
|
|
|
shift = mmu_psize_defs[psize].shift; \
|
|
|
|
|
|
|
|
#define pte_iterate_hashed_end() } while(0)
|
|
|
|
|
|
|
|
#ifdef CONFIG_PPC_HAS_HASH_64K
|
|
|
|
#define pte_pagesize_index(mm, addr, pte) get_slice_psize(mm, addr)
|
|
|
|
#else
|
|
|
|
#define pte_pagesize_index(mm, addr, pte) MMU_PAGE_4K
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#endif /* __real_pte */
|
|
|
|
|
|
|
|
|
2007-04-30 13:30:56 +07:00
|
|
|
/* pte_clear moved to later in this file */
|
|
|
|
|
|
|
|
#define PMD_BAD_BITS (PTE_TABLE_SIZE-1)
|
|
|
|
#define PUD_BAD_BITS (PMD_TABLE_SIZE-1)
|
|
|
|
|
|
|
|
#define pmd_set(pmdp, pmdval) (pmd_val(*(pmdp)) = (pmdval))
|
|
|
|
#define pmd_none(pmd) (!pmd_val(pmd))
|
|
|
|
#define pmd_bad(pmd) (!is_kernel_addr(pmd_val(pmd)) \
|
|
|
|
|| (pmd_val(pmd) & PMD_BAD_BITS))
|
|
|
|
#define pmd_present(pmd) (pmd_val(pmd) != 0)
|
|
|
|
#define pmd_clear(pmdp) (pmd_val(*(pmdp)) = 0)
|
|
|
|
#define pmd_page_vaddr(pmd) (pmd_val(pmd) & ~PMD_MASKED_BITS)
|
|
|
|
#define pmd_page(pmd) virt_to_page(pmd_page_vaddr(pmd))
|
|
|
|
|
|
|
|
#define pud_set(pudp, pudval) (pud_val(*(pudp)) = (pudval))
|
|
|
|
#define pud_none(pud) (!pud_val(pud))
|
|
|
|
#define pud_bad(pud) (!is_kernel_addr(pud_val(pud)) \
|
|
|
|
|| (pud_val(pud) & PUD_BAD_BITS))
|
|
|
|
#define pud_present(pud) (pud_val(pud) != 0)
|
|
|
|
#define pud_clear(pudp) (pud_val(*(pudp)) = 0)
|
|
|
|
#define pud_page_vaddr(pud) (pud_val(pud) & ~PUD_MASKED_BITS)
|
|
|
|
#define pud_page(pud) virt_to_page(pud_page_vaddr(pud))
|
|
|
|
|
|
|
|
#define pgd_set(pgdp, pudp) ({pgd_val(*(pgdp)) = (unsigned long)(pudp);})
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Find an entry in a page-table-directory. We combine the address region
|
|
|
|
* (the high order N bits) and the pgd portion of the address.
|
|
|
|
*/
|
|
|
|
/* to avoid overflow in free_pgtables we don't use PTRS_PER_PGD here */
|
|
|
|
#define pgd_index(address) (((address) >> (PGDIR_SHIFT)) & 0x1ff)
|
|
|
|
|
|
|
|
#define pgd_offset(mm, address) ((mm)->pgd + pgd_index(address))
|
|
|
|
|
|
|
|
#define pmd_offset(pudp,addr) \
|
|
|
|
(((pmd_t *) pud_page_vaddr(*(pudp))) + (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1)))
|
|
|
|
|
|
|
|
#define pte_offset_kernel(dir,addr) \
|
|
|
|
(((pte_t *) pmd_page_vaddr(*(dir))) + (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)))
|
|
|
|
|
|
|
|
#define pte_offset_map(dir,addr) pte_offset_kernel((dir), (addr))
|
|
|
|
#define pte_offset_map_nested(dir,addr) pte_offset_kernel((dir), (addr))
|
|
|
|
#define pte_unmap(pte) do { } while(0)
|
|
|
|
#define pte_unmap_nested(pte) do { } while(0)
|
|
|
|
|
|
|
|
/* to find an entry in a kernel page-table-directory */
|
|
|
|
/* This now only contains the vmalloc pages */
|
|
|
|
#define pgd_offset_k(address) pgd_offset(&init_mm, address)
|
|
|
|
|
|
|
|
|
|
|
|
/* Atomic PTE updates */
|
|
|
|
static inline unsigned long pte_update(struct mm_struct *mm,
|
|
|
|
unsigned long addr,
|
|
|
|
pte_t *ptep, unsigned long clr,
|
|
|
|
int huge)
|
|
|
|
{
|
2009-03-20 02:34:15 +07:00
|
|
|
#ifdef PTE_ATOMIC_UPDATES
|
2007-04-30 13:30:56 +07:00
|
|
|
unsigned long old, tmp;
|
|
|
|
|
|
|
|
__asm__ __volatile__(
|
|
|
|
"1: ldarx %0,0,%3 # pte_update\n\
|
|
|
|
andi. %1,%0,%6\n\
|
|
|
|
bne- 1b \n\
|
|
|
|
andc %1,%0,%4 \n\
|
|
|
|
stdcx. %1,0,%3 \n\
|
|
|
|
bne- 1b"
|
|
|
|
: "=&r" (old), "=&r" (tmp), "=m" (*ptep)
|
|
|
|
: "r" (ptep), "r" (clr), "m" (*ptep), "i" (_PAGE_BUSY)
|
|
|
|
: "cc" );
|
2009-03-20 02:34:15 +07:00
|
|
|
#else
|
|
|
|
unsigned long old = pte_val(*ptep);
|
|
|
|
*ptep = __pte(old & ~clr);
|
|
|
|
#endif
|
powerpc/mm: Rework I$/D$ coherency (v3)
This patch reworks the way we do I and D cache coherency on PowerPC.
The "old" way was split in 3 different parts depending on the processor type:
- Hash with per-page exec support (64-bit and >= POWER4 only) does it
at hashing time, by preventing exec on unclean pages and cleaning pages
on exec faults.
- Everything without per-page exec support (32-bit hash, 8xx, and
64-bit < POWER4) does it for all page going to user space in update_mmu_cache().
- Embedded with per-page exec support does it from do_page_fault() on
exec faults, in a way similar to what the hash code does.
That leads to confusion, and bugs. For example, the method using update_mmu_cache()
is racy on SMP where another processor can see the new PTE and hash it in before
we have cleaned the cache, and then blow trying to execute. This is hard to hit but
I think it has bitten us in the past.
Also, it's inefficient for embedded where we always end up having to do at least
one more page fault.
This reworks the whole thing by moving the cache sync into two main call sites,
though we keep different behaviours depending on the HW capability. The call
sites are set_pte_at() which is now made out of line, and ptep_set_access_flags()
which joins the former in pgtable.c
The base idea for Embedded with per-page exec support, is that we now do the
flush at set_pte_at() time when coming from an exec fault, which allows us
to avoid the double fault problem completely (we can even improve the situation
more by implementing TLB preload in update_mmu_cache() but that's for later).
If for some reason we didn't do it there and we try to execute, we'll hit
the page fault, which will do a minor fault, which will hit ptep_set_access_flags()
to do things like update _PAGE_ACCESSED or _PAGE_DIRTY if needed, we just make
this guys also perform the I/D cache sync for exec faults now. This second path
is the catch all for things that weren't cleaned at set_pte_at() time.
For cpus without per-pag exec support, we always do the sync at set_pte_at(),
thus guaranteeing that when the PTE is visible to other processors, the cache
is clean.
For the 64-bit hash with per-page exec support case, we keep the old mechanism
for now. I'll look into changing it later, once I've reworked a bit how we
use _PAGE_EXEC.
This is also a first step for adding _PAGE_EXEC support for embedded platforms
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
2009-02-10 23:02:37 +07:00
|
|
|
/* huge pages use the old page table lock */
|
|
|
|
if (!huge)
|
|
|
|
assert_pte_locked(mm, addr);
|
|
|
|
|
2009-06-03 04:17:45 +07:00
|
|
|
#ifdef CONFIG_PPC_STD_MMU_64
|
2007-04-30 13:30:56 +07:00
|
|
|
if (old & _PAGE_HASHPTE)
|
|
|
|
hpte_need_flush(mm, addr, ptep, old, huge);
|
2009-06-03 04:17:45 +07:00
|
|
|
#endif
|
|
|
|
|
2007-04-30 13:30:56 +07:00
|
|
|
return old;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int __ptep_test_and_clear_young(struct mm_struct *mm,
|
|
|
|
unsigned long addr, pte_t *ptep)
|
|
|
|
{
|
|
|
|
unsigned long old;
|
|
|
|
|
|
|
|
if ((pte_val(*ptep) & (_PAGE_ACCESSED | _PAGE_HASHPTE)) == 0)
|
|
|
|
return 0;
|
|
|
|
old = pte_update(mm, addr, ptep, _PAGE_ACCESSED, 0);
|
|
|
|
return (old & _PAGE_ACCESSED) != 0;
|
|
|
|
}
|
|
|
|
#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
|
|
|
|
#define ptep_test_and_clear_young(__vma, __addr, __ptep) \
|
|
|
|
({ \
|
|
|
|
int __r; \
|
|
|
|
__r = __ptep_test_and_clear_young((__vma)->vm_mm, __addr, __ptep); \
|
|
|
|
__r; \
|
|
|
|
})
|
|
|
|
|
|
|
|
#define __HAVE_ARCH_PTEP_SET_WRPROTECT
|
|
|
|
static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
|
|
|
|
pte_t *ptep)
|
|
|
|
{
|
|
|
|
unsigned long old;
|
|
|
|
|
|
|
|
if ((pte_val(*ptep) & _PAGE_RW) == 0)
|
|
|
|
return;
|
|
|
|
old = pte_update(mm, addr, ptep, _PAGE_RW, 0);
|
|
|
|
}
|
|
|
|
|
powerpc: Add 64 bit version of huge_ptep_set_wrprotect
The implementation of huge_ptep_set_wrprotect() directly calls
ptep_set_wrprotect() to mark a hugepte write protected. However this
call is not appropriate on ppc64 kernels as this is a small page only
implementation. This can lead to the hash not being flushed correctly
when a mapping is being converted to COW, allowing processes to continue
using the original copy.
Currently huge_ptep_set_wrprotect() unconditionally calls
ptep_set_wrprotect(). This is fine on ppc32 kernels as this call is
generic. On 64 bit this is implemented as:
pte_update(mm, addr, ptep, _PAGE_RW, 0);
On ppc64 this last parameter is the page size and is passed directly on
to hpte_need_flush():
hpte_need_flush(mm, addr, ptep, old, huge);
And this directly affects the page size we pass to flush_hash_page():
flush_hash_page(vaddr, rpte, psize, ssize, 0);
As this changes the way the hash is calculated we will flush the wrong
pages, potentially leaving live hashes to the original page.
Move the definition of huge_ptep_set_wrprotect() to the 32/64 bit specific
headers.
Signed-off-by: Andy Whitcroft <apw@shadowen.org>
Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
2008-06-26 16:55:58 +07:00
|
|
|
static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
|
|
|
|
unsigned long addr, pte_t *ptep)
|
|
|
|
{
|
|
|
|
unsigned long old;
|
|
|
|
|
Correct hash flushing from huge_ptep_set_wrprotect()
As Andy Whitcroft recently pointed out, the current powerpc version of
huge_ptep_set_wrprotect() has a bug. It just calls ptep_set_wrprotect()
which in turn calls pte_update() then hpte_need_flush() with the 'huge'
argument set to 0. This will cause hpte_need_flush() to flush the wrong
hash entries (of any). Andy's fix for this is already in the powerpc
tree as commit 016b33c4958681c24056abed8ec95844a0da80a3.
I have confirmed this is a real bug, not masked by some other
synchronization, with a new testcase for libhugetlbfs. A process write
a (MAP_PRIVATE) hugepage mapping, fork(), then alter the mapping and
have the child incorrectly see the second write.
Therefore, this should be fixed for 2.6.26, and for the stable tree.
Here is a suitable patch for 2.6.26, which I think will also be suitable
for the stable tree (neither of the headers in question has been changed
much recently).
It is cut down slighlty from Andy's original version, in that it does
not include a 32-bit version of huge_ptep_set_wrprotect(). Currently,
hugepages are not supported on any 32-bit powerpc platform. When they
are, a suitable 32-bit version can be added - the only 32-bit hardware
which supports hugepages does not use the conventional hashtable MMU and
so will have different needs anyway.
Signed-off-by: Andy Whitcroft <apw@shadowen.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2008-07-08 12:58:16 +07:00
|
|
|
if ((pte_val(*ptep) & _PAGE_RW) == 0)
|
|
|
|
return;
|
powerpc: Add 64 bit version of huge_ptep_set_wrprotect
The implementation of huge_ptep_set_wrprotect() directly calls
ptep_set_wrprotect() to mark a hugepte write protected. However this
call is not appropriate on ppc64 kernels as this is a small page only
implementation. This can lead to the hash not being flushed correctly
when a mapping is being converted to COW, allowing processes to continue
using the original copy.
Currently huge_ptep_set_wrprotect() unconditionally calls
ptep_set_wrprotect(). This is fine on ppc32 kernels as this call is
generic. On 64 bit this is implemented as:
pte_update(mm, addr, ptep, _PAGE_RW, 0);
On ppc64 this last parameter is the page size and is passed directly on
to hpte_need_flush():
hpte_need_flush(mm, addr, ptep, old, huge);
And this directly affects the page size we pass to flush_hash_page():
flush_hash_page(vaddr, rpte, psize, ssize, 0);
As this changes the way the hash is calculated we will flush the wrong
pages, potentially leaving live hashes to the original page.
Move the definition of huge_ptep_set_wrprotect() to the 32/64 bit specific
headers.
Signed-off-by: Andy Whitcroft <apw@shadowen.org>
Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
2008-06-26 16:55:58 +07:00
|
|
|
old = pte_update(mm, addr, ptep, _PAGE_RW, 1);
|
|
|
|
}
|
2007-04-30 13:30:56 +07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* We currently remove entries from the hashtable regardless of whether
|
|
|
|
* the entry was young or dirty. The generic routines only flush if the
|
|
|
|
* entry was young or dirty which is not good enough.
|
|
|
|
*
|
|
|
|
* We should be more intelligent about this but for the moment we override
|
|
|
|
* these functions and force a tlb flush unconditionally
|
|
|
|
*/
|
|
|
|
#define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
|
|
|
|
#define ptep_clear_flush_young(__vma, __address, __ptep) \
|
|
|
|
({ \
|
|
|
|
int __young = __ptep_test_and_clear_young((__vma)->vm_mm, __address, \
|
|
|
|
__ptep); \
|
|
|
|
__young; \
|
|
|
|
})
|
|
|
|
|
|
|
|
#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Set the dirty and/or accessed bits atomically in a linux PTE, this
|
|
|
|
* function doesn't need to flush the hash entry
|
|
|
|
*/
|
powerpc/mm: Rework I$/D$ coherency (v3)
This patch reworks the way we do I and D cache coherency on PowerPC.
The "old" way was split in 3 different parts depending on the processor type:
- Hash with per-page exec support (64-bit and >= POWER4 only) does it
at hashing time, by preventing exec on unclean pages and cleaning pages
on exec faults.
- Everything without per-page exec support (32-bit hash, 8xx, and
64-bit < POWER4) does it for all page going to user space in update_mmu_cache().
- Embedded with per-page exec support does it from do_page_fault() on
exec faults, in a way similar to what the hash code does.
That leads to confusion, and bugs. For example, the method using update_mmu_cache()
is racy on SMP where another processor can see the new PTE and hash it in before
we have cleaned the cache, and then blow trying to execute. This is hard to hit but
I think it has bitten us in the past.
Also, it's inefficient for embedded where we always end up having to do at least
one more page fault.
This reworks the whole thing by moving the cache sync into two main call sites,
though we keep different behaviours depending on the HW capability. The call
sites are set_pte_at() which is now made out of line, and ptep_set_access_flags()
which joins the former in pgtable.c
The base idea for Embedded with per-page exec support, is that we now do the
flush at set_pte_at() time when coming from an exec fault, which allows us
to avoid the double fault problem completely (we can even improve the situation
more by implementing TLB preload in update_mmu_cache() but that's for later).
If for some reason we didn't do it there and we try to execute, we'll hit
the page fault, which will do a minor fault, which will hit ptep_set_access_flags()
to do things like update _PAGE_ACCESSED or _PAGE_DIRTY if needed, we just make
this guys also perform the I/D cache sync for exec faults now. This second path
is the catch all for things that weren't cleaned at set_pte_at() time.
For cpus without per-pag exec support, we always do the sync at set_pte_at(),
thus guaranteeing that when the PTE is visible to other processors, the cache
is clean.
For the 64-bit hash with per-page exec support case, we keep the old mechanism
for now. I'll look into changing it later, once I've reworked a bit how we
use _PAGE_EXEC.
This is also a first step for adding _PAGE_EXEC support for embedded platforms
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
2009-02-10 23:02:37 +07:00
|
|
|
static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry)
|
2007-04-30 13:30:56 +07:00
|
|
|
{
|
|
|
|
unsigned long bits = pte_val(entry) &
|
2009-03-20 02:34:08 +07:00
|
|
|
(_PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_RW |
|
|
|
|
_PAGE_EXEC | _PAGE_HWEXEC);
|
2009-03-20 02:34:15 +07:00
|
|
|
|
|
|
|
#ifdef PTE_ATOMIC_UPDATES
|
2007-04-30 13:30:56 +07:00
|
|
|
unsigned long old, tmp;
|
|
|
|
|
|
|
|
__asm__ __volatile__(
|
|
|
|
"1: ldarx %0,0,%4\n\
|
|
|
|
andi. %1,%0,%6\n\
|
|
|
|
bne- 1b \n\
|
|
|
|
or %0,%3,%0\n\
|
|
|
|
stdcx. %0,0,%4\n\
|
|
|
|
bne- 1b"
|
|
|
|
:"=&r" (old), "=&r" (tmp), "=m" (*ptep)
|
|
|
|
:"r" (bits), "r" (ptep), "m" (*ptep), "i" (_PAGE_BUSY)
|
|
|
|
:"cc");
|
2009-03-20 02:34:15 +07:00
|
|
|
#else
|
|
|
|
unsigned long old = pte_val(*ptep);
|
|
|
|
*ptep = __pte(old | bits);
|
|
|
|
#endif
|
2007-04-30 13:30:56 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
#define __HAVE_ARCH_PTE_SAME
|
|
|
|
#define pte_same(A,B) (((pte_val(A) ^ pte_val(B)) & ~_PAGE_HPTEFLAGS) == 0)
|
|
|
|
|
|
|
|
#define pte_ERROR(e) \
|
|
|
|
printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e))
|
|
|
|
#define pmd_ERROR(e) \
|
|
|
|
printk("%s:%d: bad pmd %08lx.\n", __FILE__, __LINE__, pmd_val(e))
|
|
|
|
#define pgd_ERROR(e) \
|
|
|
|
printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
|
|
|
|
|
|
|
|
/* Encode and de-code a swap entry */
|
|
|
|
#define __swp_type(entry) (((entry).val >> 1) & 0x3f)
|
|
|
|
#define __swp_offset(entry) ((entry).val >> 8)
|
|
|
|
#define __swp_entry(type, offset) ((swp_entry_t){((type)<< 1)|((offset)<<8)})
|
|
|
|
#define __pte_to_swp_entry(pte) ((swp_entry_t){pte_val(pte) >> PTE_RPN_SHIFT})
|
|
|
|
#define __swp_entry_to_pte(x) ((pte_t) { (x).val << PTE_RPN_SHIFT })
|
|
|
|
#define pte_to_pgoff(pte) (pte_val(pte) >> PTE_RPN_SHIFT)
|
|
|
|
#define pgoff_to_pte(off) ((pte_t) {((off) << PTE_RPN_SHIFT)|_PAGE_FILE})
|
|
|
|
#define PTE_FILE_MAX_BITS (BITS_PER_LONG - PTE_RPN_SHIFT)
|
|
|
|
|
|
|
|
void pgtable_cache_init(void);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* find_linux_pte returns the address of a linux pte for a given
|
|
|
|
* effective address and directory. If not found, it returns zero.
|
|
|
|
*/static inline pte_t *find_linux_pte(pgd_t *pgdir, unsigned long ea)
|
|
|
|
{
|
|
|
|
pgd_t *pg;
|
|
|
|
pud_t *pu;
|
|
|
|
pmd_t *pm;
|
|
|
|
pte_t *pt = NULL;
|
|
|
|
|
|
|
|
pg = pgdir + pgd_index(ea);
|
|
|
|
if (!pgd_none(*pg)) {
|
|
|
|
pu = pud_offset(pg, ea);
|
|
|
|
if (!pud_none(*pu)) {
|
|
|
|
pm = pmd_offset(pu, ea);
|
|
|
|
if (pmd_present(*pm))
|
|
|
|
pt = pte_offset_kernel(pm, ea);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return pt;
|
|
|
|
}
|
|
|
|
|
2008-07-30 12:23:13 +07:00
|
|
|
pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long address);
|
|
|
|
|
2007-04-30 13:30:56 +07:00
|
|
|
#endif /* __ASSEMBLY__ */
|
|
|
|
|
|
|
|
#endif /* _ASM_POWERPC_PGTABLE_PPC64_H_ */
|