htab.c 5.3 KB
Newer Older
G
Geoff Levand 已提交
1 2 3 4
/*
 *  PS3 pagetable management routines.
 *
 *  Copyright (C) 2006 Sony Computer Entertainment Inc.
5
 *  Copyright 2006, 2007 Sony Corporation
G
Geoff Levand 已提交
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; version 2 of the License.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include <linux/kernel.h>
Y
Yinghai Lu 已提交
22
#include <linux/memblock.h>
G
Geoff Levand 已提交
23 24

#include <asm/machdep.h>
25
#include <asm/prom.h>
G
Geoff Levand 已提交
26 27
#include <asm/udbg.h>
#include <asm/lv1call.h>
28
#include <asm/ps3fb.h>
G
Geoff Levand 已提交
29 30 31

#include "platform.h"

32 33 34 35 36 37 38 39 40 41 42 43 44
/**
 * enum lpar_vas_id - id of LPAR virtual address space.
 * @lpar_vas_id_current: Current selected virtual address space
 *
 * Identify the target LPAR address space.
 */

enum ps3_lpar_vas_id {
	PS3_LPAR_VAS_ID_CURRENT = 0,
};


static DEFINE_SPINLOCK(ps3_htab_lock);
G
Geoff Levand 已提交
45 46

static long ps3_hpte_insert(unsigned long hpte_group, unsigned long va,
P
Paul Mackerras 已提交
47 48
	unsigned long pa, unsigned long rflags, unsigned long vflags,
	int psize, int ssize)
G
Geoff Levand 已提交
49
{
50 51 52 53 54
	int result;
	u64 hpte_v, hpte_r;
	u64 inserted_index;
	u64 evicted_v, evicted_r;
	u64 hpte_v_array[4], hpte_rs;
G
Geoff Levand 已提交
55
	unsigned long flags;
56
	long ret = -1;
G
Geoff Levand 已提交
57

58 59 60 61 62
	/*
	 * lv1_insert_htab_entry() will search for victim
	 * entry in both primary and secondary pte group
	 */
	vflags &= ~HPTE_V_SECONDARY;
G
Geoff Levand 已提交
63

64 65
	hpte_v = hpte_encode_v(va, psize, ssize) | vflags | HPTE_V_VALID;
	hpte_r = hpte_encode_r(ps3_mm_phys_to_lpar(pa), psize) | rflags;
G
Geoff Levand 已提交
66

67
	spin_lock_irqsave(&ps3_htab_lock, flags);
G
Geoff Levand 已提交
68

69 70 71 72 73 74
	/* talk hvc to replace entries BOLTED == 0 */
	result = lv1_insert_htab_entry(PS3_LPAR_VAS_ID_CURRENT, hpte_group,
				       hpte_v, hpte_r,
				       HPTE_V_BOLTED, 0,
				       &inserted_index,
				       &evicted_v, &evicted_r);
G
Geoff Levand 已提交
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);
G
Geoff Levand 已提交
80 81 82 83
		BUG();
	}

	/*
84
	 * see if the entry is inserted into secondary pteg
G
Geoff Levand 已提交
85
	 */
86 87 88 89 90 91
	result = lv1_read_htab_entries(PS3_LPAR_VAS_ID_CURRENT,
				       inserted_index & ~0x3UL,
				       &hpte_v_array[0], &hpte_v_array[1],
				       &hpte_v_array[2], &hpte_v_array[3],
				       &hpte_rs);
	BUG_ON(result);
G
Geoff Levand 已提交
92

93 94 95 96
	if (hpte_v_array[inserted_index % 4] & HPTE_V_SECONDARY)
		ret = (inserted_index & 7) | (1 << 3);
	else
		ret = inserted_index & 7;
G
Geoff Levand 已提交
97

98
	spin_unlock_irqrestore(&ps3_htab_lock, flags);
G
Geoff Levand 已提交
99

100
	return ret;
G
Geoff Levand 已提交
101 102 103 104 105 106 107 108 109
}

static long ps3_hpte_remove(unsigned long hpte_group)
{
	panic("ps3_hpte_remove() not implemented");
	return 0;
}

static long ps3_hpte_updatepp(unsigned long slot, unsigned long newpp,
P
Paul Mackerras 已提交
110
	unsigned long va, int psize, int ssize, int local)
