blob: 2f95d33cf34a491d5970dd14ff5b88f757b31181 [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,
Aneesh Kumar K.Vb1022fb2013-04-28 09:37:35 +000049 int psize, int apsize, 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.Vb1022fb2013-04-28 09:37:35 +000065 hpte_v = hpte_encode_v(vpn, psize, apsize, ssize) | vflags | HPTE_V_VALID;
66 hpte_r = hpte_encode_r(ps3_mm_phys_to_lpar(pa), psize, apsize) | 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.Vdb3d8532013-06-20 14:30:13 +0530112 unsigned long vpn, int psize, int apsize,
Aneesh Kumar K.Vaefa5682014-12-04 11:00:14 +0530113 int ssize, unsigned long inv_flags)
Geoff Levandc6cec722006-11-23 00:46:54 +0100114{
Masakazu Mokuno9cfeb742008-08-21 06:18:51 +1000115 int result;
116 u64 hpte_v, want_v, hpte_rs;
117 u64 hpte_v_array[4];
Geoff Levandc6cec722006-11-23 00:46:54 +0100118 unsigned long flags;
Masakazu Mokuno9cfeb742008-08-21 06:18:51 +1000119 long ret;
Geoff Levandc6cec722006-11-23 00:46:54 +0100120
Aneesh Kumar K.V74f227b2013-04-28 09:37:34 +0000121 want_v = hpte_encode_avpn(vpn, psize, ssize);
Geoff Levandc6cec722006-11-23 00:46:54 +0100122
Masakazu Mokuno9cfeb742008-08-21 06:18:51 +1000123 spin_lock_irqsave(&ps3_htab_lock, flags);
Geoff Levandc6cec722006-11-23 00:46:54 +0100124
Masakazu Mokuno9cfeb742008-08-21 06:18:51 +1000125 result = lv1_read_htab_entries(PS3_LPAR_VAS_ID_CURRENT, slot & ~0x3UL,
126 &hpte_v_array[0], &hpte_v_array[1],
127 &hpte_v_array[2], &hpte_v_array[3],
128 &hpte_rs);
Geoff Levandc6cec722006-11-23 00:46:54 +0100129
130 if (result) {
Geoff Levand97db7f72013-02-13 17:03:16 +0000131 pr_info("%s: result=%s read vpn=%lx slot=%lx psize=%d\n",
132 __func__, ps3_result(result), vpn, slot, psize);
Geoff Levandc6cec722006-11-23 00:46:54 +0100133 BUG();
134 }
135
Masakazu Mokuno9cfeb742008-08-21 06:18:51 +1000136 hpte_v = hpte_v_array[slot % 4];
Geoff Levandc6cec722006-11-23 00:46:54 +0100137
Masakazu Mokuno9cfeb742008-08-21 06:18:51 +1000138 /*
139 * As lv1_read_htab_entries() does not give us the RPN, we can
140 * not synthesize the new hpte_r value here, and therefore can
141 * not update the hpte with lv1_insert_htab_entry(), so we
Uwe Kleine-Königfd0961f2010-06-11 12:16:56 +0200142 * instead invalidate it and ask the caller to update it via
Masakazu Mokuno9cfeb742008-08-21 06:18:51 +1000143 * ps3_hpte_insert() by returning a -1 value.
144 */
145 if (!HPTE_V_COMPARE(hpte_v, want_v) || !(hpte_v & HPTE_V_VALID)) {
146 /* not found */
147 ret = -1;
148 } else {
149 /* entry found, just invalidate it */
150 result = lv1_write_htab_entry(PS3_LPAR_VAS_ID_CURRENT,
151 slot, 0, 0);
152 ret = -1;
153 }
Geoff Levandc6cec722006-11-23 00:46:54 +0100154
Masakazu Mokuno9cfeb742008-08-21 06:18:51 +1000155 spin_unlock_irqrestore(&ps3_htab_lock, flags);
156 return ret;
Geoff Levandc6cec722006-11-23 00:46:54 +0100157}
158
159static void ps3_hpte_updateboltedpp(unsigned long newpp, unsigned long ea,
Paul Mackerras1189be62007-10-11 20:37:10 +1000160 int psize, int ssize)
Geoff Levandc6cec722006-11-23 00:46:54 +0100161{
162 panic("ps3_hpte_updateboltedpp() not implemented");
163}
164
Aneesh Kumar K.V5524a272012-09-10 02:52:50 +0000165static void ps3_hpte_invalidate(unsigned long slot, unsigned long vpn,
Aneesh Kumar K.Vdb3d8532013-06-20 14:30:13 +0530166 int psize, int apsize, int ssize, int local)
Geoff Levandc6cec722006-11-23 00:46:54 +0100167{
168 unsigned long flags;
Masakazu Mokuno9cfeb742008-08-21 06:18:51 +1000169 int result;
Geoff Levandc6cec722006-11-23 00:46:54 +0100170
Masakazu Mokuno9cfeb742008-08-21 06:18:51 +1000171 spin_lock_irqsave(&ps3_htab_lock, flags);
172
173 result = lv1_write_htab_entry(PS3_LPAR_VAS_ID_CURRENT, slot, 0, 0);
Geoff Levandc6cec722006-11-23 00:46:54 +0100174
175 if (result) {
Geoff Levand97db7f72013-02-13 17:03:16 +0000176 pr_info("%s: result=%s vpn=%lx slot=%lx psize=%d\n",
177 __func__, ps3_result(result), vpn, slot, psize);
Geoff Levandc6cec722006-11-23 00:46:54 +0100178 BUG();
179 }
180
Masakazu Mokuno9cfeb742008-08-21 06:18:51 +1000181 spin_unlock_irqrestore(&ps3_htab_lock, flags);
Geoff Levandc6cec722006-11-23 00:46:54 +0100182}
183
184static void ps3_hpte_clear(void)
185{
Masakazu Mokuno9cfeb742008-08-21 06:18:51 +1000186 unsigned long hpte_count = (1UL << ppc64_pft_size) >> 4;
187 u64 i;
Geert Uytterhoeven36dff962007-02-12 00:55:26 -0800188
Masakazu Mokuno9cfeb742008-08-21 06:18:51 +1000189 for (i = 0; i < hpte_count; i++)
190 lv1_write_htab_entry(PS3_LPAR_VAS_ID_CURRENT, i, 0, 0);
Geoff Levand9263e852007-06-16 07:19:32 +1000191
192 ps3_mm_shutdown();
193 ps3_mm_vas_destroy();
Geoff Levandc6cec722006-11-23 00:46:54 +0100194}
195
196void __init ps3_hpte_init(unsigned long htab_size)
197{
Geoff Levandc6cec722006-11-23 00:46:54 +0100198 ppc_md.hpte_invalidate = ps3_hpte_invalidate;
199 ppc_md.hpte_updatepp = ps3_hpte_updatepp;
200 ppc_md.hpte_updateboltedpp = ps3_hpte_updateboltedpp;
201 ppc_md.hpte_insert = ps3_hpte_insert;
202 ppc_md.hpte_remove = ps3_hpte_remove;
203 ppc_md.hpte_clear_all = ps3_hpte_clear;
204
205 ppc64_pft_size = __ilog2(htab_size);
Geoff Levandc6cec722006-11-23 00:46:54 +0100206}
207