Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1b272275 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull sparc update from David Miller:

 1) Implement support for up to 47-bit physical addresses on sparc64.

 2) Support HAVE_CONTEXT_TRACKING on sparc64, from Kirill Tkhai.

 3) Fix Simba bridge window calculations, from Kjetil Oftedal.

* git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-next:
  sparc64: Implement HAVE_CONTEXT_TRACKING
  sparc64: Add self-IPI support for smp_send_reschedule()
  sparc: PCI: Fix incorrect address calculation of PCI Bridge windows on Simba-bridges
  sparc64: Encode huge PMDs using PTE encoding.
  sparc64: Move to 64-bit PGDs and PMDs.
  sparc64: Move from 4MB to 8MB huge pages.
  sparc64: Make PAGE_OFFSET variable.
  sparc64: Fix inconsistent max-physical-address defines.
  sparc64: Document the shift counts used to validate linear kernel addresses.
  sparc64: Define PAGE_OFFSET in terms of physical address bits.
  sparc64: Use PAGE_OFFSET instead of a magic constant.
  sparc64: Clean up 64-bit mmap exclusion defines.
parents 91838e2d 812cb83a
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -63,6 +63,7 @@ config SPARC64
	select HAVE_DYNAMIC_FTRACE
	select HAVE_FTRACE_MCOUNT_RECORD
	select HAVE_SYSCALL_TRACEPOINTS
	select HAVE_CONTEXT_TRACKING
	select HAVE_DEBUG_KMEMLEAK
	select RTC_DRV_CMOS
	select RTC_DRV_BQ4802
+0 −1
Original line number Diff line number Diff line
@@ -93,7 +93,6 @@ typedef struct {
	spinlock_t		lock;
	unsigned long		sparc64_ctx_val;
	unsigned long		huge_pte_count;
	struct page		*pgtable_page;
	struct tsb_config	tsb_block[MM_NUM_TSBS];
	struct hv_tsb_descr	tsb_descr[MM_NUM_TSBS];
} mm_context_t;
+39 −10
Original line number Diff line number Diff line
@@ -15,7 +15,10 @@
#define DCACHE_ALIASING_POSSIBLE
#endif

#define HPAGE_SHIFT		22
#define HPAGE_SHIFT		23
#define REAL_HPAGE_SHIFT	22

#define REAL_HPAGE_SIZE		(_AC(1,UL) << REAL_HPAGE_SHIFT)

#if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE)
#define HPAGE_SIZE		(_AC(1,UL) << HPAGE_SHIFT)
@@ -53,8 +56,8 @@ extern void copy_user_page(void *to, void *from, unsigned long vaddr, struct pag
/* These are used to make use of C type-checking.. */
typedef struct { unsigned long pte; } pte_t;
typedef struct { unsigned long iopte; } iopte_t;
typedef struct { unsigned int pmd; } pmd_t;
typedef struct { unsigned int pgd; } pgd_t;
typedef struct { unsigned long pmd; } pmd_t;
typedef struct { unsigned long pgd; } pgd_t;
typedef struct { unsigned long pgprot; } pgprot_t;

#define pte_val(x)	((x).pte)
@@ -73,8 +76,8 @@ typedef struct { unsigned long pgprot; } pgprot_t;
/* .. while these make it easier on the compiler */
typedef unsigned long pte_t;
typedef unsigned long iopte_t;
typedef unsigned int pmd_t;
typedef unsigned int pgd_t;
typedef unsigned long pmd_t;
typedef unsigned long pgd_t;
typedef unsigned long pgprot_t;

#define pte_val(x)	(x)
@@ -93,18 +96,44 @@ typedef unsigned long pgprot_t;

typedef pte_t *pgtable_t;

/* These two values define the virtual address space range in which we
 * must forbid 64-bit user processes from making mappings.  It used to
 * represent precisely the virtual address space hole present in most
 * early sparc64 chips including UltraSPARC-I.  But now it also is
 * further constrained by the limits of our page tables, which is
 * 43-bits of virtual address.
 */
#define SPARC64_VA_HOLE_TOP	_AC(0xfffffc0000000000,UL)
#define SPARC64_VA_HOLE_BOTTOM	_AC(0x0000040000000000,UL)

/* The next two defines specify the actual exclusion region we
 * enforce, wherein we use a 4GB red zone on each side of the VA hole.
 */
#define VA_EXCLUDE_START (SPARC64_VA_HOLE_BOTTOM - (1UL << 32UL))
#define VA_EXCLUDE_END   (SPARC64_VA_HOLE_TOP + (1UL << 32UL))

#define TASK_UNMAPPED_BASE	(test_thread_flag(TIF_32BIT) ? \
				 (_AC(0x0000000070000000,UL)) : \
				 (_AC(0xfffff80000000000,UL) + (1UL << 32UL)))
				 _AC(0x0000000070000000,UL) : \
				 VA_EXCLUDE_END)

