htab.c 5.4 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
#define PS3_VERBOSE_RESULT
G
Geoff Levand 已提交
31 32
#include "platform.h"

33 34 35 36 37 38 39 40 41 42 43 44 45
/**
 * 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 已提交
46

47
static long ps3_hpte_insert(unsigned long hpte_group, unsigned long vpn,
P
Paul Mackerras 已提交
48 49
	unsigned long pa, unsigned long rflags, unsigned long vflags,
	int psize, int ssize)
G
Geoff Levand 已提交
50
{
51 52 53 54 55
	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 已提交
56
	unsigned long flags;
57
	long ret = -1;
G
Geoff Levand 已提交
58

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

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

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

70 71 72 73 74 75
	/* 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 已提交
76 77

	if (result) {
78
		/* all entries bolted !*/
79 80 81
		pr_info("%s:result=%s vpn=%lx pa=%lx ix=%lx v=%llx r=%llx\n",
			__func__, ps3_result(result), vpn, pa, hpte_group,
			hpte_v, hpte_r);
G
Geoff Levand 已提交
82 83 84 85
		BUG();
	}

	/*
86
	 * see if the entry is inserted into secondary pteg
G
Geoff Levand 已提交
87
	 */
88 89 90 91 92 93
	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 已提交
94

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

100
	spin_unlock_irqrestore(&ps3_htab_lock, flags);
G
Geoff Levand 已提交
101

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

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,
112
	unsigned long vpn, int psize, int ssize, int local)
G
Geoff Levand 已提交
113
{
114 115 116
	int result;
	u64 hpte_v, want_v, hpte_rs;
	u64 hpte_v_array[4];
G
Geoff Levand 已提交
117
	unsigned long flags;
118
	long ret;
G
Geoff Levand 已提交
119

120
	want_v = hpte_encode_v(vpn, psize, ssize);
G
Geoff Levand 已提交
121

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

124 125 126 127
	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 已提交
128 129

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

135
	hpte_v = hpte_v_array[slot % 4];
G
Geoff Levand 已提交
136

137 138 139 140
	/*
	 * 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
141
	 * instead invalidate it and ask the caller to update it via
142 143 144 145 146 147 148 149 150 151 152
	 * 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 已提交
153

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

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

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

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

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

	if (result) {
175 176
		pr_info("%s: result=%s vpn=%lx slot=%lx psize=%d\n",
			__func__, ps3_result(result), vpn, slot, psize);
G
Geoff Levand 已提交
177 178 179
		BUG();
	}

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

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

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

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

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);
}