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