#include <asm-generic/memory_model.h>

#define PAGE_OFFSET_BY_BITS(X)	(-(_AC(1,UL) << (X)))
extern unsigned long PAGE_OFFSET;

#endif /* !(__ASSEMBLY__) */

/* We used to stick this into a hard-coded global register (%g4)
 * but that does not make sense anymore.
/* The maximum number of physical memory address bits we support, this
 * is used to size various tables used to manage kernel TLB misses and
 * also the sparsemem code.
 */
#define MAX_PHYS_ADDRESS_BITS	47

/* These two shift counts are used when indexing sparc64_valid_addr_bitmap
 * and kpte_linear_bitmap.
 */
#define PAGE_OFFSET		_AC(0xFFFFF80000000000,UL)
#define ILOG2_4MB		22
#define ILOG2_256MB		28

#ifndef __ASSEMBLY__

+125 −84
Original line number Diff line number Diff line
@@ -48,18 +48,18 @@
/* PMD_SHIFT determines the size of the area a second-level page
 * table can map
 */
#define PMD_SHIFT	(PAGE_SHIFT + (PAGE_SHIFT-4))
#define PMD_SHIFT	(PAGE_SHIFT + (PAGE_SHIFT-3))
#define PMD_SIZE	(_AC(1,UL) << PMD_SHIFT)
#define PMD_MASK	(~(PMD_SIZE-1))
#define PMD_BITS	(PAGE_SHIFT - 2)
#define PMD_BITS	(PAGE_SHIFT - 3)

/* PGDIR_SHIFT determines what a third-level page table entry can map */
#define PGDIR_SHIFT	(PAGE_SHIFT + (PAGE_SHIFT-4) + PMD_BITS)
#define PGDIR_SHIFT	(PAGE_SHIFT + (PAGE_SHIFT-3) + PMD_BITS)
#define PGDIR_SIZE	(_AC(1,UL) << PGDIR_SHIFT)
#define PGDIR_MASK	(~(PGDIR_SIZE-1))
#define PGDIR_BITS	(PAGE_SHIFT - 2)
#define PGDIR_BITS	(PAGE_SHIFT - 3)

#if (PGDIR_SHIFT + PGDIR_BITS) != 44
#if (PGDIR_SHIFT + PGDIR_BITS) != 43
#error Page table parameters do not cover virtual address space properly.
#endif

@@ -67,35 +67,12 @@
#error PMD_SHIFT must equal HPAGE_SHIFT for transparent huge pages.
#endif

/* PMDs point to PTE tables which are 4K aligned.  */
#define PMD_PADDR	_AC(0xfffffffe,UL)
#define PMD_PADDR_SHIFT	_AC(11,UL)

#define PMD_ISHUGE	_AC(0x00000001,UL)

/* This is the PMD layout when PMD_ISHUGE is set.  With 4MB huge
 * pages, this frees up a bunch of bits in the layout that we can
 * use for the protection settings and software metadata.
 */
