Add support for powernv POWER9 MMU initialization

The POWER9 MMU (PowerISA 3.0) is slightly different from current
configurations, using a partition table even for hypervisor mode, and
dropping the SDR1 register.  Key off the newly early-enabled CPU features
flags for the new architecture, and configure the MMU appropriately.

The POWER9 MMU ignores the "PSIZ" field in the PTCR, and expects a 64kB
table.  As we are enabled for powernv (hypervisor mode, no VMs), only
initialize partition table entry 0, and zero out the rest.  The actual
contents of the register are identical to SDR1 from previous architectures.

Along with this, fix a bug in the page table allocation with very large
memory.  The table can be allocated on any 256k boundary.  The
bootstrap_alloc alignment argument is an int, and with large amounts of
memory passing the size of the table as the alignment will overflow an
integer.  Hard-code the alignment at 256k as wider alignment is not
necessary.

Reviewed by:	nwhitehorn
Tested by:	Breno Leitao
Relnotes:	Yes
This commit is contained in:
Justin Hibbits 2018-05-05 16:00:02 +00:00
parent 55a12bbda2
commit 10d0cdfc6e
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=333273
6 changed files with 44 additions and 9 deletions

View File

@ -159,8 +159,8 @@ struct mtx moea64_slb_mutex;
/*
* PTEG data.
*/
u_int moea64_pteg_count;
u_int moea64_pteg_mask;
u_long moea64_pteg_count;
u_long moea64_pteg_mask;
/*
* PVO data.

View File

@ -81,8 +81,8 @@ extern u_int moea64_pte_overflow;
extern int moea64_large_page_shift;
extern uint64_t moea64_large_page_size;
extern u_int moea64_pteg_count;
extern u_int moea64_pteg_mask;
extern u_long moea64_pteg_count;
extern u_long moea64_pteg_mask;
extern int n_slbs;
#endif /* _POWERPC_AIM_MMU_OEA64_H */

View File

@ -115,6 +115,7 @@ __FBSDID("$FreeBSD$");
#include <vm/vm_extern.h>
#include <vm/vm_pageout.h>
#include <machine/cpu.h>
#include <machine/md_var.h>
#include <machine/mmuvar.h>
@ -129,6 +130,9 @@ __FBSDID("$FreeBSD$");
#define VSID_HASH_MASK 0x0000007fffffffffULL
/* POWER9 only permits a 64k partition table size. */
#define PART_SIZE 0x10000
static __inline void
TLBIE(uint64_t vpn) {
#ifndef __powerpc64__
@ -183,6 +187,7 @@ TLBIE(uint64_t vpn) {
/*
* PTEG data.
*/
static volatile struct pate *moea64_part_table;
static volatile struct lpte *moea64_pteg_table;
static struct rwlock moea64_eviction_lock;
@ -400,9 +405,15 @@ moea64_cpu_bootstrap_native(mmu_t mmup, int ap)
* Install page table
*/
__asm __volatile ("ptesync; mtsdr1 %0; isync"
:: "r"(((uintptr_t)moea64_pteg_table & ~DMAP_BASE_ADDRESS)
| (uintptr_t)(flsl(moea64_pteg_mask >> 11))));
if (cpu_features2 & PPC_FEATURE2_ARCH_3_00) {
mtspr(SPR_PTCR,
((uintptr_t)moea64_part_table & ~DMAP_BASE_ADDRESS) |
flsl((PART_SIZE >> 12) - 1));
} else {
__asm __volatile ("ptesync; mtsdr1 %0; isync"
:: "r"(((uintptr_t)moea64_pteg_table & ~DMAP_BASE_ADDRESS)
| (uintptr_t)(flsl(moea64_pteg_mask >> 11))));
}
tlbia();
}
@ -433,11 +444,28 @@ moea64_bootstrap_native(mmu_t mmup, vm_offset_t kernelstart,
* as a measure of last resort. We do this a couple times.
*/
moea64_pteg_table = (struct lpte *)moea64_bootstrap_alloc(size, size);
if (cpu_features2 & PPC_FEATURE2_ARCH_3_00) {
moea64_part_table =
(struct pate *)moea64_bootstrap_alloc(PART_SIZE, PART_SIZE);
if (hw_direct_map)
moea64_part_table =
(struct pate *)PHYS_TO_DMAP((vm_offset_t)moea64_part_table);
}
/*
* PTEG table must be aligned on a 256k boundary, but can be placed
* anywhere with that alignment.
*/
moea64_pteg_table = (struct lpte *)moea64_bootstrap_alloc(size, 256*1024);
if (hw_direct_map)
moea64_pteg_table =
(struct lpte *)PHYS_TO_DMAP((vm_offset_t)moea64_pteg_table);
DISABLE_TRANS(msr);
if (cpu_features2 & PPC_FEATURE2_ARCH_3_00) {
bzero(__DEVOLATILE(void *, moea64_part_table), PART_SIZE);
moea64_part_table[0].pagetab =
((uintptr_t)moea64_pteg_table & ~DMAP_BASE_ADDRESS) |
(uintptr_t)(flsl((moea64_pteg_count - 1) >> 11));
}
bzero(__DEVOLATILE(void *, moea64_pteg_table), moea64_pteg_count *
sizeof(struct lpteg));
ENABLE_TRANS(msr);

View File

@ -64,6 +64,12 @@ struct lpteg {
struct lpte pt[8];
};
/* Partition table entry */
struct pate {
u_int64_t pagetab;
u_int64_t proctab;
};
#endif /* LOCORE */
/* 32-bit PTE definitions */

View File

@ -243,6 +243,7 @@
#define LPCR_LPES 0x008 /* Bit 60 */
#define SPR_LPID 0x13f /* Logical Partitioning Control */
#define SPR_PTCR 0x1d0 /* Partition Table Control Register */
#define SPR_IBAT0U 0x210 /* .68 Instruction BAT Reg 0 Upper */
#define SPR_IBAT0U 0x210 /* .6. Instruction BAT Reg 0 Upper */
#define SPR_IBAT0L 0x211 /* .6. Instruction BAT Reg 0 Lower */

View File

@ -403,7 +403,7 @@ mphyp_pte_insert(mmu_t mmu, struct pvo_entry *pvo)
return (0);
}
KASSERT(result == H_PTEG_FULL, ("Page insertion error: %ld "
"(ptegidx: %#zx/%#x, PTE %#lx/%#lx", result, pvo->pvo_pte.slot,
"(ptegidx: %#zx/%#lx, PTE %#lx/%#lx", result, pvo->pvo_pte.slot,
moea64_pteg_count, pte.pte_hi, pte.pte_lo));
/*