blob: 5eabc4defea56b38d2b9280a07921a1668cde245 [file] [log] [blame]
Shubhraprakash Das79447952012-04-26 18:12:23 -06001/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13#include <linux/types.h>
14#include <linux/device.h>
15#include <linux/spinlock.h>
16#include <linux/genalloc.h>
17#include <linux/slab.h>
18#include <linux/iommu.h>
Shubhraprakash Das767fdda2011-08-15 15:49:45 -060019#include <linux/msm_kgsl.h>
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -060020#include <mach/socinfo.h>
Shubhraprakash Das767fdda2011-08-15 15:49:45 -060021
22#include "kgsl.h"
23#include "kgsl_device.h"
24#include "kgsl_mmu.h"
25#include "kgsl_sharedmem.h"
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -060026#include "kgsl_iommu.h"
Shubhraprakash Dase9541a32012-05-09 22:25:55 -060027#include "adreno_pm4types.h"
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -060028#include "adreno.h"
Jordan Crouse95b68472012-05-25 10:25:01 -060029#include "kgsl_trace.h"
30
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -070031static struct kgsl_iommu_register_list kgsl_iommuv1_reg[KGSL_IOMMU_REG_MAX] = {
32 { 0, 0, 0 }, /* GLOBAL_BASE */
33 { 0x10, 0x0003FFFF, 14 }, /* TTBR0 */
34 { 0x14, 0x0003FFFF, 14 }, /* TTBR1 */
35 { 0x20, 0, 0 }, /* FSR */
36 { 0x800, 0, 0 }, /* TLBIALL */
Shubhraprakash Das2747cf62012-09-27 23:05:43 -070037 { 0x820, 0, 0 }, /* RESUME */
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -070038};
39
Shubhraprakash Das15a8b462012-08-16 23:24:28 -070040static struct kgsl_iommu_register_list kgsl_iommuv2_reg[KGSL_IOMMU_REG_MAX] = {
41 { 0, 0, 0 }, /* GLOBAL_BASE */
42 { 0x20, 0x00FFFFFF, 14 }, /* TTBR0 */
43 { 0x28, 0x00FFFFFF, 14 }, /* TTBR1 */
44 { 0x58, 0, 0 }, /* FSR */
Shubhraprakash Das2747cf62012-09-27 23:05:43 -070045 { 0x618, 0, 0 }, /* TLBIALL */
46 { 0x008, 0, 0 } /* RESUME */
Shubhraprakash Das15a8b462012-08-16 23:24:28 -070047};
48
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -070049static int get_iommu_unit(struct device *dev, struct kgsl_mmu **mmu_out,
50 struct kgsl_iommu_unit **iommu_unit_out)
Jordan Crouse95b68472012-05-25 10:25:01 -060051{
52 int i, j, k;
53
54 for (i = 0; i < KGSL_DEVICE_MAX; i++) {
55 struct kgsl_mmu *mmu;
56 struct kgsl_iommu *iommu;
57
58 if (kgsl_driver.devp[i] == NULL)
59 continue;
60
61 mmu = kgsl_get_mmu(kgsl_driver.devp[i]);
62 if (mmu == NULL || mmu->priv == NULL)
63 continue;
64
65 iommu = mmu->priv;
66
67 for (j = 0; j < iommu->unit_count; j++) {
68 struct kgsl_iommu_unit *iommu_unit =
69 &iommu->iommu_units[j];
70 for (k = 0; k < iommu_unit->dev_count; k++) {
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -070071 if (iommu_unit->dev[k].dev == dev) {
72 *mmu_out = mmu;
73 *iommu_unit_out = iommu_unit;
74 return 0;
75 }
Jordan Crouse95b68472012-05-25 10:25:01 -060076 }
77 }
78 }
79
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -070080 return -EINVAL;
Jordan Crouse95b68472012-05-25 10:25:01 -060081}
82
83static struct kgsl_iommu_device *get_iommu_device(struct kgsl_iommu_unit *unit,
84 struct device *dev)
85{
86 int k;
87
88 for (k = 0; unit && k < unit->dev_count; k++) {
89 if (unit->dev[k].dev == dev)
90 return &(unit->dev[k]);
91 }
92
93 return NULL;
94}
95
96static int kgsl_iommu_fault_handler(struct iommu_domain *domain,
97 struct device *dev, unsigned long addr, int flags)
98{
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -070099 int ret = 0;
100 struct kgsl_mmu *mmu;
101 struct kgsl_iommu *iommu;
102 struct kgsl_iommu_unit *iommu_unit;
103 struct kgsl_iommu_device *iommu_dev;
Jordan Crouse95b68472012-05-25 10:25:01 -0600104 unsigned int ptbase, fsr;
105
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700106 ret = get_iommu_unit(dev, &mmu, &iommu_unit);
107 if (ret)
108 goto done;
109 iommu_dev = get_iommu_device(iommu_unit, dev);
Jordan Crouse95b68472012-05-25 10:25:01 -0600110 if (!iommu_dev) {
111 KGSL_CORE_ERR("Invalid IOMMU device %p\n", dev);
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700112 ret = -ENOSYS;
113 goto done;
Jordan Crouse95b68472012-05-25 10:25:01 -0600114 }
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700115 iommu = mmu->priv;
Jordan Crouse95b68472012-05-25 10:25:01 -0600116
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700117 ptbase = KGSL_IOMMU_GET_CTX_REG(iommu, iommu_unit,
Shubhraprakash Das190553a2012-06-11 15:17:59 -0600118 iommu_dev->ctx_id, TTBR0);
Jordan Crouse95b68472012-05-25 10:25:01 -0600119
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700120 fsr = KGSL_IOMMU_GET_CTX_REG(iommu, iommu_unit,
Jordan Crouse95b68472012-05-25 10:25:01 -0600121 iommu_dev->ctx_id, FSR);
122
123 KGSL_MEM_CRIT(iommu_dev->kgsldev,
124 "GPU PAGE FAULT: addr = %lX pid = %d\n",
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700125 addr, kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase));
Jordan Crouse95b68472012-05-25 10:25:01 -0600126 KGSL_MEM_CRIT(iommu_dev->kgsldev, "context = %d FSR = %X\n",
127 iommu_dev->ctx_id, fsr);
128
Shubhraprakash Das2747cf62012-09-27 23:05:43 -0700129 mmu->fault = 1;
130 iommu_dev->fault = 1;
131
Jordan Crouse95b68472012-05-25 10:25:01 -0600132 trace_kgsl_mmu_pagefault(iommu_dev->kgsldev, addr,
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700133 kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase), 0);
Jordan Crouse95b68472012-05-25 10:25:01 -0600134
Shubhraprakash Das2747cf62012-09-27 23:05:43 -0700135 /*
136 * We do not want the h/w to resume fetching data from an iommu unit
137 * that has faulted, this is better for debugging as it will stall
138 * the GPU and trigger a snapshot. To stall the transaction return
139 * EBUSY error.
140 */
141 ret = -EBUSY;
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700142done:
143 return ret;
Jordan Crouse95b68472012-05-25 10:25:01 -0600144}
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600145
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -0600146/*
147 * kgsl_iommu_disable_clk - Disable iommu clocks
148 * @mmu - Pointer to mmu structure
149 *
150 * Disables iommu clocks
151 * Return - void
152 */
153static void kgsl_iommu_disable_clk(struct kgsl_mmu *mmu)
154{
155 struct kgsl_iommu *iommu = mmu->priv;
156 struct msm_iommu_drvdata *iommu_drvdata;
157 int i, j;
158
159 for (i = 0; i < iommu->unit_count; i++) {
160 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
161 for (j = 0; j < iommu_unit->dev_count; j++) {
162 if (!iommu_unit->dev[j].clk_enabled)
163 continue;
164 iommu_drvdata = dev_get_drvdata(
165 iommu_unit->dev[j].dev->parent);
Shubhraprakash Das102aac52012-08-16 22:12:27 -0700166 if (iommu_drvdata->aclk)
167 clk_disable_unprepare(iommu_drvdata->aclk);
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -0600168 if (iommu_drvdata->clk)
169 clk_disable_unprepare(iommu_drvdata->clk);
170 clk_disable_unprepare(iommu_drvdata->pclk);
171 iommu_unit->dev[j].clk_enabled = false;
172 }
173 }
174}
175
176/*
Shubhraprakash Dascb068072012-06-07 17:52:41 -0600177 * kgsl_iommu_disable_clk_event - An event function that is executed when
178 * the required timestamp is reached. It disables the IOMMU clocks if
179 * the timestamp on which the clocks can be disabled has expired.
180 * @device - The kgsl device pointer
181 * @data - The data passed during event creation, it is the MMU pointer
182 * @id - Context ID, should always be KGSL_MEMSTORE_GLOBAL
183 * @ts - The current timestamp that has expired for the device
184 *
185 * Disables IOMMU clocks if timestamp has expired
186 * Return - void
187 */
188static void kgsl_iommu_clk_disable_event(struct kgsl_device *device, void *data,
189 unsigned int id, unsigned int ts)
190{
191 struct kgsl_mmu *mmu = data;
192 struct kgsl_iommu *iommu = mmu->priv;
193
194 if (!iommu->clk_event_queued) {
195 if (0 > timestamp_cmp(ts, iommu->iommu_last_cmd_ts))
196 KGSL_DRV_ERR(device,
197 "IOMMU disable clock event being cancelled, "
198 "iommu_last_cmd_ts: %x, retired ts: %x\n",
199 iommu->iommu_last_cmd_ts, ts);
200 return;
201 }
202
203 if (0 <= timestamp_cmp(ts, iommu->iommu_last_cmd_ts)) {
204 kgsl_iommu_disable_clk(mmu);
205 iommu->clk_event_queued = false;
206 } else {
207 /* add new event to fire when ts is reached, this can happen
208 * if we queued an event and someone requested the clocks to
209 * be disbaled on a later timestamp */
210 if (kgsl_add_event(device, id, iommu->iommu_last_cmd_ts,
211 kgsl_iommu_clk_disable_event, mmu, mmu)) {
212 KGSL_DRV_ERR(device,
213 "Failed to add IOMMU disable clk event\n");
214 iommu->clk_event_queued = false;
215 }
216 }
217}
218
219/*
220 * kgsl_iommu_disable_clk_on_ts - Sets up event to disable IOMMU clocks
221 * @mmu - The kgsl MMU pointer
222 * @ts - Timestamp on which the clocks should be disabled
223 * @ts_valid - Indicates whether ts parameter is valid, if this parameter
224 * is false then it means that the calling function wants to disable the
225 * IOMMU clocks immediately without waiting for any timestamp
226 *
227 * Creates an event to disable the IOMMU clocks on timestamp and if event
228 * already exists then updates the timestamp of disabling the IOMMU clocks
229 * with the passed in ts if it is greater than the current value at which
230 * the clocks will be disabled
231 * Return - void
232 */
233static void
234kgsl_iommu_disable_clk_on_ts(struct kgsl_mmu *mmu, unsigned int ts,
235 bool ts_valid)
236{
237 struct kgsl_iommu *iommu = mmu->priv;
238
239 if (iommu->clk_event_queued) {
240 if (ts_valid && (0 <
241 timestamp_cmp(ts, iommu->iommu_last_cmd_ts)))
242 iommu->iommu_last_cmd_ts = ts;
243 } else {
244 if (ts_valid) {
245 iommu->iommu_last_cmd_ts = ts;
246 iommu->clk_event_queued = true;
247 if (kgsl_add_event(mmu->device, KGSL_MEMSTORE_GLOBAL,
248 ts, kgsl_iommu_clk_disable_event, mmu, mmu)) {
249 KGSL_DRV_ERR(mmu->device,
250 "Failed to add IOMMU disable clk event\n");
251 iommu->clk_event_queued = false;
252 }
253 } else {
254 kgsl_iommu_disable_clk(mmu);
255 }
256 }
257}
258
259/*
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -0600260 * kgsl_iommu_enable_clk - Enable iommu clocks
261 * @mmu - Pointer to mmu structure
262 * @ctx_id - The context bank whose clocks are to be turned on
263 *
264 * Enables iommu clocks of a given context
265 * Return: 0 on success else error code
266 */
267static int kgsl_iommu_enable_clk(struct kgsl_mmu *mmu,
268 int ctx_id)
269{
270 int ret = 0;
271 int i, j;
272 struct kgsl_iommu *iommu = mmu->priv;
273 struct msm_iommu_drvdata *iommu_drvdata;
274
275 for (i = 0; i < iommu->unit_count; i++) {
276 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
277 for (j = 0; j < iommu_unit->dev_count; j++) {
278 if (iommu_unit->dev[j].clk_enabled ||
279 ctx_id != iommu_unit->dev[j].ctx_id)
280 continue;
281 iommu_drvdata =
282 dev_get_drvdata(iommu_unit->dev[j].dev->parent);
283 ret = clk_prepare_enable(iommu_drvdata->pclk);
284 if (ret)
285 goto done;
286 if (iommu_drvdata->clk) {
287 ret = clk_prepare_enable(iommu_drvdata->clk);
288 if (ret) {
289 clk_disable_unprepare(
290 iommu_drvdata->pclk);
291 goto done;
292 }
293 }
Shubhraprakash Das102aac52012-08-16 22:12:27 -0700294 if (iommu_drvdata->aclk) {
295 ret = clk_prepare_enable(iommu_drvdata->aclk);
296 if (ret) {
297 if (iommu_drvdata->clk)
298 clk_disable_unprepare(
299 iommu_drvdata->clk);
300 clk_disable_unprepare(
301 iommu_drvdata->pclk);
302 goto done;
303 }
304 }
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -0600305 iommu_unit->dev[j].clk_enabled = true;
306 }
307 }
308done:
309 if (ret)
310 kgsl_iommu_disable_clk(mmu);
311 return ret;
312}
313
Shubhraprakash Das48d97302012-05-07 12:16:08 -0600314/*
315 * kgsl_iommu_pt_equal - Check if pagetables are equal
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700316 * @mmu - Pointer to mmu structure
Shubhraprakash Das48d97302012-05-07 12:16:08 -0600317 * @pt - Pointer to pagetable
318 * @pt_base - Address of a pagetable that the IOMMU register is
319 * programmed with
320 *
321 * Checks whether the pt_base is equal to the base address of
322 * the pagetable which is contained in the pt structure
323 * Return - Non-zero if the pagetable addresses are equal else 0
324 */
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700325static int kgsl_iommu_pt_equal(struct kgsl_mmu *mmu,
326 struct kgsl_pagetable *pt,
327 unsigned int pt_base)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600328{
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700329 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600330 struct kgsl_iommu_pt *iommu_pt = pt ? pt->priv : NULL;
331 unsigned int domain_ptbase = iommu_pt ?
332 iommu_get_pt_base_addr(iommu_pt->domain) : 0;
Shubhraprakash Das48d97302012-05-07 12:16:08 -0600333 /* Only compare the valid address bits of the pt_base */
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700334 domain_ptbase &=
335 (iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
336 iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
337
338 pt_base &=
339 (iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
340 iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
341
Shubhraprakash Das48d97302012-05-07 12:16:08 -0600342 return domain_ptbase && pt_base &&
343 (domain_ptbase == pt_base);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600344}
345
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600346/*
347 * kgsl_iommu_destroy_pagetable - Free up reaources help by a pagetable
348 * @mmu_specific_pt - Pointer to pagetable which is to be freed
349 *
350 * Return - void
351 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600352static void kgsl_iommu_destroy_pagetable(void *mmu_specific_pt)
353{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600354 struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
355 if (iommu_pt->domain)
356 iommu_domain_free(iommu_pt->domain);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600357 kfree(iommu_pt);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600358}
359
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600360/*
361 * kgsl_iommu_create_pagetable - Create a IOMMU pagetable
362 *
363 * Allocate memory to hold a pagetable and allocate the IOMMU
364 * domain which is the actual IOMMU pagetable
365 * Return - void
366 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600367void *kgsl_iommu_create_pagetable(void)
368{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600369 struct kgsl_iommu_pt *iommu_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600370
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600371 iommu_pt = kzalloc(sizeof(struct kgsl_iommu_pt), GFP_KERNEL);
372 if (!iommu_pt) {
373 KGSL_CORE_ERR("kzalloc(%d) failed\n",
374 sizeof(struct kgsl_iommu_pt));
375 return NULL;
376 }
Shubhraprakash Das15a8b462012-08-16 23:24:28 -0700377 /* L2 redirect is not stable on IOMMU v2 */
378 if (msm_soc_version_supports_iommu_v1())
379 iommu_pt->domain = iommu_domain_alloc(&platform_bus_type,
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700380 MSM_IOMMU_DOMAIN_PT_CACHEABLE);
Shubhraprakash Das15a8b462012-08-16 23:24:28 -0700381 else
382 iommu_pt->domain = iommu_domain_alloc(&platform_bus_type,
383 0);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600384 if (!iommu_pt->domain) {
385 KGSL_CORE_ERR("Failed to create iommu domain\n");
386 kfree(iommu_pt);
387 return NULL;
Jordan Crouse95b68472012-05-25 10:25:01 -0600388 } else {
389 iommu_set_fault_handler(iommu_pt->domain,
390 kgsl_iommu_fault_handler);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600391 }
Jordan Crouse95b68472012-05-25 10:25:01 -0600392
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600393 return iommu_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600394}
395
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600396/*
397 * kgsl_detach_pagetable_iommu_domain - Detach the IOMMU unit from a
398 * pagetable
399 * @mmu - Pointer to the device mmu structure
400 * @priv - Flag indicating whether the private or user context is to be
401 * detached
402 *
403 * Detach the IOMMU unit with the domain that is contained in the
404 * hwpagetable of the given mmu. After detaching the IOMMU unit is not
405 * in use because the PTBR will not be set after a detach
406 * Return - void
407 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600408static void kgsl_detach_pagetable_iommu_domain(struct kgsl_mmu *mmu)
409{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600410 struct kgsl_iommu_pt *iommu_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600411 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600412 int i, j;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600413
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600414 for (i = 0; i < iommu->unit_count; i++) {
415 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600416 iommu_pt = mmu->defaultpagetable->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600417 for (j = 0; j < iommu_unit->dev_count; j++) {
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600418 /*
419 * If there is a 2nd default pagetable then priv domain
420 * is attached with this pagetable
421 */
422 if (mmu->priv_bank_table &&
423 (KGSL_IOMMU_CONTEXT_PRIV == j))
424 iommu_pt = mmu->priv_bank_table->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600425 if (iommu_unit->dev[j].attached) {
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600426 iommu_detach_device(iommu_pt->domain,
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600427 iommu_unit->dev[j].dev);
428 iommu_unit->dev[j].attached = false;
429 KGSL_MEM_INFO(mmu->device, "iommu %p detached "
430 "from user dev of MMU: %p\n",
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600431 iommu_pt->domain, mmu);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600432 }
433 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600434 }
435}
436
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600437/*
438 * kgsl_attach_pagetable_iommu_domain - Attach the IOMMU unit to a
439 * pagetable, i.e set the IOMMU's PTBR to the pagetable address and
440 * setup other IOMMU registers for the device so that it becomes
441 * active
442 * @mmu - Pointer to the device mmu structure
443 * @priv - Flag indicating whether the private or user context is to be
444 * attached
445 *
446 * Attach the IOMMU unit with the domain that is contained in the
447 * hwpagetable of the given mmu.
448 * Return - 0 on success else error code
449 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600450static int kgsl_attach_pagetable_iommu_domain(struct kgsl_mmu *mmu)
451{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600452 struct kgsl_iommu_pt *iommu_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600453 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600454 int i, j, ret = 0;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600455
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600456 /*
457 * Loop through all the iommu devcies under all iommu units and
458 * attach the domain
459 */
460 for (i = 0; i < iommu->unit_count; i++) {
461 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600462 iommu_pt = mmu->defaultpagetable->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600463 for (j = 0; j < iommu_unit->dev_count; j++) {
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600464 /*
465 * If there is a 2nd default pagetable then priv domain
466 * is attached to this pagetable
467 */
468 if (mmu->priv_bank_table &&
469 (KGSL_IOMMU_CONTEXT_PRIV == j))
470 iommu_pt = mmu->priv_bank_table->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600471 if (!iommu_unit->dev[j].attached) {
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600472 ret = iommu_attach_device(iommu_pt->domain,
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600473 iommu_unit->dev[j].dev);
474 if (ret) {
475 KGSL_MEM_ERR(mmu->device,
476 "Failed to attach device, err %d\n",
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700477 ret);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600478 goto done;
479 }
480 iommu_unit->dev[j].attached = true;
481 KGSL_MEM_INFO(mmu->device,
482 "iommu pt %p attached to dev %p, ctx_id %d\n",
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600483 iommu_pt->domain, iommu_unit->dev[j].dev,
484 iommu_unit->dev[j].ctx_id);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700485 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600486 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600487 }
488done:
489 return ret;
490}
491
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600492/*
493 * _get_iommu_ctxs - Get device pointer to IOMMU contexts
494 * @mmu - Pointer to mmu device
495 * data - Pointer to the platform data containing information about
496 * iommu devices for one iommu unit
497 * unit_id - The IOMMU unit number. This is not a specific ID but just
498 * a serial number. The serial numbers are treated as ID's of the
499 * IOMMU units
500 *
501 * Return - 0 on success else error code
502 */
503static int _get_iommu_ctxs(struct kgsl_mmu *mmu,
504 struct kgsl_device_iommu_data *data, unsigned int unit_id)
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700505{
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600506 struct kgsl_iommu *iommu = mmu->priv;
507 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[unit_id];
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700508 int i;
509
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600510 if (data->iommu_ctx_count > KGSL_IOMMU_MAX_DEVS_PER_UNIT) {
511 KGSL_CORE_ERR("Too many iommu devices defined for an "
512 "IOMMU unit\n");
513 return -EINVAL;
514 }
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700515
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600516 for (i = 0; i < data->iommu_ctx_count; i++) {
517 if (!data->iommu_ctxs[i].iommu_ctx_name)
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700518 continue;
519
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600520 iommu_unit->dev[iommu_unit->dev_count].dev =
521 msm_iommu_get_ctx(data->iommu_ctxs[i].iommu_ctx_name);
522 if (iommu_unit->dev[iommu_unit->dev_count].dev == NULL) {
523 KGSL_CORE_ERR("Failed to get iommu dev handle for "
524 "device %s\n", data->iommu_ctxs[i].iommu_ctx_name);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700525 return -EINVAL;
526 }
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600527 if (KGSL_IOMMU_CONTEXT_USER != data->iommu_ctxs[i].ctx_id &&
528 KGSL_IOMMU_CONTEXT_PRIV != data->iommu_ctxs[i].ctx_id) {
529 KGSL_CORE_ERR("Invalid context ID defined: %d\n",
530 data->iommu_ctxs[i].ctx_id);
531 return -EINVAL;
532 }
533 iommu_unit->dev[iommu_unit->dev_count].ctx_id =
534 data->iommu_ctxs[i].ctx_id;
Jordan Crouse95b68472012-05-25 10:25:01 -0600535 iommu_unit->dev[iommu_unit->dev_count].kgsldev = mmu->device;
536
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600537 KGSL_DRV_INFO(mmu->device,
538 "Obtained dev handle %p for iommu context %s\n",
539 iommu_unit->dev[iommu_unit->dev_count].dev,
540 data->iommu_ctxs[i].iommu_ctx_name);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700541
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600542 iommu_unit->dev_count++;
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700543 }
544
545 return 0;
546}
547
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600548/*
549 * kgsl_get_iommu_ctxt - Get device pointer to IOMMU contexts
550 * @mmu - Pointer to mmu device
551 *
552 * Get the device pointers for the IOMMU user and priv contexts of the
553 * kgsl device
554 * Return - 0 on success else error code
555 */
556static int kgsl_get_iommu_ctxt(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600557{
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600558 struct platform_device *pdev =
559 container_of(mmu->device->parentdev, struct platform_device,
560 dev);
561 struct kgsl_device_platform_data *pdata_dev = pdev->dev.platform_data;
562 struct kgsl_iommu *iommu = mmu->device->mmu.priv;
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700563 int i, ret = 0;
564
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600565 /* Go through the IOMMU data and get all the context devices */
566 if (KGSL_IOMMU_MAX_UNITS < pdata_dev->iommu_count) {
567 KGSL_CORE_ERR("Too many IOMMU units defined\n");
568 ret = -EINVAL;
569 goto done;
570 }
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700571
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600572 for (i = 0; i < pdata_dev->iommu_count; i++) {
573 ret = _get_iommu_ctxs(mmu, &pdata_dev->iommu_data[i], i);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700574 if (ret)
575 break;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600576 }
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600577 iommu->unit_count = pdata_dev->iommu_count;
578done:
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700579 return ret;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600580}
581
Shubhraprakash Dase9eefd72012-05-01 01:44:59 -0600582/*
583 * kgsl_set_register_map - Map the IOMMU regsiters in the memory descriptors
584 * of the respective iommu units
585 * @mmu - Pointer to mmu structure
586 *
587 * Return - 0 on success else error code
588 */
589static int kgsl_set_register_map(struct kgsl_mmu *mmu)
590{
591 struct platform_device *pdev =
592 container_of(mmu->device->parentdev, struct platform_device,
593 dev);
594 struct kgsl_device_platform_data *pdata_dev = pdev->dev.platform_data;
595 struct kgsl_iommu *iommu = mmu->device->mmu.priv;
596 struct kgsl_iommu_unit *iommu_unit;
597 int i = 0, ret = 0;
598
599 for (; i < pdata_dev->iommu_count; i++) {
600 struct kgsl_device_iommu_data data = pdata_dev->iommu_data[i];
601 iommu_unit = &iommu->iommu_units[i];
602 /* set up the IOMMU register map for the given IOMMU unit */
603 if (!data.physstart || !data.physend) {
604 KGSL_CORE_ERR("The register range for IOMMU unit not"
605 " specified\n");
606 ret = -EINVAL;
607 goto err;
608 }
609 iommu_unit->reg_map.hostptr = ioremap(data.physstart,
610 data.physend - data.physstart + 1);
611 if (!iommu_unit->reg_map.hostptr) {
612 KGSL_CORE_ERR("Failed to map SMMU register address "
613 "space from %x to %x\n", data.physstart,
614 data.physend - data.physstart + 1);
615 ret = -ENOMEM;
616 i--;
617 goto err;
618 }
619 iommu_unit->reg_map.size = data.physend - data.physstart + 1;
620 iommu_unit->reg_map.physaddr = data.physstart;
Rajeev Kulkarni55863722012-11-21 23:40:05 -0800621 ret = memdesc_sg_phys(&iommu_unit->reg_map, data.physstart,
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600622 iommu_unit->reg_map.size);
Rajeev Kulkarni55863722012-11-21 23:40:05 -0800623 if (ret)
624 goto err;
Shubhraprakash Dase9eefd72012-05-01 01:44:59 -0600625 }
626 iommu->unit_count = pdata_dev->iommu_count;
627 return ret;
628err:
629 /* Unmap any mapped IOMMU regions */
630 for (; i >= 0; i--) {
631 iommu_unit = &iommu->iommu_units[i];
632 iounmap(iommu_unit->reg_map.hostptr);
633 iommu_unit->reg_map.size = 0;
634 iommu_unit->reg_map.physaddr = 0;
635 }
636 return ret;
637}
638
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600639/*
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700640 * kgsl_iommu_get_pt_base_addr - Get the address of the pagetable that the
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600641 * IOMMU ttbr0 register is programmed with
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700642 * @mmu - Pointer to mmu
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600643 * @pt - kgsl pagetable pointer that contains the IOMMU domain pointer
644 *
645 * Return - actual pagetable address that the ttbr0 register is programmed
646 * with
647 */
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700648static unsigned int kgsl_iommu_get_pt_base_addr(struct kgsl_mmu *mmu,
649 struct kgsl_pagetable *pt)
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600650{
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700651 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600652 struct kgsl_iommu_pt *iommu_pt = pt->priv;
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700653 return iommu_get_pt_base_addr(iommu_pt->domain) &
654 (iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
655 iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600656}
657
658/*
659 * kgsl_iommu_get_pt_lsb - Return the lsb of the ttbr0 IOMMU register
660 * @mmu - Pointer to mmu structure
661 * @hostptr - Pointer to the IOMMU register map. This is used to match
662 * the iommu device whose lsb value is to be returned
663 * @ctx_id - The context bank whose lsb valus is to be returned
664 * Return - returns the lsb which is the last 14 bits of the ttbr0 IOMMU
665 * register. ttbr0 is the actual PTBR for of the IOMMU. The last 14 bits
666 * are only programmed once in the beginning when a domain is attached
667 * does not change.
668 */
669static int kgsl_iommu_get_pt_lsb(struct kgsl_mmu *mmu,
670 unsigned int unit_id,
671 enum kgsl_iommu_context_id ctx_id)
672{
673 struct kgsl_iommu *iommu = mmu->priv;
674 int i, j;
675 for (i = 0; i < iommu->unit_count; i++) {
676 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
677 for (j = 0; j < iommu_unit->dev_count; j++)
678 if (unit_id == i &&
679 ctx_id == iommu_unit->dev[j].ctx_id)
680 return iommu_unit->dev[j].pt_lsb;
681 }
682 return 0;
683}
684
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600685static void kgsl_iommu_setstate(struct kgsl_mmu *mmu,
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600686 struct kgsl_pagetable *pagetable,
687 unsigned int context_id)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600688{
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600689 if (mmu->flags & KGSL_FLAGS_STARTED) {
690 /* page table not current, then setup mmu to use new
691 * specified page table
692 */
693 if (mmu->hwpagetable != pagetable) {
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600694 unsigned int flags = 0;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600695 mmu->hwpagetable = pagetable;
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600696 flags |= kgsl_mmu_pt_get_flags(mmu->hwpagetable,
Shubhraprakash Das8649fa52012-07-26 15:49:46 -0700697 mmu->device->id) |
698 KGSL_MMUFLAGS_TLBFLUSH;
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600699 kgsl_setstate(mmu, context_id,
700 KGSL_MMUFLAGS_PTUPDATE | flags);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600701 }
702 }
703}
704
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600705static int kgsl_iommu_init(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600706{
707 /*
708 * intialize device mmu
709 *
710 * call this with the global lock held
711 */
712 int status = 0;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600713 struct kgsl_iommu *iommu;
714
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600715 iommu = kzalloc(sizeof(struct kgsl_iommu), GFP_KERNEL);
716 if (!iommu) {
717 KGSL_CORE_ERR("kzalloc(%d) failed\n",
718 sizeof(struct kgsl_iommu));
719 return -ENOMEM;
720 }
721
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600722 mmu->priv = iommu;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600723 status = kgsl_get_iommu_ctxt(mmu);
724 if (status)
725 goto done;
Shubhraprakash Dase9eefd72012-05-01 01:44:59 -0600726 status = kgsl_set_register_map(mmu);
727 if (status)
728 goto done;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600729
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700730 iommu->iommu_reg_list = kgsl_iommuv1_reg;
731 iommu->ctx_offset = KGSL_IOMMU_CTX_OFFSET_V1;
732
Shubhraprakash Das15a8b462012-08-16 23:24:28 -0700733 if (msm_soc_version_supports_iommu_v1()) {
734 iommu->iommu_reg_list = kgsl_iommuv1_reg;
735 iommu->ctx_offset = KGSL_IOMMU_CTX_OFFSET_V1;
736 } else {
737 iommu->iommu_reg_list = kgsl_iommuv2_reg;
738 iommu->ctx_offset = KGSL_IOMMU_CTX_OFFSET_V2;
739 }
740
Shubhraprakash Dase9541a32012-05-09 22:25:55 -0600741 /* A nop is required in an indirect buffer when switching
742 * pagetables in-stream */
743 kgsl_sharedmem_writel(&mmu->setstate_memory,
744 KGSL_IOMMU_SETSTATE_NOP_OFFSET,
745 cp_nop_packet(1));
746
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600747 dev_info(mmu->device->dev, "|%s| MMU type set for device is IOMMU\n",
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600748 __func__);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600749done:
750 if (status) {
751 kfree(iommu);
752 mmu->priv = NULL;
753 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600754 return status;
755}
756
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600757/*
758 * kgsl_iommu_setup_defaultpagetable - Setup the initial defualtpagetable
759 * for iommu. This function is only called once during first start, successive
760 * start do not call this funciton.
761 * @mmu - Pointer to mmu structure
762 *
763 * Create the initial defaultpagetable and setup the iommu mappings to it
764 * Return - 0 on success else error code
765 */
766static int kgsl_iommu_setup_defaultpagetable(struct kgsl_mmu *mmu)
767{
768 int status = 0;
769 int i = 0;
770 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600771 struct kgsl_pagetable *pagetable = NULL;
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600772
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600773 /* If chip is not 8960 then we use the 2nd context bank for pagetable
774 * switching on the 3D side for which a separate table is allocated */
Shubhraprakash Das15a8b462012-08-16 23:24:28 -0700775 if (!cpu_is_msm8960() && msm_soc_version_supports_iommu_v1()) {
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600776 mmu->priv_bank_table =
777 kgsl_mmu_getpagetable(KGSL_MMU_PRIV_BANK_TABLE_NAME);
778 if (mmu->priv_bank_table == NULL) {
779 status = -ENOMEM;
780 goto err;
781 }
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600782 }
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600783 mmu->defaultpagetable = kgsl_mmu_getpagetable(KGSL_MMU_GLOBAL_PT);
784 /* Return error if the default pagetable doesn't exist */
785 if (mmu->defaultpagetable == NULL) {
786 status = -ENOMEM;
787 goto err;
788 }
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600789 pagetable = mmu->priv_bank_table ? mmu->priv_bank_table :
790 mmu->defaultpagetable;
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600791 /* Map the IOMMU regsiters to only defaultpagetable */
Shubhraprakash Das15a8b462012-08-16 23:24:28 -0700792 if (msm_soc_version_supports_iommu_v1()) {
793 for (i = 0; i < iommu->unit_count; i++) {
794 iommu->iommu_units[i].reg_map.priv |=
795 KGSL_MEMFLAGS_GLOBAL;
796 status = kgsl_mmu_map(pagetable,
797 &(iommu->iommu_units[i].reg_map),
798 GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
799 if (status) {
800 iommu->iommu_units[i].reg_map.priv &=
801 ~KGSL_MEMFLAGS_GLOBAL;
802 goto err;
803 }
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600804 }
805 }
806 return status;
807err:
808 for (i--; i >= 0; i--) {
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600809 kgsl_mmu_unmap(pagetable,
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600810 &(iommu->iommu_units[i].reg_map));
811 iommu->iommu_units[i].reg_map.priv &= ~KGSL_MEMFLAGS_GLOBAL;
812 }
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600813 if (mmu->priv_bank_table) {
814 kgsl_mmu_putpagetable(mmu->priv_bank_table);
815 mmu->priv_bank_table = NULL;
816 }
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600817 if (mmu->defaultpagetable) {
818 kgsl_mmu_putpagetable(mmu->defaultpagetable);
819 mmu->defaultpagetable = NULL;
820 }
821 return status;
822}
823
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600824static int kgsl_iommu_start(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600825{
826 int status;
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600827 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600828 int i, j;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600829
830 if (mmu->flags & KGSL_FLAGS_STARTED)
831 return 0;
832
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600833 if (mmu->defaultpagetable == NULL) {
834 status = kgsl_iommu_setup_defaultpagetable(mmu);
835 if (status)
836 return -ENOMEM;
837 }
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600838 /* We use the GPU MMU to control access to IOMMU registers on 8960 with
839 * a225, hence we still keep the MMU active on 8960 */
840 if (cpu_is_msm8960()) {
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -0600841 struct kgsl_mh *mh = &(mmu->device->mh);
842 kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000001);
843 kgsl_regwrite(mmu->device, MH_MMU_MPU_END,
844 mh->mpu_base +
Shubhraprakash Das2b54b5f2012-08-08 18:21:36 -0700845 iommu->iommu_units[0].reg_map.gpuaddr);
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -0600846 } else {
847 kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000000);
848 }
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600849
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600850 mmu->hwpagetable = mmu->defaultpagetable;
851
852 status = kgsl_attach_pagetable_iommu_domain(mmu);
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -0600853 if (status) {
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600854 mmu->hwpagetable = NULL;
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -0600855 goto done;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600856 }
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600857 status = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600858 if (status) {
859 KGSL_CORE_ERR("clk enable failed\n");
860 goto done;
861 }
862 status = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_PRIV);
863 if (status) {
864 KGSL_CORE_ERR("clk enable failed\n");
865 goto done;
866 }
867 /* Get the lsb value of pagetables set in the IOMMU ttbr0 register as
868 * that value should not change when we change pagetables, so while
869 * changing pagetables we can use this lsb value of the pagetable w/o
870 * having to read it again
871 */
872 for (i = 0; i < iommu->unit_count; i++) {
873 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
Shubhraprakash Das2747cf62012-09-27 23:05:43 -0700874 for (j = 0; j < iommu_unit->dev_count; j++) {
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700875 iommu_unit->dev[j].pt_lsb = KGSL_IOMMMU_PT_LSB(iommu,
876 KGSL_IOMMU_GET_CTX_REG(iommu,
877 iommu_unit,
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600878 iommu_unit->dev[j].ctx_id,
879 TTBR0));
Shubhraprakash Das2747cf62012-09-27 23:05:43 -0700880 }
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600881 }
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600882
Shubhraprakash Dascb068072012-06-07 17:52:41 -0600883 kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -0600884 mmu->flags |= KGSL_FLAGS_STARTED;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600885
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600886done:
887 if (status) {
Shubhraprakash Dascb068072012-06-07 17:52:41 -0600888 kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600889 kgsl_detach_pagetable_iommu_domain(mmu);
890 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600891 return status;
892}
893
894static int
895kgsl_iommu_unmap(void *mmu_specific_pt,
Shubhraprakash Das0c811262012-06-06 23:22:19 -0600896 struct kgsl_memdesc *memdesc,
897 unsigned int *tlb_flags)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600898{
899 int ret;
Jordan Crouse3c86ca82012-05-21 08:41:52 -0600900 unsigned int range = kgsl_sg_size(memdesc->sg, memdesc->sglen);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600901 struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600902
903 /* All GPU addresses as assigned are page aligned, but some
904 functions purturb the gpuaddr with an offset, so apply the
905 mask here to make sure we have the right address */
906
907 unsigned int gpuaddr = memdesc->gpuaddr & KGSL_MMU_ALIGN_MASK;
908
909 if (range == 0 || gpuaddr == 0)
910 return 0;
911
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600912 ret = iommu_unmap_range(iommu_pt->domain, gpuaddr, range);
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600913 if (ret)
914 KGSL_CORE_ERR("iommu_unmap_range(%p, %x, %d) failed "
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600915 "with err: %d\n", iommu_pt->domain, gpuaddr,
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600916 range, ret);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600917
Shubhraprakash Das0c811262012-06-06 23:22:19 -0600918#ifdef CONFIG_KGSL_PER_PROCESS_PAGE_TABLE
919 /*
920 * Flushing only required if per process pagetables are used. With
921 * global case, flushing will happen inside iommu_map function
922 */
Shubhraprakash Das15a8b462012-08-16 23:24:28 -0700923 if (!ret && msm_soc_version_supports_iommu_v1())
Shubhraprakash Das0c811262012-06-06 23:22:19 -0600924 *tlb_flags = UINT_MAX;
925#endif
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600926 return 0;
927}
928
929static int
930kgsl_iommu_map(void *mmu_specific_pt,
931 struct kgsl_memdesc *memdesc,
Shubhraprakash Dasf764e462012-04-26 15:38:09 -0600932 unsigned int protflags,
933 unsigned int *tlb_flags)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600934{
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600935 int ret;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600936 unsigned int iommu_virt_addr;
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600937 struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
Jordan Crouse3c86ca82012-05-21 08:41:52 -0600938 int size = kgsl_sg_size(memdesc->sg, memdesc->sglen);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600939
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600940 BUG_ON(NULL == iommu_pt);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600941
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600942
Jordan Croused17e9aa2011-10-12 16:57:48 -0600943 iommu_virt_addr = memdesc->gpuaddr;
944
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600945 ret = iommu_map_range(iommu_pt->domain, iommu_virt_addr, memdesc->sg,
Jordan Crouse3c86ca82012-05-21 08:41:52 -0600946 size, (IOMMU_READ | IOMMU_WRITE));
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600947 if (ret) {
948 KGSL_CORE_ERR("iommu_map_range(%p, %x, %p, %d, %d) "
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600949 "failed with err: %d\n", iommu_pt->domain,
Jordan Crouse3c86ca82012-05-21 08:41:52 -0600950 iommu_virt_addr, memdesc->sg, size,
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600951 (IOMMU_READ | IOMMU_WRITE), ret);
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600952 return ret;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600953 }
954
955 return ret;
956}
957
Shubhraprakash Das79447952012-04-26 18:12:23 -0600958static void kgsl_iommu_stop(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600959{
Shubhraprakash Dascb068072012-06-07 17:52:41 -0600960 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Das2747cf62012-09-27 23:05:43 -0700961 int i, j;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600962 /*
963 * stop device mmu
964 *
965 * call this with the global lock held
966 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600967
968 if (mmu->flags & KGSL_FLAGS_STARTED) {
969 /* detach iommu attachment */
970 kgsl_detach_pagetable_iommu_domain(mmu);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600971 mmu->hwpagetable = NULL;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600972
973 mmu->flags &= ~KGSL_FLAGS_STARTED;
Shubhraprakash Dascb068072012-06-07 17:52:41 -0600974
Shubhraprakash Das2747cf62012-09-27 23:05:43 -0700975 if (mmu->fault) {
976 for (i = 0; i < iommu->unit_count; i++) {
977 struct kgsl_iommu_unit *iommu_unit =
978 &iommu->iommu_units[i];
979 for (j = 0; j < iommu_unit->dev_count; j++) {
980 if (iommu_unit->dev[j].fault) {
981 kgsl_iommu_enable_clk(mmu, j);
982 KGSL_IOMMU_SET_CTX_REG(iommu,
983 iommu_unit,
984 iommu_unit->dev[j].ctx_id,
985 RESUME, 1);
986 iommu_unit->dev[j].fault = 0;
987 }
988 }
989 }
990 mmu->fault = 0;
991 }
992 }
Shubhraprakash Dascb068072012-06-07 17:52:41 -0600993 /* switch off MMU clocks and cancel any events it has queued */
994 iommu->clk_event_queued = false;
995 kgsl_cancel_events(mmu->device, mmu);
996 kgsl_iommu_disable_clk(mmu);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600997}
998
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600999static int kgsl_iommu_close(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001000{
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -06001001 struct kgsl_iommu *iommu = mmu->priv;
1002 int i;
1003 for (i = 0; i < iommu->unit_count; i++) {
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -06001004 struct kgsl_pagetable *pagetable = (mmu->priv_bank_table ?
1005 mmu->priv_bank_table : mmu->defaultpagetable);
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -06001006 if (iommu->iommu_units[i].reg_map.gpuaddr)
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -06001007 kgsl_mmu_unmap(pagetable,
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -06001008 &(iommu->iommu_units[i].reg_map));
1009 if (iommu->iommu_units[i].reg_map.hostptr)
1010 iounmap(iommu->iommu_units[i].reg_map.hostptr);
1011 kgsl_sg_free(iommu->iommu_units[i].reg_map.sg,
1012 iommu->iommu_units[i].reg_map.sglen);
1013 }
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -06001014
1015 if (mmu->priv_bank_table)
1016 kgsl_mmu_putpagetable(mmu->priv_bank_table);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001017 if (mmu->defaultpagetable)
1018 kgsl_mmu_putpagetable(mmu->defaultpagetable);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -06001019 kfree(iommu);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001020
1021 return 0;
1022}
1023
1024static unsigned int
Shubhraprakash Das1c528262012-04-26 17:38:13 -06001025kgsl_iommu_get_current_ptbase(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001026{
Shubhraprakash Das2b8716b2012-05-04 16:58:40 -06001027 unsigned int pt_base;
1028 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Das64a745c2012-06-11 16:44:16 -06001029 /* We cannot enable or disable the clocks in interrupt context, this
1030 function is called from interrupt context if there is an axi error */
1031 if (in_interrupt())
1032 return 0;
Shubhraprakash Das2b8716b2012-05-04 16:58:40 -06001033 /* Return the current pt base by reading IOMMU pt_base register */
1034 kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001035 pt_base = KGSL_IOMMU_GET_CTX_REG(iommu, (&iommu->iommu_units[0]),
1036 KGSL_IOMMU_CONTEXT_USER,
1037 TTBR0);
Shubhraprakash Dascb068072012-06-07 17:52:41 -06001038 kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001039 return pt_base &
1040 (iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
1041 iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001042}
1043
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -06001044/*
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001045 * kgsl_iommu_default_setstate - Change the IOMMU pagetable or flush IOMMU tlb
1046 * of the primary context bank
1047 * @mmu - Pointer to mmu structure
1048 * @flags - Flags indicating whether pagetable has to chnage or tlb is to be
1049 * flushed or both
1050 *
1051 * Based on flags set the new pagetable fo the IOMMU unit or flush it's tlb or
1052 * do both by doing direct register writes to the IOMMu registers through the
1053 * cpu
1054 * Return - void
1055 */
1056static void kgsl_iommu_default_setstate(struct kgsl_mmu *mmu,
1057 uint32_t flags)
1058{
1059 struct kgsl_iommu *iommu = mmu->priv;
1060 int temp;
1061 int i;
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001062 unsigned int pt_base = kgsl_iommu_get_pt_base_addr(mmu,
1063 mmu->hwpagetable);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001064 unsigned int pt_val;
1065
1066 if (kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER)) {
1067 KGSL_DRV_ERR(mmu->device, "Failed to enable iommu clocks\n");
1068 return;
1069 }
1070 /* Mask off the lsb of the pt base address since lsb will not change */
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001071 pt_base &= (iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
1072 iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
1073
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001074 if (flags & KGSL_MMUFLAGS_PTUPDATE) {
Jordan Crousea29a2e02012-08-14 09:09:23 -06001075 kgsl_idle(mmu->device);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001076 for (i = 0; i < iommu->unit_count; i++) {
1077 /* get the lsb value which should not change when
1078 * changing ttbr0 */
1079 pt_val = kgsl_iommu_get_pt_lsb(mmu, i,
1080 KGSL_IOMMU_CONTEXT_USER);
1081 pt_val += pt_base;
1082
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001083 KGSL_IOMMU_SET_CTX_REG(iommu, (&iommu->iommu_units[i]),
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001084 KGSL_IOMMU_CONTEXT_USER, TTBR0, pt_val);
1085
1086 mb();
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001087 temp = KGSL_IOMMU_GET_CTX_REG(iommu,
1088 (&iommu->iommu_units[i]),
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001089 KGSL_IOMMU_CONTEXT_USER, TTBR0);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001090 }
1091 }
1092 /* Flush tlb */
1093 if (flags & KGSL_MMUFLAGS_TLBFLUSH) {
1094 for (i = 0; i < iommu->unit_count; i++) {
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001095 KGSL_IOMMU_SET_CTX_REG(iommu, (&iommu->iommu_units[i]),
1096 KGSL_IOMMU_CONTEXT_USER, TLBIALL, 1);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001097 mb();
1098 }
1099 }
1100 /* Disable smmu clock */
Shubhraprakash Dascb068072012-06-07 17:52:41 -06001101 kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001102}
1103
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001104/*
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001105 * kgsl_iommu_get_reg_gpuaddr - Returns the gpu address of IOMMU regsiter
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001106 * @mmu - Pointer to mmu structure
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001107 * @iommu_unit - The iommu unit for which base address is requested
1108 * @ctx_id - The context ID of the IOMMU ctx
1109 * @reg - The register for which address is required
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001110 *
1111 * Return - The number of iommu units which is also the number of register
1112 * mapped descriptor arrays which the out parameter will have
1113 */
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001114static unsigned int kgsl_iommu_get_reg_gpuaddr(struct kgsl_mmu *mmu,
1115 int iommu_unit, int ctx_id, int reg)
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001116{
1117 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001118
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001119 if (KGSL_IOMMU_GLOBAL_BASE == reg)
1120 return iommu->iommu_units[iommu_unit].reg_map.gpuaddr;
1121 else
1122 return iommu->iommu_units[iommu_unit].reg_map.gpuaddr +
1123 iommu->iommu_reg_list[reg].reg_offset +
1124 (ctx_id << KGSL_IOMMU_CTX_SHIFT) + iommu->ctx_offset;
1125}
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001126
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001127static int kgsl_iommu_get_num_iommu_units(struct kgsl_mmu *mmu)
1128{
1129 struct kgsl_iommu *iommu = mmu->priv;
1130 return iommu->unit_count;
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001131}
1132
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001133struct kgsl_mmu_ops iommu_ops = {
1134 .mmu_init = kgsl_iommu_init,
1135 .mmu_close = kgsl_iommu_close,
1136 .mmu_start = kgsl_iommu_start,
1137 .mmu_stop = kgsl_iommu_stop,
1138 .mmu_setstate = kgsl_iommu_setstate,
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001139 .mmu_device_setstate = kgsl_iommu_default_setstate,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001140 .mmu_pagefault = NULL,
1141 .mmu_get_current_ptbase = kgsl_iommu_get_current_ptbase,
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -06001142 .mmu_enable_clk = kgsl_iommu_enable_clk,
Shubhraprakash Dascb068072012-06-07 17:52:41 -06001143 .mmu_disable_clk_on_ts = kgsl_iommu_disable_clk_on_ts,
Shubhraprakash Dasfce27362012-05-09 17:44:14 -06001144 .mmu_get_pt_lsb = kgsl_iommu_get_pt_lsb,
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001145 .mmu_get_reg_gpuaddr = kgsl_iommu_get_reg_gpuaddr,
1146 .mmu_get_num_iommu_units = kgsl_iommu_get_num_iommu_units,
1147 .mmu_pt_equal = kgsl_iommu_pt_equal,
1148 .mmu_get_pt_base_addr = kgsl_iommu_get_pt_base_addr,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001149};
1150
1151struct kgsl_mmu_pt_ops iommu_pt_ops = {
1152 .mmu_map = kgsl_iommu_map,
1153 .mmu_unmap = kgsl_iommu_unmap,
1154 .mmu_create_pagetable = kgsl_iommu_create_pagetable,
1155 .mmu_destroy_pagetable = kgsl_iommu_destroy_pagetable,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001156};