#define PMD_HUGE_PADDR		_AC(0xfffff800,UL)
#define PMD_HUGE_PROTBITS	_AC(0x000007ff,UL)
#define PMD_HUGE_PRESENT	_AC(0x00000400,UL)
#define PMD_HUGE_WRITE		_AC(0x00000200,UL)
#define PMD_HUGE_DIRTY		_AC(0x00000100,UL)
#define PMD_HUGE_ACCESSED	_AC(0x00000080,UL)
#define PMD_HUGE_EXEC		_AC(0x00000040,UL)
#define PMD_HUGE_SPLITTING	_AC(0x00000020,UL)

/* PGDs point to PMD tables which are 8K aligned.  */
#define PGD_PADDR	_AC(0xfffffffc,UL)
#define PGD_PADDR_SHIFT	_AC(11,UL)

#ifndef __ASSEMBLY__

#include <linux/sched.h>

/* Entries per page directory level. */
#define PTRS_PER_PTE	(1UL << (PAGE_SHIFT-4))
#define PTRS_PER_PTE	(1UL << (PAGE_SHIFT-3))
#define PTRS_PER_PMD	(1UL << PMD_BITS)
#define PTRS_PER_PGD	(1UL << PGDIR_BITS)

@@ -112,6 +89,7 @@
#define _PAGE_VALID	  _AC(0x8000000000000000,UL) /* Valid TTE            */
#define _PAGE_R	  	  _AC(0x8000000000000000,UL) /* Keep ref bit uptodate*/
#define _PAGE_SPECIAL     _AC(0x0200000000000000,UL) /* Special page         */
#define _PAGE_PMD_HUGE    _AC(0x0100000000000000,UL) /* Huge page            */

/* Advertise support for _PAGE_SPECIAL */
#define __HAVE_ARCH_PTE_SPECIAL
@@ -125,6 +103,7 @@
#define _PAGE_IE_4U	  _AC(0x0800000000000000,UL) /* Invert Endianness    */
#define _PAGE_SOFT2_4U	  _AC(0x07FC000000000000,UL) /* Software bits, set 2 */
#define _PAGE_SPECIAL_4U  _AC(0x0200000000000000,UL) /* Special page         */
#define _PAGE_PMD_HUGE_4U _AC(0x0100000000000000,UL) /* Huge page            */
#define _PAGE_RES1_4U	  _AC(0x0002000000000000,UL) /* Reserved             */
#define _PAGE_SZ32MB_4U	  _AC(0x0001000000000000,UL) /* (Panther) 32MB page  */
#define _PAGE_SZ256MB_4U  _AC(0x2001000000000000,UL) /* (Panther) 256MB page */
@@ -155,6 +134,7 @@
#define _PAGE_READ_4V	  _AC(0x0800000000000000,UL) /* Readable SW Bit      */
#define _PAGE_WRITE_4V	  _AC(0x0400000000000000,UL) /* Writable SW Bit      */
#define _PAGE_SPECIAL_4V  _AC(0x0200000000000000,UL) /* Special page         */
#define _PAGE_PMD_HUGE_4V _AC(0x0100000000000000,UL) /* Huge page            */
#define _PAGE_PADDR_4V	  _AC(0x00FFFFFFFFFFE000,UL) /* paddr[55:13]         */
#define _PAGE_IE_4V	  _AC(0x0000000000001000,UL) /* Invert Endianness    */
#define _PAGE_E_4V	  _AC(0x0000000000000800,UL) /* side-Effect          */
@@ -180,6 +160,10 @@
#define _PAGE_SZBITS_4U	_PAGE_SZ8K_4U
#define _PAGE_SZBITS_4V	_PAGE_SZ8K_4V

#if REAL_HPAGE_SHIFT != 22
#error REAL_HPAGE_SHIFT and _PAGE_SZHUGE_foo must match up
#endif

#define _PAGE_SZHUGE_4U	_PAGE_SZ4MB_4U
#define _PAGE_SZHUGE_4V	_PAGE_SZ4MB_4V

@@ -239,16 +223,13 @@ static inline pte_t pfn_pte(unsigned long pfn, pgprot_t prot)
#define mk_pte(page, pgprot)	pfn_pte(page_to_pfn(page), (pgprot))

