103479763SNathan Whitehorn /*- 271e3c308SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 371e3c308SPedro F. Giffuni * 403479763SNathan Whitehorn * Copyright (C) 2010 Nathan Whitehorn 503479763SNathan Whitehorn * All rights reserved. 603479763SNathan Whitehorn * 703479763SNathan Whitehorn * Redistribution and use in source and binary forms, with or without 803479763SNathan Whitehorn * modification, are permitted provided that the following conditions 903479763SNathan Whitehorn * are met: 1003479763SNathan Whitehorn * 1. Redistributions of source code must retain the above copyright 1103479763SNathan Whitehorn * notice, this list of conditions and the following disclaimer. 1203479763SNathan Whitehorn * 2. Redistributions in binary form must reproduce the above copyright 1303479763SNathan Whitehorn * notice, this list of conditions and the following disclaimer in the 1403479763SNathan Whitehorn * documentation and/or other materials provided with the distribution. 1503479763SNathan Whitehorn * 1603479763SNathan Whitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1703479763SNathan Whitehorn * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1803479763SNathan Whitehorn * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1903479763SNathan Whitehorn * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2003479763SNathan Whitehorn * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 2103479763SNathan Whitehorn * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 2203479763SNathan Whitehorn * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 2303479763SNathan Whitehorn * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 2403479763SNathan Whitehorn * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 2503479763SNathan Whitehorn * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2603479763SNathan Whitehorn */ 2703479763SNathan Whitehorn 2803479763SNathan Whitehorn #include <sys/cdefs.h> 2903479763SNathan Whitehorn __FBSDID("$FreeBSD$"); 3003479763SNathan Whitehorn 3103479763SNathan Whitehorn #include <sys/param.h> 3203479763SNathan Whitehorn #include <sys/kernel.h> 3303479763SNathan Whitehorn #include <sys/ktr.h> 3403479763SNathan Whitehorn #include <sys/lock.h> 3503479763SNathan Whitehorn #include <sys/msgbuf.h> 3603479763SNathan Whitehorn #include <sys/mutex.h> 3703479763SNathan Whitehorn #include <sys/proc.h> 3803479763SNathan Whitehorn #include <sys/sysctl.h> 3903479763SNathan Whitehorn #include <sys/systm.h> 4003479763SNathan Whitehorn #include <sys/vmmeter.h> 4103479763SNathan Whitehorn 4203479763SNathan Whitehorn #include <vm/vm.h> 4303479763SNathan Whitehorn #include <vm/vm_param.h> 4403479763SNathan Whitehorn #include <vm/vm_kern.h> 4503479763SNathan Whitehorn #include <vm/vm_page.h> 4603479763SNathan Whitehorn #include <vm/vm_map.h> 4703479763SNathan Whitehorn #include <vm/vm_object.h> 4803479763SNathan Whitehorn #include <vm/vm_extern.h> 4903479763SNathan Whitehorn #include <vm/vm_pageout.h> 5003479763SNathan Whitehorn #include <vm/uma.h> 5103479763SNathan Whitehorn 5203479763SNathan Whitehorn #include <powerpc/aim/mmu_oea64.h> 5303479763SNathan Whitehorn 5403479763SNathan Whitehorn #include "ps3-hvcall.h" 5503479763SNathan Whitehorn 5603479763SNathan Whitehorn #define VSID_HASH_MASK 0x0000007fffffffffUL 5703479763SNathan Whitehorn #define PTESYNC() __asm __volatile("ptesync") 5803479763SNathan Whitehorn 5903479763SNathan Whitehorn extern int ps3fb_remap(void); 6003479763SNathan Whitehorn 6103479763SNathan Whitehorn static uint64_t mps3_vas_id; 6203479763SNathan Whitehorn 6303479763SNathan Whitehorn /* 6403479763SNathan Whitehorn * Kernel MMU interface 6503479763SNathan Whitehorn */ 6603479763SNathan Whitehorn 6745b69dd6SJustin Hibbits static void mps3_install(void); 6845b69dd6SJustin Hibbits static void mps3_bootstrap(vm_offset_t kernelstart, 6903479763SNathan Whitehorn vm_offset_t kernelend); 7045b69dd6SJustin Hibbits static void mps3_cpu_bootstrap(int ap); 7145b69dd6SJustin Hibbits static int64_t mps3_pte_synch(struct pvo_entry *); 7245b69dd6SJustin Hibbits static int64_t mps3_pte_clear(struct pvo_entry *, uint64_t ptebit); 7345b69dd6SJustin Hibbits static int64_t mps3_pte_unset(struct pvo_entry *); 7445b69dd6SJustin Hibbits static int64_t mps3_pte_insert(struct pvo_entry *); 7503479763SNathan Whitehorn 7645b69dd6SJustin Hibbits static struct pmap_funcs mps3_methods = { 7745b69dd6SJustin Hibbits .install = mps3_install, 7845b69dd6SJustin Hibbits .bootstrap = mps3_bootstrap, 7945b69dd6SJustin Hibbits .cpu_bootstrap = mps3_cpu_bootstrap, 8003479763SNathan Whitehorn }; 8103479763SNathan Whitehorn 8245b69dd6SJustin Hibbits static struct moea64_funcs mps3_funcs = { 8345b69dd6SJustin Hibbits .pte_synch = mps3_pte_synch, 8445b69dd6SJustin Hibbits .pte_clear = mps3_pte_clear, 8545b69dd6SJustin Hibbits .pte_unset = mps3_pte_unset, 8645b69dd6SJustin Hibbits .pte_insert = mps3_pte_insert, 8745b69dd6SJustin Hibbits }; 8845b69dd6SJustin Hibbits 8945b69dd6SJustin Hibbits MMU_DEF_INHERIT(ps3_mmu, "mmu_ps3", mps3_methods, oea64_mmu); 9003479763SNathan Whitehorn 91827cc9b9SNathan Whitehorn static struct mtx mps3_table_lock; 92827cc9b9SNathan Whitehorn 9303479763SNathan Whitehorn static void 9445b69dd6SJustin Hibbits mps3_install() 9545b69dd6SJustin Hibbits { 9645b69dd6SJustin Hibbits moea64_ops = &mps3_funcs; 97*49c894ddSJustin Hibbits moea64_install(); 9845b69dd6SJustin Hibbits } 9945b69dd6SJustin Hibbits 10045b69dd6SJustin Hibbits static void 10145b69dd6SJustin Hibbits mps3_bootstrap(vm_offset_t kernelstart, vm_offset_t kernelend) 10203479763SNathan Whitehorn { 10303479763SNathan Whitehorn uint64_t final_pteg_count; 10403479763SNathan Whitehorn 105827cc9b9SNathan Whitehorn mtx_init(&mps3_table_lock, "page table", NULL, MTX_DEF); 106827cc9b9SNathan Whitehorn 10745b69dd6SJustin Hibbits moea64_early_bootstrap(kernelstart, kernelend); 10803479763SNathan Whitehorn 1093fca7880SNathan Whitehorn /* In case we had a page table already */ 1103fca7880SNathan Whitehorn lv1_destruct_virtual_address_space(0); 1113fca7880SNathan Whitehorn 1123fca7880SNathan Whitehorn /* Allocate new hardware page table */ 11303479763SNathan Whitehorn lv1_construct_virtual_address_space( 11403479763SNathan Whitehorn 20 /* log_2(moea64_pteg_count) */, 2 /* n page sizes */, 11503479763SNathan Whitehorn (24UL << 56) | (16UL << 48) /* page sizes 16 MB + 64 KB */, 11603479763SNathan Whitehorn &mps3_vas_id, &final_pteg_count 11703479763SNathan Whitehorn ); 11803479763SNathan Whitehorn 1193fca7880SNathan Whitehorn lv1_select_virtual_address_space(mps3_vas_id); 1203fca7880SNathan Whitehorn 12103479763SNathan Whitehorn moea64_pteg_count = final_pteg_count / sizeof(struct lpteg); 12203479763SNathan Whitehorn 12345b69dd6SJustin Hibbits moea64_mid_bootstrap(kernelstart, kernelend); 12445b69dd6SJustin Hibbits moea64_late_bootstrap(kernelstart, kernelend); 12503479763SNathan Whitehorn } 12603479763SNathan Whitehorn 12703479763SNathan Whitehorn static void 12845b69dd6SJustin Hibbits mps3_cpu_bootstrap(int ap) 12903479763SNathan Whitehorn { 130bce6d88bSJustin Hibbits struct slb *slb = PCPU_GET(aim.slb); 13103479763SNathan Whitehorn register_t seg0; 13203479763SNathan Whitehorn int i; 13303479763SNathan Whitehorn 13403479763SNathan Whitehorn mtmsr(mfmsr() & ~PSL_DR & ~PSL_IR); 13503479763SNathan Whitehorn 13603479763SNathan Whitehorn /* 1373fca7880SNathan Whitehorn * Select the page table we configured above and set up the FB mapping 1383fca7880SNathan Whitehorn * so we can have a console. 13903479763SNathan Whitehorn */ 14003479763SNathan Whitehorn lv1_select_virtual_address_space(mps3_vas_id); 14103479763SNathan Whitehorn 14203479763SNathan Whitehorn if (!ap) 14303479763SNathan Whitehorn ps3fb_remap(); 14403479763SNathan Whitehorn 14503479763SNathan Whitehorn /* 14603479763SNathan Whitehorn * Install kernel SLB entries 14703479763SNathan Whitehorn */ 14803479763SNathan Whitehorn 14903479763SNathan Whitehorn __asm __volatile ("slbia"); 15003479763SNathan Whitehorn __asm __volatile ("slbmfee %0,%1; slbie %0;" : "=r"(seg0) : "r"(0)); 15103479763SNathan Whitehorn for (i = 0; i < 64; i++) { 15203479763SNathan Whitehorn if (!(slb[i].slbe & SLBE_VALID)) 15303479763SNathan Whitehorn continue; 15403479763SNathan Whitehorn 15503479763SNathan Whitehorn __asm __volatile ("slbmte %0, %1" :: 15603479763SNathan Whitehorn "r"(slb[i].slbv), "r"(slb[i].slbe)); 15703479763SNathan Whitehorn } 15803479763SNathan Whitehorn } 15903479763SNathan Whitehorn 160827cc9b9SNathan Whitehorn static int64_t 161827cc9b9SNathan Whitehorn mps3_pte_synch_locked(struct pvo_entry *pvo) 16203479763SNathan Whitehorn { 16303479763SNathan Whitehorn uint64_t halfbucket[4], rcbits; 16403479763SNathan Whitehorn 16503479763SNathan Whitehorn PTESYNC(); 166827cc9b9SNathan Whitehorn lv1_read_htab_entries(mps3_vas_id, pvo->pvo_pte.slot & ~0x3UL, 167827cc9b9SNathan Whitehorn &halfbucket[0], &halfbucket[1], &halfbucket[2], &halfbucket[3], 168827cc9b9SNathan Whitehorn &rcbits); 169827cc9b9SNathan Whitehorn 170827cc9b9SNathan Whitehorn /* Check if present in page table */ 171827cc9b9SNathan Whitehorn if ((halfbucket[pvo->pvo_pte.slot & 0x3] & LPTE_AVPN_MASK) != 172827cc9b9SNathan Whitehorn ((pvo->pvo_vpn >> (ADDR_API_SHFT64 - ADDR_PIDX_SHFT)) & 173827cc9b9SNathan Whitehorn LPTE_AVPN_MASK)) 174827cc9b9SNathan Whitehorn return (-1); 175827cc9b9SNathan Whitehorn if (!(halfbucket[pvo->pvo_pte.slot & 0x3] & LPTE_VALID)) 176827cc9b9SNathan Whitehorn return (-1); 17703479763SNathan Whitehorn 17803479763SNathan Whitehorn /* 179827cc9b9SNathan Whitehorn * rcbits contains the low 12 bits of each PTE's 2nd part, 18003479763SNathan Whitehorn * spaced at 16-bit intervals 18103479763SNathan Whitehorn */ 18203479763SNathan Whitehorn 183827cc9b9SNathan Whitehorn return ((rcbits >> ((3 - (pvo->pvo_pte.slot & 0x3))*16)) & 184827cc9b9SNathan Whitehorn (LPTE_CHG | LPTE_REF)); 18503479763SNathan Whitehorn } 18603479763SNathan Whitehorn 187827cc9b9SNathan Whitehorn static int64_t 18845b69dd6SJustin Hibbits mps3_pte_synch(struct pvo_entry *pvo) 18903479763SNathan Whitehorn { 190827cc9b9SNathan Whitehorn int64_t retval; 19103479763SNathan Whitehorn 192827cc9b9SNathan Whitehorn mtx_lock(&mps3_table_lock); 193827cc9b9SNathan Whitehorn retval = mps3_pte_synch_locked(pvo); 194827cc9b9SNathan Whitehorn mtx_unlock(&mps3_table_lock); 195827cc9b9SNathan Whitehorn 196827cc9b9SNathan Whitehorn return (retval); 19703479763SNathan Whitehorn } 19803479763SNathan Whitehorn 199827cc9b9SNathan Whitehorn static int64_t 20045b69dd6SJustin Hibbits mps3_pte_clear(struct pvo_entry *pvo, uint64_t ptebit) 20103479763SNathan Whitehorn { 202827cc9b9SNathan Whitehorn int64_t refchg; 203827cc9b9SNathan Whitehorn struct lpte pte; 20403479763SNathan Whitehorn 205827cc9b9SNathan Whitehorn mtx_lock(&mps3_table_lock); 206827cc9b9SNathan Whitehorn 207827cc9b9SNathan Whitehorn refchg = mps3_pte_synch_locked(pvo); 208827cc9b9SNathan Whitehorn if (refchg < 0) { 209827cc9b9SNathan Whitehorn mtx_unlock(&mps3_table_lock); 210827cc9b9SNathan Whitehorn return (refchg); 211827cc9b9SNathan Whitehorn } 212827cc9b9SNathan Whitehorn 213827cc9b9SNathan Whitehorn moea64_pte_from_pvo(pvo, &pte); 214827cc9b9SNathan Whitehorn 215827cc9b9SNathan Whitehorn pte.pte_lo |= refchg; 216827cc9b9SNathan Whitehorn pte.pte_lo &= ~ptebit; 217827cc9b9SNathan Whitehorn /* XXX: race on RC bits between write and sync. Anything to do? */ 218827cc9b9SNathan Whitehorn lv1_write_htab_entry(mps3_vas_id, pvo->pvo_pte.slot, pte.pte_hi, 219827cc9b9SNathan Whitehorn pte.pte_lo); 220827cc9b9SNathan Whitehorn mtx_unlock(&mps3_table_lock); 221827cc9b9SNathan Whitehorn 222827cc9b9SNathan Whitehorn return (refchg); 223827cc9b9SNathan Whitehorn } 224827cc9b9SNathan Whitehorn 225827cc9b9SNathan Whitehorn static int64_t 22645b69dd6SJustin Hibbits mps3_pte_unset(struct pvo_entry *pvo) 227827cc9b9SNathan Whitehorn { 228827cc9b9SNathan Whitehorn int64_t refchg; 229827cc9b9SNathan Whitehorn 230827cc9b9SNathan Whitehorn mtx_lock(&mps3_table_lock); 231827cc9b9SNathan Whitehorn refchg = mps3_pte_synch_locked(pvo); 232827cc9b9SNathan Whitehorn if (refchg < 0) { 2337c382eeaSJustin Hibbits STAT_MOEA64(moea64_pte_overflow--); 234827cc9b9SNathan Whitehorn mtx_unlock(&mps3_table_lock); 235827cc9b9SNathan Whitehorn return (-1); 236827cc9b9SNathan Whitehorn } 237827cc9b9SNathan Whitehorn /* XXX: race on RC bits between unset and sync. Anything to do? */ 238827cc9b9SNathan Whitehorn lv1_write_htab_entry(mps3_vas_id, pvo->pvo_pte.slot, 0, 0); 239827cc9b9SNathan Whitehorn mtx_unlock(&mps3_table_lock); 2407c382eeaSJustin Hibbits STAT_MOEA64(moea64_pte_valid--); 24103479763SNathan Whitehorn 242827cc9b9SNathan Whitehorn return (refchg & (LPTE_REF | LPTE_CHG)); 24303479763SNathan Whitehorn } 24403479763SNathan Whitehorn 24545b69dd6SJustin Hibbits static int64_t 24645b69dd6SJustin Hibbits mps3_pte_insert(struct pvo_entry *pvo) 24703479763SNathan Whitehorn { 24803479763SNathan Whitehorn int result; 249827cc9b9SNathan Whitehorn struct lpte pte, evicted; 25003479763SNathan Whitehorn uint64_t index; 25103479763SNathan Whitehorn 252827cc9b9SNathan Whitehorn if (pvo->pvo_vaddr & PVO_HID) { 253827cc9b9SNathan Whitehorn /* Hypercall needs primary PTEG */ 254827cc9b9SNathan Whitehorn pvo->pvo_vaddr &= ~PVO_HID; 255827cc9b9SNathan Whitehorn pvo->pvo_pte.slot ^= (moea64_pteg_mask << 3); 256827cc9b9SNathan Whitehorn } 257827cc9b9SNathan Whitehorn 258827cc9b9SNathan Whitehorn pvo->pvo_pte.slot &= ~7UL; 259827cc9b9SNathan Whitehorn moea64_pte_from_pvo(pvo, &pte); 26003479763SNathan Whitehorn evicted.pte_hi = 0; 26103479763SNathan Whitehorn PTESYNC(); 262827cc9b9SNathan Whitehorn mtx_lock(&mps3_table_lock); 263827cc9b9SNathan Whitehorn result = lv1_insert_htab_entry(mps3_vas_id, pvo->pvo_pte.slot, 264827cc9b9SNathan Whitehorn pte.pte_hi, pte.pte_lo, LPTE_LOCKED | LPTE_WIRED, 0, 26503479763SNathan Whitehorn &index, &evicted.pte_hi, &evicted.pte_lo); 266827cc9b9SNathan Whitehorn mtx_unlock(&mps3_table_lock); 26703479763SNathan Whitehorn 26803479763SNathan Whitehorn if (result != 0) { 26903479763SNathan Whitehorn /* No freeable slots in either PTEG? We're hosed. */ 27003479763SNathan Whitehorn panic("mps3_pte_insert: overflow (%d)", result); 27103479763SNathan Whitehorn return (-1); 27203479763SNathan Whitehorn } 27303479763SNathan Whitehorn 27403479763SNathan Whitehorn /* 27503479763SNathan Whitehorn * See where we ended up. 27603479763SNathan Whitehorn */ 277827cc9b9SNathan Whitehorn if ((index & ~7UL) != pvo->pvo_pte.slot) 278827cc9b9SNathan Whitehorn pvo->pvo_vaddr |= PVO_HID; 279827cc9b9SNathan Whitehorn pvo->pvo_pte.slot = index; 28003479763SNathan Whitehorn 2817c382eeaSJustin Hibbits STAT_MOEA64(moea64_pte_valid++); 28203479763SNathan Whitehorn 283827cc9b9SNathan Whitehorn if (evicted.pte_hi) { 28403479763SNathan Whitehorn KASSERT((evicted.pte_hi & (LPTE_WIRED | LPTE_LOCKED)) == 0, 28503479763SNathan Whitehorn ("Evicted a wired PTE")); 2867c382eeaSJustin Hibbits STAT_MOEA64(moea64_pte_valid--); 2877c382eeaSJustin Hibbits STAT_MOEA64(moea64_pte_overflow++); 28803479763SNathan Whitehorn } 28903479763SNathan Whitehorn 290827cc9b9SNathan Whitehorn return (0); 29103479763SNathan Whitehorn } 292