blob: cd8f2fbb6d1a28f58733bfb2a352ce1bd0615f7b [file] [log] [blame]
Geoff Levandc6cec722006-11-23 00:46:54 +01001/*
2 * PS3 pagetable management routines.
3 *
4 * Copyright (C) 2006 Sony Computer Entertainment Inc.
Geert Uytterhoeven36dff962007-02-12 00:55:26 -08005 * Copyright 2006, 2007 Sony Corporation
Geoff Levandc6cec722006-11-23 00:46:54 +01006 *
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>
Yinghai Lu95f72d12010-07-12 14:36:09 +100022#include <linux/memblock.h>
Geoff Levandc6cec722006-11-23 00:46:54 +010023
24#include <asm/machdep.h>
David S. Millerd9b2b2a2008-02-13 16:56:49 -080025#include <asm/prom.h>
Geoff Levandc6cec722006-11-23 00:46:54 +010026#include <asm/udbg.h>
Geoff Levandc6cec722006-11-23 00:46:54 +010027#include <asm/lv1call.h>
Geert Uytterhoeven36dff962007-02-12 00:55:26 -080028#include <asm/ps3fb.h>
Geoff Levandc6cec722006-11-23 00:46:54 +010029
Geoff Levand97db7f72013-02-13 17:03:16 +000030#define PS3_VERBOSE_RESULT
Geoff Levandc6cec722006-11-23 00:46:54 +010031#include "platform.h"
32
Masakazu Mokuno9cfeb742008-08-21 06:18:51 +100033/**
34 * enum lpar_vas_id - id of LPAR virtual address space.
35 * @lpar_vas_id_current: Current selected virtual address space
36 *
37 * Identify the target LPAR address space.
38 */
Geoff Levandc6cec722006-11-23 00:46:54 +010039
Masakazu Mokuno9cfeb742008-08-21 06:18:51 +100040enum ps3_lpar_vas_id {
41 PS3_LPAR_VAS_ID_CURRENT = 0,
42};
Geoff Levandc6cec722006-11-23 00:46:54 +010043
Geoff Levandc6cec722006-11-23 00:46:54 +010044
Masakazu Mokuno9cfeb742008-08-21 06:18:51 +100045static DEFINE_SPINLOCK(ps3_htab_lock);
Geoff Levandc6cec722006-11-23 00:46:54 +010046
Aneesh Kumar K.V5524a272012-09-10 02:52:50 +000047static long ps3_hpte_insert(unsigned long hpte_group, unsigned long vpn,
Paul Mackerras1189be62007-10-11 20:37:10 +100048 unsigned long pa, unsigned long rflags, unsigned long vflags,
49 int psize, int ssize)
Geoff Levandc6cec722006-11-23 00:46:54 +010050{
Masakazu Mokuno9cfeb742008-08-21 06:18:51 +100051 int result;
52 u64 hpte_v, hpte_r;
53 u64 inserted_index;
54 u64 evicted_v, evicted_r;
55 u64 hpte_v_array[4], hpte_rs;
Geoff Levandc6cec722006-11-23 00:46:54 +010056 unsigned long flags;
Masakazu Mokuno9cfeb742008-08-21 06:18:51 +100057 long ret = -1;
Geoff Levandc6cec722006-11-23 00:46:54 +010058
Masakazu Mokuno9cfeb742008-08-21 06:18:51 +100059 /*
60 * lv1_insert_htab_entry() will search for victim
61 * entry in both primary and secondary pte group
62 */
63 vflags &= ~HPTE_V_SECONDARY;
Geoff Levandc6cec722006-11-23 00:46:54 +010064
Aneesh Kumar K.V5524a272012-09-10 02:52:50 +000065 hpte_v = hpte_encode_v(vpn, psize, ssize) | vflags | HPTE_V_VALID;
Masakazu Mokuno9cfeb742008-08-21 06:18:51 +100066 hpte_r = hpte_encode_r(ps3_mm_phys_to_lpar(pa), psize) | rflags;
Geoff Levandc6cec722006-11-23 00:46:54 +010067
Masakazu Mokuno9cfeb742008-08-21 06:18:51 +100068 spin_lock_irqsave(&ps3_htab_lock, flags);
Geoff Levandc6cec722006-11-23 00:46:54 +010069
Masakazu Mokuno9cfeb742008-08-21 06:18:51 +100070 /* talk hvc to replace entries BOLTED == 0 */
71 result = lv1_insert_htab_entry(PS3_LPAR_VAS_ID_CURRENT, hpte_group,
72 hpte_v, hpte_r,
73 HPTE_V_BOLTED, 0,
74 &inserted_index,
75 &evicted_v, &evicted_r);
Geoff Levandc6cec722006-11-23 00:46:54 +010076
77 if (result) {
Masakazu Mokuno9cfeb742008-08-21 06:18:51 +100078 /* all entries bolted !*/
Geoff Levand97db7f72013-02-13 17:03:16 +000079 pr_info("%s:result=%s vpn=%lx pa=%lx ix=%lx v=%llx r=%llx\n",
80 __func__, ps3_result(result), vpn, pa, hpte_group,
81 hpte_v, hpte_r);
Geoff Levandc6cec722006-11-23 00:46:54 +010082 BUG();
83 }
84
85 /*
Masakazu Mokuno9cfeb742008-08-21 06:18:51 +100086 * see if the entry is inserted into secondary pteg
Geoff Levandc6cec722006-11-23 00:46:54 +010087 */
Masakazu Mokuno9cfeb742008-08-21 06:18:51 +100088 result = lv1_read_htab_entries(PS3_LPAR_VAS_ID_CURRENT,
89 inserted_index & ~0x3UL,
90 &hpte_v_array[0], &hpte_v_array[1],
91 &hpte_v_array[2], &hpte_v_array[3],
92 &hpte_rs);
93 BUG_ON(result);
Geoff Levandc6cec722006-11-23 00:46:54 +010094
Masakazu Mokuno9cfeb742008-08-21 06:18:51 +100095 if (hpte_v_array[inserted_index % 4] & HPTE_V_SECONDARY)
96 ret = (inserted_index & 7) | (1 << 3);
97 else
98 ret = inserted_index & 7;
Geoff Levandc6cec722006-11-23 00:46:54 +010099
Masakazu Mokuno9cfeb742008-08-21 06:18:51 +1000100 spin_unlock_irqrestore(&ps3_htab_lock, flags);
Geoff Levandc6cec722006-11-23 00:46:54 +0100101
Masakazu Mokuno9cfeb742008-08-21 06:18:51 +1000102 return ret;
Geoff Levandc6cec722006-11-23 00:46:54 +0100103}
104
105static long ps3_hpte_remove(unsigned long hpte_group)
106{
107 panic("ps3_hpte_remove() not implemented");
108 return 0;
109}
110
111static long ps3_hpte_updatepp(unsigned long slot, unsigned long newpp,
Aneesh Kumar K.V5524a272012-09-10 02:52:50 +0000112 unsigned long vpn, int psize, int ssize, int local)
Geoff Levandc6cec722006-11-23 00:46:54 +0100113{
Masakazu Mokuno9cfeb742008-08-21 06:18:51 +1000114 int result;
115 u64 hpte_v, want_v, hpte_rs;
116 u64 hpte_v_array[4];
Geoff Levandc6cec722006-11-23 00:46:54 +0100117 unsigned long flags;
Masakazu Mokuno9cfeb742008-08-21 06:18:51 +1000118 long ret;
Geoff Levandc6cec722006-11-23 00:46:54 +0100119
Aneesh Kumar K.V74f227b2013-04-28 09:37:34 +0000120 want_v = hpte_encode_avpn(vpn, psize, ssize);
Geoff Levandc6cec722006-11-23 00:46:54 +0100121
Masakazu Mokuno9cfeb742008-08-21 06:18:51 +1000122 spin_lock_irqsave(&ps3_htab_lock, flags);
Geoff Levandc6cec722006-11-23 00:46:54 +0100123
Masakazu Mokuno9cfeb742008-08-21 06:18:51 +1000124 result = lv1_read_htab_entries(PS3_LPAR_VAS_ID_CURRENT, slot & ~0x3UL,
125 &hpte_v_array[0], &hpte_v_array[1],
126 &hpte_v_array[2], &hpte_v_array[3],
127 &hpte_rs);
Geoff Levandc6cec722006-11-23 00:46:54 +0100128
129 if (result) {
Geoff Levand97db7f72013-02-13 17:03:16 +0000130 pr_info("%s: result=%s read vpn=%lx slot=%lx psize=%d\n",
131 __func__, ps3_result(result), vpn, slot, psize);
Geoff Levandc6cec722006-11-23 00:46:54 +0100132 BUG();
133 }
134
Masakazu Mokuno9cfeb742008-08-21 06:18:51 +1000135 hpte_v = hpte_v_array[slot % 4];
Geoff Levandc6cec722006-11-23 00:46:54 +0100136
Masakazu Mokuno9cfeb742008-08-21 06:18:51 +1000137 /*
138 * As lv1_read_htab_entries() does not give us the RPN, we can
139 * not synthesize the new hpte_r value here, and therefore can
140 * not update the hpte with lv1_insert_htab_entry(), so we
Uwe Kleine-Königfd0961f2010-06-11 12:16:56 +0200141 * instead invalidate it and ask the caller to update it via
Masakazu Mokuno9cfeb742008-08-21 06:18:51 +1000142 * ps3_hpte_insert() by returning a -1 value.
143 */
144 if (!HPTE_V_COMPARE(hpte_v, want_v) || !(hpte_v & HPTE_V_VALID)) {
145 /* not found */
146 ret = -1;
147 } else {
148 /* entry found, just invalidate it */
149 result = lv1_write_htab_entry(PS3_LPAR_VAS_ID_CURRENT,
150 slot, 0, 0);
151 ret = -1;
152 }
Geoff Levandc6cec722006-11-23 00:46:54 +0100153
Masakazu Mokuno9cfeb742008-08-21 06:18:51 +1000154 spin_unlock_irqrestore(&ps3_htab_lock, flags);
155 return ret;
Geoff Levandc6cec722006-11-23 00:46:54 +0100156}
157
158static void ps3_hpte_updateboltedpp(unsigned long newpp, unsigned long ea,
Paul Mackerras1189be62007-10-11 20:37:10 +1000159 int psize, int ssize)
Geoff Levandc6cec722006-11-23 00:46:54 +0100160{
161 panic("ps3_hpte_updateboltedpp() not implemented");
162}
163
Aneesh Kumar K.V5524a272012-09-10 02:52:50 +0000164static void ps3_hpte_invalidate(unsigned long slot, unsigned long vpn,
Paul Mackerras1189be62007-10-11 20:37:10 +1000165 int psize, int ssize, int local)
Geoff Levandc6cec722006-11-23 00:46:54 +0100166{
167 unsigned long flags;
Masakazu Mokuno9cfeb742008-08-21 06:18:51 +1000168 int result;
Geoff Levandc6cec722006-11-23 00:46:54 +0100169
Masakazu Mokuno9cfeb742008-08-21 06:18:51 +1000170 spin_lock_irqsave(&ps3_htab_lock, flags);
171
172 result = lv1_write_htab_entry(PS3_LPAR_VAS_ID_CURRENT, slot, 0, 0);
Geoff Levandc6cec722006-11-23 00:46:54 +0100173
174 if (result) {
Geoff Levand97db7f72013-02-13 17:03:16 +0000175 pr_info("%s: result=%s vpn=%lx slot=%lx psize=%d\n",
176 __func__, ps3_result(result), vpn, slot, psize);
Geoff Levandc6cec722006-11-23 00:46:54 +0100177 BUG();
178 }
179
Masakazu Mokuno9cfeb742008-08-21 06:18:51 +1000180 spin_unlock_irqrestore(&ps3_htab_lock, flags);
Geoff Levandc6cec722006-11-23 00:46:54 +0100181}
182
183static void ps3_hpte_clear(void)
184{
Masakazu Mokuno9cfeb742008-08-21 06:18:51 +1000185 unsigned long hpte_count = (1UL << ppc64_pft_size) >> 4;
186 u64 i;
Geert Uytterhoeven36dff962007-02-12 00:55:26 -0800187
Masakazu Mokuno9cfeb742008-08-21 06:18:51 +1000188 for (i = 0; i < hpte_count; i++)
189 lv1_write_htab_entry(PS3_LPAR_VAS_ID_CURRENT, i, 0, 0);
Geoff Levand9263e852007-06-16 07:19:32 +1000190
191 ps3_mm_shutdown();
192 ps3_mm_vas_destroy();
Geoff Levandc6cec722006-11-23 00:46:54 +0100193}
194
195void __init ps3_hpte_init(unsigned long htab_size)
196{
Geoff Levandc6cec722006-11-23 00:46:54 +0100197 ppc_md.hpte_invalidate = ps3_hpte_invalidate;
198 ppc_md.hpte_updatepp = ps3_hpte_updatepp;
199 ppc_md.hpte_updateboltedpp = ps3_hpte_updateboltedpp;
200 ppc_md.hpte_insert = ps3_hpte_insert;
201 ppc_md.hpte_remove = ps3_hpte_remove;
202 ppc_md.hpte_clear_all = ps3_hpte_clear;
203
204 ppc64_pft_size = __ilog2(htab_size);
Geoff Levandc6cec722006-11-23 00:46:54 +0100205}
206