#ifdef CONFIG_TRANSPARENT_HUGEPAGE
extern pmd_t pfn_pmd(unsigned long page_nr, pgprot_t pgprot);
#define mk_pmd(page, pgprot)	pfn_pmd(page_to_pfn(page), (pgprot))

extern pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot);

static inline pmd_t pmd_mkhuge(pmd_t pmd)
static inline pmd_t pfn_pmd(unsigned long page_nr, pgprot_t pgprot)
{
	/* Do nothing, mk_pmd() does this part.  */
	return pmd;
	pte_t pte = pfn_pte(page_nr, pgprot);

	return __pmd(pte_val(pte));
}
#define mk_pmd(page, pgprot)	pfn_pmd(page_to_pfn(page), (pgprot))
#endif

/* This one can be done with two shifts.  */
@@ -309,14 +290,25 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t prot)
	: "=r" (mask), "=r" (tmp)
	: "i" (_PAGE_PADDR_4U | _PAGE_MODIFIED_4U | _PAGE_ACCESSED_4U |
	       _PAGE_CP_4U | _PAGE_CV_4U | _PAGE_E_4U | _PAGE_PRESENT_4U |
	       _PAGE_SPECIAL),
	       _PAGE_SPECIAL | _PAGE_PMD_HUGE | _PAGE_SZALL_4U),
	  "i" (_PAGE_PADDR_4V | _PAGE_MODIFIED_4V | _PAGE_ACCESSED_4V |
	       _PAGE_CP_4V | _PAGE_CV_4V | _PAGE_E_4V | _PAGE_PRESENT_4V |
	       _PAGE_SPECIAL));
	       _PAGE_SPECIAL | _PAGE_PMD_HUGE | _PAGE_SZALL_4V));

	return __pte((pte_val(pte) & mask) | (pgprot_val(prot) & ~mask));
}

#ifdef CONFIG_TRANSPARENT_HUGEPAGE
static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot)
{
	pte_t pte = __pte(pmd_val(pmd));

	pte = pte_modify(pte, newprot);

	return __pmd(pte_val(pte));
}
#endif

static inline pte_t pgoff_to_pte(unsigned long off)
{
	off <<= PAGE_SHIFT;
@@ -357,7 +349,7 @@ static inline pgprot_t pgprot_noncached(pgprot_t prot)
 */
#define pgprot_noncached pgprot_noncached

#ifdef CONFIG_HUGETLB_PAGE
#if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE)
static inline pte_t pte_mkhuge(pte_t pte)
{
	unsigned long mask;
@@ -375,6 +367,17 @@ static inline pte_t pte_mkhuge(pte_t pte)

	return __pte(pte_val(pte) | mask);
}
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
static inline pmd_t pmd_mkhuge(pmd_t pmd)
{
	pte_t pte = __pte(pmd_val(pmd));

	pte = pte_mkhuge(pte);
	pte_val(pte) |= _PAGE_PMD_HUGE;

	return __pmd(pte_val(pte));
}
#endif
#endif

static inline pte_t pte_mkdirty(pte_t pte)
@@ -626,91 +629,130 @@ static inline unsigned long pte_special(pte_t pte)
	return pte_val(pte) & _PAGE_SPECIAL;
}

static inline int pmd_large(pmd_t pmd)
static inline unsigned long pmd_large(pmd_t pmd)
{
	return (pmd_val(pmd) & (PMD_ISHUGE | PMD_HUGE_PRESENT)) ==
		(PMD_ISHUGE | PMD_HUGE_PRESENT);
	pte_t pte = __pte(pmd_val(pmd));

	return (pte_val(pte) & _PAGE_PMD_HUGE) && pte_present(pte);
}

#ifdef CONFIG_TRANSPARENT_HUGEPAGE
static inline int pmd_young(pmd_t pmd)
static inline unsigned long pmd_young(pmd_t pmd)
{
	return pmd_val(pmd) & PMD_HUGE_ACCESSED;
	pte_t pte = __pte(pmd_val(pmd));

	return pte_young(pte);
}

