linux/arch/powerpc/platforms/ps3/htab.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 *  PS3 pagetable management routines.
   4 *
   5 *  Copyright (C) 2006 Sony Computer Entertainment Inc.
   6 *  Copyright 2006, 2007 Sony Corporation
   7 */
   8
   9#include <linux/kernel.h>
  10#include <linux/memblock.h>
  11
  12#include <asm/machdep.h>
  13#include <asm/prom.h>
  14#include <asm/udbg.h>
  15#include <asm/lv1call.h>
  16#include <asm/ps3fb.h>
  17
  18#define PS3_VERBOSE_RESULT
  19#include "platform.h"
  20
  21/**
  22 * enum lpar_vas_id - id of LPAR virtual address space.
  23 * @lpar_vas_id_current: Current selected virtual address space
  24 *
  25 * Identify the target LPAR address space.
  26 */
  27
  28enum ps3_lpar_vas_id {
  29        PS3_LPAR_VAS_ID_CURRENT = 0,
  30};
  31
  32
  33static DEFINE_SPINLOCK(ps3_htab_lock);
  34
  35static long ps3_hpte_insert(unsigned long hpte_group, unsigned long vpn,
  36        unsigned long pa, unsigned long rflags, unsigned long vflags,
  37        int psize, int apsize, int ssize)
  38{
  39        int result;
  40        u64 hpte_v, hpte_r;
  41        u64 inserted_index;
  42        u64 evicted_v, evicted_r;
  43        u64 hpte_v_array[4], hpte_rs;
  44        unsigned long flags;
  45        long ret = -1;
  46
  47        /*
  48         * lv1_insert_htab_entry() will search for victim
  49         * entry in both primary and secondary pte group
  50         */
  51        vflags &= ~HPTE_V_SECONDARY;
  52
  53        hpte_v = hpte_encode_v(vpn, psize, apsize, ssize) | vflags | HPTE_V_VALID;
  54        hpte_r = hpte_encode_r(ps3_mm_phys_to_lpar(pa), psize, apsize) | rflags;
  55
  56        spin_lock_irqsave(&ps3_htab_lock, flags);
  57
  58        /* talk hvc to replace entries BOLTED == 0 */
  59        result = lv1_insert_htab_entry(PS3_LPAR_VAS_ID_CURRENT, hpte_group,
  60                                       hpte_v, hpte_r,
  61                                       HPTE_V_BOLTED, 0,
  62                                       &inserted_index,
  63                                       &evicted_v, &evicted_r);
  64
  65        if (result) {
  66                /* all entries bolted !*/
  67                pr_info("%s:result=%s vpn=%lx pa=%lx ix=%lx v=%llx r=%llx\n",
  68                        __func__, ps3_result(result), vpn, pa, hpte_group,
  69                        hpte_v, hpte_r);
  70                BUG();
  71        }
  72
  73        /*
  74         * see if the entry is inserted into secondary pteg
  75         */
  76        result = lv1_read_htab_entries(PS3_LPAR_VAS_ID_CURRENT,
  77                                       inserted_index & ~0x3UL,
  78                                       &hpte_v_array[0], &hpte_v_array[1],
  79                                       &hpte_v_array[2], &hpte_v_array[3],
  80                                       &hpte_rs);
  81        BUG_ON(result);
  82
  83        if (hpte_v_array[inserted_index % 4] & HPTE_V_SECONDARY)
  84                ret = (inserted_index & 7) | (1 << 3);
  85        else
  86                ret = inserted_index & 7;
  87
  88        spin_unlock_irqrestore(&ps3_htab_lock, flags);
  89
  90        return ret;
  91}
  92
  93static long ps3_hpte_remove(unsigned long hpte_group)
  94{
  95        panic("ps3_hpte_remove() not implemented");
  96        return 0;
  97}
  98
  99static long ps3_hpte_updatepp(unsigned long slot, unsigned long newpp,
 100                              unsigned long vpn, int psize, int apsize,
 101                              int ssize, unsigned long inv_flags)
 102{
 103        int result;
 104        u64 hpte_v, want_v, hpte_rs;
 105        u64 hpte_v_array[4];
 106        unsigned long flags;
 107        long ret;
 108
 109        want_v = hpte_encode_avpn(vpn, psize, ssize);
 110
 111        spin_lock_irqsave(&ps3_htab_lock, flags);
 112
 113        result = lv1_read_htab_entries(PS3_LPAR_VAS_ID_CURRENT, slot & ~0x3UL,
 114                                       &hpte_v_array[0], &hpte_v_array[1],
 115                                       &hpte_v_array[2], &hpte_v_array[3],
 116                                       &hpte_rs);
 117
 118        if (result) {
 119                pr_info("%s: result=%s read vpn=%lx slot=%lx psize=%d\n",
 120                        __func__, ps3_result(result), vpn, slot, psize);
 121                BUG();
 122        }
 123
 124        hpte_v = hpte_v_array[slot % 4];
 125
 126        /*
 127         * As lv1_read_htab_entries() does not give us the RPN, we can
 128         * not synthesize the new hpte_r value here, and therefore can
 129         * not update the hpte with lv1_insert_htab_entry(), so we
 130         * instead invalidate it and ask the caller to update it via
 131         * ps3_hpte_insert() by returning a -1 value.
 132         */
 133        if (!HPTE_V_COMPARE(hpte_v, want_v) || !(hpte_v & HPTE_V_VALID)) {
 134                /* not found */
 135                ret = -1;
 136        } else {
 137                /* entry found, just invalidate it */
 138                result = lv1_write_htab_entry(PS3_LPAR_VAS_ID_CURRENT,
 139                                              slot, 0, 0);
 140                ret = -1;
 141        }
 142
 143        spin_unlock_irqrestore(&ps3_htab_lock, flags);
 144        return ret;
 145}
 146
 147static void ps3_hpte_updateboltedpp(unsigned long newpp, unsigned long ea,
 148        int psize, int ssize)
 149{
 150        panic("ps3_hpte_updateboltedpp() not implemented");
 151}
 152
 153static void ps3_hpte_invalidate(unsigned long slot, unsigned long vpn,
 154                                int psize, int apsize, int ssize, int local)
 155{
 156        unsigned long flags;
 157        int result;
 158
 159        spin_lock_irqsave(&ps3_htab_lock, flags);
 160
 161        result = lv1_write_htab_entry(PS3_LPAR_VAS_ID_CURRENT, slot, 0, 0);
 162
 163        if (result) {
 164                pr_info("%s: result=%s vpn=%lx slot=%lx psize=%d\n",
 165                        __func__, ps3_result(result), vpn, slot, psize);
 166                BUG();
 167        }
 168
 169        spin_unlock_irqrestore(&ps3_htab_lock, flags);
 170}
 171
 172static void ps3_hpte_clear(void)
 173{
 174        unsigned long hpte_count = (1UL << ppc64_pft_size) >> 4;
 175        u64 i;
 176
 177        for (i = 0; i < hpte_count; i++)
 178                lv1_write_htab_entry(PS3_LPAR_VAS_ID_CURRENT, i, 0, 0);
 179
 180        ps3_mm_shutdown();
 181        ps3_mm_vas_destroy();
 182}
 183
 184void __init ps3_hpte_init(unsigned long htab_size)
 185{
 186        mmu_hash_ops.hpte_invalidate = ps3_hpte_invalidate;
 187        mmu_hash_ops.hpte_updatepp = ps3_hpte_updatepp;
 188        mmu_hash_ops.hpte_updateboltedpp = ps3_hpte_updateboltedpp;
 189        mmu_hash_ops.hpte_insert = ps3_hpte_insert;
 190        mmu_hash_ops.hpte_remove = ps3_hpte_remove;
 191        mmu_hash_ops.hpte_clear_all = ps3_hpte_clear;
 192
 193        ppc64_pft_size = __ilog2(htab_size);
 194}
 195
 196