blob: bf40c04c34878a963e47659eeabc88fd3ff54bc9 [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>
Tarun Karra9c070822012-11-27 16:43:51 -070021#include <mach/msm_iomap.h>
22#include <mach/board.h>
23#include <stddef.h>
Shubhraprakash Das767fdda2011-08-15 15:49:45 -060024
25#include "kgsl.h"
26#include "kgsl_device.h"
27#include "kgsl_mmu.h"
28#include "kgsl_sharedmem.h"
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -060029#include "kgsl_iommu.h"
Shubhraprakash Dase9541a32012-05-09 22:25:55 -060030#include "adreno_pm4types.h"
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -060031#include "adreno.h"
Jordan Crouse95b68472012-05-25 10:25:01 -060032#include "kgsl_trace.h"
Tarun Karra9c070822012-11-27 16:43:51 -070033#include "z180.h"
34
Jordan Crouse95b68472012-05-25 10:25:01 -060035
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -070036static struct kgsl_iommu_register_list kgsl_iommuv1_reg[KGSL_IOMMU_REG_MAX] = {
37 { 0, 0, 0 }, /* GLOBAL_BASE */
38 { 0x10, 0x0003FFFF, 14 }, /* TTBR0 */
39 { 0x14, 0x0003FFFF, 14 }, /* TTBR1 */
40 { 0x20, 0, 0 }, /* FSR */
41 { 0x800, 0, 0 }, /* TLBIALL */
Shubhraprakash Das2747cf62012-09-27 23:05:43 -070042 { 0x820, 0, 0 }, /* RESUME */
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -070043};
44
Shubhraprakash Das15a8b462012-08-16 23:24:28 -070045static struct kgsl_iommu_register_list kgsl_iommuv2_reg[KGSL_IOMMU_REG_MAX] = {
46 { 0, 0, 0 }, /* GLOBAL_BASE */
47 { 0x20, 0x00FFFFFF, 14 }, /* TTBR0 */
48 { 0x28, 0x00FFFFFF, 14 }, /* TTBR1 */
49 { 0x58, 0, 0 }, /* FSR */
Shubhraprakash Das2747cf62012-09-27 23:05:43 -070050 { 0x618, 0, 0 }, /* TLBIALL */
51 { 0x008, 0, 0 } /* RESUME */
Shubhraprakash Das15a8b462012-08-16 23:24:28 -070052};
53
Tarun Karra9c070822012-11-27 16:43:51 -070054struct remote_iommu_petersons_spinlock kgsl_iommu_sync_lock_vars;
55
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -070056static int get_iommu_unit(struct device *dev, struct kgsl_mmu **mmu_out,
57 struct kgsl_iommu_unit **iommu_unit_out)
Jordan Crouse95b68472012-05-25 10:25:01 -060058{
59 int i, j, k;
60
61 for (i = 0; i < KGSL_DEVICE_MAX; i++) {
62 struct kgsl_mmu *mmu;
63 struct kgsl_iommu *iommu;
64
65 if (kgsl_driver.devp[i] == NULL)
66 continue;
67
68 mmu = kgsl_get_mmu(kgsl_driver.devp[i]);
69 if (mmu == NULL || mmu->priv == NULL)
70 continue;
71
72 iommu = mmu->priv;
73
74 for (j = 0; j < iommu->unit_count; j++) {
75 struct kgsl_iommu_unit *iommu_unit =
76 &iommu->iommu_units[j];
77 for (k = 0; k < iommu_unit->dev_count; k++) {
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -070078 if (iommu_unit->dev[k].dev == dev) {
79 *mmu_out = mmu;
80 *iommu_unit_out = iommu_unit;
81 return 0;
82 }
Jordan Crouse95b68472012-05-25 10:25:01 -060083 }
84 }
85 }
86
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -070087 return -EINVAL;
Jordan Crouse95b68472012-05-25 10:25:01 -060088}
89
90static struct kgsl_iommu_device *get_iommu_device(struct kgsl_iommu_unit *unit,
91 struct device *dev)
92{
93 int k;
94
95 for (k = 0; unit && k < unit->dev_count; k++) {
96 if (unit->dev[k].dev == dev)
97 return &(unit->dev[k]);
98 }
99
100 return NULL;
101}
102
103static int kgsl_iommu_fault_handler(struct iommu_domain *domain,
104 struct device *dev, unsigned long addr, int flags)
105{
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700106 int ret = 0;
107 struct kgsl_mmu *mmu;
108 struct kgsl_iommu *iommu;
109 struct kgsl_iommu_unit *iommu_unit;
110 struct kgsl_iommu_device *iommu_dev;
Jordan Crouse95b68472012-05-25 10:25:01 -0600111 unsigned int ptbase, fsr;
112
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700113 ret = get_iommu_unit(dev, &mmu, &iommu_unit);
114 if (ret)
115 goto done;
116 iommu_dev = get_iommu_device(iommu_unit, dev);
Jordan Crouse95b68472012-05-25 10:25:01 -0600117 if (!iommu_dev) {
118 KGSL_CORE_ERR("Invalid IOMMU device %p\n", dev);
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700119 ret = -ENOSYS;
120 goto done;
Jordan Crouse95b68472012-05-25 10:25:01 -0600121 }
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700122 iommu = mmu->priv;
Jordan Crouse95b68472012-05-25 10:25:01 -0600123
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700124 ptbase = KGSL_IOMMU_GET_CTX_REG(iommu, iommu_unit,
Shubhraprakash Das190553a2012-06-11 15:17:59 -0600125 iommu_dev->ctx_id, TTBR0);
Jordan Crouse95b68472012-05-25 10:25:01 -0600126
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700127 fsr = KGSL_IOMMU_GET_CTX_REG(iommu, iommu_unit,
Jordan Crouse95b68472012-05-25 10:25:01 -0600128 iommu_dev->ctx_id, FSR);
129
130 KGSL_MEM_CRIT(iommu_dev->kgsldev,
131 "GPU PAGE FAULT: addr = %lX pid = %d\n",
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700132 addr, kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase));
Jordan Crouse95b68472012-05-25 10:25:01 -0600133 KGSL_MEM_CRIT(iommu_dev->kgsldev, "context = %d FSR = %X\n",
134 iommu_dev->ctx_id, fsr);
135
Shubhraprakash Das2747cf62012-09-27 23:05:43 -0700136 mmu->fault = 1;
137 iommu_dev->fault = 1;
138
Jordan Crouse95b68472012-05-25 10:25:01 -0600139 trace_kgsl_mmu_pagefault(iommu_dev->kgsldev, addr,
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700140 kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase), 0);
Jordan Crouse95b68472012-05-25 10:25:01 -0600141
Shubhraprakash Das2747cf62012-09-27 23:05:43 -0700142 /*
143 * We do not want the h/w to resume fetching data from an iommu unit
144 * that has faulted, this is better for debugging as it will stall
145 * the GPU and trigger a snapshot. To stall the transaction return
146 * EBUSY error.
147 */
148 ret = -EBUSY;
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700149done:
150 return ret;
Jordan Crouse95b68472012-05-25 10:25:01 -0600151}
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600152
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -0600153/*
154 * kgsl_iommu_disable_clk - Disable iommu clocks
155 * @mmu - Pointer to mmu structure
156 *
157 * Disables iommu clocks
158 * Return - void
159 */
160static void kgsl_iommu_disable_clk(struct kgsl_mmu *mmu)
161{
162 struct kgsl_iommu *iommu = mmu->priv;
163 struct msm_iommu_drvdata *iommu_drvdata;
164 int i, j;
165
166 for (i = 0; i < iommu->unit_count; i++) {
167 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
168 for (j = 0; j < iommu_unit->dev_count; j++) {
169 if (!iommu_unit->dev[j].clk_enabled)
170 continue;
171 iommu_drvdata = dev_get_drvdata(
172 iommu_unit->dev[j].dev->parent);
Shubhraprakash Das102aac52012-08-16 22:12:27 -0700173 if (iommu_drvdata->aclk)
174 clk_disable_unprepare(iommu_drvdata->aclk);
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -0600175 if (iommu_drvdata->clk)
176 clk_disable_unprepare(iommu_drvdata->clk);
177 clk_disable_unprepare(iommu_drvdata->pclk);
178 iommu_unit->dev[j].clk_enabled = false;
179 }
180 }
181}
182
183/*
Shubhraprakash Dascb068072012-06-07 17:52:41 -0600184 * kgsl_iommu_disable_clk_event - An event function that is executed when
185 * the required timestamp is reached. It disables the IOMMU clocks if
186 * the timestamp on which the clocks can be disabled has expired.
187 * @device - The kgsl device pointer
188 * @data - The data passed during event creation, it is the MMU pointer
189 * @id - Context ID, should always be KGSL_MEMSTORE_GLOBAL
190 * @ts - The current timestamp that has expired for the device
191 *
192 * Disables IOMMU clocks if timestamp has expired
193 * Return - void
194 */
195static void kgsl_iommu_clk_disable_event(struct kgsl_device *device, void *data,
196 unsigned int id, unsigned int ts)
197{
198 struct kgsl_mmu *mmu = data;
199 struct kgsl_iommu *iommu = mmu->priv;
200
201 if (!iommu->clk_event_queued) {
202 if (0 > timestamp_cmp(ts, iommu->iommu_last_cmd_ts))
203 KGSL_DRV_ERR(device,
204 "IOMMU disable clock event being cancelled, "
205 "iommu_last_cmd_ts: %x, retired ts: %x\n",
206 iommu->iommu_last_cmd_ts, ts);
207 return;
208 }
209
210 if (0 <= timestamp_cmp(ts, iommu->iommu_last_cmd_ts)) {
211 kgsl_iommu_disable_clk(mmu);
212 iommu->clk_event_queued = false;
213 } else {
214 /* add new event to fire when ts is reached, this can happen
215 * if we queued an event and someone requested the clocks to
216 * be disbaled on a later timestamp */
217 if (kgsl_add_event(device, id, iommu->iommu_last_cmd_ts,
218 kgsl_iommu_clk_disable_event, mmu, mmu)) {
219 KGSL_DRV_ERR(device,
220 "Failed to add IOMMU disable clk event\n");
221 iommu->clk_event_queued = false;
222 }
223 }
224}
225
226/*
227 * kgsl_iommu_disable_clk_on_ts - Sets up event to disable IOMMU clocks
228 * @mmu - The kgsl MMU pointer
229 * @ts - Timestamp on which the clocks should be disabled
230 * @ts_valid - Indicates whether ts parameter is valid, if this parameter
231 * is false then it means that the calling function wants to disable the
232 * IOMMU clocks immediately without waiting for any timestamp
233 *
234 * Creates an event to disable the IOMMU clocks on timestamp and if event
235 * already exists then updates the timestamp of disabling the IOMMU clocks
236 * with the passed in ts if it is greater than the current value at which
237 * the clocks will be disabled
238 * Return - void
239 */
240static void
241kgsl_iommu_disable_clk_on_ts(struct kgsl_mmu *mmu, unsigned int ts,
242 bool ts_valid)
243{
244 struct kgsl_iommu *iommu = mmu->priv;
245
246 if (iommu->clk_event_queued) {
247 if (ts_valid && (0 <
248 timestamp_cmp(ts, iommu->iommu_last_cmd_ts)))
249 iommu->iommu_last_cmd_ts = ts;
250 } else {
251 if (ts_valid) {
252 iommu->iommu_last_cmd_ts = ts;
253 iommu->clk_event_queued = true;
254 if (kgsl_add_event(mmu->device, KGSL_MEMSTORE_GLOBAL,
255 ts, kgsl_iommu_clk_disable_event, mmu, mmu)) {
256 KGSL_DRV_ERR(mmu->device,
257 "Failed to add IOMMU disable clk event\n");
258 iommu->clk_event_queued = false;
259 }
260 } else {
261 kgsl_iommu_disable_clk(mmu);
262 }
263 }
264}
265
266/*
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -0600267 * kgsl_iommu_enable_clk - Enable iommu clocks
268 * @mmu - Pointer to mmu structure
269 * @ctx_id - The context bank whose clocks are to be turned on
270 *
271 * Enables iommu clocks of a given context
272 * Return: 0 on success else error code
273 */
274static int kgsl_iommu_enable_clk(struct kgsl_mmu *mmu,
275 int ctx_id)
276{
277 int ret = 0;
278 int i, j;
279 struct kgsl_iommu *iommu = mmu->priv;
280 struct msm_iommu_drvdata *iommu_drvdata;
281
282 for (i = 0; i < iommu->unit_count; i++) {
283 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
284 for (j = 0; j < iommu_unit->dev_count; j++) {
285 if (iommu_unit->dev[j].clk_enabled ||
286 ctx_id != iommu_unit->dev[j].ctx_id)
287 continue;
288 iommu_drvdata =
289 dev_get_drvdata(iommu_unit->dev[j].dev->parent);
290 ret = clk_prepare_enable(iommu_drvdata->pclk);
291 if (ret)
292 goto done;
293 if (iommu_drvdata->clk) {
294 ret = clk_prepare_enable(iommu_drvdata->clk);
295 if (ret) {
296 clk_disable_unprepare(
297 iommu_drvdata->pclk);
298 goto done;
299 }
300 }
Shubhraprakash Das102aac52012-08-16 22:12:27 -0700301 if (iommu_drvdata->aclk) {
302 ret = clk_prepare_enable(iommu_drvdata->aclk);
303 if (ret) {
304 if (iommu_drvdata->clk)
305 clk_disable_unprepare(
306 iommu_drvdata->clk);
307 clk_disable_unprepare(
308 iommu_drvdata->pclk);
309 goto done;
310 }
311 }
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -0600312 iommu_unit->dev[j].clk_enabled = true;
313 }
314 }
315done:
316 if (ret)
317 kgsl_iommu_disable_clk(mmu);
318 return ret;
319}
320
Shubhraprakash Das48d97302012-05-07 12:16:08 -0600321/*
322 * kgsl_iommu_pt_equal - Check if pagetables are equal
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700323 * @mmu - Pointer to mmu structure
Shubhraprakash Das48d97302012-05-07 12:16:08 -0600324 * @pt - Pointer to pagetable
325 * @pt_base - Address of a pagetable that the IOMMU register is
326 * programmed with
327 *
328 * Checks whether the pt_base is equal to the base address of
329 * the pagetable which is contained in the pt structure
330 * Return - Non-zero if the pagetable addresses are equal else 0
331 */
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700332static int kgsl_iommu_pt_equal(struct kgsl_mmu *mmu,
333 struct kgsl_pagetable *pt,
334 unsigned int pt_base)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600335{
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700336 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600337 struct kgsl_iommu_pt *iommu_pt = pt ? pt->priv : NULL;
338 unsigned int domain_ptbase = iommu_pt ?
339 iommu_get_pt_base_addr(iommu_pt->domain) : 0;
Shubhraprakash Das48d97302012-05-07 12:16:08 -0600340 /* Only compare the valid address bits of the pt_base */
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700341 domain_ptbase &=
342 (iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
343 iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
344
345 pt_base &=
346 (iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
347 iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
348
Shubhraprakash Das48d97302012-05-07 12:16:08 -0600349 return domain_ptbase && pt_base &&
350 (domain_ptbase == pt_base);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600351}
352
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600353/*
354 * kgsl_iommu_destroy_pagetable - Free up reaources help by a pagetable
355 * @mmu_specific_pt - Pointer to pagetable which is to be freed
356 *
357 * Return - void
358 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600359static void kgsl_iommu_destroy_pagetable(void *mmu_specific_pt)
360{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600361 struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
362 if (iommu_pt->domain)
363 iommu_domain_free(iommu_pt->domain);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600364 kfree(iommu_pt);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600365}
366
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600367/*
368 * kgsl_iommu_create_pagetable - Create a IOMMU pagetable
369 *
370 * Allocate memory to hold a pagetable and allocate the IOMMU
371 * domain which is the actual IOMMU pagetable
372 * Return - void
373 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600374void *kgsl_iommu_create_pagetable(void)
375{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600376 struct kgsl_iommu_pt *iommu_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600377
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600378 iommu_pt = kzalloc(sizeof(struct kgsl_iommu_pt), GFP_KERNEL);
379 if (!iommu_pt) {
380 KGSL_CORE_ERR("kzalloc(%d) failed\n",
381 sizeof(struct kgsl_iommu_pt));
382 return NULL;
383 }
Shubhraprakash Das15a8b462012-08-16 23:24:28 -0700384 /* L2 redirect is not stable on IOMMU v2 */
385 if (msm_soc_version_supports_iommu_v1())
386 iommu_pt->domain = iommu_domain_alloc(&platform_bus_type,
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700387 MSM_IOMMU_DOMAIN_PT_CACHEABLE);
Shubhraprakash Das15a8b462012-08-16 23:24:28 -0700388 else
389 iommu_pt->domain = iommu_domain_alloc(&platform_bus_type,
390 0);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600391 if (!iommu_pt->domain) {
392 KGSL_CORE_ERR("Failed to create iommu domain\n");
393 kfree(iommu_pt);
394 return NULL;
Jordan Crouse95b68472012-05-25 10:25:01 -0600395 } else {
396 iommu_set_fault_handler(iommu_pt->domain,
397 kgsl_iommu_fault_handler);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600398 }
Jordan Crouse95b68472012-05-25 10:25:01 -0600399
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600400 return iommu_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600401}
402
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600403/*
404 * kgsl_detach_pagetable_iommu_domain - Detach the IOMMU unit from a
405 * pagetable
406 * @mmu - Pointer to the device mmu structure
407 * @priv - Flag indicating whether the private or user context is to be
408 * detached
409 *
410 * Detach the IOMMU unit with the domain that is contained in the
411 * hwpagetable of the given mmu. After detaching the IOMMU unit is not
412 * in use because the PTBR will not be set after a detach
413 * Return - void
414 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600415static void kgsl_detach_pagetable_iommu_domain(struct kgsl_mmu *mmu)
416{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600417 struct kgsl_iommu_pt *iommu_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600418 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600419 int i, j;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600420
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600421 for (i = 0; i < iommu->unit_count; i++) {
422 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600423 iommu_pt = mmu->defaultpagetable->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600424 for (j = 0; j < iommu_unit->dev_count; j++) {
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600425 /*
426 * If there is a 2nd default pagetable then priv domain
427 * is attached with this pagetable
428 */
429 if (mmu->priv_bank_table &&
430 (KGSL_IOMMU_CONTEXT_PRIV == j))
431 iommu_pt = mmu->priv_bank_table->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600432 if (iommu_unit->dev[j].attached) {
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600433 iommu_detach_device(iommu_pt->domain,
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600434 iommu_unit->dev[j].dev);
435 iommu_unit->dev[j].attached = false;
436 KGSL_MEM_INFO(mmu->device, "iommu %p detached "
437 "from user dev of MMU: %p\n",
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600438 iommu_pt->domain, mmu);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600439 }
440 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600441 }
442}
443
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600444/*
445 * kgsl_attach_pagetable_iommu_domain - Attach the IOMMU unit to a
446 * pagetable, i.e set the IOMMU's PTBR to the pagetable address and
447 * setup other IOMMU registers for the device so that it becomes
448 * active
449 * @mmu - Pointer to the device mmu structure
450 * @priv - Flag indicating whether the private or user context is to be
451 * attached
452 *
453 * Attach the IOMMU unit with the domain that is contained in the
454 * hwpagetable of the given mmu.
455 * Return - 0 on success else error code
456 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600457static int kgsl_attach_pagetable_iommu_domain(struct kgsl_mmu *mmu)
458{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600459 struct kgsl_iommu_pt *iommu_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600460 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600461 int i, j, ret = 0;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600462
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600463 /*
464 * Loop through all the iommu devcies under all iommu units and
465 * attach the domain
466 */
467 for (i = 0; i < iommu->unit_count; i++) {
468 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600469 iommu_pt = mmu->defaultpagetable->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600470 for (j = 0; j < iommu_unit->dev_count; j++) {
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600471 /*
472 * If there is a 2nd default pagetable then priv domain
473 * is attached to this pagetable
474 */
475 if (mmu->priv_bank_table &&
476 (KGSL_IOMMU_CONTEXT_PRIV == j))
477 iommu_pt = mmu->priv_bank_table->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600478 if (!iommu_unit->dev[j].attached) {
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600479 ret = iommu_attach_device(iommu_pt->domain,
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600480 iommu_unit->dev[j].dev);
481 if (ret) {
482 KGSL_MEM_ERR(mmu->device,
483 "Failed to attach device, err %d\n",
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700484 ret);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600485 goto done;
486 }
487 iommu_unit->dev[j].attached = true;
488 KGSL_MEM_INFO(mmu->device,
489 "iommu pt %p attached to dev %p, ctx_id %d\n",
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600490 iommu_pt->domain, iommu_unit->dev[j].dev,
491 iommu_unit->dev[j].ctx_id);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700492 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600493 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600494 }
495done:
496 return ret;
497}
498
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600499/*
500 * _get_iommu_ctxs - Get device pointer to IOMMU contexts
501 * @mmu - Pointer to mmu device
502 * data - Pointer to the platform data containing information about
503 * iommu devices for one iommu unit
504 * unit_id - The IOMMU unit number. This is not a specific ID but just
505 * a serial number. The serial numbers are treated as ID's of the
506 * IOMMU units
507 *
508 * Return - 0 on success else error code
509 */
510static int _get_iommu_ctxs(struct kgsl_mmu *mmu,
511 struct kgsl_device_iommu_data *data, unsigned int unit_id)
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700512{
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600513 struct kgsl_iommu *iommu = mmu->priv;
514 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[unit_id];
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700515 int i;
516
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600517 if (data->iommu_ctx_count > KGSL_IOMMU_MAX_DEVS_PER_UNIT) {
518 KGSL_CORE_ERR("Too many iommu devices defined for an "
519 "IOMMU unit\n");
520 return -EINVAL;
521 }
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700522
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600523 for (i = 0; i < data->iommu_ctx_count; i++) {
524 if (!data->iommu_ctxs[i].iommu_ctx_name)
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700525 continue;
526
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600527 iommu_unit->dev[iommu_unit->dev_count].dev =
528 msm_iommu_get_ctx(data->iommu_ctxs[i].iommu_ctx_name);
529 if (iommu_unit->dev[iommu_unit->dev_count].dev == NULL) {
530 KGSL_CORE_ERR("Failed to get iommu dev handle for "
531 "device %s\n", data->iommu_ctxs[i].iommu_ctx_name);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700532 return -EINVAL;
533 }
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600534 if (KGSL_IOMMU_CONTEXT_USER != data->iommu_ctxs[i].ctx_id &&
535 KGSL_IOMMU_CONTEXT_PRIV != data->iommu_ctxs[i].ctx_id) {
536 KGSL_CORE_ERR("Invalid context ID defined: %d\n",
537 data->iommu_ctxs[i].ctx_id);
538 return -EINVAL;
539 }
540 iommu_unit->dev[iommu_unit->dev_count].ctx_id =
541 data->iommu_ctxs[i].ctx_id;
Jordan Crouse95b68472012-05-25 10:25:01 -0600542 iommu_unit->dev[iommu_unit->dev_count].kgsldev = mmu->device;
543
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600544 KGSL_DRV_INFO(mmu->device,
545 "Obtained dev handle %p for iommu context %s\n",
546 iommu_unit->dev[iommu_unit->dev_count].dev,
547 data->iommu_ctxs[i].iommu_ctx_name);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700548
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600549 iommu_unit->dev_count++;
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700550 }
551
552 return 0;
553}
554
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600555/*
Tarun Karra9c070822012-11-27 16:43:51 -0700556 * kgsl_get_sync_lock - Init Sync Lock between GPU and CPU
557 * @mmu - Pointer to mmu device
558 *
559 * Return - 0 on success else error code
560 */
561static int kgsl_iommu_init_sync_lock(struct kgsl_mmu *mmu)
562{
563 struct kgsl_iommu *iommu = mmu->device->mmu.priv;
564 int status = 0;
565 struct kgsl_pagetable *pagetable = NULL;
566 uint32_t lock_gpu_addr = 0;
567 uint32_t lock_phy_addr = 0;
568 uint32_t page_offset = 0;
569
570 iommu->sync_lock_initialized = 0;
571
572 if (!(mmu->flags & KGSL_MMU_FLAGS_IOMMU_SYNC)) {
573 KGSL_DRV_ERR(mmu->device,
574 "The GPU microcode does not support IOMMUv1 sync opcodes\n");
575 return -ENXIO;
576 }
577
578 /* Get the physical address of the Lock variables */
579 lock_phy_addr = (msm_iommu_lock_initialize()
580 - MSM_SHARED_RAM_BASE + msm_shared_ram_phys);
581
582 if (!lock_phy_addr) {
583 KGSL_DRV_ERR(mmu->device,
584 "GPU CPU sync lock is not supported by kernel\n");
585 return -ENXIO;
586 }
587
588 /* Align the physical address to PAGE boundary and store the offset */
589 page_offset = (lock_phy_addr & (PAGE_SIZE - 1));
590 lock_phy_addr = (lock_phy_addr & ~(PAGE_SIZE - 1));
591 iommu->sync_lock_desc.physaddr = (unsigned int)lock_phy_addr;
592
593 iommu->sync_lock_desc.size =
594 PAGE_ALIGN(sizeof(kgsl_iommu_sync_lock_vars));
595 status = memdesc_sg_phys(&iommu->sync_lock_desc,
596 iommu->sync_lock_desc.physaddr,
597 iommu->sync_lock_desc.size);
598
599 if (status)
600 return status;
601
602 /* Map Lock variables to GPU pagetable */
Jordan Crousedc67dfb2012-10-25 09:41:46 -0600603 iommu->sync_lock_desc.priv |= KGSL_MEMDESC_GLOBAL;
Tarun Karra9c070822012-11-27 16:43:51 -0700604
605 pagetable = mmu->priv_bank_table ? mmu->priv_bank_table :
606 mmu->defaultpagetable;
607
608 status = kgsl_mmu_map(pagetable, &iommu->sync_lock_desc,
609 GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
610
611 if (status) {
612 kgsl_mmu_unmap(pagetable, &iommu->sync_lock_desc);
Jordan Crousedc67dfb2012-10-25 09:41:46 -0600613 iommu->sync_lock_desc.priv &= ~KGSL_MEMDESC_GLOBAL;
Tarun Karra9c070822012-11-27 16:43:51 -0700614 return status;
615 }
616
617 /* Store Lock variables GPU address */
618 lock_gpu_addr = (iommu->sync_lock_desc.gpuaddr + page_offset);
619
620 kgsl_iommu_sync_lock_vars.flag[PROC_APPS] = (lock_gpu_addr +
621 (offsetof(struct remote_iommu_petersons_spinlock,
622 flag[PROC_APPS])));
623 kgsl_iommu_sync_lock_vars.flag[PROC_GPU] = (lock_gpu_addr +
624 (offsetof(struct remote_iommu_petersons_spinlock,
625 flag[PROC_GPU])));
626 kgsl_iommu_sync_lock_vars.turn = (lock_gpu_addr +
627 (offsetof(struct remote_iommu_petersons_spinlock, turn)));
628
629 iommu->sync_lock_vars = &kgsl_iommu_sync_lock_vars;
630
631 /* Flag Sync Lock is Initialized */
632 iommu->sync_lock_initialized = 1;
633
634 return status;
635}
636
637/*
638 * kgsl_iommu_sync_lock - Acquire Sync Lock between GPU and CPU
639 * @mmu - Pointer to mmu device
640 * @cmds - Pointer to array of commands
641 *
642 * Return - int - number of commands.
643 */
644inline unsigned int kgsl_iommu_sync_lock(struct kgsl_mmu *mmu,
645 unsigned int *cmds)
646{
647 struct kgsl_device *device = mmu->device;
648 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
649 struct kgsl_iommu *iommu = mmu->device->mmu.priv;
650 struct remote_iommu_petersons_spinlock *lock_vars =
651 iommu->sync_lock_vars;
652 unsigned int *start = cmds;
653
654 if (!iommu->sync_lock_initialized)
655 return 0;
656
657 *cmds++ = cp_type3_packet(CP_MEM_WRITE, 2);
658 *cmds++ = lock_vars->flag[PROC_GPU];
659 *cmds++ = 1;
660
661 cmds += adreno_add_idle_cmds(adreno_dev, cmds);
662
663 *cmds++ = cp_type3_packet(CP_WAIT_REG_MEM, 5);
664 /* MEM SPACE = memory, FUNCTION = equals */
665 *cmds++ = 0x13;
666 *cmds++ = lock_vars->flag[PROC_GPU];
667 *cmds++ = 0x1;
668 *cmds++ = 0x1;
669 *cmds++ = 0x1;
670
671 *cmds++ = cp_type3_packet(CP_MEM_WRITE, 2);
672 *cmds++ = lock_vars->turn;
673 *cmds++ = 0;
674
675 cmds += adreno_add_idle_cmds(adreno_dev, cmds);
676
677 *cmds++ = cp_type3_packet(CP_WAIT_REG_MEM, 5);
678 /* MEM SPACE = memory, FUNCTION = equals */
679 *cmds++ = 0x13;
680 *cmds++ = lock_vars->flag[PROC_GPU];
681 *cmds++ = 0x1;
682 *cmds++ = 0x1;
683 *cmds++ = 0x1;
684
685 *cmds++ = cp_type3_packet(CP_TEST_TWO_MEMS, 3);
686 *cmds++ = lock_vars->flag[PROC_APPS];
687 *cmds++ = lock_vars->turn;
688 *cmds++ = 0;
689
690 cmds += adreno_add_idle_cmds(adreno_dev, cmds);
691
692 return cmds - start;
693}
694
695/*
696 * kgsl_iommu_sync_lock - Release Sync Lock between GPU and CPU
697 * @mmu - Pointer to mmu device
698 * @cmds - Pointer to array of commands
699 *
700 * Return - int - number of commands.
701 */
702inline unsigned int kgsl_iommu_sync_unlock(struct kgsl_mmu *mmu,
703 unsigned int *cmds)
704{
705 struct kgsl_device *device = mmu->device;
706 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
707 struct kgsl_iommu *iommu = mmu->device->mmu.priv;
708 struct remote_iommu_petersons_spinlock *lock_vars =
709 iommu->sync_lock_vars;
710 unsigned int *start = cmds;
711
712 if (!iommu->sync_lock_initialized)
713 return 0;
714
715 *cmds++ = cp_type3_packet(CP_MEM_WRITE, 2);
716 *cmds++ = lock_vars->flag[PROC_GPU];
717 *cmds++ = 0;
718
719 *cmds++ = cp_type3_packet(CP_WAIT_REG_MEM, 5);
720 /* MEM SPACE = memory, FUNCTION = equals */
721 *cmds++ = 0x13;
722 *cmds++ = lock_vars->flag[PROC_GPU];
723 *cmds++ = 0x0;
724 *cmds++ = 0x1;
725 *cmds++ = 0x1;
726
727 cmds += adreno_add_idle_cmds(adreno_dev, cmds);
728
729 return cmds - start;
730}
731
732/*
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600733 * kgsl_get_iommu_ctxt - Get device pointer to IOMMU contexts
734 * @mmu - Pointer to mmu device
735 *
736 * Get the device pointers for the IOMMU user and priv contexts of the
737 * kgsl device
738 * Return - 0 on success else error code
739 */
740static int kgsl_get_iommu_ctxt(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600741{
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600742 struct platform_device *pdev =
743 container_of(mmu->device->parentdev, struct platform_device,
744 dev);
745 struct kgsl_device_platform_data *pdata_dev = pdev->dev.platform_data;
746 struct kgsl_iommu *iommu = mmu->device->mmu.priv;
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700747 int i, ret = 0;
748
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600749 /* Go through the IOMMU data and get all the context devices */
750 if (KGSL_IOMMU_MAX_UNITS < pdata_dev->iommu_count) {
751 KGSL_CORE_ERR("Too many IOMMU units defined\n");
752 ret = -EINVAL;
753 goto done;
754 }
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700755
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600756 for (i = 0; i < pdata_dev->iommu_count; i++) {
757 ret = _get_iommu_ctxs(mmu, &pdata_dev->iommu_data[i], i);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700758 if (ret)
759 break;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600760 }
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600761 iommu->unit_count = pdata_dev->iommu_count;
762done:
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700763 return ret;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600764}
765
Shubhraprakash Dase9eefd72012-05-01 01:44:59 -0600766/*
767 * kgsl_set_register_map - Map the IOMMU regsiters in the memory descriptors
768 * of the respective iommu units
769 * @mmu - Pointer to mmu structure
770 *
771 * Return - 0 on success else error code
772 */
773static int kgsl_set_register_map(struct kgsl_mmu *mmu)
774{
775 struct platform_device *pdev =
776 container_of(mmu->device->parentdev, struct platform_device,
777 dev);
778 struct kgsl_device_platform_data *pdata_dev = pdev->dev.platform_data;
779 struct kgsl_iommu *iommu = mmu->device->mmu.priv;
780 struct kgsl_iommu_unit *iommu_unit;
781 int i = 0, ret = 0;
782
783 for (; i < pdata_dev->iommu_count; i++) {
784 struct kgsl_device_iommu_data data = pdata_dev->iommu_data[i];
785 iommu_unit = &iommu->iommu_units[i];
786 /* set up the IOMMU register map for the given IOMMU unit */
787 if (!data.physstart || !data.physend) {
788 KGSL_CORE_ERR("The register range for IOMMU unit not"
789 " specified\n");
790 ret = -EINVAL;
791 goto err;
792 }
793 iommu_unit->reg_map.hostptr = ioremap(data.physstart,
794 data.physend - data.physstart + 1);
795 if (!iommu_unit->reg_map.hostptr) {
796 KGSL_CORE_ERR("Failed to map SMMU register address "
797 "space from %x to %x\n", data.physstart,
798 data.physend - data.physstart + 1);
799 ret = -ENOMEM;
800 i--;
801 goto err;
802 }
803 iommu_unit->reg_map.size = data.physend - data.physstart + 1;
804 iommu_unit->reg_map.physaddr = data.physstart;
Rajeev Kulkarni55863722012-11-21 23:40:05 -0800805 ret = memdesc_sg_phys(&iommu_unit->reg_map, data.physstart,
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600806 iommu_unit->reg_map.size);
Rajeev Kulkarni55863722012-11-21 23:40:05 -0800807 if (ret)
808 goto err;
Shubhraprakash Dase9eefd72012-05-01 01:44:59 -0600809 }
810 iommu->unit_count = pdata_dev->iommu_count;
811 return ret;
812err:
813 /* Unmap any mapped IOMMU regions */
814 for (; i >= 0; i--) {
815 iommu_unit = &iommu->iommu_units[i];
816 iounmap(iommu_unit->reg_map.hostptr);
817 iommu_unit->reg_map.size = 0;
818 iommu_unit->reg_map.physaddr = 0;
819 }
820 return ret;
821}
822
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600823/*
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700824 * kgsl_iommu_get_pt_base_addr - Get the address of the pagetable that the
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600825 * IOMMU ttbr0 register is programmed with
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700826 * @mmu - Pointer to mmu
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600827 * @pt - kgsl pagetable pointer that contains the IOMMU domain pointer
828 *
829 * Return - actual pagetable address that the ttbr0 register is programmed
830 * with
831 */
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700832static unsigned int kgsl_iommu_get_pt_base_addr(struct kgsl_mmu *mmu,
833 struct kgsl_pagetable *pt)
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600834{
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700835 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600836 struct kgsl_iommu_pt *iommu_pt = pt->priv;
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700837 return iommu_get_pt_base_addr(iommu_pt->domain) &
838 (iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
839 iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600840}
841
842/*
843 * kgsl_iommu_get_pt_lsb - Return the lsb of the ttbr0 IOMMU register
844 * @mmu - Pointer to mmu structure
845 * @hostptr - Pointer to the IOMMU register map. This is used to match
846 * the iommu device whose lsb value is to be returned
847 * @ctx_id - The context bank whose lsb valus is to be returned
848 * Return - returns the lsb which is the last 14 bits of the ttbr0 IOMMU
849 * register. ttbr0 is the actual PTBR for of the IOMMU. The last 14 bits
850 * are only programmed once in the beginning when a domain is attached
851 * does not change.
852 */
853static int kgsl_iommu_get_pt_lsb(struct kgsl_mmu *mmu,
854 unsigned int unit_id,
855 enum kgsl_iommu_context_id ctx_id)
856{
857 struct kgsl_iommu *iommu = mmu->priv;
858 int i, j;
859 for (i = 0; i < iommu->unit_count; i++) {
860 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
861 for (j = 0; j < iommu_unit->dev_count; j++)
862 if (unit_id == i &&
863 ctx_id == iommu_unit->dev[j].ctx_id)
864 return iommu_unit->dev[j].pt_lsb;
865 }
866 return 0;
867}
868
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600869static void kgsl_iommu_setstate(struct kgsl_mmu *mmu,
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600870 struct kgsl_pagetable *pagetable,
871 unsigned int context_id)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600872{
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600873 if (mmu->flags & KGSL_FLAGS_STARTED) {
874 /* page table not current, then setup mmu to use new
875 * specified page table
876 */
877 if (mmu->hwpagetable != pagetable) {
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600878 unsigned int flags = 0;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600879 mmu->hwpagetable = pagetable;
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600880 flags |= kgsl_mmu_pt_get_flags(mmu->hwpagetable,
Shubhraprakash Das8649fa52012-07-26 15:49:46 -0700881 mmu->device->id) |
882 KGSL_MMUFLAGS_TLBFLUSH;
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600883 kgsl_setstate(mmu, context_id,
884 KGSL_MMUFLAGS_PTUPDATE | flags);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600885 }
886 }
887}
888
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600889static int kgsl_iommu_init(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600890{
891 /*
892 * intialize device mmu
893 *
894 * call this with the global lock held
895 */
896 int status = 0;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600897 struct kgsl_iommu *iommu;
898
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600899 iommu = kzalloc(sizeof(struct kgsl_iommu), GFP_KERNEL);
900 if (!iommu) {
901 KGSL_CORE_ERR("kzalloc(%d) failed\n",
902 sizeof(struct kgsl_iommu));
903 return -ENOMEM;
904 }
905
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600906 mmu->priv = iommu;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600907 status = kgsl_get_iommu_ctxt(mmu);
908 if (status)
909 goto done;
Shubhraprakash Dase9eefd72012-05-01 01:44:59 -0600910 status = kgsl_set_register_map(mmu);
911 if (status)
912 goto done;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600913
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700914 iommu->iommu_reg_list = kgsl_iommuv1_reg;
915 iommu->ctx_offset = KGSL_IOMMU_CTX_OFFSET_V1;
916
Shubhraprakash Das15a8b462012-08-16 23:24:28 -0700917 if (msm_soc_version_supports_iommu_v1()) {
918 iommu->iommu_reg_list = kgsl_iommuv1_reg;
919 iommu->ctx_offset = KGSL_IOMMU_CTX_OFFSET_V1;
920 } else {
921 iommu->iommu_reg_list = kgsl_iommuv2_reg;
922 iommu->ctx_offset = KGSL_IOMMU_CTX_OFFSET_V2;
923 }
924
Shubhraprakash Dase9541a32012-05-09 22:25:55 -0600925 /* A nop is required in an indirect buffer when switching
926 * pagetables in-stream */
927 kgsl_sharedmem_writel(&mmu->setstate_memory,
928 KGSL_IOMMU_SETSTATE_NOP_OFFSET,
929 cp_nop_packet(1));
930
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600931 dev_info(mmu->device->dev, "|%s| MMU type set for device is IOMMU\n",
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600932 __func__);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600933done:
934 if (status) {
935 kfree(iommu);
936 mmu->priv = NULL;
937 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600938 return status;
939}
940
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600941/*
942 * kgsl_iommu_setup_defaultpagetable - Setup the initial defualtpagetable
943 * for iommu. This function is only called once during first start, successive
944 * start do not call this funciton.
945 * @mmu - Pointer to mmu structure
946 *
947 * Create the initial defaultpagetable and setup the iommu mappings to it
948 * Return - 0 on success else error code
949 */
950static int kgsl_iommu_setup_defaultpagetable(struct kgsl_mmu *mmu)
951{
952 int status = 0;
953 int i = 0;
954 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600955 struct kgsl_pagetable *pagetable = NULL;
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600956
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600957 /* If chip is not 8960 then we use the 2nd context bank for pagetable
958 * switching on the 3D side for which a separate table is allocated */
Shubhraprakash Das15a8b462012-08-16 23:24:28 -0700959 if (!cpu_is_msm8960() && msm_soc_version_supports_iommu_v1()) {
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600960 mmu->priv_bank_table =
961 kgsl_mmu_getpagetable(KGSL_MMU_PRIV_BANK_TABLE_NAME);
962 if (mmu->priv_bank_table == NULL) {
963 status = -ENOMEM;
964 goto err;
965 }
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600966 }
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600967 mmu->defaultpagetable = kgsl_mmu_getpagetable(KGSL_MMU_GLOBAL_PT);
968 /* Return error if the default pagetable doesn't exist */
969 if (mmu->defaultpagetable == NULL) {
970 status = -ENOMEM;
971 goto err;
972 }
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600973 pagetable = mmu->priv_bank_table ? mmu->priv_bank_table :
974 mmu->defaultpagetable;
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600975 /* Map the IOMMU regsiters to only defaultpagetable */
Shubhraprakash Das15a8b462012-08-16 23:24:28 -0700976 if (msm_soc_version_supports_iommu_v1()) {
977 for (i = 0; i < iommu->unit_count; i++) {
978 iommu->iommu_units[i].reg_map.priv |=
Jordan Crousedc67dfb2012-10-25 09:41:46 -0600979 KGSL_MEMDESC_GLOBAL;
Shubhraprakash Das15a8b462012-08-16 23:24:28 -0700980 status = kgsl_mmu_map(pagetable,
981 &(iommu->iommu_units[i].reg_map),
982 GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
983 if (status) {
984 iommu->iommu_units[i].reg_map.priv &=
Jordan Crousedc67dfb2012-10-25 09:41:46 -0600985 ~KGSL_MEMDESC_GLOBAL;
Shubhraprakash Das15a8b462012-08-16 23:24:28 -0700986 goto err;
987 }
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600988 }
989 }
990 return status;
991err:
992 for (i--; i >= 0; i--) {
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600993 kgsl_mmu_unmap(pagetable,
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600994 &(iommu->iommu_units[i].reg_map));
Jordan Crousedc67dfb2012-10-25 09:41:46 -0600995 iommu->iommu_units[i].reg_map.priv &= ~KGSL_MEMDESC_GLOBAL;
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600996 }
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600997 if (mmu->priv_bank_table) {
998 kgsl_mmu_putpagetable(mmu->priv_bank_table);
999 mmu->priv_bank_table = NULL;
1000 }
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -06001001 if (mmu->defaultpagetable) {
1002 kgsl_mmu_putpagetable(mmu->defaultpagetable);
1003 mmu->defaultpagetable = NULL;
1004 }
1005 return status;
1006}
1007
Shubhraprakash Das1c528262012-04-26 17:38:13 -06001008static int kgsl_iommu_start(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001009{
Tarun Karra9c070822012-11-27 16:43:51 -07001010 struct kgsl_device *device = mmu->device;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001011 int status;
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -06001012 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001013 int i, j;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001014
1015 if (mmu->flags & KGSL_FLAGS_STARTED)
1016 return 0;
1017
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -06001018 if (mmu->defaultpagetable == NULL) {
1019 status = kgsl_iommu_setup_defaultpagetable(mmu);
1020 if (status)
1021 return -ENOMEM;
Tarun Karra9c070822012-11-27 16:43:51 -07001022
1023 /* Initialize the sync lock between GPU and CPU */
1024 if (msm_soc_version_supports_iommu_v1() &&
1025 (device->id == KGSL_DEVICE_3D0))
1026 kgsl_iommu_init_sync_lock(mmu);
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -06001027 }
Tarun Karra9c070822012-11-27 16:43:51 -07001028
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -06001029 /* We use the GPU MMU to control access to IOMMU registers on 8960 with
1030 * a225, hence we still keep the MMU active on 8960 */
1031 if (cpu_is_msm8960()) {
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -06001032 struct kgsl_mh *mh = &(mmu->device->mh);
1033 kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000001);
1034 kgsl_regwrite(mmu->device, MH_MMU_MPU_END,
1035 mh->mpu_base +
Shubhraprakash Das2b54b5f2012-08-08 18:21:36 -07001036 iommu->iommu_units[0].reg_map.gpuaddr);
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -06001037 } else {
1038 kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000000);
1039 }
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -06001040
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001041 mmu->hwpagetable = mmu->defaultpagetable;
1042
1043 status = kgsl_attach_pagetable_iommu_domain(mmu);
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -06001044 if (status) {
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -06001045 mmu->hwpagetable = NULL;
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -06001046 goto done;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -06001047 }
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -06001048 status = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001049 if (status) {
1050 KGSL_CORE_ERR("clk enable failed\n");
1051 goto done;
1052 }
1053 status = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_PRIV);
1054 if (status) {
1055 KGSL_CORE_ERR("clk enable failed\n");
1056 goto done;
1057 }
1058 /* Get the lsb value of pagetables set in the IOMMU ttbr0 register as
1059 * that value should not change when we change pagetables, so while
1060 * changing pagetables we can use this lsb value of the pagetable w/o
1061 * having to read it again
1062 */
1063 for (i = 0; i < iommu->unit_count; i++) {
1064 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
Shubhraprakash Das2747cf62012-09-27 23:05:43 -07001065 for (j = 0; j < iommu_unit->dev_count; j++) {
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001066 iommu_unit->dev[j].pt_lsb = KGSL_IOMMMU_PT_LSB(iommu,
1067 KGSL_IOMMU_GET_CTX_REG(iommu,
1068 iommu_unit,
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001069 iommu_unit->dev[j].ctx_id,
1070 TTBR0));
Shubhraprakash Das2747cf62012-09-27 23:05:43 -07001071 }
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001072 }
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001073
Shubhraprakash Dascb068072012-06-07 17:52:41 -06001074 kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -06001075 mmu->flags |= KGSL_FLAGS_STARTED;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001076
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001077done:
1078 if (status) {
Shubhraprakash Dascb068072012-06-07 17:52:41 -06001079 kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001080 kgsl_detach_pagetable_iommu_domain(mmu);
1081 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001082 return status;
1083}
1084
1085static int
1086kgsl_iommu_unmap(void *mmu_specific_pt,
Shubhraprakash Das0c811262012-06-06 23:22:19 -06001087 struct kgsl_memdesc *memdesc,
1088 unsigned int *tlb_flags)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001089{
1090 int ret;
Jordan Crouse3c86ca82012-05-21 08:41:52 -06001091 unsigned int range = kgsl_sg_size(memdesc->sg, memdesc->sglen);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -06001092 struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001093
1094 /* All GPU addresses as assigned are page aligned, but some
1095 functions purturb the gpuaddr with an offset, so apply the
1096 mask here to make sure we have the right address */
1097
1098 unsigned int gpuaddr = memdesc->gpuaddr & KGSL_MMU_ALIGN_MASK;
1099
1100 if (range == 0 || gpuaddr == 0)
1101 return 0;
1102
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -06001103 ret = iommu_unmap_range(iommu_pt->domain, gpuaddr, range);
Shubhraprakash Das08894b92011-10-14 11:42:25 -06001104 if (ret)
1105 KGSL_CORE_ERR("iommu_unmap_range(%p, %x, %d) failed "
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -06001106 "with err: %d\n", iommu_pt->domain, gpuaddr,
Shubhraprakash Das08894b92011-10-14 11:42:25 -06001107 range, ret);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001108
Shubhraprakash Das0c811262012-06-06 23:22:19 -06001109#ifdef CONFIG_KGSL_PER_PROCESS_PAGE_TABLE
1110 /*
1111 * Flushing only required if per process pagetables are used. With
1112 * global case, flushing will happen inside iommu_map function
1113 */
Shubhraprakash Das15a8b462012-08-16 23:24:28 -07001114 if (!ret && msm_soc_version_supports_iommu_v1())
Shubhraprakash Das0c811262012-06-06 23:22:19 -06001115 *tlb_flags = UINT_MAX;
1116#endif
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001117 return 0;
1118}
1119
1120static int
1121kgsl_iommu_map(void *mmu_specific_pt,
1122 struct kgsl_memdesc *memdesc,
Shubhraprakash Dasf764e462012-04-26 15:38:09 -06001123 unsigned int protflags,
1124 unsigned int *tlb_flags)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001125{
Shubhraprakash Das08894b92011-10-14 11:42:25 -06001126 int ret;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001127 unsigned int iommu_virt_addr;
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -06001128 struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
Jordan Crouse3c86ca82012-05-21 08:41:52 -06001129 int size = kgsl_sg_size(memdesc->sg, memdesc->sglen);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001130
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -06001131 BUG_ON(NULL == iommu_pt);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001132
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001133
Jordan Croused17e9aa2011-10-12 16:57:48 -06001134 iommu_virt_addr = memdesc->gpuaddr;
1135
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -06001136 ret = iommu_map_range(iommu_pt->domain, iommu_virt_addr, memdesc->sg,
Jordan Crouse3c86ca82012-05-21 08:41:52 -06001137 size, (IOMMU_READ | IOMMU_WRITE));
Shubhraprakash Das08894b92011-10-14 11:42:25 -06001138 if (ret) {
1139 KGSL_CORE_ERR("iommu_map_range(%p, %x, %p, %d, %d) "
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -06001140 "failed with err: %d\n", iommu_pt->domain,
Jordan Crouse3c86ca82012-05-21 08:41:52 -06001141 iommu_virt_addr, memdesc->sg, size,
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -06001142 (IOMMU_READ | IOMMU_WRITE), ret);
Shubhraprakash Das08894b92011-10-14 11:42:25 -06001143 return ret;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001144 }
1145
1146 return ret;
1147}
1148
Shubhraprakash Das79447952012-04-26 18:12:23 -06001149static void kgsl_iommu_stop(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001150{
Shubhraprakash Dascb068072012-06-07 17:52:41 -06001151 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Das2747cf62012-09-27 23:05:43 -07001152 int i, j;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001153 /*
1154 * stop device mmu
1155 *
1156 * call this with the global lock held
1157 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001158
1159 if (mmu->flags & KGSL_FLAGS_STARTED) {
1160 /* detach iommu attachment */
1161 kgsl_detach_pagetable_iommu_domain(mmu);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -06001162 mmu->hwpagetable = NULL;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001163
1164 mmu->flags &= ~KGSL_FLAGS_STARTED;
Shubhraprakash Dascb068072012-06-07 17:52:41 -06001165
Shubhraprakash Das2747cf62012-09-27 23:05:43 -07001166 if (mmu->fault) {
1167 for (i = 0; i < iommu->unit_count; i++) {
1168 struct kgsl_iommu_unit *iommu_unit =
1169 &iommu->iommu_units[i];
1170 for (j = 0; j < iommu_unit->dev_count; j++) {
1171 if (iommu_unit->dev[j].fault) {
1172 kgsl_iommu_enable_clk(mmu, j);
1173 KGSL_IOMMU_SET_CTX_REG(iommu,
1174 iommu_unit,
1175 iommu_unit->dev[j].ctx_id,
1176 RESUME, 1);
1177 iommu_unit->dev[j].fault = 0;
1178 }
1179 }
1180 }
1181 mmu->fault = 0;
1182 }
1183 }
Shubhraprakash Dascb068072012-06-07 17:52:41 -06001184 /* switch off MMU clocks and cancel any events it has queued */
1185 iommu->clk_event_queued = false;
1186 kgsl_cancel_events(mmu->device, mmu);
1187 kgsl_iommu_disable_clk(mmu);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001188}
1189
Shubhraprakash Das1c528262012-04-26 17:38:13 -06001190static int kgsl_iommu_close(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001191{
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -06001192 struct kgsl_iommu *iommu = mmu->priv;
1193 int i;
1194 for (i = 0; i < iommu->unit_count; i++) {
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -06001195 struct kgsl_pagetable *pagetable = (mmu->priv_bank_table ?
1196 mmu->priv_bank_table : mmu->defaultpagetable);
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -06001197 if (iommu->iommu_units[i].reg_map.gpuaddr)
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -06001198 kgsl_mmu_unmap(pagetable,
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -06001199 &(iommu->iommu_units[i].reg_map));
1200 if (iommu->iommu_units[i].reg_map.hostptr)
1201 iounmap(iommu->iommu_units[i].reg_map.hostptr);
1202 kgsl_sg_free(iommu->iommu_units[i].reg_map.sg,
1203 iommu->iommu_units[i].reg_map.sglen);
1204 }
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -06001205
1206 if (mmu->priv_bank_table)
1207 kgsl_mmu_putpagetable(mmu->priv_bank_table);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001208 if (mmu->defaultpagetable)
1209 kgsl_mmu_putpagetable(mmu->defaultpagetable);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -06001210 kfree(iommu);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001211
1212 return 0;
1213}
1214
1215static unsigned int
Shubhraprakash Das1c528262012-04-26 17:38:13 -06001216kgsl_iommu_get_current_ptbase(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001217{
Shubhraprakash Das2b8716b2012-05-04 16:58:40 -06001218 unsigned int pt_base;
1219 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Das64a745c2012-06-11 16:44:16 -06001220 /* We cannot enable or disable the clocks in interrupt context, this
1221 function is called from interrupt context if there is an axi error */
1222 if (in_interrupt())
1223 return 0;
Shubhraprakash Das2b8716b2012-05-04 16:58:40 -06001224 /* Return the current pt base by reading IOMMU pt_base register */
1225 kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001226 pt_base = KGSL_IOMMU_GET_CTX_REG(iommu, (&iommu->iommu_units[0]),
1227 KGSL_IOMMU_CONTEXT_USER,
1228 TTBR0);
Shubhraprakash Dascb068072012-06-07 17:52:41 -06001229 kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001230 return pt_base &
1231 (iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
1232 iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001233}
1234
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -06001235/*
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001236 * kgsl_iommu_default_setstate - Change the IOMMU pagetable or flush IOMMU tlb
1237 * of the primary context bank
1238 * @mmu - Pointer to mmu structure
1239 * @flags - Flags indicating whether pagetable has to chnage or tlb is to be
1240 * flushed or both
1241 *
1242 * Based on flags set the new pagetable fo the IOMMU unit or flush it's tlb or
1243 * do both by doing direct register writes to the IOMMu registers through the
1244 * cpu
1245 * Return - void
1246 */
1247static void kgsl_iommu_default_setstate(struct kgsl_mmu *mmu,
1248 uint32_t flags)
1249{
1250 struct kgsl_iommu *iommu = mmu->priv;
1251 int temp;
1252 int i;
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001253 unsigned int pt_base = kgsl_iommu_get_pt_base_addr(mmu,
1254 mmu->hwpagetable);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001255 unsigned int pt_val;
1256
1257 if (kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER)) {
1258 KGSL_DRV_ERR(mmu->device, "Failed to enable iommu clocks\n");
1259 return;
1260 }
1261 /* Mask off the lsb of the pt base address since lsb will not change */
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001262 pt_base &= (iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
1263 iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
1264
Tarun Karra9c070822012-11-27 16:43:51 -07001265 //if (msm_soc_version_supports_iommu_v1())
Shubhraprakash Dasee61e4d2012-11-27 17:07:44 -07001266 /* Acquire GPU-CPU sync Lock here */
1267 msm_iommu_lock();
1268
1269 if (flags & KGSL_MMUFLAGS_PTUPDATE) {
1270 if (!msm_soc_version_supports_iommu_v1())
1271 kgsl_idle(mmu->device);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001272 for (i = 0; i < iommu->unit_count; i++) {
1273 /* get the lsb value which should not change when
1274 * changing ttbr0 */
1275 pt_val = kgsl_iommu_get_pt_lsb(mmu, i,
1276 KGSL_IOMMU_CONTEXT_USER);
1277 pt_val += pt_base;
1278
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001279 KGSL_IOMMU_SET_CTX_REG(iommu, (&iommu->iommu_units[i]),
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001280 KGSL_IOMMU_CONTEXT_USER, TTBR0, pt_val);
1281
1282 mb();
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001283 temp = KGSL_IOMMU_GET_CTX_REG(iommu,
1284 (&iommu->iommu_units[i]),
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001285 KGSL_IOMMU_CONTEXT_USER, TTBR0);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001286 }
1287 }
1288 /* Flush tlb */
1289 if (flags & KGSL_MMUFLAGS_TLBFLUSH) {
1290 for (i = 0; i < iommu->unit_count; i++) {
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001291 KGSL_IOMMU_SET_CTX_REG(iommu, (&iommu->iommu_units[i]),
1292 KGSL_IOMMU_CONTEXT_USER, TLBIALL, 1);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001293 mb();
1294 }
1295 }
Tarun Karra9c070822012-11-27 16:43:51 -07001296
1297 /* Release GPU-CPU sync Lock here */
1298 msm_iommu_unlock();
1299
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001300 /* Disable smmu clock */
Shubhraprakash Dascb068072012-06-07 17:52:41 -06001301 kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001302}
1303
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001304/*
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001305 * kgsl_iommu_get_reg_gpuaddr - Returns the gpu address of IOMMU regsiter
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001306 * @mmu - Pointer to mmu structure
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001307 * @iommu_unit - The iommu unit for which base address is requested
1308 * @ctx_id - The context ID of the IOMMU ctx
1309 * @reg - The register for which address is required
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001310 *
1311 * Return - The number of iommu units which is also the number of register
1312 * mapped descriptor arrays which the out parameter will have
1313 */
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001314static unsigned int kgsl_iommu_get_reg_gpuaddr(struct kgsl_mmu *mmu,
1315 int iommu_unit, int ctx_id, int reg)
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001316{
1317 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001318
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001319 if (KGSL_IOMMU_GLOBAL_BASE == reg)
1320 return iommu->iommu_units[iommu_unit].reg_map.gpuaddr;
1321 else
1322 return iommu->iommu_units[iommu_unit].reg_map.gpuaddr +
1323 iommu->iommu_reg_list[reg].reg_offset +
1324 (ctx_id << KGSL_IOMMU_CTX_SHIFT) + iommu->ctx_offset;
1325}
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001326
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001327static int kgsl_iommu_get_num_iommu_units(struct kgsl_mmu *mmu)
1328{
1329 struct kgsl_iommu *iommu = mmu->priv;
1330 return iommu->unit_count;
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001331}
1332
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001333struct kgsl_mmu_ops iommu_ops = {
1334 .mmu_init = kgsl_iommu_init,
1335 .mmu_close = kgsl_iommu_close,
1336 .mmu_start = kgsl_iommu_start,
1337 .mmu_stop = kgsl_iommu_stop,
1338 .mmu_setstate = kgsl_iommu_setstate,
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001339 .mmu_device_setstate = kgsl_iommu_default_setstate,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001340 .mmu_pagefault = NULL,
1341 .mmu_get_current_ptbase = kgsl_iommu_get_current_ptbase,
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -06001342 .mmu_enable_clk = kgsl_iommu_enable_clk,
Shubhraprakash Dascb068072012-06-07 17:52:41 -06001343 .mmu_disable_clk_on_ts = kgsl_iommu_disable_clk_on_ts,
Shubhraprakash Dasfce27362012-05-09 17:44:14 -06001344 .mmu_get_pt_lsb = kgsl_iommu_get_pt_lsb,
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001345 .mmu_get_reg_gpuaddr = kgsl_iommu_get_reg_gpuaddr,
1346 .mmu_get_num_iommu_units = kgsl_iommu_get_num_iommu_units,
1347 .mmu_pt_equal = kgsl_iommu_pt_equal,
1348 .mmu_get_pt_base_addr = kgsl_iommu_get_pt_base_addr,
Tarun Karra9c070822012-11-27 16:43:51 -07001349 .mmu_sync_lock = kgsl_iommu_sync_lock,
1350 .mmu_sync_unlock = kgsl_iommu_sync_unlock,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001351};
1352
1353struct kgsl_mmu_pt_ops iommu_pt_ops = {
1354 .mmu_map = kgsl_iommu_map,
1355 .mmu_unmap = kgsl_iommu_unmap,
1356 .mmu_create_pagetable = kgsl_iommu_create_pagetable,
1357 .mmu_destroy_pagetable = kgsl_iommu_destroy_pagetable,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001358};