Skip to content

Commit

Permalink
[PATCH] ppc64: pgtable.h and other header cleanups
Browse files Browse the repository at this point in the history
This patch started as simply removing a few never-used macros from
asm-ppc64/pgtable.h, then kind of grew.  It now makes a bunch of
cleanups to the ppc64 low-level header files (with corresponding
changes to .c files where necessary) such as:
	- Abolishing never-used macros
	- Eliminating multiple #defines with the same purpose
	- Removing pointless macros (cases where just expanding the
macro everywhere turns out clearer and more sensible)
	- Removing some cases where macros which could be defined in
terms of each other weren't
	- Moving imalloc() related definitions from pgtable.h to their
own header file (imalloc.h)
	- Re-arranging headers to group things more logically
	- Moving all VSID allocation related things to mmu.h, instead
of being split between mmu.h and mmu_context.h
	- Removing some reserved space for flags from the PMD - we're
not using it.
	- Fix some bugs which broke compile with STRICT_MM_TYPECHECKS.

Signed-off-by: David Gibson <dwg@au1.ibm.com>
Acked-by: Paul Mackerras <paulus@samba.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
  • Loading branch information
David Gibson authored and Linus Torvalds committed May 5, 2005
1 parent e685752 commit 1f8d419
Show file tree
Hide file tree
Showing 11 changed files with 219 additions and 239 deletions.
2 changes: 1 addition & 1 deletion arch/ppc64/kernel/pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -438,7 +438,7 @@ pgprot_t pci_phys_mem_access_prot(struct file *file,
int i;

if (page_is_ram(offset >> PAGE_SHIFT))
return prot;
return __pgprot(prot);

prot |= _PAGE_NO_CACHE | _PAGE_GUARDED;

Expand Down
3 changes: 1 addition & 2 deletions arch/ppc64/mm/hash_native.c
Original file line number Diff line number Diff line change
Expand Up @@ -320,8 +320,7 @@ static void native_flush_hash_range(unsigned long context,

j = 0;
for (i = 0; i < number; i++) {
if ((batch->addr[i] >= USER_START) &&
(batch->addr[i] <= USER_END))
if (batch->addr[i] < KERNELBASE)
vsid = get_vsid(context, batch->addr[i]);
else
vsid = get_kernel_vsid(batch->addr[i]);
Expand Down
11 changes: 5 additions & 6 deletions arch/ppc64/mm/hash_utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -298,24 +298,23 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
int local = 0;
cpumask_t tmp;

if ((ea & ~REGION_MASK) > EADDR_MASK)
return 1;

switch (REGION_ID(ea)) {
case USER_REGION_ID:
user_region = 1;
mm = current->mm;
if ((ea > USER_END) || (! mm))
if (! mm)
return 1;

vsid = get_vsid(mm->context.id, ea);
break;
case IO_REGION_ID:
if (ea > IMALLOC_END)
return 1;
mm = &ioremap_mm;
vsid = get_kernel_vsid(ea);
break;
case VMALLOC_REGION_ID:
if (ea > VMALLOC_END)
return 1;
mm = &init_mm;
vsid = get_kernel_vsid(ea);
break;
Expand Down Expand Up @@ -362,7 +361,7 @@ void flush_hash_page(unsigned long context, unsigned long ea, pte_t pte,
unsigned long vsid, vpn, va, hash, secondary, slot;
unsigned long huge = pte_huge(pte);

if ((ea >= USER_START) && (ea <= USER_END))
if (ea < KERNELBASE)
vsid = get_vsid(context, ea);
else
vsid = get_kernel_vsid(ea);
Expand Down
5 changes: 3 additions & 2 deletions arch/ppc64/mm/imalloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <asm/pgalloc.h>
#include <asm/pgtable.h>
#include <asm/semaphore.h>
#include <asm/imalloc.h>

static DECLARE_MUTEX(imlist_sem);
struct vm_struct * imlist = NULL;
Expand All @@ -23,11 +24,11 @@ static int get_free_im_addr(unsigned long size, unsigned long *im_addr)
unsigned long addr;
struct vm_struct **p, *tmp;

addr = IMALLOC_START;
addr = ioremap_bot;
for (p = &imlist; (tmp = *p) ; p = &tmp->next) {
if (size + addr < (unsigned long) tmp->addr)
break;
if ((unsigned long)tmp->addr >= IMALLOC_START)
if ((unsigned long)tmp->addr >= ioremap_bot)
addr = tmp->size + (unsigned long) tmp->addr;
if (addr > IMALLOC_END-size)
return 1;
Expand Down
1 change: 1 addition & 0 deletions arch/ppc64/mm/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
#include <asm/iommu.h>
#include <asm/abs_addr.h>
#include <asm/vdso.h>
#include <asm/imalloc.h>

int mem_init_done;
unsigned long ioremap_bot = IMALLOC_BASE;
Expand Down
5 changes: 5 additions & 0 deletions arch/ppc64/mm/stab.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@
#include <asm/paca.h>
#include <asm/cputable.h>

struct stab_entry {
unsigned long esid_data;
unsigned long vsid_data;
};

/* Both the segment table and SLB code uses the following cache */
#define NR_STAB_CACHE_ENTRIES 8
DEFINE_PER_CPU(long, stab_cache_ptr);
Expand Down
24 changes: 24 additions & 0 deletions include/asm-ppc64/imalloc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#ifndef _PPC64_IMALLOC_H
#define _PPC64_IMALLOC_H

/*
* Define the address range of the imalloc VM area.
*/
#define PHBS_IO_BASE IOREGIONBASE
#define IMALLOC_BASE (IOREGIONBASE + 0x80000000ul) /* Reserve 2 gigs for PHBs */
#define IMALLOC_END (IOREGIONBASE + EADDR_MASK)


/* imalloc region types */
#define IM_REGION_UNUSED 0x1
#define IM_REGION_SUBSET 0x2
#define IM_REGION_EXISTS 0x4
#define IM_REGION_OVERLAP 0x8
#define IM_REGION_SUPERSET 0x10

extern struct vm_struct * im_get_free_area(unsigned long size);
extern struct vm_struct * im_get_area(unsigned long v_addr, unsigned long size,
int region_type);
unsigned long im_free(void *addr);

#endif /* _PPC64_IMALLOC_H */
193 changes: 147 additions & 46 deletions include/asm-ppc64/mmu.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,10 @@

#include <linux/config.h>
#include <asm/page.h>
#include <linux/stringify.h>

#ifndef __ASSEMBLY__

/* Time to allow for more things here */
typedef unsigned long mm_context_id_t;
typedef struct {
mm_context_id_t id;
#ifdef CONFIG_HUGETLB_PAGE
pgd_t *huge_pgdir;
u16 htlb_segs; /* bitmask */
#endif
} mm_context_t;
/*
* Segment table
*/

#define STE_ESID_V 0x80
#define STE_ESID_KS 0x20
Expand All @@ -36,15 +27,48 @@ typedef struct {

#define STE_VSID_SHIFT 12

struct stab_entry {
unsigned long esid_data;
unsigned long vsid_data;
};
/* Location of cpu0's segment table */
#define STAB0_PAGE 0x9
#define STAB0_PHYS_ADDR (STAB0_PAGE<<PAGE_SHIFT)
#define STAB0_VIRT_ADDR (KERNELBASE+STAB0_PHYS_ADDR)

/*
* SLB
*/

/* Hardware Page Table Entry */
#define SLB_NUM_BOLTED 3
#define SLB_CACHE_ENTRIES 8

/* Bits in the SLB ESID word */
#define SLB_ESID_V ASM_CONST(0x0000000008000000) /* valid */

/* Bits in the SLB VSID word */
#define SLB_VSID_SHIFT 12
#define SLB_VSID_KS ASM_CONST(0x0000000000000800)
#define SLB_VSID_KP ASM_CONST(0x0000000000000400)
#define SLB_VSID_N ASM_CONST(0x0000000000000200) /* no-execute */
#define SLB_VSID_L ASM_CONST(0x0000000000000100) /* largepage 16M */
#define SLB_VSID_C ASM_CONST(0x0000000000000080) /* class */

#define SLB_VSID_KERNEL (SLB_VSID_KP|SLB_VSID_C)
#define SLB_VSID_USER (SLB_VSID_KP|SLB_VSID_KS)

/*
* Hash table
*/

#define HPTES_PER_GROUP 8

/* Values for PP (assumes Ks=0, Kp=1) */
/* pp0 will always be 0 for linux */
#define PP_RWXX 0 /* Supervisor read/write, User none */
#define PP_RWRX 1 /* Supervisor read/write, User read */
#define PP_RWRW 2 /* Supervisor read/write, User read/write */
#define PP_RXRX 3 /* Supervisor read, User read */

#ifndef __ASSEMBLY__

/* Hardware Page Table Entry */
typedef struct {
unsigned long avpn:57; /* vsid | api == avpn */
unsigned long : 2; /* Software use */
Expand Down Expand Up @@ -90,14 +114,6 @@ typedef struct {
} dw1;
} HPTE;

/* Values for PP (assumes Ks=0, Kp=1) */
/* pp0 will always be 0 for linux */
#define PP_RWXX 0 /* Supervisor read/write, User none */
#define PP_RWRX 1 /* Supervisor read/write, User read */
#define PP_RWRW 2 /* Supervisor read/write, User read/write */
#define PP_RXRX 3 /* Supervisor read, User read */


extern HPTE * htab_address;
extern unsigned long htab_hash_mask;

Expand Down Expand Up @@ -174,31 +190,70 @@ extern int __hash_page(unsigned long ea, unsigned long access,

extern void htab_finish_init(void);

extern void hpte_init_native(void);
extern void hpte_init_lpar(void);
extern void hpte_init_iSeries(void);

extern long pSeries_lpar_hpte_insert(unsigned long hpte_group,
unsigned long va, unsigned long prpn,
int secondary, unsigned long hpteflags,
int bolted, int large);
extern long native_hpte_insert(unsigned long hpte_group, unsigned long va,
unsigned long prpn, int secondary,
unsigned long hpteflags, int bolted, int large);

#endif /* __ASSEMBLY__ */

/*
* Location of cpu0's segment table
* VSID allocation
*
* We first generate a 36-bit "proto-VSID". For kernel addresses this
* is equal to the ESID, for user addresses it is:
* (context << 15) | (esid & 0x7fff)
*
* The two forms are distinguishable because the top bit is 0 for user
* addresses, whereas the top two bits are 1 for kernel addresses.
* Proto-VSIDs with the top two bits equal to 0b10 are reserved for
* now.
*
* The proto-VSIDs are then scrambled into real VSIDs with the
* multiplicative hash:
*
* VSID = (proto-VSID * VSID_MULTIPLIER) % VSID_MODULUS
* where VSID_MULTIPLIER = 268435399 = 0xFFFFFC7
* VSID_MODULUS = 2^36-1 = 0xFFFFFFFFF
*
* This scramble is only well defined for proto-VSIDs below
* 0xFFFFFFFFF, so both proto-VSID and actual VSID 0xFFFFFFFFF are
* reserved. VSID_MULTIPLIER is prime, so in particular it is
* co-prime to VSID_MODULUS, making this a 1:1 scrambling function.
* Because the modulus is 2^n-1 we can compute it efficiently without
* a divide or extra multiply (see below).
*
* This scheme has several advantages over older methods:
*
* - We have VSIDs allocated for every kernel address
* (i.e. everything above 0xC000000000000000), except the very top
* segment, which simplifies several things.
*
* - We allow for 15 significant bits of ESID and 20 bits of
* context for user addresses. i.e. 8T (43 bits) of address space for
* up to 1M contexts (although the page table structure and context
* allocation will need changes to take advantage of this).
*
* - The scramble function gives robust scattering in the hash
* table (at least based on some initial results). The previous
* method was more susceptible to pathological cases giving excessive
* hash collisions.
*/
/*
* WARNING - If you change these you must make sure the asm
* implementations in slb_allocate (slb_low.S), do_stab_bolted
* (head.S) and ASM_VSID_SCRAMBLE (below) are changed accordingly.
*
* You'll also need to change the precomputed VSID values in head.S
* which are used by the iSeries firmware.
*/
#define STAB0_PAGE 0x9
#define STAB0_PHYS_ADDR (STAB0_PAGE<<PAGE_SHIFT)
#define STAB0_VIRT_ADDR (KERNELBASE+STAB0_PHYS_ADDR)

#define SLB_NUM_BOLTED 3
#define SLB_CACHE_ENTRIES 8

/* Bits in the SLB ESID word */
#define SLB_ESID_V 0x0000000008000000 /* entry is valid */

/* Bits in the SLB VSID word */
#define SLB_VSID_SHIFT 12
#define SLB_VSID_KS 0x0000000000000800
#define SLB_VSID_KP 0x0000000000000400
#define SLB_VSID_N 0x0000000000000200 /* no-execute */
#define SLB_VSID_L 0x0000000000000100 /* largepage (4M) */
#define SLB_VSID_C 0x0000000000000080 /* class */

#define SLB_VSID_KERNEL (SLB_VSID_KP|SLB_VSID_C)
#define SLB_VSID_USER (SLB_VSID_KP|SLB_VSID_KS)

#define VSID_MULTIPLIER ASM_CONST(200730139) /* 28-bit prime */
#define VSID_BITS 36
Expand Down Expand Up @@ -239,4 +294,50 @@ extern void htab_finish_init(void);
srdi rx,rx,VSID_BITS; /* extract 2^36 bit */ \
add rt,rt,rx


#ifndef __ASSEMBLY__

typedef unsigned long mm_context_id_t;

typedef struct {
mm_context_id_t id;
#ifdef CONFIG_HUGETLB_PAGE
pgd_t *huge_pgdir;
u16 htlb_segs; /* bitmask */
#endif
} mm_context_t;


static inline unsigned long vsid_scramble(unsigned long protovsid)
{
#if 0
/* The code below is equivalent to this function for arguments
* < 2^VSID_BITS, which is all this should ever be called
* with. However gcc is not clever enough to compute the
* modulus (2^n-1) without a second multiply. */
return ((protovsid * VSID_MULTIPLIER) % VSID_MODULUS);
#else /* 1 */
unsigned long x;

x = protovsid * VSID_MULTIPLIER;
x = (x >> VSID_BITS) + (x & VSID_MODULUS);
return (x + ((x+1) >> VSID_BITS)) & VSID_MODULUS;
#endif /* 1 */
}

/* This is only valid for addresses >= KERNELBASE */
static inline unsigned long get_kernel_vsid(unsigned long ea)
{
return vsid_scramble(ea >> SID_SHIFT);
}

/* This is only valid for user addresses (which are below 2^41) */
static inline unsigned long get_vsid(unsigned long context, unsigned long ea)
{
return vsid_scramble((context << USER_ESID_BITS)
| (ea >> SID_SHIFT));
}

#endif /* __ASSEMBLY */

#endif /* _PPC64_MMU_H_ */
Loading

0 comments on commit 1f8d419

Please sign in to comment.