static inline int pmd_write(pmd_t pmd)
static inline unsigned long pmd_write(pmd_t pmd)
{
	return pmd_val(pmd) & PMD_HUGE_WRITE;
	pte_t pte = __pte(pmd_val(pmd));

	return pte_write(pte);
}

static inline unsigned long pmd_pfn(pmd_t pmd)
{
	unsigned long val = pmd_val(pmd) & PMD_HUGE_PADDR;
	pte_t pte = __pte(pmd_val(pmd));

	return val >> (PAGE_SHIFT - PMD_PADDR_SHIFT);
	return pte_pfn(pte);
}

static inline int pmd_trans_splitting(pmd_t pmd)
static inline unsigned long pmd_trans_huge(pmd_t pmd)
{
	return (pmd_val(pmd) & (PMD_ISHUGE|PMD_HUGE_SPLITTING)) ==
		(PMD_ISHUGE|PMD_HUGE_SPLITTING);
	pte_t pte = __pte(pmd_val(pmd));

	return pte_val(pte) & _PAGE_PMD_HUGE;
}

static inline int pmd_trans_huge(pmd_t pmd)
static inline unsigned long pmd_trans_splitting(pmd_t pmd)
{
	return pmd_val(pmd) & PMD_ISHUGE;
	pte_t pte = __pte(pmd_val(pmd));

	return pmd_trans_huge(pmd) && pte_special(pte);
}

#define has_transparent_hugepage() 1

static inline pmd_t pmd_mkold(pmd_t pmd)
{
	pmd_val(pmd) &= ~PMD_HUGE_ACCESSED;
	return pmd;
	pte_t pte = __pte(pmd_val(pmd));

	pte = pte_mkold(pte);

	return __pmd(pte_val(pte));
}

static inline pmd_t pmd_wrprotect(pmd_t pmd)
{
	pmd_val(pmd) &= ~PMD_HUGE_WRITE;
	return pmd;
	pte_t pte = __pte(pmd_val(pmd));

	pte = pte_wrprotect(pte);

	return __pmd(pte_val(pte));
}

static inline pmd_t pmd_mkdirty(pmd_t pmd)
{
	pmd_val(pmd) |= PMD_HUGE_DIRTY;
	return pmd;
	pte_t pte = __pte(pmd_val(pmd));

	pte = pte_mkdirty(pte);

	return __pmd(pte_val(pte));
}

static inline pmd_t pmd_mkyoung(pmd_t pmd)
{
	pmd_val(pmd) |= PMD_HUGE_ACCESSED;
	return pmd;
	pte_t pte = __pte(pmd_val(pmd));

	pte = pte_mkyoung(pte);

	return __pmd(pte_val(pte));
}

static inline pmd_t pmd_mkwrite(pmd_t pmd)
{
	pmd_val(pmd) |= PMD_HUGE_WRITE;
	return pmd;
	pte_t pte = __pte(pmd_val(pmd));

	pte = pte_mkwrite(pte);

	return __pmd(pte_val(pte));
}

static inline pmd_t pmd_mknotpresent(pmd_t pmd)
{
	pmd_val(pmd) &= ~PMD_HUGE_PRESENT;
	unsigned long mask;

	if (tlb_type == hypervisor)
		mask = _PAGE_PRESENT_4V;
	else
		mask = _PAGE_PRESENT_4U;

	pmd_val(pmd) &= ~mask;

	return pmd;
}

static inline pmd_t pmd_mksplitting(pmd_t pmd)
{
	pmd_val(pmd) |= PMD_HUGE_SPLITTING;
	return pmd;
	pte_t pte = __pte(pmd_val(pmd));

	pte = pte_mkspecial(pte);

	return __pmd(pte_val(pte));
}

extern pgprot_t pmd_pgprot(pmd_t entry);
static inline pgprot_t pmd_pgprot(pmd_t entry)
{
	unsigned long val = pmd_val(entry);

	return __pgprot(val);
}
#endif