G
Geoff Levand 已提交
111
{
112 113 114
	int result;
	u64 hpte_v, want_v, hpte_rs;
	u64 hpte_v_array[4];
G
Geoff Levand 已提交
115
	unsigned long flags;
116
	long ret;
G
Geoff Levand 已提交
117

118
	want_v = hpte_encode_v(va, psize, ssize);
G
Geoff Levand 已提交
119

120
	spin_lock_irqsave(&ps3_htab_lock, flags);
G
Geoff Levand 已提交
121

122 123 124 125
	result = lv1_read_htab_entries(PS3_LPAR_VAS_ID_CURRENT, slot & ~0x3UL,
				       &hpte_v_array[0], &hpte_v_array[1],
				       &hpte_v_array[2], &hpte_v_array[3],
				       &hpte_rs);
G
Geoff Levand 已提交
126 127

	if (result) {
128 129
		pr_info("%s: res=%d read va=%lx slot=%lx psize=%d\n",
			__func__, result, va, slot, psize);
G
Geoff Levand 已提交
130 131 132
		BUG();
	}

133
	hpte_v = hpte_v_array[slot % 4];
G
Geoff Levand 已提交
134

135 136 137 138
	/*
	 * As lv1_read_htab_entries() does not give us the RPN, we can
	 * not synthesize the new hpte_r value here, and therefore can
	 * not update the hpte with lv1_insert_htab_entry(), so we
139
	 * instead invalidate it and ask the caller to update it via
140 141 142 143 144 145 146 147 148 149 150
	 * ps3_hpte_insert() by returning a -1 value.
	 */
	if (!HPTE_V_COMPARE(hpte_v, want_v) || !(hpte_v & HPTE_V_VALID)) {
		/* not found */
		ret = -1;
	} else {
		/* entry found, just invalidate it */
		result = lv1_write_htab_entry(PS3_LPAR_VAS_ID_CURRENT,
					      slot, 0, 0);
		ret = -1;
	}
G
Geoff Levand 已提交
151

152 153
	spin_unlock_irqrestore(&ps3_htab_lock, flags);
	return ret;
G
Geoff Levand 已提交
154 155 156
}

static void ps3_hpte_updateboltedpp(unsigned long newpp, unsigned long ea,
P
Paul Mackerras 已提交
157
	int psize, int ssize)
G
Geoff Levand 已提交
158 159 160 161 162
{
	panic("ps3_hpte_updateboltedpp() not implemented");
}

static void ps3_hpte_invalidate(unsigned long slot, unsigned long va,
P
Paul Mackerras 已提交
163
	int psize, int ssize, int local)
G
Geoff Levand 已提交
164 165
{
	unsigned long flags;
166 167 168
	int result;

	spin_lock_irqsave(&ps3_htab_lock, flags);
G
Geoff Levand 已提交
169

170
	result = lv1_write_htab_entry(PS3_LPAR_VAS_ID_CURRENT, slot, 0, 0);
G
Geoff Levand 已提交
171 172

	if (result) {
173 174
		pr_info("%s: res=%d va=%lx slot=%lx psize=%d\n",
			__func__, result, va, slot, psize);
G
Geoff Levand 已提交
175 176 177
		BUG();
	}

178
	spin_unlock_irqrestore(&ps3_htab_lock, flags);
G
Geoff Levand 已提交
179 180 181 182
}

static void ps3_hpte_clear(void)
{
183 184
	unsigned long hpte_count = (1UL << ppc64_pft_size) >> 4;
	u64 i;
G
Geoff Levand 已提交
185

186 187
	for (i = 0; i < hpte_count; i++)
		lv1_write_htab_entry(PS3_LPAR_VAS_ID_CURRENT, i, 0, 0);
G
Geoff Levand 已提交
188 189 190

	ps3_mm_shutdown();
	ps3_mm_vas_destroy();
G
Geoff Levand 已提交
191 192 193 194 195 196 197 198 199 200 201 202 203 204
}

void __init ps3_hpte_init(unsigned long htab_size)
{
	ppc_md.hpte_invalidate = ps3_hpte_invalidate;
	ppc_md.hpte_updatepp = ps3_hpte_updatepp;
	ppc_md.hpte_updateboltedpp = ps3_hpte_updateboltedpp;
	ppc_md.hpte_insert = ps3_hpte_insert;
	ppc_md.hpte_remove = ps3_hpte_remove;
	ppc_md.hpte_clear_all = ps3_hpte_clear;

	ppc64_pft_size = __ilog2(htab_size);
}