blob: f2393e4cd73fe3c9ed5834b2e857afc3d8f9290d [file] [log] [blame]
Duy Truonge833aca2013-02-12 13:35:08 -08001/* Copyright (c) 2011-2012, The Linux Foundation. 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;
Tarun Karrab8107322013-02-07 13:46:02 -0800112 struct kgsl_device *device;
Tarun Karra99678f82013-02-13 13:57:25 -0800113 struct adreno_device *adreno_dev;
114 unsigned int no_page_fault_log = 0;
Jordan Crouse95b68472012-05-25 10:25:01 -0600115
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700116 ret = get_iommu_unit(dev, &mmu, &iommu_unit);
117 if (ret)
118 goto done;
119 iommu_dev = get_iommu_device(iommu_unit, dev);
Jordan Crouse95b68472012-05-25 10:25:01 -0600120 if (!iommu_dev) {
121 KGSL_CORE_ERR("Invalid IOMMU device %p\n", dev);
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700122 ret = -ENOSYS;
123 goto done;
Jordan Crouse95b68472012-05-25 10:25:01 -0600124 }
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700125 iommu = mmu->priv;
Tarun Karrab8107322013-02-07 13:46:02 -0800126 device = mmu->device;
Tarun Karra99678f82013-02-13 13:57:25 -0800127 adreno_dev = ADRENO_DEVICE(device);
Jordan Crouse95b68472012-05-25 10:25:01 -0600128
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700129 ptbase = KGSL_IOMMU_GET_CTX_REG(iommu, iommu_unit,
Shubhraprakash Das190553a2012-06-11 15:17:59 -0600130 iommu_dev->ctx_id, TTBR0);
Jordan Crouse95b68472012-05-25 10:25:01 -0600131
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700132 fsr = KGSL_IOMMU_GET_CTX_REG(iommu, iommu_unit,
Jordan Crouse95b68472012-05-25 10:25:01 -0600133 iommu_dev->ctx_id, FSR);
134
Tarun Karra99678f82013-02-13 13:57:25 -0800135 if (adreno_dev->ft_pf_policy & KGSL_FT_PAGEFAULT_LOG_ONE_PER_PAGE)
136 no_page_fault_log = kgsl_mmu_log_fault_addr(mmu, ptbase, addr);
Tarun Karrab8107322013-02-07 13:46:02 -0800137
138 if (!no_page_fault_log) {
139 KGSL_MEM_CRIT(iommu_dev->kgsldev,
140 "GPU PAGE FAULT: addr = %lX pid = %d\n",
141 addr, kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase));
142 KGSL_MEM_CRIT(iommu_dev->kgsldev, "context = %d FSR = %X\n",
143 iommu_dev->ctx_id, fsr);
144 }
Jordan Crouse95b68472012-05-25 10:25:01 -0600145
Shubhraprakash Das2747cf62012-09-27 23:05:43 -0700146 mmu->fault = 1;
147 iommu_dev->fault = 1;
148
Jordan Crouse95b68472012-05-25 10:25:01 -0600149 trace_kgsl_mmu_pagefault(iommu_dev->kgsldev, addr,
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700150 kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase), 0);
Jordan Crouse95b68472012-05-25 10:25:01 -0600151
Shubhraprakash Das2747cf62012-09-27 23:05:43 -0700152 /*
153 * We do not want the h/w to resume fetching data from an iommu unit
154 * that has faulted, this is better for debugging as it will stall
155 * the GPU and trigger a snapshot. To stall the transaction return
156 * EBUSY error.
157 */
Tarun Karra99678f82013-02-13 13:57:25 -0800158 if (adreno_dev->ft_pf_policy & KGSL_FT_PAGEFAULT_GPUHALT_ENABLE)
159 ret = -EBUSY;
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700160done:
161 return ret;
Jordan Crouse95b68472012-05-25 10:25:01 -0600162}
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600163
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -0600164/*
165 * kgsl_iommu_disable_clk - Disable iommu clocks
166 * @mmu - Pointer to mmu structure
167 *
168 * Disables iommu clocks
169 * Return - void
170 */
171static void kgsl_iommu_disable_clk(struct kgsl_mmu *mmu)
172{
173 struct kgsl_iommu *iommu = mmu->priv;
174 struct msm_iommu_drvdata *iommu_drvdata;
175 int i, j;
176
177 for (i = 0; i < iommu->unit_count; i++) {
178 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
179 for (j = 0; j < iommu_unit->dev_count; j++) {
180 if (!iommu_unit->dev[j].clk_enabled)
181 continue;
182 iommu_drvdata = dev_get_drvdata(
183 iommu_unit->dev[j].dev->parent);
Shubhraprakash Das102aac52012-08-16 22:12:27 -0700184 if (iommu_drvdata->aclk)
185 clk_disable_unprepare(iommu_drvdata->aclk);
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -0600186 if (iommu_drvdata->clk)
187 clk_disable_unprepare(iommu_drvdata->clk);
188 clk_disable_unprepare(iommu_drvdata->pclk);
189 iommu_unit->dev[j].clk_enabled = false;
190 }
191 }
192}
193
194/*
Shubhraprakash Dascb068072012-06-07 17:52:41 -0600195 * kgsl_iommu_disable_clk_event - An event function that is executed when
196 * the required timestamp is reached. It disables the IOMMU clocks if
197 * the timestamp on which the clocks can be disabled has expired.
198 * @device - The kgsl device pointer
199 * @data - The data passed during event creation, it is the MMU pointer
200 * @id - Context ID, should always be KGSL_MEMSTORE_GLOBAL
201 * @ts - The current timestamp that has expired for the device
202 *
203 * Disables IOMMU clocks if timestamp has expired
204 * Return - void
205 */
206static void kgsl_iommu_clk_disable_event(struct kgsl_device *device, void *data,
207 unsigned int id, unsigned int ts)
208{
209 struct kgsl_mmu *mmu = data;
210 struct kgsl_iommu *iommu = mmu->priv;
211
212 if (!iommu->clk_event_queued) {
213 if (0 > timestamp_cmp(ts, iommu->iommu_last_cmd_ts))
214 KGSL_DRV_ERR(device,
215 "IOMMU disable clock event being cancelled, "
216 "iommu_last_cmd_ts: %x, retired ts: %x\n",
217 iommu->iommu_last_cmd_ts, ts);
218 return;
219 }
220
221 if (0 <= timestamp_cmp(ts, iommu->iommu_last_cmd_ts)) {
222 kgsl_iommu_disable_clk(mmu);
223 iommu->clk_event_queued = false;
224 } else {
225 /* add new event to fire when ts is reached, this can happen
226 * if we queued an event and someone requested the clocks to
227 * be disbaled on a later timestamp */
228 if (kgsl_add_event(device, id, iommu->iommu_last_cmd_ts,
229 kgsl_iommu_clk_disable_event, mmu, mmu)) {
230 KGSL_DRV_ERR(device,
231 "Failed to add IOMMU disable clk event\n");
232 iommu->clk_event_queued = false;
233 }
234 }
235}
236
237/*
238 * kgsl_iommu_disable_clk_on_ts - Sets up event to disable IOMMU clocks
239 * @mmu - The kgsl MMU pointer
240 * @ts - Timestamp on which the clocks should be disabled
241 * @ts_valid - Indicates whether ts parameter is valid, if this parameter
242 * is false then it means that the calling function wants to disable the
243 * IOMMU clocks immediately without waiting for any timestamp
244 *
245 * Creates an event to disable the IOMMU clocks on timestamp and if event
246 * already exists then updates the timestamp of disabling the IOMMU clocks
247 * with the passed in ts if it is greater than the current value at which
248 * the clocks will be disabled
249 * Return - void
250 */
251static void
252kgsl_iommu_disable_clk_on_ts(struct kgsl_mmu *mmu, unsigned int ts,
253 bool ts_valid)
254{
255 struct kgsl_iommu *iommu = mmu->priv;
256
257 if (iommu->clk_event_queued) {
258 if (ts_valid && (0 <
259 timestamp_cmp(ts, iommu->iommu_last_cmd_ts)))
260 iommu->iommu_last_cmd_ts = ts;
261 } else {
262 if (ts_valid) {
263 iommu->iommu_last_cmd_ts = ts;
264 iommu->clk_event_queued = true;
265 if (kgsl_add_event(mmu->device, KGSL_MEMSTORE_GLOBAL,
266 ts, kgsl_iommu_clk_disable_event, mmu, mmu)) {
267 KGSL_DRV_ERR(mmu->device,
268 "Failed to add IOMMU disable clk event\n");
269 iommu->clk_event_queued = false;
270 }
271 } else {
272 kgsl_iommu_disable_clk(mmu);
273 }
274 }
275}
276
277/*
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -0600278 * kgsl_iommu_enable_clk - Enable iommu clocks
279 * @mmu - Pointer to mmu structure
280 * @ctx_id - The context bank whose clocks are to be turned on
281 *
282 * Enables iommu clocks of a given context
283 * Return: 0 on success else error code
284 */
285static int kgsl_iommu_enable_clk(struct kgsl_mmu *mmu,
286 int ctx_id)
287{
288 int ret = 0;
289 int i, j;
290 struct kgsl_iommu *iommu = mmu->priv;
291 struct msm_iommu_drvdata *iommu_drvdata;
292
293 for (i = 0; i < iommu->unit_count; i++) {
294 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
295 for (j = 0; j < iommu_unit->dev_count; j++) {
296 if (iommu_unit->dev[j].clk_enabled ||
297 ctx_id != iommu_unit->dev[j].ctx_id)
298 continue;
299 iommu_drvdata =
300 dev_get_drvdata(iommu_unit->dev[j].dev->parent);
301 ret = clk_prepare_enable(iommu_drvdata->pclk);
302 if (ret)
303 goto done;
304 if (iommu_drvdata->clk) {
305 ret = clk_prepare_enable(iommu_drvdata->clk);
306 if (ret) {
307 clk_disable_unprepare(
308 iommu_drvdata->pclk);
309 goto done;
310 }
311 }
Shubhraprakash Das102aac52012-08-16 22:12:27 -0700312 if (iommu_drvdata->aclk) {
313 ret = clk_prepare_enable(iommu_drvdata->aclk);
314 if (ret) {
315 if (iommu_drvdata->clk)
316 clk_disable_unprepare(
317 iommu_drvdata->clk);
318 clk_disable_unprepare(
319 iommu_drvdata->pclk);
320 goto done;
321 }
322 }
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -0600323 iommu_unit->dev[j].clk_enabled = true;
324 }
325 }
326done:
327 if (ret)
328 kgsl_iommu_disable_clk(mmu);
329 return ret;
330}
331
Shubhraprakash Das48d97302012-05-07 12:16:08 -0600332/*
333 * kgsl_iommu_pt_equal - Check if pagetables are equal
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700334 * @mmu - Pointer to mmu structure
Shubhraprakash Das48d97302012-05-07 12:16:08 -0600335 * @pt - Pointer to pagetable
336 * @pt_base - Address of a pagetable that the IOMMU register is
337 * programmed with
338 *
339 * Checks whether the pt_base is equal to the base address of
340 * the pagetable which is contained in the pt structure
341 * Return - Non-zero if the pagetable addresses are equal else 0
342 */
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700343static int kgsl_iommu_pt_equal(struct kgsl_mmu *mmu,
344 struct kgsl_pagetable *pt,
345 unsigned int pt_base)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600346{
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700347 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600348 struct kgsl_iommu_pt *iommu_pt = pt ? pt->priv : NULL;
349 unsigned int domain_ptbase = iommu_pt ?
350 iommu_get_pt_base_addr(iommu_pt->domain) : 0;
Shubhraprakash Das48d97302012-05-07 12:16:08 -0600351 /* Only compare the valid address bits of the pt_base */
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700352 domain_ptbase &=
353 (iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
354 iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
355
356 pt_base &=
357 (iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
358 iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
359
Shubhraprakash Das48d97302012-05-07 12:16:08 -0600360 return domain_ptbase && pt_base &&
361 (domain_ptbase == pt_base);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600362}
363
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600364/*
365 * kgsl_iommu_destroy_pagetable - Free up reaources help by a pagetable
366 * @mmu_specific_pt - Pointer to pagetable which is to be freed
367 *
368 * Return - void
369 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600370static void kgsl_iommu_destroy_pagetable(void *mmu_specific_pt)
371{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600372 struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
373 if (iommu_pt->domain)
374 iommu_domain_free(iommu_pt->domain);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600375 kfree(iommu_pt);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600376}
377
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600378/*
379 * kgsl_iommu_create_pagetable - Create a IOMMU pagetable
380 *
381 * Allocate memory to hold a pagetable and allocate the IOMMU
382 * domain which is the actual IOMMU pagetable
383 * Return - void
384 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600385void *kgsl_iommu_create_pagetable(void)
386{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600387 struct kgsl_iommu_pt *iommu_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600388
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600389 iommu_pt = kzalloc(sizeof(struct kgsl_iommu_pt), GFP_KERNEL);
390 if (!iommu_pt) {
391 KGSL_CORE_ERR("kzalloc(%d) failed\n",
392 sizeof(struct kgsl_iommu_pt));
393 return NULL;
394 }
Shubhraprakash Das15a8b462012-08-16 23:24:28 -0700395 /* L2 redirect is not stable on IOMMU v2 */
396 if (msm_soc_version_supports_iommu_v1())
397 iommu_pt->domain = iommu_domain_alloc(&platform_bus_type,
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700398 MSM_IOMMU_DOMAIN_PT_CACHEABLE);
Shubhraprakash Das15a8b462012-08-16 23:24:28 -0700399 else
400 iommu_pt->domain = iommu_domain_alloc(&platform_bus_type,
401 0);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600402 if (!iommu_pt->domain) {
403 KGSL_CORE_ERR("Failed to create iommu domain\n");
404 kfree(iommu_pt);
405 return NULL;
Jordan Crouse95b68472012-05-25 10:25:01 -0600406 } else {
407 iommu_set_fault_handler(iommu_pt->domain,
408 kgsl_iommu_fault_handler);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600409 }
Jordan Crouse95b68472012-05-25 10:25:01 -0600410
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600411 return iommu_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600412}
413
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600414/*
415 * kgsl_detach_pagetable_iommu_domain - Detach the IOMMU unit from a
416 * pagetable
417 * @mmu - Pointer to the device mmu structure
418 * @priv - Flag indicating whether the private or user context is to be
419 * detached
420 *
421 * Detach the IOMMU unit with the domain that is contained in the
422 * hwpagetable of the given mmu. After detaching the IOMMU unit is not
423 * in use because the PTBR will not be set after a detach
424 * Return - void
425 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600426static void kgsl_detach_pagetable_iommu_domain(struct kgsl_mmu *mmu)
427{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600428 struct kgsl_iommu_pt *iommu_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600429 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600430 int i, j;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600431
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600432 for (i = 0; i < iommu->unit_count; i++) {
433 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600434 iommu_pt = mmu->defaultpagetable->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600435 for (j = 0; j < iommu_unit->dev_count; j++) {
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600436 /*
437 * If there is a 2nd default pagetable then priv domain
438 * is attached with this pagetable
439 */
440 if (mmu->priv_bank_table &&
441 (KGSL_IOMMU_CONTEXT_PRIV == j))
442 iommu_pt = mmu->priv_bank_table->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600443 if (iommu_unit->dev[j].attached) {
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600444 iommu_detach_device(iommu_pt->domain,
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600445 iommu_unit->dev[j].dev);
446 iommu_unit->dev[j].attached = false;
447 KGSL_MEM_INFO(mmu->device, "iommu %p detached "
448 "from user dev of MMU: %p\n",
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600449 iommu_pt->domain, mmu);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600450 }
451 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600452 }
453}
454
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600455/*
456 * kgsl_attach_pagetable_iommu_domain - Attach the IOMMU unit to a
457 * pagetable, i.e set the IOMMU's PTBR to the pagetable address and
458 * setup other IOMMU registers for the device so that it becomes
459 * active
460 * @mmu - Pointer to the device mmu structure
461 * @priv - Flag indicating whether the private or user context is to be
462 * attached
463 *
464 * Attach the IOMMU unit with the domain that is contained in the
465 * hwpagetable of the given mmu.
466 * Return - 0 on success else error code
467 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600468static int kgsl_attach_pagetable_iommu_domain(struct kgsl_mmu *mmu)
469{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600470 struct kgsl_iommu_pt *iommu_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600471 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600472 int i, j, ret = 0;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600473
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600474 /*
475 * Loop through all the iommu devcies under all iommu units and
476 * attach the domain
477 */
478 for (i = 0; i < iommu->unit_count; i++) {
479 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600480 iommu_pt = mmu->defaultpagetable->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600481 for (j = 0; j < iommu_unit->dev_count; j++) {
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600482 /*
483 * If there is a 2nd default pagetable then priv domain
484 * is attached to this pagetable
485 */
486 if (mmu->priv_bank_table &&
487 (KGSL_IOMMU_CONTEXT_PRIV == j))
488 iommu_pt = mmu->priv_bank_table->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600489 if (!iommu_unit->dev[j].attached) {
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600490 ret = iommu_attach_device(iommu_pt->domain,
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600491 iommu_unit->dev[j].dev);
492 if (ret) {
493 KGSL_MEM_ERR(mmu->device,
494 "Failed to attach device, err %d\n",
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700495 ret);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600496 goto done;
497 }
498 iommu_unit->dev[j].attached = true;
499 KGSL_MEM_INFO(mmu->device,
500 "iommu pt %p attached to dev %p, ctx_id %d\n",
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600501 iommu_pt->domain, iommu_unit->dev[j].dev,
502 iommu_unit->dev[j].ctx_id);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700503 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600504 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600505 }
506done:
507 return ret;
508}
509
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600510/*
511 * _get_iommu_ctxs - Get device pointer to IOMMU contexts
512 * @mmu - Pointer to mmu device
513 * data - Pointer to the platform data containing information about
514 * iommu devices for one iommu unit
515 * unit_id - The IOMMU unit number. This is not a specific ID but just
516 * a serial number. The serial numbers are treated as ID's of the
517 * IOMMU units
518 *
519 * Return - 0 on success else error code
520 */
521static int _get_iommu_ctxs(struct kgsl_mmu *mmu,
522 struct kgsl_device_iommu_data *data, unsigned int unit_id)
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700523{
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600524 struct kgsl_iommu *iommu = mmu->priv;
525 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[unit_id];
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700526 int i;
527
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600528 if (data->iommu_ctx_count > KGSL_IOMMU_MAX_DEVS_PER_UNIT) {
529 KGSL_CORE_ERR("Too many iommu devices defined for an "
530 "IOMMU unit\n");
531 return -EINVAL;
532 }
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700533
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600534 for (i = 0; i < data->iommu_ctx_count; i++) {
535 if (!data->iommu_ctxs[i].iommu_ctx_name)
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700536 continue;
537
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600538 iommu_unit->dev[iommu_unit->dev_count].dev =
539 msm_iommu_get_ctx(data->iommu_ctxs[i].iommu_ctx_name);
540 if (iommu_unit->dev[iommu_unit->dev_count].dev == NULL) {
541 KGSL_CORE_ERR("Failed to get iommu dev handle for "
542 "device %s\n", data->iommu_ctxs[i].iommu_ctx_name);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700543 return -EINVAL;
544 }
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600545 if (KGSL_IOMMU_CONTEXT_USER != data->iommu_ctxs[i].ctx_id &&
546 KGSL_IOMMU_CONTEXT_PRIV != data->iommu_ctxs[i].ctx_id) {
547 KGSL_CORE_ERR("Invalid context ID defined: %d\n",
548 data->iommu_ctxs[i].ctx_id);
549 return -EINVAL;
550 }
551 iommu_unit->dev[iommu_unit->dev_count].ctx_id =
552 data->iommu_ctxs[i].ctx_id;
Jordan Crouse95b68472012-05-25 10:25:01 -0600553 iommu_unit->dev[iommu_unit->dev_count].kgsldev = mmu->device;
554
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600555 KGSL_DRV_INFO(mmu->device,
556 "Obtained dev handle %p for iommu context %s\n",
557 iommu_unit->dev[iommu_unit->dev_count].dev,
558 data->iommu_ctxs[i].iommu_ctx_name);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700559
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600560 iommu_unit->dev_count++;
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700561 }
562
563 return 0;
564}
565
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600566/*
Tarun Karra9c070822012-11-27 16:43:51 -0700567 * kgsl_get_sync_lock - Init Sync Lock between GPU and CPU
568 * @mmu - Pointer to mmu device
569 *
570 * Return - 0 on success else error code
571 */
572static int kgsl_iommu_init_sync_lock(struct kgsl_mmu *mmu)
573{
574 struct kgsl_iommu *iommu = mmu->device->mmu.priv;
575 int status = 0;
576 struct kgsl_pagetable *pagetable = NULL;
577 uint32_t lock_gpu_addr = 0;
578 uint32_t lock_phy_addr = 0;
579 uint32_t page_offset = 0;
580
581 iommu->sync_lock_initialized = 0;
582
583 if (!(mmu->flags & KGSL_MMU_FLAGS_IOMMU_SYNC)) {
584 KGSL_DRV_ERR(mmu->device,
585 "The GPU microcode does not support IOMMUv1 sync opcodes\n");
586 return -ENXIO;
587 }
588
589 /* Get the physical address of the Lock variables */
590 lock_phy_addr = (msm_iommu_lock_initialize()
591 - MSM_SHARED_RAM_BASE + msm_shared_ram_phys);
592
593 if (!lock_phy_addr) {
594 KGSL_DRV_ERR(mmu->device,
595 "GPU CPU sync lock is not supported by kernel\n");
596 return -ENXIO;
597 }
598
599 /* Align the physical address to PAGE boundary and store the offset */
600 page_offset = (lock_phy_addr & (PAGE_SIZE - 1));
601 lock_phy_addr = (lock_phy_addr & ~(PAGE_SIZE - 1));
602 iommu->sync_lock_desc.physaddr = (unsigned int)lock_phy_addr;
603
604 iommu->sync_lock_desc.size =
605 PAGE_ALIGN(sizeof(kgsl_iommu_sync_lock_vars));
606 status = memdesc_sg_phys(&iommu->sync_lock_desc,
607 iommu->sync_lock_desc.physaddr,
608 iommu->sync_lock_desc.size);
609
610 if (status)
611 return status;
612
613 /* Map Lock variables to GPU pagetable */
Jordan Crousedc67dfb2012-10-25 09:41:46 -0600614 iommu->sync_lock_desc.priv |= KGSL_MEMDESC_GLOBAL;
Tarun Karra9c070822012-11-27 16:43:51 -0700615
616 pagetable = mmu->priv_bank_table ? mmu->priv_bank_table :
617 mmu->defaultpagetable;
618
619 status = kgsl_mmu_map(pagetable, &iommu->sync_lock_desc,
620 GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
621
622 if (status) {
623 kgsl_mmu_unmap(pagetable, &iommu->sync_lock_desc);
Jordan Crousedc67dfb2012-10-25 09:41:46 -0600624 iommu->sync_lock_desc.priv &= ~KGSL_MEMDESC_GLOBAL;
Tarun Karra9c070822012-11-27 16:43:51 -0700625 return status;
626 }
627
628 /* Store Lock variables GPU address */
629 lock_gpu_addr = (iommu->sync_lock_desc.gpuaddr + page_offset);
630
631 kgsl_iommu_sync_lock_vars.flag[PROC_APPS] = (lock_gpu_addr +
632 (offsetof(struct remote_iommu_petersons_spinlock,
633 flag[PROC_APPS])));
634 kgsl_iommu_sync_lock_vars.flag[PROC_GPU] = (lock_gpu_addr +
635 (offsetof(struct remote_iommu_petersons_spinlock,
636 flag[PROC_GPU])));
637 kgsl_iommu_sync_lock_vars.turn = (lock_gpu_addr +
638 (offsetof(struct remote_iommu_petersons_spinlock, turn)));
639
640 iommu->sync_lock_vars = &kgsl_iommu_sync_lock_vars;
641
642 /* Flag Sync Lock is Initialized */
643 iommu->sync_lock_initialized = 1;
644
645 return status;
646}
647
648/*
649 * kgsl_iommu_sync_lock - Acquire Sync Lock between GPU and CPU
650 * @mmu - Pointer to mmu device
651 * @cmds - Pointer to array of commands
652 *
653 * Return - int - number of commands.
654 */
655inline unsigned int kgsl_iommu_sync_lock(struct kgsl_mmu *mmu,
656 unsigned int *cmds)
657{
658 struct kgsl_device *device = mmu->device;
659 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
660 struct kgsl_iommu *iommu = mmu->device->mmu.priv;
661 struct remote_iommu_petersons_spinlock *lock_vars =
662 iommu->sync_lock_vars;
663 unsigned int *start = cmds;
664
665 if (!iommu->sync_lock_initialized)
666 return 0;
667
668 *cmds++ = cp_type3_packet(CP_MEM_WRITE, 2);
669 *cmds++ = lock_vars->flag[PROC_GPU];
670 *cmds++ = 1;
671
672 cmds += adreno_add_idle_cmds(adreno_dev, cmds);
673
674 *cmds++ = cp_type3_packet(CP_WAIT_REG_MEM, 5);
675 /* MEM SPACE = memory, FUNCTION = equals */
676 *cmds++ = 0x13;
677 *cmds++ = lock_vars->flag[PROC_GPU];
678 *cmds++ = 0x1;
679 *cmds++ = 0x1;
680 *cmds++ = 0x1;
681
682 *cmds++ = cp_type3_packet(CP_MEM_WRITE, 2);
683 *cmds++ = lock_vars->turn;
684 *cmds++ = 0;
685
686 cmds += adreno_add_idle_cmds(adreno_dev, cmds);
687
688 *cmds++ = cp_type3_packet(CP_WAIT_REG_MEM, 5);
689 /* MEM SPACE = memory, FUNCTION = equals */
690 *cmds++ = 0x13;
691 *cmds++ = lock_vars->flag[PROC_GPU];
692 *cmds++ = 0x1;
693 *cmds++ = 0x1;
694 *cmds++ = 0x1;
695
696 *cmds++ = cp_type3_packet(CP_TEST_TWO_MEMS, 3);
697 *cmds++ = lock_vars->flag[PROC_APPS];
698 *cmds++ = lock_vars->turn;
699 *cmds++ = 0;
700
701 cmds += adreno_add_idle_cmds(adreno_dev, cmds);
702
703 return cmds - start;
704}
705
706/*
707 * kgsl_iommu_sync_lock - Release Sync Lock between GPU and CPU
708 * @mmu - Pointer to mmu device
709 * @cmds - Pointer to array of commands
710 *
711 * Return - int - number of commands.
712 */
713inline unsigned int kgsl_iommu_sync_unlock(struct kgsl_mmu *mmu,
714 unsigned int *cmds)
715{
716 struct kgsl_device *device = mmu->device;
717 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
718 struct kgsl_iommu *iommu = mmu->device->mmu.priv;
719 struct remote_iommu_petersons_spinlock *lock_vars =
720 iommu->sync_lock_vars;
721 unsigned int *start = cmds;
722
723 if (!iommu->sync_lock_initialized)
724 return 0;
725
726 *cmds++ = cp_type3_packet(CP_MEM_WRITE, 2);
727 *cmds++ = lock_vars->flag[PROC_GPU];
728 *cmds++ = 0;
729
730 *cmds++ = cp_type3_packet(CP_WAIT_REG_MEM, 5);
731 /* MEM SPACE = memory, FUNCTION = equals */
732 *cmds++ = 0x13;
733 *cmds++ = lock_vars->flag[PROC_GPU];
734 *cmds++ = 0x0;
735 *cmds++ = 0x1;
736 *cmds++ = 0x1;
737
738 cmds += adreno_add_idle_cmds(adreno_dev, cmds);
739
740 return cmds - start;
741}
742
743/*
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600744 * kgsl_get_iommu_ctxt - Get device pointer to IOMMU contexts
745 * @mmu - Pointer to mmu device
746 *
747 * Get the device pointers for the IOMMU user and priv contexts of the
748 * kgsl device
749 * Return - 0 on success else error code
750 */
751static int kgsl_get_iommu_ctxt(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600752{
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600753 struct platform_device *pdev =
754 container_of(mmu->device->parentdev, struct platform_device,
755 dev);
756 struct kgsl_device_platform_data *pdata_dev = pdev->dev.platform_data;
757 struct kgsl_iommu *iommu = mmu->device->mmu.priv;
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700758 int i, ret = 0;
759
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600760 /* Go through the IOMMU data and get all the context devices */
761 if (KGSL_IOMMU_MAX_UNITS < pdata_dev->iommu_count) {
762 KGSL_CORE_ERR("Too many IOMMU units defined\n");
763 ret = -EINVAL;
764 goto done;
765 }
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700766
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600767 for (i = 0; i < pdata_dev->iommu_count; i++) {
768 ret = _get_iommu_ctxs(mmu, &pdata_dev->iommu_data[i], i);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700769 if (ret)
770 break;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600771 }
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600772 iommu->unit_count = pdata_dev->iommu_count;
773done:
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700774 return ret;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600775}
776
Shubhraprakash Dase9eefd72012-05-01 01:44:59 -0600777/*
778 * kgsl_set_register_map - Map the IOMMU regsiters in the memory descriptors
779 * of the respective iommu units
780 * @mmu - Pointer to mmu structure
781 *
782 * Return - 0 on success else error code
783 */
784static int kgsl_set_register_map(struct kgsl_mmu *mmu)
785{
786 struct platform_device *pdev =
787 container_of(mmu->device->parentdev, struct platform_device,
788 dev);
789 struct kgsl_device_platform_data *pdata_dev = pdev->dev.platform_data;
790 struct kgsl_iommu *iommu = mmu->device->mmu.priv;
791 struct kgsl_iommu_unit *iommu_unit;
792 int i = 0, ret = 0;
793
794 for (; i < pdata_dev->iommu_count; i++) {
795 struct kgsl_device_iommu_data data = pdata_dev->iommu_data[i];
796 iommu_unit = &iommu->iommu_units[i];
797 /* set up the IOMMU register map for the given IOMMU unit */
798 if (!data.physstart || !data.physend) {
799 KGSL_CORE_ERR("The register range for IOMMU unit not"
800 " specified\n");
801 ret = -EINVAL;
802 goto err;
803 }
804 iommu_unit->reg_map.hostptr = ioremap(data.physstart,
805 data.physend - data.physstart + 1);
806 if (!iommu_unit->reg_map.hostptr) {
807 KGSL_CORE_ERR("Failed to map SMMU register address "
808 "space from %x to %x\n", data.physstart,
809 data.physend - data.physstart + 1);
810 ret = -ENOMEM;
811 i--;
812 goto err;
813 }
814 iommu_unit->reg_map.size = data.physend - data.physstart + 1;
815 iommu_unit->reg_map.physaddr = data.physstart;
Rajeev Kulkarni55863722012-11-21 23:40:05 -0800816 ret = memdesc_sg_phys(&iommu_unit->reg_map, data.physstart,
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600817 iommu_unit->reg_map.size);
Rajeev Kulkarni55863722012-11-21 23:40:05 -0800818 if (ret)
819 goto err;
Shubhraprakash Dase9eefd72012-05-01 01:44:59 -0600820 }
821 iommu->unit_count = pdata_dev->iommu_count;
822 return ret;
823err:
824 /* Unmap any mapped IOMMU regions */
825 for (; i >= 0; i--) {
826 iommu_unit = &iommu->iommu_units[i];
827 iounmap(iommu_unit->reg_map.hostptr);
828 iommu_unit->reg_map.size = 0;
829 iommu_unit->reg_map.physaddr = 0;
830 }
831 return ret;
832}
833
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600834/*
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700835 * kgsl_iommu_get_pt_base_addr - Get the address of the pagetable that the
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600836 * IOMMU ttbr0 register is programmed with
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700837 * @mmu - Pointer to mmu
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600838 * @pt - kgsl pagetable pointer that contains the IOMMU domain pointer
839 *
840 * Return - actual pagetable address that the ttbr0 register is programmed
841 * with
842 */
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700843static unsigned int kgsl_iommu_get_pt_base_addr(struct kgsl_mmu *mmu,
844 struct kgsl_pagetable *pt)
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600845{
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700846 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600847 struct kgsl_iommu_pt *iommu_pt = pt->priv;
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700848 return iommu_get_pt_base_addr(iommu_pt->domain) &
849 (iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
850 iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600851}
852
853/*
854 * kgsl_iommu_get_pt_lsb - Return the lsb of the ttbr0 IOMMU register
855 * @mmu - Pointer to mmu structure
856 * @hostptr - Pointer to the IOMMU register map. This is used to match
857 * the iommu device whose lsb value is to be returned
858 * @ctx_id - The context bank whose lsb valus is to be returned
859 * Return - returns the lsb which is the last 14 bits of the ttbr0 IOMMU
860 * register. ttbr0 is the actual PTBR for of the IOMMU. The last 14 bits
861 * are only programmed once in the beginning when a domain is attached
862 * does not change.
863 */
864static int kgsl_iommu_get_pt_lsb(struct kgsl_mmu *mmu,
865 unsigned int unit_id,
866 enum kgsl_iommu_context_id ctx_id)
867{
868 struct kgsl_iommu *iommu = mmu->priv;
869 int i, j;
870 for (i = 0; i < iommu->unit_count; i++) {
871 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
872 for (j = 0; j < iommu_unit->dev_count; j++)
873 if (unit_id == i &&
874 ctx_id == iommu_unit->dev[j].ctx_id)
875 return iommu_unit->dev[j].pt_lsb;
876 }
877 return 0;
878}
879
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600880static void kgsl_iommu_setstate(struct kgsl_mmu *mmu,
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600881 struct kgsl_pagetable *pagetable,
882 unsigned int context_id)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600883{
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600884 if (mmu->flags & KGSL_FLAGS_STARTED) {
885 /* page table not current, then setup mmu to use new
886 * specified page table
887 */
888 if (mmu->hwpagetable != pagetable) {
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600889 unsigned int flags = 0;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600890 mmu->hwpagetable = pagetable;
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600891 flags |= kgsl_mmu_pt_get_flags(mmu->hwpagetable,
Shubhraprakash Das8649fa52012-07-26 15:49:46 -0700892 mmu->device->id) |
893 KGSL_MMUFLAGS_TLBFLUSH;
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600894 kgsl_setstate(mmu, context_id,
895 KGSL_MMUFLAGS_PTUPDATE | flags);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600896 }
897 }
898}
899
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600900static int kgsl_iommu_init(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600901{
902 /*
903 * intialize device mmu
904 *
905 * call this with the global lock held
906 */
907 int status = 0;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600908 struct kgsl_iommu *iommu;
909
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600910 iommu = kzalloc(sizeof(struct kgsl_iommu), GFP_KERNEL);
911 if (!iommu) {
912 KGSL_CORE_ERR("kzalloc(%d) failed\n",
913 sizeof(struct kgsl_iommu));
914 return -ENOMEM;
915 }
916
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600917 mmu->priv = iommu;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600918 status = kgsl_get_iommu_ctxt(mmu);
919 if (status)
920 goto done;
Shubhraprakash Dase9eefd72012-05-01 01:44:59 -0600921 status = kgsl_set_register_map(mmu);
922 if (status)
923 goto done;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600924
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700925 iommu->iommu_reg_list = kgsl_iommuv1_reg;
926 iommu->ctx_offset = KGSL_IOMMU_CTX_OFFSET_V1;
927
Shubhraprakash Das15a8b462012-08-16 23:24:28 -0700928 if (msm_soc_version_supports_iommu_v1()) {
929 iommu->iommu_reg_list = kgsl_iommuv1_reg;
930 iommu->ctx_offset = KGSL_IOMMU_CTX_OFFSET_V1;
931 } else {
932 iommu->iommu_reg_list = kgsl_iommuv2_reg;
933 iommu->ctx_offset = KGSL_IOMMU_CTX_OFFSET_V2;
934 }
935
Shubhraprakash Dase9541a32012-05-09 22:25:55 -0600936 /* A nop is required in an indirect buffer when switching
937 * pagetables in-stream */
938 kgsl_sharedmem_writel(&mmu->setstate_memory,
939 KGSL_IOMMU_SETSTATE_NOP_OFFSET,
940 cp_nop_packet(1));
941
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600942 dev_info(mmu->device->dev, "|%s| MMU type set for device is IOMMU\n",
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600943 __func__);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600944done:
945 if (status) {
946 kfree(iommu);
947 mmu->priv = NULL;
948 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600949 return status;
950}
951
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600952/*
953 * kgsl_iommu_setup_defaultpagetable - Setup the initial defualtpagetable
954 * for iommu. This function is only called once during first start, successive
955 * start do not call this funciton.
956 * @mmu - Pointer to mmu structure
957 *
958 * Create the initial defaultpagetable and setup the iommu mappings to it
959 * Return - 0 on success else error code
960 */
961static int kgsl_iommu_setup_defaultpagetable(struct kgsl_mmu *mmu)
962{
963 int status = 0;
964 int i = 0;
965 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600966 struct kgsl_pagetable *pagetable = NULL;
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600967
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600968 /* If chip is not 8960 then we use the 2nd context bank for pagetable
969 * switching on the 3D side for which a separate table is allocated */
Shubhraprakash Das15a8b462012-08-16 23:24:28 -0700970 if (!cpu_is_msm8960() && msm_soc_version_supports_iommu_v1()) {
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600971 mmu->priv_bank_table =
972 kgsl_mmu_getpagetable(KGSL_MMU_PRIV_BANK_TABLE_NAME);
973 if (mmu->priv_bank_table == NULL) {
974 status = -ENOMEM;
975 goto err;
976 }
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600977 }
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600978 mmu->defaultpagetable = kgsl_mmu_getpagetable(KGSL_MMU_GLOBAL_PT);
979 /* Return error if the default pagetable doesn't exist */
980 if (mmu->defaultpagetable == NULL) {
981 status = -ENOMEM;
982 goto err;
983 }
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600984 pagetable = mmu->priv_bank_table ? mmu->priv_bank_table :
985 mmu->defaultpagetable;
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600986 /* Map the IOMMU regsiters to only defaultpagetable */
Shubhraprakash Das15a8b462012-08-16 23:24:28 -0700987 if (msm_soc_version_supports_iommu_v1()) {
988 for (i = 0; i < iommu->unit_count; i++) {
989 iommu->iommu_units[i].reg_map.priv |=
Jordan Crousedc67dfb2012-10-25 09:41:46 -0600990 KGSL_MEMDESC_GLOBAL;
Shubhraprakash Das15a8b462012-08-16 23:24:28 -0700991 status = kgsl_mmu_map(pagetable,
992 &(iommu->iommu_units[i].reg_map),
993 GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
994 if (status) {
995 iommu->iommu_units[i].reg_map.priv &=
Jordan Crousedc67dfb2012-10-25 09:41:46 -0600996 ~KGSL_MEMDESC_GLOBAL;
Shubhraprakash Das15a8b462012-08-16 23:24:28 -0700997 goto err;
998 }
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600999 }
1000 }
1001 return status;
1002err:
1003 for (i--; i >= 0; i--) {
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -06001004 kgsl_mmu_unmap(pagetable,
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -06001005 &(iommu->iommu_units[i].reg_map));
Jordan Crousedc67dfb2012-10-25 09:41:46 -06001006 iommu->iommu_units[i].reg_map.priv &= ~KGSL_MEMDESC_GLOBAL;
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -06001007 }
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -06001008 if (mmu->priv_bank_table) {
1009 kgsl_mmu_putpagetable(mmu->priv_bank_table);
1010 mmu->priv_bank_table = NULL;
1011 }
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -06001012 if (mmu->defaultpagetable) {
1013 kgsl_mmu_putpagetable(mmu->defaultpagetable);
1014 mmu->defaultpagetable = NULL;
1015 }
1016 return status;
1017}
1018
Shubhraprakash Das1c528262012-04-26 17:38:13 -06001019static int kgsl_iommu_start(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001020{
Tarun Karra9c070822012-11-27 16:43:51 -07001021 struct kgsl_device *device = mmu->device;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001022 int status;
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -06001023 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001024 int i, j;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001025
1026 if (mmu->flags & KGSL_FLAGS_STARTED)
1027 return 0;
1028
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -06001029 if (mmu->defaultpagetable == NULL) {
1030 status = kgsl_iommu_setup_defaultpagetable(mmu);
1031 if (status)
1032 return -ENOMEM;
Tarun Karra9c070822012-11-27 16:43:51 -07001033
1034 /* Initialize the sync lock between GPU and CPU */
1035 if (msm_soc_version_supports_iommu_v1() &&
1036 (device->id == KGSL_DEVICE_3D0))
1037 kgsl_iommu_init_sync_lock(mmu);
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -06001038 }
Tarun Karra9c070822012-11-27 16:43:51 -07001039
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -06001040 /* We use the GPU MMU to control access to IOMMU registers on 8960 with
1041 * a225, hence we still keep the MMU active on 8960 */
1042 if (cpu_is_msm8960()) {
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -06001043 struct kgsl_mh *mh = &(mmu->device->mh);
1044 kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000001);
1045 kgsl_regwrite(mmu->device, MH_MMU_MPU_END,
1046 mh->mpu_base +
Shubhraprakash Das2b54b5f2012-08-08 18:21:36 -07001047 iommu->iommu_units[0].reg_map.gpuaddr);
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -06001048 } else {
1049 kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000000);
1050 }
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -06001051
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001052 mmu->hwpagetable = mmu->defaultpagetable;
1053
1054 status = kgsl_attach_pagetable_iommu_domain(mmu);
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -06001055 if (status) {
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -06001056 mmu->hwpagetable = NULL;
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -06001057 goto done;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -06001058 }
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -06001059 status = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001060 if (status) {
1061 KGSL_CORE_ERR("clk enable failed\n");
1062 goto done;
1063 }
1064 status = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_PRIV);
1065 if (status) {
1066 KGSL_CORE_ERR("clk enable failed\n");
1067 goto done;
1068 }
1069 /* Get the lsb value of pagetables set in the IOMMU ttbr0 register as
1070 * that value should not change when we change pagetables, so while
1071 * changing pagetables we can use this lsb value of the pagetable w/o
1072 * having to read it again
1073 */
1074 for (i = 0; i < iommu->unit_count; i++) {
1075 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
Shubhraprakash Das2747cf62012-09-27 23:05:43 -07001076 for (j = 0; j < iommu_unit->dev_count; j++) {
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001077 iommu_unit->dev[j].pt_lsb = KGSL_IOMMMU_PT_LSB(iommu,
1078 KGSL_IOMMU_GET_CTX_REG(iommu,
1079 iommu_unit,
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001080 iommu_unit->dev[j].ctx_id,
1081 TTBR0));
Shubhraprakash Das2747cf62012-09-27 23:05:43 -07001082 }
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001083 }
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001084
Shubhraprakash Dascb068072012-06-07 17:52:41 -06001085 kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -06001086 mmu->flags |= KGSL_FLAGS_STARTED;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001087
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001088done:
1089 if (status) {
Shubhraprakash Dascb068072012-06-07 17:52:41 -06001090 kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001091 kgsl_detach_pagetable_iommu_domain(mmu);
1092 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001093 return status;
1094}
1095
1096static int
1097kgsl_iommu_unmap(void *mmu_specific_pt,
Shubhraprakash Das0c811262012-06-06 23:22:19 -06001098 struct kgsl_memdesc *memdesc,
1099 unsigned int *tlb_flags)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001100{
1101 int ret;
Jordan Crouse3c86ca82012-05-21 08:41:52 -06001102 unsigned int range = kgsl_sg_size(memdesc->sg, memdesc->sglen);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -06001103 struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001104
1105 /* All GPU addresses as assigned are page aligned, but some
1106 functions purturb the gpuaddr with an offset, so apply the
1107 mask here to make sure we have the right address */
1108
1109 unsigned int gpuaddr = memdesc->gpuaddr & KGSL_MMU_ALIGN_MASK;
1110
1111 if (range == 0 || gpuaddr == 0)
1112 return 0;
1113
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -06001114 ret = iommu_unmap_range(iommu_pt->domain, gpuaddr, range);
Shubhraprakash Das08894b92011-10-14 11:42:25 -06001115 if (ret)
1116 KGSL_CORE_ERR("iommu_unmap_range(%p, %x, %d) failed "
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -06001117 "with err: %d\n", iommu_pt->domain, gpuaddr,
Shubhraprakash Das08894b92011-10-14 11:42:25 -06001118 range, ret);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001119
Shubhraprakash Das0c811262012-06-06 23:22:19 -06001120#ifdef CONFIG_KGSL_PER_PROCESS_PAGE_TABLE
1121 /*
1122 * Flushing only required if per process pagetables are used. With
1123 * global case, flushing will happen inside iommu_map function
1124 */
Shubhraprakash Das15a8b462012-08-16 23:24:28 -07001125 if (!ret && msm_soc_version_supports_iommu_v1())
Shubhraprakash Das0c811262012-06-06 23:22:19 -06001126 *tlb_flags = UINT_MAX;
1127#endif
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001128 return 0;
1129}
1130
1131static int
1132kgsl_iommu_map(void *mmu_specific_pt,
1133 struct kgsl_memdesc *memdesc,
Shubhraprakash Dasf764e462012-04-26 15:38:09 -06001134 unsigned int protflags,
1135 unsigned int *tlb_flags)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001136{
Shubhraprakash Das08894b92011-10-14 11:42:25 -06001137 int ret;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001138 unsigned int iommu_virt_addr;
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -06001139 struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
Jordan Crouse3c86ca82012-05-21 08:41:52 -06001140 int size = kgsl_sg_size(memdesc->sg, memdesc->sglen);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001141
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -06001142 BUG_ON(NULL == iommu_pt);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001143
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001144
Jordan Croused17e9aa2011-10-12 16:57:48 -06001145 iommu_virt_addr = memdesc->gpuaddr;
1146
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -06001147 ret = iommu_map_range(iommu_pt->domain, iommu_virt_addr, memdesc->sg,
Jordan Crouse3c86ca82012-05-21 08:41:52 -06001148 size, (IOMMU_READ | IOMMU_WRITE));
Shubhraprakash Das08894b92011-10-14 11:42:25 -06001149 if (ret) {
1150 KGSL_CORE_ERR("iommu_map_range(%p, %x, %p, %d, %d) "
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -06001151 "failed with err: %d\n", iommu_pt->domain,
Jordan Crouse3c86ca82012-05-21 08:41:52 -06001152 iommu_virt_addr, memdesc->sg, size,
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -06001153 (IOMMU_READ | IOMMU_WRITE), ret);
Shubhraprakash Das08894b92011-10-14 11:42:25 -06001154 return ret;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001155 }
1156
1157 return ret;
1158}
1159
Shubhraprakash Das79447952012-04-26 18:12:23 -06001160static void kgsl_iommu_stop(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001161{
Shubhraprakash Dascb068072012-06-07 17:52:41 -06001162 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Das2747cf62012-09-27 23:05:43 -07001163 int i, j;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001164 /*
1165 * stop device mmu
1166 *
1167 * call this with the global lock held
1168 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001169
1170 if (mmu->flags & KGSL_FLAGS_STARTED) {
1171 /* detach iommu attachment */
1172 kgsl_detach_pagetable_iommu_domain(mmu);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -06001173 mmu->hwpagetable = NULL;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001174
1175 mmu->flags &= ~KGSL_FLAGS_STARTED;
Shubhraprakash Dascb068072012-06-07 17:52:41 -06001176
Shubhraprakash Das2747cf62012-09-27 23:05:43 -07001177 if (mmu->fault) {
1178 for (i = 0; i < iommu->unit_count; i++) {
1179 struct kgsl_iommu_unit *iommu_unit =
1180 &iommu->iommu_units[i];
1181 for (j = 0; j < iommu_unit->dev_count; j++) {
1182 if (iommu_unit->dev[j].fault) {
1183 kgsl_iommu_enable_clk(mmu, j);
1184 KGSL_IOMMU_SET_CTX_REG(iommu,
1185 iommu_unit,
1186 iommu_unit->dev[j].ctx_id,
1187 RESUME, 1);
1188 iommu_unit->dev[j].fault = 0;
1189 }
1190 }
1191 }
1192 mmu->fault = 0;
1193 }
1194 }
Shubhraprakash Dascb068072012-06-07 17:52:41 -06001195 /* switch off MMU clocks and cancel any events it has queued */
1196 iommu->clk_event_queued = false;
1197 kgsl_cancel_events(mmu->device, mmu);
1198 kgsl_iommu_disable_clk(mmu);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001199}
1200
Shubhraprakash Das1c528262012-04-26 17:38:13 -06001201static int kgsl_iommu_close(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001202{
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -06001203 struct kgsl_iommu *iommu = mmu->priv;
1204 int i;
1205 for (i = 0; i < iommu->unit_count; i++) {
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -06001206 struct kgsl_pagetable *pagetable = (mmu->priv_bank_table ?
1207 mmu->priv_bank_table : mmu->defaultpagetable);
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -06001208 if (iommu->iommu_units[i].reg_map.gpuaddr)
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -06001209 kgsl_mmu_unmap(pagetable,
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -06001210 &(iommu->iommu_units[i].reg_map));
1211 if (iommu->iommu_units[i].reg_map.hostptr)
1212 iounmap(iommu->iommu_units[i].reg_map.hostptr);
1213 kgsl_sg_free(iommu->iommu_units[i].reg_map.sg,
1214 iommu->iommu_units[i].reg_map.sglen);
1215 }
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -06001216
1217 if (mmu->priv_bank_table)
1218 kgsl_mmu_putpagetable(mmu->priv_bank_table);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001219 if (mmu->defaultpagetable)
1220 kgsl_mmu_putpagetable(mmu->defaultpagetable);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -06001221 kfree(iommu);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001222
1223 return 0;
1224}
1225
1226static unsigned int
Shubhraprakash Das1c528262012-04-26 17:38:13 -06001227kgsl_iommu_get_current_ptbase(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001228{
Shubhraprakash Das2b8716b2012-05-04 16:58:40 -06001229 unsigned int pt_base;
1230 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Das64a745c2012-06-11 16:44:16 -06001231 /* We cannot enable or disable the clocks in interrupt context, this
1232 function is called from interrupt context if there is an axi error */
1233 if (in_interrupt())
1234 return 0;
Shubhraprakash Das2b8716b2012-05-04 16:58:40 -06001235 /* Return the current pt base by reading IOMMU pt_base register */
1236 kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001237 pt_base = KGSL_IOMMU_GET_CTX_REG(iommu, (&iommu->iommu_units[0]),
1238 KGSL_IOMMU_CONTEXT_USER,
1239 TTBR0);
Shubhraprakash Dascb068072012-06-07 17:52:41 -06001240 kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001241 return pt_base &
1242 (iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
1243 iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001244}
1245
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -06001246/*
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001247 * kgsl_iommu_default_setstate - Change the IOMMU pagetable or flush IOMMU tlb
1248 * of the primary context bank
1249 * @mmu - Pointer to mmu structure
1250 * @flags - Flags indicating whether pagetable has to chnage or tlb is to be
1251 * flushed or both
1252 *
1253 * Based on flags set the new pagetable fo the IOMMU unit or flush it's tlb or
1254 * do both by doing direct register writes to the IOMMu registers through the
1255 * cpu
1256 * Return - void
1257 */
1258static void kgsl_iommu_default_setstate(struct kgsl_mmu *mmu,
1259 uint32_t flags)
1260{
1261 struct kgsl_iommu *iommu = mmu->priv;
1262 int temp;
1263 int i;
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001264 unsigned int pt_base = kgsl_iommu_get_pt_base_addr(mmu,
1265 mmu->hwpagetable);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001266 unsigned int pt_val;
1267
1268 if (kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER)) {
1269 KGSL_DRV_ERR(mmu->device, "Failed to enable iommu clocks\n");
1270 return;
1271 }
1272 /* Mask off the lsb of the pt base address since lsb will not change */
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001273 pt_base &= (iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
1274 iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
1275
Tarun Karra9c070822012-11-27 16:43:51 -07001276 //if (msm_soc_version_supports_iommu_v1())
Shubhraprakash Dasee61e4d2012-11-27 17:07:44 -07001277 /* Acquire GPU-CPU sync Lock here */
1278 msm_iommu_lock();
1279
1280 if (flags & KGSL_MMUFLAGS_PTUPDATE) {
1281 if (!msm_soc_version_supports_iommu_v1())
1282 kgsl_idle(mmu->device);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001283 for (i = 0; i < iommu->unit_count; i++) {
1284 /* get the lsb value which should not change when
1285 * changing ttbr0 */
1286 pt_val = kgsl_iommu_get_pt_lsb(mmu, i,
1287 KGSL_IOMMU_CONTEXT_USER);
1288 pt_val += pt_base;
1289
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001290 KGSL_IOMMU_SET_CTX_REG(iommu, (&iommu->iommu_units[i]),
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001291 KGSL_IOMMU_CONTEXT_USER, TTBR0, pt_val);
1292
1293 mb();
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001294 temp = KGSL_IOMMU_GET_CTX_REG(iommu,
1295 (&iommu->iommu_units[i]),
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001296 KGSL_IOMMU_CONTEXT_USER, TTBR0);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001297 }
1298 }
1299 /* Flush tlb */
1300 if (flags & KGSL_MMUFLAGS_TLBFLUSH) {
1301 for (i = 0; i < iommu->unit_count; i++) {
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001302 KGSL_IOMMU_SET_CTX_REG(iommu, (&iommu->iommu_units[i]),
1303 KGSL_IOMMU_CONTEXT_USER, TLBIALL, 1);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001304 mb();
1305 }
1306 }
Tarun Karra9c070822012-11-27 16:43:51 -07001307
1308 /* Release GPU-CPU sync Lock here */
1309 msm_iommu_unlock();
1310
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001311 /* Disable smmu clock */
Shubhraprakash Dascb068072012-06-07 17:52:41 -06001312 kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001313}
1314
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001315/*
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001316 * kgsl_iommu_get_reg_gpuaddr - Returns the gpu address of IOMMU regsiter
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001317 * @mmu - Pointer to mmu structure
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001318 * @iommu_unit - The iommu unit for which base address is requested
1319 * @ctx_id - The context ID of the IOMMU ctx
1320 * @reg - The register for which address is required
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001321 *
1322 * Return - The number of iommu units which is also the number of register
1323 * mapped descriptor arrays which the out parameter will have
1324 */
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001325static unsigned int kgsl_iommu_get_reg_gpuaddr(struct kgsl_mmu *mmu,
1326 int iommu_unit, int ctx_id, int reg)
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001327{
1328 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001329
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001330 if (KGSL_IOMMU_GLOBAL_BASE == reg)
1331 return iommu->iommu_units[iommu_unit].reg_map.gpuaddr;
1332 else
1333 return iommu->iommu_units[iommu_unit].reg_map.gpuaddr +
1334 iommu->iommu_reg_list[reg].reg_offset +
1335 (ctx_id << KGSL_IOMMU_CTX_SHIFT) + iommu->ctx_offset;
1336}
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001337
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001338static int kgsl_iommu_get_num_iommu_units(struct kgsl_mmu *mmu)
1339{
1340 struct kgsl_iommu *iommu = mmu->priv;
1341 return iommu->unit_count;
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001342}
1343
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001344struct kgsl_mmu_ops iommu_ops = {
1345 .mmu_init = kgsl_iommu_init,
1346 .mmu_close = kgsl_iommu_close,
1347 .mmu_start = kgsl_iommu_start,
1348 .mmu_stop = kgsl_iommu_stop,
1349 .mmu_setstate = kgsl_iommu_setstate,
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001350 .mmu_device_setstate = kgsl_iommu_default_setstate,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001351 .mmu_pagefault = NULL,
1352 .mmu_get_current_ptbase = kgsl_iommu_get_current_ptbase,
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -06001353 .mmu_enable_clk = kgsl_iommu_enable_clk,
Shubhraprakash Dascb068072012-06-07 17:52:41 -06001354 .mmu_disable_clk_on_ts = kgsl_iommu_disable_clk_on_ts,
Shubhraprakash Dasfce27362012-05-09 17:44:14 -06001355 .mmu_get_pt_lsb = kgsl_iommu_get_pt_lsb,
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001356 .mmu_get_reg_gpuaddr = kgsl_iommu_get_reg_gpuaddr,
1357 .mmu_get_num_iommu_units = kgsl_iommu_get_num_iommu_units,
1358 .mmu_pt_equal = kgsl_iommu_pt_equal,
1359 .mmu_get_pt_base_addr = kgsl_iommu_get_pt_base_addr,
Tarun Karra9c070822012-11-27 16:43:51 -07001360 .mmu_sync_lock = kgsl_iommu_sync_lock,
1361 .mmu_sync_unlock = kgsl_iommu_sync_unlock,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001362};
1363
1364struct kgsl_mmu_pt_ops iommu_pt_ops = {
1365 .mmu_map = kgsl_iommu_map,
1366 .mmu_unmap = kgsl_iommu_unmap,
1367 .mmu_create_pagetable = kgsl_iommu_create_pagetable,
1368 .mmu_destroy_pagetable = kgsl_iommu_destroy_pagetable,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001369};