static inline int pmd_present(pmd_t pmd)
{
	return pmd_val(pmd) != 0U;
	return pmd_val(pmd) != 0UL;
}

#define pmd_none(pmd)			(!pmd_val(pmd))
@@ -728,33 +770,32 @@ static inline void set_pmd_at(struct mm_struct *mm, unsigned long addr,

static inline void pmd_set(struct mm_struct *mm, pmd_t *pmdp, pte_t *ptep)
{
	unsigned long val = __pa((unsigned long) (ptep)) >> PMD_PADDR_SHIFT;
	unsigned long val = __pa((unsigned long) (ptep));

	pmd_val(*pmdp) = val;
}

#define pud_set(pudp, pmdp)	\
	(pud_val(*(pudp)) = (__pa((unsigned long) (pmdp)) >> PGD_PADDR_SHIFT))
	(pud_val(*(pudp)) = (__pa((unsigned long) (pmdp))))
static inline unsigned long __pmd_page(pmd_t pmd)
{
	unsigned long paddr = (unsigned long) pmd_val(pmd);
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
	if (pmd_val(pmd) & PMD_ISHUGE)
		paddr &= PMD_HUGE_PADDR;
#endif
	paddr <<= PMD_PADDR_SHIFT;
	return ((unsigned long) __va(paddr));
	pte_t pte = __pte(pmd_val(pmd));
	unsigned long pfn;

	pfn = pte_pfn(pte);

	return ((unsigned long) __va(pfn << PAGE_SHIFT));
}
#define pmd_page(pmd) 			virt_to_page((void *)__pmd_page(pmd))
#define pud_page_vaddr(pud)		\
	((unsigned long) __va((((unsigned long)pud_val(pud))<<PGD_PADDR_SHIFT)))
	((unsigned long) __va(pud_val(pud)))
#define pud_page(pud) 			virt_to_page((void *)pud_page_vaddr(pud))
#define pmd_bad(pmd)			(0)
#define pmd_clear(pmdp)			(pmd_val(*(pmdp)) = 0U)
#define pmd_clear(pmdp)			(pmd_val(*(pmdp)) = 0UL)
#define pud_none(pud)			(!pud_val(pud))
#define pud_bad(pud)			(0)
#define pud_present(pud)		(pud_val(pud) != 0U)
#define pud_clear(pudp)			(pud_val(*(pudp)) = 0U)
#define pud_clear(pudp)			(pud_val(*(pudp)) = 0UL)

/* Same in both SUN4V and SUN4U.  */
#define pte_none(pte) 			(!pte_val(pte))
@@ -789,7 +830,7 @@ static inline pmd_t pmdp_get_and_clear(struct mm_struct *mm,
				       pmd_t *pmdp)
{
	pmd_t pmd = *pmdp;
	set_pmd_at(mm, addr, pmdp, __pmd(0U));
	set_pmd_at(mm, addr, pmdp, __pmd(0UL));
	return pmd;
}

@@ -837,8 +878,8 @@ static inline void __set_pte_at(struct mm_struct *mm, unsigned long addr,
})
#endif

extern pgd_t swapper_pg_dir[2048];
extern pmd_t swapper_low_pmd_dir[2048];
extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
extern pmd_t swapper_low_pmd_dir[PTRS_PER_PMD];

extern void paging_init(void);
extern unsigned long find_ecache_flush_span(unsigned long size);
+4 −2
Original line number Diff line number Diff line
@@ -3,9 +3,11 @@

#ifdef __KERNEL__

#include <asm/page.h>

#define SECTION_SIZE_BITS       30
#define MAX_PHYSADDR_BITS       42
#define MAX_PHYSMEM_BITS        42
#define MAX_PHYSADDR_BITS       MAX_PHYS_ADDRESS_BITS
#define MAX_PHYSMEM_BITS        MAX_PHYS_ADDRESS_BITS

#endif /* !(__KERNEL__) */

Loading